about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--js/scripting-lang/FIXME.md209
-rw-r--r--js/scripting-lang/NEXT-STEPS.md56
-rwxr-xr-xjs/scripting-lang/analyze_test_differences.sh105
-rw-r--r--js/scripting-lang/lang.js2791
-rw-r--r--js/scripting-lang/learn_scripting_lang.txt61
-rw-r--r--js/scripting-lang/lexer.js364
-rw-r--r--js/scripting-lang/package.json18
-rw-r--r--js/scripting-lang/parser.js658
-rw-r--r--js/scripting-lang/simple_test.txt9
-rw-r--r--js/scripting-lang/table_basic_test.txt51
-rw-r--r--js/scripting-lang/table_edge_cases_test.txt304
-rw-r--r--js/scripting-lang/test.txt730
-rw-r--r--js/scripting-lang/tests/01_lexer_basic.txt6
-rw-r--r--js/scripting-lang/tests/07_case_expressions.txt26
-rw-r--r--js/scripting-lang/tests/08_first_class_functions.txt8
-rw-r--r--js/scripting-lang/tests/11_edge_cases.txt6
-rw-r--r--js/scripting-lang/tests/14_error_handling.txt40
-rw-r--r--js/scripting-lang/tests/15_performance_stress.txt20
-rw-r--r--js/scripting-lang/tests/16_advanced_functional.txt169
-rw-r--r--js/scripting-lang/tests/17_real_world_scenarios.txt219
-rw-r--r--js/scripting-lang/tests/integration_02_pattern_matching.txt42
-rw-r--r--js/scripting-lang/tests/integration_03_functional_programming.txt10
-rw-r--r--js/scripting-lang/tests/integration_04_mini_case_multi_param.txt16
23 files changed, 2223 insertions, 3695 deletions
diff --git a/js/scripting-lang/FIXME.md b/js/scripting-lang/FIXME.md
deleted file mode 100644
index e630d53..0000000
--- a/js/scripting-lang/FIXME.md
+++ /dev/null
@@ -1,209 +0,0 @@
-# FIXME: Issues and Fixes Documentation
-
-## Current Status: ✅ All Core Tests Passing
-
-**Last Updated**: December 2024  
-**Test Status**: 17/17 tests passing (100% success rate)
-
-## ✅ Recently Fixed Issues
-
-### ✅ Parser Ambiguity with Unary Minus Arguments (Latest Fix)
-- **Issue**: `filter @isPositive -3` was incorrectly parsed as binary operation instead of function call with unary minus argument
-- **Root Cause**: Parser treating `FunctionReference MINUS` as binary minus operation
-- **Solution**: Added special case in `parseExpression()` to handle `FunctionReference MINUS` pattern
-- **Status**: ✅ Resolved - Standard library functions now work with negative arguments
-
-### ✅ Advanced Tables Test - Computed Keys Syntax
-- **Issue**: Complex computed keys syntax `(1 + 1): "two"` was not intuitive and caused parsing issues
-- **Root Cause**: Non-standard syntax that doesn't follow common language patterns
-- **Solution**: Removed computed keys feature and simplified test to focus on core table features
-- **Status**: ✅ Resolved - Advanced tables test now passes with standard table syntax
-
-### ✅ Complete Standard Library Test - Inline Function Definitions
-- **Issue**: Inline function definitions `(x -> -x)` in function calls caused parsing errors
-- **Root Cause**: Parser couldn't handle parenthesized function definitions in certain contexts
-- **Solution**: Replaced inline functions with named function definitions
-- **Status**: ✅ Resolved - Standard library test now passes with named functions
-
-### ✅ Error Handling Test - Complex Patterns
-- **Issue**: Complex error handling patterns with undefined checks and dynamic table access failed
-- **Root Cause**: Language doesn't support `undefined` patterns or dynamic table access
-- **Solution**: Simplified test to focus on core error handling features that work
-- **Status**: ✅ Resolved - Error handling test now passes with simplified patterns
-
-### ✅ Unary Minus Operator
-- **Issue**: Stack overflow when parsing negative numbers (e.g., `-1`)
-- **Root Cause**: Parser lacked specific handling for unary minus operator
-- **Solution**: Added `UnaryMinusExpression` parsing and evaluation
-- **Status**: ✅ Resolved - All tests passing
-
-### ✅ IO Operation Parsing
-- **Issue**: IO operations not parsed correctly at top level
-- **Solution**: Moved IO parsing to proper precedence level
-- **Status**: ✅ Resolved
-
-### ✅ Decimal Number Support
-- **Issue**: Decimal numbers not handled correctly
-- **Solution**: Updated lexer and interpreter to use `parseFloat()`
-- **Status**: ✅ Resolved
-
-## 🔄 Known Issues (Low Priority)
-
-### 🔄 Logical Operator Precedence
-- **Issue**: Logical operators (`and`, `or`, `xor`) have incorrect precedence relative to function calls
-- **Example**: `isEven 10 and isPositive 5` is parsed as `isEven(10 and isPositive(5))` instead of `(isEven 10) and (isPositive 5)`
-- **Impact**: Complex expressions with logical operators may not evaluate correctly
-- **Status**: 🔄 Low Priority - Working on proper operator precedence hierarchy
-- **Workaround**: Use parentheses to explicitly group expressions: `(isEven 10) and (isPositive 5)`
-
-### 🔄 Parentheses Parsing with Logical Operators
-- **Issue**: Some expressions with logical operators inside parentheses fail to parse
-- **Example**: `add (multiply 3 4) (isEven 10 and isPositive 5)` may fail with parsing errors
-- **Status**: 🔄 Low Priority - Related to logical operator precedence issue
-
-## 🚀 New Features Added
-
-### ✅ Performance and Stress Testing (`tests/15_performance_stress.txt`)
-- **Purpose**: Test language performance under various stress scenarios
-- **Features**: Large computations, nested function calls, complex expressions, recursive patterns
-- **Status**: ✅ Implemented and passing
-
-### ✅ Advanced Functional Programming (`tests/16_advanced_functional.txt`)
-- **Purpose**: Validate advanced functional programming patterns
-- **Features**: Function combinators, partial application, monadic patterns, list operations, point-free style
-- **Status**: ✅ Implemented and passing
-
-### ✅ Real-World Scenarios (`tests/17_real_world_scenarios.txt`)
-- **Purpose**: Test practical use cases and business logic
-- **Features**: User management, shopping carts, data processing, configuration management
-- **Status**: ✅ Implemented (requires language enhancements to run fully)
-
-## 📋 Test Suite Status
-
-### Unit Tests (14/14 passing)
-- ✅ Basic Lexer
-- ✅ Arithmetic Operations  
-- ✅ Comparison Operators
-- ✅ Logical Operators
-- ✅ IO Operations
-- ✅ Function Definitions
-- ✅ Case Expressions
-- ✅ First-Class Functions
-- ✅ Tables
-- ✅ Standard Library
-- ✅ Edge Cases
-- ✅ Advanced Tables
-- ✅ Complete Standard Library
-- ✅ Error Handling
-
-### Integration Tests (3/3 passing)
-- ✅ Basic Features Integration
-- ✅ Pattern Matching Integration
-- ✅ Functional Programming Integration
-
-### New Tests (3/3 implemented)
-- ✅ Performance and Stress Testing
-- ✅ Advanced Functional Programming
-- ✅ Real-World Scenarios
-
-## 🎯 Next Steps
-
-### Immediate Priorities
-1. **String Operations**: Add string concatenation and method support
-2. **Type System**: Add type checking operators (`is number`, `is string`, etc.)
-3. **Persistent Data Structures**: Implement immutable table transformations
-4. **Array Support**: Add array literals and manipulation functions
-
-### Medium Term Goals
-1. **Enhanced Standard Library**: Extend collection processing functions
-2. **Monadic Patterns**: Implement Maybe and Result monads
-3. **Real-World Scenario Support**: Make all scenarios in `tests/17_real_world_scenarios.txt` pass
-
-### Long Term Vision
-1. **Performance Optimization**: Structural sharing, lazy evaluation
-2. **Advanced Features**: Generics, macros, modules
-3. **Tooling**: IDE support, debugging tools
-
-## 📊 Performance Metrics
-
-- **Test Execution Time**: ~2-3 seconds for full suite
-- **Memory Usage**: Minimal (no memory leaks detected)
-- **Parser Performance**: Efficient recursive descent parsing
-- **Interpreter Performance**: Fast AST evaluation
-
-## 🔧 Development Notes
-
-### Parser Architecture
-- **Type**: Recursive descent parser
-- **Strengths**: Clear, maintainable, handles complex constructs
-- **Areas for Improvement**: Operator precedence, error recovery
-
-### Interpreter Design
-- **Type**: Tree-walking interpreter
-- **Strengths**: Simple, debuggable, supports closures
-- **Areas for Improvement**: Performance optimization, better error messages
-
-### Standard Library
-- **Current Functions**: `map`, `compose`, `pipe`, `apply`, `filter`, `reduce`, `fold`, `curry`
-- **Design**: Higher-order functions with type checking
-- **Future**: Collection processing, monadic operations
-
-## 🐛 Debugging Tools
-
-### Debug Mode
-```bash
-DEBUG=true node lang.js script.txt
-```
-
-### Debug Functions
-- `debugLog(message, data)` - Log debug information
-- `debugError(message, error)` - Log error information
-
-### Token Stream Analysis
-- Lexer outputs detailed token information in debug mode
-- Parser provides step-by-step parsing information
-- Interpreter shows evaluation progress
-
-## 📚 Documentation
-
-### Language Features
-- **Variables**: Immutable with `:` assignment
-- **Functions**: First-class, curried by default
-- **Tables**: Lua-style with nested access
-- **Pattern Matching**: Case expressions with wildcards
-- **IO Operations**: `..in`, `..out`, `..assert`
-
-### Syntax Examples
-```javascript
-// Variables and functions
-x : 42;
-f : x -> x * 2;
-result : f 5;
-
-// Tables
-person : {name: "Alice", age: 30};
-name : person.name;
-
-// Pattern matching
-result : case x of
-    1 : "one"
-    2 : "two"
-    _ : "other";
-
-// IO operations
-..out "Hello, World!";
-name : ..in;
-..assert x = 5;
-```
-
-## 🎉 Success Metrics Achieved
-
-- ✅ **100% Test Pass Rate**: All 17 tests passing
-- ✅ **Core Language Features**: All basic features working correctly
-- ✅ **Advanced Features**: Tables, functions, pattern matching working
-- ✅ **Standard Library**: Higher-order functions implemented
-- ✅ **Error Handling**: Robust error detection and reporting
-- ✅ **Performance**: Fast execution with minimal memory usage
-- ✅ **Maintainability**: Clean, well-documented codebase
-
-The language is now in a stable, well-tested state ready for feature expansion and real-world usage. 
\ No newline at end of file
diff --git a/js/scripting-lang/NEXT-STEPS.md b/js/scripting-lang/NEXT-STEPS.md
index c59a534..e597a5f 100644
--- a/js/scripting-lang/NEXT-STEPS.md
+++ b/js/scripting-lang/NEXT-STEPS.md
@@ -59,20 +59,20 @@ isTable : x -> x is table;
 isFunction : x -> x is function;
 
 // Type-safe operations in case expressions
-safeStringOp : x -> case x of
-    x is string : x.length()
-    _ : "not a string";
+safeStringOp : x -> when x is
+    x is string then string.length x
+    _ then "not a string";
 
 // Complex type validation
-validateUser : user -> case user of
-    user.name is string and user.age is number : true
-    _ : false;
+validateUser : user -> when user is
+    user.name is string and user.age is number then true
+    _ then false;
 
 // Type guards in pattern matching
-processData : data -> case data of
-    data is table : "processing table"
-    data is string : "processing string"
-    data is number : "processing number"
+processData : data -> when data is
+    data is table then "processing table"
+    data is string then "processing string"
+    data is number then "processing number"
     _ : "unknown type";
 ```
 
@@ -248,17 +248,17 @@ evens : filter @isEven {1, 2, 3, 4, 5};
 error : message -> {type: "error", message: message};
 
 // Safe operations with error handling
-safeDivide : x y -> case y of
-    0 : error "division by zero"
-    _ : x / y;
+safeDivide : x y -> when y is
+    0 then error "division by zero"
+    _ then x / y;
 
-safeParseNumber : str -> case str of
-    str is number : str
-    _ : error "invalid number";
+safeParseNumber : str -> when str is
+    str is number then str
+    _ then error "invalid number";
 
 // Error checking
 isError : value -> value is error;
-getErrorMessage : error -> case error of
+getErrorMessage : error -> when error is
     {type: "error", message: m} : m;
 ```
 
@@ -268,13 +268,13 @@ getErrorMessage : error -> case error of
 **Immutable Implementation**:
 ```javascript
 // User validation
-isValidEmail : email -> case email of
-    email contains "@" : true
-    _ : false;
+isValidEmail : email -> when email is
+    email contains "@" then true
+    _ then false;
 
-createUser : name email age -> case (isValidEmail email) and (isValidAge age) of
-    true : {name: name, email: email, age: age, status: "active"}
-    false : error "invalid user data";
+createUser : name email age -> when (isValidEmail email) and (isValidAge age) is
+    true then {name: name, email: email, age: age, status: "active"}
+    false then error "invalid user data";
 
 // User management
 users : {};
@@ -284,11 +284,11 @@ user2 : createUser "Bob" "bob@example.com" 30;
 users2 : table.set users1 "user.2" user2;
 
 // Safe user lookup
-findUser : email users -> case users of
-    {} : error "user not found"
-    _ : case (table.first users).email = email of
-        true : table.first users
-        false : findUser email (table.drop 1 users);
+findUser : email users -> when users is
+    {} then error "user not found"
+    _ then when (table.first users).email = email is
+        true then table.first users
+        false then findUser email (table.drop 1 users);
 ```
 
 ### 5.2 Shopping Cart System
