summaryrefslogtreecommitdiff
path: root/static/js/lang.js
diff options
context:
space:
mode:
Diffstat (limited to 'static/js/lang.js')
-rw-r--r--static/js/lang.js24
1 files changed, 23 insertions, 1 deletions
diff --git a/static/js/lang.js b/static/js/lang.js
index 50fe098..92ff133 100644
--- a/static/js/lang.js
+++ b/static/js/lang.js
@@ -565,6 +565,18 @@ class Environment {
}
return rv;
}
+ addClosure(node, closure) {
+ if (Array.isArray(node)) {
+ for (let i = 0; i < node.length; ++i)
+ node[i] = this.addClosure(node[i], closure);
+ } else if (typeof node === "object") {
+ for (let key of Object.keys(node).filter((key) => key != "closure")) {
+ node[key] = this.addClosure(node[key], closure);
+ node.closure = closure;
+ }
+ }
+ return node;
+ }
eval(node) {
const scope = this.scopes[this.scopes.length - 1];
@@ -574,7 +586,10 @@ class Environment {
case N.BoolLiteral:
return node.val;
case N.FnDecl: {
- scope[node.name] = node;
+ node.closure = _.cloneDeep({ ...node.closure, ...scope });
+ node.body = this.addClosure(node.body, node.closure);
+
+ scope[node.name] = _.cloneDeep(node);
return node;
}
case N.FnCall: {
@@ -610,6 +625,13 @@ class Environment {
}
i --;
}
+ if (node.closure && node.closure.hasOwnProperty(node.val)) {
+ const val = node.closure[node.val];
+ if (typeof val === "object") {
+ return this.eval(val);
+ }
+ return val;
+ }
throw new Error(`Runtime error: Undefined variable "${node.val}"`);
}
case N.Assignment: {