summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKai Stevenson <kai@kaistevenson.com>2025-11-06 20:25:30 -0800
committerKai Stevenson <kai@kaistevenson.com>2025-11-06 20:28:23 -0800
commitccaff310c85a64a852d96ee71ecf9640de57ea36 (patch)
tree029409c816b67c7d07920d288b3b1386178ac515 /src
parent490b9c94fba16f484be3bb58b8a4a4880b9396bc (diff)
runtime workskai/recursion
Diffstat (limited to 'src')
-rw-r--r--src/lang/js-lang/builtin/sbuiltin.ts2
-rw-r--r--src/lang/js-lang/core/eval.ts29
-rw-r--r--src/lang/ks-lang/index.ts13
3 files changed, 23 insertions, 21 deletions
diff --git a/src/lang/js-lang/builtin/sbuiltin.ts b/src/lang/js-lang/builtin/sbuiltin.ts
index 663c2f9..013854c 100644
--- a/src/lang/js-lang/builtin/sbuiltin.ts
+++ b/src/lang/js-lang/builtin/sbuiltin.ts
@@ -7,7 +7,7 @@ export const V_SBUILTIN_Call: SBUILTIN = (node, frame) => {
const children = getEvaluatedChildren(node, frame);
const fn = children[0] as FnPrim | undefined;
- if (!fn?.fn) {
+ if (!fn) {
throw new Error(
`Invalid params for function call: ${JSON.stringify(
children,
diff --git a/src/lang/js-lang/core/eval.ts b/src/lang/js-lang/core/eval.ts
index 1a9e292..dfbd3ce 100644
--- a/src/lang/js-lang/core/eval.ts
+++ b/src/lang/js-lang/core/eval.ts
@@ -6,9 +6,8 @@ import {
NodeType,
FnPrim,
SENTINEL_NO_BUILTIN,
- NamedFnPrim,
} from "../../ts-lang";
-import { nameToBUILTIN, nameToSBUILTIN, V_SBUILTIN_Map } from "../builtin";
+import { nameToBUILTIN, nameToSBUILTIN } from "../builtin";
const V_SENTINEL_NO_BUILTIN: SENTINEL_NO_BUILTIN = "__NO_BUILTIN__";
@@ -35,14 +34,7 @@ const handleBind = (node: ASTNode, frame: StackFrame) => {
const inner = _evaluate(node.children[1], frame);
if (inner.fn) {
- const named: NamedFnPrim<any, any, any, any> = {
- args: inner.args,
- fn: inner.fn,
- name: node.children[0].name,
- frame,
- };
-
- return named;
+ return [inner, frame, node.children[0]["name"]];
}
return inner;
@@ -60,18 +52,23 @@ const handleFn = (node: ASTNode): FnPrim => {
const mapZip = (args: ASTNode[], values: any[]) =>
Object.fromEntries(args.map(({ name }, i) => [name, values[i]]));
-export const callFn = (fn: FnPrim, values: any[], frame: StackFrame) => {
- if ((fn as NamedFnPrim<any, any, any, any>).frame) {
- return _evaluate(fn.fn, {
+export const callFn = (
+ fn: FnPrim | [FnPrim, StackFrame, ASTNode["name"]],
+ values: any[],
+ frame: StackFrame
+) => {
+ if (Array.isArray(fn)) {
+ const [prim, frame, name] = fn;
+ return _evaluate(prim.fn, {
bindings: {
- ...mapZip(fn.args as ASTNode[], values),
...frame.bindings,
- ...(fn as NamedFnPrim<any, any, any, any>).frame.bindings,
+ [name]: fn,
+ ...mapZip(prim.args as ASTNode[], values),
},
});
}
return _evaluate(fn.fn, {
- bindings: { ...mapZip(fn.args as ASTNode[], values), ...frame.bindings },
+ bindings: { ...frame.bindings, ...mapZip(fn.args as ASTNode[], values) },
});
};
diff --git a/src/lang/ks-lang/index.ts b/src/lang/ks-lang/index.ts
index 772c9c9..633d9b9 100644
--- a/src/lang/ks-lang/index.ts
+++ b/src/lang/ks-lang/index.ts
@@ -8,6 +8,7 @@ import {
CallFn,
EmptyStackFrame,
ASTNode,
+ StackFrame,
} from "../ts-lang";
export type TransformArgs<Args extends readonly ASTNode[]> = {
@@ -40,13 +41,17 @@ export const createFn =
: EvalError<`Program's args do not extend args constraint`>
: EvalError<"Cannot create a function from a program that does not eval to a function">
: never => {
- const [programFn] = evaluate(parse(lex(program))) as Array<FnPrim>;
- if (!programFn.fn) {
+ const [e] = evaluate(parse(lex(program))) as [
+ FnPrim | [FnPrim, StackFrame, ASTNode["name"]]
+ ];
+
+ const fn: FnPrim = Array.isArray(e) ? e[0] : e;
+
+ if (!fn.fn) {
throw new Error(
"Cannot create a function from a program that does not eval to a function"
);
}
- return ((...args: any[]) =>
- callFn(programFn, args, emptyStackFrame)) as any;
+ return ((...args: any[]) => callFn(e, args, emptyStackFrame)) as any;
};