[WIP] Implement save, load, over, infile, outfile, on, lipsum, help + start implementing undo, redo, exit, edit
This commit is contained in:
@@ -1,17 +1,46 @@
|
||||
import {Command, CommandData, ParseContext, StrTerm} from "./command.js";
|
||||
import {Command, CommandData, ParseContext, StrTerm, unwrapString, wrapString} from "./command.js";
|
||||
import {Executable} from "../parse.js";
|
||||
import {LexInput} from "../lexer.js";
|
||||
import {StrVM} from "../vm.js";
|
||||
import {Lines} from "./lines.js";
|
||||
import {Words} from "./words.js";
|
||||
import {Join} from "./join.js";
|
||||
|
||||
export type OnData = {
|
||||
type: 'line'|'word',
|
||||
type: 'line'|'word'|'index',
|
||||
specific: StrTerm,
|
||||
exec: Executable<CommandData>,
|
||||
}
|
||||
|
||||
/**
|
||||
* This command has a few forms:
|
||||
*
|
||||
* on line 3 <exec>
|
||||
* Assume the subject is a string and perform the given exec on line 3
|
||||
*
|
||||
* on word 3 <exec>
|
||||
* Assume the subject is a string and perform the given exec on word 3
|
||||
*
|
||||
* on index 3 <exec>
|
||||
* on 3 <exec>
|
||||
* Assume the subject is a destructured and perform the given exec on the item at index 3.
|
||||
*/
|
||||
export class On extends Command<OnData> {
|
||||
async attemptParse(context: ParseContext): Promise<OnData> {
|
||||
// Check if the next term we received is an int or a variable.
|
||||
// If so, we got the "on 3 <exec>" form of the command.
|
||||
const next = context.peekTerm()
|
||||
if ( next?.term === 'int' || next?.term === 'variable' ) {
|
||||
return {
|
||||
type: 'index',
|
||||
specific: context.popTerm(),
|
||||
exec: await context.popExecutable(),
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, assume we got the "on <type> <index> <exec>" form:
|
||||
return {
|
||||
type: context.popKeywordInSet(['line', 'word']).value,
|
||||
type: context.popKeywordInSet(['line', 'word', 'index']).value,
|
||||
specific: context.popTerm(),
|
||||
exec: await context.popExecutable(),
|
||||
}
|
||||
@@ -24,4 +53,50 @@ export class On extends Command<OnData> {
|
||||
isParseCandidate(token: LexInput): boolean {
|
||||
return this.isKeyword(token, 'on')
|
||||
}
|
||||
|
||||
async execute(vm: StrVM, data: OnData): Promise<StrVM> {
|
||||
// If the type is line|word, first destructure the subject accordingly:
|
||||
let rejoin = false
|
||||
if ( data.type === 'line' ) {
|
||||
vm = await (new Lines).execute(vm)
|
||||
rejoin = true
|
||||
} else if ( data.type === 'word' ) {
|
||||
vm = await (new Words).execute(vm)
|
||||
rejoin = true
|
||||
}
|
||||
|
||||
// Then, apply the given command to the specified index of the subject:
|
||||
vm = await vm.replaceContextMatchingTerm(ctx => ({
|
||||
destructured: async sub => {
|
||||
// Retrieve the specific item in the destructured we're operating over:
|
||||
const idx = ctx.resolveInt(data.specific)
|
||||
const operand = sub[idx]
|
||||
if ( !operand ) {
|
||||
throw new Error(`Invalid ${data.type} ${idx}`)
|
||||
}
|
||||
|
||||
// Apply the command to the value of the given index:
|
||||
const result = await vm.runInChild(async (child, childCtx) => {
|
||||
await childCtx.replaceSubject(() => wrapString(operand.value))
|
||||
await data.exec.command.execute(child, data.exec.data)
|
||||
return unwrapString(childCtx.getSubject())
|
||||
})
|
||||
|
||||
// Replace the specific index back into the destructured:
|
||||
sub[idx] = {
|
||||
...operand,
|
||||
value: result,
|
||||
}
|
||||
|
||||
return sub
|
||||
},
|
||||
}))
|
||||
|
||||
// If we previously split the value (i.e. for type = line|word), rejoin it:
|
||||
if ( rejoin ) {
|
||||
vm = await (new Join).execute(vm, {})
|
||||
}
|
||||
|
||||
return vm
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user