diff options
Diffstat (limited to 'js/baba-yaga/tests/interpreter-with-header.test.js')
-rw-r--r-- | js/baba-yaga/tests/interpreter-with-header.test.js | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/js/baba-yaga/tests/interpreter-with-header.test.js b/js/baba-yaga/tests/interpreter-with-header.test.js new file mode 100644 index 0000000..0f50be4 --- /dev/null +++ b/js/baba-yaga/tests/interpreter-with-header.test.js @@ -0,0 +1,90 @@ +import assert from 'assert'; +import { createLexer } from '../src/core/lexer.js'; +import { createParser } from '../src/core/parser.js'; +import { createInterpreter } from '../src/core/interpreter.js'; + +function interpret(code) { + const lexer = createLexer(code); + const tokens = lexer.allTokens(); + const parser = createParser(tokens); + const ast = parser.parse(); + const interpreter = createInterpreter(ast); + interpreter.interpret(); + return interpreter; +} + +describe('with header locals', () => { + it('evaluates untyped locals', () => { + const code = ` + addMul : x y -> with (inc : x + 1; prod : inc * y;) -> inc + prod; + r : addMul 2 5; + `; + const itp = interpret(code); + assert.strictEqual(itp.scope.get('r').value, (2+1) + ((2+1)*5)); + }); + + it('evaluates typed locals with validation', () => { + const code = ` + sumNext : (x: Int, y: Int) -> Int -> + with (nx Int; ny Int; nx : x + 1; ny : y + 1;) -> nx + ny; + r : sumNext 2 3; + `; + const itp = interpret(code); + assert.strictEqual(itp.scope.get('r').value, 7); + }); + + it('rejects typed local mismatch', () => { + const code = ` + bad : (x: Int) -> Int -> + with (s String; s : x + 1;) -> 0; + r : bad 2; + `; + assert.throws(() => interpret(code), /Type mismatch for s: expected String/); + }); + + it('works with when expressions', () => { + const code = ` + classify : n -> + with (lo Int; hi Int; lo : 10; hi : 100;) -> + when n is + 0 then "zero" + _ then when (n > hi) is + true then "large" + _ then when (n > lo) is + true then "medium" + _ then "small"; + a : classify 0; + b : classify 50; + c : classify 200; + `; + const itp = interpret(code); + assert.strictEqual(itp.scope.get('a'), 'zero'); + assert.strictEqual(itp.scope.get('b'), 'medium'); + assert.strictEqual(itp.scope.get('c'), 'large'); + }); + + it('supports with rec for mutual recursion', () => { + const code = ` + isEvenOdd : z -> + with rec ( + isEven : n -> when n is 0 then true _ then isOdd (n - 1); + isOdd : n -> when n is 0 then false _ then isEven (n - 1); + ) -> { e: isEven 10, o: isOdd 7 }; + r : isEvenOdd 0; + `; + const itp = interpret(code); + const r = itp.scope.get('r'); + assert.strictEqual(r.e, true); + assert.strictEqual(r.o, true); + }); + + it('errors if with rec binding is not a function', () => { + const code = ` + bad : z -> with rec (x : 1;) -> 0; + r : bad 0; + `; + assert.throws(() => interpret(code), /with rec expects function-valued bindings/); + }); +}); + + |