From 560ca09223284abc7f8ab4840adfbc2cbc73177a Mon Sep 17 00:00:00 2001 From: "Elizabeth (Lizzy) Hunt" Date: Sat, 22 Apr 2023 23:42:19 -0600 Subject: Closure (#1) * Add 'closures' and sample programs, lodash too * Remove prettier garbage --- static/js/lang.js | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'static/js/lang.js') 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: { -- cgit v1.2.3-70-g09d2