Implement take command and comments (--) + misc cleanup
This commit is contained in:
@@ -382,7 +382,6 @@ export class ParseContext {
|
||||
// Now, the remainder of the subcontext inputs should be a series of executables
|
||||
// separated by `terminator` tokens -- e.g. (split _; join |), so parse executables
|
||||
// from the subcontext until it is empty:
|
||||
console.log(sc.inputs)
|
||||
while ( sc.inputs.length > 0 ) {
|
||||
const [exec, remainingInputs] = await this.childParser(sc.inputs)
|
||||
lambda.body.push(exec)
|
||||
|
||||
@@ -51,6 +51,7 @@ import {Concat} from "./concat.js";
|
||||
import {Call} from "./call.js";
|
||||
import {Chunk} from "./chunk.js";
|
||||
import {Script} from "./script.js";
|
||||
import {Take} from "./take.js";
|
||||
|
||||
export type Commands = Command<CommandData>[]
|
||||
export const commands: Commands = [
|
||||
@@ -97,6 +98,7 @@ export const commands: Commands = [
|
||||
new Sort,
|
||||
new Split,
|
||||
new Suffix,
|
||||
new Take,
|
||||
new To,
|
||||
new Trim,
|
||||
new Undo,
|
||||
|
||||
76
src/vm/commands/take.ts
Normal file
76
src/vm/commands/take.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import {Command, ParseContext, StrTerm, TypeError} from "./command.js";
|
||||
import {LexInput} from "../lexer.js";
|
||||
import {StrVM} from "../vm.js";
|
||||
import {Lines} from "./lines.js";
|
||||
import {Words} from "./words.js";
|
||||
|
||||
export type TakeData = {
|
||||
type: 'line'|'word'|'index',
|
||||
specific: StrTerm,
|
||||
}
|
||||
|
||||
/**
|
||||
* This command has a few forms:
|
||||
*
|
||||
* take line 3
|
||||
* Assume the subject is a string and keep only line 3
|
||||
*
|
||||
* take word 3
|
||||
* Assume the subject is a string and keep only word 3
|
||||
*
|
||||
* take index 3
|
||||
* take 3
|
||||
* Assume the subject is a destructured and keep only the item at index 3.
|
||||
*/
|
||||
export class Take extends Command<TakeData> {
|
||||
async attemptParse(context: ParseContext): Promise<TakeData> {
|
||||
// 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 = await context.peekTerm()
|
||||
if ( next?.term === 'int' || next?.term === 'variable' ) {
|
||||
return {
|
||||
type: 'index',
|
||||
specific: await context.popTerm(),
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, assume we got the "on <type> <index> <exec>" form:
|
||||
return {
|
||||
type: context.popKeywordInSet(['line', 'word', 'index']).value,
|
||||
specific: await context.popTerm(),
|
||||
}
|
||||
}
|
||||
|
||||
getDisplayName(): string {
|
||||
return 'take'
|
||||
}
|
||||
|
||||
isParseCandidate(token: LexInput): boolean {
|
||||
return this.isKeyword(token, 'take')
|
||||
}
|
||||
|
||||
async execute(vm: StrVM, data: TakeData): Promise<StrVM> {
|
||||
// If the type is line|word, first destructure the subject accordingly:
|
||||
if ( data.type === 'line' ) {
|
||||
vm = await (new Lines).execute(vm)
|
||||
} else if ( data.type === 'word' ) {
|
||||
vm = await (new Words).execute(vm)
|
||||
}
|
||||
|
||||
return vm.replaceContextMatchingTerm(ctx => ({
|
||||
override: async sub => {
|
||||
if ( sub.term !== 'destructured' ) {
|
||||
throw new TypeError('Cannot `take`: invalid type')
|
||||
}
|
||||
|
||||
// Retrieve the specific item in the destructured we're operating over:
|
||||
const idx = ctx.resolveInt(data.specific)
|
||||
const operand = sub.value[idx]
|
||||
if ( !operand ) {
|
||||
throw new Error(`Invalid ${data.type} ${idx}`)
|
||||
}
|
||||
return operand.value
|
||||
},
|
||||
}))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user