diff options
Diffstat (limited to 'static/js/lang.js')
-rw-r--r-- | static/js/lang.js | 24 |
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: { |