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); }); });