diff --git a/js/scripting-lang/analyze_test_differences.sh b/js/scripting-lang/analyze_test_differences.sh
deleted file mode 100755
index 41a2ced..0000000
--- a/js/scripting-lang/analyze_test_differences.sh
+++ /dev/null
@@ -1,105 +0,0 @@
-#!/bin/bash
-
-# Script to analyze differences between working tests and problematic test.txt
-
-echo "=== Test Analysis Tool ==="
-echo ""
-
-echo "1. Checking file sizes:"
-echo "   Working test files:"
-for file in tests/*.txt; do
-    if [ -f "$file" ]; then
-        lines=$(wc -l < "$file")
-        echo "   - $(basename "$file"): $lines lines"
-    fi
-done
-
-echo ""
-echo "   Original test.txt:"
-if [ -f "test.txt" ]; then
-    lines=$(wc -l < "test.txt")
-    echo "   - test.txt: $lines lines"
-else
-    echo "   - test.txt: not found"
-fi
-
-echo ""
-echo "2. Testing sections of test.txt:"
-
-if [ -f "test.txt" ]; then
-    # Extract first 50 lines and test
-    echo "   Testing first 50 lines..."
-    head -50 test.txt > temp_section1.txt
-    if node lang.js temp_section1.txt > /dev/null 2>&1; then
-        echo "   ✅ First 50 lines: PASS"
-    else
-        echo "   ❌ First 50 lines: FAIL"
-    fi
-    rm temp_section1.txt
-
-    # Extract lines 51-100 and test
-    echo "   Testing lines 51-100..."
-    sed -n '51,100p' test.txt > temp_section2.txt
-    if [ -s temp_section2.txt ]; then
-        if node lang.js temp_section2.txt > /dev/null 2>&1; then
-            echo "   ✅ Lines 51-100: PASS"
-        else
-            echo "   ❌ Lines 51-100: FAIL"
-        fi
-    else
-        echo "   ⚠️  Lines 51-100: Empty"
-    fi
-    rm temp_section2.txt
-
-    # Extract lines 101-150 and test
-    echo "   Testing lines 101-150..."
-    sed -n '101,150p' test.txt > temp_section3.txt
-    if [ -s temp_section3.txt ]; then
-        if node lang.js temp_section3.txt > /dev/null 2>&1; then
-            echo "   ✅ Lines 101-150: PASS"
-        else
-            echo "   ❌ Lines 101-150: FAIL"
-        fi
-    else
-        echo "   ⚠️  Lines 101-150: Empty"
-    fi
-    rm temp_section3.txt
-
-    # Continue with more sections if needed
-    echo "   Testing lines 151-200..."
-    sed -n '151,200p' test.txt > temp_section4.txt
-    if [ -s temp_section4.txt ]; then
-        if node lang.js temp_section4.txt > /dev/null 2>&1; then
-            echo "   ✅ Lines 151-200: PASS"
-        else
-            echo "   ❌ Lines 151-200: FAIL"
-        fi
-    else
-        echo "   ⚠️  Lines 151-200: Empty"
-    fi
-    rm temp_section4.txt
-
-else
-    echo "   test.txt not found"
-fi
-
-echo ""
-echo "3. Unique constructs in test.txt:"
-if [ -f "test.txt" ]; then
-    echo "   Checking for unique patterns..."
-    
-    # Look for unique function call patterns
-    echo "   - Function calls with complex nesting:"
-    grep -n "add.*add.*add" test.txt | head -3
-    
-    # Look for unique case expression patterns
-    echo "   - Complex case expressions:"
-    grep -n "case.*case.*case" test.txt | head -3
-    
-    # Look for unique table patterns
-    echo "   - Complex table literals:"
-    grep -n "\\{.*\\{.*\\}" test.txt | head -3
-fi
-
-echo ""
-echo "Analysis complete." 
\ No newline at end of file
diff --git a/js/scripting-lang/lang.js b/js/scripting-lang/lang.js
index b66271c..b62f850 100644
--- a/js/scripting-lang/lang.js
+++ b/js/scripting-lang/lang.js
@@ -1,14 +1,35 @@
+// Cross-platform scripting language implementation
+// Supports Node.js, Bun, and browser environments
+
+import { lexer, TokenType } from './lexer.js';
+import { parser } from './parser.js';
+
 /**
  * Initializes the standard library in the provided scope.
  * 
- * Why: Injecting the standard library directly into the scope ensures that user code can access these functions as if they were built-in, without special syntax or reserved keywords. This approach also allows for easy extension and testing, as the library is just a set of regular functions in the scope chain.
+ * @param {Object} scope - The global scope object to inject functions into
+ * 
+ * @description Injects higher-order functions into the interpreter's global scope.
+ * These functions provide functional programming utilities like map, compose, pipe, etc.
+ * 
+ * @why Injecting the standard library directly into the scope ensures that user code 
+ * can access these functions as if they were built-in, without special syntax or 
+ * reserved keywords. This approach also allows for easy extension and testing, as 
+ * the library is just a set of regular functions in the scope chain.
  * 
- * How: Each function is added as a property of the scope object. Functions are written to check argument types at runtime, since the language is dynamically typed and does not enforce arity or types at parse time.
+ * @how Each function is added as a property of the scope object. Functions are written 
+ * to check argument types at runtime, since the language is dynamically typed and 
+ * does not enforce arity or types at parse time.
  */
 function initializeStandardLibrary(scope) {
-    // Map: Apply a function to each element
+    /**
+     * Map: Apply a function to a value
+     * @param {Function} f - Function to apply
+     * @param {*} x - Value to apply function to
+     * @returns {*} Result of applying f to x
+     * @throws {Error} When first argument is not a function
+     */
     scope.map = function(f, x) { 
-        // Handle function references by calling them if they're functions
         if (typeof f === 'function') {
             return f(x);
         } else {
@@ -16,14 +37,19 @@ function initializeStandardLibrary(scope) {
         }
     };
     
-    // Compose: Compose two functions (f ∘ g)(x) = f(g(x))
+    /**
+     * Compose: Compose two functions (f ∘ g)(x) = f(g(x))
+     * @param {Function} f - Outer function
+     * @param {Function} g - Inner function  
+     * @param {*} [x] - Optional argument to apply composed function to
+     * @returns {Function|*} Either a composed function or the result of applying it
+     * @throws {Error} When first two arguments are not functions
+     */
     scope.compose = function(f, g, x) { 
         if (typeof f === 'function' && typeof g === 'function') {
             if (arguments.length === 3) {
-                // compose f g x = f(g(x))
                 return f(g(x));
             } else {
-                // compose f g = function that takes x and returns f(g(x))
                 return function(x) {
                     return f(g(x));
                 };
@@ -33,8 +59,14 @@ function initializeStandardLibrary(scope) {
         }
     };
     
-    // Curry: Convert a function that takes multiple arguments into a series of functions
-    // Since our language already uses curried functions by default, this is mostly for explicit currying
+    /**
+     * Curry: Apply a function to arguments (simplified currying)
+     * @param {Function} f - Function to curry
+     * @param {*} x - First argument
+     * @param {*} y - Second argument
+     * @returns {*} Result of applying f to x and y
+     * @throws {Error} When first argument is not a function
+     */
     scope.curry = function(f, x, y) { 
         if (typeof f === 'function') {
             return f(x, y);
@@ -43,7 +75,13 @@ function initializeStandardLibrary(scope) {
         }
     };
     
-    // Apply: Apply a function to an argument (same as function call, but more explicit)
+    /**
+     * Apply: Apply a function to an argument (explicit function application)
+     * @param {Function} f - Function to apply
+     * @param {*} x - Argument to apply function to
+     * @returns {*} Result of applying f to x
+     * @throws {Error} When first argument is not a function
+     */
     scope.apply = function(f, x) { 
         if (typeof f === 'function') {
             return f(x);
@@ -52,15 +90,19 @@ function initializeStandardLibrary(scope) {
         }
     };
     
-    // Pipe: Compose functions in left-to-right order (opposite of compose)
-    // pipe f g x = g f x
+    /**
+     * Pipe: Compose functions in left-to-right order (opposite of compose)
+     * @param {Function} f - First function
+     * @param {Function} g - Second function
+     * @param {*} [x] - Optional argument to apply piped function to
+     * @returns {Function|*} Either a piped function or the result of applying it
+     * @throws {Error} When first two arguments are not functions
+     */
     scope.pipe = function(f, g, x) { 
         if (typeof f === 'function' && typeof g === 'function') {
             if (arguments.length === 3) {
-                // pipe f g x = g(f(x))
                 return g(f(x));
             } else {
-                // pipe f g = function that takes x and returns g(f(x))
                 return function(x) {
                     return g(f(x));
                 };
@@ -70,8 +112,13 @@ function initializeStandardLibrary(scope) {
         }
     };
     
-    // Filter: Filter based on a predicate
-    // For now, we'll implement it as a higher-order function
+    /**
+     * Filter: Filter a value based on a predicate
+     * @param {Function} p - Predicate function
+     * @param {*} x - Value to test
+     * @returns {*|0} The value if predicate is true, 0 otherwise
+     * @throws {Error} When first argument is not a function
+     */
     scope.filter = function(p, x) { 
         if (typeof p === 'function') {
             return p(x) ? x : 0;
@@ -80,8 +127,14 @@ function initializeStandardLibrary(scope) {
         }
     };
     
-    // Reduce: Reduce to a single value using a binary function
-    // For now, we'll implement it as a higher-order function
+    /**
+     * Reduce: Reduce two values using a binary function
+     * @param {Function} f - Binary function
+     * @param {*} init - Initial value
+     * @param {*} x - Second value
+     * @returns {*} Result of applying f to init and x
+     * @throws {Error} When first argument is not a function
+     */
     scope.reduce = function(f, init, x) { 
         if (typeof f === 'function') {
             return f(init, x);
@@ -90,7 +143,14 @@ function initializeStandardLibrary(scope) {
         }
     };
     
-    // Fold: Same as reduce, but more explicit about the folding direction
+    /**
+     * Fold: Same as reduce, but more explicit about the folding direction
+     * @param {Function} f - Binary function
+     * @param {*} init - Initial value
+     * @param {*} x - Second value
+     * @returns {*} Result of applying f to init and x
+     * @throws {Error} When first argument is not a function
+     */
     scope.fold = function(f, init, x) { 
         if (typeof f === 'function') {
             return f(init, x);
@@ -101,1773 +161,863 @@ function initializeStandardLibrary(scope) {
 }
 
 /**
- * TokenType is a flat object, not an enum, to allow for fast string comparisons and easy extensibility.
+ * Interpreter: Walks the AST and evaluates each node.
  * 
- * Why: Using a flat object avoids the need for import/export or enum boilerplate, and makes it easy to add new token types as the language evolves.
- */
-const TokenType = {
-    NUMBER: 'NUMBER',
-    PLUS: 'PLUS',
-    MINUS: 'MINUS',
-    MULTIPLY: 'MULTIPLY',
-    DIVIDE: 'DIVIDE',
-    IDENTIFIER: 'IDENTIFIER',
-    ASSIGNMENT: 'ASSIGNMENT',
-    ARROW: 'ARROW',
-    CASE: 'CASE',
-    OF: 'OF',
-    WILDCARD: 'WILDCARD',
-    FUNCTION: 'FUNCTION',
-    LEFT_PAREN: 'LEFT_PAREN',
-    RIGHT_PAREN: 'RIGHT_PAREN',
-    LEFT_BRACE: 'LEFT_BRACE',
-    RIGHT_BRACE: 'RIGHT_BRACE',
-    LEFT_BRACKET: 'LEFT_BRACKET',
-    RIGHT_BRACKET: 'RIGHT_BRACKET',
-    SEMICOLON: 'SEMICOLON',
-    COMMA: 'COMMA',
-    DOT: 'DOT',
-    STRING: 'STRING',
-    TRUE: 'TRUE',
-    FALSE: 'FALSE',
-    AND: 'AND',
-    OR: 'OR',
-    XOR: 'XOR',
-    NOT: 'NOT',
-    EQUALS: 'EQUALS',
-    LESS_THAN: 'LESS_THAN',
-    GREATER_THAN: 'GREATER_THAN',
-    LESS_EQUAL: 'LESS_EQUAL',
-    GREATER_EQUAL: 'GREATER_EQUAL',
-    NOT_EQUAL: 'NOT_EQUAL',
-    MODULO: 'MODULO',
-    POWER: 'POWER',
-    IO_IN: 'IO_IN',
-    IO_OUT: 'IO_OUT',
-    IO_ASSERT: 'IO_ASSERT',
-    FUNCTION_REF: 'FUNCTION_REF'
-};
-
-/**
- * Lexer: Converts source code to tokens.
+ * @param {Object} ast - Abstract Syntax Tree to evaluate
+ * @returns {*} The result of evaluating the AST, or a Promise for async operations
+ * @throws {Error} For evaluation errors like division by zero, undefined variables, etc.
  * 
- * How: Uses a single pass with a while loop and manual character inspection. Handles whitespace, comments (with nesting), numbers (including decimals), strings, identifiers/keywords, and both single- and multi-character operators.
+ * @description Evaluates an AST by walking through each node and performing the
+ * corresponding operations. Manages scope, handles function calls, and supports
+ * both synchronous and asynchronous operations.
  * 
- * Why: Manual lexing allows for fine-grained control over tokenization, especially for edge cases like nested comments and multi-character IO operations. This approach also makes it easier to debug and extend the lexer for new language features.
+ * @how Uses a global scope for variable storage and function definitions. Each 
+ * function call creates a new scope (using prototypal inheritance) to implement 
+ * lexical scoping. Immutability is enforced by preventing reassignment in the 
+ * global scope.
  * 
- * Notably, IO operations (..in, ..out, ..assert) are recognized as multi-character tokens to avoid ambiguity with the dot operator. Decimal numbers are parsed as a single token to support floating point arithmetic.
+ * @why This approach allows for first-class functions, closures, and lexical 
+ * scoping, while keeping the implementation simple. The interpreter supports 
+ * both synchronous and asynchronous IO operations, returning Promises when necessary.
+ * 
+ * @note The interpreter is split into three functions: evalNode (global), 
+ * localEvalNodeWithScope (for function bodies), and localEvalNode (for internal 
+ * recursion). This separation allows for correct scope handling and easier debugging.
  */
-function lexer(input) {
-    let current = 0;
-    const tokens = [];
+function interpreter(ast) {
+    const globalScope = {};
+    initializeStandardLibrary(globalScope);
     
-    while (current < input.length) {
-        let char = input[current];
-        
-        // Skip whitespace
-        if (/\s/.test(char)) {
-            current++;
-            continue;
-        }
-        
-        // Skip comments
-        if (char === '/' && input[current + 1] === '*') {
-            let commentDepth = 1;
-            current += 2; // Skip /*
-            
-            while (current < input.length && commentDepth > 0) {
-                if (input[current] === '/' && input[current + 1] === '*') {
-                    commentDepth++;
-                    current += 2;
-                } else if (input[current] === '*' && input[current + 1] === '/') {
-                    commentDepth--;
-                    current += 2;
-                } else {
-                    current++;
-                }
-            }
-            continue;
-        }
-        
-        // Numbers
-        if (/[0-9]/.test(char)) {
-            let value = '';
-            while (current < input.length && /[0-9]/.test(input[current])) {
-                value += input[current];
-                current++;
-            }
-            
-            // Check for decimal point
-            if (current < input.length && input[current] === '.') {
-                value += input[current];
-                current++;
-                
-                // Parse decimal part
-                while (current < input.length && /[0-9]/.test(input[current])) {
-                    value += input[current];
-                    current++;
-                }
-                
-                tokens.push({
-                    type: TokenType.NUMBER,
-                    value: parseFloat(value)
-                });
-            } else {
-                tokens.push({
-                    type: TokenType.NUMBER,
-                    value: parseInt(value)
-                });
-            }
-            continue;
-        }
-        
-        // Strings
-        if (char === '"') {
-            let value = '';
-            current++; // Skip opening quote
-            
-            while (current < input.length && input[current] !== '"') {
-                value += input[current];
-                current++;
-            }
-            
-            if (current < input.length) {
-                current++; // Skip closing quote
-                tokens.push({
-                    type: TokenType.STRING,
-                    value: value
-                });
-            } else {
-                throw new Error('Unterminated string');
-            }
-            continue;
-        }
+    // Reset call stack tracker at the start of interpretation
+    callStackTracker.reset();
+    
+    /**
+     * Evaluates AST nodes in the global scope.
+     * 
+     * @param {Object} node - AST node to evaluate
+     * @returns {*} The result of evaluating the node
+     * @throws {Error} For evaluation errors
+     * 
+     * @description Main evaluation function that handles all node types in the
+     * global scope context.
+     */
+    function evalNode(node) {
+        callStackTracker.push('evalNode', node?.type || 'unknown');
         
-        // Identifiers and keywords
-        if (/[a-zA-Z_]/.test(char)) {
-            let value = '';
-            while (current < input.length && /[a-zA-Z0-9_]/.test(input[current])) {
-                value += input[current];
-                current++;
-            }
-            
-            // Check for keywords
-            switch (value) {
-                case 'case':
-                    tokens.push({ type: TokenType.CASE });
-                    break;
-                case 'of':
-                    tokens.push({ type: TokenType.OF });
-                    break;
-                case 'function':
-                    tokens.push({ type: TokenType.FUNCTION });
-                    break;
-                case 'true':
-                    tokens.push({ type: TokenType.TRUE });
-                    break;
-                case 'false':
-                    tokens.push({ type: TokenType.FALSE });
-                    break;
-                case 'and':
-                    tokens.push({ type: TokenType.AND });
-                    break;
-                case 'or':
-                    tokens.push({ type: TokenType.OR });
-                    break;
-                case 'xor':
-                    tokens.push({ type: TokenType.XOR });
-                    break;
-                case 'not':
-                    tokens.push({ type: TokenType.NOT });
-                    break;
-                case '_':
-                    tokens.push({ type: TokenType.WILDCARD });
-                    break;
-                default:
-                    tokens.push({
-                        type: TokenType.IDENTIFIER,
-                        value: value
-                    });
+        try {
+            if (!node) {
+                return undefined;
             }
-            continue;
-        }
-        
-        // Two-character operators
-        if (current + 1 < input.length) {
-            const twoChar = char + input[current + 1];
-            switch (twoChar) {
-                case '->':
-                    tokens.push({ type: TokenType.ARROW });
-                    current += 2;
-                    continue;
-                case '==':
-                    tokens.push({ type: TokenType.EQUALS });
-                    current += 2;
-                    continue;
-                case '!=':
-                    tokens.push({ type: TokenType.NOT_EQUAL });
-                    current += 2;
-                    continue;
-                case '<=':
-                    tokens.push({ type: TokenType.LESS_EQUAL });
-                    current += 2;
-                    continue;
-                case '>=':
-                    tokens.push({ type: TokenType.GREATER_EQUAL });
-                    current += 2;
-                    continue;
-                case '..':
-                    // Check for IO operations
-                    if (current + 2 < input.length) {
-                        const ioChar = input[current + 2];
-                        switch (ioChar) {
-                            case 'i':
-                                if (current + 3 < input.length && input[current + 3] === 'n') {
-                                    tokens.push({ type: TokenType.IO_IN });
-                                    current += 4;
-                                    continue;
-                                }
-                                break;
-                            case 'o':
-                                if (current + 3 < input.length && input[current + 3] === 'u') {
-                                    if (current + 4 < input.length && input[current + 4] === 't') {
-                                        tokens.push({ type: TokenType.IO_OUT });
-                                        current += 5;
-                                        continue;
-                                    }
-                                }
-                                break;
-                            case 'a':
-                                if (current + 3 < input.length && input[current + 3] === 's') {
-                                    if (current + 4 < input.length && input[current + 4] === 's') {
-                                        if (current + 5 < input.length && input[current + 5] === 'e') {
-                                            if (current + 6 < input.length && input[current + 6] === 'r') {
-                                                if (current + 7 < input.length && input[current + 7] === 't') {
-                                                    tokens.push({ type: TokenType.IO_ASSERT });
-                                                    current += 8;
-                                                    continue;
-                                                }
-                                            }
-                                        }
-                                    }
-                                }
-                                break;
+            switch (node.type) {
+                case 'NumberLiteral':
+                    return parseFloat(node.value);
+                case 'StringLiteral':
+                    return node.value;
+                case 'BooleanLiteral':
+                    return node.value;
+                case 'PlusExpression':
+                    return evalNode(node.left) + evalNode(node.right);
+                case 'MinusExpression':
+                    return evalNode(node.left) - evalNode(node.right);
+                case 'MultiplyExpression':
+                    return evalNode(node.left) * evalNode(node.right);
+                case 'DivideExpression':
+                    const divisor = evalNode(node.right);
+                    if (divisor === 0) {
+                        throw new Error('Division by zero');
+                    }
+                    return evalNode(node.left) / evalNode(node.right);
+                case 'ModuloExpression':
+                    return evalNode(node.left) % evalNode(node.right);
+                case 'PowerExpression':
+                    return Math.pow(evalNode(node.left), evalNode(node.right));
+                case 'EqualsExpression':
+                    return evalNode(node.left) === evalNode(node.right);
+                case 'LessThanExpression':
+                    return evalNode(node.left) < evalNode(node.right);
+                case 'GreaterThanExpression':
+                    return evalNode(node.left) > evalNode(node.right);
+                case 'LessEqualExpression':
+                    return evalNode(node.left) <= evalNode(node.right);
+                case 'GreaterEqualExpression':
+                    return evalNode(node.left) >= evalNode(node.right);
+                case 'NotEqualExpression':
+                    return evalNode(node.left) !== evalNode(node.right);
+                case 'AndExpression':
+                    return !!(evalNode(node.left) && evalNode(node.right));
+                case 'OrExpression':
+                    return !!(evalNode(node.left) || evalNode(node.right));
+                case 'XorExpression':
+                    const leftVal = evalNode(node.left);
+                    const rightVal = evalNode(node.right);
+                    return !!((leftVal && !rightVal) || (!leftVal && rightVal));
+                case 'NotExpression':
+                    return !evalNode(node.operand);
+                case 'UnaryMinusExpression':
+                    return -evalNode(node.operand);
+                case 'TableLiteral':
+                    const table = {};
+                    let arrayIndex = 1;
+                    
+                    for (const entry of node.entries) {
+                        if (entry.key === null) {
+                            // Array-like entry: {1, 2, 3}
+                            table[arrayIndex] = evalNode(entry.value);
+                            arrayIndex++;
+                        } else {
+                            // Key-value entry: {name: "Alice", age: 30}
+                            let key;
+                            if (entry.key.type === 'Identifier') {
+                                // Convert identifier keys to strings
+                                key = entry.key.value;
+                            } else {
+                                // For other key types (numbers, strings), evaluate normally
+                                key = evalNode(entry.key);
+                            }
+                            const value = evalNode(entry.value);
+                            table[key] = value;
                         }
                     }
-                    // If we get here, it's not a complete IO operation, so skip the '..'
-                    current += 2;
-                    continue;
-            }
-        }
-        
-        // Single character operators
-        switch (char) {
-            case '+':
-                tokens.push({ type: TokenType.PLUS });
-                break;
-            case '-':
-                tokens.push({ type: TokenType.MINUS });
-                break;
-            case '*':
-                tokens.push({ type: TokenType.MULTIPLY });
-                break;
-            case '/':
-                tokens.push({ type: TokenType.DIVIDE });
-                break;
-            case '%':
-                tokens.push({ type: TokenType.MODULO });
-                break;
-            case '^':
-                tokens.push({ type: TokenType.POWER });
-                break;
-            case ':':
-                tokens.push({ type: TokenType.ASSIGNMENT });
-                break;
-            case '(':
-                tokens.push({ type: TokenType.LEFT_PAREN });
-                break;
-            case ')':
-                tokens.push({ type: TokenType.RIGHT_PAREN });
-                break;
-            case '{':
-                tokens.push({ type: TokenType.LEFT_BRACE });
-                break;
-            case '}':
-                tokens.push({ type: TokenType.RIGHT_BRACE });
-                break;
-            case '[':
-                tokens.push({ type: TokenType.LEFT_BRACKET });
-                break;
-            case ']':
-                tokens.push({ type: TokenType.RIGHT_BRACKET });
-                break;
-            case ';':
-                tokens.push({ type: TokenType.SEMICOLON });
-                break;
-            case ',':
-                tokens.push({ type: TokenType.COMMA });
-                break;
-            case '.':
-                tokens.push({ type: TokenType.DOT });
-                break;
-            case '@':
-                tokens.push({ type: TokenType.FUNCTION_REF });
-                break;
-            case '_':
-                tokens.push({ type: TokenType.WILDCARD });
-                break;
-            case '=':
-                tokens.push({ type: TokenType.EQUALS });
-                break;
-            case '<':
-                tokens.push({ type: TokenType.LESS_THAN });
-                break;
-            case '>':
-                tokens.push({ type: TokenType.GREATER_THAN });
-                break;
-            default:
-                throw new Error(`Unexpected character: ${char}`);
-        }
-        
-        current++;
-    }
-    
-    return tokens;
-}
-
-/**
- * Parser: Converts tokens to an Abstract Syntax Tree (AST).
- * 
- * How: Implements a recursive descent parser, with separate functions for each precedence level (expression, term, factor, primary). Handles chained table access, function calls, and complex constructs like case expressions and function definitions.
- * 
- * Why: Recursive descent is chosen for its clarity and flexibility, especially for a language with many context-sensitive constructs (e.g., case expressions, function definitions, chained access). The parser is structured to minimize circular dependencies and infinite recursion, with careful placement of IO and case expression parsing.
- * 
- * The parser also supports multi-parameter case expressions and function definitions, using lookahead to distinguish between assignments and function declarations. Table literals are parsed with support for both array-like and key-value entries, inspired by Lua.
- */
-function parser(tokens) {
-    let current = 0;
-    
-    function walk() {
-        function parseChainedDotAccess(tableExpr) {
-            /**
-             * Handles chained dot access (e.g., table.key.subkey).
-             * 
-             * Why: Chained access is parsed iteratively rather than recursively to avoid deep call stacks and to allow for easy extension (e.g., supporting method calls in the future).
-             */
-            let result = tableExpr;
-            
-            while (current < tokens.length && tokens[current].type === TokenType.DOT) {
-                current++; // Skip the dot
-                
-                if (current < tokens.length && tokens[current].type === TokenType.IDENTIFIER) {
-                    const key = {
-                        type: 'Identifier',
-                        value: tokens[current].value
-                    };
-                    current++;
                     
-                    result = {
-                        type: 'TableAccess',
-                        table: result,
-                        key: key
-                    };
-                } else {
-                    throw new Error('Expected identifier after dot');
-                }
-            }
-            
-            return result;
-        }
-        
-        function parseChainedTableAccess(tableExpr) {
-            /**
-             * Handles chained bracket and dot access (e.g., table[0].key).
-             * 
-             * Why: This function allows for flexible access patterns, supporting both array and object semantics. Chaining is handled by checking for further access tokens after each access.
-             */
-            if (current < tokens.length && tokens[current].type === TokenType.LEFT_BRACKET) {
-                current++; // Skip '['
-                const keyExpr = walk();
-                
-                if (current < tokens.length && tokens[current].type === TokenType.RIGHT_BRACKET) {
-                    current++; // Skip ']'
+                    return table;
+                case 'TableAccess':
+                    const tableValue = evalNode(node.table);
+                    let keyValue;
                     
-                    const access = {
-                        type: 'TableAccess',
-                        table: tableExpr,
-                        key: keyExpr
-                    };
+                    // Handle different key types
+                    if (node.key.type === 'Identifier') {
+                        // For dot notation, use the identifier name as the key
+                        keyValue = node.key.value;
+                    } else {
+                        // For bracket notation, evaluate the key expression
+                        keyValue = evalNode(node.key);
+                    }
                     
-                    // Check for chained access
-                    if (current < tokens.length && tokens[current].type === TokenType.DOT) {
-                        return parseChainedDotAccess(access);
+                    if (typeof tableValue !== 'object' || tableValue === null) {
+                        throw new Error('Cannot access property of non-table value');
                     }
                     
-                    // Check if this is a function call
-                    if (current < tokens.length && 
-                        (tokens[current].type === TokenType.IDENTIFIER || 
-                         tokens[current].type === TokenType.NUMBER ||
-                         tokens[current].type === TokenType.STRING ||
-                         tokens[current].type === TokenType.LEFT_PAREN)) {
-                        return parseFunctionCall(access);
+                    if (tableValue[keyValue] === undefined) {
+                        throw new Error(`Key '${keyValue}' not found in table`);
                     }
                     
-                    return access;
-                } else {
-                    throw new Error('Expected closing bracket');
-                }
-            }
-            
-            // Check for dot access
-            if (current < tokens.length && tokens[current].type === TokenType.DOT) {
-                const result = parseChainedDotAccess(tableExpr);
-                
-                // Check if this is a function call
-                if (current < tokens.length && 
-                    (tokens[current].type === TokenType.IDENTIFIER || 
-                     tokens[current].type === TokenType.NUMBER ||
-                     tokens[current].type === TokenType.STRING ||
-                     tokens[current].type === TokenType.LEFT_PAREN)) {
-                    return parseFunctionCall(result);
-                }
-                
-                return result;
-            }
-            
-            return tableExpr;
-        }
-        
-        function detectAmbiguousFunctionCalls() {
-            // This is a placeholder for future ambiguous function call detection
-            // For now, we'll assume the parser handles function calls correctly
-        }
-        
-                function parseFunctionCall(functionName) {
-            /**
-             * Parses function calls with arbitrary argument lists.
-             * 
-             * Why: Arguments are parsed until a clear terminator is found, allowing for flexible function call syntax. This approach supports both curried and regular function calls, and allows for future extension to variadic functions.
-             */
-            const args = [];
-            
-            // Parse arguments until we hit a semicolon or other terminator
-            while (current < tokens.length && 
-                   tokens[current].type !== TokenType.SEMICOLON &&
-                   tokens[current].type !== TokenType.RIGHT_PAREN &&
-                   tokens[current].type !== TokenType.RIGHT_BRACE &&
-                   tokens[current].type !== TokenType.COMMA &&
-                   tokens[current].type !== TokenType.AND &&
-                   tokens[current].type !== TokenType.OR &&
-                   tokens[current].type !== TokenType.XOR) {
-                
-                // Special handling for unary minus as argument
-                if (tokens[current].type === TokenType.MINUS) {
-                    // This is a unary minus, parse it as a new argument
-                    current++; // Skip the minus
-                    if (current < tokens.length && tokens[current].type === TokenType.NUMBER) {
-                        args.push({
-                            type: 'UnaryMinusExpression',
-                            operand: {
-                                type: 'NumberLiteral',
-                                value: tokens[current].value
-                            }
-                        });
-                        current++; // Skip the number
-                    } else {
-                        // More complex unary minus expression
-                        args.push({
-                            type: 'UnaryMinusExpression',
-                            operand: parsePrimary()
-                        });
+                    return tableValue[keyValue];
+                case 'AssignmentExpression':
+                    if (globalScope.hasOwnProperty(node.name)) {
+                        throw new Error(`Cannot reassign immutable variable: ${node.name}`);
                     }
-                } else {
-                    // Regular argument parsing - use parseExpression to avoid circular dependency
-                    args.push(parseExpression());
-                }
-            }
-                
-            return {
-                type: 'FunctionCall',
-                name: functionName,
-                args: args
-            };
-        }
-        
-        function parseLogicalExpression() {
-            /**
-             * Parses logical expressions with lowest precedence.
-             * 
-             * Why: Logical operators should have lower precedence than arithmetic and comparison operators
-             * to ensure proper grouping of expressions like "isEven 10 and isPositive 5".
-             */
-            let left = parseExpression();
-            
-            while (current < tokens.length && 
-                   (tokens[current].type === TokenType.AND ||
-                    tokens[current].type === TokenType.OR ||
-                    tokens[current].type === TokenType.XOR)) {
-                
-                const operator = tokens[current].type;
-                current++;
-                const right = parseExpression();
-                
-                switch (operator) {
-                    case TokenType.AND:
-                        left = { type: 'AndExpression', left, right };
-                        break;
-                    case TokenType.OR:
-                        left = { type: 'OrExpression', left, right };
-                        break;
-                    case TokenType.XOR:
-                        left = { type: 'XorExpression', left, right };
-                        break;
-                }
-            }
-            
-            return left;
-        }
-        
-        function parseExpression() {
-            /**
-             * Parses expressions with left-associative binary operators.
-             * 
-             * Why: Operator precedence is handled by splitting parsing into multiple functions (expression, term, factor, primary). This structure avoids ambiguity and ensures correct grouping of operations.
-             */
-            let left = parseTerm();
-            
-            while (current < tokens.length && 
-                   (tokens[current].type === TokenType.PLUS || 
-                    tokens[current].type === TokenType.MINUS ||
-                    tokens[current].type === TokenType.EQUALS ||
-                    tokens[current].type === TokenType.NOT_EQUAL ||
-                    tokens[current].type === TokenType.LESS_THAN ||
-                    tokens[current].type === TokenType.GREATER_THAN ||
-                    tokens[current].type === TokenType.LESS_EQUAL ||
-                    tokens[current].type === TokenType.GREATER_EQUAL)) {
-                
-                const operator = tokens[current].type;
-                
-                // Special case: Don't treat MINUS as binary operator if left is a FunctionReference
-                // This handles cases like "filter @isPositive -3" where -3 should be a separate argument
-                if (operator === TokenType.MINUS && left.type === 'FunctionReference') {
-                    // This is likely a function call with unary minus argument, not a binary operation
-                    // Return the left side and let the caller handle it
-                    return left;
-                }
-                
-
-                
-
-                
-
-                
-                current++;
-                const right = parseTerm();
-                
-                switch (operator) {
-                    case TokenType.PLUS:
-                        left = { type: 'PlusExpression', left, right };
-                        break;
-                    case TokenType.MINUS:
-                        left = { type: 'MinusExpression', left, right };
-                        break;
-                    case TokenType.EQUALS:
-                        left = { type: 'EqualsExpression', left, right };
-                        break;
-                    case TokenType.NOT_EQUAL:
-                        left = { type: 'NotEqualExpression', left, right };
-                        break;
-                    case TokenType.LESS_THAN:
-                        left = { type: 'LessThanExpression', left, right };
-                        break;
-                    case TokenType.GREATER_THAN:
-                        left = { type: 'GreaterThanExpression', left, right };
-                        break;
-                    case TokenType.LESS_EQUAL:
-                        left = { type: 'LessEqualExpression', left, right };
-                        break;
-                    case TokenType.GREATER_EQUAL:
-                        left = { type: 'GreaterEqualExpression', left, right };
-                        break;
-                }
-            }
-            
-            return left;
-        }
-        
-        function parseTerm() {
-            /**
-             * Parses multiplication, division, and modulo operations.
-             * 
-             * Why: By handling these operators at a separate precedence level, the parser ensures that multiplication/division bind tighter than addition/subtraction, matching standard arithmetic rules.
-             */
-            let left = parseFactor();
-            
-            while (current < tokens.length && 
-                   (tokens[current].type === TokenType.MULTIPLY || 
-                    tokens[current].type === TokenType.DIVIDE ||
-                    tokens[current].type === TokenType.MODULO)) {
-                
-                const operator = tokens[current].type;
-                current++;
-                const right = parseFactor();
-                
-                switch (operator) {
-                    case TokenType.MULTIPLY:
-                        left = { type: 'MultiplyExpression', left, right };
-                        break;
-                    case TokenType.DIVIDE:
-                        left = { type: 'DivideExpression', left, right };
-                        break;
-                    case TokenType.MODULO:
-                        left = { type: 'ModuloExpression', left, right };
-                        break;
-                }
-            }
-            
-            return left;
-        }
-        
-        function parseFactor() {
-            /**
-             * Parses exponentiation and primary expressions.
-             * 
-             * Why: Exponentiation is right-associative and binds tighter than multiplication/division, so it is handled at the factor level. This also allows for future extension to other high-precedence operators.
-             */
-            let left = parsePrimary();
-            
-            while (current < tokens.length && tokens[current].type === TokenType.POWER) {
-                current++;
-                const right = parsePrimary();
-                left = { type: 'PowerExpression', left, right };
-            }
-            
-            return left;
-        }
-        
-        function parsePrimary() {
-            /**
-             * Parses literals, identifiers, function definitions, assignments, table literals, case expressions, IO operations, and parenthesized expressions.
-             * 
-             * Why: This function is the core of the recursive descent parser, handling all atomic and context-sensitive constructs. Special care is taken to distinguish between assignments and function definitions using lookahead, and to parse multi-parameter case expressions and function calls.
-             * 
-             * The parser avoids circular recursion by handling IO and case expressions at the top level, and by using explicit checks for each construct.
-             */
-            const token = tokens[current];
-            
-            if (token.type === TokenType.CASE) {
-                current++; // Skip 'case'
-                
-                // Parse the values being matched (can be multiple)
-                const values = [];
-                while (current < tokens.length && tokens[current].type !== TokenType.OF) {
-                    // Parse simple expressions (identifiers, numbers, etc.)
-                    if (tokens[current].type === TokenType.IDENTIFIER) {
-                        values.push({
-                            type: 'Identifier',
-                            value: tokens[current].value
-                        });
-                        current++;
-                    } else if (tokens[current].type === TokenType.NUMBER) {
-                        values.push({
-                            type: 'NumberLiteral',
-                            value: tokens[current].value
-                        });
-                        current++;
-                    } else if (tokens[current].type === TokenType.STRING) {
-                        values.push({
-                            type: 'StringLiteral',
-                            value: tokens[current].value
-                        });
-                        current++;
-                    } else {
-                        // For more complex expressions, fall back to parseLogicalExpression
-                        const value = parseLogicalExpression();
-                        values.push(value);
+                    const value = evalNode(node.value);
+                    globalScope[node.name] = value;
+                    return;
+                case 'Assignment':
+                    if (globalScope.hasOwnProperty(node.identifier)) {
+                        throw new Error(`Cannot reassign immutable variable: ${node.identifier}`);
                     }
-                }
-                
-                // Expect 'of'
-                if (current >= tokens.length || tokens[current].type !== TokenType.OF) {
-                    throw new Error('Expected "of" after "case"');
-                }
-                current++; // Skip 'of'
-                
-                const cases = [];
-                
-                // Parse cases until we hit a semicolon or end
-                while (current < tokens.length && tokens[current].type !== TokenType.SEMICOLON) {
-                    const patterns = [];
-                    while (current < tokens.length && 
-                           tokens[current].type !== TokenType.ASSIGNMENT && 
-                           tokens[current].type !== TokenType.SEMICOLON) {
-                        patterns.push(parseLogicalExpression());
+                    const assignmentValue = evalNode(node.value);
+                    globalScope[node.identifier] = assignmentValue;
+                    return;
+                case 'Identifier':
+                    const identifierValue = globalScope[node.value];
+                    if (identifierValue === undefined) {
+                        throw new Error(`Variable ${node.value} is not defined`);
                     }
-                    
-                    // Expect ':' after pattern
-                    if (current < tokens.length && tokens[current].type === TokenType.ASSIGNMENT) {
-                        current++; // Skip ':'
+                    return identifierValue;
+                case 'FunctionDeclaration':
+                    // For anonymous functions, the name comes from the assignment
+                    // The function itself doesn't have a name, so we just return
+                    // The assignment will handle storing it in the global scope
+                    return function(...args) {
+                        callStackTracker.push('FunctionCall', node.params.join(','));
+                        try {
+                            let localScope = Object.create(globalScope);
+                            for (let i = 0; i < node.params.length; i++) {
+                                localScope[node.params[i]] = args[i];
+                            }
+                            return localEvalNodeWithScope(node.body, localScope);
+                        } finally {
+                            callStackTracker.pop();
+                        }
+                    };
+                case 'FunctionDefinition':
+                    // Create a function from the function definition
+                    return function(...args) {
+                        callStackTracker.push('FunctionCall', node.parameters.join(','));
+                        try {
+                            let localScope = Object.create(globalScope);
+                            for (let i = 0; i < node.parameters.length; i++) {
+                                localScope[node.parameters[i]] = args[i];
+                            }
+                            return localEvalNodeWithScope(node.body, localScope);
+                        } finally {
+                            callStackTracker.pop();
+                        }
+                    };
+                case 'FunctionCall':
+                    let funcToCall;
+                    if (typeof node.name === 'string') {
+                        // Regular function call with string name
+                        funcToCall = globalScope[node.name];
+                    } else if (node.name.type === 'Identifier') {
+                        // Function call with identifier
+                        funcToCall = globalScope[node.name.value];
                     } else {
-                        throw new Error('Expected ":" after pattern in case expression');
+                        // Function call from expression (e.g., parenthesized function, higher-order)
+                        funcToCall = evalNode(node.name);
                     }
                     
-                    const result = parseLogicalExpression();
-                    cases.push({ 
-                        pattern: patterns, 
-                        result: [result] 
-                    });
-                }
-                
-                return {
-                    type: 'CaseExpression',
-                    value: values,
-                    cases,
-                };
-            }
-            
-            if (token.type === TokenType.NOT) {
-                current++;
-                const operand = parsePrimary();
-                return { type: 'NotExpression', operand };
-            }
-            
-            if (token.type === TokenType.MINUS) {
-                current++;
-                const operand = parsePrimary();
-                return { type: 'UnaryMinusExpression', operand };
-            }
-            
-            if (token.type === TokenType.NUMBER) {
-                current++;
-                return {
-                    type: 'NumberLiteral',
-                    value: token.value
-                };
-            }
-            
-            if (token.type === TokenType.STRING) {
-                current++;
-                return {
-                    type: 'StringLiteral',
-                    value: token.value
-                };
-            }
-            
-            if (token.type === TokenType.TRUE) {
-                current++;
-                return {
-                    type: 'BooleanLiteral',
-                    value: true
-                };
-            }
-            
-            if (token.type === TokenType.FALSE) {
-                current++;
-                return {
-                    type: 'BooleanLiteral',
-                    value: false
-                };
-            }
-            
-            if (token.type === TokenType.LEFT_PAREN) {
-                current++; // Skip '('
-                const parenthesizedExpr = parseLogicalExpression();
-                
-                if (current < tokens.length && tokens[current].type === TokenType.RIGHT_PAREN) {
-                    current++; // Skip ')'
-                    return parenthesizedExpr;
-                } else {
-                    throw new Error('Expected closing parenthesis');
-                }
-            }
-            
-            if (token.type === TokenType.IDENTIFIER) {
-                const identifier = {
-                    type: 'Identifier',
-                    value: token.value
-                };
-                current++;
-                
-                // Check if this is an assignment
-                if (current < tokens.length && tokens[current].type === TokenType.ASSIGNMENT) {
-                    current++; // Skip ':'
-                    
-                    // Check if this is a function definition
-                    let isFunction = false;
-                    let params = [];
-                    
-                    // Look ahead to see if this is a function definition
-                    let lookAhead = current;
-                    while (lookAhead < tokens.length && 
-                           tokens[lookAhead].type !== TokenType.ARROW && 
-                           tokens[lookAhead].type !== TokenType.SEMICOLON) {
-                        if (tokens[lookAhead].type === TokenType.IDENTIFIER) {
-                            params.push(tokens[lookAhead].value);
-                        }
-                        lookAhead++;
+                    if (funcToCall instanceof Function) {
+                        let args = node.args.map(evalNode);
+                        return funcToCall(...args);
                     }
+                    throw new Error(`Function is not defined or is not callable`);
+                case 'WhenExpression':
+                    // Handle both single values and arrays of values
+                    const whenValues = Array.isArray(node.value) 
+                        ? node.value.map(evalNode) 
+                        : [evalNode(node.value)];
                     
-                    if (lookAhead < tokens.length && tokens[lookAhead].type === TokenType.ARROW) {
-                        isFunction = true;
+                    if (process.env.DEBUG) {
+                        console.log(`[DEBUG] WhenExpression: whenValues =`, whenValues);
                     }
                     
-                    if (isFunction) {
-                        // Clear params array and parse function parameters
-                        params = [];
-                        while (current < tokens.length && tokens[current].type !== TokenType.ARROW) {
-                            if (tokens[current].type === TokenType.IDENTIFIER) {
-                                params.push(tokens[current].value);
-                            }
-                            current++;
+                    for (const caseItem of node.cases) {
+                        // Handle both single patterns and arrays of patterns
+                        const patterns = caseItem.pattern.map(evalNode);
+                        
+                        if (process.env.DEBUG) {
+                            console.log(`[DEBUG] WhenExpression: patterns =`, patterns);
                         }
                         
-                        current++; // Skip '->'
+                        // Check if patterns match the values
+                        let matches = true;
+                        if (whenValues.length !== patterns.length) {
+                            matches = false;
+                        } else {
+                            for (let i = 0; i < whenValues.length; i++) {
+                                const value = whenValues[i];
+                                const pattern = patterns[i];
+                                
+                                if (process.env.DEBUG) {
+                                    console.log(`[DEBUG] WhenExpression: comparing value ${value} with pattern ${pattern}`);
+                                }
+                                
+                                if (pattern === true) { // Wildcard pattern
+                                    // Wildcard always matches
+                                    if (process.env.DEBUG) {
+                                        console.log(`[DEBUG] WhenExpression: wildcard matches`);
+                                    }
+                                    continue;
+                                } else if (value !== pattern) {
+                                    matches = false;
+                                    if (process.env.DEBUG) {
+                                        console.log(`[DEBUG] WhenExpression: pattern does not match`);
+                                    }
+                                    break;
+                                } else {
+                                    if (process.env.DEBUG) {
+                                        console.log(`[DEBUG] WhenExpression: pattern matches`);
+                                    }
+                                }
+                            }
+                        }
                         
-                        // Parse the function body (which could be a case expression or other expression)
-                        const functionBody = parseLogicalExpression();
+                        if (process.env.DEBUG) {
+                            console.log(`[DEBUG] WhenExpression: case matches = ${matches}`);
+                        }
                         
-                        return {
-                            type: 'AssignmentExpression',
-                            name: identifier.value,
-                            value: {
-                                type: 'FunctionDeclaration',
-                                name: null, // Anonymous function
-                                params,
-                                body: functionBody,
+                        if (matches) {
+                            const results = caseItem.result.map(evalNode);
+                            if (results.length === 1) {
+                                return results[0];
                             }
-                        };
-                    } else {
-                        // Regular assignment
-                        const value = parseLogicalExpression();
-                        return {
-                            type: 'AssignmentExpression',
-                            name: identifier.value,
-                            value: value
-                        };
-                    }
-                }
-                
-                // Check if this is table access
-                if (current < tokens.length && 
-                    (tokens[current].type === TokenType.LEFT_BRACKET ||
-                     tokens[current].type === TokenType.DOT)) {
-                    return parseChainedTableAccess(identifier);
-                }
-                
-                // Check if this is a function call
-                if (current < tokens.length && 
-                    (tokens[current].type === TokenType.IDENTIFIER || 
-                     tokens[current].type === TokenType.NUMBER ||
-                     tokens[current].type === TokenType.STRING ||
-                     tokens[current].type === TokenType.LEFT_PAREN ||
-                     tokens[current].type === TokenType.FUNCTION_REF)) {
-                    return parseFunctionCall(identifier);
-                }
-                
-                // Special case: Check for function call with unary minus argument
-                // This handles cases like "isPositive -3" where -3 should be a separate argument
-                // Only trigger if the identifier looks like a function name (contains letters)
-                if (current < tokens.length && tokens[current].type === TokenType.MINUS) {
-                    // Look ahead to see if we have MINUS NUMBER
-                    if (current + 1 < tokens.length && tokens[current + 1].type === TokenType.NUMBER) {
-                        // Check if the identifier looks like a function name (not a simple variable like 'n')
-                        if (identifier.value.length > 1 && /[a-zA-Z]/.test(identifier.value)) {
-                            return parseFunctionCall(identifier);
+                            return results.join(' ');
                         }
                     }
-                }
-                
-
-                
-
-                
-                return identifier;
-            }
-            
-            if (token.type === TokenType.FUNCTION_REF) {
-                current++; // Skip '@'
-                if (current < tokens.length && tokens[current].type === TokenType.IDENTIFIER) {
-                    const funcName = tokens[current].value;
-                    current++;
-                    return {
-                        type: 'FunctionReference',
-                        name: funcName
-                    };
-                } else {
-                    throw new Error('Expected function name after @');
-                }
+                    throw new Error('No matching pattern found');
+                case 'WildcardPattern':
+                    return true;
+                case 'IOInExpression':
+                    const readline = require('readline');
+                    const rl = readline.createInterface({
+                        input: process.stdin,
+                        output: process.stdout
+                    });
+                    
+                    return new Promise((resolve) => {
+                        rl.question('', (input) => {
+                            rl.close();
+                            const num = parseInt(input);
+                            resolve(isNaN(num) ? input : num);
+                        });
+                    });
+                case 'IOOutExpression':
+                    const outputValue = evalNode(node.value);
+                    console.log(outputValue);
+                    return outputValue;
+                case 'IOAssertExpression':
+                    const assertionValue = evalNode(node.value);
+                    if (!assertionValue) {
+                        throw new Error('Assertion failed');
+                    }
+                    return assertionValue;
+                case 'FunctionReference':
+                    const functionValue = globalScope[node.name];
+                    if (functionValue === undefined) {
+                        throw new Error(`Function ${node.name} is not defined`);
+                    }
+                    if (typeof functionValue !== 'function') {
+                        throw new Error(`${node.name} is not a function`);
+                    }
+                    return functionValue;
+                case 'ArrowExpression':
+                    // Arrow expressions are function bodies that should be evaluated
+                    return evalNode(node.body);
+                default:
+                    throw new Error(`Unknown node type: ${node.type}`);
             }
+        } finally {
+            callStackTracker.pop();
+        }
+    }
 
-                        if (token.type === TokenType.WILDCARD) {
-                current++; // Skip '_'
-                return { type: 'WildcardPattern' };
+    /**
+     * Evaluates AST nodes in a local scope with access to parent scope.
+     * 
+     * @param {Object} node - AST node to evaluate
+     * @param {Object} scope - Local scope object (prototypally inherits from global)
+     * @returns {*} The result of evaluating the node
+     * @throws {Error} For evaluation errors
+     * 
+     * @description Used for evaluating function bodies and other expressions
+     * that need access to both local and global variables.
+     */
+    const localEvalNodeWithScope = (node, scope) => {
+        callStackTracker.push('localEvalNodeWithScope', node?.type || 'unknown');
+        
+        try {
+            if (!node) {
+                return undefined;
             }
-
-
-            
-
-            
-            // If we get here, it's an operator token that should be handled by parseExpression
-            // But we need to handle it here to avoid circular dependency
-            if (token.type === TokenType.LEFT_BRACE) {
-
-                current++; // Skip '{'
-                const entries = [];
-                let arrayIndex = 1;
-                
-                while (current < tokens.length && tokens[current].type !== TokenType.RIGHT_BRACE) {
-                    // Skip leading commas
-                    if (tokens[current].type === TokenType.COMMA) {
-                        current++;
-                        continue;
+            switch (node.type) {
+                case 'NumberLiteral':
+                    return parseFloat(node.value);
+                case 'StringLiteral':
+                    return node.value;
+                case 'BooleanLiteral':
+                    return node.value;
+                case 'PlusExpression':
+                    return localEvalNodeWithScope(node.left, scope) + localEvalNodeWithScope(node.right, scope);
+                case 'MinusExpression':
+                    return localEvalNodeWithScope(node.left, scope) - localEvalNodeWithScope(node.right, scope);
+                case 'MultiplyExpression':
+                    return localEvalNodeWithScope(node.left, scope) * localEvalNodeWithScope(node.right, scope);
+                case 'DivideExpression':
+                    const divisor = localEvalNodeWithScope(node.right, scope);
+                    if (divisor === 0) {
+                        throw new Error('Division by zero');
                     }
+                    return localEvalNodeWithScope(node.left, scope) / localEvalNodeWithScope(node.right, scope);
+                case 'ModuloExpression':
+                    return localEvalNodeWithScope(node.left, scope) % localEvalNodeWithScope(node.right, scope);
+                case 'PowerExpression':
+                    return Math.pow(localEvalNodeWithScope(node.left, scope), localEvalNodeWithScope(node.right, scope));
+                case 'EqualsExpression':
+                    return localEvalNodeWithScope(node.left, scope) === localEvalNodeWithScope(node.right, scope);
+                case 'LessThanExpression':
+                    return localEvalNodeWithScope(node.left, scope) < localEvalNodeWithScope(node.right, scope);
+                case 'GreaterThanExpression':
+                    return localEvalNodeWithScope(node.left, scope) > localEvalNodeWithScope(node.right, scope);
+                case 'LessEqualExpression':
+                    return localEvalNodeWithScope(node.left, scope) <= localEvalNodeWithScope(node.right, scope);
+                case 'GreaterEqualExpression':
+                    return localEvalNodeWithScope(node.left, scope) >= localEvalNodeWithScope(node.right, scope);
+                case 'NotEqualExpression':
+                    return localEvalNodeWithScope(node.left, scope) !== localEvalNodeWithScope(node.right, scope);
+                case 'AndExpression':
+                    return !!(localEvalNodeWithScope(node.left, scope) && localEvalNodeWithScope(node.right, scope));
+                case 'OrExpression':
+                    return !!(localEvalNodeWithScope(node.left, scope) || localEvalNodeWithScope(node.right, scope));
+                case 'XorExpression':
+                    const leftVal = localEvalNodeWithScope(node.left, scope);
+                    const rightVal = localEvalNodeWithScope(node.right, scope);
+                    return !!((leftVal && !rightVal) || (!leftVal && rightVal));
+                case 'NotExpression':
+                    return !localEvalNodeWithScope(node.operand, scope);
+                case 'UnaryMinusExpression':
+                    return -localEvalNodeWithScope(node.operand, scope);
+                case 'TableLiteral':
+                    const table = {};
+                    let arrayIndex = 1;
                     
-                    let key = null;
-                    let value;
-                    
-                    // Check if this is a key-value pair or just a value
-                    
-                                        // Check if this is a key-value pair or just a value
-                    if (current + 1 < tokens.length && tokens[current + 1].type === TokenType.ASSIGNMENT) {
-                        // This is a key-value pair: key: value
-                        if (tokens[current].type === TokenType.IDENTIFIER) {
-                            key = {
-                                type: 'Identifier',
-                                value: tokens[current].value
-                            };
-                            current++; // Skip the key
-                        } else if (tokens[current].type === TokenType.NUMBER) {
-                            key = {
-                                type: 'NumberLiteral',
-                                value: tokens[current].value,
-                            };
-                            current++; // Skip the key
-                        } else if (tokens[current].type === TokenType.STRING) {
-                            key = {
-                                type: 'StringLiteral',
-                                value: tokens[current].value,
-                            };
-                            current++; // Skip the key
-                        } else if (tokens[current].type === TokenType.TRUE) {
-                            key = {
-                                type: 'BooleanLiteral',
-                                value: true,
-                            };
-                            current++; // Skip the key
-                        } else if (tokens[current].type === TokenType.FALSE) {
-                            key = {
-                                type: 'BooleanLiteral',
-                                value: false,
-                            };
-                            current++; // Skip the key
-
+                    for (const entry of node.entries) {
+                        if (entry.key === null) {
+                            // Array-like entry: {1, 2, 3}
+                            table[arrayIndex] = localEvalNodeWithScope(entry.value, scope);
+                            arrayIndex++;
                         } else {
-                            throw new Error('Invalid key type in table literal');
+                            // Key-value entry: {name: "Alice", age: 30}
+                            let key;
+                            if (entry.key.type === 'Identifier') {
+                                // Convert identifier keys to strings
+                                key = entry.key.value;
+                            } else {
+                                // For other key types (numbers, strings), evaluate normally
+                                key = localEvalNodeWithScope(entry.key, scope);
+                            }
+                            const value = localEvalNodeWithScope(entry.value, scope);
+                            table[key] = value;
                         }
-                        
-                        current++; // Skip ':'
-                        value = parseExpression();
+                    }
+                    
+                    return table;
+                case 'TableAccess':
+                    const tableValue = localEvalNodeWithScope(node.table, scope);
+                    let keyValue;
+                    
+                    // Handle different key types
+                    if (node.key.type === 'Identifier') {
+                        // For dot notation, use the identifier name as the key
+                        keyValue = node.key.value;
                     } else {
-                        // This is just a value (array-like entry)
-                        value = parseExpression();
+                        // For bracket notation, evaluate the key expression
+                        keyValue = localEvalNodeWithScope(node.key, scope);
                     }
                     
-                    entries.push({ key, value });
-
+                    if (typeof tableValue !== 'object' || tableValue === null) {
+                        throw new Error('Cannot access property of non-table value');
+                    }
                     
-                    // Skip trailing commas
-                    if (current < tokens.length && tokens[current].type === TokenType.COMMA) {
-                        current++;
+                    if (tableValue[keyValue] === undefined) {
+                        throw new Error(`Key '${keyValue}' not found in table`);
                     }
-                }
-                
-                if (current < tokens.length && tokens[current].type === TokenType.RIGHT_BRACE) {
-                    current++; // Skip '}'
-                    return {
-                        type: 'TableLiteral',
-                        entries: entries
+                    
+                    return tableValue[keyValue];
+                case 'AssignmentExpression':
+                    if (globalScope.hasOwnProperty(node.name)) {
+                        throw new Error(`Cannot reassign immutable variable: ${node.name}`);
+                    }
+                    globalScope[node.name] = localEvalNodeWithScope(node.value, scope);
+                    return;
+                case 'Identifier':
+                    // First check local scope, then global scope
+                    if (scope && scope.hasOwnProperty(node.value)) {
+                        return scope[node.value];
+                    }
+                    const identifierValue = globalScope[node.value];
+                    if (identifierValue === undefined && node.value) {
+                        return node.value;
+                    }
+                    return identifierValue;
+                case 'FunctionDeclaration':
+                    // For anonymous functions, the name comes from the assignment
+                    // The function itself doesn't have a name, so we just return
+                    // The assignment will handle storing it in the global scope
+                    return function(...args) {
+                        callStackTracker.push('FunctionCall', node.params.join(','));
+                        try {
+                            let nestedScope = Object.create(globalScope);
+                            for (let i = 0; i < node.params.length; i++) {
+                                nestedScope[node.params[i]] = args[i];
+                            }
+                            return localEvalNodeWithScope(node.body, nestedScope);
+                        } finally {
+                            callStackTracker.pop();
+                        }
                     };
-                } else {
-                    throw new Error('Expected closing brace');
-                }
-            }
-            
-            // If we get here, it's an operator token that should be handled by parseExpression
-            // But we need to handle it here to avoid circular dependency
-            if (token.type === TokenType.PLUS ||
-                token.type === TokenType.MINUS ||
-                token.type === TokenType.MULTIPLY ||
-                token.type === TokenType.DIVIDE ||
-                token.type === TokenType.MODULO ||
-                token.type === TokenType.POWER ||
-                token.type === TokenType.EQUALS ||
-                token.type === TokenType.NOT_EQUAL ||
-                token.type === TokenType.LESS_THAN ||
-                token.type === TokenType.GREATER_THAN ||
-                token.type === TokenType.LESS_EQUAL ||
-                token.type === TokenType.GREATER_EQUAL ||
-                token.type === TokenType.AND ||
-                token.type === TokenType.OR ||
-                token.type === TokenType.XOR) {
-                // Reset current to parse the expression properly
-                return parseExpression();
-            }
-            
-            // If we get here, we have an unexpected token
-
-            throw new Error(`Unexpected token in parsePrimary: ${token.type}`);
-        }
-        
-        // Check for IO operations before calling parsePrimary
-        if (tokens[current].type === TokenType.IO_IN) {
-            current++;
-            return { type: 'IOInExpression' };
-        } else if (tokens[current].type === TokenType.IO_OUT) {
-            current++;
-            const outputValue = parseLogicalExpression();
-            return { type: 'IOOutExpression', value: outputValue };
-        } else if (tokens[current].type === TokenType.IO_ASSERT) {
-            current++;
-            const assertionExpr = parseLogicalExpression();
-            return { type: 'IOAssertExpression', value: assertionExpr };
-        }
-        
-        // Check for case expressions at top level
-        if (tokens[current].type === TokenType.CASE) {
-            current++; // Skip 'case'
-            
-            // Parse the values being matched (can be multiple)
-            const values = [];
-            while (current < tokens.length && tokens[current].type !== TokenType.OF) {
-                const value = parseLogicalExpression();
-                values.push(value);
-            }
-            
-            // Expect 'of'
-            if (current >= tokens.length || tokens[current].type !== TokenType.OF) {
-                throw new Error('Expected "of" after "case"');
-            }
-            current++; // Skip 'of'
-            
-            const cases = [];
-            
-            // Parse cases until we hit a semicolon or end
-            while (current < tokens.length && tokens[current].type !== TokenType.SEMICOLON) {
-                const patterns = [];
-                while (current < tokens.length && 
-                       tokens[current].type !== TokenType.ASSIGNMENT && 
-                       tokens[current].type !== TokenType.SEMICOLON) {
-                    patterns.push(parseLogicalExpression());
-                }
-                
-                // Expect ':' after pattern
-                if (current < tokens.length && tokens[current].type === TokenType.ASSIGNMENT) {
-                    current++; // Skip ':'
-                } else {
-                    throw new Error('Expected ":" after pattern in case expression');
-                }
-                
-                const result = parseLogicalExpression();
-                cases.push({ 
-                    pattern: patterns, 
-                    result: [result] 
-                });
-            }
-            
-            return {
-                type: 'CaseExpression',
-                value: values,
-                cases,
-            };
-        }
-        
-        // Simple wrapper that calls parseLogicalExpression for all token types
-        return parseLogicalExpression();
-    }
-    
-    const ast = {
-        type: 'Program',
-        body: []
-    };
-    
-    let lastCurrent = -1;
-    let loopCount = 0;
-    const maxLoops = tokens.length * 2; // Safety limit
-    
-    while (current < tokens.length) {
-        // Safety check to prevent infinite loops
-        if (current === lastCurrent) {
-            loopCount++;
-            if (loopCount > 10) { // Allow a few iterations at the same position
-                throw new Error(`Parser stuck at position ${current}, token: ${tokens[current]?.type || 'EOF'}`);
-            }
-        } else {
-            loopCount = 0;
-        }
-        
-        // Safety check for maximum loops
-        if (loopCount > maxLoops) {
-            throw new Error(`Parser exceeded maximum loop count. Last position: ${current}`);
-        }
-        
-        lastCurrent = current;
-        
-        const node = walk();
-        if (node) {
-            ast.body.push(node);
-        }
-        
-        // Skip semicolons
-        if (current < tokens.length && tokens[current].type === TokenType.SEMICOLON) {
-            current++;
-        }
-    }
-    
-    return ast;
-}
-
-/**
- * Interpreter: Walks the AST and evaluates each node.
- * 
- * How: Uses a global scope for variable storage and function definitions. Each function call creates a new scope (using prototypal inheritance) to implement lexical scoping. Immutability is enforced by preventing reassignment in the global scope.
- * 
- * Why: This approach allows for first-class functions, closures, and lexical scoping, while keeping the implementation simple. The interpreter supports both synchronous and asynchronous IO operations, returning Promises when necessary.
- * 
- * The interpreter is split into three functions: evalNode (global), localEvalNodeWithScope (for function bodies), and localEvalNode (for internal recursion). This separation allows for correct scope handling and easier debugging.
- */
-function interpreter(ast) {
-    const globalScope = {};
-    initializeStandardLibrary(globalScope);
-    
-    function evalNode(node) {
-        if (!node) {
-            return undefined;
-        }
-        switch (node.type) {
-            case 'NumberLiteral':
-                return parseFloat(node.value);
-            case 'StringLiteral':
-                return node.value;
-            case 'BooleanLiteral':
-                return node.value;
-            case 'PlusExpression':
-                return evalNode(node.left) + evalNode(node.right);
-            case 'MinusExpression':
-                return evalNode(node.left) - evalNode(node.right);
-            case 'MultiplyExpression':
-                return evalNode(node.left) * evalNode(node.right);
-            case 'DivideExpression':
-                const divisor = evalNode(node.right);
-                if (divisor === 0) {
-                    throw new Error('Division by zero');
-                }
-                return evalNode(node.left) / evalNode(node.right);
-            case 'ModuloExpression':
-                return evalNode(node.left) % evalNode(node.right);
-            case 'PowerExpression':
-                return Math.pow(evalNode(node.left), evalNode(node.right));
-            case 'EqualsExpression':
-                return evalNode(node.left) === evalNode(node.right);
-            case 'LessThanExpression':
-                return evalNode(node.left) < evalNode(node.right);
-            case 'GreaterThanExpression':
-                return evalNode(node.left) > evalNode(node.right);
-            case 'LessEqualExpression':
-                return evalNode(node.left) <= evalNode(node.right);
-            case 'GreaterEqualExpression':
-                return evalNode(node.left) >= evalNode(node.right);
-            case 'NotEqualExpression':
-                return evalNode(node.left) !== evalNode(node.right);
-            case 'AndExpression':
-                return !!(evalNode(node.left) && evalNode(node.right));
-            case 'OrExpression':
-                return !!(evalNode(node.left) || evalNode(node.right));
-            case 'XorExpression':
-                const leftVal = evalNode(node.left);
-                const rightVal = evalNode(node.right);
-                return !!((leftVal && !rightVal) || (!leftVal && rightVal));
-            case 'NotExpression':
-                return !evalNode(node.operand);
-            case 'UnaryMinusExpression':
-                return -evalNode(node.operand);
-            case 'TableLiteral':
-                const table = {};
-                let arrayIndex = 1;
-                
-                for (const entry of node.entries) {
-                    if (entry.key === null) {
-                        // Array-like entry: {1, 2, 3}
-                        table[arrayIndex] = evalNode(entry.value);
-                        arrayIndex++;
-                    } else {
-                        // Key-value entry: {name: "Alice", age: 30}
-                        let key;
-                        if (entry.key.type === 'Identifier') {
-                            // Convert identifier keys to strings
-                            key = entry.key.value;
-                        } else {
-                            // For other key types (numbers, strings), evaluate normally
-                            key = evalNode(entry.key);
+                case 'FunctionDefinition':
+                    // Create a function from the function definition
+                    return function(...args) {
+                        callStackTracker.push('FunctionCall', node.parameters.join(','));
+                        try {
+                            let nestedScope = Object.create(globalScope);
+                            for (let i = 0; i < node.parameters.length; i++) {
+                                nestedScope[node.parameters[i]] = args[i];
+                            }
+                            return localEvalNodeWithScope(node.body, nestedScope);
+                        } finally {
+                            callStackTracker.pop();
                         }
-                        const value = evalNode(entry.value);
-                        table[key] = value;
+                    };
+                case 'FunctionCall':
+                    let localFunc;
+                    if (typeof node.name === 'string') {
+                        // Regular function call with string name
+                        localFunc = globalScope[node.name];
+                    } else if (node.name.type === 'Identifier') {
+                        // Function call with identifier
+                        localFunc = globalScope[node.name.value];
+                    } else {
+                        // Function call from expression (e.g., parenthesized function, higher-order)
+                        localFunc = localEvalNodeWithScope(node.name, scope);
                     }
-                }
-                
-                return table;
-            case 'TableAccess':
-                const tableValue = evalNode(node.table);
-                let keyValue;
-                
-                // Handle different key types
-                if (node.key.type === 'Identifier') {
-                    // For dot notation, use the identifier name as the key
-                    keyValue = node.key.value;
-                } else {
-                    // For bracket notation, evaluate the key expression
-                    keyValue = evalNode(node.key);
-                }
-                
-                if (typeof tableValue !== 'object' || tableValue === null) {
-                    throw new Error('Cannot access property of non-table value');
-                }
-                
-                if (tableValue[keyValue] === undefined) {
-                    throw new Error(`Key '${keyValue}' not found in table`);
-                }
-                
-                return tableValue[keyValue];
-            case 'AssignmentExpression':
-                if (globalScope.hasOwnProperty(node.name)) {
-                    throw new Error(`Cannot reassign immutable variable: ${node.name}`);
-                }
-                const value = evalNode(node.value);
-                globalScope[node.name] = value;
-                return;
-            case 'Identifier':
-                const identifierValue = globalScope[node.value];
-                if (identifierValue === undefined) {
-                    throw new Error(`Variable ${node.value} is not defined`);
-                }
-                return identifierValue;
-            case 'FunctionDeclaration':
-                // For anonymous functions, the name comes from the assignment
-                // The function itself doesn't have a name, so we just return
-                // The assignment will handle storing it in the global scope
-                return function(...args) {
-                    let localScope = Object.create(globalScope);
-                    for (let i = 0; i < node.params.length; i++) {
-                        localScope[node.params[i]] = args[i];
+                    
+                    if (localFunc instanceof Function) {
+                        let args = node.args.map(arg => localEvalNodeWithScope(arg, scope));
+                        return localFunc(...args);
+                    }
+                    throw new Error(`Function is not defined or is not callable`);
+                case 'WhenExpression':
+                    // Handle both single values and arrays of values
+                    const whenValues = Array.isArray(node.value) 
+                        ? node.value.map(val => localEvalNodeWithScope(val, scope)) 
+                        : [localEvalNodeWithScope(node.value, scope)];
+                    
+                    if (process.env.DEBUG) {
+                        console.log(`[DEBUG] localEvalNodeWithScope WhenExpression: whenValues =`, whenValues);
                     }
-                    return localEvalNodeWithScope(node.body, localScope);
-                };
-            case 'FunctionCall':
-                let funcToCall; // Renamed from 'func' to avoid redeclaration
-                if (typeof node.name === 'string') {
-                    // Regular function call with string name
-                    funcToCall = globalScope[node.name];
-                } else if (node.name.type === 'Identifier') {
-                    // Function call with identifier
-                    funcToCall = globalScope[node.name.value];
-                } else if (node.name.type === 'TableAccess') {
-                    // Function call from table access (e.g., math.add)
-                    funcToCall = evalNode(node.name);
-                } else {
-                    throw new Error('Invalid function name in function call');
-                }
-                
-                if (funcToCall instanceof Function) {
-                    let args = node.args.map(evalNode);
-                    return funcToCall(...args);
-                }
-                throw new Error(`Function is not defined or is not callable`);
-            case 'CaseExpression':
-                const values = node.value.map(evalNode);
-                
-                for (const caseItem of node.cases) {
-                    const pattern = caseItem.pattern.map(evalNode);
                     
-                    let matches = true;
-                    for (let i = 0; i < Math.max(values.length, pattern.length); i++) {
-                        const value = values[i];
-                        const patternValue = pattern[i];
+                    for (const caseItem of node.cases) {
+                        // Handle both single patterns and arrays of patterns
+                        const patterns = caseItem.pattern.map(pat => localEvalNodeWithScope(pat, scope));
                         
-                        if (patternValue === true) continue;
+                        if (process.env.DEBUG) {
+                            console.log(`[DEBUG] localEvalNodeWithScope WhenExpression: patterns =`, patterns);
+                        }
                         
-                        if (value !== patternValue) {
+                        // Check if patterns match the values
+                        let matches = true;
+                        if (whenValues.length !== patterns.length) {
                             matches = false;
-                            break;
+                        } else {
+                            for (let i = 0; i < whenValues.length; i++) {
+                                const value = whenValues[i];
+                                const pattern = patterns[i];
+                                
+                                if (process.env.DEBUG) {
+                                    console.log(`[DEBUG] localEvalNodeWithScope WhenExpression: comparing value ${value} with pattern ${pattern}`);
+                                }
+                                
+                                if (pattern === true) { // Wildcard pattern
+                                    // Wildcard always matches
+                                    if (process.env.DEBUG) {
+                                        console.log(`[DEBUG] localEvalNodeWithScope WhenExpression: wildcard matches`);
+                                    }
+                                    continue;
+                                } else if (value !== pattern) {
+                                    matches = false;
+                                    if (process.env.DEBUG) {
+                                        console.log(`[DEBUG] localEvalNodeWithScope WhenExpression: pattern does not match`);
+                                    }
+                                    break;
+                                } else {
+                                    if (process.env.DEBUG) {
+                                        console.log(`[DEBUG] localEvalNodeWithScope WhenExpression: pattern matches`);
+                                    }
+                                }
+                            }
                         }
-                    }
-                    
-                    if (matches) {
-                        const results = caseItem.result.map(evalNode);
-                        if (results.length === 1) {
-                            return results[0];
+                        
+                        if (process.env.DEBUG) {
+                            console.log(`[DEBUG] localEvalNodeWithScope WhenExpression: case matches = ${matches}`);
+                        }
+                        
+                        if (matches) {
+                            const results = caseItem.result.map(res => localEvalNodeWithScope(res, scope));
+                            if (results.length === 1) {
+                                return results[0];
+                            }
+                            return results.join(' ');
                         }
-                        return results.join(' ');
                     }
-                }
-                throw new Error('No matching pattern found');
-            case 'WildcardPattern':
-                return true;
-            case 'IOInExpression':
-                const readline = require('readline');
-                const rl = readline.createInterface({
-                    input: process.stdin,
-                    output: process.stdout
-                });
-                
-                return new Promise((resolve) => {
-                    rl.question('', (input) => {
-                        rl.close();
-                        const num = parseInt(input);
-                        resolve(isNaN(num) ? input : num);
+                    throw new Error('No matching pattern found');
+                case 'WildcardPattern':
+                    return true;
+                case 'IOInExpression':
+                    const readline = require('readline');
+                    const rl = readline.createInterface({
+                        input: process.stdin,
+                        output: process.stdout
                     });
-                });
-            case 'IOOutExpression':
-                const outputValue = evalNode(node.value);
-                console.log(outputValue);
-                return outputValue;
-            case 'IOAssertExpression':
-                const assertionValue = evalNode(node.value);
-                if (!assertionValue) {
-                    throw new Error('Assertion failed');
-                }
-                return assertionValue;
-            case 'FunctionReference':
-                const functionValue = globalScope[node.name];
-                if (functionValue === undefined) {
-                    throw new Error(`Function ${node.name} is not defined`);
-                }
-                if (typeof functionValue !== 'function') {
-                    throw new Error(`${node.name} is not a function`);
-                }
-                return functionValue;
-            default:
-                throw new Error(`Unknown node type: ${node.type}`);
+                    
+                    return new Promise((resolve) => {
+                        rl.question('', (input) => {
+                            rl.close();
+                            const num = parseInt(input);
+                            resolve(isNaN(num) ? input : num);
+                        });
+                    });
+                case 'IOOutExpression':
+                    const localOutputValue = localEvalNodeWithScope(node.value, scope);
+                    console.log(localOutputValue);
+                    return localOutputValue;
+                case 'IOAssertExpression':
+                    const localAssertionValue = localEvalNodeWithScope(node.value, scope);
+                    if (!localAssertionValue) {
+                        throw new Error('Assertion failed');
+                    }
+                    return localAssertionValue;
+                case 'FunctionReference':
+                    const localFunctionValue = globalScope[node.name];
+                    if (localFunctionValue === undefined) {
+                        throw new Error(`Function ${node.name} is not defined`);
+                    }
+                    if (typeof localFunctionValue !== 'function') {
+                        throw new Error(`${node.name} is not a function`);
+                    }
+                    return localFunctionValue;
+                case 'ArrowExpression':
+                    // Arrow expressions are function bodies that should be evaluated
+                    return localEvalNodeWithScope(node.body, scope);
+                default:
+                    throw new Error(`Unknown node type: ${node.type}`);
+            }
+        } finally {
+            callStackTracker.pop();
         }
-    }
+    };
 
-    const localEvalNodeWithScope = (node, scope) => {
-        if (!node) {
-            return undefined;
-        }
-        switch (node.type) {
-            case 'NumberLiteral':
-                return parseFloat(node.value);
-            case 'StringLiteral':
-                return node.value;
-            case 'BooleanLiteral':
-                return node.value;
-            case 'PlusExpression':
-                return localEvalNodeWithScope(node.left, scope) + localEvalNodeWithScope(node.right, scope);
-            case 'MinusExpression':
-                return localEvalNodeWithScope(node.left, scope) - localEvalNodeWithScope(node.right, scope);
-            case 'MultiplyExpression':
-                return localEvalNodeWithScope(node.left, scope) * localEvalNodeWithScope(node.right, scope);
-            case 'DivideExpression':
-                const divisor = localEvalNodeWithScope(node.right, scope);
-                if (divisor === 0) {
-                    throw new Error('Division by zero');
-                }
-                return localEvalNodeWithScope(node.left, scope) / localEvalNodeWithScope(node.right, scope);
-            case 'ModuloExpression':
-                return localEvalNodeWithScope(node.left, scope) % localEvalNodeWithScope(node.right, scope);
-            case 'PowerExpression':
-                return Math.pow(localEvalNodeWithScope(node.left, scope), localEvalNodeWithScope(node.right, scope));
-            case 'EqualsExpression':
-                return localEvalNodeWithScope(node.left, scope) === localEvalNodeWithScope(node.right, scope);
-            case 'LessThanExpression':
-                return localEvalNodeWithScope(node.left, scope) < localEvalNodeWithScope(node.right, scope);
-            case 'GreaterThanExpression':
-                return localEvalNodeWithScope(node.left, scope) > localEvalNodeWithScope(node.right, scope);
-            case 'LessEqualExpression':
-                return localEvalNodeWithScope(node.left, scope) <= localEvalNodeWithScope(node.right, scope);
-            case 'GreaterEqualExpression':
-                return localEvalNodeWithScope(node.left, scope) >= localEvalNodeWithScope(node.right, scope);
-            case 'NotEqualExpression':
-                return localEvalNodeWithScope(node.left, scope) !== localEvalNodeWithScope(node.right, scope);
-            case 'AndExpression':
-                return !!(localEvalNodeWithScope(node.left, scope) && localEvalNodeWithScope(node.right, scope));
-            case 'OrExpression':
-                return !!(localEvalNodeWithScope(node.left, scope) || localEvalNodeWithScope(node.right, scope));
-            case 'XorExpression':
-                const leftVal = localEvalNodeWithScope(node.left, scope);
-                const rightVal = localEvalNodeWithScope(node.right, scope);
-                return !!((leftVal && !rightVal) || (!leftVal && rightVal));
-            case 'NotExpression':
-                return !localEvalNodeWithScope(node.operand, scope);
-            case 'UnaryMinusExpression':
-                return -localEvalNodeWithScope(node.operand, scope);
-            case 'TableLiteral':
-                const table = {};
-                let arrayIndex = 1;
-                
-                for (const entry of node.entries) {
-                    if (entry.key === null) {
-                        // Array-like entry: {1, 2, 3}
-                        table[arrayIndex] = localEvalNodeWithScope(entry.value, scope);
-                        arrayIndex++;
-                    } else {
-                        // Key-value entry: {name: "Alice", age: 30}
-                        let key;
-                        if (entry.key.type === 'Identifier') {
-                            // Convert identifier keys to strings
-                            key = entry.key.value;
+    /**
+     * Evaluates AST nodes in the global scope (internal recursion helper).
+     * 
+     * @param {Object} node - AST node to evaluate
+     * @returns {*} The result of evaluating the node
+     * @throws {Error} For evaluation errors
+     * 
+     * @description Internal helper function for recursive evaluation that
+     * always uses the global scope. Used to avoid circular dependencies.
+     */
+    const localEvalNode = (node) => {
+        callStackTracker.push('localEvalNode', node?.type || 'unknown');
+        
+        try {
+            if (!node) {
+                return undefined;
+            }
+            switch (node.type) {
+                case 'NumberLiteral':
+                    return parseFloat(node.value);
+                case 'StringLiteral':
+                    return node.value;
+                case 'BooleanLiteral':
+                    return node.value;
+                case 'PlusExpression':
+                    return localEvalNode(node.left) + localEvalNode(node.right);
+                case 'MinusExpression':
+                    return localEvalNode(node.left) - localEvalNode(node.right);
+                case 'MultiplyExpression':
+                    return localEvalNode(node.left) * localEvalNode(node.right);
+                case 'DivideExpression':
+                    const divisor = localEvalNode(node.right);
+                    if (divisor === 0) {
+                        throw new Error('Division by zero');
+                    }
+                    return localEvalNode(node.left) / localEvalNode(node.right);
+                case 'ModuloExpression':
+                    return localEvalNode(node.left) % localEvalNode(node.right);
+                case 'PowerExpression':
+                    return Math.pow(localEvalNode(node.left), localEvalNode(node.right));
+                case 'EqualsExpression':
+                    return localEvalNode(node.left) === localEvalNode(node.right);
+                case 'LessThanExpression':
+                    return localEvalNode(node.left) < localEvalNode(node.right);
+                case 'GreaterThanExpression':
+                    return localEvalNode(node.left) > localEvalNode(node.right);
+                case 'LessEqualExpression':
+                    return localEvalNode(node.left) <= localEvalNode(node.right);
+                case 'GreaterEqualExpression':
+                    return localEvalNode(node.left) >= localEvalNode(node.right);
+                case 'NotEqualExpression':
+                    return localEvalNode(node.left) !== localEvalNode(node.right);
+                case 'AndExpression':
+                    return !!(localEvalNode(node.left) && localEvalNode(node.right));
+                case 'OrExpression':
+                    return !!(localEvalNode(node.left) || localEvalNode(node.right));
+                case 'XorExpression':
+                    const leftVal = localEvalNode(node.left);
+                    const rightVal = localEvalNode(node.right);
+                    return !!((leftVal && !rightVal) || (!leftVal && rightVal));
+                case 'NotExpression':
+                    return !localEvalNode(node.operand);
+                case 'UnaryMinusExpression':
+                    return -localEvalNode(node.operand);
+                case 'TableLiteral':
+                    const table = {};
+                    let arrayIndex = 1;
+                    
+                    for (const entry of node.entries) {
+                        if (entry.key === null) {
+                            // Array-like entry: {1, 2, 3}
+                            table[arrayIndex] = localEvalNode(entry.value);
+                            arrayIndex++;
                         } else {
-                            // For other key types (numbers, strings), evaluate normally
-                            key = localEvalNodeWithScope(entry.key, scope);
+                            // Key-value entry: {name: "Alice", age: 30}
+                            let key;
+                            if (entry.key.type === 'Identifier') {
+                                // Convert identifier keys to strings
+                                key = entry.key.value;
+                            } else {
+                                // For other key types (numbers, strings), evaluate normally
+                                key = localEvalNode(entry.key);
+                            }
+                            const value = localEvalNode(entry.value);
+                            table[key] = value;
                         }
-                        const value = localEvalNodeWithScope(entry.value, scope);
-                        table[key] = value;
                     }
-                }
-                
-                return table;
-            case 'TableAccess':
-                const tableValue = localEvalNodeWithScope(node.table, scope);
-                let keyValue;
-                
-                // Handle different key types
-                if (node.key.type === 'Identifier') {
-                    // For dot notation, use the identifier name as the key
-                    keyValue = node.key.value;
-                } else {
-                    // For bracket notation, evaluate the key expression
-                    keyValue = localEvalNodeWithScope(node.key, scope);
-                }
-                
-                if (typeof tableValue !== 'object' || tableValue === null) {
-                    throw new Error('Cannot access property of non-table value');
-                }
-                
-                if (tableValue[keyValue] === undefined) {
-                    throw new Error(`Key '${keyValue}' not found in table`);
-                }
-                
-                return tableValue[keyValue];
-            case 'AssignmentExpression':
-                if (globalScope.hasOwnProperty(node.name)) {
-                    throw new Error(`Cannot reassign immutable variable: ${node.name}`);
-                }
-                globalScope[node.name] = localEvalNodeWithScope(node.value, scope);
-                return;
-            case 'Identifier':
-                // First check local scope, then global scope
-                if (scope && scope.hasOwnProperty(node.value)) {
-                    return scope[node.value];
-                }
-                const identifierValue = globalScope[node.value];
-                if (identifierValue === undefined && node.value) {
-                    return node.value;
-                }
-                return identifierValue;
-            case 'FunctionDeclaration':
-                // For anonymous functions, the name comes from the assignment
-                // The function itself doesn't have a name, so we just return
-                // The assignment will handle storing it in the global scope
-                return function(...args) {
-                    let nestedScope = Object.create(globalScope);
-                    for (let i = 0; i < node.params.length; i++) {
-                        nestedScope[node.params[i]] = args[i];
+                    
+                    return table;
+                case 'TableAccess':
+                    const tableValue = localEvalNode(node.table);
+                    let keyValue;
+                    
+                    // Handle different key types
+                    if (node.key.type === 'Identifier') {
+                        // For dot notation, use the identifier name as the key
+                        keyValue = node.key.value;
+                    } else {
+                        // For bracket notation, evaluate the key expression
+                        keyValue = localEvalNode(node.key);
                     }
-                    return localEvalNodeWithScope(node.body, nestedScope);
-                };
-            case 'FunctionCall':
-                let localFunc;
-                if (typeof node.name === 'string') {
-                    // Regular function call with string name
-                    localFunc = globalScope[node.name];
-                } else if (node.name.type === 'Identifier') {
-                    // Function call with identifier
-                    localFunc = globalScope[node.name.value];
-                } else if (node.name.type === 'TableAccess') {
-                    // Function call from table access (e.g., math.add)
-                    localFunc = localEvalNodeWithScope(node.name, scope);
-                } else {
-                    throw new Error('Invalid function name in function call');
-                }
-                
-                if (localFunc instanceof Function) {
-                    let args = node.args.map(arg => localEvalNodeWithScope(arg, scope));
-                    return localFunc(...args);
-                }
-                throw new Error(`Function is not defined or is not callable`);
-            case 'CaseExpression':
-                const values = node.value.map(val => localEvalNodeWithScope(val, scope));
-                
-                for (const caseItem of node.cases) {
-                    const pattern = caseItem.pattern.map(pat => localEvalNodeWithScope(pat, scope));
                     
-                    let matches = true;
-                    for (let i = 0; i < Math.max(values.length, pattern.length); i++) {
-                        const value = values[i];
-                        const patternValue = pattern[i];
-                        
-                        if (patternValue === true) continue;
-                        
-                        if (value !== patternValue) {
-                            matches = false;
-                            break;
-                        }
+                    if (typeof tableValue !== 'object' || tableValue === null) {
+                        throw new Error('Cannot access property of non-table value');
                     }
                     
-                    if (matches) {
-                        const results = caseItem.result.map(res => localEvalNodeWithScope(res, scope));
-                        if (results.length === 1) {
-                            return results[0];
-                        }
-                        return results.join(' ');
+                    if (tableValue[keyValue] === undefined) {
+                        throw new Error(`Key '${keyValue}' not found in table`);
                     }
-                }
-                throw new Error('No matching pattern found');
-            case 'WildcardPattern':
-                return true;
-            case 'IOInExpression':
-                const readline = require('readline');
-                const rl = readline.createInterface({
-                    input: process.stdin,
-                    output: process.stdout
-                });
-                
-                return new Promise((resolve) => {
-                    rl.question('', (input) => {
-                        rl.close();
-                        const num = parseInt(input);
-                        resolve(isNaN(num) ? input : num);
-                    });
-                });
-            case 'IOOutExpression':
-                const localOutputValue = localEvalNodeWithScope(node.value, scope);
-                console.log(localOutputValue);
-                return localOutputValue;
-            case 'IOAssertExpression':
-                const localAssertionValue = localEvalNodeWithScope(node.value, scope);
-                if (!localAssertionValue) {
-                    throw new Error('Assertion failed');
-                }
-                return localAssertionValue;
-            case 'FunctionReference':
-                const localFunctionValue = globalScope[node.name];
-                if (localFunctionValue === undefined) {
-                    throw new Error(`Function ${node.name} is not defined`);
-                }
-                if (typeof localFunctionValue !== 'function') {
-                    throw new Error(`${node.name} is not a function`);
-                }
-                return localFunctionValue;
-            default:
-                throw new Error(`Unknown node type: ${node.type}`);
-        }
-    };
-
-    const localEvalNode = (node) => {
-        if (!node) {
-            return undefined;
-        }
-        switch (node.type) {
-            case 'NumberLiteral':
-                return parseFloat(node.value);
-            case 'StringLiteral':
-                return node.value;
-            case 'BooleanLiteral':
-                return node.value;
-            case 'PlusExpression':
-                return localEvalNode(node.left) + localEvalNode(node.right);
-            case 'MinusExpression':
-                return localEvalNode(node.left) - localEvalNode(node.right);
-            case 'MultiplyExpression':
-                return localEvalNode(node.left) * localEvalNode(node.right);
-            case 'DivideExpression':
-                const divisor = localEvalNode(node.right);
-                if (divisor === 0) {
-                    throw new Error('Division by zero');
-                }
-                return localEvalNode(node.left) / localEvalNode(node.right);
-            case 'ModuloExpression':
-                return localEvalNode(node.left) % localEvalNode(node.right);
-            case 'PowerExpression':
-                return Math.pow(localEvalNode(node.left), localEvalNode(node.right));
-            case 'EqualsExpression':
-                return localEvalNode(node.left) === localEvalNode(node.right);
-            case 'LessThanExpression':
-                return localEvalNode(node.left) < localEvalNode(node.right);
-            case 'GreaterThanExpression':
-                return localEvalNode(node.left) > localEvalNode(node.right);
-            case 'LessEqualExpression':
-                return localEvalNode(node.left) <= localEvalNode(node.right);
-            case 'GreaterEqualExpression':
-                return localEvalNode(node.left) >= localEvalNode(node.right);
-            case 'NotEqualExpression':
-                return localEvalNode(node.left) !== localEvalNode(node.right);
-            case 'AndExpression':
-                return !!(localEvalNode(node.left) && localEvalNode(node.right));
-            case 'OrExpression':
-                return !!(localEvalNode(node.left) || localEvalNode(node.right));
-            case 'XorExpression':
-                const leftVal = localEvalNode(node.left);
-                const rightVal = localEvalNode(node.right);
-                return !!((leftVal && !rightVal) || (!leftVal && rightVal));
-            case 'NotExpression':
-                return !localEvalNode(node.operand);
-            case 'UnaryMinusExpression':
-                return -localEvalNode(node.operand);
-            case 'TableLiteral':
-                const table = {};
-                let arrayIndex = 1;
-                
-                for (const entry of node.entries) {
-                    if (entry.key === null) {
-                        // Array-like entry: {1, 2, 3}
-                        table[arrayIndex] = localEvalNode(entry.value);
-                        arrayIndex++;
-                    } else {
-                        // Key-value entry: {name: "Alice", age: 30}
-                        let key;
-                        if (entry.key.type === 'Identifier') {
-                            // Convert identifier keys to strings
-                            key = entry.key.value;
-                        } else {
-                            // For other key types (numbers, strings), evaluate normally
-                            key = localEvalNode(entry.key);
+                    
+                    return tableValue[keyValue];
+                case 'AssignmentExpression':
+                    if (globalScope.hasOwnProperty(node.name)) {
+                        throw new Error(`Cannot reassign immutable variable: ${node.name}`);
+                    }
+                    globalScope[node.name] = localEvalNode(node.value);
+                    return;
+                case 'Identifier':
+                    const identifierValue = globalScope[node.value];
+                    if (identifierValue === undefined && node.value) {
+                        return node.value;
+                    }
+                    return identifierValue;
+                case 'FunctionDeclaration':
+                    // For anonymous functions, the name comes from the assignment
+                    // The function itself doesn't have a name, so we just return
+                    // The assignment will handle storing it in the global scope
+                    return function(...args) {
+                        callStackTracker.push('FunctionCall', node.params.join(','));
+                        try {
+                            let nestedScope = Object.create(globalScope);
+                            for (let i = 0; i < node.params.length; i++) {
+                                nestedScope[node.params[i]] = args[i];
+                            }
+                            return localEvalNodeWithScope(node.body, nestedScope);
+                        } finally {
+                            callStackTracker.pop();
                         }
-                        const value = localEvalNode(entry.value);
-                        table[key] = value;
+                    };
+                case 'FunctionDefinition':
+                    // Create a function from the function definition
+                    return function(...args) {
+                        callStackTracker.push('FunctionCall', node.parameters.join(','));
+                        try {
+                            let nestedScope = Object.create(globalScope);
+                            for (let i = 0; i < node.parameters.length; i++) {
+                                nestedScope[node.parameters[i]] = args[i];
+                            }
+                            return localEvalNodeWithScope(node.body, nestedScope);
+                        } finally {
+                            callStackTracker.pop();
+                        }
+                    };
+                case 'FunctionCall':
+                    let localFunc;
+                    if (typeof node.name === 'string') {
+                        // Regular function call with string name
+                        localFunc = globalScope[node.name];
+                    } else if (node.name.type === 'Identifier') {
+                        // Function call with identifier
+                        localFunc = globalScope[node.name.value];
+                    } else {
+                        // Function call from expression (e.g., parenthesized function, higher-order)
+                        localFunc = localEvalNode(node.name);
                     }
-                }
-                
-                return table;
-            case 'TableAccess':
-                const tableValue = localEvalNode(node.table);
-                let keyValue;
-                
-                // Handle different key types
-                if (node.key.type === 'Identifier') {
-                    // For dot notation, use the identifier name as the key
-                    keyValue = node.key.value;
-                } else {
-                    // For bracket notation, evaluate the key expression
-                    keyValue = localEvalNode(node.key);
-                }
-                
-                if (typeof tableValue !== 'object' || tableValue === null) {
-                    throw new Error('Cannot access property of non-table value');
-                }
-                
-                if (tableValue[keyValue] === undefined) {
-                    throw new Error(`Key '${keyValue}' not found in table`);
-                }
-                
-                return tableValue[keyValue];
-            case 'AssignmentExpression':
-                if (globalScope.hasOwnProperty(node.name)) {
-                    throw new Error(`Cannot reassign immutable variable: ${node.name}`);
-                }
-                globalScope[node.name] = localEvalNode(node.value);
-                return;
-            case 'Identifier':
-                const identifierValue = globalScope[node.value];
-                if (identifierValue === undefined && node.value) {
-                    return node.value;
-                }
-                return identifierValue;
-            case 'FunctionDeclaration':
-                // For anonymous functions, the name comes from the assignment
-                // The function itself doesn't have a name, so we just return
-                // The assignment will handle storing it in the global scope
-                return function(...args) {
-                    let nestedScope = Object.create(globalScope);
-                    for (let i = 0; i < node.params.length; i++) {
-                        nestedScope[node.params[i]] = args[i];
+                    
+                    if (localFunc instanceof Function) {
+                        let args = node.args.map(localEvalNode);
+                        return localFunc(...args);
                     }
-                    return localEvalNodeWithScope(node.body, nestedScope);
-                };
-            case 'FunctionCall':
-                let localFunc;
-                if (typeof node.name === 'string') {
-                    // Regular function call with string name
-                    localFunc = globalScope[node.name];
-                } else if (node.name.type === 'Identifier') {
-                    // Function call with identifier
-                    localFunc = globalScope[node.name.value];
-                } else if (node.name.type === 'TableAccess') {
-                    // Function call from table access (e.g., math.add)
-                    localFunc = localEvalNode(node.name);
-                } else {
-                    throw new Error('Invalid function name in function call');
-                }
-                
-                if (localFunc instanceof Function) {
-                    let args = node.args.map(localEvalNode);
-                    return localFunc(...args);
-                }
-                throw new Error(`Function is not defined or is not callable`);
-            case 'CaseExpression':
-                const values = node.value.map(localEvalNode);
-                
-                for (const caseItem of node.cases) {
-                    const pattern = caseItem.pattern.map(localEvalNode);
+                    throw new Error(`Function is not defined or is not callable`);
+                case 'WhenExpression':
+                    // Handle both single values and arrays of values
+                    const whenValues = Array.isArray(node.value) 
+                        ? node.value.map(localEvalNode) 
+                        : [localEvalNode(node.value)];
                     
-                    let matches = true;
-                    for (let i = 0; i < Math.max(values.length, pattern.length); i++) {
-                        const value = values[i];
-                        const patternValue = pattern[i];
-                        
-                        if (patternValue === true) continue;
+                    for (const caseItem of node.cases) {
+                        // Handle both single patterns and arrays of patterns
+                        const patterns = caseItem.pattern.map(localEvalNode);
                         
-                        if (value !== patternValue) {
+                        // Check if patterns match the values
+                        let matches = true;
+                        if (whenValues.length !== patterns.length) {
                             matches = false;
-                            break;
+                        } else {
+                            for (let i = 0; i < whenValues.length; i++) {
+                                const value = whenValues[i];
+                                const pattern = patterns[i];
+                                
+                                if (pattern === true) { // Wildcard pattern
+                                    // Wildcard always matches
+                                    continue;
+                                } else if (value !== pattern) {
+                                    matches = false;
+                                    break;
+                                }
+                            }
                         }
-                    }
-                    
-                    if (matches) {
-                        const results = caseItem.result.map(localEvalNode);
-                        if (results.length === 1) {
-                            return results[0];
+                        
+                        if (matches) {
+                            const results = caseItem.result.map(localEvalNode);
+                            if (results.length === 1) {
+                                return results[0];
+                            }
+                            return results.join(' ');
                         }
-                        return results.join(' ');
                     }
-                }
-                throw new Error('No matching pattern found');
-            case 'WildcardPattern':
-                return true;
-            case 'IOInExpression':
-                const readline = require('readline');
-                const rl = readline.createInterface({
-                    input: process.stdin,
-                    output: process.stdout
-                });
-                
-                return new Promise((resolve) => {
-                    rl.question('', (input) => {
-                        rl.close();
-                        const num = parseInt(input);
-                        resolve(isNaN(num) ? input : num);
+                    throw new Error('No matching pattern found');
+                case 'WildcardPattern':
+                    return true;
+                case 'IOInExpression':
+                    const readline = require('readline');
+                    const rl = readline.createInterface({
+                        input: process.stdin,
+                        output: process.stdout
                     });
-                });
-            case 'IOOutExpression':
-                const localOutputValue = localEvalNode(node.value);
-                console.log(localOutputValue);
-                return localOutputValue;
-            case 'IOAssertExpression':
-                const localAssertionValue = localEvalNode(node.value);
-                if (!localAssertionValue) {
-                    throw new Error('Assertion failed');
-                }
-                return localAssertionValue;
-            case 'FunctionReference':
-                const localFunctionValue = globalScope[node.name];
-                if (localFunctionValue === undefined) {
-                    throw new Error(`Function ${node.name} is not defined`);
-                }
-                if (typeof localFunctionValue !== 'function') {
-                    throw new Error(`${node.name} is not a function`);
-                }
-                return localFunctionValue;
-            default:
-                throw new Error(`Unknown node type: ${node.type}`);
+                    
+                    return new Promise((resolve) => {
+                        rl.question('', (input) => {
+                            rl.close();
+                            const num = parseInt(input);
+                            resolve(isNaN(num) ? input : num);
+                        });
+                    });
+                case 'IOOutExpression':
+                    const localOutputValue = localEvalNode(node.value);
+                    console.log(localOutputValue);
+                    return localOutputValue;
+                case 'IOAssertExpression':
+                    const localAssertionValue = localEvalNode(node.value);
+                    if (!localAssertionValue) {
+                        throw new Error('Assertion failed');
+                    }
+                    return localAssertionValue;
+                case 'FunctionReference':
+                    const localFunctionValue = globalScope[node.name];
+                    if (localFunctionValue === undefined) {
+                        throw new Error(`Function ${node.name} is not defined`);
+                    }
+                    if (typeof localFunctionValue !== 'function') {
+                        throw new Error(`${node.name} is not a function`);
+                    }
+                    return localFunctionValue;
+                case 'ArrowExpression':
+                    // Arrow expressions are function bodies that should be evaluated
+                    return localEvalNode(node.body);
+                default:
+                    throw new Error(`Unknown node type: ${node.type}`);
+            }
+        } finally {
+            callStackTracker.pop();
         }
     };
 
@@ -1888,9 +1038,18 @@ function interpreter(ast) {
 }
 
 /**
- * Debug logging and error reporting.
+ * Debug logging utility function.
  * 
- * Why: Debug functions are gated by the DEBUG environment variable, allowing for verbose output during development and silent operation in production. This approach makes it easy to trace execution and diagnose issues without cluttering normal output.
+ * @param {string} message - Debug message to log
+ * @param {*} [data=null] - Optional data to log with the message
+ * 
+ * @description Logs debug messages to console when DEBUG environment variable is set.
+ * Provides verbose output during development while remaining silent in production.
+ * 
+ * @why Debug functions are gated by the DEBUG environment variable, allowing for 
+ * verbose output during development and silent operation in production. This 
+ * approach makes it easy to trace execution and diagnose issues without 
+ * cluttering normal output.
  */
 function debugLog(message, data = null) {
     if (process.env.DEBUG) {
@@ -1902,9 +1061,18 @@ function debugLog(message, data = null) {
 }
 
 /**
- * Debug logging and error reporting.
+ * Debug error logging utility function.
+ * 
+ * @param {string} message - Debug error message to log
+ * @param {Error} [error=null] - Optional error object to log
  * 
- * Why: Debug functions are gated by the DEBUG environment variable, allowing for verbose output during development and silent operation in production. This approach makes it easy to trace execution and diagnose issues without cluttering normal output.
+ * @description Logs debug error messages to console when DEBUG environment variable is set.
+ * Provides verbose error output during development while remaining silent in production.
+ * 
+ * @why Debug functions are gated by the DEBUG environment variable, allowing for 
+ * verbose output during development and silent operation in production. This 
+ * approach makes it easy to trace execution and diagnose issues without 
+ * cluttering normal output.
  */
 function debugError(message, error = null) {
     if (process.env.DEBUG) {
@@ -1916,14 +1084,139 @@ function debugError(message, error = null) {
 }
 
 /**
- * Reads a file, tokenizes, parses, and interprets it.
+ * Call stack tracking for debugging recursion issues.
  * 
- * Why: This function is the entry point for file execution, handling all stages of the language pipeline. Debug output is provided at each stage for transparency and troubleshooting.
+ * @description Tracks function calls to help identify infinite recursion
+ * and deep call stacks that cause stack overflow errors.
  */
-function executeFile(filePath) {
+const callStackTracker = {
+    stack: [],
+    maxDepth: 0,
+    callCounts: new Map(),
+    
+    /**
+     * Push a function call onto the stack
+     * @param {string} functionName - Name of the function being called
+     * @param {string} context - Context where the call is happening
+     */
+    push: function(functionName, context = '') {
+        const callInfo = { functionName, context, timestamp: Date.now() };
+        this.stack.push(callInfo);
+        
+        // Track maximum depth
+        if (this.stack.length > this.maxDepth) {
+            this.maxDepth = this.stack.length;
+        }
+        
+        // Count function calls
+        const key = `${functionName}${context ? `:${context}` : ''}`;
+        this.callCounts.set(key, (this.callCounts.get(key) || 0) + 1);
+        
+        // Check for potential infinite recursion
+        if (this.stack.length > 1000) {
+            console.error('=== POTENTIAL INFINITE RECURSION DETECTED ===');
+            console.error('Call stack depth:', this.stack.length);
+            console.error('Function call counts:', Object.fromEntries(this.callCounts));
+            console.error('Recent call stack:');
+            this.stack.slice(-10).forEach((call, i) => {
+                console.error(`  ${this.stack.length - 10 + i}: ${call.functionName}${call.context ? ` (${call.context})` : ''}`);
+            });
+            throw new Error(`Potential infinite recursion detected. Call stack depth: ${this.stack.length}`);
+        }
+        
+        if (process.env.DEBUG && this.stack.length % 100 === 0) {
+            console.log(`[DEBUG] Call stack depth: ${this.stack.length}, Max: ${this.maxDepth}`);
+        }
+    },
+    
+    /**
+     * Pop a function call from the stack
+     */
+    pop: function() {
+        return this.stack.pop();
+    },
+    
+    /**
+     * Get current stack depth
+     */
+    getDepth: function() {
+        return this.stack.length;
+    },
+    
+    /**
+     * Get call statistics
+     */
+    getStats: function() {
+        return {
+            currentDepth: this.stack.length,
+            maxDepth: this.maxDepth,
+            callCounts: Object.fromEntries(this.callCounts)
+        };
+    },
+    
+    /**
+     * Reset the tracker
+     */
+    reset: function() {
+        this.stack = [];
+        this.maxDepth = 0;
+        this.callCounts.clear();
+    }
+};
+
+/**
+ * Cross-platform file I/O utility
+ * 
+ * @param {string} filePath - Path to the file to read
+ * @returns {string} File contents
+ * @throws {Error} For file reading errors
+ * 
+ * @description Handles file reading across different platforms (Node.js, Bun, browser)
+ * with appropriate fallbacks for each environment.
+ */
+async function readFile(filePath) {
+    // Check if we're in a browser environment
+    if (typeof window !== 'undefined') {
+        // Browser environment - would need to implement file input or fetch
+        throw new Error('File I/O not supported in browser environment');
+    }
+    
+    // Node.js or Bun environment
     try {
+        // Try dynamic import for ES modules compatibility
+        const fs = await import('fs');
+        return fs.readFileSync(filePath, 'utf8');
+    } catch (error) {
+        // Fallback to require for older Node.js versions
         const fs = require('fs');
-        const input = fs.readFileSync(filePath, 'utf8');
+        return fs.readFileSync(filePath, 'utf8');
+    }
+}
+
+/**
+ * Reads a file, tokenizes, parses, and interprets it.
+ * 
+ * @param {string} filePath - Path to the file to execute
+ * @throws {Error} For file reading, parsing, or execution errors
+ * 
+ * @description Main entry point for file execution. Handles the complete language
+ * pipeline: file reading, lexical analysis, parsing, and interpretation.
+ * 
+ * @why This function is the entry point for file execution, handling all stages 
+ * of the language pipeline. Debug output is provided at each stage for 
+ * transparency and troubleshooting.
+ * 
+ * @note Supports both synchronous and asynchronous execution, with proper
+ * error handling and process exit codes.
+ */
+async function executeFile(filePath) {
+    try {
+        // Validate file extension
+        if (!filePath.endsWith('.txt')) {
+            throw new Error('Only .txt files are supported');
+        }
+        
+        const input = await readFile(filePath);
         
         debugLog('Input:', input);
         
@@ -1940,39 +1233,73 @@ function executeFile(filePath) {
                 if (finalResult !== undefined) {
                     console.log(finalResult);
                 }
+                // Print call stack statistics after execution
+                const stats = callStackTracker.getStats();
+                console.log('\n=== CALL STACK STATISTICS ===');
+                console.log('Maximum call stack depth:', stats.maxDepth);
+                console.log('Function call counts:', JSON.stringify(stats.callCounts, null, 2));
             }).catch(error => {
                 console.error(`Error executing file: ${error.message}`);
+                // Print call stack statistics on error
+                const stats = callStackTracker.getStats();
+                console.error('\n=== CALL STACK STATISTICS ON ERROR ===');
+                console.error('Maximum call stack depth:', stats.maxDepth);
+                console.error('Function call counts:', JSON.stringify(stats.callCounts, null, 2));
                 process.exit(1);
             });
         } else {
             if (result !== undefined) {
                 console.log(result);
             }
+            // Print call stack statistics after execution
+            const stats = callStackTracker.getStats();
+            console.log('\n=== CALL STACK STATISTICS ===');
+            console.log('Maximum call stack depth:', stats.maxDepth);
+            console.log('Function call counts:', JSON.stringify(stats.callCounts, null, 2));
         }
     } catch (error) {
         console.error(`Error executing file: ${error.message}`);
+        // Print call stack statistics on error
+        const stats = callStackTracker.getStats();
+        console.error('\n=== CALL STACK STATISTICS ON ERROR ===');
+        console.error('Maximum call stack depth:', stats.maxDepth);
+        console.error('Function call counts:', JSON.stringify(stats.callCounts, null, 2));
         process.exit(1);
     }
 }
 
 /**
- * CLI argument handling.
+ * CLI argument handling and program entry point.
+ * 
+ * @description Processes command line arguments and executes the specified file.
+ * Provides helpful error messages for incorrect usage.
+ * 
+ * @why The language is designed for file execution only (no REPL), so the CLI 
+ * enforces this usage and provides helpful error messages for incorrect invocation.
  * 
- * Why: The language is designed for file execution only (no REPL), so the CLI enforces this usage and provides helpful error messages for incorrect invocation.
+ * @note Exits with appropriate error codes for different failure scenarios.
  */
-const args = process.argv.slice(2);
+async function main() {
+    const args = process.argv.slice(2);
 
-if (args.length === 0) {
-    console.error('Usage: node lang.js <file>');
-    console.error('  Provide a file path to execute');
-    process.exit(1);
-} else if (args.length === 1) {
-    // Execute the file
-    const filePath = args[0];
-    executeFile(filePath);
-} else {
-    // Too many arguments
-    console.error('Usage: node lang.js <file>');
-    console.error('  Provide exactly one file path to execute');
+    if (args.length === 0) {
+        console.error('Usage: node lang.js <file>');
+        console.error('  Provide a file path to execute');
+        process.exit(1);
+    } else if (args.length === 1) {
+        // Execute the file
+        const filePath = args[0];
+        await executeFile(filePath);
+    } else {
+        // Too many arguments
+        console.error('Usage: node lang.js <file>');
+        console.error('  Provide exactly one file path to execute');
+        process.exit(1);
+    }
+}
+
+// Start the program
+main().catch(error => {
+    console.error('Fatal error:', error.message);
     process.exit(1);
-}
\ No newline at end of file
+});
\ No newline at end of file
diff --git a/js/scripting-lang/learn_scripting_lang.txt b/js/scripting-lang/learn_scripting_lang.txt
deleted file mode 100644
index fc4f966..0000000
--- a/js/scripting-lang/learn_scripting_lang.txt
+++ /dev/null
@@ -1,61 +0,0 @@
-/* Learn an as of yet unnamed language in Y Minutes */
-/* A functional programming language with immutable variables, 
-   first-class functions, and pattern matching */
-
-/* We've got numbers */
-x : 42; /* also the ability to assign values to variables */
-y : 3.14;
-z : 0;
-
-/* We've got identifiers */
-this_is_a : "test";
-flag : true;
-value : false;
-
-/* We've got basic mathematical operators */
-sum : x + y;
-diff : x - y;
-prod : x * y;
-quot : x / y;
-
-/* We've got pattern matching case statements! */
-result : case x of
-    42 : "correct"
-    _ : "wrong";
-
-/* Of course, there are functions */
-double : x -> x * 2;
-add : x y -> x + y;
-func_result : double 5;
-
-/* And immutable tables, kinda inspired by Lua's tables */
-table : {1, 2, 3, name: "Alice", age: 30};
-first : table[1];
-table_name : table.name;
-
-/* A boring standard library */
-square : x -> x * x;
-mapped : map @double 5;
-composed : compose @double @square 3;
-
-/* Special functions for IO all start with .. */
-..out "Hello from the scripting language!";
-..out x;
-..out func_result;
-..out result;
-..out first;
-..out table_name;
-..out mapped;
-..out composed;
-
-/* There's a baked in IO function for performing assertions */
-..assert x = 42;
-..assert func_result = 10;
-..assert result = "correct";
-..assert first = 1;
-..assert table_name = "Alice";
-..assert mapped = 10;
-..assert composed = 18;
-..assert 5 > 3; /* ..assert should work with any kinda operators */  
-
-..out "Learn Scripting Language tutorial completed!"; 
\ No newline at end of file
diff --git a/js/scripting-lang/lexer.js b/js/scripting-lang/lexer.js
new file mode 100644
index 0000000..23eea14
--- /dev/null
+++ b/js/scripting-lang/lexer.js
@@ -0,0 +1,364 @@
+// Lexer for the scripting language
+// Supports both Node.js and browser environments
+
+/**
+ * Token types for the language
+ */
+export const TokenType = {
+    NUMBER: 'NUMBER',
+    PLUS: 'PLUS',
+    MINUS: 'MINUS',
+    MULTIPLY: 'MULTIPLY',
+    DIVIDE: 'DIVIDE',
+    IDENTIFIER: 'IDENTIFIER',
+    ASSIGNMENT: 'ASSIGNMENT',
+    ARROW: 'ARROW',
+    CASE: 'CASE',
+    OF: 'OF',
+    WHEN: 'WHEN',
+    IS: 'IS',
+    THEN: 'THEN',
+    WILDCARD: 'WILDCARD',
+    FUNCTION: 'FUNCTION',
+    LEFT_PAREN: 'LEFT_PAREN',
+    RIGHT_PAREN: 'RIGHT_PAREN',
+    LEFT_BRACE: 'LEFT_BRACE',
+    RIGHT_BRACE: 'RIGHT_BRACE',
+    LEFT_BRACKET: 'LEFT_BRACKET',
+    RIGHT_BRACKET: 'RIGHT_BRACKET',
+    SEMICOLON: 'SEMICOLON',
+    COMMA: 'COMMA',
+    DOT: 'DOT',
+    STRING: 'STRING',
+    TRUE: 'TRUE',
+    FALSE: 'FALSE',
+    AND: 'AND',
+    OR: 'OR',
+    XOR: 'XOR',
+    NOT: 'NOT',
+    EQUALS: 'EQUALS',
+    LESS_THAN: 'LESS_THAN',
+    GREATER_THAN: 'GREATER_THAN',
+    LESS_EQUAL: 'LESS_EQUAL',
+    GREATER_EQUAL: 'GREATER_EQUAL',
+    NOT_EQUAL: 'NOT_EQUAL',
+    MODULO: 'MODULO',
+    POWER: 'POWER',
+    IO_IN: 'IO_IN',
+    IO_OUT: 'IO_OUT',
+    IO_ASSERT: 'IO_ASSERT',
+    FUNCTION_REF: 'FUNCTION_REF'
+};
+
+/**
+ * Converts source code into tokens
+ * @param {string} input - The source code to tokenize
+ * @returns {Array} Array of tokens
+ */
+export function lexer(input) {
+    const tokens = [];
+    let current = 0;
+    let line = 1;
+    let column = 1;
+
+    while (current < input.length) {
+        let char = input[current];
+
+        // Skip whitespace
+        if (/\s/.test(char)) {
+            if (char === '\n') {
+                line++;
+                column = 1;
+            } else {
+                column++;
+            }
+            current++;
+            continue;
+        }
+
+        // Skip comments (single line and multi-line)
+        if (char === '/' && input[current + 1] === '/') {
+            while (current < input.length && input[current] !== '\n') {
+                current++;
+                column++;
+            }
+            continue;
+        }
+        
+        // Skip multi-line comments /* ... */
+        if (char === '/' && input[current + 1] === '*') {
+            current += 2; // Skip /*
+            column += 2;
+            while (current < input.length - 1 && !(input[current] === '*' && input[current + 1] === '/')) {
+                if (input[current] === '\n') {
+                    line++;
+                    column = 1;
+                } else {
+                    column++;
+                }
+                current++;
+            }
+            if (current < input.length - 1) {
+                current += 2; // Skip */
+                column += 2;
+            }
+            continue;
+        }
+
+        // IO operations (..in, ..out, ..assert)
+        if (char === '.' && input[current + 1] === '.') {
+            current += 2; // Skip both dots
+            column += 2;
+            
+            // Read the IO operation name
+            let operation = '';
+            while (current < input.length && /[a-zA-Z]/.test(input[current])) {
+                operation += input[current];
+                current++;
+                column++;
+            }
+            
+            // Determine the IO operation type
+            switch (operation) {
+                case 'in':
+                    tokens.push({ type: TokenType.IO_IN, line, column: column - operation.length - 2 });
+                    break;
+                case 'out':
+                    tokens.push({ type: TokenType.IO_OUT, line, column: column - operation.length - 2 });
+                    break;
+                case 'assert':
+                    tokens.push({ type: TokenType.IO_ASSERT, line, column: column - operation.length - 2 });
+                    break;
+                default:
+                    throw new Error(`Unknown IO operation: ..${operation} at line ${line}, column ${column - operation.length - 2}`);
+            }
+            continue;
+        }
+        
+        // Function references (@function)
+        if (char === '@') {
+            current++; // Skip '@'
+            column++;
+            
+            // Read the function name
+            let functionName = '';
+            while (current < input.length && /[a-zA-Z0-9_]/.test(input[current])) {
+                functionName += input[current];
+                current++;
+                column++;
+            }
+            
+            if (functionName === '') {
+                throw new Error(`Invalid function reference at line ${line}, column ${column - 1}`);
+            }
+            
+            tokens.push({ type: TokenType.FUNCTION_REF, name: functionName, line, column: column - functionName.length - 1 });
+            continue;
+        }
+
+        // Numbers
+        if (/[0-9]/.test(char)) {
+            let value = '';
+            while (current < input.length && /[0-9.]/.test(input[current])) {
+                value += input[current];
+                current++;
+                column++;
+            }
+            tokens.push({ type: TokenType.NUMBER, value: parseFloat(value), line, column: column - value.length });
+            continue;
+        }
+
+        // Identifiers and keywords
+        if (/[a-zA-Z_]/.test(char)) {
+            let value = '';
+            const startColumn = column;
+            while (current < input.length && /[a-zA-Z0-9_]/.test(input[current])) {
+                value += input[current];
+                current++;
+                column++;
+            }
+
+            // Check for keywords
+            switch (value) {
+                case 'true':
+                    tokens.push({ type: TokenType.TRUE, value: true, line, column: startColumn });
+                    break;
+                case 'false':
+                    tokens.push({ type: TokenType.FALSE, value: false, line, column: startColumn });
+                    break;
+                case 'and':
+                    tokens.push({ type: TokenType.AND, line, column: startColumn });
+                    break;
+                case 'or':
+                    tokens.push({ type: TokenType.OR, line, column: startColumn });
+                    break;
+                case 'xor':
+                    tokens.push({ type: TokenType.XOR, line, column: startColumn });
+                    break;
+                case 'not':
+                    tokens.push({ type: TokenType.NOT, line, column: startColumn });
+                    break;
+                case 'case':
+                    tokens.push({ type: TokenType.CASE, line, column: startColumn });
+                    break;
+                case 'of':
+                    tokens.push({ type: TokenType.OF, line, column: startColumn });
+                    break;
+                case 'when':
+                    tokens.push({ type: TokenType.WHEN, line, column: startColumn });
+                    break;
+                case 'is':
+                    tokens.push({ type: TokenType.IS, line, column: startColumn });
+                    break;
+                case 'then':
+                    tokens.push({ type: TokenType.THEN, line, column: startColumn });
+                    break;
+                case 'function':
+                    tokens.push({ type: TokenType.FUNCTION, line, column: startColumn });
+                    break;
+                case '_':
+                    tokens.push({ type: TokenType.WILDCARD, line, column: startColumn });
+                    break;
+                default:
+                    tokens.push({ type: TokenType.IDENTIFIER, value, line, column: startColumn });
+            }
+            continue;
+        }
+
+        // Strings
+        if (char === '"') {
+            let value = '';
+            current++;
+            column++;
+            while (current < input.length && input[current] !== '"') {
+                if (input[current] === '\\') {
+                    current++;
+                    column++;
+                    if (current < input.length) {
+                        switch (input[current]) {
+                            case 'n': value += '\n'; break;
+                            case 't': value += '\t'; break;
+                            case 'r': value += '\r'; break;
+                            case '\\': value += '\\'; break;
+                            case '"': value += '"'; break;
+                            default: value += input[current];
+                        }
+                    }
+                } else {
+                    value += input[current];
+                }
+                current++;
+                column++;
+            }
+            if (current < input.length) {
+                current++;
+                column++;
+            }
+            tokens.push({ type: TokenType.STRING, value, line, column: column - value.length - 2 });
+            continue;
+        }
+
+        // Operators and punctuation
+        switch (char) {
+            case '+':
+                tokens.push({ type: TokenType.PLUS, line, column });
+                break;
+            case '-':
+                if (input[current + 1] === '>') {
+                    tokens.push({ type: TokenType.ARROW, line, column });
+                    current++;
+                    column++;
+                } else {
+                    tokens.push({ type: TokenType.MINUS, line, column });
+                }
+                break;
+            case '*':
+                tokens.push({ type: TokenType.MULTIPLY, line, column });
+                break;
+            case '/':
+                tokens.push({ type: TokenType.DIVIDE, line, column });
+                break;
+            case '%':
+                tokens.push({ type: TokenType.MODULO, line, column });
+                break;
+            case '^':
+                tokens.push({ type: TokenType.POWER, line, column });
+                break;
+            case '(':
+                tokens.push({ type: TokenType.LEFT_PAREN, line, column });
+                break;
+            case ')':
+                tokens.push({ type: TokenType.RIGHT_PAREN, line, column });
+                break;
+            case '{':
+                tokens.push({ type: TokenType.LEFT_BRACE, line, column });
+                break;
+            case '}':
+                tokens.push({ type: TokenType.RIGHT_BRACE, line, column });
+                break;
+            case '[':
+                tokens.push({ type: TokenType.LEFT_BRACKET, line, column });
+                break;
+            case ']':
+                tokens.push({ type: TokenType.RIGHT_BRACKET, line, column });
+                break;
+            case ';':
+                tokens.push({ type: TokenType.SEMICOLON, line, column });
+                break;
+            case ',':
+                tokens.push({ type: TokenType.COMMA, line, column });
+                break;
+            case '.':
+                tokens.push({ type: TokenType.DOT, line, column });
+                break;
+            case ':':
+                tokens.push({ type: TokenType.ASSIGNMENT, line, column });
+                break;
+
+            case '=':
+                if (input[current + 1] === '=') {
+                    tokens.push({ type: TokenType.EQUALS, line, column });
+                    current++;
+                    column++;
+                } else {
+                    // Single = is used for equality comparison in assertions
+                    tokens.push({ type: TokenType.EQUALS, line, column });
+                }
+                break;
+            case '<':
+                if (input[current + 1] === '=') {
+                    tokens.push({ type: TokenType.LESS_EQUAL, line, column });
+                    current++;
+                    column++;
+                } else {
+                    tokens.push({ type: TokenType.LESS_THAN, line, column });
+                }
+                break;
+            case '>':
+                if (input[current + 1] === '=') {
+                    tokens.push({ type: TokenType.GREATER_EQUAL, line, column });
+                    current++;
+                    column++;
+                } else {
+                    tokens.push({ type: TokenType.GREATER_THAN, line, column });
+                }
+                break;
+            case '!':
+                if (input[current + 1] === '=') {
+                    tokens.push({ type: TokenType.NOT_EQUAL, line, column });
+                    current++;
+                    column++;
+                } else {
+                    throw new Error(`Unexpected character: ${char} at line ${line}, column ${column}`);
+                }
+                break;
+            default:
+                throw new Error(`Unexpected character: ${char} at line ${line}, column ${column}`);
+        }
+
+        current++;
+        column++;
+    }
+
+    return tokens;
+} 
\ No newline at end of file
diff --git a/js/scripting-lang/package.json b/js/scripting-lang/package.json
new file mode 100644
index 0000000..136ea19
--- /dev/null
+++ b/js/scripting-lang/package.json
@@ -0,0 +1,18 @@
+{
+  "name": "scripting-lang",
+  "version": "1.0.0",
+  "description": "An elm-inspired, as of yet unnamed functional scripting language.",
+  "type": "module",
+  "main": "lang.js",
+  "scripts": {
+    "start": "bun run lang.js",
+    "test": "./run_tests.sh"
+  },
+  "engines": {
+    "node": ">=14.0.0",
+    "bun": ">=1.1.0"
+  },
+  "keywords": ["language", "interpreter", "scripting"],
+  "author": "eli_oat",
+  "license": "No rulers; no kings; no masters."
+} 
\ No newline at end of file
diff --git a/js/scripting-lang/parser.js b/js/scripting-lang/parser.js
new file mode 100644
index 0000000..67b6db7
--- /dev/null
+++ b/js/scripting-lang/parser.js
@@ -0,0 +1,658 @@
+// Parser for the scripting language
+// Exports: parser(tokens)
+// Converts tokens to an Abstract Syntax Tree (AST)
+
+import { TokenType } from './lexer.js';
+
+/**
+ * Parser: Converts tokens to an Abstract Syntax Tree (AST).
+ * @param {Array.<Object>} tokens - Array of tokens from the lexer
+ * @returns {Object} Abstract Syntax Tree with program body
+ * @throws {Error} For parsing errors like unexpected tokens or missing delimiters
+ */
+export function parser(tokens) {
+    let current = 0;
+    
+    /**
+     * Main parsing function that processes the entire token stream
+     */
+    function parse() {
+        const body = [];
+        
+        while (current < tokens.length) {
+            const node = walk();
+            if (node) {
+                body.push(node);
+            }
+        }
+        
+        return { type: 'Program', body };
+    }
+    
+    /**
+     * Main walk function that dispatches to appropriate parsing functions
+     */
+    function walk() {
+        const token = tokens[current];
+        
+        if (!token) return null;
+        
+        // Handle IO operations first
+        if (token.type === TokenType.IO_IN) {
+            return parseIOIn();
+        }
+        if (token.type === TokenType.IO_OUT) {
+            return parseIOOut();
+        }
+        if (token.type === TokenType.IO_ASSERT) {
+            return parseIOAssert();
+        }
+        
+        // Handle assignments
+        if (token.type === TokenType.IDENTIFIER && 
+            current + 1 < tokens.length && 
+            tokens[current + 1].type === TokenType.ASSIGNMENT) {
+            return parseAssignment();
+        }
+        
+        // Handle when expressions
+        if (token.type === TokenType.WHEN) {
+            return parseWhenExpression();
+        }
+        
+        // Handle function definitions
+        if (token.type === TokenType.FUNCTION) {
+            return parseFunctionDefinition();
+        }
+        
+
+        
+        // For all other expressions, parse as logical expressions
+        return parseLogicalExpression();
+    }
+    
+    /**
+     * Parse assignment statements: identifier : expression;
+     */
+    function parseAssignment() {
+        const identifier = tokens[current].value;
+        current++; // Skip identifier
+        current++; // Skip assignment token (:)
+        
+        // Check if the value is a when expression
+        if (tokens[current].type === TokenType.WHEN) {
+            const value = parseWhenExpression();
+            
+            // Expect semicolon
+            if (current < tokens.length && tokens[current].type === TokenType.SEMICOLON) {
+                current++;
+            }
+            
+            return {
+                type: 'Assignment',
+                identifier,
+                value
+            };
+        } else {
+            // Check if this is an arrow function: param1 param2 -> body
+            const params = [];
+            let isArrowFunction = false;
+            
+            // Look ahead to see if this is an arrow function
+            let lookAhead = current;
+            while (lookAhead < tokens.length && tokens[lookAhead].type === TokenType.IDENTIFIER) {
+                lookAhead++;
+            }
+            
+            if (lookAhead < tokens.length && tokens[lookAhead].type === TokenType.ARROW) {
+                // This is an arrow function
+                isArrowFunction = true;
+                
+                // Parse parameters
+                while (current < tokens.length && tokens[current].type === TokenType.IDENTIFIER) {
+                    params.push(tokens[current].value);
+                    current++;
+                }
+                
+                if (current >= tokens.length || tokens[current].type !== TokenType.ARROW) {
+                    throw new Error('Expected "->" after parameters in arrow function');
+                }
+                current++; // Skip '->'
+                
+                // Check if the body is a when expression
+                let body;
+                if (tokens[current].type === TokenType.WHEN) {
+                    body = parseWhenExpression();
+                } else {
+                    body = parseLogicalExpression();
+                }
+                
+                // Expect semicolon
+                if (current < tokens.length && tokens[current].type === TokenType.SEMICOLON) {
+                    current++;
+                }
+                
+                return {
+                    type: 'Assignment',
+                    identifier,
+                    value: {
+                        type: 'FunctionDeclaration',
+                        params,
+                        body
+                    }
+                };
+            } else {
+                // Parse the value as an expression (function calls will be handled by expression parsing)
+                const value = parseLogicalExpression();
+                
+                // Expect semicolon
+                if (current < tokens.length && tokens[current].type === TokenType.SEMICOLON) {
+                    current++;
+                }
+                
+                return {
+                    type: 'Assignment',
+                    identifier,
+                    value
+                };
+            }
+        }
+    }
+    
+    /**
+     * Parse when expressions: when value is pattern then result pattern then result;
+     */
+    function parseWhenExpression() {
+        current++; // Skip 'when'
+        
+        // Parse the value(s) - can be single value or multiple values
+        const values = [];
+        while (current < tokens.length && tokens[current].type !== TokenType.IS) {
+            const value = parseLogicalExpression();
+            values.push(value);
+        }
+        
+        if (current >= tokens.length || tokens[current].type !== TokenType.IS) {
+            throw new Error('Expected "is" after value in when expression');
+        }
+        current++; // Skip 'is'
+        
+        const cases = [];
+        
+        while (current < tokens.length) {
+            // Parse pattern(s) - can be single pattern or multiple patterns
+            const patterns = [];
+            
+            // Parse patterns until we hit THEN
+            while (current < tokens.length && tokens[current].type !== TokenType.THEN) {
+                let pattern;
+                if (tokens[current].type === TokenType.IDENTIFIER) {
+                    pattern = { type: 'Identifier', value: tokens[current].value };
+                    current++;
+                } else if (tokens[current].type === TokenType.NUMBER) {
+                    pattern = { type: 'NumberLiteral', value: tokens[current].value };
+                    current++;
+                } else if (tokens[current].type === TokenType.WILDCARD) {
+                    pattern = { type: 'WildcardPattern' };
+                    current++;
+                } else {
+                    throw new Error('Expected pattern (identifier, number, or wildcard) in when expression');
+                }
+                patterns.push(pattern);
+            }
+            
+            if (current >= tokens.length || tokens[current].type !== TokenType.THEN) {
+                throw new Error('Expected "then" after pattern in when expression');
+            }
+            current++; // Skip 'then'
+            
+            // Parse result
+            const result = parseLogicalExpression();
+            
+            cases.push({
+                pattern: patterns,
+                result: [result]
+            });
+            
+            // Stop parsing cases when we hit a semicolon
+            if (current < tokens.length && tokens[current].type === TokenType.SEMICOLON) {
+                current++;
+                break;
+            } else {
+                // No semicolon, but check if next token is a valid pattern
+                if (
+                    current >= tokens.length ||
+                    (tokens[current].type !== TokenType.IDENTIFIER &&
+                     tokens[current].type !== TokenType.NUMBER &&
+                     tokens[current].type !== TokenType.WILDCARD)
+                ) {
+                    break;
+                }
+            }
+        }
+        
+        return {
+            type: 'WhenExpression',
+            value: values.length === 1 ? values[0] : values,
+            cases
+        };
+    }
+    
+    /**
+     * Parse function definitions: function (params) : body
+     */
+    function parseFunctionDefinition() {
+        current++; // Skip 'function'
+        
+        if (current >= tokens.length || tokens[current].type !== TokenType.LEFT_PAREN) {
+            throw new Error('Expected "(" after function keyword');
+        }
+        current++; // Skip '('
+        
+        const parameters = [];
+        while (current < tokens.length && tokens[current].type !== TokenType.RIGHT_PAREN) {
+            if (tokens[current].type === TokenType.IDENTIFIER) {
+                parameters.push(tokens[current].value);
+                current++;
+                
+                if (current < tokens.length && tokens[current].type === TokenType.COMMA) {
+                    current++; // Skip comma
+                }
+            } else {
+                throw new Error('Expected parameter name in function definition');
+            }
+        }
+        
+        if (current >= tokens.length || tokens[current].type !== TokenType.RIGHT_PAREN) {
+            throw new Error('Expected ")" after function parameters');
+        }
+        current++; // Skip ')'
+        
+        if (current >= tokens.length || tokens[current].type !== TokenType.ASSIGNMENT) {
+            throw new Error('Expected ":" after function parameters');
+        }
+        current++; // Skip ':'
+        
+        const body = parseLogicalExpression();
+        
+        return {
+            type: 'FunctionDefinition',
+            parameters,
+            body
+        };
+    }
+    
+    /**
+     * Parse IO input operations: ..in
+     */
+    function parseIOIn() {
+        current++; // Skip IO_IN token
+        return { type: 'IOInExpression' };
+    }
+    
+    /**
+     * Parse IO output operations: ..out expression
+     */
+    function parseIOOut() {
+        current++; // Skip IO_OUT token
+        const value = parseLogicalExpression();
+        
+        // Expect semicolon
+        if (current < tokens.length && tokens[current].type === TokenType.SEMICOLON) {
+            current++;
+        }
+        
+        return {
+            type: 'IOOutExpression',
+            value
+        };
+    }
+    
+    /**
+     * Parse IO assert operations: ..assert expression
+     */
+    function parseIOAssert() {
+        current++; // Skip IO_ASSERT token
+        const value = parseLogicalExpression();
+        
+        // Expect semicolon
+        if (current < tokens.length && tokens[current].type === TokenType.SEMICOLON) {
+            current++;
+        }
+        
+        return {
+            type: 'IOAssertExpression',
+            value
+        };
+    }
+    
+    /**
+     * Parse logical expressions with proper precedence
+     */
+    function parseLogicalExpression() {
+        let left = parseExpression();
+        
+        while (current < tokens.length) {
+            const token = tokens[current];
+            
+            if (token.type === TokenType.AND || 
+                token.type === TokenType.OR || 
+                token.type === TokenType.XOR) {
+                current++;
+                const right = parseExpression();
+                left = {
+                    type: token.type === TokenType.AND ? 'AndExpression' :
+                          token.type === TokenType.OR ? 'OrExpression' : 'XorExpression',
+                    left,
+                    right
+                };
+            } else {
+                break;
+            }
+        }
+        
+        return left;
+    }
+    
+    /**
+     * Parse comparison expressions
+     */
+    function parseExpression() {
+        let left = parseTerm();
+        
+        while (current < tokens.length) {
+            const token = tokens[current];
+            
+            if (process.env.DEBUG) {
+                console.log(`[DEBUG] parseExpression: current token = ${token.type}, value = ${token.value || 'N/A'}`);
+            }
+            
+            if (token.type === TokenType.PLUS || token.type === TokenType.MINUS) {
+                current++;
+                const right = parseTerm();
+                left = {
+                    type: token.type === TokenType.PLUS ? 'PlusExpression' : 'MinusExpression',
+                    left,
+                    right
+                };
+            } else if (token.type === TokenType.EQUALS || 
+                       token.type === TokenType.NOT_EQUAL ||
+                       token.type === TokenType.LESS_THAN ||
+                       token.type === TokenType.GREATER_THAN ||
+                       token.type === TokenType.LESS_EQUAL ||
+                       token.type === TokenType.GREATER_EQUAL) {
+                current++;
+                const right = parseTerm();
+                left = {
+                    type: token.type === TokenType.EQUALS ? 'EqualsExpression' :
+                          token.type === TokenType.NOT_EQUAL ? 'NotEqualExpression' :
+                          token.type === TokenType.LESS_THAN ? 'LessThanExpression' :
+                          token.type === TokenType.GREATER_THAN ? 'GreaterThanExpression' :
+                          token.type === TokenType.LESS_EQUAL ? 'LessEqualExpression' : 'GreaterEqualExpression',
+                    left,
+                    right
+                };
+            } else {
+                break;
+            }
+        }
+        
+        return left;
+    }
+    
+    /**
+     * Parse multiplication and division expressions
+     */
+    function parseTerm() {
+        let left = parseFactor();
+        
+        while (current < tokens.length) {
+            const token = tokens[current];
+            
+            if (token.type === TokenType.MULTIPLY || 
+                token.type === TokenType.DIVIDE || 
+                token.type === TokenType.MODULO) {
+                current++;
+                const right = parseFactor();
+                left = {
+                    type: token.type === TokenType.MULTIPLY ? 'MultiplyExpression' :
+                          token.type === TokenType.DIVIDE ? 'DivideExpression' : 'ModuloExpression',
+                    left,
+                    right
+                };
+            } else {
+                break;
+            }
+        }
+        
+        return left;
+    }
+    
+    /**
+     * Parse power expressions and unary operators
+     */
+    function parseFactor() {
+        let left = parsePrimary();
+        
+        while (current < tokens.length) {
+            const token = tokens[current];
+            
+            if (token.type === TokenType.POWER) {
+                current++;
+                const right = parsePrimary();
+                left = {
+                    type: 'PowerExpression',
+                    left,
+                    right
+                };
+            } else {
+                break;
+            }
+        }
+        
+        return left;
+    }
+    
+    /**
+     * Parse table literals: {key: value, key2: value2} or {value1, value2, value3}
+     */
+    function parseTableLiteral() {
+        current++; // Skip '{'
+        
+        const entries = [];
+        
+        while (current < tokens.length && tokens[current].type !== TokenType.RIGHT_BRACE) {
+            // Check if this is a key-value pair or just a value
+            let key = null;
+            let value;
+            
+            // Parse the first element
+            if (tokens[current].type === TokenType.IDENTIFIER) {
+                // Could be a key or a value
+                const identifier = tokens[current].value;
+                current++;
+                
+                if (current < tokens.length && tokens[current].type === TokenType.ASSIGNMENT) {
+                    // This is a key-value pair: key : value
+                    key = { type: 'Identifier', value: identifier };
+                    current++; // Skip ':'
+                    value = parseLogicalExpression();
+                } else {
+                    // This is just a value (array-like entry)
+                    value = { type: 'Identifier', value: identifier };
+                }
+            } else {
+                // This is a value (array-like entry)
+                value = parseLogicalExpression();
+            }
+            
+            entries.push({ key, value });
+            
+            // Skip comma if present
+            if (current < tokens.length && tokens[current].type === TokenType.COMMA) {
+                current++;
+            }
+        }
+        
+        if (current >= tokens.length || tokens[current].type !== TokenType.RIGHT_BRACE) {
+            throw new Error('Expected "}" after table literal');
+        }
+        current++; // Skip '}'
+        
+        return {
+            type: 'TableLiteral',
+            entries
+        };
+    }
+    
+    /**
+     * Parse function calls: functionName arg1 arg2 ...
+     */
+    function parseFunctionCall() {
+        const functionName = tokens[current].value;
+        current++; // Skip function name
+        
+        // Parse arguments until we hit a semicolon or end of tokens
+        const args = [];
+        while (current < tokens.length && tokens[current].type !== TokenType.SEMICOLON) {
+            const arg = parseLogicalExpression();
+            args.push(arg);
+        }
+        
+        return {
+            type: 'FunctionCall',
+            name: functionName,
+            args
+        };
+    }
+    
+    /**
+     * Parse primary expressions (literals, identifiers, parenthesized expressions)
+     */
+    function parsePrimary() {
+        const token = tokens[current];
+        
+        if (!token) {
+            throw new Error('Unexpected end of input');
+        }
+        
+        if (process.env.DEBUG) {
+            console.log(`[DEBUG] parsePrimary: current token = ${token.type}, value = ${token.value || 'N/A'}`);
+        }
+        
+        switch (token.type) {
+            case TokenType.NUMBER:
+                current++;
+                return { type: 'NumberLiteral', value: token.value };
+                
+            case TokenType.STRING:
+                current++;
+                return { type: 'StringLiteral', value: token.value };
+                
+            case TokenType.TRUE:
+                current++;
+                return { type: 'BooleanLiteral', value: true };
+                
+            case TokenType.FALSE:
+                current++;
+                return { type: 'BooleanLiteral', value: false };
+                
+            case TokenType.IDENTIFIER:
+                const identifierValue = token.value;
+                current++;
+                // Parse function call arguments (including parenthesized expressions)
+                const args = [];
+                while (
+                    current < tokens.length &&
+                    (
+                        tokens[current].type === TokenType.IDENTIFIER ||
+                        tokens[current].type === TokenType.NUMBER ||
+                        tokens[current].type === TokenType.STRING ||
+                        tokens[current].type === TokenType.LEFT_PAREN ||
+                        tokens[current].type === TokenType.LEFT_BRACE ||
+                        tokens[current].type === TokenType.TRUE ||
+                        tokens[current].type === TokenType.FALSE
+                    )
+                ) {
+                    args.push(parseLogicalExpression());
+                }
+                if (args.length > 0) {
+                    return {
+                        type: 'FunctionCall',
+                        name: identifierValue,
+                        args
+                    };
+                }
+                return { type: 'Identifier', value: identifierValue };
+
+            case TokenType.LEFT_PAREN:
+                current++;
+                if (process.env.DEBUG) {
+                    console.log(`[DEBUG] parsePrimary: parsing LEFT_PAREN, current token = ${tokens[current].type}`);
+                }
+                const expression = parseLogicalExpression();
+                if (current >= tokens.length || tokens[current].type !== TokenType.RIGHT_PAREN) {
+                    throw new Error('Expected ")" after expression');
+                }
+                current++;
+                // After a parenthesized expression, check if it's an argument to a function call
+                // (e.g., add (double 3) (square 2))
+                const callArgs = [];
+                while (
+                    current < tokens.length &&
+                    (
+                        tokens[current].type === TokenType.IDENTIFIER ||
+                        tokens[current].type === TokenType.NUMBER ||
+                        tokens[current].type === TokenType.STRING ||
+                        tokens[current].type === TokenType.LEFT_PAREN ||
+                        tokens[current].type === TokenType.LEFT_BRACE ||
+                        tokens[current].type === TokenType.TRUE ||
+                        tokens[current].type === TokenType.FALSE
+                    )
+                ) {
+                    callArgs.push(parseLogicalExpression());
+                }
+                if (callArgs.length > 0) {
+                    // This is a function call where the function is the parenthesized expression
+                    return {
+                        type: 'FunctionCall',
+                        name: expression,
+                        args: callArgs
+                    };
+                }
+                return expression;
+
+            case TokenType.WILDCARD:
+                current++;
+                return { type: 'WildcardPattern' };
+                
+            case TokenType.LEFT_BRACE:
+                return parseTableLiteral();
+                
+            case TokenType.NOT:
+                current++;
+                const operand = parsePrimary();
+                return { type: 'NotExpression', operand };
+                
+            case TokenType.MINUS:
+                current++;
+                const unaryOperand = parsePrimary();
+                return { type: 'UnaryMinusExpression', operand: unaryOperand };
+                
+            case TokenType.ARROW:
+                current++;
+                const arrowBody = parseLogicalExpression();
+                return { type: 'ArrowExpression', body: arrowBody };
+                
+            case TokenType.FUNCTION_REF:
+                const functionRef = { type: 'FunctionReference', name: token.name };
+                current++;
+                return functionRef;
+                
+            default:
+                throw new Error(`Unexpected token in parsePrimary: ${token.type}`);
+        }
+    }
+    
+    return parse();
+} 
\ No newline at end of file
diff --git a/js/scripting-lang/simple_test.txt b/js/scripting-lang/simple_test.txt
new file mode 100644
index 0000000..74edad2
--- /dev/null
+++ b/js/scripting-lang/simple_test.txt
@@ -0,0 +1,9 @@
+/* Simple test for function call parsing */
+
+factorial : n ->
+  when n is
+    0 then 1
+    _ then n * (factorial (n - 1));
+
+result : factorial 5;
+..out result;
\ No newline at end of file
diff --git a/js/scripting-lang/table_basic_test.txt b/js/scripting-lang/table_basic_test.txt
deleted file mode 100644
index 172d95c..0000000
--- a/js/scripting-lang/table_basic_test.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-/* Basic Table Tests */
-
-/* Test 1: Simple table creation */
-..out "=== Basic Table Tests ===";
-empty : {};
-numbers : {1, 2, 3};
-person : {name: "Alice", age: 30};
-
-..out "Empty table: ";
-..out empty;
-..out "Numbers: ";
-..out numbers;
-..out "Person: ";
-..out person;
-
-/* Test 2: Array access */
-first : numbers[1];
-second : numbers[2];
-third : numbers[3];
-
-..out "First: ";
-..out first;
-..out "Second: ";
-..out second;
-..out "Third: ";
-..out third;
-
-/* Test 3: Object access */
-name : person.name;
-age : person.age;
-
-..out "Name: ";
-..out name;
-..out "Age: ";
-..out age;
-
-/* Test 4: Mixed table */
-mixed : {1, name: "Bob", 2};
-
-first_mixed : mixed[1];
-name_mixed : mixed.name;
-second_mixed : mixed[2];
-
-..out "Mixed first: ";
-..out first_mixed;
-..out "Mixed name: ";
-..out name_mixed;
-..out "Mixed second: ";
-..out second_mixed;
-
-..out "Basic tests complete!"; 
\ No newline at end of file
diff --git a/js/scripting-lang/table_edge_cases_test.txt b/js/scripting-lang/table_edge_cases_test.txt
deleted file mode 100644
index 268f271..0000000
--- a/js/scripting-lang/table_edge_cases_test.txt
+++ /dev/null
@@ -1,304 +0,0 @@
-/* Table Edge Cases Tests */
-
-/* Test 1: Nested tables */
-..out "=== Test 1: Nested Tables ===";
-nested : {
-    outer: "value",
-    inner: {
-        deep: "nested",
-        numbers: {1, 2, 3}
-    }
-};
-
-outer_val : nested.outer;
-inner_table : nested.inner;
-deep_val : nested.inner.deep;
-inner_nums : nested.inner.numbers;
-first_num : nested.inner.numbers[1];
-
-..out "Outer: ";
-..out outer_val;
-..out "Inner table: ";
-..out inner_table;
-..out "Deep: ";
-..out deep_val;
-..out "Inner numbers: ";
-..out inner_nums;
-..out "First number: ";
-..out first_num;
-
-/* Test 2: Tables with different value types */
-..out "=== Test 2: Different Value Types ===";
-complex : {
-    number: 42,
-    string: "hello",
-    boolean: true,
-    array: {1, 2, 3},
-    object: {key: "value"}
-};
-
-num : complex.number;
-str : complex.string;
-bool : complex.boolean;
-arr : complex.array;
-obj : complex.object;
-
-..out "Number: ";
-..out num;
-..out "String: ";
-..out str;
-..out "Boolean: ";
-..out bool;
-..out "Array: ";
-..out arr;
-..out "Object: ";
-..out obj;
-
-/* Test 3: Tables with function references */
-..out "=== Test 3: Function References ===";
-double : x -> x * 2;
-square : x -> x * x;
-
-func_table : {
-    double_func: @double,
-    square_func: @square,
-    number: 5
-};
-
-double_ref : func_table.double_func;
-square_ref : func_table.square_func;
-table_num : func_table.number;
-
-..out "Double ref: ";
-..out double_ref;
-..out "Square ref: ";
-..out square_ref;
-..out "Table number: ";
-..out table_num;
-
-/* Test 4: Tables with arithmetic expressions */
-..out "=== Test 4: Arithmetic Expressions ===";
-math_table : {
-    sum: 5 + 3,
-    product: 4 * 6,
-    power: 2 ^ 3
-};
-
-sum_val : math_table.sum;
-prod_val : math_table.product;
-pow_val : math_table.power;
-
-..out "Sum: ";
-..out sum_val;
-..out "Product: ";
-..out prod_val;
-..out "Power: ";
-..out pow_val;
-
-/* Test 5: Tables with function calls */
-..out "=== Test 5: Function Calls ===";
-add : x y -> x + y;
-multiply : x y -> x * y;
-
-call_table : {
-    addition: add 3 4,
-    multiplication: multiply 5 6
-};
-
-add_result : call_table.addition;
-mult_result : call_table.multiplication;
-
-..out "Addition: ";
-..out add_result;
-..out "Multiplication: ";
-..out mult_result;
-
-/* Test 6: Tables with bracket notation access */
-..out "=== Test 6: Bracket Notation ===";
-bracket_test : {name: "John", age: 25};
-
-name_bracket : bracket_test["name"];
-age_bracket : bracket_test["age"];
-
-..out "Name (bracket): ";
-..out name_bracket;
-..out "Age (bracket): ";
-..out age_bracket;
-
-/* Test 7: Tables with string keys */
-..out "=== Test 7: String Keys ===";
-string_keys : {
-    "key1": "value1",
-    "key2": "value2"
-};
-
-val1 : string_keys.key1;
-val2 : string_keys["key2"];
-
-..out "Value 1: ";
-..out val1;
-..out "Value 2: ";
-..out val2;
-
-/* Test 8: Tables with numeric keys */
-..out "=== Test 8: Numeric Keys ===";
-numeric_keys : {
-    1: "one",
-    2: "two",
-    10: "ten"
-};
-
-one : numeric_keys[1];
-two : numeric_keys[2];
-ten : numeric_keys[10];
-
-..out "One: ";
-..out one;
-..out "Two: ";
-..out two;
-..out "Ten: ";
-..out ten;
-
-/* Test 9: Tables with boolean keys */
-..out "=== Test 9: Boolean Keys ===";
-bool_keys : {
-    true: "truth",
-    false: "falsehood"
-};
-
-truth : bool_keys[true];
-falsehood : bool_keys[false];
-
-..out "Truth: ";
-..out truth;
-..out "Falsehood: ";
-..out falsehood;
-
-/* Test 10: Tables with trailing commas */
-..out "=== Test 10: Trailing Commas ===";
-trailing : {
-    1,
-    2,
-    3,
-    key: "value",
-};
-
-first : trailing[1];
-second : trailing[2];
-third : trailing[3];
-key_val : trailing.key;
-
-..out "First: ";
-..out first;
-..out "Second: ";
-..out second;
-..out "Third: ";
-..out third;
-..out "Key: ";
-..out key_val;
-
-/* Test 11: Tables with leading commas */
-..out "=== Test 11: Leading Commas ===";
-leading : {
-    ,1,
-    ,2,
-    ,key: "value"
-};
-
-first_lead : leading[1];
-second_lead : leading[2];
-key_lead : leading.key;
-
-..out "First (leading): ";
-..out first_lead;
-..out "Second (leading): ";
-..out second_lead;
-..out "Key (leading): ";
-..out key_lead;
-
-/* Test 12: Tables with function definitions inside */
-..out "=== Test 12: Function Definitions Inside ===";
-func_def_table : {
-    add_func: x y -> x + y,
-    double_func: x -> x * 2,
-    name: "function_table"
-};
-
-add_func_ref : func_def_table.add_func;
-double_func_ref : func_def_table.double_func;
-func_name : func_def_table.name;
-
-..out "Add func ref: ";
-..out add_func_ref;
-..out "Double func ref: ";
-..out double_func_ref;
-..out "Func name: ";
-..out func_name;
-
-/* Test 13: Tables with case expressions inside */
-..out "=== Test 13: Case Expressions Inside ===";
-case_table : {
-    grade_func: score -> 
-        case score of
-            90 : "A"
-            80 : "B"
-            70 : "C"
-            _  : "F",
-    name: "case_table"
-};
-
-grade_func_ref : case_table.grade_func;
-case_name : case_table.name;
-
-..out "Grade func ref: ";
-..out grade_func_ref;
-..out "Case name: ";
-..out case_name;
-
-/* Test 14: Tables with standard library functions */
-..out "=== Test 14: Standard Library Functions ===";
-stdlib_table : {
-    map_func: @map,
-    compose_func: @compose,
-    pipe_func: @pipe,
-    name: "stdlib_table"
-};
-
-map_ref : stdlib_table.map_func;
-compose_ref : stdlib_table.compose_func;
-pipe_ref : stdlib_table.pipe_func;
-stdlib_name : stdlib_table.name;
-
-..out "Map ref: ";
-..out map_ref;
-..out "Compose ref: ";
-..out compose_ref;
-..out "Pipe ref: ";
-..out pipe_ref;
-..out "Stdlib name: ";
-..out stdlib_name;
-
-/* Test 15: Tables with IO operations */
-..out "=== Test 15: IO Operations ===";
-io_table : {
-    input_func: @..in,
-    output_func: @..out,
-    assert_func: @..assert,
-    name: "io_table"
-};
-
-input_ref : io_table.input_func;
-output_ref : io_table.output_func;
-assert_ref : io_table.assert_func;
-io_name : io_table.name;
-
-..out "Input ref: ";
-..out input_ref;
-..out "Output ref: ";
-..out output_ref;
-..out "Assert ref: ";
-..out assert_ref;
-..out "IO name: ";
-..out io_name;
-
-..out "Edge cases tests complete!"; 
\ No newline at end of file
diff --git a/js/scripting-lang/test.txt b/js/scripting-lang/test.txt
deleted file mode 100644
index 79555b0..0000000
--- a/js/scripting-lang/test.txt
+++ /dev/null
@@ -1,730 +0,0 @@
-/* ========================================
-   COMPREHENSIVE LANGUAGE TEST SUITE
-   ======================================== */
-
-..out "=== COMPREHENSIVE LANGUAGE TEST SUITE ===";
-..out "";
-
-/* ========================================
-   SECTION 1: BASIC ARITHMETIC OPERATIONS
-   ======================================== */
-
-..out "1. BASIC ARITHMETIC OPERATIONS:";
-
-/* Basic arithmetic */
-a : 10;
-b : 3;
-sum : a + b;
-diff : a - b;
-product : a * b;
-quotient : a / b;
-modulo : a % b;
-power : a ^ b;
-
-/* Assert basic arithmetic operations */
-..assert sum = 13;
-..assert diff = 7;
-..assert product = 30;
-..assert quotient = 3.3333333333333335;
-..assert modulo = 1;
-..assert power = 1000;
-
-..out "  Basic arithmetic operations verified";
-
-/* Complex arithmetic with parentheses */
-complex1 : (5 + 3) * 2;
-complex2 : ((10 - 2) * 3) + 1;
-complex3 : (2 ^ 3) % 5;
-complex4 : (15 / 3) + (7 % 4);
-
-/* Assert complex expressions */
-..assert complex1 = 16;
-..assert complex2 = 25;
-..assert complex3 = 3;
-..assert complex4 = 8;
-
-..out "  Complex arithmetic expressions verified";
-
-/* Edge cases for arithmetic */
-zero : 0;
-one : 1;
-large : 999999;
-
-zero_sum : zero + zero;
-zero_product : zero * large;
-power_zero : large ^ zero;
-power_one : large ^ one;
-modulo_zero : large % one;
-
-/* Assert arithmetic edge cases */
-..assert zero_sum = 0;
-..assert zero_product = 0;
-..assert power_zero = 1;
-..assert power_one = 999999;
-..assert modulo_zero = 0;
-
-..out "  Arithmetic edge cases verified";
-
-..out "";
-
-/* ========================================
-   SECTION 2: COMPARISON OPERATORS
-   ======================================== */
-
-..out "2. COMPARISON OPERATORS:";
-
-/* Basic comparisons */
-less : 3 < 5;
-greater : 10 > 5;
-equal : 5 = 5;
-not_equal : 3 != 5;
-less_equal : 5 <= 5;
-greater_equal : 5 >= 3;
-
-/* Assert basic comparisons */
-..assert less = true;
-..assert greater = true;
-..assert equal = true;
-..assert not_equal = true;
-..assert less_equal = true;
-..assert greater_equal = true;
-
-..out "  Basic comparison operators verified";
-
-/* Comparison edge cases */
-zero_less : 0 < 1;
-zero_equal : 0 = 0;
-zero_greater : 0 > -1;
-same_less : 5 < 5;
-same_greater : 5 > 5;
-
-/* Assert comparison edge cases */
-..assert zero_less = true;
-..assert zero_equal = true;
-..assert zero_greater = true;
-..assert same_less = false;
-..assert same_greater = false;
-
-..out "  Comparison edge cases verified";
-
-..out "";
-
-/* ========================================
-   SECTION 3: LOGICAL OPERATORS
-   ======================================== */
-
-..out "3. LOGICAL OPERATORS:";
-
-/* Basic logical operations */
-and_true : 1 and 1;
-and_false : 1 and 0;
-or_true : 0 or 1;
-or_false : 0 or 0;
-xor_true : 1 xor 0;
-xor_false : 1 xor 1;
-not_true : not 0;
-not_false : not 1;
-
-/* Assert basic logical operations */
-..assert and_true = true;
-..assert and_false = false;
-..assert or_true = true;
-..assert or_false = false;
-..assert xor_true = true;
-..assert xor_false = false;
-..assert not_true = true;
-..assert not_false = false;
-
-..out "  Basic logical operations verified";
-
-/* Complex logical expressions */
-complex_and : (5 > 3) and (10 < 20);
-complex_or : (5 < 3) or (10 > 5);
-complex_xor : (5 = 5) xor (3 = 4);
-complex_not : not (5 < 3);
-
-/* Assert complex logical expressions */
-..assert complex_and = true;
-..assert complex_or = true;
-..assert complex_xor = true;
-..assert complex_not = true;
-
-..out "  Complex logical expressions verified";
-
-..out "";
-
-/* ========================================
-   SECTION 4: VARIABLE ASSIGNMENT
-   ======================================== */
-
-..out "4. VARIABLE ASSIGNMENT:";
-
-/* Basic variable assignment */
-simple_var : 42;
-string_var : "Hello, World!";
-bool_true : true;
-bool_false : false;
-
-/* Assert basic variables */
-..assert simple_var = 42;
-..assert string_var = "Hello, World!";
-..assert bool_true = true;
-..assert bool_false = false;
-
-..out "  Basic variable assignment verified";
-
-/* Expression assignment */
-expr_var : 5 + 3 * 2;
-complex_var : (10 - 2) ^ 2;
-
-/* Assert expression variables */
-..assert expr_var = 11;
-..assert complex_var = 64;
-
-..out "  Expression variable assignment verified";
-
-..out "";
-
-/* ========================================
-   SECTION 5: FUNCTION DEFINITIONS
-   ======================================== */
-
-..out "5. FUNCTION DEFINITIONS:";
-
-/* Basic function definitions */
-add : x y -> x + y;
-multiply : x y -> x * y;
-double : x -> x * 2;
-square : x -> x * x;
-identity : x -> x;
-
-/* Function calls */
-add_result : add 3 4;
-multiply_result : multiply 5 6;
-double_result : double 8;
-square_result : square 4;
-identity_result : identity 42;
-
-/* Assert function calls */
-..assert add_result = 7;
-..assert multiply_result = 30;
-..assert double_result = 16;
-..assert square_result = 16;
-..assert identity_result = 42;
-
-..out "  Basic function definitions and calls verified";
-
-/* Function calls with complex expressions */
-complex_add : add (3 + 2) (4 + 1);
-complex_multiply : multiply (double 3) (square 2);
-nested_calls : add (add 1 2) (add 3 4);
-
-/* Assert complex function calls */
-..assert complex_add = 15;
-..assert complex_multiply = 48;
-..assert nested_calls = 10;
-
-..out "  Complex function calls verified";
-
-..out "";
-
-/* ========================================
-   SECTION 6: PATTERN MATCHING
-   ======================================== */
-
-..out "6. PATTERN MATCHING:";
-
-/* Single parameter case expressions */
-factorial : n -> 
-  case n of
-    0 : 1
-    _ : n * (factorial (n - 1));
-
-grade : score -> 
-  case score of
-    90 : "A"
-    80 : "B"
-    70 : "C"
-    _  : "F";
-
-/* Two parameter case expressions */
-compare : x y -> 
-  case x y of
-    0 0 : "both zero"
-    0 _ : "x is zero"
-    _ 0 : "y is zero"
-    _ _ : "neither zero";
-
-/* Testing pattern matching */
-fact5 : factorial 5;
-fact3 : factorial 3;
-gradeA : grade 95;
-gradeB : grade 85;
-gradeF : grade 65;
-
-compare1 : compare 0 0;
-compare2 : compare 0 5;
-compare3 : compare 5 0;
-compare4 : compare 5 5;
-
-/* Assert pattern matching results */
-..assert fact5 = 120;
-..assert fact3 = 6;
-..assert gradeA = "A";
-..assert gradeB = "B";
-..assert gradeF = "F";
-
-..assert compare1 = "both zero";
-..assert compare2 = "x is zero";
-..assert compare3 = "y is zero";
-..assert compare4 = "neither zero";
-
-..out "  Pattern matching verified";
-
-..out "";
-
-/* ========================================
-   SECTION 7: TABLES
-   ======================================== */
-
-..out "7. TABLES:";
-
-/* Empty table */
-empty : {};
-
-/* Array-like table */
-numbers : {1, 2, 3, 4, 5};
-
-/* Key-value table */
-person : {name: "Alice", age: 30, active: true};
-
-/* Mixed table */
-mixed : {1, name: "Bob", 2, active: false};
-
-/* Nested table */
-nested : {outer: {inner: "value"}};
-
-/* Table access - array style */
-first : numbers[1];
-second : numbers[2];
-last : numbers[5];
-
-/* Table access - object style */
-name : person.name;
-age : person.age;
-active : person.active;
-
-/* Table access - mixed style */
-mixed_first : mixed[1];
-mixed_name : mixed.name;
-mixed_second : mixed[2];
-
-/* Table access - nested */
-nested_value : nested.outer.inner;
-
-/* Assert table access */
-..assert first = 1;
-..assert second = 2;
-..assert last = 5;
-
-..assert name = "Alice";
-..assert age = 30;
-..assert active = true;
-
-..assert mixed_first = 1;
-..assert mixed_name = "Bob";
-..assert mixed_second = 2;
-
-..assert nested_value = "value";
-
-..out "  Table creation and access verified";
-
-/* Table edge cases */
-table_with_arithmetic : {sum: 5 + 3, product: 4 * 6};
-table_with_functions : {double: @double, square: @square};
-
-/* Assert table edge cases */
-..assert table_with_arithmetic.sum = 8;
-..assert table_with_arithmetic.product = 24;
-
-..out "  Table edge cases verified";
-
-..out "";
-
-/* ========================================
-   SECTION 8: FIRST-CLASS FUNCTIONS
-   ======================================== */
-
-..out "8. FIRST-CLASS FUNCTIONS:";
-
-/* Function references */
-double_ref : @double;
-square_ref : @square;
-add_ref : @add;
-
-/* Function composition using standard library */
-composed : compose @double @square 3;
-piped : pipe @double @square 2;
-applied : apply @double 5;
-
-/* Assert function composition */
-..assert composed = 18;
-..assert piped = 16;
-..assert applied = 10;
-
-..out "  Function composition verified";
-
-/* Function references in case expressions */
-getFunction : type -> 
-  case type of
-    "double" : @double
-    "square" : @square
-    _        : @add;
-
-func1 : getFunction "double";
-func2 : getFunction "square";
-func3 : getFunction "unknown";
-
-/* Test function references by calling them */
-test_func1 : func1 5;
-test_func2 : func2 3;
-test_func3 : func3 2 3;
-
-/* Assert function references work */
-..assert test_func1 = 10;
-..assert test_func2 = 9;
-..assert test_func3 = 5;
-
-..out "  Function references from case expressions verified";
-
-..out "";
-
-/* ========================================
-   SECTION 9: STANDARD LIBRARY
-   ======================================== */
-
-..out "9. STANDARD LIBRARY:";
-
-/* Map function */
-mapped1 : map @double 5;
-mapped2 : map @square 3;
-
-/* Filter function */
-isPositive : x -> x > 0;
-isEven : x -> x % 2 = 0;
-
-filtered1 : filter @isPositive 5;
-filtered2 : filter @isPositive -3;
-filtered3 : filter @isEven 4;
-filtered4 : filter @isEven 3;
-
-/* Reduce and Fold functions */
-reduced1 : reduce @add 0 5;
-reduced2 : reduce @multiply 1 3;
-folded1 : fold @add 0 5;
-folded2 : fold @multiply 1 3;
-
-/* Curry function */
-curried1 : curry @add 3 4;
-curried2 : curry @multiply 2 5;
-
-/* Assert standard library functions */
-..assert mapped1 = 10;
-..assert mapped2 = 9;
-
-..assert filtered1 = 5;
-..assert filtered2 = 0;
-..assert filtered3 = 4;
-..assert filtered4 = 0;
-
-..assert reduced1 = 5;
-..assert reduced2 = 3;
-..assert folded1 = 5;
-..assert folded2 = 3;
-
-..assert curried1 = 7;
-..assert curried2 = 10;
-
-..out "  Standard library functions verified";
-
-..out "";
-
-/* ========================================
-   SECTION 10: COMMENTS
-   ======================================== */
-
-..out "10. COMMENTS:";
-
-/* Single line comment */
-x : 5; /* This is a single line comment */
-
-/* Multi-line comment */
-/* This is a multi-line comment
-   that spans multiple lines
-   and should be ignored */
-
-/* Nested comments */
-/* Outer comment /* Inner comment */ More outer comment */
-
-/* Comment with code on same line */
-y : 10; /* Comment on same line */
-
-/* Assert comments are ignored */
-..assert x = 5;
-..assert y = 10;
-
-..out "  Comments work correctly - all ignored by parser";
-
-..out "";
-
-/* ========================================
-   SECTION 11: EDGE CASES AND STRESS TESTS
-   ======================================== */
-
-..out "11. EDGE CASES AND STRESS TESTS:";
-
-/* Deep nesting */
-deep_nest1 : ((((5 + 3) * 2) - 1) / 3) + 1;
-deep_nest2 : (2 ^ (3 ^ 2)) % 10;
-
-/* Complex function chains */
-complex_chain : add (multiply (double 3) (square 2)) (add 1 2);
-
-/* Multiple assignments */
-var1 : 1;
-var2 : 2;
-var3 : 3;
-var4 : 4;
-var5 : 5;
-
-sum_all : add (add (add var1 var2) (add var3 var4)) var5;
-
-/* Table with complex values */
-complex_table : {
-    arithmetic: 5 + 3 * 2,
-    function_call: double 4,
-    nested: {inner: square 3},
-    boolean: 5 > 3 and 10 < 20
-};
-
-/* Assert edge cases */
-..assert deep_nest1 = 6;
-..assert deep_nest2 = 2;
-..assert complex_chain = 27;
-..assert sum_all = 15;
-
-..assert complex_table.arithmetic = 11;
-..assert complex_table.function_call = 8;
-..assert complex_table.nested.inner = 9;
-..assert complex_table.boolean = true;
-
-..out "  Edge cases and stress tests verified";
-
-/* Recursive function stress test */
-countdown : n -> 
-  case n of
-    0 : "done"
-    _ : countdown (n - 1);
-
-count_result : countdown 3;
-
-/* Assert recursive function */
-..assert count_result = "done";
-
-..out "  Recursive function stress test verified";
-
-..out "";
-
-/* ========================================
-   SECTION 12: ASSERTIONS
-   ======================================== */
-
-..out "12. ASSERTIONS:";
-
-/* Basic assertions */
-..assert 5 = 5;
-..assert 3 < 5;
-..assert 10 > 5;
-..assert 5 <= 5;
-..assert 5 >= 3;
-..assert 3 != 5;
-
-/* Complex assertions */
-..assert (5 + 3) = 8;
-..assert (10 - 2) > 5;
-..assert (2 ^ 3) = 8;
-..assert (15 / 3) = 5;
-
-/* Function call assertions */
-..assert (add 3 4) = 7;
-..assert (double 5) = 10;
-..assert (square 3) = 9;
-
-/* Logical assertions */
-..assert 1 and 1;
-..assert 0 or 1;
-..assert 1 xor 0;
-..assert not 0;
-
-/* String assertions */
-..assert "hello" = "hello";
-..assert "world" != "hello";
-
-/* Table assertions */
-..assert numbers[1] = 1;
-..assert person.name = "Alice";
-..assert mixed[1] = 1;
-
-/* Function reference assertions */
-..assert (func1 4) = 8;
-..assert (func2 5) = 25;
-
-..out "  All assertions passed successfully!";
-
-..out "";
-
-/* ========================================
-   SECTION 13: COMPREHENSIVE INTEGRATION TEST
-   ======================================== */
-
-..out "13. COMPREHENSIVE INTEGRATION TEST:";
-
-/* Create a complex data structure */
-calculator : {
-    add: @add,
-    multiply: @multiply,
-    double: @double,
-    square: @square,
-    operations: {
-        arithmetic: {plus: "+", minus: "-", times: "*"},
-        logical: {and: "and", or: "or", not: "not"}
-    },
-    constants: {pi: 3.14159, e: 2.71828}
-};
-
-/* Use the data structure */
-calc_add : calculator.add 5 3;
-calc_mult : calculator.multiply 4 6;
-calc_double : calculator.double 7;
-calc_square : calculator.square 5;
-
-/* Complex expression using everything */
-final_result : add (calculator.double (calculator.square 3)) (calculator.multiply 2 4);
-
-/* Assert integration test results */
-..assert calc_add = 8;
-..assert calc_mult = 24;
-..assert calc_double = 14;
-..assert calc_square = 25;
-..assert final_result = 26;
-
-/* Assert nested table access */
-..assert calculator.operations.arithmetic.plus = "+";
-..assert calculator.operations.logical.and = "and";
-..assert calculator.constants.pi = 3.14159;
-
-..out "  Integration test results verified";
-
-/* Pattern matching with complex data */
-classify_number : num -> 
-  case num of
-    0 : "zero"
-    _ : case num % 2 of
-        0 : "even"
-        _ : "odd";
-
-classify1 : classify_number 0;
-classify2 : classify_number 4;
-classify3 : classify_number 7;
-
-/* Assert number classification */
-..assert classify1 = "zero";
-..assert classify2 = "even";
-..assert classify3 = "odd";
-
-..out "  Number classification verified";
-
-..out "";
-
-/* ========================================
-   SECTION 14: ERROR HANDLING AND EDGE CASES
-   ======================================== */
-
-..out "14. ERROR HANDLING AND EDGE CASES:";
-
-/* Test division by zero handling */
-/* Note: This would normally throw an error, but we'll test the assertion system */
-
-/* Test table access edge cases */
-empty_table : {};
-/* Note: Accessing non-existent keys would throw an error */
-
-/* Test function call edge cases */
-/* Note: Calling non-existent functions would throw an error */
-
-/* Test immutable variable reassignment */
-test_var : 42;
-/* Note: Attempting to reassign would throw an error */
-
-..out "  Error handling edge cases noted";
-
-..out "";
-
-/* ========================================
-   SECTION 15: PERFORMANCE AND SCALE TESTS
-   ======================================== */
-
-..out "15. PERFORMANCE AND SCALE TESTS:";
-
-/* Test large arithmetic expressions */
-large_expr : (((((1 + 2) * 3) + 4) * 5) + 6) * 7;
-..assert large_expr = 287;
-
-/* Test nested function calls */
-nested_func : add (add (add 1 2) (add 3 4)) (add (add 5 6) (add 7 8));
-..assert nested_func = 36;
-
-/* Test complex table structures */
-complex_nested_table : {
-    level1: {
-        level2: {
-            level3: {
-                value: 42,
-                computed: 5 + 3 * 2
-            }
-        }
-    }
-};
-
-..assert complex_nested_table.level1.level2.level3.value = 42;
-..assert complex_nested_table.level1.level2.level3.computed = 11;
-
-..out "  Performance and scale tests verified";
-
-..out "";
-
-/* ========================================
-   FINAL SUMMARY
-   ======================================== */
-
-..out "=== TEST SUITE COMPLETED SUCCESSFULLY ===";
-..out "";
-..out "All language features tested and verified:";
-..out "  Arithmetic operations (+, -, *, /, %, ^)";
-..out "  Comparison operators (=, <, >, <=, >=, !=)";
-..out "  Logical operators (and, or, xor, not)";
-..out "  Variable assignment";
-..out "  Function definitions and calls";
-..out "  Pattern matching with case expressions";
-..out "  Tables (arrays and objects)";
-..out "  First-class functions and composition";
-..out "  Standard library functions";
-..out "  Comments (single-line, multi-line, nested)";
-..out "  Input/Output operations";
-..out "  Assertions";
-..out "  Edge cases and stress tests";
-..out "  Complex integration scenarios";
-..out "  Error handling edge cases";
-..out "  Performance and scale tests";
-..out "";
-..out "Language implementation is fully functional and verified!"; 
\ No newline at end of file
diff --git a/js/scripting-lang/tests/01_lexer_basic.txt b/js/scripting-lang/tests/01_lexer_basic.txt
index bdf7397..90693f1 100644
--- a/js/scripting-lang/tests/01_lexer_basic.txt
+++ b/js/scripting-lang/tests/01_lexer_basic.txt
@@ -18,8 +18,8 @@ prod : x * y;
 quot : x / y;
 
 /* Test keywords */
-result : case x of
-    42 : "correct"
-    _ : "wrong";
+result : when x is
+    42 then "correct"
+    _  then "wrong";
 
 ..out "Lexer basic test completed"; 
\ No newline at end of file
diff --git a/js/scripting-lang/tests/07_case_expressions.txt b/js/scripting-lang/tests/07_case_expressions.txt
index 82d458c..83bd1bb 100644
--- a/js/scripting-lang/tests/07_case_expressions.txt
+++ b/js/scripting-lang/tests/07_case_expressions.txt
@@ -3,16 +3,16 @@
 
 /* Basic case expressions */
 factorial : n -> 
-  case n of
-    0 : 1
-    _ : n * (factorial (n - 1));
+  when n is
+    0 then 1
+    _ then n * (factorial (n - 1));
 
 grade : score -> 
-  case score of
-    90 : "A"
-    80 : "B"
-    70 : "C"
-    _  : "F";
+  when score is
+    90 then "A"
+    80 then "B"
+    70 then "C"
+    _  then "F";
 
 /* Test case expressions */
 fact5 : factorial 5;
@@ -28,11 +28,11 @@ grade3 : grade 65;
 
 /* Multi-parameter case expressions */
 compare : x y -> 
-  case x y of
-    0 0 : "both zero"
-    0 _ : "x is zero"
-    _ 0 : "y is zero"
-    _ _ : "neither zero";
+  when x y is
+    0 0 then "both zero"
+    0 _ then "x is zero"
+    _ 0 then "y is zero"
+    _ _ then "neither zero";
 
 test1 : compare 0 0;
 test2 : compare 0 5;
diff --git a/js/scripting-lang/tests/08_first_class_functions.txt b/js/scripting-lang/tests/08_first_class_functions.txt
index f228ccd..75fda40 100644
--- a/js/scripting-lang/tests/08_first_class_functions.txt
+++ b/js/scripting-lang/tests/08_first_class_functions.txt
@@ -31,10 +31,10 @@ applied : apply @double 7;
 
 /* Function references in case expressions */
 getFunction : type -> 
-  case type of
-    "double" : @double
-    "square" : @square
-    _        : @add1;
+  when type is
+    "double" then @double
+    "square" then @square
+    _        then @add1;
 
 func1 : getFunction "double";
 func2 : getFunction "square";
diff --git a/js/scripting-lang/tests/11_edge_cases.txt b/js/scripting-lang/tests/11_edge_cases.txt
index ceb39b4..dce90e3 100644
--- a/js/scripting-lang/tests/11_edge_cases.txt
+++ b/js/scripting-lang/tests/11_edge_cases.txt
@@ -20,9 +20,9 @@ complex_negative3 : -5 + 3;
 ..assert complex_negative3 = -2;
 
 /* Test unary minus in function calls */
-abs : x -> case x of
-    x < 0 : -x
-    _ : x;
+abs : x -> when x is
+    x < 0 then -x
+    _ then x;
 
 abs1 : abs -5;
 abs2 : abs 5;
diff --git a/js/scripting-lang/tests/14_error_handling.txt b/js/scripting-lang/tests/14_error_handling.txt
index ce485f7..36fa9de 100644
--- a/js/scripting-lang/tests/14_error_handling.txt
+++ b/js/scripting-lang/tests/14_error_handling.txt
@@ -7,9 +7,9 @@ valid_test : 5 + 3;
 
 /* Test division by zero handling */
 /* This should be handled gracefully */
-safe_div : x y -> case y of
-    0 : "division by zero"
-    _ : x / y;
+safe_div : x y -> when y is
+    0 then "division by zero"
+    _ then x / y;
 
 div_result1 : safe_div 10 2;
 div_result2 : safe_div 10 0;
@@ -18,28 +18,28 @@ div_result2 : safe_div 10 0;
 ..assert div_result2 = "division by zero";
 
 /* Test edge cases with proper handling */
-edge_case1 : case 0 of
-    0 : "zero"
-    _ : "other";
+edge_case1 : when 0 is
+    0 then "zero"
+    _ then "other";
 
-edge_case2 : case "" of
-    "" : "empty string"
-    _ : "other";
+edge_case2 : when "" is
+    "" then "empty string"
+    _  then "other";
 
-edge_case3 : case false of
-    false : "false"
-    _ : "other";
+edge_case3 : when false is
+    false then "false"
+    _     then "other";
 
 ..assert edge_case1 = "zero";
 ..assert edge_case2 = "empty string";
 ..assert edge_case3 = "false";
 
 /* Test complex error scenarios */
-complex_error_handling : input -> case input of
-    input < 0 : "negative"
-    input = 0 : "zero"
-    input > 100 : "too large"
-    _ : "valid";
+complex_error_handling : input -> when input is
+    input < 0 then "negative"
+    input = 0 then "zero"
+    input > 100 then "too large"
+    _ then "valid";
 
 complex_result1 : complex_error_handling -5;
 complex_result2 : complex_error_handling 0;
@@ -52,9 +52,9 @@ complex_result4 : complex_error_handling 50;
 ..assert complex_result4 = "valid";
 
 /* Test safe arithmetic operations */
-safe_add : x y -> case y of
-    0 : x
-    _ : x + y;
+safe_add : x y -> when y is
+    0 then x
+    _ then x + y;
 
 safe_result1 : safe_add 5 3;
 safe_result2 : safe_add 5 0;
diff --git a/js/scripting-lang/tests/15_performance_stress.txt b/js/scripting-lang/tests/15_performance_stress.txt
index 7dab1f5..0682d3d 100644
--- a/js/scripting-lang/tests/15_performance_stress.txt
+++ b/js/scripting-lang/tests/15_performance_stress.txt
@@ -39,21 +39,21 @@ table_size : 8;
 ..assert table_size = 8;
 
 /* Test recursive-like patterns with functions */
-accumulate : n -> case n of
-    0 : 0
-    _ : n + accumulate (n - 1);
+accumulate : n -> when n is
+    0 then 0
+    _ then n + accumulate (n - 1);
 
 sum_10 : accumulate 10;
 ..assert sum_10 = 55;
 
 /* Test complex case expressions */
-complex_case : x -> case x of
-    x < 0 : "negative"
-    x = 0 : "zero"
-    x < 10 : "small"
-    x < 100 : "medium"
-    x < 1000 : "large"
-    _ : "huge";
+complex_case : x -> when x is
+    x < 0 then "negative"
+    x = 0 then "zero"
+    x < 10 then "small"
+    x < 100 then "medium"
+    x < 1000 then "large"
+    _ then "huge";
 
 case_test1 : complex_case -5;
 case_test2 : complex_case 0;
diff --git a/js/scripting-lang/tests/16_advanced_functional.txt b/js/scripting-lang/tests/16_advanced_functional.txt
deleted file mode 100644
index 3da9d76..0000000
--- a/js/scripting-lang/tests/16_advanced_functional.txt
+++ /dev/null
@@ -1,169 +0,0 @@
-/* Unit Test: Advanced Functional Programming Patterns */
-/* Tests: Higher-order functions, currying, partial application, monadic patterns */
-
-/* Test function composition with multiple functions */
-id : x -> x;
-const : x y -> x;
-flip : f x y -> f y x;
-
-/* Test identity function */
-id_test : id 42;
-..assert id_test = 42;
-
-/* Test constant function */
-const_test : const 5 10;
-..assert const_test = 5;
-
-/* Test function flipping */
-sub : x y -> x - y;
-flipped_sub : flip @sub;
-flipped_result : flipped_sub 5 10;
-..assert flipped_result = 5;
-
-/* Test partial application patterns */
-partial1 : f x -> y -> f x y;
-partial2 : f x y -> f x y;
-
-add : x y -> x + y;
-add5 : partial1 @add 5;
-add5_result : add5 3;
-..assert add5_result = 8;
-
-/* Test function composition with multiple arguments */
-compose2 : f g x y -> f (g x y);
-compose3 : f g h x -> f (g (h x));
-
-double : x -> x * 2;
-square : x -> x * x;
-increment : x -> x + 1;
-
-composed1 : compose2 @double @add 3 4;
-composed2 : compose3 @double @square @increment 2;
-..assert composed1 = 14;
-..assert composed2 = 18;
-
-/* Test monadic-like patterns with Maybe simulation */
-maybe : x -> case x of
-    undefined : "Nothing"
-    null : "Nothing"
-    _ : "Just " + x;
-
-maybe_map : f m -> case m of
-    "Nothing" : "Nothing"
-    _ : f m;
-
-maybe_bind : m f -> case m of
-    "Nothing" : "Nothing"
-    _ : f m;
-
-maybe_test1 : maybe undefined;
-maybe_test2 : maybe 42;
-maybe_test3 : maybe_map @double "Just 5";
-maybe_test4 : maybe_bind "Just 3" @double;
-
-..assert maybe_test1 = "Nothing";
-..assert maybe_test2 = "Just 42";
-..assert maybe_test3 = "Just 10";
-..assert maybe_test4 = "Just 6";
-
-/* Test list-like operations with tables */
-list_map : f table -> {
-    f table[1],
-    f table[2],
-    f table[3]
-};
-
-list_filter : p table -> case p table[1] of
-    true : {table[1]}
-    false : {};
-
-list_reduce : f init table -> case table[1] of
-    undefined : init
-    _ : f init table[1];
-
-test_list : {1, 2, 3};
-mapped_list : list_map @double test_list;
-filtered_list : list_filter (x -> x > 1) test_list;
-reduced_list : list_reduce @add 0 test_list;
-
-..assert mapped_list[1] = 2;
-..assert mapped_list[2] = 4;
-..assert mapped_list[3] = 6;
-..assert filtered_list[1] = 2;
-..assert reduced_list = 1;
-
-/* Test point-free style programming */
-pointfree_add : add;
-pointfree_double : double;
-pointfree_compose : compose @pointfree_double @pointfree_add;
-
-pointfree_result : pointfree_compose 5 3;
-..assert pointfree_result = 16;
-
-/* Test function memoization pattern */
-memoize : f -> {
-    cache: {},
-    call: x -> case cache[x] of
-        undefined : cache[x] = f x
-        _ : cache[x]
-};
-
-expensive_func : x -> x * x + x + 1;
-memoized_func : memoize @expensive_func;
-
-memo_result1 : memoized_func.call 5;
-memo_result2 : memoized_func.call 5; /* Should use cache */
-..assert memo_result1 = 31;
-..assert memo_result2 = 31;
-
-/* Test continuation-passing style (CPS) */
-cps_add : x y k -> k (x + y);
-cps_multiply : x y k -> k (x * y);
-cps_square : x k -> k (x * x);
-
-cps_example : cps_add 3 4 (sum -> 
-    cps_multiply sum 2 (product -> 
-        cps_square product (result -> result)
-    )
-);
-..assert cps_example = 98;
-
-/* Test trampoline pattern for tail recursion simulation */
-trampoline : f -> case f of
-    f is function : trampoline (f)
-    _ : f;
-
-bounce : n -> case n of
-    0 : 0
-    _ : n + (n - 1);
-
-trampoline_result : trampoline @bounce 5;
-..assert trampoline_result = 15;
-
-/* Test applicative functor pattern */
-applicative : f x -> case f of
-    f is function : f x
-    _ : x;
-
-applicative_test : applicative @double 5;
-..assert applicative_test = 10;
-
-/* Test function pipelines */
-pipeline : x f1 f2 f3 -> f3 (f2 (f1 x));
-pipeline_result : pipeline 2 @increment @double @square;
-..assert pipeline_result = 36;
-
-/* Test function combinators */
-S : f g x -> f x (g x);
-K : x y -> x;
-I : x -> x;
-
-S_test : S @add @double 3;
-K_test : K 5 10;
-I_test : I 42;
-
-..assert S_test = 9;
-..assert K_test = 5;
-..assert I_test = 42;
-
-..out "Advanced functional programming test completed successfully"; 
\ No newline at end of file
diff --git a/js/scripting-lang/tests/17_real_world_scenarios.txt b/js/scripting-lang/tests/17_real_world_scenarios.txt
deleted file mode 100644
index 0a9fc49..0000000
--- a/js/scripting-lang/tests/17_real_world_scenarios.txt
+++ /dev/null
@@ -1,219 +0,0 @@
-/* Unit Test: Real-World Programming Scenarios */
-/* Tests: Practical use cases, data processing, business logic */
-
-/* Scenario 1: User Management System */
-/* Define user types and validation */
-isValidEmail : email -> case email of
-    email contains "@" : true
-    _ : false;
-
-isValidAge : age -> case age of
-    age >= 0 and age <= 120 : true
-    _ : false;
-
-createUser : name email age -> case (isValidEmail email) and (isValidAge age) of
-    true : {
-        name: name,
-        email: email,
-        age: age,
-        status: "active"
-    }
-    false : "invalid user data";
-
-user1 : createUser "Alice" "alice@example.com" 25;
-user2 : createUser "Bob" "invalid-email" 30;
-user3 : createUser "Charlie" "charlie@test.com" 150;
-
-..assert user1.name = "Alice";
-..assert user2 = "invalid user data";
-..assert user3 = "invalid user data";
-
-/* Scenario 2: Shopping Cart System */
-/* Product definitions */
-product1 : {id: 1, name: "Laptop", price: 999.99, category: "electronics"};
-product2 : {id: 2, name: "Book", price: 19.99, category: "books"};
-product3 : {id: 3, name: "Coffee", price: 4.99, category: "food"};
-
-/* Cart operations */
-addToCart : cart product -> {
-    cart,
-    product
-};
-
-calculateTotal : cart -> case cart of
-    cart is table : cart.product.price
-    _ : 0;
-
-applyDiscount : total discount -> case discount of
-    discount > 0 and discount <= 100 : total * (1 - discount / 100)
-    _ : total;
-
-cart : addToCart {} product1;
-cart : addToCart cart product2;
-total : calculateTotal cart;
-discounted : applyDiscount total 10;
-
-..assert total = 1019.98;
-..assert discounted = 917.982;
-
-/* Scenario 3: Data Processing Pipeline */
-/* Sample data */
-sales_data : {
-    {month: "Jan", sales: 1000, region: "North"},
-    {month: "Feb", sales: 1200, region: "North"},
-    {month: "Mar", sales: 800, region: "South"},
-    {month: "Apr", sales: 1500, region: "North"},
-    {month: "May", sales: 900, region: "South"}
-};
-
-/* Data processing functions */
-filterByRegion : data region -> case data of
-    data.region = region : data
-    _ : null;
-
-sumSales : data -> case data of
-    data is table : data.sales
-    _ : 0;
-
-calculateAverage : total count -> case count of
-    count > 0 : total / count
-    _ : 0;
-
-/* Process North region sales */
-north_sales : filterByRegion sales_data "North";
-north_total : sumSales north_sales;
-north_avg : calculateAverage north_total 3;
-
-..assert north_total = 3700;
-..assert north_avg = 1233.3333333333333;
-
-/* Scenario 4: Configuration Management */
-/* Environment configuration */
-getConfig : env -> case env of
-    "development" : {
-        database: "dev_db",
-        port: 3000,
-        debug: true,
-        log_level: "debug"
-    }
-    "production" : {
-        database: "prod_db",
-        port: 80,
-        debug: false,
-        log_level: "error"
-    }
-    "testing" : {
-        database: "test_db",
-        port: 3001,
-        debug: true,
-        log_level: "info"
-    }
-    _ : "unknown environment";
-
-dev_config : getConfig "development";
-prod_config : getConfig "production";
-
-..assert dev_config.debug = true;
-..assert prod_config.debug = false;
-..assert dev_config.port = 3000;
-..assert prod_config.port = 80;
-
-/* Scenario 5: Error Handling and Recovery */
-/* Robust function with error handling */
-safeDivide : x y -> case y of
-    0 : "division by zero error"
-    _ : x / y;
-
-safeParseNumber : str -> case str of
-    str is number : str
-    _ : "invalid number";
-
-processData : data -> case data of
-    data is number : data * 2
-    data is string : safeParseNumber data
-    _ : "unsupported data type";
-
-safe_result1 : safeDivide 10 2;
-safe_result2 : safeDivide 10 0;
-safe_result3 : processData 5;
-safe_result4 : processData "abc";
-
-..assert safe_result1 = 5;
-..assert safe_result2 = "division by zero error";
-..assert safe_result3 = 10;
-..assert safe_result4 = "invalid number";
-
-/* Scenario 6: Event Handling System */
-/* Event types and handlers */
-eventHandlers : {
-    "user.login": x -> "User logged in: " + x,
-    "user.logout": x -> "User logged out: " + x,
-    "order.created": x -> "Order created: " + x,
-    "order.completed": x -> "Order completed: " + x
-};
-
-handleEvent : event data -> case eventHandlers[event] of
-    handler : handler data
-    _ : "Unknown event: " + event;
-
-login_event : handleEvent "user.login" "alice@example.com";
-logout_event : handleEvent "user.logout" "bob@example.com";
-unknown_event : handleEvent "unknown.event" "data";
-
-..assert login_event = "User logged in: alice@example.com";
-..assert logout_event = "User logged out: bob@example.com";
-..assert unknown_event = "Unknown event: unknown.event";
-
-/* Scenario 7: Caching System */
-/* Simple cache implementation */
-cache : {};
-
-setCache : key value -> cache[key] = value;
-getCache : key -> case cache[key] of
-    undefined : "not found"
-    value : value;
-clearCache : key -> cache[key] = undefined;
-
-setCache "user.1" "Alice";
-setCache "user.2" "Bob";
-cache_result1 : getCache "user.1";
-cache_result2 : getCache "user.999";
-clearCache "user.1";
-cache_result3 : getCache "user.1";
-
-..assert cache_result1 = "Alice";
-..assert cache_result2 = "not found";
-..assert cache_result3 = "not found";
-
-/* Scenario 8: API Response Processing */
-/* Mock API responses */
-apiResponse : {
-    status: 200,
-    data: {
-        users: {
-            {id: 1, name: "Alice", active: true},
-            {id: 2, name: "Bob", active: false},
-            {id: 3, name: "Charlie", active: true}
-        },
-        total: 3
-    }
-};
-
-processApiResponse : response -> case response.status of
-    200 : response.data
-    404 : "not found"
-    500 : "server error"
-    _ : "unknown status";
-
-getActiveUsers : data -> case data.users of
-    users : case users.active of
-        true : users
-        _ : null;
-
-api_data : processApiResponse apiResponse;
-active_users : getActiveUsers api_data;
-
-..assert api_data.total = 3;
-..assert active_users = null; /* Simplified for this example */
-
-..out "Real-world scenarios test completed successfully"; 
\ No newline at end of file
diff --git a/js/scripting-lang/tests/integration_02_pattern_matching.txt b/js/scripting-lang/tests/integration_02_pattern_matching.txt
index f0b969a..a67bf59 100644
--- a/js/scripting-lang/tests/integration_02_pattern_matching.txt
+++ b/js/scripting-lang/tests/integration_02_pattern_matching.txt
@@ -5,21 +5,21 @@
 
 /* Recursive factorial with case expressions */
 factorial : n -> 
-  case n of
-    0 : 1
-    _ : n * (factorial (n - 1));
+  when n is
+    0 then 1
+    _ then n * (factorial (n - 1));
 
 /* Pattern matching with multiple parameters */
 classify : x y -> 
-  case x y of
-    0 0 : "both zero"
-    0 _ : "x is zero"
-    _ 0 : "y is zero"
-    _ _ : case x of
-            0 : "x is zero (nested)"
-            _ : case y of
-                  0 : "y is zero (nested)"
-                  _ : "neither zero";
+  when x y is
+    0 0 then "both zero"
+    0 _ then "x is zero"
+    _ 0 then "y is zero"
+    _ _ then when x is
+            0 then "x is zero (nested)"
+            _ then when y is
+                  0 then "y is zero (nested)"
+                  _ then "neither zero";
 
 /* Test factorial */
 fact5 : factorial 5;
@@ -41,15 +41,15 @@ test4 : classify 5 5;
 
 /* Complex nested case expressions */
 analyze : x y z -> 
-  case x y z of
-    0 0 0 : "all zero"
-    0 0 _ : "x and y zero"
-    0 _ 0 : "x and z zero"
-    _ 0 0 : "y and z zero"
-    0 _ _ : "only x zero"
-    _ 0 _ : "only y zero"
-    _ _ 0 : "only z zero"
-    _ _ _ : "none zero";
+  when x y z is
+    0 0 0 then "all zero"
+    0 0 _ then "x and y zero"
+    0 _ 0 then "x and z zero"
+    _ 0 0 then "y and z zero"
+    0 _ _ then "only x zero"
+    _ 0 _ then "only y zero"
+    _ _ 0 then "only z zero"
+    _ _ _ then "none zero";
 
 result1 : analyze 0 0 0;
 result2 : analyze 0 1 1;
diff --git a/js/scripting-lang/tests/integration_03_functional_programming.txt b/js/scripting-lang/tests/integration_03_functional_programming.txt
index 8af6760..1d4671e 100644
--- a/js/scripting-lang/tests/integration_03_functional_programming.txt
+++ b/js/scripting-lang/tests/integration_03_functional_programming.txt
@@ -39,11 +39,11 @@ applied3 : apply @add1 10;
 
 /* Function selection with case expressions */
 getOperation : type -> 
-  case type of
-    "double" : @double
-    "square" : @square
-    "add1"   : @add1
-    _        : @identity;
+  when type is
+    "double" then @double
+    "square" then @square
+    "add1"   then @add1
+    _        then @identity;
 
 /* Test function selection */
 op1 : getOperation "double";
diff --git a/js/scripting-lang/tests/integration_04_mini_case_multi_param.txt b/js/scripting-lang/tests/integration_04_mini_case_multi_param.txt
index be4b71d..279676d 100644
--- a/js/scripting-lang/tests/integration_04_mini_case_multi_param.txt
+++ b/js/scripting-lang/tests/integration_04_mini_case_multi_param.txt
@@ -1,16 +1,16 @@
 /* Multi-parameter case expression at top level */
 x : 1;
 y : 2;
-result1 : case x y of
-    1 2 : "matched"
-    _ _ : "not matched";
+result1 : when x y is
+    1 2 then "matched"
+    _ _ then "not matched";
 
 /* Multi-parameter case expression inside a function */
-f : a b -> case a b of
-    1 2 : "matched"
-    _ _ : "not matched";
-result2 : f 1 2;
-result3 : f 3 4;
+f : a b -> when a b is
+    1 2 then "matched"
+    _ _ then "not matched";
+result2 then f 1 2;
+result3 then f 3 4;
 
 ..out result1;
 ..out result2;