diff --git a/packages/mondo/mondo.mjs b/packages/mondo/mondo.mjs index 8db36bd5..705b9de9 100644 --- a/packages/mondo/mondo.mjs +++ b/packages/mondo/mondo.mjs @@ -331,6 +331,19 @@ export class MondoRunner { //console.log(printAst(ast)); return this.evaluate(ast, scope); } + evaluate_let(ast, scope) { + // (let ((x 3) (y 4)) ...body) + // = ((fn (x y) ...body) 3 4) + const defs = ast.children[1].children; + const args = defs.map((pair) => pair.children[0]); + const vals = defs.map((pair) => pair.children[1]); + const body = ast.children.slice(2); + const lambda = { + type: 'list', + children: [{ type: 'plain', value: 'fn' }, { type: 'list', children: args }, ...body], + }; + return this.evaluate({ type: 'list', children: [lambda, ...vals] }, scope); + } evaluate_def(ast, scope) { // function definition special form? if (ast.children[1].type === 'list') { @@ -441,6 +454,9 @@ export class MondoRunner { if (name === 'if') { return this.evaluate_if(ast, scope); } + if (name === 'let') { + return this.evaluate_let(ast, scope); + } if (name === 'def') { this.evaluate_def(ast, scope); } diff --git a/packages/mondo/test/mondo.test.mjs b/packages/mondo/test/mondo.test.mjs index 0fac441e..236fa291 100644 --- a/packages/mondo/test/mondo.test.mjs +++ b/packages/mondo/test/mondo.test.mjs @@ -610,4 +610,47 @@ describe('mondo arithmetic', () => { ), ).toEqual(0.24998750000000042)); it('sicp 84.1', () => expect(evaluate(`((fn (x y z) (+ x y (square z))) 1 2 3)`, scope)).toEqual(12)); + + // let expressions + it('sicp 87.1', () => + expect( + evaluate( + ` +(+ (let ((x 3)) +(+ x (* x 10))) x) +`, + { x: 5 }, + ), + ).toEqual(38)); + it('sicp 87.2', () => + expect( + evaluate( + ` +(let ((x 3) +(y (+ x 2))) +(* x y)) + `, + { x: 2 }, + ), + ).toEqual(12)); + it('sicp 88.1', () => + expect( + evaluate( + ` +(def (f g) (g 2)) +(f square) + `, + scope, + ), + ).toEqual(4)); + it('sicp 88.2', () => + expect( + evaluate( + ` +(def (f g) (g 2)) +(f (fn (z) (* z (+ z 1)))) + `, + scope, + ), + ).toEqual(6)); });