From f2372e7a415da0edce6d9460327d652a487e18ba Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 30 Mar 2025 17:55:37 +0200 Subject: [PATCH] mondo: refactor evaluate function into bits --- packages/mondo/README.md | 2 +- packages/mondo/mondo.mjs | 75 +++++++++++++++++------------- packages/mondo/test/mondo.test.mjs | 2 +- packages/mondough/mondough.mjs | 2 +- 4 files changed, 45 insertions(+), 36 deletions(-) diff --git a/packages/mondo/README.md b/packages/mondo/README.md index 47812e83d..d283ccf31 100644 --- a/packages/mondo/README.md +++ b/packages/mondo/README.md @@ -31,6 +31,6 @@ function evaluator(node) { } return fn(...args); } -const runner = new MondoRunner(evaluator); +const runner = new MondoRunner({ evaluator }); const pat = runner.run('add 1 (mul 2 PI)') // 7.283185307179586 ``` diff --git a/packages/mondo/mondo.mjs b/packages/mondo/mondo.mjs index 89236a3bb..e19116ae6 100644 --- a/packages/mondo/mondo.mjs +++ b/packages/mondo/mondo.mjs @@ -306,7 +306,7 @@ export function printAst(ast, compact = false, lvl = 0) { // lisp runner export class MondoRunner { - constructor(evaluator) { + constructor({ evaluator } = {}) { this.parser = new MondoParser(); this.evaluator = evaluator; this.assert(typeof evaluator === 'function', `expected an evaluator function to be passed to new MondoRunner`); @@ -322,43 +322,52 @@ export class MondoRunner { console.log(printAst(ast)); return this.evaluate(ast); } - evaluate(ast, scope = {}) { - if (ast.type !== 'list') { - // is leaf - if (ast.type === 'number') { - ast.value = Number(ast.value); - } else if (['quotes_double', 'quotes_single'].includes(ast.type)) { - ast.value = ast.value.slice(1, -1); - } - return this.evaluator(ast, scope); + evaluate_def(ast, scope) { + // (def name body) + if (ast.children.length !== 3) { + throw new Error(`expected "def" to have 3 children, but got ${ast.children.length}`); } - - if (ast.children[0]?.value === 'def') { - if (ast.children.length !== 3) { - throw new Error(`expected "def" to have 3 children, but got ${ast.children.length}`); - } - // (def myfn (fn (_) (ply 2 _))) - // ^name ^body - const name = ast.children[1].value; - const body = this.evaluate(ast.children[2], scope); - scope[name] = body; - return this.evaluator(ast, scope); - } - if (ast.children[0]?.value === 'fn') { - // (fn (_) (ply 2 _) - // ^args ^ body - const [_, args, body] = ast.children; - const argNames = args.children.map((child) => child.value); - return (x) => { - scope = { - [argNames[0]]: x, // TODO: merge scope... + support multiple args - }; - return this.evaluate(body, scope); + const name = ast.children[1].value; + const body = this.evaluate(ast.children[2], scope); + scope[name] = body; + return this.evaluator(ast, scope); + } + evaluate_lambda(ast, scope) { + // (fn (_) (ply 2 _) + // ^args ^ body + const [_, args, body] = ast.children; + const argNames = args.children.map((child) => child.value); + return (x) => { + scope = { + [argNames[0]]: x, // TODO: merge scope... + support multiple args }; - } + return this.evaluate(body, scope); + }; + } + evaluate_list(ast, scope) { // evaluate all children before evaluating list (dont mutate!!!) const args = ast.children.map((arg) => this.evaluate(arg, scope)); const node = { type: 'list', children: args }; return this.evaluator(node, scope); } + evaluate_leaf(ast, scope) { + if (ast.type === 'number') { + ast.value = Number(ast.value); + } else if (['quotes_double', 'quotes_single'].includes(ast.type)) { + ast.value = ast.value.slice(1, -1); + } + return this.evaluator(ast, scope); + } + evaluate(ast, scope = {}) { + if (ast.type !== 'list') { + return this.evaluate_leaf(ast, scope); + } + if (ast.children[0]?.value === 'def') { + return this.evaluate_def(ast, scope); + } + if (ast.children[0]?.value === 'fn') { + return this.evaluate_lambda(ast, scope); + } + return this.evaluate_list(ast, scope); + } } diff --git a/packages/mondo/test/mondo.test.mjs b/packages/mondo/test/mondo.test.mjs index 47e0e165d..6f8090cc5 100644 --- a/packages/mondo/test/mondo.test.mjs +++ b/packages/mondo/test/mondo.test.mjs @@ -150,6 +150,6 @@ describe('mondo arithmetic', () => { } return fn(...args); } - const runner = new MondoRunner(evaluator); + const runner = new MondoRunner({ evaluator }); it('should desugar (.)', () => expect(runner.run('add 1 (mul 2 PI)').toFixed(2)).toEqual('7.28')); }); diff --git a/packages/mondough/mondough.mjs b/packages/mondough/mondough.mjs index 543dcfeb2..effaf367c 100644 --- a/packages/mondough/mondough.mjs +++ b/packages/mondough/mondough.mjs @@ -87,7 +87,7 @@ function evaluator(node, scope) { return pat; } -let runner = new MondoRunner(evaluator); +let runner = new MondoRunner({ evaluator }); export function mondo(code, offset = 0) { if (Array.isArray(code)) {