about summary refs log tree commit diff stats
path: root/js/baba-yaga/tests
diff options
context:
space:
mode:
Diffstat (limited to 'js/baba-yaga/tests')
-rw-r--r--js/baba-yaga/tests/arrow_functions.test.js99
-rw-r--r--js/baba-yaga/tests/data_structures.test.js211
-rw-r--r--js/baba-yaga/tests/functional-enhancements.test.js649
-rw-r--r--js/baba-yaga/tests/interpreter-with-header.test.js90
-rw-r--r--js/baba-yaga/tests/js-interop.test.js407
-rw-r--r--js/baba-yaga/tests/language_features.test.js450
-rw-r--r--js/baba-yaga/tests/logical_operators.test.js85
-rw-r--r--js/baba-yaga/tests/math_namespace.test.js112
-rw-r--r--js/baba-yaga/tests/parser-with-header.test.js36
-rw-r--r--js/baba-yaga/tests/recursive_functions.test.js223
-rw-r--r--js/baba-yaga/tests/turing_completeness.test.js270
-rw-r--r--js/baba-yaga/tests/typed_curried_functions.test.js222
-rw-r--r--js/baba-yaga/tests/utilities.test.js278
-rw-r--r--js/baba-yaga/tests/with-advanced-patterns.test.js290
-rw-r--r--js/baba-yaga/tests/with-type-system-edge-cases.test.js223
-rw-r--r--js/baba-yaga/tests/with-when-expressions.test.js158
16 files changed, 3803 insertions, 0 deletions
diff --git a/js/baba-yaga/tests/arrow_functions.test.js b/js/baba-yaga/tests/arrow_functions.test.js
new file mode 100644
index 0000000..d6a8aee
--- /dev/null
+++ b/js/baba-yaga/tests/arrow_functions.test.js
@@ -0,0 +1,99 @@
+const assert = require('assert');
+const { createLexer } = require('../src/core/lexer');
+const { createParser } = require('../src/core/parser');
+const { createInterpreter } = require('../src/core/interpreter');
+
+describe('Arrow Functions in Table Literals', () => {
+  function interpret(code) {
+    const lexer = createLexer(code);
+    const tokens = lexer.allTokens();
+    const parser = createParser(tokens);
+    const ast = parser.parse();
+    const interpreter = createInterpreter(ast);
+    return interpreter.interpret();
+  }
+
+  it('should correctly parse and execute single arrow function in table', () => {
+    const code = `calculator : {
+  add: x y -> x + y;
+};
+result : calculator.add 5 3;
+result`;
+    
+    const result = interpret(code);
+    assert.strictEqual(result.value, 8);
+    assert.strictEqual(result.isFloat, false);
+  });
+
+  it('should correctly handle arrow function with single parameter', () => {
+    const code = `calculator : {
+  double: x -> x * 2;
+};
+result : calculator.double 5;
+result`;
+    
+    const result = interpret(code);
+    assert.strictEqual(result.value, 10);
+    assert.strictEqual(result.isFloat, false);
+  });
+
+  it('should correctly handle arrow function with complex body', () => {
+    const code = `calculator : {
+  complex: x y -> (x + y) * (x - y);
+};
+result : calculator.complex 5 3;
+result`;
+    
+    const result = interpret(code);
+    assert.strictEqual(result.value, 16);
+    assert.strictEqual(result.isFloat, false);
+  });
+
+  it('should correctly handle arrow function with parentheses for precedence', () => {
+    const code = `calculator : {
+  multiply: x y -> x * (y + 1);
+};
+result : calculator.multiply 3 2;
+result`;
+    
+    const result = interpret(code);
+    assert.strictEqual(result.value, 9);
+    assert.strictEqual(result.isFloat, false);
+  });
+
+  it('should correctly handle multiple arrow functions in table', () => {
+    const code = `calculator : {
+  add: x y -> x + y;
+  subtract: x y -> x - y;
+  multiply: x y -> x * (y + 1);
+  complex: x y -> (x + y) * (x - y);
+};
+result1 : calculator.add 5 3;
+result2 : calculator.subtract 10 4;
+result3 : calculator.multiply 3 2;
+result4 : calculator.complex 5 3;
+result1`;
+    
+    const result = interpret(code);
+    assert.strictEqual(result.value, 8);
+    assert.strictEqual(result.isFloat, false);
+  });
+
+  it('should correctly handle arrow functions with different parameter counts', () => {
+    const code = `calculator : {
+  add: x y -> x + y;
+  double: x -> x * 2;
+  identity: x -> x;
+  constant: -> 42;
+};
+result1 : calculator.add 5 3;
+result2 : calculator.double 7;
+result3 : calculator.identity 99;
+result4 : calculator.constant;
+result1`;
+    
+    const result = interpret(code);
+    assert.strictEqual(result.value, 8);
+    assert.strictEqual(result.isFloat, false);
+  });
+}); 
\ No newline at end of file
diff --git a/js/baba-yaga/tests/data_structures.test.js b/js/baba-yaga/tests/data_structures.test.js
new file mode 100644
index 0000000..f22fb82
--- /dev/null
+++ b/js/baba-yaga/tests/data_structures.test.js
@@ -0,0 +1,211 @@
+const assert = require('assert');
+const { createLexer } = require('../src/core/lexer');
+const { createParser } = require('../src/core/parser');
+const { createInterpreter } = require('../src/core/interpreter');
+
+describe('Data Structures and Higher-Order Functions', () => {
+  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 interpret list literals', () => {
+    const code = 'myList : [1, 2, 3];';
+    const interpreter = interpret(code);
+    const myList = interpreter.scope.get('myList');
+    assert.deepStrictEqual(myList.map(item => item.value), [1, 2, 3]);
+  });
+
+  it('should correctly interpret table literals', () => {
+    const code = 'myTable : { name: "Alice" age: 30 };';
+    const interpreter = interpret(code);
+    const expectedTable = { type: 'Object', properties: new Map([['name', 'Alice'], ['age', { value: 30, isFloat: false }]]) };
+    const actualTable = interpreter.scope.get('myTable');
+    assert.strictEqual(actualTable.type, expectedTable.type);
+    assert.deepStrictEqual(Array.from(actualTable.properties.entries()), Array.from(expectedTable.properties.entries()));
+  });
+
+  it('should correctly access list elements using dot notation', () => {
+    const code = 'myList : [10, 20, 30];\nio.out myList.1;';
+    // For io.out, we need to capture console.log output. This test will pass if no error is thrown.
+    // A more robust test would mock console.log.
+    assert.doesNotThrow(() => interpret(code));
+  });
+
+  it('should correctly access table properties using dot notation', () => {
+    const code = 'myTable : { name: "Bob", age: 25 };\nio.out myTable.name;';
+    assert.doesNotThrow(() => interpret(code));
+  });
+
+  it('should correctly interpret anonymous functions', () => {
+    const code = 'myFunc : (x -> x + 1);\nio.out (myFunc 5);';
+    assert.doesNotThrow(() => interpret(code));
+  });
+
+  it('should correctly apply map to a list', () => {
+    const code = 'io.out (map (x -> x * 2) [1, 2, 3]);';
+    assert.doesNotThrow(() => interpret(code));
+  });
+
+  it('should correctly apply filter to a list', () => {
+    const code = 'io.out (filter (x -> x > 2) [1, 2, 3, 4, 5]);';
+    assert.doesNotThrow(() => interpret(code));
+  });
+
+  it('should correctly apply reduce to a list', () => {
+    const code = 'io.out (reduce (acc item -> acc + item) 0 [1, 2, 3, 4]);';
+    assert.doesNotThrow(() => interpret(code));
+  });
+
+  it('should compose functions with reduce (composeAll) and accept list literal as argument', () => {
+    const code = `
+      composeAll : funcs ->
+        reduce (acc fn -> (x -> acc (fn x))) (x -> x) funcs;
+
+      inc    : x -> x + 1;
+      double : x -> x * 2;
+
+      combo : composeAll [inc, double];
+      res   : combo 3;
+    `;
+    const interpreter = interpret(code);
+    const res = interpreter.scope.get('res');
+    assert.strictEqual(res.value, 7);
+  });
+
+  // New tests for list and table pattern matching
+  it('should correctly match a list literal in a when expression', () => {
+    const code = `
+      myList : [1, 2, 3];
+      result : when myList is
+        [1, 2, 3] then "Matched List"
+        _       then "Did Not Match";
+    `;
+    const interpreter = interpret(code);
+    assert.strictEqual(interpreter.scope.get('result'), 'Matched List');
+  });
+
+  it('should correctly match a list with a wildcard in a when expression', () => {
+    const code = `
+      myList : [1, 2, 3];
+      result : when myList is
+        [1, _, 3] then "Matched Wildcard List"
+        _       then "Did Not Match";
+    `;
+    const interpreter = interpret(code);
+    assert.strictEqual(interpreter.scope.get('result'), 'Matched Wildcard List');
+  });
+
+  it('should correctly match a table literal in a when expression', () => {
+    const code = `
+      myTable : { a: 1, b: 2 };
+      result : when myTable is
+        { a: 1, b: 2 } then "Matched Table"
+        _            then "Did Not Match";
+    `;
+    const interpreter = interpret(code);
+    assert.strictEqual(interpreter.scope.get('result'), 'Matched Table');
+  });
+
+  it('should correctly match a table with a wildcard value in a when expression', () => {
+    const code = `
+      myTable : { a: 1, b: 2 };
+      result : when myTable is
+        { a: 1, b: _ } then "Matched Wildcard Table"
+        _            then "Did Not Match";
+    `;
+    const interpreter = interpret(code);
+    assert.strictEqual(interpreter.scope.get('result'), 'Matched Wildcard Table');
+  });
+
+  it('should correctly call a function defined within a table', () => {
+    const code = `
+      myCalculator : {
+        add: x y -> x + y,
+        subtract: x y -> x - y
+      };
+      resultAdd : myCalculator.add 10 5;
+      resultSubtract : myCalculator.subtract 10 5;
+    `;
+    const interpreter = interpret(code);
+    const resultAdd = interpreter.scope.get('resultAdd');
+    const resultSubtract = interpreter.scope.get('resultSubtract');
+    assert.strictEqual(resultAdd.value, 15);
+    assert.strictEqual(resultSubtract.value, 5);
+  });
+
+  it('should allow both direct and Map-based property access on tables', () => {
+    const code = `
+      myObj : { x: 42, y: "ok" };
+    `;
+    const interpreter = interpret(code);
+    const obj = interpreter.scope.get('myObj');
+    // direct access via proxy
+    assert.strictEqual(obj.x.value, 42);
+    assert.strictEqual(obj.y, 'ok');
+    // map-based access remains available
+    assert.strictEqual(obj.properties.get('x').value, 42);
+    assert.strictEqual(obj.properties.get('y'), 'ok');
+  });
+
+  it('should return shape metadata for lists, strings, tables, and scalars', () => {
+    const code = `
+      lst : [10, 20, 30];
+      str : "abc";
+      tbl : { a: 1, b: 2 };
+      n   : 42;
+
+      sLst : shape lst;
+      sStr : shape str;
+      sTbl : shape tbl;
+      sNum : shape n;
+    `;
+    const interpreter = interpret(code);
+    const sLst = interpreter.scope.get('sLst');
+    const sStr = interpreter.scope.get('sStr');
+    const sTbl = interpreter.scope.get('sTbl');
+    const sNum = interpreter.scope.get('sNum');
+
+    // List
+    assert.strictEqual(sLst.kind, 'List');
+    assert.strictEqual(sLst.rank.value, 1);
+    assert.strictEqual(sLst.size.value, 3);
+    assert.strictEqual(sLst.shape[0].value, 3);
+
+    // String
+    assert.strictEqual(sStr.kind, 'String');
+    assert.strictEqual(sStr.rank.value, 1);
+    assert.strictEqual(sStr.size.value, 3);
+    assert.strictEqual(sStr.shape[0].value, 3);
+
+    // Table
+    assert.strictEqual(sTbl.kind, 'Table');
+    assert.strictEqual(sTbl.rank.value, 1);
+    assert.strictEqual(sTbl.size.value, 2);
+    assert.strictEqual(sTbl.shape[0].value, 2);
+    // keys array contains 'a' and 'b' (order not enforced here)
+    const keys = new Set(sTbl.keys);
+    assert.strictEqual(keys.has('a') && keys.has('b'), true);
+
+    // Scalar
+    assert.strictEqual(sNum.kind, 'Scalar');
+    assert.strictEqual(sNum.rank.value, 0);
+    assert.strictEqual(Array.isArray(sNum.shape) && sNum.shape.length === 0, true);
+    assert.strictEqual(sNum.size.value, 1);
+  });
+
+  it('should correctly handle a wildcard pattern in a when expression for tables', () => {
+    const code = `
+      myTable : { a: 1 b: 2 };
+      result : when myTable is
+        _ then "Wildcard Match";
+    `;
+    const interpreter = interpret(code);
+    assert.strictEqual(interpreter.scope.get('result'), 'Wildcard Match');
+  });
+});
\ No newline at end of file
diff --git a/js/baba-yaga/tests/functional-enhancements.test.js b/js/baba-yaga/tests/functional-enhancements.test.js
new file mode 100644
index 0000000..59cabf4
--- /dev/null
+++ b/js/baba-yaga/tests/functional-enhancements.test.js
@@ -0,0 +1,649 @@
+import { createLexer } from '../src/core/lexer.js';
+import { createParser } from '../src/core/parser.js';
+import { createInterpreter } from '../src/core/interpreter.js';
+
+function runBabaYaga(code) {
+  const lexer = createLexer(code);
+  const tokens = lexer.allTokens();
+  const parser = createParser(tokens);
+  const ast = parser.parse();
+  
+  const outputs = [];
+  const debugOutputs = [];
+  
+  const host = {
+    io: {
+      out: (...args) => outputs.push(args.join(' ')),
+      debug: (...args) => debugOutputs.push(args.join(' ')),
+      in: () => '',
+    },
+  };
+  
+  const interpreter = createInterpreter(ast, host);
+  const result = interpreter.interpret();
+  
+  return { outputs, debugOutputs, result };
+}
+
+describe('Functional Programming Enhancements', () => {
+  
+  describe('Scan Operations', () => {
+    test('scan with addition function', () => {
+      const code = `
+        addFunc : acc x -> acc + x;
+        numbers : [1, 2, 3, 4, 5];
+        result : scan addFunc 0 numbers;
+        io.out result;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('0,1,3,6,10,15');
+    });
+
+    test('cumsum utility function', () => {
+      const code = `
+        numbers : [1, 2, 3, 4, 5];
+        result : cumsum numbers;
+        io.out result;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('0,1,3,6,10,15');
+    });
+
+    test('cumprod utility function', () => {
+      const code = `
+        numbers : [1, 2, 3, 4];
+        result : cumprod numbers;
+        io.out result;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('1,1,2,6,24');
+    });
+
+    test('scan with multiplication function', () => {
+      const code = `
+        mulFunc : acc x -> acc * x;
+        numbers : [2, 3, 4];
+        result : scan mulFunc 1 numbers;
+        io.out result;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('1,2,6,24');
+    });
+  });
+
+  describe('Array Indexing Operations', () => {
+    test('at function selects elements at indices', () => {
+      const code = `
+        data : [10, 20, 30, 40, 50];
+        indices : [0, 2, 4];
+        result : at indices data;
+        io.out result;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('10,30,50');
+    });
+
+    test('where function finds matching indices', () => {
+      const code = `
+        data : [10, 21, 30, 43, 50];
+        evenPredicate : x -> x % 2 = 0;
+        result : where evenPredicate data;
+        io.out result;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('0,2,4');
+    });
+
+    test('take function gets first n elements', () => {
+      const code = `
+        data : [1, 2, 3, 4, 5, 6];
+        result : take 3 data;
+        io.out result;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('1,2,3');
+    });
+
+    test('drop function removes first n elements', () => {
+      const code = `
+        data : [1, 2, 3, 4, 5, 6];
+        result : drop 3 data;
+        io.out result;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('4,5,6');
+    });
+
+    test('at with empty indices returns empty array', () => {
+      const code = `
+        data : [1, 2, 3];
+        indices : [];
+        result : at indices data;
+        io.out result;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('');
+    });
+
+    test('take with zero returns empty array', () => {
+      const code = `
+        data : [1, 2, 3];
+        result : take 0 data;
+        io.out result;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('');
+    });
+  });
+
+  describe('Function Combinators', () => {
+    test('flip reverses function argument order', () => {
+      const code = `
+        subtract : x y -> x - y;
+        flippedSubtract : flip subtract;
+        result : flippedSubtract 3 10;
+        io.out result;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('7'); // 10 - 3 = 7
+    });
+
+    test('apply applies function to value', () => {
+      const code = `
+        double : x -> x * 2;
+        result : apply double 7;
+        io.out result;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('14');
+    });
+
+    test('pipe pipes value through function', () => {
+      const code = `
+        triple : x -> x * 3;
+        result : pipe 4 triple;
+        io.out result;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('12');
+    });
+
+    test('compose creates function composition', () => {
+      const code = `
+        increment : x -> x + 1;
+        double : x -> x * 2;
+        composed : compose increment double;
+        result : composed 5;
+        io.out result;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('11'); // increment(double(5)) = increment(10) = 11
+    });
+
+    test('combinators work with curried functions', () => {
+      const code = `
+        add : x -> y -> x + y;
+        add5 : add 5;
+        flippedAdd5 : flip add5;
+        result : flippedAdd5 3;
+        io.out result;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('8'); // Should still work: 5 + 3 = 8
+    });
+  });
+
+  describe('Broadcasting Operations', () => {
+    test('broadcast applies scalar operation to array', () => {
+      const code = `
+        addOp : x y -> x + y;
+        numbers : [1, 2, 3, 4];
+        result : broadcast addOp 10 numbers;
+        io.out result;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('11,12,13,14');
+    });
+
+    test('zipWith applies operation element-wise', () => {
+      const code = `
+        mulOp : x y -> x * y;
+        array1 : [1, 2, 3];
+        array2 : [4, 5, 6];
+        result : zipWith mulOp array1 array2;
+        io.out result;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('4,10,18');
+    });
+
+    test('zipWith handles arrays of different lengths', () => {
+      const code = `
+        addOp : x y -> x + y;
+        array1 : [1, 2, 3, 4, 5];
+        array2 : [10, 20, 30];
+        result : zipWith addOp array1 array2;
+        io.out result;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('11,22,33'); // Only processes minimum length
+    });
+
+    test('reshape creates 2D matrix', () => {
+      const code = `
+        flatArray : [1, 2, 3, 4, 5, 6];
+        result : reshape [2, 3] flatArray;
+        // Check that result is a 2x3 matrix
+        row1 : result.0;
+        row2 : result.1;
+        io.out row1;
+        io.out row2;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('1,2,3'); // First row
+      expect(outputs[1]).toBe('4,5,6'); // Second row
+    });
+
+    test('broadcast with subtraction', () => {
+      const code = `
+        subOp : x y -> x - y;
+        numbers : [10, 20, 30];
+        result : broadcast subOp 5 numbers;
+        io.out result;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('-5,-15,-25'); // 5 - 10, 5 - 20, 5 - 30
+    });
+  });
+
+  describe('Monadic Operations', () => {
+    test('flatMap flattens mapped results', () => {
+      const code = `
+        duplicateFunc : x -> [x, x];
+        original : [1, 2, 3];
+        result : flatMap duplicateFunc original;
+        io.out result;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('1,1,2,2,3,3');
+    });
+
+    test('flatMap with range generation', () => {
+      const code = `
+        rangeFunc : x -> range 1 x;
+        original : [2, 3];
+        result : flatMap rangeFunc original;
+        io.out result;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('1,2,1,2,3');
+    });
+
+    test('flatMap with empty results', () => {
+      const code = `
+        emptyFunc : x -> [];
+        original : [1, 2, 3];
+        result : flatMap emptyFunc original;
+        io.out result;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('');
+    });
+
+    test('flatMap with mixed result lengths', () => {
+      const code = `
+        variableFunc : x -> when x is
+          1 then [x]
+          2 then [x, x]
+          _ then [x, x, x];
+        original : [1, 2, 3];
+        result : flatMap variableFunc original;
+        io.out result;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('1,2,2,3,3,3');
+    });
+  });
+
+  describe('Pattern Guards', () => {
+    test('basic pattern guards with numeric conditions', () => {
+      const code = `
+        classify : x ->
+          when x is
+            n if (n > 0) then "positive"
+            n if (n < 0) then "negative"
+            0 then "zero";
+        
+        result1 : classify 5;
+        result2 : classify -3;
+        result3 : classify 0;
+        io.out result1;
+        io.out result2;
+        io.out result3;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('positive');
+      expect(outputs[1]).toBe('negative');
+      expect(outputs[2]).toBe('zero');
+    });
+
+    test('pattern guards with range conditions', () => {
+      const code = `
+        categorizeAge : age ->
+          when age is
+            a if (a >= 0 and a < 18) then "minor"
+            a if (a >= 18 and a < 65) then "adult"
+            a if (a >= 65) then "senior"
+            _ then "invalid";
+        
+        result1 : categorizeAge 16;
+        result2 : categorizeAge 30;
+        result3 : categorizeAge 70;
+        io.out result1;
+        io.out result2;
+        io.out result3;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('minor');
+      expect(outputs[1]).toBe('adult');
+      expect(outputs[2]).toBe('senior');
+    });
+
+    test('pattern guards with complex conditions', () => {
+      const code = `
+        gradeStudent : score ->
+          when score is
+            s if (s >= 90) then "A"
+            s if (s >= 80 and s < 90) then "B"
+            s if (s >= 70 and s < 80) then "C"
+            s if (s < 70) then "F"
+            _ then "Invalid";
+        
+        result1 : gradeStudent 95;
+        result2 : gradeStudent 85;
+        result3 : gradeStudent 75;
+        result4 : gradeStudent 65;
+        io.out result1;
+        io.out result2;
+        io.out result3;
+        io.out result4;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('A');
+      expect(outputs[1]).toBe('B');
+      expect(outputs[2]).toBe('C');
+      expect(outputs[3]).toBe('F');
+    });
+
+    test('pattern guards with wildcard patterns', () => {
+      const code = `
+        checkRange : x ->
+          when x is
+            _ if (x >= 1 and x <= 10) then "small"
+            _ if (x >= 11 and x <= 100) then "medium"
+            _ if (x > 100) then "large"
+            _ then "invalid";
+        
+        result1 : checkRange 5;
+        result2 : checkRange 50;
+        result3 : checkRange 150;
+        result4 : checkRange -5;
+        io.out result1;
+        io.out result2;
+        io.out result3;
+        io.out result4;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('small');
+      expect(outputs[1]).toBe('medium');
+      expect(outputs[2]).toBe('large');
+      expect(outputs[3]).toBe('invalid');
+    });
+
+    test('pattern guards fail when condition is false', () => {
+      const code = `
+        testGuard : x ->
+          when x is
+            n if (n > 10) then "big"
+            _ then "small";
+        
+        result1 : testGuard 15;
+        result2 : testGuard 5;
+        io.out result1;
+        io.out result2;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('big');
+      expect(outputs[1]).toBe('small');
+    });
+  });
+
+  describe('Integration Tests', () => {
+    test('combining scan and broadcast operations', () => {
+      const code = `
+        numbers : [1, 2, 3, 4];
+        cumulative : cumsum numbers;
+        addTen : broadcast (x y -> x + y) 10 cumulative;
+        io.out addTen;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('10,11,13,16,20'); // cumsum [1,2,3,4] = [0,1,3,6,10], then +10 each
+    });
+
+    test('combining flatMap with array indexing', () => {
+      const code = `
+        data : [[1, 2], [3, 4, 5], [6]];
+        flattened : flatMap (x -> x) data;
+        evens : where (x -> x % 2 = 0) flattened;
+        evenValues : at evens flattened;
+        io.out evenValues;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('2,4,6');
+    });
+
+    test('combining pattern guards with functional operations', () => {
+      const code = `
+        processNumbers : numbers ->
+          with (
+            classified : map (n -> when n is
+              x if (x > 0) then "pos"
+              x if (x < 0) then "neg"
+              0 then "zero") numbers;
+            positives : filter (n -> n > 0) numbers;
+            posSum : reduce (acc x -> acc + x) 0 positives;
+          ) ->
+            {classifications: classified, sum: posSum};
+        
+        result : processNumbers [-2, 0, 3, -1, 5];
+        io.out result.sum;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('8'); // 3 + 5 = 8
+    });
+
+    test('complex pipeline with multiple new features', () => {
+      const code = `
+        data : [1, 2, 3, 4, 5];
+        
+        // Use scan to get cumulative sums
+        cumSums : cumsum data;
+        
+        // Use broadcast to multiply by 2
+        doubled : broadcast (x y -> x * y) 2 cumSums;
+        
+        // Use where to find indices of values > 10
+        bigIndices : where (x -> x > 10) doubled;
+        
+        // Use at to get those values
+        bigValues : at bigIndices doubled;
+        
+        io.out bigValues;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('12,20,30'); // Values > 10 from [0,2,6,12,20,30]
+    });
+  });
+
+  describe('Error Handling', () => {
+    test('at throws error for out of bounds index', () => {
+      const code = `
+        data : [1, 2, 3];
+        indices : [0, 5];
+        result : at indices data;
+      `;
+      expect(() => runBabaYaga(code)).toThrow(/Index out of bounds|Can't find variable/);
+    });
+
+    test('reshape throws error for incompatible dimensions', () => {
+      const code = `
+        data : [1, 2, 3, 4, 5];
+        result : reshape [2, 3] data;
+      `;
+      expect(() => runBabaYaga(code)).toThrow('Cannot reshape array');
+    });
+
+    test('scan requires function as first argument', () => {
+      const code = `
+        result : scan 42 0 [1, 2, 3];
+      `;
+      expect(() => runBabaYaga(code)).toThrow('Scan expects a function');
+    });
+
+    test('broadcast requires function as first argument', () => {
+      const code = `
+        result : broadcast "not a function" 5 [1, 2, 3];
+      `;
+      expect(() => runBabaYaga(code)).toThrow('broadcast expects a function');
+    });
+
+    test('where requires function as first argument', () => {
+      const code = `
+        result : where "not a function" [1, 2, 3];
+      `;
+      expect(() => runBabaYaga(code)).toThrow('where expects a function');
+    });
+
+    test('flatMap requires function as first argument', () => {
+      const code = `
+        result : flatMap 42 [1, 2, 3];
+      `;
+      expect(() => runBabaYaga(code)).toThrow('flatMap expects a function');
+    });
+
+    test('take with negative number throws error', () => {
+      const code = `
+        result : take -1 [1, 2, 3];
+      `;
+      expect(() => runBabaYaga(code)).toThrow('take expects a non-negative number');
+    });
+
+    test('drop with negative number throws error', () => {
+      const code = `
+        result : drop -1 [1, 2, 3];
+      `;
+      expect(() => runBabaYaga(code)).toThrow('drop expects a non-negative number');
+    });
+  });
+
+  describe('Edge Cases', () => {
+    test('scan with empty array', () => {
+      const code = `
+        addFunc : acc x -> acc + x;
+        result : scan addFunc 0 [];
+        io.out result;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('0'); // Just the initial value
+    });
+
+    test('broadcast with empty array', () => {
+      const code = `
+        addOp : x y -> x + y;
+        result : broadcast addOp 5 [];
+        io.out result;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe(''); // Empty result
+    });
+
+    test('zipWith with empty arrays', () => {
+      const code = `
+        addOp : x y -> x + y;
+        result : zipWith addOp [] [];
+        io.out result;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe(''); // Empty result
+    });
+
+    test('where with no matches', () => {
+      const code = `
+        neverTrue : x -> false;
+        result : where neverTrue [1, 2, 3];
+        io.out result;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe(''); // No matching indices
+    });
+
+    test('flatMap with single-element arrays', () => {
+      const code = `
+        wrapFunc : x -> [x];
+        result : flatMap wrapFunc [1, 2, 3];
+        io.out result;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('1,2,3'); // Should flatten to original
+    });
+
+    test('pattern guards with complex boolean expressions', () => {
+      const code = `
+        complexTest : x ->
+          when x is
+            n if ((n > 5) and (n < 15) and (n % 2 = 0)) then "even between 5 and 15"
+            n if ((n > 0) or (n < -10)) then "positive or very negative"
+            _ then "other";
+        
+        result1 : complexTest 8;
+        result2 : complexTest 3;
+        result3 : complexTest -15;
+        result4 : complexTest -5;
+        io.out result1;
+        io.out result2;
+        io.out result3;
+        io.out result4;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('even between 5 and 15'); // 8 matches first condition
+      expect(outputs[1]).toBe('positive or very negative'); // 3 is positive
+      expect(outputs[2]).toBe('positive or very negative'); // -15 is very negative
+      expect(outputs[3]).toBe('other'); // -5 doesn't match any condition
+    });
+
+    test('combinators with identity functions', () => {
+      const code = `
+        identity : x -> x;
+        doubled : x -> x * 2;
+        
+        // Compose with identity should be equivalent to original function
+        composedWithId : compose identity doubled;
+        result1 : composedWithId 5;
+        
+        // Apply identity should return original value
+        result2 : apply identity 42;
+        
+        // Pipe through identity should return original value
+        result3 : pipe 7 identity;
+        
+        io.out result1;
+        io.out result2;
+        io.out result3;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('10'); // identity(doubled(5)) = 10
+      expect(outputs[1]).toBe('42'); // identity(42) = 42
+      expect(outputs[2]).toBe('7');  // pipe 7 identity = 7
+    });
+  });
+});
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/);
+  });
+});
+
+
diff --git a/js/baba-yaga/tests/js-interop.test.js b/js/baba-yaga/tests/js-interop.test.js
new file mode 100644
index 0000000..77c760a
--- /dev/null
+++ b/js/baba-yaga/tests/js-interop.test.js
@@ -0,0 +1,407 @@
+// js-interop.test.js - Tests for JavaScript interop functionality
+
+import { describe, it, expect } from 'bun:test';
+import { createLexer } from '../src/core/lexer.js';
+import { createParser } from '../src/core/parser.js';
+import { createInterpreter } from '../src/core/interpreter.js';
+
+// Helper function to run Baba Yaga code with JS interop
+function runBabaCode(code, jsBridgeConfig = {}) {
+  const lexer = createLexer(code);
+  const tokens = lexer.allTokens();
+  const parser = createParser(tokens);
+  const ast = parser.parse();
+  
+  const host = {
+    jsBridgeConfig: {
+      allowedFunctions: new Set([
+        'JSON.parse', 'JSON.stringify',
+        'Math.abs', 'Math.floor', 'Math.ceil', 'Math.round',
+        'Math.min', 'Math.max', 'Math.random',
+        'console.log', 'console.warn', 'console.error',
+        'Date.now', 'performance.now',
+        'testFunction', 'testAsyncFunction', 'testErrorFunction'
+      ]),
+      ...jsBridgeConfig
+    },
+    io: {
+      out: () => {}, // Silent for tests
+      debug: () => {}
+    }
+  };
+  
+  // Add test functions to global scope for testing
+  global.testFunction = (x) => x * 2;
+  global.testAsyncFunction = async (x) => Promise.resolve(x + 10);
+  global.testErrorFunction = () => { throw new Error('Test error'); };
+  
+  // The JS bridge will create its own default sandbox
+  // We'll add test functions to the allowed functions, but let the bridge handle the sandbox
+  
+  const interpreter = createInterpreter(ast, host);
+  interpreter.interpret();
+  return interpreter.scope.get('result');
+}
+
+describe('JavaScript Interop - Basic Function Calls', () => {
+  it('should call JavaScript Math.abs function', () => {
+    const code = `
+      result : io.callJS "Math.abs" [-5];
+      result;
+    `;
+    
+    const result = runBabaCode(code);
+    expect(result).toBeDefined();
+    expect(result.type).toBe('Result');
+    expect(result.variant).toBe('Ok');
+    expect(result.value.value).toBe(5);
+  });
+
+  it('should call JavaScript JSON.parse function', () => {
+    const code = `
+      jsonStr : "{\\"name\\": \\"Alice\\", \\"age\\": 30}";
+      result : io.callJS "JSON.parse" [jsonStr];
+      result;
+    `;
+    
+    const result = runBabaCode(code);
+    expect(result).toBeDefined();
+    expect(result.type).toBe('Result');
+    expect(result.variant).toBe('Ok');
+    
+    const parsed = result.value;
+    expect(parsed.type).toBe('JSValue');
+    expect(parsed.value.name).toBe('Alice');
+    expect(parsed.value.age).toBe(30);
+  });
+
+  it('should call JavaScript JSON.stringify function', () => {
+    const code = `
+      data : {name: "Bob", age: 25};
+      jsObj : io.tableToObject data;
+      result : io.callJS "JSON.stringify" [jsObj];
+      result;
+    `;
+    
+    const result = runBabaCode(code);
+    expect(result).toBeDefined();
+    expect(result.type).toBe('Result');
+    expect(result.variant).toBe('Ok');
+    
+    const jsonStr = result.value;
+    expect(jsonStr.type).toBe('JSValue');
+    expect(typeof jsonStr.value).toBe('string');
+    expect(jsonStr.value).toContain('Bob');
+    expect(jsonStr.value).toContain('25');
+  });
+
+  it('should handle function call errors gracefully', () => {
+    const code = `
+      result : io.callJS "nonexistentFunction" [42];
+      result;
+    `;
+    
+    const result = runBabaCode(code);
+    expect(result).toBeDefined();
+    expect(result.type).toBe('Result');
+    expect(result.variant).toBe('Err');
+    
+    const errorMsg = result.value;
+    expect(errorMsg).toContain('not allowed');
+  });
+
+  it('should handle JavaScript errors in called functions', () => {
+    const code = `
+      result : io.callJS "testErrorFunction" [];
+      result;
+    `;
+    
+    const result = runBabaCode(code);
+    expect(result).toBeDefined();
+    expect(result.type).toBe('Result');
+    expect(result.variant).toBe('Err');
+    
+    const errorMsg = result.value;
+    expect(errorMsg).toContain('Test error');
+  });
+});
+
+describe('JavaScript Interop - Property Access', () => {
+  it('should get property from JavaScript object', () => {
+    const code = `
+      jsObj : io.callJS "JSON.parse" ["{\\"x\\": 42, \\"y\\": 24}"];
+      result : when jsObj is
+        Ok obj then io.getProperty obj "x"
+        Err msg then Err msg;
+      result;
+    `;
+    
+    const result = runBabaCode(code);
+    expect(result).toBeDefined();
+    expect(result.type).toBe('Result');
+    expect(result.variant).toBe('Ok');
+    expect(result.value.value).toBe(42);
+  });
+
+  it('should handle missing properties gracefully', () => {
+    const code = `
+      jsObj : io.callJS "JSON.parse" ["{\\"x\\": 42}"];
+      result : when jsObj is
+        Ok obj then io.getProperty obj "missing"
+        Err msg then Err msg;
+      result;
+    `;
+    
+    const result = runBabaCode(code);
+    expect(result).toBeDefined();
+    expect(result.type).toBe('Result');
+    expect(result.variant).toBe('Ok');
+    expect(result.value).toBe(null);
+  });
+
+  it('should check if property exists', () => {
+    const code = `
+      jsObj : io.callJS "JSON.parse" ["{\\"name\\": \\"test\\"}"];
+      hasName : when jsObj is
+        Ok obj then io.hasProperty obj "name"
+        Err _ then false;
+      hasMissing : when jsObj is
+        Ok obj then io.hasProperty obj "missing"
+        Err _ then false;
+      result : {hasName: hasName, hasMissing: hasMissing};
+      result;
+    `;
+    
+    const result = runBabaCode(code);
+    expect(result).toBeDefined();
+    expect(result.type).toBe('Object');
+    expect(result.properties.get('hasName')).toBe(true);
+    expect(result.properties.get('hasMissing')).toBe(false);
+  });
+});
+
+describe('JavaScript Interop - Array Conversion', () => {
+  it('should convert JavaScript array to Baba Yaga list', () => {
+    const code = `
+      jsArray : io.callJS "JSON.parse" ["[1, 2, 3, 4, 5]"];
+      result : when jsArray is
+        Ok arr then io.jsArrayToList arr
+        Err msg then Err msg;
+      result;
+    `;
+    
+    const result = runBabaCode(code);
+    expect(result).toBeDefined();
+    expect(result.type).toBe('Result');
+    expect(result.variant).toBe('Ok');
+    
+    const list = result.value;
+    expect(Array.isArray(list)).toBe(true);
+    expect(list.length).toBe(5);
+    expect(list[0].value).toBe(1);
+    expect(list[4].value).toBe(5);
+  });
+
+  it('should convert Baba Yaga list to JavaScript array', () => {
+    const code = `
+      babaList : [10, 20, 30];
+      jsArray : io.listToJSArray babaList;
+      result : io.callJS "JSON.stringify" [jsArray];
+      result;
+    `;
+    
+    const result = runBabaCode(code);
+    expect(result).toBeDefined();
+    expect(result.type).toBe('Result');
+    expect(result.variant).toBe('Ok');
+    
+    const jsonStr = result.value;
+    expect(jsonStr.type).toBe('JSValue');
+    expect(jsonStr.value).toBe('[10,20,30]');
+  });
+});
+
+describe('JavaScript Interop - Object/Table Conversion', () => {
+  it('should convert Baba Yaga table to JavaScript object', () => {
+    const code = `
+      babaTable : {name: "Alice", age: 30, active: true};
+      jsObj : io.tableToObject babaTable;
+      result : io.callJS "JSON.stringify" [jsObj];
+      result;
+    `;
+    
+    const result = runBabaCode(code);
+    expect(result).toBeDefined();
+    expect(result.type).toBe('Result');
+    expect(result.variant).toBe('Ok');
+    
+    const jsonStr = result.value;
+    expect(jsonStr.type).toBe('JSValue');
+    const parsed = JSON.parse(jsonStr.value);
+    expect(parsed.name).toBe('Alice');
+    expect(parsed.age).toBe(30);
+    expect(parsed.active).toBe(true);
+  });
+
+  it('should convert JavaScript object to Baba Yaga table', () => {
+    const code = `
+      jsObj : io.callJS "JSON.parse" ["{\\"x\\": 100, \\"y\\": 200}"];
+      result : when jsObj is
+        Ok obj then io.objectToTable obj
+        Err msg then Err msg;
+      result;
+    `;
+    
+    const result = runBabaCode(code);
+    expect(result).toBeDefined();
+    expect(result.type).toBe('Result');
+    expect(result.variant).toBe('Ok');
+    
+    const table = result.value;
+    expect(table.type).toBe('Object');
+    expect(table.properties.get('x').value).toBe(100);
+    expect(table.properties.get('y').value).toBe(200);
+  });
+});
+
+describe('JavaScript Interop - Error Handling', () => {
+  it('should track and retrieve last JavaScript error', () => {
+    const code = `
+      // Cause an error
+      errorResult : io.callJS "testErrorFunction" [];
+      
+      // For now, just test that we can cause an error
+      // The error tracking functions have syntax issues in Baba Yaga
+      result : {errorResult: errorResult};
+      result;
+    `;
+    
+    const result = runBabaCode(code);
+    expect(result).toBeDefined();
+    expect(result.type).toBe('Object');
+    
+    // Error result should be Err
+    const errorResult = result.properties.get('errorResult');
+    expect(errorResult.type).toBe('Result');
+    expect(errorResult.variant).toBe('Err');
+  });
+});
+
+describe('JavaScript Interop - Real-world Usage Patterns', () => {
+  it('should implement safe JSON parsing pattern', () => {
+    const code = `
+      parseJSON : jsonString ->
+        when (validate.type "String" jsonString) is
+          false then Err "Input must be a string"
+          true then when (io.callJS "JSON.parse" [jsonString]) is
+            Ok parsed then Ok (io.objectToTable parsed)
+            Err msg then Err ("JSON parse error: " .. msg);
+      
+      // Test valid JSON
+      validResult : parseJSON "{\\"name\\": \\"Bob\\", \\"age\\": 25}";
+      
+      // Test invalid JSON
+      invalidResult : parseJSON "invalid json";
+      
+      result : {valid: validResult, invalid: invalidResult};
+      result;
+    `;
+    
+    const result = runBabaCode(code);
+    expect(result).toBeDefined();
+    expect(result.type).toBe('Object');
+    
+    // Valid result should be Ok
+    const validResult = result.properties.get('valid');
+    expect(validResult.type).toBe('Result');
+    expect(validResult.variant).toBe('Ok');
+    
+    // Invalid result should be Err
+    const invalidResult = result.properties.get('invalid');
+    expect(invalidResult.type).toBe('Result');
+    expect(invalidResult.variant).toBe('Err');
+  });
+
+  it('should implement safe mathematical operations', () => {
+    const code = `
+      // Test each operation individually to avoid curried function issues
+      minResult : io.callJS "Math.min" [10, 5];
+      maxResult : io.callJS "Math.max" [10, 5];
+      absResult : io.callJS "Math.abs" [-7];
+      
+      result : {min: minResult, max: maxResult, abs: absResult};
+      result;
+    `;
+    
+    const result = runBabaCode(code);
+    expect(result).toBeDefined();
+    expect(result.type).toBe('Object');
+    
+    // All results should be Ok
+    const minResult = result.properties.get('min');
+    expect(minResult.type).toBe('Result');
+    expect(minResult.variant).toBe('Ok');
+    expect(minResult.value.value).toBe(5);
+    
+    const maxResult = result.properties.get('max');
+    expect(maxResult.type).toBe('Result');
+    expect(maxResult.variant).toBe('Ok');
+    expect(maxResult.value.value).toBe(10);
+    
+    const absResult = result.properties.get('abs');
+    expect(absResult.type).toBe('Result');
+    expect(absResult.variant).toBe('Ok');
+    expect(absResult.value.value).toBe(7);
+  });
+
+  it('should handle complex nested data structures', () => {
+    const code = `
+      complexData : {
+        users: [
+          {name: "Alice", scores: [85, 92, 78]},
+          {name: "Bob", scores: [90, 87, 95]}
+        ],
+        meta: {
+          total: 2,
+          created: "2024-01-01"
+        }
+      };
+      
+      // Convert to JS and back
+      jsObj : io.tableToObject complexData;
+      jsonStr : io.callJS "JSON.stringify" [jsObj];
+      
+      result : when jsonStr is
+        Ok str then when (io.callJS "JSON.parse" [str]) is
+          Ok parsed then io.objectToTable parsed
+          Err msg then Err ("Parse failed: " .. msg)
+        Err msg then Err ("Stringify failed: " .. msg);
+      
+      result;
+    `;
+    
+    const result = runBabaCode(code);
+    expect(result).toBeDefined();
+    expect(result.type).toBe('Result');
+    expect(result.variant).toBe('Ok');
+    
+    const roundTripped = result.value;
+    expect(roundTripped.type).toBe('Object');
+    expect(roundTripped.properties.has('users')).toBe(true);
+    expect(roundTripped.properties.has('meta')).toBe(true);
+    
+    // Check nested structure integrity
+    const users = roundTripped.properties.get('users');
+    expect(Array.isArray(users)).toBe(true);
+    expect(users.length).toBe(2);
+    
+    const alice = users[0];
+    expect(alice.type).toBe('Object');
+    expect(alice.properties.get('name')).toBe('Alice');
+  });
+});
+
+// Clean up global test functions
+global.testFunction = undefined;
+global.testAsyncFunction = undefined;
+global.testErrorFunction = undefined;
diff --git a/js/baba-yaga/tests/language_features.test.js b/js/baba-yaga/tests/language_features.test.js
new file mode 100644
index 0000000..0550f70
--- /dev/null
+++ b/js/baba-yaga/tests/language_features.test.js
@@ -0,0 +1,450 @@
+const assert = require('assert');
+const { createLexer } = require('../src/core/lexer');
+const { createParser } = require('../src/core/parser');
+const { createInterpreter } = require('../src/core/interpreter');
+
+describe('Language Features', () => {
+  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('Mathematical Constants', () => {
+    it('should correctly handle PI constant', () => {
+      const code = 'result : PI;';
+      const interpreter = interpret(code);
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result.value, Math.PI);
+      assert.strictEqual(result.isFloat, true);
+    });
+
+    it('should correctly handle INFINITY constant', () => {
+      const code = 'result : INFINITY;';
+      const interpreter = interpret(code);
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result.value, Infinity);
+      assert.strictEqual(result.isFloat, true);
+    });
+
+    it('should use constants in expressions', () => {
+      const code = 'result : 2 * PI;';
+      const interpreter = interpret(code);
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result.value, 2 * Math.PI);
+    });
+  });
+
+  describe('Immutable List Operations', () => {
+    it('should correctly append to lists', () => {
+      const code = `
+        original : [1, 2, 3];
+        result : append original 4;
+      `;
+      const interpreter = interpret(code);
+      const original = interpreter.scope.get('original');
+      const result = interpreter.scope.get('result');
+      assert.deepStrictEqual(original.map(item => item.value), [1, 2, 3]);
+      assert.deepStrictEqual(result.map(item => item.value), [1, 2, 3, 4]);
+    });
+
+    it('should correctly prepend to lists', () => {
+      const code = `
+        original : [1, 2, 3];
+        result : prepend 0 original;
+      `;
+      const interpreter = interpret(code);
+      const original = interpreter.scope.get('original');
+      const result = interpreter.scope.get('result');
+      assert.deepStrictEqual(original.map(item => item.value), [1, 2, 3]);
+      assert.deepStrictEqual(result.map(item => item.value), [0, 1, 2, 3]);
+    });
+
+    it('should correctly concatenate lists', () => {
+      const code = `
+        list1 : [1, 2];
+        list2 : [3, 4];
+        result : concat list1 list2;
+      `;
+      const interpreter = interpret(code);
+      const result = interpreter.scope.get('result');
+      assert.deepStrictEqual(result.map(item => item.value), [1, 2, 3, 4]);
+    });
+
+    it('should correctly update list elements', () => {
+      const code = `
+        original : [1, 2, 3];
+        result : update original 1 99;
+      `;
+      const interpreter = interpret(code);
+      const original = interpreter.scope.get('original');
+      const result = interpreter.scope.get('result');
+      assert.deepStrictEqual(original.map(item => item.value), [1, 2, 3]);
+      assert.deepStrictEqual(result.map(item => item.value), [1, 99, 3]);
+    });
+
+    it('should correctly remove elements from lists', () => {
+      const code = `
+        original : [1, 2, 3];
+        result : removeAt original 1;
+      `;
+      const interpreter = interpret(code);
+      const original = interpreter.scope.get('original');
+      const result = interpreter.scope.get('result');
+      assert.deepStrictEqual(original.map(item => item.value), [1, 2, 3]);
+      assert.deepStrictEqual(result.map(item => item.value), [1, 3]);
+    });
+
+    it('should correctly slice lists', () => {
+      const code = `
+        original : [1, 2, 3, 4, 5];
+        result : slice original 1 4;
+      `;
+      const interpreter = interpret(code);
+      const original = interpreter.scope.get('original');
+      const result = interpreter.scope.get('result');
+      assert.deepStrictEqual(original.map(item => item.value), [1, 2, 3, 4, 5]);
+      assert.deepStrictEqual(result.map(item => item.value), [2, 3, 4]);
+    });
+  });
+
+  describe('Immutable Table Operations', () => {
+    it('should correctly set table properties', () => {
+      const code = `
+        original : {name: "Alice", age: 30};
+        result : set original "city" "NYC";
+      `;
+      const interpreter = interpret(code);
+      const original = interpreter.scope.get('original');
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(original.properties.get('name'), 'Alice');
+      assert.strictEqual(original.properties.get('age').value, 30);
+      assert.strictEqual(result.properties.get('name'), 'Alice');
+      assert.strictEqual(result.properties.get('age').value, 30);
+      assert.strictEqual(result.properties.get('city'), 'NYC');
+    });
+
+    it('should correctly remove table properties', () => {
+      const code = `
+        original : {name: "Alice", age: 30};
+        result : remove original "age";
+      `;
+      const interpreter = interpret(code);
+      const original = interpreter.scope.get('original');
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(original.properties.get('name'), 'Alice');
+      assert.strictEqual(original.properties.get('age').value, 30);
+      assert.strictEqual(result.properties.get('name'), 'Alice');
+      assert.strictEqual(result.properties.has('age'), false);
+    });
+
+    it('should correctly merge tables', () => {
+      const code = `
+        table1 : {name: "Alice", age: 30};
+        table2 : {city: "NYC", country: "USA"};
+        result : merge table1 table2;
+      `;
+      const interpreter = interpret(code);
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result.properties.get('name'), 'Alice');
+      assert.strictEqual(result.properties.get('age').value, 30);
+      assert.strictEqual(result.properties.get('city'), 'NYC');
+      assert.strictEqual(result.properties.get('country'), 'USA');
+    });
+
+    it('should correctly get table keys', () => {
+      const code = `
+        table : {name: "Alice", age: 30};
+        result : keys table;
+      `;
+      const interpreter = interpret(code);
+      const result = interpreter.scope.get('result');
+      assert.deepStrictEqual(result, ['name', 'age']);
+    });
+
+    it('should correctly get table values', () => {
+      const code = `
+        table : {name: "Alice", age: 30};
+        result : values table;
+      `;
+      const interpreter = interpret(code);
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result[0], 'Alice');
+      assert.strictEqual(result[1].value, 30);
+    });
+  });
+
+  describe('String Operations', () => {
+    it('should correctly concatenate strings', () => {
+      const code = 'result : str.concat "Hello" " " "World";';
+      const interpreter = interpret(code);
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result, 'Hello World');
+    });
+
+    it('should correctly split strings', () => {
+      const code = 'result : str.split "a,b,c" ",";';
+      const interpreter = interpret(code);
+      const result = interpreter.scope.get('result');
+      assert.deepStrictEqual(result, ['a', 'b', 'c']);
+    });
+
+    it('should correctly join lists into strings', () => {
+      const code = 'result : str.join ["a", "b", "c"] "-";';
+      const interpreter = interpret(code);
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result, 'a-b-c');
+    });
+
+    it('should correctly get string length', () => {
+      const code = 'result : str.length "hello";';
+      const interpreter = interpret(code);
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result.value, 5);
+    });
+
+    it('should correctly get substrings', () => {
+      const code = 'result : str.substring "hello world" 0 5;';
+      const interpreter = interpret(code);
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result, 'hello');
+    });
+
+    it('should correctly replace substrings', () => {
+      const code = 'result : str.replace "hello hello" "hello" "hi";';
+      const interpreter = interpret(code);
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result, 'hi hi');
+    });
+
+    it('should correctly trim strings', () => {
+      const code = 'result : str.trim "  hello  ";';
+      const interpreter = interpret(code);
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result, 'hello');
+    });
+
+    it('should correctly convert to uppercase', () => {
+      const code = 'result : str.upper "hello";';
+      const interpreter = interpret(code);
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result, 'HELLO');
+    });
+
+    it('should correctly convert to lowercase', () => {
+      const code = 'result : str.lower "HELLO";';
+      const interpreter = interpret(code);
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result, 'hello');
+    });
+  });
+
+  describe('Type Declarations and Type Checking', () => {
+    it('should correctly handle type declarations', () => {
+      const code = `
+        myNumber Int;
+        myNumber : 42;
+      `;
+      const interpreter = interpret(code);
+      const result = interpreter.scope.get('myNumber');
+      assert.strictEqual(result.value, 42);
+    });
+
+    it('should correctly handle type checking in when expressions', () => {
+      const code = `
+        checkType : val ->
+          when val is
+            Int then "Integer"
+            String then "String"
+            Bool then "Boolean"
+            _ then "Other";
+        
+        result1 : checkType 42;
+        result2 : checkType "hello";
+        result3 : checkType true;
+      `;
+      const interpreter = interpret(code);
+      assert.strictEqual(interpreter.scope.get('result1'), 'Integer');
+      assert.strictEqual(interpreter.scope.get('result2'), 'String');
+      assert.strictEqual(interpreter.scope.get('result3'), 'Boolean');
+    });
+  });
+
+  describe('Result Type', () => {
+    it('should correctly create Ok results', () => {
+      const code = 'result : Ok 42;';
+      const interpreter = interpret(code);
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result.type, 'Result');
+      assert.strictEqual(result.variant, 'Ok');
+      assert.strictEqual(result.value.value, 42);
+    });
+
+    it('should correctly create Err results', () => {
+      const code = 'result : Err "error message";';
+      const interpreter = interpret(code);
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result.type, 'Result');
+      assert.strictEqual(result.variant, 'Err');
+      assert.strictEqual(result.value, 'error message');
+    });
+
+    it('should correctly pattern match on Result types', () => {
+      const code = `
+        divide : x y ->
+          when y is
+            0 then Err "Division by zero"
+            _ then Ok (x / y);
+        
+        result1 : when (divide 10 2) is
+          Ok value then value
+          Err msg then 0;
+        
+        result2 : when (divide 10 0) is
+          Ok value then value
+          Err msg then msg;
+      `;
+      const interpreter = interpret(code);
+      const result1 = interpreter.scope.get('result1');
+      const result2 = interpreter.scope.get('result2');
+      assert.strictEqual(result1.value, 5);
+      assert.strictEqual(result2, 'Division by zero');
+    });
+  });
+
+  describe('Operators', () => {
+    it('should correctly handle unary negation', () => {
+      const code = 'result : -5;';
+      const interpreter = interpret(code);
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result.value, -5);
+    });
+
+    it('should correctly handle string concatenation with ..', () => {
+      const code = 'result : "Hello" .. " " .. "World";';
+      const interpreter = interpret(code);
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result, 'Hello World');
+    });
+
+    it('should correctly handle comparison operators', () => {
+      const code = `
+        result1 : 5 > 3;
+        result2 : 5 < 3;
+        result3 : 5 >= 5;
+        result4 : 5 <= 3;
+        result5 : 5 = 5;
+      `;
+      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'), true);
+    });
+
+    it('should correctly handle modulo operator', () => {
+      const code = `
+        result1 : 10 % 3;
+        result2 : 15 % 4;
+        result3 : 7 % 2;
+      `;
+      const interpreter = interpret(code);
+      assert.strictEqual(interpreter.scope.get('result1').value, 1);
+      assert.strictEqual(interpreter.scope.get('result2').value, 3);
+      assert.strictEqual(interpreter.scope.get('result3').value, 1);
+    });
+  });
+
+  describe('Curried Functions and Partial Application', () => {
+    it('should correctly handle curried functions', () => {
+      const code = `
+        add : x -> y -> x + y;
+        add5 : add 5;
+        result : add5 3;
+      `;
+      const interpreter = interpret(code);
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result.value, 8);
+    });
+
+    it('should correctly handle partial application', () => {
+      const code = `
+        multiply : x -> y -> x * y;
+        double : multiply 2;
+        result : double 7;
+      `;
+      const interpreter = interpret(code);
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result.value, 14);
+    });
+  });
+
+  describe('Anonymous Functions', () => {
+    it('should correctly handle anonymous functions', () => {
+      const code = `
+        result : (x -> x * 2) 5;
+      `;
+      const interpreter = interpret(code);
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result.value, 10);
+    });
+
+    it('should correctly handle anonymous functions with multiple parameters', () => {
+      const code = `
+        result : (x y -> x + y) 3 4;
+      `;
+      const interpreter = interpret(code);
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result.value, 7);
+    });
+  });
+
+  describe('Function Calls', () => {
+    it('should correctly handle parenthesized function calls', () => {
+      const code = `
+        add : x y -> x + y;
+        result : (add 3 4);
+      `;
+      const interpreter = interpret(code);
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result.value, 7);
+    });
+
+    it('should correctly handle non-parenthesized function calls', () => {
+      const code = `
+        add : x y -> x + y;
+        result : add 3 4;
+      `;
+      const interpreter = interpret(code);
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result.value, 7);
+    });
+  });
+
+  describe('Error Handling', () => {
+    it('should handle division by zero', () => {
+      const code = 'result : 10 / 0;';
+      assert.throws(() => interpret(code), /Division by zero/);
+    });
+
+    it('should handle index out of bounds', () => {
+      const code = 'result : [1, 2, 3].5;';
+      assert.throws(() => interpret(code), /Index out of bounds/);
+    });
+
+    it('should handle undefined variables', () => {
+      const code = 'result : undefinedVar;';
+      assert.throws(() => interpret(code), /Undefined variable/);
+    });
+
+    it('should handle undefined properties', () => {
+      const code = 'result : {name: "Alice"}.age;';
+      assert.throws(() => interpret(code), /Undefined property/);
+    });
+  });
+}); 
\ No newline at end of file
diff --git a/js/baba-yaga/tests/logical_operators.test.js b/js/baba-yaga/tests/logical_operators.test.js
new file mode 100644
index 0000000..ebb2efa
--- /dev/null
+++ b/js/baba-yaga/tests/logical_operators.test.js
@@ -0,0 +1,85 @@
+import { evaluate } from '../runner.js';
+
+describe('Logical Operators', () => {
+  test('!= (not equal) operator', () => {
+    const result = evaluate('1 != 2');
+    expect(result.ok).toBe(true);
+    expect(result.value).toBe(true);
+    
+    const result2 = evaluate('1 != 1');
+    expect(result2.ok).toBe(true);
+    expect(result2.value).toBe(false);
+  });
+
+  test('and (logical and) operator', () => {
+    const result = evaluate('true and true');
+    expect(result.ok).toBe(true);
+    expect(result.value).toBe(true);
+    
+    const result2 = evaluate('true and false');
+    expect(result2.ok).toBe(true);
+    expect(result2.value).toBe(false);
+    
+    const result3 = evaluate('false and true');
+    expect(result3.ok).toBe(true);
+    expect(result3.value).toBe(false);
+    
+    const result4 = evaluate('false and false');
+    expect(result4.ok).toBe(true);
+    expect(result4.value).toBe(false);
+  });
+
+  test('or (logical or) operator', () => {
+    const result = evaluate('true or true');
+    expect(result.ok).toBe(true);
+    expect(result.value).toBe(true);
+    
+    const result2 = evaluate('true or false');
+    expect(result2.ok).toBe(true);
+    expect(result2.value).toBe(true);
+    
+    const result3 = evaluate('false or true');
+    expect(result3.ok).toBe(true);
+    expect(result3.value).toBe(true);
+    
+    const result4 = evaluate('false or false');
+    expect(result4.ok).toBe(true);
+    expect(result4.value).toBe(false);
+  });
+
+  test('xor operator', () => {
+    const result = evaluate('true xor true');
+    expect(result.ok).toBe(true);
+    expect(result.value).toBe(false);
+    
+    const result2 = evaluate('true xor false');
+    expect(result2.ok).toBe(true);
+    expect(result2.value).toBe(true);
+    
+    const result3 = evaluate('false xor true');
+    expect(result3.ok).toBe(true);
+    expect(result3.value).toBe(true);
+    
+    const result4 = evaluate('false xor false');
+    expect(result4.ok).toBe(true);
+    expect(result4.value).toBe(false);
+  });
+
+  test('operator precedence', () => {
+    // and should have higher precedence than or
+    const result = evaluate('true or false and false');
+    expect(result.ok).toBe(true);
+    expect(result.value).toBe(true); // true or (false and false) = true or false = true
+    
+    // Comparison should have higher precedence than logical
+    const result2 = evaluate('1 < 2 and 3 > 1');
+    expect(result2.ok).toBe(true);
+    expect(result2.value).toBe(true); // (1 < 2) and (3 > 1) = true and true = true
+  });
+
+  test('complex logical expressions', () => {
+    const result = evaluate('1 != 2 and 3 > 1 or false');
+    expect(result.ok).toBe(true);
+    expect(result.value).toBe(true); // (1 != 2 and 3 > 1) or false = (true and true) or false = true or false = true
+  });
+});
diff --git a/js/baba-yaga/tests/math_namespace.test.js b/js/baba-yaga/tests/math_namespace.test.js
new file mode 100644
index 0000000..c892bbb
--- /dev/null
+++ b/js/baba-yaga/tests/math_namespace.test.js
@@ -0,0 +1,112 @@
+const assert = require('assert');
+const { createLexer } = require('../src/core/lexer');
+const { createParser } = require('../src/core/parser');
+const { createInterpreter } = require('../src/core/interpreter');
+
+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('Math Namespace', () => {
+  it('should support basic numeric ops: abs/floor/ceil/round/trunc', () => {
+    const code = `
+      a : math.abs -3;
+      b : math.floor 2.9;
+      c : math.ceil 2.1;
+      d : math.round 2.5;
+      e : math.trunc -2.9;
+    `;
+    const itp = interpret(code);
+    assert.strictEqual(itp.scope.get('a').value, 3);
+    assert.strictEqual(itp.scope.get('b').value, 2);
+    assert.strictEqual(itp.scope.get('c').value, 3);
+    assert.strictEqual(itp.scope.get('d').value, 3);
+    assert.strictEqual(itp.scope.get('e').value, -2);
+  });
+
+  it('should support min/max/clamp', () => {
+    const code = `
+      a : math.min 10 3;
+      b : math.max 10 3;
+      c : math.clamp 15 0 10;
+    `;
+    const itp = interpret(code);
+    assert.strictEqual(itp.scope.get('a').value, 3);
+    assert.strictEqual(itp.scope.get('b').value, 10);
+    assert.strictEqual(itp.scope.get('c').value, 10);
+  });
+
+  it('should support pow/sqrt/exp/log (with domain checks)', () => {
+    const code = `
+      p : math.pow 2 8;
+      s : math.sqrt 9;
+      e : math.exp 1;
+      l : math.log 2.718281828;
+    `;
+    const itp = interpret(code);
+    assert.strictEqual(itp.scope.get('p').value, 256);
+    assert.strictEqual(itp.scope.get('s').value, 3);
+    assert.ok(Math.abs(itp.scope.get('e').value - Math.E) < 1e-9);
+    assert.ok(Math.abs(itp.scope.get('l').value - 1) < 1e-6);
+
+    assert.throws(() => interpret('x : math.sqrt -1;'));
+    assert.throws(() => interpret('x : math.log 0;'));
+  });
+
+  it('should support trig and conversions', () => {
+    const code = `
+      c : math.cos 0;
+      s : math.sin 0;
+      a : math.atan2 1 1;
+      d : math.deg PI;
+      r : math.rad 180;
+    `;
+    const itp = interpret(code);
+    assert.ok(Math.abs(itp.scope.get('c').value - 1) < 1e-12);
+    assert.ok(Math.abs(itp.scope.get('s').value - 0) < 1e-12);
+    assert.ok(Math.abs(itp.scope.get('a').value - Math.PI/4) < 1e-6);
+    assert.ok(Math.abs(itp.scope.get('d').value - 180) < 1e-12);
+    assert.ok(Math.abs(itp.scope.get('r').value - Math.PI) < 1e-6);
+  });
+
+  it('should support random and randomInt', () => {
+    const code = `
+      one : math.randomInt 1 1;
+    `;
+    const itp = interpret(code);
+    assert.strictEqual(itp.scope.get('one').value, 1);
+  });
+
+  it('should accept Int where Float is expected, and Number as supertype', () => {
+    const code = `
+      // Float-typed parameter accepts Int (widening)
+      f : (x: Float) -> Float -> x;
+      r1 : f 2;
+
+      // Number supertype accepts Int or Float
+      idN : (x: Number) -> Number -> x;
+      n1 : idN 2;
+      n2 : idN 2.5;
+
+      // Return type Number accepts either Int or Float (use dummy arg since zero-arg call syntax is not supported)
+      retN1 : (z: Int) -> Number -> 3;
+      retN2 : (z: Int) -> Number -> 3.5;
+      v1 : retN1 0;
+      v2 : retN2 0;
+    `;
+    const itp = interpret(code);
+    assert.strictEqual(itp.scope.get('r1').value, 2);
+    assert.strictEqual(itp.scope.get('n1').value, 2);
+    assert.ok(Math.abs(itp.scope.get('n2').value - 2.5) < 1e-12);
+    assert.strictEqual(itp.scope.get('v1').value, 3);
+    assert.ok(Math.abs(itp.scope.get('v2').value - 3.5) < 1e-12);
+  });
+});
+
+
diff --git a/js/baba-yaga/tests/parser-with-header.test.js b/js/baba-yaga/tests/parser-with-header.test.js
new file mode 100644
index 0000000..f9de453
--- /dev/null
+++ b/js/baba-yaga/tests/parser-with-header.test.js
@@ -0,0 +1,36 @@
+import assert from 'assert';
+import { createLexer } from '../src/core/lexer.js';
+import { createParser } from '../src/core/parser.js';
+
+function parse(code) {
+  const lexer = createLexer(code);
+  const tokens = lexer.allTokens();
+  const parser = createParser(tokens);
+  return parser.parse();
+}
+
+describe('parser: with header', () => {
+  it('parses basic with header', () => {
+    const ast = parse('f : x -> with (a : x + 1; b : a * 2;) -> a + b;');
+    const fn = ast.body[0];
+    assert.strictEqual(fn.type, 'FunctionDeclaration');
+    assert.strictEqual(fn.body.type, 'WithHeader');
+    assert.strictEqual(fn.body.entries.length, 2);
+    assert.strictEqual(fn.body.entries[0].type, 'WithAssign');
+  });
+
+  it('parses typed locals in header', () => {
+    const ast = parse('g : (x: Int) -> Int -> with (a Int; a : x;) -> a;');
+    const fn = ast.body[0];
+    assert.strictEqual(fn.body.entries[0].type, 'WithTypeDecl');
+    assert.strictEqual(fn.body.entries[1].type, 'WithAssign');
+  });
+
+  it('parses with rec variant', () => {
+    const ast = parse('h : -> with rec (f : x -> x; g : y -> y;) -> 0;');
+    const fn = ast.body[0];
+    assert.strictEqual(fn.body.recursive, true);
+  });
+});
+
+
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
diff --git a/js/baba-yaga/tests/turing_completeness.test.js b/js/baba-yaga/tests/turing_completeness.test.js
new file mode 100644
index 0000000..04daa03
--- /dev/null
+++ b/js/baba-yaga/tests/turing_completeness.test.js
@@ -0,0 +1,270 @@
+const assert = require('assert');
+const { createLexer } = require('../src/core/lexer');
+const { createParser } = require('../src/core/parser');
+const { createInterpreter } = require('../src/core/interpreter');
+
+describe('Turing Completeness Tests', () => {
+  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
+  }
+
+  describe('Church Numerals (Basic)', () => {
+    it('should implement basic Church numerals', () => {
+      const code = `
+        // Church numerals: represent numbers as functions
+        // Zero: applies function 0 times
+        zero : f x -> x;
+        
+        // One: applies function 1 time
+        one : f x -> f x;
+        
+        // Test with increment function
+        inc : x -> x + 1;
+        
+        // Convert Church numeral to regular number
+        toNumber : n -> n inc 0;
+        
+        // Test conversions
+        result0 : toNumber zero;
+        result1 : toNumber one;
+      `;
+
+      const interpreter = interpret(code);
+      
+      assert.strictEqual(interpreter.scope.get('result0').value, 0);
+      assert.strictEqual(interpreter.scope.get('result1').value, 1);
+    });
+  });
+
+  describe('Lambda Calculus (Basic)', () => {
+    it('should implement basic lambda calculus operations', () => {
+      const code = `
+        // Basic lambda calculus operations
+        
+        // Identity function
+        id : x -> x;
+        
+        // Constant function
+        const : x y -> x;
+        
+        // Function composition
+        compose : f g x -> f (g x);
+        
+        // Test identity
+        testId : id 42;
+        
+        // Test constant
+        testConst : const 10 20;
+        
+        // Test composition
+        testCompose : compose (x -> x + 1) (x -> x * 2) 5;
+      `;
+
+      const interpreter = interpret(code);
+      
+      assert.strictEqual(interpreter.scope.get('testId').value, 42);
+      assert.strictEqual(interpreter.scope.get('testConst').value, 10);
+      assert.strictEqual(interpreter.scope.get('testCompose').value, 11); // (5*2)+1 = 11
+    });
+  });
+
+  describe('Universal Function (Basic)', () => {
+    it('should implement a basic universal function', () => {
+      const code = `
+        // Simple universal function using function encoding
+        // This demonstrates that our language can simulate any computable function
+        
+        // Function registry
+        functionRegistry : {
+          inc: x -> x + 1;
+          double: x -> x * 2;
+        };
+        
+        // Universal function that can simulate any registered function
+        universal : funcName input ->
+          when funcName is
+            "inc" then (functionRegistry.inc input)
+            "double" then (functionRegistry.double input)
+            _ then input;
+        
+        // Test the universal function
+        result1 : universal "inc" 5;
+        result2 : universal "double" 5;
+      `;
+
+      const interpreter = interpret(code);
+      
+      assert.strictEqual(interpreter.scope.get('result1').value, 6);
+      assert.strictEqual(interpreter.scope.get('result2').value, 10);
+    });
+  });
+
+  describe('Turing Machine Simulator (Basic)', () => {
+    it('should simulate a basic Turing machine', () => {
+      const code = `
+        // Simple Turing machine that counts 1s on the tape
+        // States: "start", "halt"
+        
+        // Initialize Turing machine
+        initTM : {
+          tape: [1, 1, 0, 1],
+          head: 0,
+          state: "start"
+        };
+        
+        // Transition function
+        transition : tm ->
+          when tm.state is
+            "start" then when (tm.head >= (length tm.tape)) is
+                            true then { tape: tm.tape, head: tm.head, state: "halt" }
+                            _    then { tape: tm.tape, head: tm.head + 1, state: "start" }
+            _ then tm;
+        
+        // Run Turing machine
+        runTM : tm ->
+          when tm.state is
+            "halt" then tm
+            _ then runTM (transition tm);
+        
+        // Test
+        result : runTM initTM;
+      `;
+
+      const interpreter = interpret(code);
+      const result = interpreter.scope.get('result');
+      
+      // Should reach halt state
+      assert.strictEqual(result.state, "halt");
+    });
+  });
+
+  describe('Recursive Functions (Turing Complete)', () => {
+    it('should demonstrate Turing completeness through recursion', () => {
+      const code = `
+        // Ackermann function - a classic example of a computable but not primitive recursive function
+        // This demonstrates that our language can compute any computable function
+        
+        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));
+        
+        // Test with small values (larger values would cause stack overflow)
+        result1 : ackermann 0 5;
+        result2 : ackermann 1 3;
+        result3 : ackermann 2 2;
+      `;
+
+      const interpreter = interpret(code);
+      
+      assert.strictEqual(interpreter.scope.get('result1').value, 6);
+      assert.strictEqual(interpreter.scope.get('result2').value, 5);
+      assert.strictEqual(interpreter.scope.get('result3').value, 7);
+    });
+  });
+
+  describe('Higher-Order Functions (Turing Complete)', () => {
+    it('should demonstrate Turing completeness through higher-order functions', () => {
+      const code = `
+        // Higher-order functions that can simulate any computable function
+        
+        // Test with factorial using fixed point
+        factorialHelper : f n ->
+          when n is
+            0 then 1
+            _ then n * (f (n - 1));
+        
+        // Test with small values
+        testFactorial : factorialHelper (n -> 1) 0;
+        testFactorial2 : factorialHelper (n -> n * 1) 1;
+      `;
+
+      const interpreter = interpret(code);
+      
+      assert.strictEqual(interpreter.scope.get('testFactorial').value, 1);
+      // The helper calls f(0) when n=1; with f = (n -> n * 1), this evaluates to 0
+      assert.strictEqual(interpreter.scope.get('testFactorial2').value, 0);
+    });
+  });
+
+  describe('SKI Combinator Calculus (Basic)', () => {
+    it('should implement basic SKI combinators', () => {
+      const code = `
+        // SKI Combinator Calculus - basic version
+        
+        // K combinator: Kxy = x
+        K : x y -> x;
+        
+        // I combinator: Ix = x
+        I : x -> x;
+        
+        // Test I combinator
+        testI : I 42;
+        
+        // Test K combinator
+        testK : K 10 20;
+        
+        // Test composition
+        compose : f g x -> f (g x);
+        testCompose : compose (x -> x + 1) (x -> x * 2) 5;
+      `;
+
+      const interpreter = interpret(code);
+      
+      assert.strictEqual(interpreter.scope.get('testI').value, 42);
+      assert.strictEqual(interpreter.scope.get('testK').value, 10);
+      assert.strictEqual(interpreter.scope.get('testCompose').value, 11); // (5*2)+1 = 11
+    });
+  });
+
+  describe('Mutual Recursion (Turing Complete)', () => {
+    it('should demonstrate Turing completeness through mutual recursion', () => {
+      const code = `
+        // Mutual recursion example - isEven and isOdd
+        // This demonstrates that our language can handle complex recursive patterns
+        
+        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);
+        
+        // Test mutual recursion
+        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);
+    });
+  });
+}); 
\ No newline at end of file
diff --git a/js/baba-yaga/tests/typed_curried_functions.test.js b/js/baba-yaga/tests/typed_curried_functions.test.js
new file mode 100644
index 0000000..010e2e1
--- /dev/null
+++ b/js/baba-yaga/tests/typed_curried_functions.test.js
@@ -0,0 +1,222 @@
+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('Typed Curried Functions', () => {
+  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('Basic Typed Curried Function Parsing', () => {
+    it('should parse single-parameter typed curried function', () => {
+      const code = 'multiply : (x: Float) -> (Float -> Float) -> y -> x * y;';
+      const lexer = createLexer(code);
+      const tokens = lexer.allTokens();
+      const parser = createParser(tokens);
+      const ast = parser.parse();
+      
+      assert.strictEqual(ast.body.length, 1);
+      assert.strictEqual(ast.body[0].type, 'CurriedFunctionDeclaration');
+      assert.strictEqual(ast.body[0].name, 'multiply');
+      assert.strictEqual(ast.body[0].param.name, 'x');
+      assert.deepStrictEqual(ast.body[0].param.type, { type: 'PrimitiveType', name: 'Float' });
+      assert.strictEqual(ast.body[0].returnType.type, 'FunctionType');
+    });
+
+    it('should parse multi-step typed curried function', () => {
+      const code = 'add3 : (x: Int) -> (Int -> (Int -> Int)) -> y -> z -> x + y + z;';
+      const lexer = createLexer(code);
+      const tokens = lexer.allTokens();
+      const parser = createParser(tokens);
+      const ast = parser.parse();
+      
+      assert.strictEqual(ast.body.length, 1);
+      assert.strictEqual(ast.body[0].type, 'CurriedFunctionDeclaration');
+    });
+  });
+
+  describe('Typed Curried Function Execution', () => {
+    it('should execute basic typed curried function', () => {
+      const code = `
+        multiply : (x: Float) -> (Float -> Float) -> y -> x * y;
+        double : multiply 2.0;
+        result : double 5.0;
+      `;
+      const interpreter = interpret(code);
+      
+      const multiply = interpreter.scope.get('multiply');
+      assert.strictEqual(multiply.type, 'Function');
+      
+      const double = interpreter.scope.get('double');
+      assert.strictEqual(double.type, 'Function');
+      
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result.value, 10.0);
+    });
+
+    it('should validate parameter types in curried functions', () => {
+      const code = `
+        multiply : (x: Float) -> (Float -> Float) -> y -> x * y;
+        double : multiply 2.0;
+      `;
+      const interpreter = interpret(code);
+      
+      // This should work - Float parameter
+      const double = interpreter.scope.get('double');
+      assert.strictEqual(double.type, 'Function');
+      
+      // Test type validation on second parameter
+      const code2 = `
+        result : double 5.0;
+      `;
+      const lexer2 = createLexer(code2);
+      const tokens2 = lexer2.allTokens();
+      const parser2 = createParser(tokens2);
+      const ast2 = parser2.parse();
+      const interpreter2 = createInterpreter(ast2, { scope: interpreter.scope });
+      interpreter2.interpret();
+      
+      assert.strictEqual(interpreter2.scope.get('result').value, 10.0);
+    });
+
+    it('should reject invalid parameter types', () => {
+      const code = `
+        multiply : (x: Float) -> (Float -> Float) -> y -> x * y;
+        result : multiply "invalid";
+      `;
+      
+      assert.throws(() => {
+        interpret(code);
+      }, /Type mismatch.*Expected Float.*got String/);
+    });
+
+    it('should handle Int to Float widening in curried functions', () => {
+      const code = `
+        multiply : (x: Float) -> (Float -> Float) -> y -> x * y;
+        double : multiply 2;  // Int should widen to Float
+        result : double 5.0;
+      `;
+      const interpreter = interpret(code);
+      
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result.value, 10.0);
+    });
+  });
+
+  describe('Complex Typed Curried Functions', () => {
+    it('should handle three-parameter curried function', () => {
+      const code = `
+        add3 : (x: Int) -> (Int -> (Int -> Int)) -> y -> z -> x + y + z;
+        add5 : add3 5;
+        add5and3 : add5 3;
+        result : add5and3 2;
+      `;
+      const interpreter = interpret(code);
+      
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result.value, 10);
+    });
+
+    it('should validate return types in curried functions', () => {
+      const code = `
+        badFunc : (x: Int) -> (String -> Int) -> y -> x + y;  // Returns String but declares Int
+        badFunc5 : badFunc 5;
+        result : badFunc5 "test";
+      `;
+      
+      // This should fail because x + y returns String but function declares Int return type
+      assert.throws(() => {
+        interpret(code);
+      }, /Return type mismatch.*Expected Int.*got String/);
+    });
+
+    it('should support function type parameters', () => {
+      // Test that we can at least parse and use functions with function return types
+      const code = `
+        makeAdder : (x: Int) -> (Int -> Int) -> y -> x + y;
+        add5 : makeAdder 5;
+        result : add5 3;
+      `;
+      const interpreter = interpret(code);
+      
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result.value, 8);
+    });
+  });
+
+  describe('Backward Compatibility', () => {
+    it('should still support untyped curried functions', () => {
+      const code = `
+        multiply : x -> y -> x * y;
+        double : multiply 2.0;
+        result : double 5.0;
+      `;
+      const interpreter = interpret(code);
+      
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result.value, 10.0);
+    });
+
+    it('should still support multi-parameter typed functions', () => {
+      const code = `
+        add : (x: Float, y: Float) -> Float -> x + y;
+        result : add 2.0 3.0;
+      `;
+      const interpreter = interpret(code);
+      
+      const result = interpreter.scope.get('result');
+      assert.strictEqual(result.value, 5.0);
+    });
+
+    it('should distinguish between multi-param and curried syntax', () => {
+      const code1 = `
+        multiParam : (x: Float, y: Float) -> Float -> x + y;
+        result1 : multiParam 2.0 3.0;
+      `;
+      
+      const code2 = `
+        curried : (x: Float) -> (Float -> Float) -> y -> x + y;
+        addTwo : curried 2.0;
+        result2 : addTwo 3.0;
+      `;
+      
+      const interpreter1 = interpret(code1);
+      const interpreter2 = interpret(code2);
+      
+      assert.strictEqual(interpreter1.scope.get('result1').value, 5.0);
+      assert.strictEqual(interpreter2.scope.get('result2').value, 5.0);
+    });
+  });
+
+  describe('Error Handling', () => {
+    it('should provide clear error messages for type mismatches', () => {
+      const code = `
+        multiply : (x: Float) -> (Float -> Float) -> y -> x * y;
+        result : multiply "not a number";
+      `;
+      
+      assert.throws(() => {
+        interpret(code);
+      }, /Type mismatch in function 'multiply': Expected Float for parameter 'x', but got String/);
+    });
+
+    it('should validate return type of curried function', () => {
+      const code = `
+        badFunction : (x: Int) -> (Int -> String) -> y -> x + y;  // Returns Int but declares String
+        add5 : badFunction 5;
+        result : add5 3;
+      `;
+      
+      assert.throws(() => {
+        interpret(code);
+      }, /Return type mismatch in function 'add5': Expected String, but got Int/);
+    });
+  });
+});
\ No newline at end of file
diff --git a/js/baba-yaga/tests/utilities.test.js b/js/baba-yaga/tests/utilities.test.js
new file mode 100644
index 0000000..5303fea
--- /dev/null
+++ b/js/baba-yaga/tests/utilities.test.js
@@ -0,0 +1,278 @@
+import { createLexer } from '../src/core/lexer.js';
+import { createParser } from '../src/core/parser.js';
+import { createInterpreter } from '../src/core/interpreter.js';
+
+function runBabaYaga(code) {
+  const lexer = createLexer(code);
+  const tokens = lexer.allTokens();
+  const parser = createParser(tokens);
+  const ast = parser.parse();
+  
+  const outputs = [];
+  const debugOutputs = [];
+  
+  const host = {
+    io: {
+      out: (...args) => outputs.push(args.join(' ')),
+      debug: (...args) => debugOutputs.push(args.join(' ')),
+      in: () => '',
+    },
+  };
+  
+  const interpreter = createInterpreter(ast, host);
+  const result = interpreter.interpret();
+  
+  return { outputs, debugOutputs, result };
+}
+
+describe('Utility Functions', () => {
+  describe('validate namespace', () => {
+    test('validate.notEmpty', () => {
+      const code = `
+        io.out (validate.notEmpty "hello");
+        io.out (validate.notEmpty "");
+        io.out (validate.notEmpty [1, 2, 3]);
+        io.out (validate.notEmpty []);
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['true', 'false', 'true', 'false']);
+    });
+
+    test('validate.range', () => {
+      const code = `
+        io.out (validate.range 1 10 5);
+        io.out (validate.range 1 10 15);
+        io.out (validate.range 1 10 1);
+        io.out (validate.range 1 10 10);
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['true', 'false', 'true', 'true']);
+    });
+
+    test('validate.email', () => {
+      const code = `
+        io.out (validate.email "test@example.com");
+        io.out (validate.email "invalid-email");
+        io.out (validate.email "user@domain.co.uk");
+        io.out (validate.email "@domain.com");
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['true', 'false', 'true', 'false']);
+    });
+
+    test('validate.type', () => {
+      const code = `
+        io.out (validate.type "Int" 42);
+        io.out (validate.type "String" 42);
+        io.out (validate.type "String" "hello");
+        io.out (validate.type "Bool" true);
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['true', 'false', 'true', 'true']);
+    });
+  });
+
+  describe('text namespace', () => {
+    test('text.lines', () => {
+      const code = `
+        // Test with single line (since escape sequences aren't implemented yet)
+        lines : text.lines "hello world test";
+        io.out (length lines);
+        first : lines.0;
+        io.out first;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['1', 'hello world test']);
+    });
+
+    test('text.words', () => {
+      const code = `
+        words : text.words "hello   world  test";
+        io.out (length words);
+        io.out words.0;
+        io.out words.1;
+        io.out words.2;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['3', 'hello', 'world', 'test']);
+    });
+
+    test('text.padLeft and text.padRight', () => {
+      const code = `
+        io.out (text.padLeft 10 "hi");
+        io.out (text.padRight 10 "hi");
+        io.out (str.length (text.padLeft 5 "test"));
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs[0]).toBe('        hi');
+      expect(outputs[1]).toBe('hi        ');
+      expect(outputs[2]).toBe('5');
+    });
+  });
+
+  describe('utility functions', () => {
+    test('chunk', () => {
+      const code = `
+        numbers : [1, 2, 3, 4, 5, 6];
+        chunks : chunk numbers 2;
+        io.out (length chunks);
+        firstChunk : chunks.0;
+        io.out (length firstChunk);
+        io.out firstChunk.0;
+        io.out firstChunk.1;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['3', '2', '1', '2']);
+    });
+
+    test('range', () => {
+      const code = `
+        r1 : range 1 5;
+        r2 : range 5 1;
+        io.out (length r1);
+        io.out r1.0;
+        io.out r1.4;
+        io.out (length r2);
+        io.out r2.0;
+        io.out r2.4;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['5', '1', '5', '5', '5', '1']);
+    });
+
+    test('repeat', () => {
+      const code = `
+        repeated : repeat 3 "hello";
+        io.out (length repeated);
+        io.out repeated.0;
+        io.out repeated.1;
+        io.out repeated.2;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['3', 'hello', 'hello', 'hello']);
+    });
+  });
+
+  describe('sort namespace', () => {
+    test('sort.by with numbers', () => {
+      const code = `
+        numbers : [3, 1, 4, 1, 5, 9, 2, 6];
+        sorted : sort.by numbers (x -> x);
+        io.out sorted.0;
+        io.out sorted.1;
+        io.out sorted.7;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['1', '1', '9']);
+    });
+
+    test('sort.by with objects', () => {
+      const code = `
+        people : [
+          {name: "Alice", age: 30},
+          {name: "Bob", age: 25},
+          {name: "Charlie", age: 35}
+        ];
+        sortedByAge : sort.by people (p -> p.age);
+        first : sortedByAge.0;
+        second : sortedByAge.1;
+        third : sortedByAge.2;
+        io.out first.name;
+        io.out second.name;
+        io.out third.name;
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['Bob', 'Alice', 'Charlie']);
+    });
+  });
+
+  describe('group namespace', () => {
+    test('group.by', () => {
+      const code = `
+        numbers : [1, 2, 3, 4, 5, 6];
+        grouped : group.by numbers (x -> x % 2 = 0);
+        evenGroup : grouped."true";
+        oddGroup : grouped."false";
+        io.out (length evenGroup);
+        io.out (length oddGroup);
+        io.out (evenGroup.0);
+        io.out (oddGroup.0);
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['3', '3', '2', '1']);
+    });
+  });
+
+  describe('random namespace', () => {
+    test('random.choice', () => {
+      const code = `
+        list : [1, 2, 3];
+        choice : random.choice list;
+        io.out (validate.range 1 3 choice);
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['true']);
+    });
+
+    test('random.shuffle', () => {
+      const code = `
+        list : [1, 2, 3, 4, 5];
+        shuffled : random.shuffle list;
+        io.out (length shuffled);
+        io.out (length list);
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['5', '5']);
+    });
+
+    test('random.range', () => {
+      const code = `
+        r : random.range 1 10;
+        io.out (validate.range 1 10 r);
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['true']);
+    });
+  });
+
+  describe('debug namespace', () => {
+    test('debug.print', () => {
+      const code = `
+        testFunc : x -> x * 2;
+        debug.print 42;
+        debug.print testFunc;
+      `;
+      const { debugOutputs } = runBabaYaga(code);
+      expect(debugOutputs.length).toBe(2);
+      expect(debugOutputs[0]).toContain('42');
+      expect(debugOutputs[1]).toContain('function');
+    });
+
+    test('debug.inspect', () => {
+      const code = `
+        testFunc : x -> x * 2;
+        inspection : debug.inspect testFunc;
+        len : str.length inspection;
+        io.out (len > 10);
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['true']);
+    });
+  });
+
+  describe('assert function', () => {
+    test('assert success', () => {
+      const code = `
+        assert (2 + 2 = 4) "Math works";
+        io.out "Success";
+      `;
+      const { outputs } = runBabaYaga(code);
+      expect(outputs).toEqual(['Success']);
+    });
+
+    test('assert failure', () => {
+      const code = `assert (2 + 2 = 5) "This should fail";`;
+      expect(() => runBabaYaga(code)).toThrow('Assertion failed: This should fail');
+    });
+  });
+});
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');
+  });
+});
diff --git a/js/baba-yaga/tests/with-type-system-edge-cases.test.js b/js/baba-yaga/tests/with-type-system-edge-cases.test.js
new file mode 100644
index 0000000..048d60a
--- /dev/null
+++ b/js/baba-yaga/tests/with-type-system-edge-cases.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';
+
+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: type system edge cases', () => {
+  it('handles complex type combinations in single with block', () => {
+    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 numeric type widening correctly', () => {
+    const code = `
+      testNumericWidening : x y ->
+        with (
+          intVal Int; intVal : x;
+          floatVal Float; floatVal : intVal;  // Int -> Float
+          numberVal Number; numberVal : floatVal;  // Float -> Number
+          mixedSum Number; mixedSum : intVal + 0.5;  // Int + Float -> Number
+        ) -> { intVal: intVal, floatVal: floatVal, numberVal: numberVal, mixedSum: mixedSum };
+      result : testNumericWidening 5 3;
+    `;
+    const itp = interpret(code);
+    const result = itp.scope.get('result');
+    assert.strictEqual(result.intVal.value, 5);
+    assert.strictEqual(result.floatVal.value, 5);
+    assert.strictEqual(result.numberVal.value, 5);
+    assert.strictEqual(result.mixedSum.value, 5.5);
+  });
+
+  it('validates types with complex computed expressions', () => {
+    const code = `
+      testComputedTypes : a b ->
+        with (
+          sum Int; sum : a + b;
+          product Int; product : a * b;
+          difference Int; difference : a - b;
+          isPositive Bool; isPositive : sum > 0;
+          isLarge Bool; isLarge : product > 100;
+          sumStr String; sumStr : str.concat "Sum: " "valid";
+          productStr String; productStr : str.concat "Product: " "valid";
+        ) -> { sum: sum, product: product, difference: difference, isPositive: isPositive, isLarge: isLarge, sumStr: sumStr, productStr: productStr };
+      result : testComputedTypes 7 8;
+    `;
+    const itp = interpret(code);
+    const result = itp.scope.get('result');
+    assert.strictEqual(result.sum.value, 15);
+    assert.strictEqual(result.product.value, 56);
+    assert.strictEqual(result.difference.value, -1);
+    assert.strictEqual(result.isPositive, true);
+    assert.strictEqual(result.isLarge, false);
+    assert.strictEqual(result.sumStr, 'Sum: valid');
+    assert.strictEqual(result.productStr, 'Product: valid');
+  });
+
+  it('validates types with mathematical functions', () => {
+    const code = `
+      testMathTypes : x y ->
+        with (
+          sqrtResult Float; sqrtResult : math.sqrt x;
+          powResult Float; powResult : math.pow x y;
+          absResult Number; absResult : math.abs x;
+          complexResult Float; complexResult : (sqrtResult * powResult) + absResult;
+        ) -> { sqrtResult: sqrtResult, powResult: powResult, absResult: absResult, complexResult: complexResult };
+      result : testMathTypes 16 2;
+    `;
+    const itp = interpret(code);
+    const result = itp.scope.get('result');
+    assert.strictEqual(result.sqrtResult.value, 4);
+    assert.strictEqual(result.powResult.value, 256);
+    assert.strictEqual(result.absResult.value, 16);
+    assert.strictEqual(result.complexResult.value, 1040);
+  });
+
+  it('validates types with string operations', () => {
+    const code = `
+      testStringTypes : input ->
+        with (
+          length Int; length : str.length input;
+          trimmed String; trimmed : str.trim input;
+          upper String; upper : str.upper input;
+          isEmpty Bool; isEmpty : length = 0;
+          hasContent Bool; hasContent : length > 0;
+          description String; description : str.concat "Length: " "valid";
+        ) -> { length: length, trimmed: trimmed, upper: upper, isEmpty: isEmpty, hasContent: hasContent, description: description };
+      result : testStringTypes "  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: valid');
+  });
+
+  it('validates types with list and table operations', () => {
+    const code = `
+      testDataStructureTypes : items ->
+        with (
+          count Int; count : length items;
+          isEmpty Bool; isEmpty : count = 0;
+          hasItems Bool; hasItems : count > 0;
+          tags List; tags : [count, isEmpty, hasItems];
+          summary Table; summary : { count: count, empty: isEmpty, hasItems: hasItems };
+        ) -> { count: count, isEmpty: isEmpty, hasItems: hasItems, tags: tags, summary: summary };
+      result : testDataStructureTypes [1, 2, 3];
+    `;
+    const itp = interpret(code);
+    const result = itp.scope.get('result');
+    assert.strictEqual(result.count.value, 3);
+    assert.strictEqual(result.isEmpty, false);
+    assert.strictEqual(result.hasItems, true);
+            assert.deepStrictEqual(result.tags.map(x => typeof x === 'object' ? x.value : x), [3, false, true]);
+            // Baba Yaga objects have properties Map structure
+        assert.strictEqual(result.summary.properties.get('count').value, 3);
+        assert.strictEqual(result.summary.properties.get('empty'), false);
+        assert.strictEqual(result.summary.properties.get('hasItems'), true);
+  });
+
+  it('handles complex nested structures with type validation', () => {
+    const code = `
+      testNestedTypes : user ->
+        with (
+          userId Int; userId : user.id;
+          userName String; userName : str.upper (str.trim user.name);
+          userAge Int; userAge : user.age;
+          isAdult Bool; isAdult : userAge >= 18;
+          ageGroup String; ageGroup : when isAdult is
+            true then "adult"
+            _ then "minor";
+          userProfile Table; userProfile : {
+            id: userId,
+            name: userName,
+            age: userAge,
+            status: ageGroup,
+            verified: isAdult,
+            tags: [userId, ageGroup, isAdult]
+          };
+        ) -> userProfile;
+      result : testNestedTypes { id: 1, name: "  john doe  ", age: 25 };
+    `;
+    const itp = interpret(code);
+    const result = itp.scope.get('result');
+    assert.strictEqual(result.id.value, 1);
+    assert.strictEqual(result.name, 'JOHN DOE');
+    assert.strictEqual(result.age.value, 25);
+    assert.strictEqual(result.status, 'adult');
+    assert.strictEqual(result.verified, true);
+            assert.deepStrictEqual(result.tags.map(x => typeof x === 'object' ? x.value : x), [1, 'adult', true]);
+  });
+
+  it('handles conditional type assignment with validation', () => {
+    const code = `
+      testConditionalTypes : x ->
+        with (
+          numericType : when (x > 0) is
+            true then "positive"
+            _ then when (x < 0) is
+              true then "negative"
+              _ then "zero";
+          isValid : (x >= -100) and (x <= 100);
+          result : when isValid is
+            true then { value: x, type: numericType, valid: true }
+            _ then { value: "invalid", type: "error", valid: false };
+        ) -> result;
+      result1 : testConditionalTypes 50;
+      result2 : testConditionalTypes -25;
+      result3 : testConditionalTypes 0;
+      result4 : testConditionalTypes 150;
+    `;
+    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.properties.get('value').value, 50);
+    assert.strictEqual(result1.properties.get('type'), 'positive');
+    assert.strictEqual(result1.properties.get('valid'), true);
+    
+    assert.strictEqual(result2.properties.get('value').value, -25);
+    assert.strictEqual(result2.properties.get('type'), 'negative');
+    assert.strictEqual(result2.properties.get('valid'), true);
+    
+    assert.strictEqual(result3.properties.get('value').value, 0);
+    assert.strictEqual(result3.properties.get('type'), 'zero');
+    assert.strictEqual(result3.properties.get('valid'), true);
+    
+    assert.strictEqual(result4.properties.get('value'), 'invalid');
+    assert.strictEqual(result4.properties.get('type'), 'error');
+    assert.strictEqual(result4.properties.get('valid'), false);
+  });
+});
diff --git a/js/baba-yaga/tests/with-when-expressions.test.js b/js/baba-yaga/tests/with-when-expressions.test.js
new file mode 100644
index 0000000..af14d10
--- /dev/null
+++ b/js/baba-yaga/tests/with-when-expressions.test.js
@@ -0,0 +1,158 @@
+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: when expressions', () => {
+  it('evaluates simple single-line when expressions', () => {
+    const code = `
+      test : x ->
+        with (status : when x is 0 then "zero" _ then "other";) -> status;
+      result : test 0;
+    `;
+    const itp = interpret(code);
+    assert.strictEqual(itp.scope.get('result'), 'zero');
+  });
+
+  it('evaluates multi-line when expressions', () => {
+    const code = `
+      test : x ->
+        with (
+          status : when x is
+            0 then "zero"
+            _ then when (x < 10) is
+              true then "small"
+              _ then "large";
+        ) -> status;
+      result1 : test 0;
+      result2 : test 5;
+      result3 : test 15;
+    `;
+    const itp = interpret(code);
+    assert.strictEqual(itp.scope.get('result1'), 'zero');
+    assert.strictEqual(itp.scope.get('result2'), 'small');
+    assert.strictEqual(itp.scope.get('result3'), 'large');
+  });
+
+  it('evaluates complex when expressions with pattern guards', () => {
+    const code = `
+      test : x ->
+        with (
+          category : when x is
+            n if (n < 0) then "negative"
+            0 then "zero"
+            n if (n > 10) then "large"
+            _ then "small";
+        ) -> category;
+      result1 : test -5;
+      result2 : test 0;
+      result3 : test 5;
+      result4 : test 15;
+    `;
+    const itp = interpret(code);
+    assert.strictEqual(itp.scope.get('result1'), 'negative');
+    assert.strictEqual(itp.scope.get('result2'), 'zero');
+    assert.strictEqual(itp.scope.get('result3'), 'small');
+    assert.strictEqual(itp.scope.get('result4'), 'large');
+  });
+
+  it('evaluates mixed when expressions with other types', () => {
+    const code = `
+      test : x ->
+        with (
+          num : x + 1;
+          category : when x is
+            0 then "zero"
+            _ then when (x < 10) is
+              true then "small"
+              _ then "large";
+          isValid : x > 0;
+        ) -> { num: num, category: category, isValid: isValid };
+      result : test 5;
+    `;
+    const itp = interpret(code);
+    const result = itp.scope.get('result');
+    assert.strictEqual(result.num.value, 6);
+    assert.strictEqual(result.category, 'small');
+    assert.strictEqual(result.isValid, true);
+  });
+
+  it('evaluates deeply nested when expressions', () => {
+    const code = `
+      test : x ->
+        with (
+          status : when x is
+            0 then "zero"
+            _ then when (x < 10) is
+              true then "small"
+              _ then when (x < 100) is
+                true then "medium"
+                _ then when (x < 1000) is
+                  true then "large"
+                  _ then "huge";
+        ) -> status;
+      result1 : test 0;
+      result2 : test 5;
+      result3 : test 50;
+      result4 : test 500;
+      result5 : test 5000;
+    `;
+    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');
+  });
+
+  it('works with arithmetic expressions in when conditions', () => {
+    const code = `
+      test : x ->
+        with (
+          status : when (x + 1) is
+            1 then "zero-based"
+            _ then when ((x * 2) > 10) is
+              true then "large"
+              _ then "small";
+        ) -> status;
+      result1 : test 0;
+      result2 : test 3;
+      result3 : test 6;
+    `;
+    const itp = interpret(code);
+    assert.strictEqual(itp.scope.get('result1'), 'zero-based');
+    assert.strictEqual(itp.scope.get('result2'), 'small');
+    assert.strictEqual(itp.scope.get('result3'), 'large');
+  });
+
+  it('works with function calls in when conditions', () => {
+    const code = `
+      test : list ->
+        with (
+          len : length list;
+          status : when len is
+            0 then "empty"
+            _ then when (len > 5) is
+              true then "long"
+              _ then "short";
+        ) -> status;
+      result1 : test [];
+      result2 : test [1, 2, 3];
+      result3 : test [1, 2, 3, 4, 5, 6];
+    `;
+    const itp = interpret(code);
+    assert.strictEqual(itp.scope.get('result1'), 'empty');
+    assert.strictEqual(itp.scope.get('result2'), 'short');
+    assert.strictEqual(itp.scope.get('result3'), 'long');
+  });
+});