diff options
Diffstat (limited to 'js/baba-yaga/tests/recursive_functions.test.js')
-rw-r--r-- | js/baba-yaga/tests/recursive_functions.test.js | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/js/baba-yaga/tests/recursive_functions.test.js b/js/baba-yaga/tests/recursive_functions.test.js new file mode 100644 index 0000000..a2380ef --- /dev/null +++ b/js/baba-yaga/tests/recursive_functions.test.js @@ -0,0 +1,223 @@ +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'; + +describe('Recursive Function Calls', () => { + 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(); // Execute the code + return interpreter; // Return the interpreter instance to access scope + } + + it('should correctly handle simple function calls', () => { + const code = ` + simpleFunc : n -> n + 1; + result : simpleFunc 5; + `; + + const interpreter = interpret(code); + const result = interpreter.scope.get('result'); + assert.strictEqual(result.value, 6); + }); + + it('should correctly handle when expressions', () => { + const code = ` + checkNumber : num -> + when num is + 1 then "One" + 2 then "Two" + _ then "Something else"; + result : checkNumber 3; + `; + + const interpreter = interpret(code); + assert.strictEqual(interpreter.scope.get('result'), 'Something else'); + }); + + it('should correctly compute factorial recursively', () => { + const code = ` + factorial : n -> + when n is + 0 then 1 + 1 then 1 + _ then n * (factorial (n - 1)); + + result1 : factorial 0; + result2 : factorial 1; + result3 : factorial 5; + result4 : factorial 6; + `; + + const interpreter = interpret(code); + const result1 = interpreter.scope.get('result1'); + const result2 = interpreter.scope.get('result2'); + const result3 = interpreter.scope.get('result3'); + const result4 = interpreter.scope.get('result4'); + assert.strictEqual(result1.value, 1); + assert.strictEqual(result2.value, 1); + assert.strictEqual(result3.value, 120); // 5! = 120 + assert.strictEqual(result4.value, 720); // 6! = 720 + }); + + it('should correctly compute Fibonacci numbers recursively', () => { + const code = ` + fib : n -> + when n is + 0 then 0 + 1 then 1 + _ then (fib (n - 1)) + (fib (n - 2)); + + fib0 : fib 0; + fib1 : fib 1; + fib2 : fib 2; + fib3 : fib 3; + fib4 : fib 4; + fib5 : fib 5; + fib6 : fib 6; + `; + + const interpreter = interpret(code); + const fib0 = interpreter.scope.get('fib0'); + const fib1 = interpreter.scope.get('fib1'); + const fib2 = interpreter.scope.get('fib2'); + const fib3 = interpreter.scope.get('fib3'); + const fib4 = interpreter.scope.get('fib4'); + const fib5 = interpreter.scope.get('fib5'); + const fib6 = interpreter.scope.get('fib6'); + assert.strictEqual(fib0.value, 0); + assert.strictEqual(fib1.value, 1); + assert.strictEqual(fib2.value, 1); + assert.strictEqual(fib3.value, 2); + assert.strictEqual(fib4.value, 3); + assert.strictEqual(fib5.value, 5); + assert.strictEqual(fib6.value, 8); + }); + + it('should correctly compute sum of digits recursively', () => { + const code = ` + sumDigits : n -> + when n is + 0 then 0 + _ then (n % 10) + (sumDigits ((n - (n % 10)) / 10)); + + result1 : sumDigits 123; + result2 : sumDigits 456; + result3 : sumDigits 999; + `; + + const interpreter = interpret(code); + const result1 = interpreter.scope.get('result1'); + const result2 = interpreter.scope.get('result2'); + const result3 = interpreter.scope.get('result3'); + assert.strictEqual(result1.value, 6); + assert.strictEqual(result2.value, 15); + assert.strictEqual(result3.value, 27); + }); + + it('should correctly compute power recursively', () => { + const code = ` + power : base exp -> + when exp is + 0 then 1 + 1 then base + _ then base * (power base (exp - 1)); + + result1 : power 2 0; + result2 : power 2 1; + result3 : power 2 3; + result4 : power 3 4; + result5 : power 5 2; + `; + + const interpreter = interpret(code); + const result1 = interpreter.scope.get('result1'); + const result2 = interpreter.scope.get('result2'); + const result3 = interpreter.scope.get('result3'); + const result4 = interpreter.scope.get('result4'); + const result5 = interpreter.scope.get('result5'); + assert.strictEqual(result1.value, 1); + assert.strictEqual(result2.value, 2); + assert.strictEqual(result3.value, 8); // 2^3 = 8 + assert.strictEqual(result4.value, 81); // 3^4 = 81 + assert.strictEqual(result5.value, 25); // 5^2 = 25 + }); + + it('should correctly compute greatest common divisor recursively', () => { + const code = ` + gcd : a b -> + when b is + 0 then a + _ then gcd b (a % b); + + result1 : gcd 48 18; + result2 : gcd 54 24; + result3 : gcd 7 13; + result4 : gcd 100 25; + `; + + const interpreter = interpret(code); + const result1 = interpreter.scope.get('result1'); + const result2 = interpreter.scope.get('result2'); + const result3 = interpreter.scope.get('result3'); + const result4 = interpreter.scope.get('result4'); + assert.strictEqual(result1.value, 6); + assert.strictEqual(result2.value, 6); + assert.strictEqual(result3.value, 1); + assert.strictEqual(result4.value, 25); + }); + + it('should handle mutual recursion correctly', () => { + const code = ` + isEven : n -> + when n is + 0 then true + 1 then false + _ then isOdd (n - 1); + + isOdd : n -> + when n is + 0 then false + 1 then true + _ then isEven (n - 1); + + result1 : isEven 0; + result2 : isEven 1; + result3 : isEven 2; + result4 : isEven 3; + result5 : isOdd 0; + result6 : isOdd 1; + result7 : isOdd 2; + result8 : isOdd 3; + `; + + const interpreter = interpret(code); + assert.strictEqual(interpreter.scope.get('result1'), true); + assert.strictEqual(interpreter.scope.get('result2'), false); + assert.strictEqual(interpreter.scope.get('result3'), true); + assert.strictEqual(interpreter.scope.get('result4'), false); + assert.strictEqual(interpreter.scope.get('result5'), false); + assert.strictEqual(interpreter.scope.get('result6'), true); + assert.strictEqual(interpreter.scope.get('result7'), false); + assert.strictEqual(interpreter.scope.get('result8'), true); + }); + + it('should handle deep recursion without stack overflow', () => { + const code = ` + countDown : n -> + when n is + 0 then 0 + _ then 1 + (countDown (n - 1)); + + result : countDown 100; + `; + + const interpreter = interpret(code); + const result = interpreter.scope.get('result'); + assert.strictEqual(result.value, 100); + }); +}); \ No newline at end of file |