about summary refs log tree commit diff stats
path: root/js/baba-yaga/tests/with-advanced-patterns.test.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/baba-yaga/tests/with-advanced-patterns.test.js')
-rw-r--r--js/baba-yaga/tests/with-advanced-patterns.test.js290
1 files changed, 290 insertions, 0 deletions
diff --git a/js/baba-yaga/tests/with-advanced-patterns.test.js b/js/baba-yaga/tests/with-advanced-patterns.test.js
new file mode 100644
index 0000000..2ea2d44
--- /dev/null
+++ b/js/baba-yaga/tests/with-advanced-patterns.test.js
@@ -0,0 +1,290 @@
+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: advanced patterns', () => {
+  it('handles empty with blocks', () => {
+    const code = `
+      testEmptyWith : x ->
+        with () -> x;
+      result : testEmptyWith 42;
+    `;
+    const itp = interpret(code);
+    assert.strictEqual(itp.scope.get('result').value, 42);
+  });
+
+  it('handles single entry with blocks', () => {
+    const code = `
+      testSingleEntry : x ->
+        with (value : x + 1;) -> value;
+      result : testSingleEntry 5;
+    `;
+    const itp = interpret(code);
+    assert.strictEqual(itp.scope.get('result').value, 6);
+  });
+
+  it('handles complex dependencies between entries', () => {
+    const code = `
+      testDependencies : x y ->
+        with (
+          a : x + y;
+          b : a * 2;
+          c : b - x;
+          d : c + a;
+          e : d * b;
+        ) -> e;
+      result : testDependencies 3 4;
+    `;
+    const itp = interpret(code);
+    // a = 3 + 4 = 7
+    // b = 7 * 2 = 14
+    // c = 14 - 3 = 11
+    // d = 11 + 7 = 18
+    // e = 18 * 14 = 252
+    assert.strictEqual(itp.scope.get('result').value, 252);
+  });
+
+  it('handles deep nesting of when expressions beyond 4 levels', () => {
+    const code = `
+      testDeepNesting : x ->
+        with (
+          level1 : when x is
+            0 then "zero"
+            _ then when (x < 5) is
+              true then "small"
+              _ then when (x < 10) is
+                true then "medium"
+                _ then when (x < 20) is
+                  true then "large"
+                  _ then when (x < 50) is
+                    true then "huge"
+                    _ then when (x < 100) is
+                      true then "massive"
+                      _ then "gigantic";
+        ) -> level1;
+      result1 : testDeepNesting 0;
+      result2 : testDeepNesting 3;
+      result3 : testDeepNesting 7;
+      result4 : testDeepNesting 15;
+      result5 : testDeepNesting 30;
+      result6 : testDeepNesting 70;
+      result7 : testDeepNesting 150;
+    `;
+    const itp = interpret(code);
+    assert.strictEqual(itp.scope.get('result1'), 'zero');
+    assert.strictEqual(itp.scope.get('result2'), 'small');
+    assert.strictEqual(itp.scope.get('result3'), 'medium');
+    assert.strictEqual(itp.scope.get('result4'), 'large');
+    assert.strictEqual(itp.scope.get('result5'), 'huge');
+    assert.strictEqual(itp.scope.get('result6'), 'massive');
+    assert.strictEqual(itp.scope.get('result7'), 'gigantic');
+  });
+
+  it('handles mixed types in with blocks', () => {
+    const code = `
+      testMixedTypes : x ->
+        with (
+          num Int; num : x + 1;
+          str String; str : str.concat "Value: " "number";
+          isValid Bool; isValid : x > 0;
+          list List; list : [x, x * 2, x * 3];
+          table Table; table : { value: x, doubled: x * 2 };
+        ) -> { num: num, str: str, isValid: isValid, list: list, table: table };
+      result : testMixedTypes 10;
+    `;
+    const itp = interpret(code);
+    const result = itp.scope.get('result');
+    assert.strictEqual(result.num.value, 11);
+    assert.strictEqual(result.str, 'Value: number');
+    assert.strictEqual(result.isValid, true);
+            assert.deepStrictEqual(result.list.map(x => x.value), [10, 20, 30]);
+            // Baba Yaga objects have properties Map structure
+        assert.strictEqual(result.table.properties.get('value').value, 10);
+        assert.strictEqual(result.table.properties.get('doubled').value, 20);
+  });
+
+  it('handles recursive with rec with complex functions', () => {
+    const code = `
+      testComplexRecursive : n ->
+        with rec (
+          factorial : x ->
+            when x is
+              0 then 1
+              _ then x * (factorial (x - 1));
+          
+          fibonacci : x ->
+            when x is
+              0 then 0
+              1 then 1
+              _ then (fibonacci (x - 1)) + (fibonacci (x - 2));
+          
+          ackermann : m n ->
+            when m is
+              0 then n + 1
+              _ then when n is
+                0 then ackermann (m - 1) 1
+                _ then ackermann (m - 1) (ackermann m (n - 1));
+        ) -> { fact: factorial n, fib: fibonacci n, ack: ackermann 2 3 };
+      result : testComplexRecursive 5;
+    `;
+    const itp = interpret(code);
+    const result = itp.scope.get('result');
+    assert.strictEqual(result.fact.value, 120);  // 5! = 120
+    assert.strictEqual(result.fib.value, 5);    // fib(5) = 5
+    assert.strictEqual(result.ack.value, 9);    // ack(2,3) = 9
+  });
+
+  it('handles complex mathematical expressions with type validation', () => {
+    const code = `
+      testComplexMath : x y z ->
+        with (
+          a : x * x;
+          b : y * y;
+          c : z * z;
+          sumSquares : a + b;
+          hypotenuse : math.sqrt sumSquares;
+          result : hypotenuse + (math.sqrt (a + b + c));
+        ) -> result;
+      result : testComplexMath 3 4 5;
+    `;
+    const itp = interpret(code);
+    const result = itp.scope.get('result');
+    // a = 3² = 9, b = 4² = 16, c = 5² = 25
+    // sumSquares = 9 + 16 = 25
+    // hypotenuse = √25 = 5
+    // result = 5 + √(9 + 16 + 25) = 5 + √50 = 5 + 7.07... ≈ 12.07
+    assert(Math.abs(result.value - 12.07) < 0.1);
+  });
+
+  it('handles string operations with type validation', () => {
+    const code = `
+      testStringOps : input ->
+        with (
+          length : str.length input;
+          trimmed : str.trim input;
+          upper : str.upper input;
+          isEmpty : length = 0;
+          hasContent : length > 0;
+          description : str.concat "Length: " (when (length > 10) is true then "long" _ then "short");
+        ) -> {
+          length: length,
+          trimmed: trimmed,
+          upper: upper,
+          isEmpty: isEmpty,
+          hasContent: hasContent,
+          description: description
+        };
+      result : testStringOps "  Hello World  ";
+    `;
+    const itp = interpret(code);
+    const result = itp.scope.get('result');
+    assert.strictEqual(result.length.value, 15);
+    assert.strictEqual(result.trimmed, 'Hello World');
+    assert.strictEqual(result.upper, '  HELLO WORLD  ');
+    assert.strictEqual(result.isEmpty, false);
+    assert.strictEqual(result.hasContent, true);
+    assert.strictEqual(result.description, 'Length: long');
+  });
+
+  it('handles list and table edge cases with type validation', () => {
+    const code = `
+      testListTableEdgeCases : items ->
+        with (
+          count : length items;
+          isEmpty : count = 0;
+          hasItems : count > 0;
+          firstItem : when count is
+            0 then "none"
+            _ then items.0;
+          lastItem : when count is
+            0 then "none"
+            _ then when count is
+              1 then items.0
+              _ then when count is
+                2 then items.1
+                _ then when count is
+                  3 then items.2
+                  _ then "many";
+          summary : {
+            count: count,
+            empty: isEmpty,
+            hasItems: hasItems,
+            first: firstItem,
+            last: lastItem
+          };
+        ) -> summary;
+      result1 : testListTableEdgeCases [];
+      result2 : testListTableEdgeCases [42];
+      result3 : testListTableEdgeCases [1, 2];
+      result4 : testListTableEdgeCases [10, 20, 30];
+    `;
+    const itp = interpret(code);
+    const result1 = itp.scope.get('result1');
+    const result2 = itp.scope.get('result2');
+    const result3 = itp.scope.get('result3');
+    const result4 = itp.scope.get('result4');
+    
+    assert.strictEqual(result1.count.value, 0);
+    assert.strictEqual(result1.empty, true);
+    assert.strictEqual(result1.hasItems, false);
+    assert.strictEqual(result1.first, 'none');
+    assert.strictEqual(result1.last, 'none');
+    
+    assert.strictEqual(result2.count.value, 1);
+    assert.strictEqual(result2.empty, false);
+    assert.strictEqual(result2.hasItems, true);
+    assert.strictEqual(result2.first.value, 42);
+    assert.strictEqual(result2.last.value, 42);
+    
+    assert.strictEqual(result3.count.value, 2);
+    assert.strictEqual(result3.empty, false);
+    assert.strictEqual(result3.hasItems, true);
+    assert.strictEqual(result3.first.value, 1);
+    assert.strictEqual(result3.last.value, 2);
+    
+    assert.strictEqual(result4.count.value, 3);
+    assert.strictEqual(result4.empty, false);
+    assert.strictEqual(result4.hasItems, true);
+    assert.strictEqual(result4.first.value, 10);
+    assert.strictEqual(result4.last.value, 30);  // items.2 when count is 3
+  });
+
+  it('handles error handling edge cases', () => {
+    const code = `
+      testErrorHandling : x ->
+        with (
+          isValid : x >= 0;
+          safeValue : when isValid is
+            true then x
+            _ then 0;
+          result : when isValid is
+            true then { value: safeValue, status: "valid" }
+            _ then { value: safeValue, status: "invalid", error: "negative value" };
+        ) -> result;
+      result1 : testErrorHandling 5;
+      result2 : testErrorHandling -3;
+    `;
+    const itp = interpret(code);
+    const result1 = itp.scope.get('result1');
+    const result2 = itp.scope.get('result2');
+    
+    assert.strictEqual(result1.properties.get('value').value, 5);
+    assert.strictEqual(result1.properties.get('status'), 'valid');
+    assert.strictEqual(result1.properties.get('error'), undefined);
+    
+    assert.strictEqual(result2.properties.get('value').value, 0);
+    assert.strictEqual(result2.properties.get('status'), 'invalid');
+    assert.strictEqual(result2.properties.get('error'), 'negative value');
+  });
+});