about summary refs log tree commit diff stats
path: root/js/baba-yaga/tests/recursive_functions.test.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/baba-yaga/tests/recursive_functions.test.js')
-rw-r--r--js/baba-yaga/tests/recursive_functions.test.js223
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