Add if command
This commit is contained in:
8
HELP.md
8
HELP.md
@@ -381,6 +381,14 @@ str %> call $myFooReplacer bar
|
||||
```
|
||||
|
||||
|
||||
### Control Structures
|
||||
|
||||
#### `if <cond> <lambda>`
|
||||
Execute the given lambda if `cond` is truthy. Cond may be a lambda, in which case it is executed.
|
||||
A value is truthy UNLESS it is the literal empty string (`''`) or the integer `0`.
|
||||
Example: `foo` -> `if (contains foo) (suffix bar)` -> `foobar`
|
||||
|
||||
|
||||
### Misc
|
||||
|
||||
#### `lipsum <num> <word|line|para>`
|
||||
|
||||
56
src/vm/commands/if.ts
Normal file
56
src/vm/commands/if.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import {LexInput} from "../lexer.js";
|
||||
import {Command, ParseContext, StrTerm} from "./command.js";
|
||||
import {StrVM} from "../vm.js";
|
||||
import {Call} from "./call.js";
|
||||
|
||||
export type IfData = {
|
||||
cond: StrTerm,
|
||||
callable: StrTerm,
|
||||
}
|
||||
|
||||
export class If extends Command<IfData> {
|
||||
async attemptParse(context: ParseContext): Promise<IfData> {
|
||||
return {
|
||||
cond: await context.popTerm(),
|
||||
callable: await context.popTerm(),
|
||||
}
|
||||
}
|
||||
|
||||
isParseCandidate(token: LexInput): boolean {
|
||||
return this.isKeyword(token, 'if')
|
||||
}
|
||||
|
||||
getDisplayName(): string {
|
||||
return 'if'
|
||||
}
|
||||
|
||||
async execute(vm: StrVM, data: IfData): Promise<StrVM> {
|
||||
return vm.replaceContextFromChild(async (childVM, ctx) => {
|
||||
let cond = ctx.resolveRequired(data.cond)
|
||||
|
||||
// If `cond` is a lambda, then call it before evaluating its truthiness.
|
||||
if ( cond.term === 'lambda' ) {
|
||||
await childVM.runInChild(async (lambdaVM, lambdaCtx) => {
|
||||
await (new Call).execute(lambdaVM, {
|
||||
callable: cond,
|
||||
params: [],
|
||||
})
|
||||
|
||||
cond = lambdaCtx.getSubject()
|
||||
})
|
||||
}
|
||||
|
||||
if ( (cond.term === 'string' || cond.term === 'int') && !cond.value ) {
|
||||
// The string was empty/falsy, so do not execute the body.
|
||||
return
|
||||
}
|
||||
|
||||
const callable = ctx.resolveLambda(data.callable)
|
||||
|
||||
await (new Call).execute(childVM, {
|
||||
callable,
|
||||
params: [],
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -54,6 +54,7 @@ import {Script} from "./script.js";
|
||||
import {Take} from "./take.js";
|
||||
import {Group} from "./group.js";
|
||||
import {Flatten} from "./flatten.js";
|
||||
import {If} from "./if.js";
|
||||
|
||||
export type Commands = Command<CommandData>[]
|
||||
export const commands: Commands = [
|
||||
@@ -74,6 +75,7 @@ export const commands: Commands = [
|
||||
new Group,
|
||||
new Help,
|
||||
new History,
|
||||
new If,
|
||||
new Indent,
|
||||
new InFile,
|
||||
new Join,
|
||||
|
||||
Reference in New Issue
Block a user