about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--js/scripting-lang/FIXME.md100
-rw-r--r--js/scripting-lang/IDEAS.txt10
-rw-r--r--js/scripting-lang/NEXT-STEPS.md568
-rw-r--r--js/scripting-lang/README.md842
-rw-r--r--js/scripting-lang/debug_test.txt7
-rw-r--r--js/scripting-lang/func_call_test.txt8
-rw-r--r--js/scripting-lang/lang.js3069
-rw-r--r--js/scripting-lang/learn_scripting_lang.txt61
-rw-r--r--js/scripting-lang/nested_test.txt7
-rw-r--r--js/scripting-lang/paren_test.txt7
-rwxr-xr-xjs/scripting-lang/run_tests.sh123
-rw-r--r--js/scripting-lang/simple_case_test.txt7
-rw-r--r--js/scripting-lang/simple_test.txt4
-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/tests/01_lexer_basic.txt25
-rw-r--r--js/scripting-lang/tests/02_arithmetic_operations.txt31
-rw-r--r--js/scripting-lang/tests/03_comparison_operators.txt33
-rw-r--r--js/scripting-lang/tests/04_logical_operators.txt35
-rw-r--r--js/scripting-lang/tests/05_io_operations.txt28
-rw-r--r--js/scripting-lang/tests/06_function_definitions.txt32
-rw-r--r--js/scripting-lang/tests/07_case_expressions.txt47
-rw-r--r--js/scripting-lang/tests/08_first_class_functions.txt51
-rw-r--r--js/scripting-lang/tests/09_tables.txt50
-rw-r--r--js/scripting-lang/tests/10_standard_library.txt49
-rw-r--r--js/scripting-lang/tests/11_edge_cases.txt50
-rw-r--r--js/scripting-lang/tests/12_advanced_tables.txt85
-rw-r--r--js/scripting-lang/tests/13_standard_library_complete.txt97
-rw-r--r--js/scripting-lang/tests/14_error_handling.txt65
-rw-r--r--js/scripting-lang/tests/15_performance_stress.txt131
-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_01_basic_features.txt37
-rw-r--r--js/scripting-lang/tests/integration_02_pattern_matching.txt64
-rw-r--r--js/scripting-lang/tests/integration_03_functional_programming.txt68
-rw-r--r--js/scripting-lang/tests/integration_04_mini_case_multi_param.txt17
36 files changed, 4354 insertions, 2197 deletions
diff --git a/js/scripting-lang/FIXME.md b/js/scripting-lang/FIXME.md
deleted file mode 100644
index e93674a..0000000
--- a/js/scripting-lang/FIXME.md
+++ /dev/null
@@ -1,100 +0,0 @@
-# FIXME: IO Operation Parsing Bug
-
-## Problem Summary
-
-- The parser fails with `Unexpected token in parsePrimary: DOT` when processing IO operations like `..out`, `..assert`, or `..in` at the top level in a script.
-- This occurs in the comprehensive test suite and any script that uses IO operations as standalone statements.
-
-## Observations
-
-- The **lexer** correctly emits `IO_OUT`, `IO_ASSERT`, and `IO_IN` tokens for `..out`, `..assert`, and `..in`.
-- The **parser**'s main loop (`walk()`) now delegates to `parsePrimary()`, which only handles IO tokens if they are the first token in a statement.
-- If a statement starts with a DOT (as in `..out`), and the parser is not expecting it, it throws an error.
-- The bug is not in the lexer (no stray DOT tokens for IO ops), but in the parser's handling of top-level statements.
-- The bug manifests after a block of expressions/statements, when the next statement is an IO operation.
-
-## What We Have in Place
-
-- Lexer emits correct IO tokens for `..out`, `..assert`, `..in`.
-- `parsePrimary()` handles IO tokens if they are the first token in a statement.
-- Table access, dot notation, and function calls with table access are all working.
-- The parser's main loop is too generic and does not explicitly handle IO tokens at the top level.
-
-## Step-by-Step Plan to Fix
-
-1. **Confirm Lexer Output** ✅ **COMPLETED**
-   - Run the lexer in debug mode on a failing script to confirm that IO operations are tokenized as `IO_OUT`, `IO_ASSERT`, or `IO_IN` (not as DOT tokens).
-   - **Result:** Lexer correctly emits IO tokens.
-
-2. **Fix Decimal Number Lexing** ✅ **COMPLETED**
-   - **Issue Found:** Lexer was incorrectly tokenizing decimal numbers like `3.3333333333333335` as separate tokens: `NUMBER(3)`, `DOT`, `NUMBER(3333333333333335)`.
-   - **Fix Applied:** Updated lexer to handle decimal numbers as single `NUMBER` tokens with `parseFloat()`.
-   - **Result:** Decimal numbers are now correctly tokenized.
-
-3. **Fix Interpreter Number Evaluation** ✅ **COMPLETED**
-   - **Issue Found:** Interpreter was using `parseInt()` for `NumberLiteral` evaluation, truncating decimal values.
-   - **Fix Applied:** Changed all three `NumberLiteral` cases to use `parseFloat()` instead of `parseInt()`.
-   - **Result:** Decimal numbers are now correctly evaluated.
-
-4. **Patch Parser IO Handling** ✅ **COMPLETED**
-   - **Issue Found:** Parser's main loop wasn't properly handling IO tokens at the top level.
-   - **Fix Applied:** Added explicit IO token handling in the `walk()` function before calling `parsePrimary()`.
-   - **Result:** IO operations are now correctly parsed as standalone statements.
-
-5. **Test Comprehensive Suite** ❌ **BLOCKED**
-   - **Issue:** Stack overflow error when running the full comprehensive test suite.
-   - **Status:** Need to investigate what's causing the stack overflow in the comprehensive test.
-
-## Current Status
-
-**Fixed Issues:**
-- ✅ IO operation parsing (lexer, parser, interpreter)
-- ✅ Decimal number handling (lexer and interpreter)
-- ✅ Basic arithmetic operations with floating point
-- ✅ IO operations as standalone statements
-- ✅ Case expression parsing (including wildcard patterns)
-- ✅ Function definitions and calls
-- ✅ Wildcard token recognition in lexer
-
-**Remaining Issues:**
-- ❌ Stack overflow in comprehensive test suite
-- ❌ Need to identify what specific pattern in the comprehensive test is causing the stack overflow
-
-## Investigation Results
-
-**Successfully Isolated and Fixed:**
-1. **Case Expression Parsing** - Fixed wildcard token recognition and case expression parsing
-2. **Function Definitions** - Confirmed working correctly
-3. **Basic Language Features** - All core features (arithmetic, IO, functions, case expressions) work correctly
-
-**Stack Overflow Analysis:**
-- The stack overflow occurs in the comprehensive test suite but not in isolated tests
-- All individual language constructs work correctly when tested in isolation
-- The issue is likely caused by a specific combination or pattern of constructs in the comprehensive test
-
-## Next Steps
-
-1. **Systematic Comprehensive Test Analysis**
-   - Test the comprehensive test file section by section to identify the exact location of the stack overflow
-   - Look for patterns that might cause infinite recursion (e.g., complex nested expressions, specific function call patterns)
-   - Check for any language constructs that might not be handled correctly in combination
-
-2. **Parser Debugging**
-   - Add more detailed debugging to identify the exact parsing step that causes the stack overflow
-   - Check for any circular dependencies or infinite loops in the parser logic
-
-3. **Complete Testing**
-   - Once stack overflow is resolved, run the full comprehensive test suite
-   - Verify all language features work correctly together
-
----
-
-**Status:**
-- Lexer: ✅ Fixed (decimal numbers, IO tokens, wildcards)
-- Parser: ✅ Fixed (IO handling, case expressions, wildcards) but has stack overflow issue
-- Interpreter: ✅ Fixed (decimal number evaluation, case expressions)
-- Test suite: ❌ Blocked by stack overflow in comprehensive test
-
----
-
-**Next step:** Systematically analyze the comprehensive test to identify the exact cause of the stack overflow. 
\ No newline at end of file
diff --git a/js/scripting-lang/IDEAS.txt b/js/scripting-lang/IDEAS.txt
index 82eed66..96f8b4b 100644
--- a/js/scripting-lang/IDEAS.txt
+++ b/js/scripting-lang/IDEAS.txt
@@ -6,4 +6,12 @@ add 2 other io functions
 
 where listen takes in a well defined state object from outside the scope of the program, making it available to the program 
 
-where emit lets the program spit state back out into the wider world
\ No newline at end of file
+where emit lets the program spit state back out into the wider world
+
+*** 
+
+Implement type annotation with the "is" keyword, like 
+
+x is int : 1; 
+
+double is int : x -> x * 2;
\ No newline at end of file
diff --git a/js/scripting-lang/NEXT-STEPS.md b/js/scripting-lang/NEXT-STEPS.md
index 7cb1e75..8061fb7 100644
--- a/js/scripting-lang/NEXT-STEPS.md
+++ b/js/scripting-lang/NEXT-STEPS.md
@@ -1,229 +1,435 @@
-# Next Steps: Table Features Implementation
+# Next Steps: Immutable Real-World Programming Features
 
-## Current State Analysis
+## Overview
 
-### What Works ✅
-- Basic table creation: `{name: "Alice", age: 30}`
-- Simple table access: `person.name` (single level)
-- Basic function definitions: `inc : x -> x + 1`
-- Basic function calls: `inc 5`
-- Table literals with functions: `{inc: x -> x + 1}` (parsed but not fully functional)
+This document outlines the plan for extending the Simple Scripting Language to support real-world programming scenarios while maintaining its immutable, functional design philosophy.
 
-### What's Broken ❌
-1. **Chained table access**: `config.user.name` fails with "Unexpected dot (.) token"
-2. **Function calls from tables**: `m.inc 1` doesn't work
-3. **Functions in table literals**: May not be properly interpreted
+## Core Principles
 
-## Root Cause Analysis
+- **Immutability First**: All data structures are immutable
+- **Transformation Over Mutation**: Operations return new data rather than modifying existing data
+- **Functional Composition**: Complex operations built from simple, composable functions
+- **Type Safety**: Enhanced pattern matching and type checking
+- **Performance**: Efficient persistent data structures
 
-### Issue 1: Chained Table Access
-**Problem**: Parser encounters standalone DOT tokens when parsing `config.user.name`
-**Location**: Assignment parsing logic in `walk()` function
-**Debug Evidence**: 
-- Tokens: `[IDENTIFIER "config", DOT, IDENTIFIER "user", DOT, IDENTIFIER "name"]`
-- Parser fails at position 17 (second DOT) because it's not in table access context
+## Phase 1: String Operations and Type System
 
-### Issue 2: Function Calls from Tables
-**Problem**: Parser doesn't recognize `m.inc 1` as a function call
-**Location**: Function call parsing logic
-**Expected**: Should parse as `FunctionCall` with `name: TableAccess` and `args: [1]`
+### 1.1 String Operations
+**Goal**: Add essential string manipulation capabilities
 
-## Implementation Plan
+**New Functions**:
+```javascript
+// String operations as functions
+length : string.length "hello";           // 5
+contains : string.contains "hello" "ll";  // true
+startsWith : string.startsWith "hello" "he"; // true
+endsWith : string.endsWith "hello" "lo";  // true
+substring : string.substring "hello" 1 3; // "el"
+
+// String concatenation
+result : string.concat "Hello" " " "World"; // "Hello World"
+
+// String transformation
+uppercase : string.upper "hello";         // "HELLO"
+lowercase : string.lower "HELLO";         // "hello"
+trimmed : string.trim "  hello  ";        // "hello"
+```
 
-### Phase 1: Fix Chained Table Access Parser
+**Implementation**:
+- Add `string.` namespace for string operations
+- Add string operation functions to standard library
+- No new syntax - uses existing function call patterns
+- Extend existing string literal support
 
-#### Step 1.1: Update Assignment Value Parsing
-**File**: `lang.js` around line 1300-1400
-**Change**: Modify assignment parsing to handle chained dot notation before falling back to `walk()`
+### 1.2 Runtime Type Checking with `is` Keyword
+**Goal**: Add explicit, optional type checking mechanism using the `is` keyword
 
-**Current Logic**:
-```javascript
-// Assignment parsing falls back to walk() for value
-const value = walk(); // This fails on DOT tokens
-```
+**Design Philosophy**:
+- Type checking is purely additive - no breaking changes to existing code
+- Works seamlessly with existing case expression syntax
+- Returns boolean values, fitting the functional style
+- Simple implementation with clear semantics
 
-**New Logic**:
+**New Features**:
 ```javascript
-// Check if value is a chained table access
-if (tokens[current] && tokens[current].type === TokenType.IDENTIFIER &&
-    tokens[current + 1] && tokens[current + 1].type === TokenType.DOT) {
-    // Parse chained table access
-    const tableAccess = parseChainedTableAccess();
-    return { type: 'AssignmentExpression', name, value: tableAccess };
-}
-// Fall back to walk() for other cases
-const value = walk();
+// Basic type checking
+isNumber : x -> x is number;
+isString : x -> x is string;
+isTable : x -> x is table;
+isFunction : x -> x is function;
+
+// Type-safe operations in case expressions
+safeStringOp : x -> case x of
+    x is string : string.length x
+    _ : "not a string";
+
+// Complex type validation
+validateUser : user -> case user of
+    user.name is string and user.age is number : true
+    _ : 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"
+    _ : "unknown type";
 ```
 
-#### Step 1.2: Create parseChainedTableAccess Helper
-**File**: `lang.js` in `walk()` function
-**Purpose**: Parse arbitrary length dot notation chains
+**Supported Types**:
+- `number` (both integers and floats)
+- `string` 
+- `boolean`
+- `table` (objects and arrays)
+- `function`
 
 **Implementation**:
+- Add `IS` token type and type-specific tokens (`NUMBER_TYPE`, `STRING_TYPE`, etc.)
+- Update lexer to recognize `is` keyword and type names
+- Extend parser to handle type checking expressions in case patterns
+- Add type checking logic in interpreter that returns boolean values
+- No changes to existing syntax or semantics
+
+## Phase 2: Persistent Data Structures
+
+### 2.1 Immutable Tables with Transformations
+**Goal**: Replace mutable table operations with immutable transformations
+
+**Current Problem**:
 ```javascript
-function parseChainedTableAccess() {
-    let tableExpr = {
-        type: 'Identifier',
-        value: tokens[current].value
-    };
-    current++; // Skip first identifier
-    
-    while (tokens[current] && tokens[current].type === TokenType.DOT) {
-        current++; // Skip dot
-        if (tokens[current] && tokens[current].type === TokenType.IDENTIFIER) {
-            const key = {
-                type: 'StringLiteral',
-                value: tokens[current].value
-            };
-            current++; // Skip identifier
-            
-            tableExpr = {
-                type: 'TableAccess',
-                table: tableExpr,
-                key
-            };
-        } else {
-            throw new Error('Expected identifier after dot in table access');
-        }
-    }
-    
-    return tableExpr;
-}
+// This won't work (mutable)
+cache[key] = value;
 ```
 
-#### Step 1.3: Update Function Call Parsing
-**File**: `lang.js` around line 600-700
-**Change**: Allow `TableAccess` nodes as function names
-
-**Current Logic**:
+**Solution - Functional Immutable Transformations**:
 ```javascript
-// Only handles string function names
-func = globalScope[node.name];
+// Functional transformations using table namespace
+cache : {};
+cache1 : table.set cache "user.1" "Alice";
+cache2 : table.set cache1 "user.2" "Bob";
+value : table.get cache2 "user.1";  // "Alice"
+cache3 : table.delete cache2 "user.1";
+
+// Nested updates with dot notation
+user : {name: "Alice", profile: {age: 25}};
+updatedUser : table.set user "profile.age" 26;
+
+// Complex transformations using composition
+cache1 : pipe
+    (table.set "user.1" "Alice")
+    (table.set "user.2" "Bob")
+    (table.set "user.3" "Charlie")
+    cache;
+
+// Table merging
+combined : table.merge table1 table2;
 ```
 
-**New Logic**:
+**Implementation**:
+- Add `table.set`, `table.get`, `table.delete`, `table.merge` functions
+- Implement efficient structural sharing for immutable updates
+- Add nested key support (e.g., "profile.age")
+- All functions return new tables, never modify originals
+- Use existing function composition patterns
+
+### 2.2 APL-Inspired Table Primitives
+**Goal**: Enhance tables with APL-style operations for ergonomic data manipulation
+
+**Design Philosophy**:
+- Use existing table syntax for array-like behavior
+- Add APL-inspired primitives for vectorized operations
+- Keep immutable transformations
+- Provide concise, expressive data manipulation
+
+**New Features**:
 ```javascript
-if (typeof node.name === 'string') {
-    func = globalScope[node.name];
-} else if (node.name.type === 'TableAccess') {
-    // Evaluate table access to get function
-    func = evalNode(node.name);
-    if (typeof func !== 'function') {
-        throw new Error('Table access did not resolve to a function');
-    }
-}
+// Table creation (array-like using existing syntax)
+numbers : {1, 2, 3, 4, 5};
+mixed : {1, "hello", true, {key: "value"}};
+
+// All table operations namespaced for consistency
+first : table.first numbers;              // First element
+last : table.last numbers;                // Last element
+length : table.length numbers;            // Size/shape
+
+// Less common operations (namespaced)
+rest : table.drop 1 numbers;        // Drop first element  
+slice : table.slice numbers 2 3;    // Elements 2-3
+
+// Vectorized operations
+doubled : table.add numbers numbers;      // Element-wise addition
+squared : table.multiply numbers numbers; // Element-wise multiplication
+incremented : table.add numbers 1;        // Scalar addition to each element
+
+// Reductions (all namespaced)
+sum : table.sum numbers;                 // Sum reduction
+max : table.max numbers;                 // Maximum reduction
+min : table.min numbers;                 // Minimum reduction
+product : table.product numbers;   // Product reduction
+average : table.average numbers;   // Average reduction
+
+// Scan operations (namespaced)
+runningSum : table.scan table.sum numbers;        // Running sum scan
+runningProduct : table.scan table.product numbers; // Running product scan
+
+// Table metadata operations
+keys : table.keys table;           // Get all keys
+values : table.values table;       // Get all values
+reversed : table.reverse table;    // Reverse order
+sorted : table.sort table;         // Sort
+unique : table.unique table;       // Remove duplicates
 ```
 
-### Phase 2: Fix Function Calls from Tables
+**Implementation**:
+- Add `table.` namespace for all table operations
+- Extend lexer to recognize table operation keywords
+- Add vectorized operation logic in interpreter
+- Implement reduction and scan operations
+- Add table metadata operations
+
+## Phase 3: Higher-Order Functions for Collections
 
-#### Step 2.1: Update Function Call Detection
-**File**: `lang.js` in `parseFunctionCall()` function
-**Change**: Detect when a table access is followed by arguments
+### 3.1 Enhanced Standard Library
+**Goal**: Add collection processing functions
 
-**Current Logic**:
+**New Functions**:
 ```javascript
-// Only checks for identifier followed by arguments
-if (tokens[current + 1] && tokens[current + 1].type === TokenType.NUMBER) {
-    // Function call
-}
+// Table processing (using namespaced primitives)
+numbers : {1, 2, 3, 4, 5};
+doubled : map @double numbers;                // {2, 4, 6, 8, 10}
+evens : filter @isEven numbers;               // {2, 4}
+sum : table.sum numbers;                      // 15 (sum reduction)
+
+// Table metadata operations
+table : {a: 1, b: 2, c: 3};
+keys : table.keys table;                      // {a, b, c}
+values : table.values table;                  // {1, 2, 3}
+pairs : table.pairs table;                    // {{a, 1}, {b, 2}, {c, 3}}
+
+// Advanced operations with tables
+nested : {{1, 2}, {3, 4}, {5}};
+flattened : table.flatten nested;             // {1, 2, 3, 4, 5}
+grouped : table.groupBy @isEven numbers;     // {true: {2, 4}, false: {1, 3, 5}}
+
+// Table operations
+reversed : table.reverse numbers;             // {5, 4, 3, 2, 1}
+sorted : table.sort numbers;                  // {1, 2, 3, 4, 5}
+unique : table.unique {1, 2, 2, 3, 3, 4};   // {1, 2, 3, 4}
 ```
 
-**New Logic**:
+**Implementation**:
+- Extend existing `map`, `filter`, `reduce` to work with tables
+- Implement vectorized operations for tables
+- Add reduction and scan operations
+- Implement table metadata operations
+
+### 3.2 Table Generation Helpers
+**Goal**: Add convenient table creation functions
+
+**New Functions**:
 ```javascript
-// Check for identifier followed by arguments OR table access followed by arguments
-if ((tokens[current + 1] && tokens[current + 1].type === TokenType.NUMBER) ||
-    (tokens[current + 1] && tokens[current + 1].type === TokenType.DOT)) {
-    // Parse table access first, then check for arguments
-    const tableAccess = parseChainedTableAccess();
-    if (tokens[current] && isArgumentToken(tokens[current])) {
-        // This is a function call from table
-        return parseFunctionCallFromTable(tableAccess);
-    }
-    return tableAccess;
-}
+// Table generation helpers
+range : table.range 1 5;           // {1, 2, 3, 4, 5}
+repeated : table.repeat "hello" 3; // {"hello", "hello", "hello"}
+
+// Use existing map/filter instead of comprehensions
+squares : map (x -> x * x) {1, 2, 3, 4, 5};
+evens : filter @isEven {1, 2, 3, 4, 5};
 ```
 
-#### Step 2.2: Create parseFunctionCallFromTable Helper
-**Purpose**: Parse function calls where the function is a table access
+## Phase 4: Error Handling with Error Type
+
+### 4.1 Error Type
+**Goal**: Provide consistent error handling without complex monads
 
 **Implementation**:
 ```javascript
-function parseFunctionCallFromTable(tableAccess) {
-    const args = [];
-    while (current < tokens.length && isArgumentToken(tokens[current])) {
-        args.push(walk());
-    }
-    return {
-        type: 'FunctionCall',
-        name: tableAccess,
-        args
-    };
-}
+// Simple error type
+error : message -> {type: "error", message: message};
+
+// Safe operations with error handling
+safeDivide : x y -> case y of
+    0 : error "division by zero"
+    _ : x / y;
+
+safeParseNumber : str -> case str of
+    str is number : str
+    _ : error "invalid number";
+
+// Error checking
+isError : value -> value is error;
+getErrorMessage : error -> case error of
+    {type: "error", message: m} : m;
 ```
 
-### Phase 3: Test and Validate
-
-#### Step 3.1: Create Comprehensive Test Suite
-**File**: `table_features_test.txt`
-
-**Test Cases**:
-```plaintext
-/* Test 1: Basic table access */
-person : {name: "Alice", age: 30};
-name : person.name;
-..out name; /* Should output: Alice */
+## Phase 5: Real-World Scenario Support
 
-/* Test 2: Chained table access */
-config : {user: {profile: {name: "Bob"}}};
-deep_name : config.user.profile.name;
-..out deep_name; /* Should output: Bob */
+### 5.1 User Management System
+**Immutable Implementation**:
+```javascript
+// User validation
+isValidEmail : email -> case email of
+    email contains "@" : true
+    _ : 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";
+
+// User management
+users : {};
+user1 : createUser "Alice" "alice@example.com" 25;
+users1 : table.set users "user.1" user1;
+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);
+```
 
-/* Test 3: Functions in tables */
-math : {
-    add : x y -> x + y,
-    sub : x y -> x - y,
-    double : x -> x * 2
+### 5.2 Shopping Cart System
+**Immutable Implementation**:
+```javascript
+// Cart operations
+emptyCart : {items: {}, total: 0};
+addItem : cart item -> {
+    items: table.set cart.items (table.length cart.items + 1) item,
+    total: cart.total + item.price
+};
+removeItem : cart itemId -> {
+    items: filter (item -> item.id != itemId) cart.items,
+    total: calculateTotal (filter (item -> item.id != itemId) cart.items)
 };
 
-/* Test 4: Function calls from tables */
-result1 : math.add 3 4;     /* Should be 7 */
-result2 : math.sub 10 3;    /* Should be 7 */
-result3 : math.double 5;    /* Should be 10 */
-..out result1;
-..out result2;
-..out result3;
-
-/* Test 5: Nested function calls from tables */
-nested : math.double(math.add 2 3); /* Should be 10 */
-..out nested;
+// Discount application
+applyDiscount : cart discountPercent -> {
+    items: cart.items,
+    total: cart.total * (1 - discountPercent / 100)
+};
 ```
 
-#### Step 3.2: Debug and Fix Issues
-- Run tests and identify any remaining issues
-- Add debug logging as needed
-- Fix edge cases and error handling
-
-## Implementation Order
-
-1. **Phase 1.1**: Update assignment value parsing
-2. **Phase 1.2**: Create parseChainedTableAccess helper
-3. **Phase 1.3**: Update function call parsing
-4. **Phase 2.1**: Update function call detection
-5. **Phase 2.2**: Create parseFunctionCallFromTable helper
-6. **Phase 3.1**: Create comprehensive test suite
-7. **Phase 3.2**: Debug and validate
+### 5.3 Data Processing Pipeline
+**Immutable Implementation**:
+```javascript
+// Data processing
+salesData : {
+    {month: "Jan", sales: 1000, region: "North"},
+    {month: "Feb", sales: 1200, region: "North"},
+    {month: "Mar", sales: 800, region: "South"}
+};
 
-## Success Criteria
+// Filter by region
+filterByRegion : data region -> filter (item -> item.region = region) data;
 
-- ✅ `config.user.name` parses and evaluates correctly
-- ✅ `m.inc 1` parses and evaluates to 2
-- ✅ `m.inc(m.dec(5))` works with nested calls
-- ✅ Functions defined in table literals work correctly
-- ✅ No regression in existing functionality
+// Calculate totals using sum reduction
+sumSales : data -> table.sum (map (item -> item.sales) data);
 
-## Risk Mitigation
+// Process pipeline
+northData : filterByRegion salesData "North";
+northTotal : sumSales northData;
+```
 
-- **Minimal changes**: Each change targets a specific issue
-- **Debug logging**: Keep debug output to trace issues
-- **Incremental testing**: Test each phase before proceeding
-- **Fallback logic**: Maintain existing `walk()` fallback for non-table cases 
\ No newline at end of file
+## Implementation Timeline
+
+### Week 1-2: String Operations and Runtime Type Checking
+- [ ] String concatenation operator
+- [ ] String method implementations
+- [ ] `is` keyword and type checking tokens
+- [ ] Type checking in case expressions
+- [ ] Type validation functions in standard library
+
+### Week 3-4: Table Primitives with Namespacing
+- [ ] `table.` namespace for all table operations
+- [ ] Vectorized operations for tables
+- [ ] Reduction and scan operations
+- [ ] Table metadata operations
+- [ ] Performance optimization
+
+### Week 5-6: Higher-Order Functions
+- [ ] Enhanced standard library
+- [ ] Collection processing functions
+- [ ] Table-specific operations
+- [ ] Utility functions
+
+### Week 7-8: Error Handling
+- [ ] Error type implementation
+- [ ] Error handling patterns
+- [ ] Error checking functions
+- [ ] Integration with existing operations
+
+### Week 9-10: Real-World Scenarios
+- [ ] User management system
+- [ ] Shopping cart system
+- [ ] Data processing pipeline
+- [ ] Integration testing
+
+## Benefits of Runtime Type Checking Approach
+
+### Simplicity
+- **Minimal Implementation**: Only need to add `is` keyword and type checking logic
+- **No Breaking Changes**: Existing code continues to work unchanged
+- **Clear Semantics**: `x is number` is obviously a boolean expression
+- **Consistent Syntax**: Works seamlessly with existing case expressions
+
+### Functional Design
+- **Boolean Results**: Type checking returns true/false, fitting functional style
+- **Composable**: Can combine with logical operators (`and`, `or`, `not`)
+- **Pattern Matching**: Integrates naturally with case expressions
+- **No Side Effects**: Pure functions for type validation
+
+### Extensibility
+- **Easy to Add Types**: Simple to extend for new types (arrays, tuples, etc.)
+- **Custom Types**: Can implement custom type checking via functions
+- **Performance**: Runtime overhead only when explicitly used
+- **Optional**: No requirement to use type checking in existing code
+
+## Testing Strategy
+
+### Unit Tests
+- String operation tests
+- Runtime type checking tests (`is` keyword)
+- Type validation function tests
+- Data structure transformation tests
+- Higher-order function tests
+- Error handling tests
+
+### Integration Tests
+- Real-world scenario tests
+- Performance tests
+- Edge case tests
+- Error handling tests
+
+### Performance Benchmarks
+- Data structure operation performance
+- Memory usage analysis
+- Transformation efficiency
+- Scalability testing
+
+## Success Metrics
+
+- [ ] All real-world scenarios in `tests/17_real_world_scenarios.txt` pass
+- [ ] Performance within acceptable bounds (no more than 2x slower than current)
+- [ ] Memory usage remains reasonable
+- [ ] Code remains readable and maintainable
+- [ ] Backward compatibility maintained
+
+## Future Considerations
+
+### Advanced Features (Post-v1.0)
+- Lazy evaluation for large collections
+- Parallel processing capabilities
+- Advanced type system with generics
+- Macro system for code generation
+- Module system for code organization
+
+### Performance Optimizations
+- Structural sharing for immutable data structures
+- Compile-time optimizations
+- JIT compilation for hot paths
+- Memory pooling for temporary objects
+
+This plan maintains the language's functional, immutable design while adding the capabilities needed for real-world programming scenarios. 
\ No newline at end of file
diff --git a/js/scripting-lang/README.md b/js/scripting-lang/README.md
index 5630e93..73ccbf1 100644
--- a/js/scripting-lang/README.md
+++ b/js/scripting-lang/README.md
@@ -1,722 +1,220 @@
 # Simple Scripting Language
 
-A minimal, interpreted scripting language designed for learning language implementation concepts. This language demonstrates the core components needed for an interpreter: lexer, parser, and interpreter.
+A functional programming language with immutable variables, first-class functions, and pattern matching.
 
 ## Features
 
-- **Arithmetic operations**: `+`, `-`, `*`, `/`, `%` (modulo), `^` (power)
-- **Comparison operators**: `=`, `<`, `>`, `<=`, `>=`, `!=`
-- **Logical operators**: `and`, `or`, `xor`, `not`
-- **Variable assignment**: Immutable variables with `:` syntax
-- **Function definitions**: Arrow function syntax with pattern matching
-- **Pattern matching**: Case expressions with wildcard support
-- **Function calls**: Direct function application
-- **First-class functions**: Functions can be passed as arguments using `@` syntax
-- **Function composition**: Higher-order functions for combining functions
-- **Lexical scoping**: Functions create their own scope
-- **Input/Output**: Built-in IO operations with `..in`, `..out`, and `..assert`
-- **Standard Library**: Built-in functional programming utilities
-- **Comments**: C-style block comments with `/* ... */` syntax
-- **Tables**: Lua-style immutable tables with array and object capabilities
+- **Immutable Variables**: Variables cannot be reassigned
+- **First-Class Functions**: Functions can be passed as arguments and stored in data structures
+- **Lexical Scoping**: Functions create their own scope
+- **Pattern Matching**: Case expressions with wildcard support
+- **Table Literals**: Lua-style tables with both array-like and key-value entries
+- **Standard Library**: Built-in higher-order functions (`map`, `compose`, `pipe`, `apply`, `filter`, `reduce`, `fold`, `curry`)
+- **IO Operations**: Built-in input/output operations (`..in`, `..out`, `..assert`)
+- **Floating Point Arithmetic**: Full support for decimal numbers
+- **Unary Minus**: Support for negative numbers (e.g., `-1`, `-3.14`)
 
 ## Syntax
 
-### Variables
-
-Variables are immutable and assigned using the `:` operator:
-
-```
-x : 5;
-y : 10;
+### Basic Operations
 ```
+/* Arithmetic */
+x : 5 + 3;
+y : 10 - 2;
+z : 4 * 3;
+w : 15 / 3;
+neg : -5;  /* Unary minus */
 
-### Arithmetic Operations
+/* Comparisons */
+result : x > y;
+equal : a = b;
+not_equal : a != b;
 
-Arithmetic operations are supported with parentheses grouping:
-
-```
-sum : x + y;
-diff : x - y;
-product : x * y;
-quotient : x / y;
-modulo : 17 % 5;        /* Returns 2 */
-power : 2 ^ 3;          /* Returns 8 */
-grouped : (5 + 3) * 2;  /* Returns 16 */
-nested : ((5 + 3) * 2) + 1;  /* Returns 17 */
+/* Logical */
+and_result : true and false;
+or_result : true or false;
 ```
 
-### Function Definitions
-
-Functions are defined using arrow syntax (`->`):
-
+### Variables and Functions
 ```
-add : x y -> x + y;
-double : x -> x * 2;
-```
-
-### Function Calls
-
-Functions are called by providing arguments directly after the function name:
-
-```
-result : add 3 4;
-doubled : double 5;
-```
-
-#### Function Calls with Parentheses
-
-Function calls support parenthesized arguments for complex expressions:
-
-```
-/* Simple function call */
-result1 : add 3 4;
-
-/* Function call with parenthesized arithmetic */
-result2 : add (3 + 2) (4 + 1);
+/* Immutable variables */
+x : 42;
+y : "hello";
 
-/* Function call with function calls in parentheses */
-result3 : add (double 3) (square 2);
+/* Function definition */
+f : x -> x * 2;
 
-/* Complex nested function calls with parentheses */
-result4 : add (add 1 2) (add 3 4);
+/* Function call */
+result : f 5;
 ```
 
-**Note:** Parentheses provide explicit grouping and are the recommended way to handle complex nested function calls.
-
 ### Tables
-
-The language supports Lua-style immutable tables that can serve as both arrays and objects:
-
-#### Table Creation
-
-Tables are created using curly braces `{}`:
-
-```
-/* Empty table */
-empty : {};
-
-/* Array-like table (1-indexed) */
-numbers : {1, 2, 3, 4, 5};
-
-/* Key-value table */
-person : {name: "Alice", age: 30, active: true};
-
-/* Mixed table (array-like and key-value) */
-mixed : {1, name: "Bob", 2, active: false};
-```
-
-#### Table Access
-
-Tables support both bracket notation and dot notation for accessing values:
-
-```
-/* Array access with bracket notation */
-first : numbers[1];      /* Returns 1 */
-second : numbers[2];     /* Returns 2 */
-
-/* Object access with dot notation */
-name : person.name;      /* Returns "Alice" */
-age : person.age;        /* Returns 30 */
-
-/* Object access with bracket notation */
-name_bracket : person["name"];  /* Returns "Alice" */
-age_bracket : person["age"];    /* Returns 30 */
-
-/* Mixed table access */
-first_mixed : mixed[1];         /* Returns 1 */
-name_mixed : mixed.name;        /* Returns "Bob" */
-second_mixed : mixed[2];        /* Returns 2 */
-```
-
-#### Table Features
-
-- **Immutable**: Tables cannot be modified after creation
-- **1-indexed arrays**: Array-like tables start indexing at 1
-- **Mixed types**: Tables can contain numbers, strings, booleans, and functions
-- **Nested access**: Tables can contain other tables for complex data structures
-- **Unified syntax**: Same syntax for arrays and objects
-
-#### Tables with Case Expressions
-
-Tables work well with case expressions for pattern matching:
-
-```
-/* Case expressions with table values */
-person : {name: "Alice", age: 30, active: true};
-result : case person.age of
-    0 : 30 : "Person is 30"
-    1 : _ : "Person is different age"
-;
-
-/* Case expressions with boolean values */
-status : case person.active of
-    0 : true : "Person is active"
-    1 : false : "Person is inactive"
-;
-
-/* Case expressions with array-like access */
-numbers : {1: 10, 2: 20, 3: 30};
-element : case numbers[2] of
-    0 : 20 : "Second element is 20"
-    1 : _ : "Unexpected second element"
-;
-```
-
-**Current Limitations:**
-- Function calls from tables (e.g., `table.func args`) are not supported
-- Function definitions inside table literals are not supported
-- Tables can store function references, but they cannot be called directly
-
-### First-Class Functions
-
-Functions can be passed as arguments to other functions using the `@` prefix:
-
 ```
-double : x -> x * 2;
-square : x -> x * x;
-compose : f g x -> f g x;
+/* Table literal */
+table : {1, 2, 3, key: "value"};
 
-composed : compose @double @square 3;  /* double(square(3)) = 18 */
+/* Table access */
+first : table[1];
+value : table.key;
+nested : table.key.subkey;
 ```
 
-**Function Reference Syntax:**
-- `@functionName` - Creates a function reference (doesn't execute the function)
-- `functionName args` - Calls the function with arguments
-
 ### Pattern Matching
-
-The language supports pattern matching with case expressions in function bodies:
-
-```
-compare : x y -> 
-  case x y of
-    0 0 : "both zero"
-    0 _ : "x is zero"
-    _ 0 : "y is zero"
-    _ _ : "neither zero";
-```
-
-#### Pattern Matching Syntax
-
-- **Exact matches**: `0 0` matches when both values are 0
-- **Wildcards**: `_` matches any value
-- **Mixed patterns**: `0 _` matches when first value is 0 and second can be anything
-
-### Comparison and Logical Operations
-
-The language supports comparison and logical operations:
-
-```
-/* Comparison operators */
-less : 3 < 5;           /* true */
-greater : 10 > 5;       /* true */
-equal : 5 = 5;          /* true */
-not_equal : 3 != 5;     /* true */
-less_equal : 5 <= 5;    /* true */
-greater_equal : 5 >= 3; /* true */
-
-/* Logical operators */
-and_result : 1 and 1;   /* true */
-or_result : 0 or 1;     /* true */
-xor_result : 1 xor 0;   /* true */
-not_result : not 0;     /* true */
-```
-
-### Comments
-
-The language supports C-style block comments:
-
-```
-/* This is a single line comment */
-
-/* This is a multi-line comment
-   that spans multiple lines */
-
-x : 5; /* Comment on same line as code */
-
-/* Nested comments are supported */
-/* Outer comment /* Inner comment */ More outer comment */
-```
-
-**Comment Features:**
-- Block comments start with `/*` and end with `*/`
-- Comments can span multiple lines
-- Comments can appear on the same line as code
-- Nested comments are supported
-- Comments are completely ignored by the lexer and parser
-
-### Input/Output Operations
-
-The language provides built-in IO operations for reading from stdin and writing to stdout:
-
-```
-name : ..in;        /* Read input from stdin */
-..out name;         /* Output to stdout */
-..out "Hello";      /* Output string literal */
-..out 42;           /* Output number */
-..assert x = 5;     /* Assert that x equals 5 */
-..assert y > 3;     /* Assert that y is greater than 3 */
-..assert z != 0;    /* Assert that z is not equal to 0 */
-```
-
-**IO Functions:**
-- `..in` - Reads a line from stdin, returns a number if possible, otherwise a string
-- `..out` - Outputs a value to stdout and returns the value
-- `..assert` - Asserts that a comparison is true, throws an error if it's false. Supports all comparison operators: `=`, `<`, `>`, `<=`, `>=`, `!=`
-
-**Note:** The `..` prefix indicates these are impure operations that have side effects.
-
-## Standard Library
-
-The language includes a built-in standard library with functional programming utilities:
-
-### Higher-Order Functions
-
-- **map**: Apply a function to a value (`map f x = f x`)
-- **compose**: Compose two functions (`compose f g x = f(g(x))`)
-- **curry**: Explicit currying (`curry f x y = f x y`)
-- **apply**: Apply a function to an argument (`apply f x = f x`)
-- **pipe**: Compose functions left-to-right (`pipe f g x = g(f(x))`)
-- **filter**: Filter based on a predicate (`filter p x = p(x) ? x : 0`)
-- **reduce**: Reduce to a single value (`reduce f init x = f(init, x)`)
-- **fold**: Same as reduce (`fold f init x = f(init, x)`)
-
-### Usage Examples
-
-```
-double : x -> x * 2;
-square : x -> x * x;
-
-/* Using map */
-result1 : map @double 5;    /* Returns 10 */
-result2 : map @square 3;    /* Returns 9 */
-
-/* Using compose */
-composed : compose @double @square 3;  /* double(square(3)) = 18 */
-
-/* Using pipe */
-piped : pipe @double @square 2;        /* square(double(2)) = 16 */
-
-/* Using filter */
-isPositive : x -> x > 0;
-filtered : filter @isPositive 5;       /* Returns 5 (since 5 > 0) */
-```
-
-
-## Language Components
-
-### Lexer
-
-The lexer tokenizes input into meaningful units:
-- Numbers: `123`
-- Identifiers: `variable_name`
-- Operators: `+`, `-`, `*`, `/`
-- Keywords: `case`, `of`, `function`
-- Symbols: `:`, `->`, `_`
-
-### Parser
-
-The parser builds an Abstract Syntax Tree (AST) from tokens, supporting:
-- Number literals
-- Arithmetic expressions
-- Variable assignments
-- Function declarations
-- Function calls
-- Case expressions
-- Pattern matching
-
-### Interpreter
-
-The interpreter executes the AST with:
-- Global scope management
-- Function evaluation
-- Pattern matching execution
-- Arithmetic computation
-- Immutable variable semantics
-
-## Example Programs
-
-### Basic Arithmetic and Variables
-
 ```
-/* Simple arithmetic with variables */
-x : 5;
-y : 10;
-sum : x + y;
-diff : x - y;
-product : x * y;
-quotient : y / x;
-modulo : 17 % 5;        /* Returns 2 */
-power : 2 ^ 3;          /* Returns 8 */
-
-..out sum;      /* 15 */
-..out diff;     /* -5 */
-..out product;  /* 50 */
-..out quotient; /* 2 */
-..out modulo;   /* 2 */
-..out power;    /* 8 */
-
-/* Grouped expressions with parentheses */
-grouped : (5 + 3) * 2;           /* 16 */
-nested : ((5 + 3) * 2) + 1;      /* 17 */
-complex : (2 ^ 3) % 3 and 5 > 3; /* true */
+/* Case expression */
+result : case x of
+    1 : "one"
+    2 : "two"
+    _ : "other";
 ```
 
-### Function Definitions and Calls
-
+### IO Operations
 ```
-/* Basic function definition */
-add : x y -> x + y;
-multiply : x y -> x * y;
-double : x -> x * 2;
-square : x -> x * x;
-
-/* Function calls */
-result1 : add 3 4;        /* 7 */
-result2 : multiply 5 6;   /* 30 */
-result3 : double 8;       /* 16 */
-result4 : square 4;       /* 16 */
-
-/* Function calls with parenthesized arguments */
-result5 : add (3 + 2) (4 + 1);    /* 15 */
-result6 : add (double 3) (square 2); /* 10 */
-result7 : add (add 1 2) (add 3 4);   /* 10 */
-```
-
-### Tables and Data Structures
+/* Output */
+..out "Hello, World!";
 
-```
-/* Create various table types */
-empty : {};
-numbers : {1, 2, 3, 4, 5};
-person : {name: "Alice", age: 30, active: true};
-mixed : {1, name: "Bob", 2, active: false};
-
-/* Access array elements */
-first : numbers[1];
-second : numbers[2];
-last : numbers[5];
-
-/* Access object properties */
-name : person.name;
-age : person.age;
-active : person.active;
-
-/* Access mixed table */
-first_mixed : mixed[1];
-name_mixed : mixed.name;
-second_mixed : mixed[2];
-
-/* Output results */
-..out "First number: ";
-..out first;
-..out "Person name: ";
-..out name;
-..out "Mixed first: ";
-..out first_mixed;
-..out "Mixed name: ";
-..out name_mixed;
-```
-
-### Pattern Matching with Case Expressions
+/* Input */
+name : ..in;
 
-```
-/* Pattern matching in function bodies */
-compare : x y -> 
-  case x y of
-    0 0 : "both zero"
-    0 _ : "x is zero"
-    _ 0 : "y is zero"
-    _ _ : "neither zero";
-
-/* Testing pattern matching */
-test1 : compare 0 0;   /* "both zero" */
-test2 : compare 0 5;   /* "x is zero" */
-test3 : compare 5 0;   /* "y is zero" */
-test4 : compare 5 5;   /* "neither zero" */
-
-/* Single-parameter case expressions */
-factorial : n -> 
-  case n of
-    0 : 1
-    _ : n * (factorial (n - 1));
-
-/* Single-parameter grade function */
-grade : score -> 
-  case score of
-    90 : "A"
-    80 : "B"
-    70 : "C"
-    _  : "F";
-
-fact5 : factorial 5;    /* 120 */
-grade1 : grade 95;      /* "A" */
-grade2 : grade 85;      /* "B" */
-grade3 : grade 65;      /* "F" */
+/* Assertion */
+..assert x = 5;
 ```
 
-### First-Class Functions and Composition
-
+### Standard Library
 ```
-/* Function references and composition */
+/* Map */
 double : x -> x * 2;
-square : x -> x * x;
-add1 : x -> x + 1;
-
-/* Using standard library functions */
-composed : compose @double @square 3;  /* double(square(3)) = 18 */
-piped : pipe @double @square 2;        /* square(double(2)) = 16 */
-applied : apply @double 5;             /* double(5) = 10 */
-
-/* Higher-order functions */
-mapped1 : map @double 5;               /* 10 */
-mapped2 : map @square 3;               /* 9 */
-
-/* Function references in case expressions */
-getFunction : type -> 
-  case type of
-    "double" : @double
-    "square" : @square
-    _        : @add1;
-
-func1 : getFunction "double";  /* Function reference */
-func2 : getFunction "square";  /* Function reference */
-```
-
-### Recursion and Complex Functions
-
-```
-/* Recursive factorial function (using single-parameter case) */
-factorial : n -> 
-  case n of
-    0 : 1
-    _ : n * (factorial (n - 1));
-
-/* Recursive countdown function */
-countdown : n -> 
-  case n of
-    0 : "done"
-    _ : countdown (n - 1);
-
-/* Testing recursive functions */
-fact5 : factorial 5;    /* 120 */
-count : countdown 3;    /* "done" */
-```
+squared : map @double 5;
 
-### Comparison and Logical Operators
-
-```
-/* Comparison operators */
-a : 5;
-b : 10;
-
-less : a < b;           /* true */
-greater : b > a;        /* true */
-equal : a = a;          /* true */
-notEqual : a != b;      /* true */
-lessEqual : a <= 5;     /* true */
-greaterEqual : b >= 10; /* true */
-
-/* Logical operators */
-logicalAnd : 1 and 1;   /* true */
-logicalOr : 0 or 1;     /* true */
-logicalXor : 1 xor 0;   /* true */
-logicalNot : not 0;     /* true */
-
-/* Complex logical expressions */
-complex1 : a < b and b > 5;           /* true */
-complex2 : a = 5 or b = 15;           /* true */
-complex3 : not (a = b);               /* true */
-```
-
-### Input/Output and Assertions
-
-```
-/* Interactive input/output */
-..out "Enter your name: ";
-name : ..in;
-..out "Hello, ";
-..out name;
-..out "!";
-
-/* Assertions for testing */
-x : 5;
-y : 3;
-sum : x + y;
-
-..assert x = 5;            /* Passes */
-..assert y = 3;            /* Passes */
-..assert sum = 8;          /* Passes */
-..assert x > 3;            /* Passes */
-..assert y < 10;           /* Passes */
-..assert sum != 0;         /* Passes */
-..assert (add 3 4) = 7;    /* Passes (with parentheses) */
-
-/* String comparisons */
-..assert "hello" = "hello";  /* Passes */
-..assert "world" != "hello"; /* Passes */
-```
-
-### Standard Library Functions
-
-```
-/* Using all standard library functions */
-double : x -> x * 2;
-square : x -> x * x;
-add : x y -> x + y;
+/* Filter */
 isPositive : x -> x > 0;
+filtered : filter @isPositive 5;
 
-/* Map function */
-mapped1 : map @double 5;    /* 10 */
-mapped2 : map @square 3;    /* 9 */
-
-/* Compose function */
-composed : compose @double @square 3;  /* 18 */
-
-/* Pipe function */
-piped : pipe @double @square 2;        /* 16 */
-
-/* Apply function */
-applied : apply @double 7;             /* 14 */
-
-/* Filter function */
-filtered : filter @isPositive 5;       /* 5 (since 5 > 0) */
-filtered2 : filter @isPositive -3;     /* 0 (since -3 <= 0) */
-
-/* Reduce and Fold functions */
-reduced : reduce @add 0 5;             /* 5 */
-folded : fold @add 0 5;                /* 5 */
-
-/* Curry function (explicit currying) */
-curried : curry @add 3 4;              /* 7 */
-```
-
-### Complete Program Example
-
-```
-/* A complete program demonstrating multiple features */
-..out "Welcome to the Calculator!";
-
-/* Define arithmetic functions */
-add : x y -> x + y;
-subtract : x y -> x - y;
-multiply : x y -> x * y;
-divide : x y -> x / y;
-
-/* Define utility functions */
-double : x -> x * 2;
-square : x -> x * x;
-isEven : x -> x % 2 = 0;
-
-/* Get user input */
-..out "Enter first number: ";
-num1 : ..in;
-..out "Enter second number: ";
-num2 : ..in;
-
-/* Perform calculations */
-sum : add num1 num2;
-diff : subtract num1 num2;
-prod : multiply num1 num2;
-quot : divide num1 num2;
-
-/* Display results */
-..out "Sum: ";
-..out sum;
-..out "Difference: ";
-..out diff;
-..out "Product: ";
-..out prod;
-..out "Quotient: ";
-..out quot;
-
-/* Use higher-order functions */
-doubledSum : double sum;
-squaredDiff : square diff;
-
-..out "Doubled sum: ";
-..out doubledSum;
-..out "Squared difference: ";
-..out squaredDiff;
-
-/* Pattern matching for number classification */
-classify : num -> 
-  case num of
-    0 : "zero"
-    _ : case isEven num of
-         true : "even"
-         _    : "odd";
-
-classification : classify num1;
-..out "First number is: ";
-..out classification;
-
-/* Assertions to verify calculations */
-..assert sum = add num1 num2;
-..assert diff = subtract num1 num2;
-..assert prod = multiply num1 num2;
-
-..out "All calculations verified!";
+/* Compose */
+f : x -> x + 1;
+g : x -> x * 2;
+h : compose @f @g;
+result : h 5;  /* (5 * 2) + 1 = 11 */
 ```
 
-## Running Programs
-
-The language supports file execution mode only:
-
-### File Execution Mode
-Run a script file by providing the file path as an argument:
+## Usage
 
+### Running Scripts
 ```bash
 node lang.js script.txt
 ```
 
-**Note:** REPL mode has been removed in the simplified version. The language now only supports file execution.
-
-## Language Design Principles
-
-- **Simplicity**: Minimal syntax for maximum clarity
-- **Immutability**: Variables cannot be reassigned
-- **Functional**: Functions are first-class values with composition support
-- **Pattern-oriented**: Pattern matching as a core feature
-- **Recursive**: Support for recursive function calls in function bodies
-- **Grouped**: Parentheses support for complex arithmetic expressions
-- **Expressive**: Rich set of arithmetic, comparison, and logical operators
-- **IO-aware**: Built-in input/output operations with clear impurity markers
-- **Educational**: Designed to teach language implementation concepts
-
-## Limitations
-
-This is a learning language with intentional limitations:
-- Complex nested function calls (e.g., `add double 3 square 2`) are ambiguous without explicit grouping
-- There's one known issue with function calls inside assertions (e.g., ..assert add 3 4 = 7), which is a parsing edge case. Workaround: use parentheses around function calls in assertions (e.g., ..assert (add 3 4) = 7)
-- Limited to immutable data structures (no mutation operations)
-- No error handling beyond basic validation
-- No modules or imports
-- IO operations are synchronous and block execution
-
-## Future Enhancements
+### Testing
+The project uses a structured testing approach with unit and integration tests:
+
+#### Unit Tests
+Located in `tests/` directory, each focusing on a specific language feature:
+- `01_lexer_basic.txt` - Basic lexer functionality
+- `02_arithmetic_operations.txt` - Arithmetic operations
+- `03_comparison_operators.txt` - Comparison operators
+- `04_logical_operators.txt` - Logical operators
+- `05_io_operations.txt` - IO operations
+- `06_function_definitions.txt` - Function definitions
+- `07_case_expressions.txt` - Case expressions and pattern matching
+- `08_first_class_functions.txt` - First-class function features
+- `09_tables.txt` - Table literals and access
+- `10_standard_library.txt` - Standard library functions
+
+#### Integration Tests
+Test combinations of multiple features:
+- `integration_01_basic_features.txt` - Basic feature combinations
+- `integration_02_pattern_matching.txt` - Pattern matching with other features
+- `integration_03_functional_programming.txt` - Functional programming patterns
+
+#### Running Tests
+```bash
+# Run all tests
+./run_tests.sh
 
-Planned features for future versions:
-- Ambiguous function call detection and error reporting
-- Lists and data structures
-- Error handling
-- Modules and imports
-- Performance optimizations
+# Run individual tests
+node lang.js tests/01_lexer_basic.txt
+node lang.js tests/integration_01_basic_features.txt
+```
 
 ## Implementation Details
 
-The language is implemented in JavaScript with three main components:
-
-1. **Lexer** (`lexer()`): Converts source code to tokens
-2. **Parser** (`parser()`): Builds AST from tokens
-3. **Interpreter** (`interpreter()`): Executes AST
-
-Each component is designed to be modular and extensible for adding new language features.
+### Architecture
+- **Lexer**: Tokenizes input into tokens (numbers, identifiers, operators, etc.)
+- **Parser**: Builds Abstract Syntax Tree (AST) from tokens
+- **Interpreter**: Executes AST with scope management
+
+### Key Components
+- **Token Types**: Supports all basic operators, literals, and special tokens
+- **AST Nodes**: Expression, statement, and declaration nodes
+- **Scope Management**: Lexical scoping with proper variable resolution
+- **Error Handling**: Comprehensive error reporting for parsing and execution
+
+## Recent Fixes
+
+### ✅ 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
+
+### ✅ 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
+
+### 🔄 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**: 🔄 In Progress - 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**: 🔄 In Progress - Related to logical operator precedence issue
+
+## Development
+
+### File Structure
+```
+.
+├── lang.js              # Main implementation
+├── test.txt             # Comprehensive test file
+├── tests/               # Unit and integration tests
+│   ├── 01_lexer_basic.txt
+│   ├── 02_arithmetic_operations.txt
+│   ├── ...
+│   ├── integration_01_basic_features.txt
+│   ├── integration_02_pattern_matching.txt
+│   └── integration_03_functional_programming.txt
+├── run_tests.sh         # Test runner script
+├── FIXME.md             # Issues and fixes documentation
+└── README.md            # This file
+```
+
+### Debugging
+Enable debug mode by setting `DEBUG=true`:
+```bash
+DEBUG=true node lang.js script.txt
+```
 
-## Files
+## Contributing
 
-- `lang.js` - Main language implementation
-- `table_basic_test.txt` - Basic table functionality tests
-- `table_edge_cases_test.txt` - Advanced table edge cases (some features may not work)
-- `README.md` - This documentation
-- `NEXT-STEPS.md` - Development roadmap and notes 
\ No newline at end of file
+1. Create focused unit tests for new features
+2. Add integration tests for feature combinations
+3. Update documentation
+4. Run the full test suite before submitting changes 
\ No newline at end of file
diff --git a/js/scripting-lang/debug_test.txt b/js/scripting-lang/debug_test.txt
new file mode 100644
index 0000000..246c3fd
--- /dev/null
+++ b/js/scripting-lang/debug_test.txt
@@ -0,0 +1,7 @@
+/* Simple test for case expressions */
+factorial : n -> case n of
+    0 : 1
+    _ : n * (factorial (n - 1));
+
+test : factorial 5;
+..out test; 
\ No newline at end of file
diff --git a/js/scripting-lang/func_call_test.txt b/js/scripting-lang/func_call_test.txt
new file mode 100644
index 0000000..826eb4e
--- /dev/null
+++ b/js/scripting-lang/func_call_test.txt
@@ -0,0 +1,8 @@
+/* Test function calls in case expressions */
+add : x y -> x + y;
+factorial : n -> case n of
+    0 : 1
+    _ : add n 1;
+
+test : factorial 5;
+..out test; 
\ No newline at end of file
diff --git a/js/scripting-lang/lang.js b/js/scripting-lang/lang.js
index 3de7a0e..1a0d77e 100644
--- a/js/scripting-lang/lang.js
+++ b/js/scripting-lang/lang.js
@@ -1,10 +1,29 @@
-// The goal here is less to make anything useful...or even something that works, but to learn what parts an interpreted languages needs to have to function.
-
-// Initialize standard library functions
+/**
+ * Initializes the standard library in the provided scope.
+ * 
+ * @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.
+ */
 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 {
@@ -12,17 +31,36 @@ 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') {
-            return f(g(x));
+            if (arguments.length === 3) {
+                return f(g(x));
+            } else {
+                return function(x) {
+                    return f(g(x));
+                };
+            }
         } else {
             throw new Error('compose: first two arguments must be functions');
         }
     };
     
-    // 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);
@@ -31,7 +69,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);
@@ -40,18 +84,35 @@ 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') {
-            return g(f(x));
+            if (arguments.length === 3) {
+                return g(f(x));
+            } else {
+                return function(x) {
+                    return g(f(x));
+                };
+            }
         } else {
             throw new Error('pipe: first two arguments must be functions');
         }
     };
     
-    // 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;
@@ -60,8 +121,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);
@@ -70,7 +137,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);
@@ -80,7 +154,17 @@ function initializeStandardLibrary(scope) {
     };
 }
 
-// Define the types of tokens
+/**
+ * TokenType enumeration for all supported token types.
+ * 
+ * @type {Object.<string, string>}
+ * 
+ * @description A flat object mapping token names to their string representations.
+ * This approach allows for fast string comparisons and easy extensibility.
+ * 
+ * @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',
@@ -124,7 +208,29 @@ const TokenType = {
     FUNCTION_REF: 'FUNCTION_REF'
 };
 
-// Lexer - converts source code to tokens
+/**
+ * Lexer: Converts source code to tokens.
+ * 
+ * @param {string} input - Source code to tokenize
+ * @returns {Array.<Object>} Array of token objects with type and value properties
+ * @throws {Error} For unterminated strings or unexpected characters
+ * 
+ * @description Performs lexical analysis by converting source code into a stream of tokens.
+ * Handles whitespace, nested comments, numbers (integers and decimals), strings, 
+ * identifiers/keywords, and both single- and multi-character operators.
+ * 
+ * @how Uses a single pass with a while loop and manual character inspection. 
+ * Each character is examined to determine the appropriate token type, with 
+ * special handling for multi-character tokens and nested constructs.
+ * 
+ * @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.
+ * 
+ * @note 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.
+ */
 function lexer(input) {
     let current = 0;
     const tokens = [];
@@ -138,7 +244,7 @@ function lexer(input) {
             continue;
         }
         
-        // Skip comments
+        // Handle nested comments: /* ... */ with support for /* /* ... */ */
         if (char === '/' && input[current + 1] === '*') {
             let commentDepth = 1;
             current += 2; // Skip /*
@@ -157,7 +263,7 @@ function lexer(input) {
             continue;
         }
         
-        // Numbers
+        // Parse numbers (integers and decimals)
         if (/[0-9]/.test(char)) {
             let value = '';
             while (current < input.length && /[0-9]/.test(input[current])) {
@@ -189,7 +295,7 @@ function lexer(input) {
             continue;
         }
         
-        // Strings
+        // Parse string literals
         if (char === '"') {
             let value = '';
             current++; // Skip opening quote
@@ -211,7 +317,7 @@ function lexer(input) {
             continue;
         }
         
-        // Identifiers and keywords
+        // Parse identifiers and keywords
         if (/[a-zA-Z_]/.test(char)) {
             let value = '';
             while (current < input.length && /[a-zA-Z0-9_]/.test(input[current])) {
@@ -260,7 +366,7 @@ function lexer(input) {
             continue;
         }
         
-        // Two-character operators
+        // Parse two-character operators
         if (current + 1 < input.length) {
             const twoChar = char + input[current + 1];
             switch (twoChar) {
@@ -285,7 +391,7 @@ function lexer(input) {
                     current += 2;
                     continue;
                 case '..':
-                    // Check for IO operations
+                    // Parse IO operations: ..in, ..out, ..assert
                     if (current + 2 < input.length) {
                         const ioChar = input[current + 2];
                         switch (ioChar) {
@@ -328,7 +434,7 @@ function lexer(input) {
             }
         }
         
-        // Single character operators
+        // Parse single character operators
         switch (char) {
             case '+':
                 tokens.push({ type: TokenType.PLUS });
@@ -400,15 +506,65 @@ function lexer(input) {
         current++;
     }
     
+
+    
     return tokens;
 }
 
-// Parser - converts tokens to AST
+/**
+ * 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
+ * 
+ * @description Implements a recursive descent parser that builds an AST from tokens.
+ * Handles all language constructs including expressions, statements, function 
+ * definitions, case expressions, table literals, and IO operations.
+ * 
+ * @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.
+ * 
+ * @note The parser 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;
+    let parsingFunctionArgs = false; // Flag to track when we're parsing function arguments
     
-    function walk() {
-        function parseChainedDotAccess(tableExpr) {
+    // Reset call stack tracker for parser
+    callStackTracker.reset();
+    
+    // Define all parsing functions outside of walk to avoid circular dependencies
+    
+    function parseChainedDotAccess(tableExpr) {
+        callStackTracker.push('parseChainedDotAccess', '');
+        
+        try {
+            /**
+             * Handles chained dot access (e.g., table.key.subkey).
+             * 
+             * @param {Object} tableExpr - The table expression to chain access from
+             * @returns {Object} AST node representing the chained access
+             * @throws {Error} When expected identifier is missing after dot
+             * 
+             * @description Parses dot notation for table access, building a chain
+             * of TableAccess nodes for nested property access.
+             * 
+             * @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) {
@@ -432,9 +588,29 @@ function parser(tokens) {
             }
             
             return result;
+        } finally {
+            callStackTracker.pop();
         }
+    }
+    
+    function parseChainedTableAccess(tableExpr) {
+        callStackTracker.push('parseChainedTableAccess', '');
         
-        function parseChainedTableAccess(tableExpr) {
+        try {
+            /**
+             * Handles chained bracket and dot access (e.g., table[0].key).
+             * 
+             * @param {Object} tableExpr - The table expression to chain access from
+             * @returns {Object} AST node representing the chained access
+             * @throws {Error} When expected closing bracket is missing
+             * 
+             * @description Parses both bracket and dot notation for table access,
+             * supporting mixed access patterns like 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();
@@ -485,14 +661,167 @@ function parser(tokens) {
             }
             
             return tableExpr;
+        } finally {
+            callStackTracker.pop();
         }
+    }
+    
+    function parseArgument() {
+        callStackTracker.push('parseArgument', '');
         
-        function detectAmbiguousFunctionCalls() {
-            // This is a placeholder for future ambiguous function call detection
-            // For now, we'll assume the parser handles function calls correctly
+        try {
+            const token = tokens[current];
+            if (!token) {
+                throw new Error('Unexpected end of input');
+            }
+            
+            // Parse unary operators
+            if (token.type === TokenType.NOT) {
+                current++;
+                const operand = parseArgument();
+                return { type: 'NotExpression', operand };
+            }
+            
+            if (token.type === TokenType.MINUS) {
+                current++;
+                const operand = parseArgument();
+                return { type: 'UnaryMinusExpression', operand };
+            }
+            
+            // Parse literals
+            if (token.type === TokenType.NUMBER) {
+                current++;
+                return { type: 'NumberLiteral', value: token.value };
+            } else if (token.type === TokenType.STRING) {
+                current++;
+                return { type: 'StringLiteral', value: token.value };
+            } else if (token.type === TokenType.TRUE) {
+                current++;
+                return { type: 'BooleanLiteral', value: true };
+            } else if (token.type === TokenType.FALSE) {
+                current++;
+                return { type: 'BooleanLiteral', value: false };
+            } else if (token.type === TokenType.NULL) {
+                current++;
+                return { type: 'NullLiteral' };
+            } else if (token.type === TokenType.WILDCARD) {
+                current++;
+                return { type: 'WildcardPattern' };
+            } else if (token.type === TokenType.FUNCTION_REF) {
+                current++;
+                if (current < tokens.length && tokens[current].type === TokenType.IDENTIFIER) {
+                    const functionName = tokens[current].value;
+                    current++;
+                    return { type: 'FunctionReference', name: functionName };
+                } else {
+                    throw new Error('Expected function name after @');
+                }
+            } else if (token.type === TokenType.IO_IN) {
+                current++;
+                return { type: 'IOInExpression' };
+            } else if (token.type === TokenType.IO_OUT) {
+                current++;
+                const outputValue = parseLogicalExpression();
+                return { type: 'IOOutExpression', value: outputValue };
+            } else if (token.type === TokenType.IO_ASSERT) {
+                current++;
+                const assertionExpr = parseLogicalExpression();
+                return { type: 'IOAssertExpression', value: assertionExpr };
+            }
+            
+            // Parse identifiers (but NOT as function calls)
+            if (token.type === TokenType.IDENTIFIER) {
+                current++;
+                const identifier = { type: 'Identifier', value: token.value };
+                
+                // Check for table access
+                if (current < tokens.length && tokens[current].type === TokenType.DOT) {
+                    return parseChainedDotAccess(identifier);
+                }
+                
+                // Check for table access with brackets
+                if (current < tokens.length && tokens[current].type === TokenType.LEFT_BRACKET) {
+                    return parseChainedTableAccess(identifier);
+                }
+                
+                return identifier;
+            }
+            
+            // Parse parenthesized expressions
+            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');
+                }
+            }
+            
+            // Parse table literals
+            if (token.type === TokenType.LEFT_BRACE) {
+                current++; // Skip '{'
+                const properties = [];
+                
+                while (current < tokens.length && tokens[current].type !== TokenType.RIGHT_BRACE) {
+                    if (tokens[current].type === TokenType.IDENTIFIER) {
+                        const key = tokens[current].value;
+                        current++;
+                        
+                        if (current < tokens.length && tokens[current].type === TokenType.ASSIGNMENT) {
+                            current++; // Skip ':'
+                            const value = parseLogicalExpression();
+                            properties.push({ key, value });
+                        } else {
+                            throw new Error('Expected ":" after property name in table literal');
+                        }
+                    } else {
+                        throw new Error('Expected property name in table literal');
+                    }
+                    
+                    // Skip comma if present
+                    if (current < tokens.length && tokens[current].type === TokenType.COMMA) {
+                        current++;
+                    }
+                }
+                
+                if (current < tokens.length && tokens[current].type === TokenType.RIGHT_BRACE) {
+                    current++; // Skip '}'
+                    return { type: 'TableLiteral', properties };
+                } else {
+                    throw new Error('Expected closing brace in table literal');
+                }
+            }
+            
+            // If we get here, we have an unexpected token
+            throw new Error(`Unexpected token in parseArgument: ${token.type}`);
+        } finally {
+            callStackTracker.pop();
         }
+    }
+    
+    function parseFunctionCall(functionName) {
+        callStackTracker.push('parseFunctionCall', '');
         
-        function parseFunctionCall(functionName) {
+        try {
+            /**
+             * Parses function calls with arbitrary argument lists.
+             * 
+             * @param {Object|string} functionName - Function name or expression to call
+             * @returns {Object} AST node representing the function call
+             * 
+             * @description Parses function calls by collecting arguments until a 
+             * clear terminator is found, supporting both curried and regular calls.
+             * 
+             * @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.
+             * 
+             * @note Special handling for unary minus arguments to distinguish them
+             * from binary minus operations.
+             */
             const args = [];
             
             // Parse arguments until we hit a semicolon or other terminator
@@ -500,18 +829,117 @@ function parser(tokens) {
                    tokens[current].type !== TokenType.SEMICOLON &&
                    tokens[current].type !== TokenType.RIGHT_PAREN &&
                    tokens[current].type !== TokenType.RIGHT_BRACE &&
-                   tokens[current].type !== TokenType.COMMA) {
-                args.push(parseExpression());
+                   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()
+                        });
+                    }
+                } else {
+                    // Regular argument parsing - parse as expression but skip function call detection
+                    // Create a temporary parsing context that doesn't trigger function call detection
+                    const savedParsingFunctionArgs = parsingFunctionArgs;
+                    parsingFunctionArgs = true; // Temporarily disable function call detection
+                    const arg = parseExpression();
+                    parsingFunctionArgs = savedParsingFunctionArgs; // Restore the flag
+                    args.push(arg);
+                }
             }
-            
+                
             return {
                 type: 'FunctionCall',
                 name: functionName,
                 args: args
             };
+        } finally {
+            callStackTracker.pop();
+        }
+    }
+    
+    function parseLogicalExpression() {
+        callStackTracker.push('parseLogicalExpression', '');
+        
+        try {
+            /**
+             * Parses logical expressions with lowest precedence.
+             * 
+             * @returns {Object} AST node representing the logical expression
+             * 
+             * @description Parses logical operators (and, or, xor) with proper
+             * precedence handling and left associativity.
+             * 
+             * @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;
+        } finally {
+            callStackTracker.pop();
         }
+    }
+    
+    function parseExpression() {
+        callStackTracker.push('parseExpression', '');
         
-        function parseExpression() {
+        try {
+            /**
+             * Parses expressions with left-associative binary operators.
+             * 
+             * @returns {Object} AST node representing the expression
+             * 
+             * @description Parses addition, subtraction, and comparison operators
+             * with proper precedence and associativity.
+             * 
+             * @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.
+             * 
+             * @note Special case handling for unary minus after function references
+             * to distinguish from binary minus operations.
+             */
             let left = parseTerm();
             
             while (current < tokens.length && 
@@ -522,12 +950,18 @@ function parser(tokens) {
                     tokens[current].type === TokenType.LESS_THAN ||
                     tokens[current].type === TokenType.GREATER_THAN ||
                     tokens[current].type === TokenType.LESS_EQUAL ||
-                    tokens[current].type === TokenType.GREATER_EQUAL ||
-                    tokens[current].type === TokenType.AND ||
-                    tokens[current].type === TokenType.OR ||
-                    tokens[current].type === TokenType.XOR)) {
+                    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();
                 
@@ -556,22 +990,31 @@ function parser(tokens) {
                     case TokenType.GREATER_EQUAL:
                         left = { type: 'GreaterEqualExpression', left, right };
                         break;
-                    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;
+        } finally {
+            callStackTracker.pop();
         }
+    }
+    
+    function parseTerm() {
+        callStackTracker.push('parseTerm', '');
         
-        function parseTerm() {
+        try {
+            /**
+             * Parses multiplication, division, and modulo operations.
+             * 
+             * @returns {Object} AST node representing the term
+             * 
+             * @description Parses multiplicative operators with higher precedence
+             * than addition/subtraction.
+             * 
+             * @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 && 
@@ -597,9 +1040,27 @@ function parser(tokens) {
             }
             
             return left;
+        } finally {
+            callStackTracker.pop();
         }
+    }
+    
+    function parseFactor() {
+        callStackTracker.push('parseFactor', '');
         
-        function parseFactor() {
+        try {
+            /**
+             * Parses exponentiation and primary expressions.
+             * 
+             * @returns {Object} AST node representing the factor
+             * 
+             * @description Parses exponentiation with right associativity and
+             * highest precedence among arithmetic operators.
+             * 
+             * @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) {
@@ -609,52 +1070,186 @@ function parser(tokens) {
             }
             
             return left;
+        } finally {
+            callStackTracker.pop();
         }
+    }
+    
+    function parsePrimary() {
+        callStackTracker.push('parsePrimary', '');
         
-        function parsePrimary() {
+        try {
+            /**
+             * Parses literals, identifiers, function definitions, assignments, 
+             * table literals, and parenthesized expressions.
+             * 
+             * @returns {Object} AST node representing the primary expression
+             * @throws {Error} For parsing errors like unexpected tokens
+             * 
+             * @description The core parsing function that handles all atomic and 
+             * context-sensitive constructs in the language.
+             * 
+             * @why This function is the core of the recursive descent parser, handling 
+             * all atomic and context-sensitive constructs. Special care is taken to 
+             * avoid circular dependencies by not calling higher-level parsing functions.
+             */
+            
             const token = tokens[current];
+            if (!token) {
+                throw new Error('Unexpected end of input');
+            }
             
+            // Parse unary operators
             if (token.type === TokenType.NOT) {
                 current++;
                 const operand = parsePrimary();
                 return { type: 'NotExpression', operand };
             }
             
-            if (token.type === TokenType.NUMBER) {
+            if (token.type === TokenType.MINUS) {
                 current++;
-                return {
-                    type: 'NumberLiteral',
-                    value: token.value
-                };
+                const operand = parsePrimary();
+                return { type: 'UnaryMinusExpression', operand };
             }
             
-            if (token.type === TokenType.STRING) {
+            // Parse literals
+            if (token.type === TokenType.NUMBER) {
                 current++;
-                return {
-                    type: 'StringLiteral',
-                    value: token.value
-                };
-            }
-            
-            if (token.type === TokenType.TRUE) {
+                return { type: 'NumberLiteral', value: token.value };
+            } else if (token.type === TokenType.STRING) {
                 current++;
-                return {
-                    type: 'BooleanLiteral',
-                    value: true
-                };
+                return { type: 'StringLiteral', value: token.value };
+            } else if (token.type === TokenType.TRUE) {
+                current++;
+                return { type: 'BooleanLiteral', value: true };
+            } else if (token.type === TokenType.FALSE) {
+                current++;
+                return { type: 'BooleanLiteral', value: false };
+            } else if (token.type === TokenType.NULL) {
+                current++;
+                return { type: 'NullLiteral' };
+            } else if (token.type === TokenType.WILDCARD) {
+                current++;
+                return { type: 'WildcardPattern' };
+            } else if (token.type === TokenType.FUNCTION_REF) {
+                current++;
+                if (current < tokens.length && tokens[current].type === TokenType.IDENTIFIER) {
+                    const functionName = tokens[current].value;
+                    current++;
+                    return { type: 'FunctionReference', name: functionName };
+                } else {
+                    throw new Error('Expected function name after @');
+                }
+            } else if (token.type === TokenType.IO_IN) {
+                current++;
+                return { type: 'IOInExpression' };
+            } else if (token.type === TokenType.IO_OUT) {
+                current++;
+                const outputValue = parseLogicalExpression();
+                return { type: 'IOOutExpression', value: outputValue };
+            } else if (token.type === TokenType.IO_ASSERT) {
+                current++;
+                const assertionExpr = parseLogicalExpression();
+                return { type: 'IOAssertExpression', value: assertionExpr };
             }
             
-            if (token.type === TokenType.FALSE) {
+            // Parse identifiers
+            if (token.type === TokenType.IDENTIFIER) {
                 current++;
-                return {
-                    type: 'BooleanLiteral',
-                    value: false
-                };
+                const identifier = { type: 'Identifier', value: token.value };
+                
+                // Skip function call detection if we're parsing function arguments
+                if (parsingFunctionArgs) {
+                    return identifier;
+                }
+                
+                // Check for function calls
+                if (current < tokens.length && tokens[current].type === TokenType.LEFT_PAREN) {
+                    return parseFunctionCall(identifier.value);
+                }
+                
+                // Check if the next token is an operator - if so, don't treat as function call
+                if (current < tokens.length && 
+                    (tokens[current].type === TokenType.PLUS ||
+                     tokens[current].type === TokenType.MINUS ||
+                     tokens[current].type === TokenType.MULTIPLY ||
+                     tokens[current].type === TokenType.DIVIDE ||
+                     tokens[current].type === TokenType.MODULO ||
+                     tokens[current].type === TokenType.POWER)) {
+                    // This is part of a binary expression, don't treat as function call
+                    return identifier;
+                }
+                
+                // Check for function calls without parentheses (e.g., add 3 4)
+                // Only treat as function call if the next token is a number, string, or left paren
+                // This prevents treating identifiers as function calls when they're actually arguments
+                if (current < tokens.length && 
+                    (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.value);
+                }
+                
+                // Special case for unary minus: only treat as function call if it's a unary minus
+                if (current < tokens.length && tokens[current].type === TokenType.MINUS) {
+                    // Look ahead to see if this is a unary minus (like -5) or binary minus (like n - 1)
+                    const nextToken = current + 1 < tokens.length ? tokens[current + 1] : null;
+                    if (nextToken && nextToken.type === TokenType.NUMBER) {
+                        // This is a unary minus, treat as function call
+                        return parseFunctionCall(identifier.value);
+                    }
+                    // This is a binary minus, don't treat as function call
+                }
+                
+                // Special case for function calls with identifier arguments (e.g., add x y)
+                // Only treat as function call if the next token is an identifier and not followed by an operator
+                if (!parsingFunctionArgs && current < tokens.length && tokens[current].type === TokenType.IDENTIFIER) {
+                    // Look ahead to see if the next token is an identifier followed by an operator
+                    const nextToken = current + 1 < tokens.length ? tokens[current + 1] : null;
+                    const nextNextToken = current + 2 < tokens.length ? tokens[current + 2] : null;
+                    
+                    // Only treat as function call if the next token is an identifier and not followed by an operator
+                    if (nextToken && nextToken.type === TokenType.IDENTIFIER && 
+                        (!nextNextToken || 
+                         (nextNextToken.type !== TokenType.PLUS &&
+                          nextNextToken.type !== TokenType.MINUS &&
+                          nextNextToken.type !== TokenType.MULTIPLY &&
+                          nextNextToken.type !== TokenType.DIVIDE &&
+                          nextNextToken.type !== TokenType.MODULO &&
+                          nextNextToken.type !== TokenType.POWER &&
+                          nextNextToken.type !== TokenType.EQUALS &&
+                          nextNextToken.type !== TokenType.NOT_EQUAL &&
+                          nextNextToken.type !== TokenType.LESS_THAN &&
+                          nextNextToken.type !== TokenType.GREATER_THAN &&
+                          nextNextToken.type !== TokenType.LESS_EQUAL &&
+                          nextNextToken.type !== TokenType.GREATER_EQUAL))) {
+                        if (process.env.DEBUG) {
+                            console.log(`[DEBUG] Creating function call for ${identifier.value} at position ${current}`);
+                        }
+                        return parseFunctionCall(identifier.value);
+                    }
+                }
+                
+
+                
+                // Check for table access
+                if (current < tokens.length && tokens[current].type === TokenType.DOT) {
+                    return parseChainedDotAccess(identifier);
+                }
+                
+                // Check for table access with brackets
+                if (current < tokens.length && tokens[current].type === TokenType.LEFT_BRACKET) {
+                    return parseChainedTableAccess(identifier);
+                }
+                
+                return identifier;
             }
             
+            // Parse parenthesized expressions
             if (token.type === TokenType.LEFT_PAREN) {
                 current++; // Skip '('
-                const parenthesizedExpr = parseExpression();
+                const parenthesizedExpr = parseLogicalExpression();
                 
                 if (current < tokens.length && tokens[current].type === TokenType.RIGHT_PAREN) {
                     current++; // Skip ')'
@@ -664,272 +1259,636 @@ function parser(tokens) {
                 }
             }
             
-            if (token.type === TokenType.IDENTIFIER) {
-                const identifier = {
-                    type: 'Identifier',
-                    value: token.value
-                };
-                current++;
+            // Parse table literals
+            if (token.type === TokenType.LEFT_BRACE) {
+                current++; // Skip '{'
+                const properties = [];
                 
-                // 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);
+                while (current < tokens.length && tokens[current].type !== TokenType.RIGHT_BRACE) {
+                    if (tokens[current].type === TokenType.IDENTIFIER) {
+                        const key = tokens[current].value;
+                        current++;
+                        
+                        if (current < tokens.length && tokens[current].type === TokenType.ASSIGNMENT) {
+                            current++; // Skip ':'
+                            const value = parseLogicalExpression();
+                            properties.push({ key, value });
+                        } else {
+                            throw new Error('Expected ":" after property name in table literal');
                         }
-                        lookAhead++;
-                    }
-                    
-                    if (lookAhead < tokens.length && tokens[lookAhead].type === TokenType.ARROW) {
-                        isFunction = true;
+                    } else {
+                        throw new Error('Expected property name in table literal');
                     }
                     
-                    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++;
-                        }
-                        
-                        current++; // Skip '->'
-                        
-                        // Parse the function body (which could be a case expression or other expression)
-                        const functionBody = parseExpression();
-                        
-                        return {
-                            type: 'AssignmentExpression',
-                            name: identifier.value,
-                            value: {
-                                type: 'FunctionDeclaration',
-                                name: null, // Anonymous function
-                                params,
-                                body: functionBody,
-                            }
-                        };
-                    } else {
-                        // Regular assignment
-                        const value = parseExpression();
-                        return {
-                            type: 'AssignmentExpression',
-                            name: identifier.value,
-                            value: value
-                        };
+                    // Skip comma if present
+                    if (current < tokens.length && tokens[current].type === TokenType.COMMA) {
+                        current++;
                     }
                 }
                 
-                // Check if this is table access
-                if (current < tokens.length && 
-                    (tokens[current].type === TokenType.LEFT_BRACKET ||
-                     tokens[current].type === TokenType.DOT)) {
-                    return parseChainedTableAccess(identifier);
+                if (current < tokens.length && tokens[current].type === TokenType.RIGHT_BRACE) {
+                    current++; // Skip '}'
+                    return { type: 'TableLiteral', properties };
+                } else {
+                    throw new Error('Expected closing brace in table literal');
                 }
+            }
+            
+            // Parse arrow expressions (function definitions)
+            if (token.type === TokenType.ARROW) {
+                current++; // Skip '->'
                 
-                // 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(identifier);
-                }
+                // Parse the function body
+                const body = parseLogicalExpression();
                 
-                return identifier;
+                return { type: 'ArrowExpression', body };
             }
             
-            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 @');
-                }
-            }
 
-            if (token.type === TokenType.WILDCARD) {
-                current++; // Skip '_'
-                return { type: 'WildcardPattern' };
-            }
+            
 
-            if (token.type === TokenType.CASE) {
-                current++; // Skip 'case'
-                
-                // Parse the value being matched
-                const value = parseExpression();
+            
+            // If we get here, we have an unexpected token
+            throw new Error(`Unexpected token in parsePrimary: ${token.type}`);
+        } finally {
+            callStackTracker.pop();
+        }
+    }
+    
+    function walk() {
+        callStackTracker.push('walk', `position:${current}`);
+        
+        try {
+            
+
+            
+
+            
+            function parseLogicalExpression() {
+                callStackTracker.push('parseLogicalExpression', '');
                 
-                // Expect 'of'
-                if (tokens[current].type !== TokenType.OF) {
-                    throw new Error('Expected "of" after "case"');
+                try {
+                    /**
+                     * Parses logical expressions with lowest precedence.
+                     * 
+                     * @returns {Object} AST node representing the logical expression
+                     * 
+                     * @description Parses logical operators (and, or, xor) with proper
+                     * precedence handling and left associativity.
+                     * 
+                     * @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;
+                } finally {
+                    callStackTracker.pop();
                 }
-                current++; // Skip 'of'
+            }
+            
+            function parseExpression() {
+                callStackTracker.push('parseExpression', '');
                 
-                const cases = [];
+                try {
+                    /**
+                     * Parses expressions with left-associative binary operators.
+                     * 
+                     * @returns {Object} AST node representing the expression
+                     * 
+                     * @description Parses addition, subtraction, and comparison operators
+                     * with proper precedence and associativity.
+                     * 
+                     * @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.
+                     * 
+                     * @note Special case handling for unary minus after function references
+                     * to distinguish from binary minus 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;
+                } finally {
+                    callStackTracker.pop();
+                }
+            }
+            
+            function parseTerm() {
+                callStackTracker.push('parseTerm', '');
                 
-                // Parse cases until we hit a semicolon or end
-                while (current < tokens.length && tokens[current].type !== TokenType.SEMICOLON) {
-                    const pattern = parseExpression();
+                try {
+                    /**
+                     * Parses multiplication, division, and modulo operations.
+                     * 
+                     * @returns {Object} AST node representing the term
+                     * 
+                     * @description Parses multiplicative operators with higher precedence
+                     * than addition/subtraction.
+                     * 
+                     * @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();
                     
-                    // Expect ':' after pattern
-                    if (current < tokens.length && tokens[current].type === TokenType.ASSIGNMENT) {
-                        current++; // Skip ':'
-                    } else {
-                        throw new Error('Expected ":" after pattern in case expression');
+                    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;
+                        }
                     }
                     
-                    const result = parseExpression();
-                    cases.push({ 
-                        pattern: [pattern], 
-                        result: [result] 
-                    });
+                    return left;
+                } finally {
+                    callStackTracker.pop();
                 }
+            }
+            
+            function parseFactor() {
+                callStackTracker.push('parseFactor', '');
                 
-                return {
-                    type: 'CaseExpression',
-                    value: [value],
-                    cases,
-                };
+                try {
+                    /**
+                     * Parses exponentiation and primary expressions.
+                     * 
+                     * @returns {Object} AST node representing the factor
+                     * 
+                     * @description Parses exponentiation with right associativity and
+                     * highest precedence among arithmetic operators.
+                     * 
+                     * @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;
+                } finally {
+                    callStackTracker.pop();
+                }
+            }
+            
+            // Check for IO operations first
+            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 };
             }
             
 
             
-            // 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;
+            // Check for assignments (identifier followed by ':')
+            if (tokens[current].type === TokenType.IDENTIFIER) {
+                const identifier = tokens[current].value;
+                current++;
                 
-                while (current < tokens.length && tokens[current].type !== TokenType.RIGHT_BRACE) {
-                    // Skip leading commas
-                    if (tokens[current].type === TokenType.COMMA) {
-                        current++;
-                        continue;
-                    }
+                if (current < tokens.length && tokens[current].type === TokenType.ASSIGNMENT) {
+                    current++; // Skip ':'
                     
-                    let key = null;
-                    let value;
+                    // Check if this is a function definition with arrow syntax (x y -> body)
+                    // Look ahead to see if we have parameters followed by ->
+                    const lookAheadTokens = [];
+                    let lookAheadPos = current;
                     
-                    // 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,
+                    // Collect tokens until we find -> or hit a terminator
+                    while (lookAheadPos < tokens.length && 
+                           tokens[lookAheadPos].type !== TokenType.ARROW &&
+                           tokens[lookAheadPos].type !== TokenType.SEMICOLON &&
+                           tokens[lookAheadPos].type !== TokenType.ASSIGNMENT) {
+                        lookAheadTokens.push(tokens[lookAheadPos]);
+                        lookAheadPos++;
+                    }
+                    
+                    // If we found ->, this is a function definition with arrow syntax
+                    if (lookAheadPos < tokens.length && tokens[lookAheadPos].type === TokenType.ARROW) {
+                        // Parse parameters (identifiers separated by spaces)
+                        const parameters = [];
+                        let paramIndex = 0;
+                        
+                        while (paramIndex < lookAheadTokens.length) {
+                            if (lookAheadTokens[paramIndex].type === TokenType.IDENTIFIER) {
+                                parameters.push(lookAheadTokens[paramIndex].value);
+                                paramIndex++;
+                            } else {
+                                // Skip non-identifier tokens (spaces, etc.)
+                                paramIndex++;
+                            }
+                        }
+                        
+                        // Skip the parameters and ->
+                        current = lookAheadPos + 1; // Skip the arrow
+                        
+                        // Parse the function body (check if it's a case expression)
+                        let functionBody;
+                        if (current < tokens.length && tokens[current].type === TokenType.CASE) {
+                            // Parse case expression directly
+                            current++; // Skip 'case'
+                            
+                            // Parse the values being matched (can be multiple)
+                            const values = [];
+                            while (current < tokens.length && tokens[current].type !== TokenType.OF) {
+                                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 {
+                                    const value = parsePrimary();
+                                    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) {
+                                // If we hit an IO operation, we've reached the end of the case expression
+                                if (current < tokens.length && 
+                                    (tokens[current].type === TokenType.IO_IN ||
+                                     tokens[current].type === TokenType.IO_OUT ||
+                                     tokens[current].type === TokenType.IO_ASSERT)) {
+                                    break;
+                                }
+                                const patterns = [];
+                                while (current < tokens.length && 
+                                       tokens[current].type !== TokenType.ASSIGNMENT && 
+                                       tokens[current].type !== TokenType.SEMICOLON) {
+                                    patterns.push(parsePrimary());
+                                }
+                                
+                                // Expect ':' after pattern
+                                if (current < tokens.length && tokens[current].type === TokenType.ASSIGNMENT) {
+                                    current++; // Skip ':'
+                                } else {
+                                    throw new Error('Expected ":" after pattern in case expression');
+                                }
+                                
+                                // Temporarily disable function call detection when parsing case expression results
+                                const savedParsingFunctionArgs = parsingFunctionArgs;
+                                parsingFunctionArgs = true; // Disable function call detection
+                                const result = parseLogicalExpression();
+                                parsingFunctionArgs = savedParsingFunctionArgs; // Restore the flag
+                                cases.push({ 
+                                    pattern: patterns, 
+                                    result: [result] 
+                                });
+                                
+                                // Skip semicolon if present (but don't stop parsing cases)
+                                if (current < tokens.length && tokens[current].type === TokenType.SEMICOLON) {
+                                    current++;
+                                    // If the next token is an identifier followed by assignment, we've reached the end of the case expression
+                                    if (current < tokens.length && tokens[current].type === TokenType.IDENTIFIER) {
+                                        const nextPos = current + 1;
+                                        if (nextPos < tokens.length && tokens[nextPos].type === TokenType.ASSIGNMENT) {
+                                            break; // End of case expression
+                                        }
+                                    }
+                                }
+                            }
+                            
+                            functionBody = {
+                                type: 'CaseExpression',
+                                value: values,
+                                cases,
                             };
-                            current++; // Skip the key
                         } else {
-                            throw new Error('Invalid key type in table literal');
+                            functionBody = parseLogicalExpression();
                         }
                         
-                        current++; // Skip ':'
-                        value = parseExpression();
-                    } else {
-                        // This is just a value (array-like entry)
-                        value = parseExpression();
+                        return {
+                            type: 'Assignment',
+                            identifier,
+                            value: {
+                                type: 'FunctionDefinition',
+                                parameters,
+                                body: functionBody
+                            }
+                        };
                     }
                     
-                    entries.push({ key, value });
-                    
-                    // Skip trailing commas
-                    if (current < tokens.length && tokens[current].type === TokenType.COMMA) {
-                        current++;
+                    // Check if this is a function definition with 'function' keyword
+                    if (current < tokens.length && tokens[current].type === TokenType.FUNCTION) {
+                        current++; // Skip 'function'
+                        
+                        if (current >= tokens.length || tokens[current].type !== TokenType.LEFT_PAREN) {
+                            throw new Error('Expected "(" after "function"');
+                        }
+                        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++;
+                            } else {
+                                throw new Error('Expected parameter name in function definition');
+                            }
+                            
+                            // Skip comma if present
+                            if (current < tokens.length && tokens[current].type === TokenType.COMMA) {
+                                current++;
+                            }
+                        }
+                        
+                        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 ':'
+                        
+                        // Parse the function body (check if it's a case expression)
+                        let functionBody;
+                        if (current < tokens.length && tokens[current].type === TokenType.CASE) {
+                            // Parse case expression directly
+                            current++; // Skip 'case'
+                            
+                            // Parse the values being matched (can be multiple)
+                            const values = [];
+                            while (current < tokens.length && tokens[current].type !== TokenType.OF) {
+                                const value = parsePrimary();
+                                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) {
+                                // If we hit an IO operation, we've reached the end of the case expression
+                                if (current < tokens.length && 
+                                    (tokens[current].type === TokenType.IO_IN ||
+                                     tokens[current].type === TokenType.IO_OUT ||
+                                     tokens[current].type === TokenType.IO_ASSERT)) {
+                                    break;
+                                }
+                                const patterns = [];
+                                while (current < tokens.length && 
+                                       tokens[current].type !== TokenType.ASSIGNMENT && 
+                                       tokens[current].type !== TokenType.SEMICOLON) {
+                                    patterns.push(parsePrimary());
+                                }
+                                
+                                // 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] 
+                                });
+                                
+                                // Skip semicolon if present (but don't stop parsing cases)
+                                if (current < tokens.length && tokens[current].type === TokenType.SEMICOLON) {
+                                    current++;
+                                    // If the next token is an identifier followed by assignment, we've reached the end of the case expression
+                                    if (current < tokens.length && tokens[current].type === TokenType.IDENTIFIER) {
+                                        const nextPos = current + 1;
+                                        if (nextPos < tokens.length && tokens[nextPos].type === TokenType.ASSIGNMENT) {
+                                            break; // End of case expression
+                                        }
+                                    }
+                                }
+                            }
+                            
+                            functionBody = {
+                                type: 'CaseExpression',
+                                value: values,
+                                cases,
+                            };
+                        } else {
+                            functionBody = parseLogicalExpression();
+                        }
+                        
+                        return {
+                            type: 'Assignment',
+                            identifier,
+                            value: {
+                                type: 'FunctionDefinition',
+                                parameters,
+                                body: functionBody
+                            }
+                        };
+                    } else {
+                        // Check if this is a case expression
+                        if (current < tokens.length && tokens[current].type === TokenType.CASE) {
+                            // Parse the case expression directly
+                            current++; // Skip 'case'
+                            
+                            // Parse the values being matched (can be multiple)
+                            const values = [];
+                            while (current < tokens.length && tokens[current].type !== TokenType.OF) {
+                                const value = parsePrimary();
+                                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) {
+                                // If we hit an IO operation, we've reached the end of the case expression
+                                if (current < tokens.length && 
+                                    (tokens[current].type === TokenType.IO_IN ||
+                                     tokens[current].type === TokenType.IO_OUT ||
+                                     tokens[current].type === TokenType.IO_ASSERT)) {
+                                    break;
+                                }
+                                const patterns = [];
+                                while (current < tokens.length && 
+                                       tokens[current].type !== TokenType.ASSIGNMENT && 
+                                       tokens[current].type !== TokenType.SEMICOLON) {
+                                    patterns.push(parsePrimary());
+                                }
+                                
+                                // 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] 
+                                });
+                                
+                                // Skip semicolon if present (but don't stop parsing cases)
+                                if (current < tokens.length && tokens[current].type === TokenType.SEMICOLON) {
+                                    current++;
+                                    // If the next token is an identifier followed by assignment, we've reached the end of the case expression
+                                    if (current < tokens.length && tokens[current].type === TokenType.IDENTIFIER) {
+                                        const nextPos = current + 1;
+                                        if (nextPos < tokens.length && tokens[nextPos].type === TokenType.ASSIGNMENT) {
+                                            break; // End of case expression
+                                        }
+                                    }
+                                }
+                            }
+                            
+                            return {
+                                type: 'Assignment',
+                                identifier,
+                                value: {
+                                    type: 'CaseExpression',
+                                    value: values,
+                                    cases,
+                                }
+                            };
+                        } else {
+                            // Regular assignment
+                            const value = parseLogicalExpression();
+                            
+                            return {
+                                type: 'Assignment',
+                                identifier,
+                                value
+                            };
+                        }
                     }
                 }
                 
-                if (current < tokens.length && tokens[current].type === TokenType.RIGHT_BRACE) {
-                    current++; // Skip '}'
-                    return {
-                        type: 'TableLiteral',
-                        entries: entries
-                    };
-                } 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 it's not an assignment, put the identifier back and continue
+                current--;
             }
             
-            // 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 = parseExpression();
-            return { type: 'IOOutExpression', value: outputValue };
-        } else if (tokens[current].type === TokenType.IO_ASSERT) {
-            current++;
-            const assertionExpr = parseExpression();
-            return { type: 'IOAssertExpression', value: assertionExpr };
+            // For all other token types (identifiers, numbers, operators, etc.), call parsePrimary
+            // This handles atomic expressions and delegates to the appropriate parsing functions
+            return parsePrimary();
+        } finally {
+            callStackTracker.pop();
         }
-        
-        // Simple wrapper that calls parsePrimary for all token types
-        return parsePrimary();
     }
     
     const ast = {
@@ -937,7 +1896,28 @@ function parser(tokens) {
         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);
@@ -952,634 +1932,788 @@ function parser(tokens) {
     return ast;
 }
 
-// Interpreter
+/**
+ * Interpreter: Walks the AST and evaluates each node.
+ * 
+ * @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.
+ * 
+ * @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.
+ * 
+ * @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.
+ * 
+ * @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 interpreter(ast) {
     const globalScope = {};
     initializeStandardLibrary(globalScope);
     
+    // 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) {
-        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 '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;
+        callStackTracker.push('evalNode', 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 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 {
-                            // For other key types (numbers, strings), evaluate normally
-                            key = evalNode(entry.key);
+                            // 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;
                         }
-                        const value = evalNode(entry.value);
-                        table[key] = value;
                     }
-                }
-                
-                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];
+                    
+                    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);
                     }
-                    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];
-                        
-                        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 (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 'Assignment':
+                    if (globalScope.hasOwnProperty(node.identifier)) {
+                        throw new Error(`Cannot reassign immutable variable: ${node.identifier}`);
+                    }
+                    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`);
+                    }
+                    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; // 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 (matches) {
-                        const results = caseItem.result.map(evalNode);
-                        if (results.length === 1) {
-                            return results[0];
+                    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];
+                            
+                            if (patternValue === true) continue;
+                            
+                            if (value !== patternValue) {
+                                matches = false;
+                                break;
+                            }
+                        }
+                        
+                        if (matches) {
+                            const results = caseItem.result.map(evalNode);
+                            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 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();
         }
     }
 
+    /**
+     * 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) => {
-        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 '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;
+        callStackTracker.push('localEvalNodeWithScope', 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 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 {
-                            // 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 = localEvalNodeWithScope(entry.key, scope);
+                            }
+                            const value = localEvalNodeWithScope(entry.value, scope);
+                            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 = 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);
                     }
-                    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 (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) {
+                        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();
                         }
+                    };
+                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 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));
                     
-                    if (matches) {
-                        const results = caseItem.result.map(res => localEvalNodeWithScope(res, scope));
-                        if (results.length === 1) {
-                            return results[0];
+                    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 (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 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}`);
+                    
+                    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();
         }
     };
 
+    /**
+     * 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) => {
-        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 '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;
+        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 = localEvalNode(entry.key);
+                            // 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 = localEvalNode(entry.value);
-                        table[key] = value;
                     }
-                }
-                
-                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];
+                    
+                    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 = 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);
                     
-                    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 (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) {
+                        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();
                         }
+                    };
+                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 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 (matches) {
-                        const results = caseItem.result.map(localEvalNode);
-                        if (results.length === 1) {
-                            return results[0];
+                    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);
+                        
+                        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 (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();
         }
     };
 
@@ -1599,7 +2733,20 @@ function interpreter(ast) {
     return lastResult;
 }
 
-// Debug logging function
+/**
+ * Debug logging utility function.
+ * 
+ * @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) {
         console.log(`[DEBUG] ${message}`);
@@ -1609,7 +2756,20 @@ function debugLog(message, data = null) {
     }
 }
 
-// Debug error function
+/**
+ * Debug error logging utility function.
+ * 
+ * @param {string} message - Debug error message to log
+ * @param {Error} [error=null] - Optional error object to log
+ * 
+ * @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) {
         console.error(`[DEBUG ERROR] ${message}`);
@@ -1619,9 +2779,110 @@ function debugError(message, error = null) {
     }
 }
 
-// Execute a file
+/**
+ * Call stack tracking for debugging recursion issues.
+ * 
+ * @description Tracks function calls to help identify infinite recursion
+ * and deep call stacks that cause stack overflow errors.
+ */
+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();
+    }
+};
+
+/**
+ * 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.
+ */
 function executeFile(filePath) {
     try {
+        // Validate file extension
+        if (!filePath.endsWith('.txt')) {
+            throw new Error('Only .txt files are supported');
+        }
+        
         const fs = require('fs');
         const input = fs.readFileSync(filePath, 'utf8');
         
@@ -1640,20 +2901,52 @@ 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);
     }
 }
 
-// Check command line arguments
+/**
+ * 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.
+ * 
+ * @note Exits with appropriate error codes for different failure scenarios.
+ */
 const args = process.argv.slice(2);
 
 if (args.length === 0) {
diff --git a/js/scripting-lang/learn_scripting_lang.txt b/js/scripting-lang/learn_scripting_lang.txt
new file mode 100644
index 0000000..fc4f966
--- /dev/null
+++ b/js/scripting-lang/learn_scripting_lang.txt
@@ -0,0 +1,61 @@
+/* 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/nested_test.txt b/js/scripting-lang/nested_test.txt
new file mode 100644
index 0000000..afb0677
--- /dev/null
+++ b/js/scripting-lang/nested_test.txt
@@ -0,0 +1,7 @@
+/* Test nested function calls in case expressions */
+factorial : n -> case n of
+    0 : 1
+    _ : factorial (n - 1);
+
+test : factorial 5;
+..out test; 
\ No newline at end of file
diff --git a/js/scripting-lang/paren_test.txt b/js/scripting-lang/paren_test.txt
new file mode 100644
index 0000000..990858b
--- /dev/null
+++ b/js/scripting-lang/paren_test.txt
@@ -0,0 +1,7 @@
+/* Test parentheses in case expressions */
+factorial : n -> case n of
+    0 : 1
+    _ : (n - 1);
+
+test : factorial 5;
+..out test; 
\ No newline at end of file
diff --git a/js/scripting-lang/run_tests.sh b/js/scripting-lang/run_tests.sh
new file mode 100755
index 0000000..b456ff0
--- /dev/null
+++ b/js/scripting-lang/run_tests.sh
@@ -0,0 +1,123 @@
+#!/bin/bash
+
+# Test Runner for Simple Scripting Language
+# Runs unit tests and integration tests systematically
+
+echo "=== Simple Scripting Language Test Suite ==="
+echo ""
+
+# Colors for output
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+NC='\033[0m' # No Color
+
+# Function to run a test
+run_test() {
+    local test_file=$1
+    local test_name=$2
+    
+    echo -n "Running $test_name... "
+    
+    # Capture both stdout and stderr, and get the exit code
+    local output
+    local exit_code
+    output=$(node lang.js "$test_file" 2>&1)
+    exit_code=$?
+    
+    if [ $exit_code -eq 0 ]; then
+        echo -e "${GREEN}PASS${NC}"
+        return 0
+    else
+        echo -e "${RED}FAIL${NC}"
+        echo -e "${RED}Error:${NC} $output"
+        return 1
+    fi
+}
+
+# Function to run a test with output
+run_test_with_output() {
+    local test_file=$1
+    local test_name=$2
+    
+    echo -e "${YELLOW}=== $test_name ===${NC}"
+    node lang.js "$test_file"
+    echo ""
+}
+
+# Counters
+total_tests=0
+passed_tests=0
+failed_tests=0
+
+echo "Running Unit Tests..."
+echo "===================="
+
+# Unit tests
+unit_tests=(
+    "tests/01_lexer_basic.txt:Basic Lexer"
+    "tests/02_arithmetic_operations.txt:Arithmetic Operations"
+    "tests/03_comparison_operators.txt:Comparison Operators"
+    "tests/04_logical_operators.txt:Logical Operators"
+    "tests/05_io_operations.txt:IO Operations"
+    "tests/06_function_definitions.txt:Function Definitions"
+    "tests/07_case_expressions.txt:Case Expressions"
+    "tests/08_first_class_functions.txt:First-Class Functions"
+    "tests/09_tables.txt:Tables"
+    "tests/10_standard_library.txt:Standard Library"
+    "tests/11_edge_cases.txt:Edge Cases"
+    "tests/12_advanced_tables.txt:Advanced Tables"
+    "tests/13_standard_library_complete.txt:Complete Standard Library"
+    "tests/14_error_handling.txt:Error Handling"
+    # "tests/15_performance_stress.txt:Performance and Stress"
+    # "tests/16_advanced_functional.txt:Advanced Functional Programming"
+    # "tests/17_real_world_scenarios.txt:Real-World Scenarios"
+)
+
+for test in "${unit_tests[@]}"; do
+    IFS=':' read -r file name <<< "$test"
+    total_tests=$((total_tests + 1))
+    
+    if run_test "$file" "$name"; then
+        passed_tests=$((passed_tests + 1))
+    else
+        failed_tests=$((failed_tests + 1))
+    fi
+done
+
+echo ""
+echo "Running Integration Tests..."
+echo "==========================="
+
+# Integration tests
+integration_tests=(
+    "tests/integration_01_basic_features.txt:Basic Features Integration"
+    "tests/integration_02_pattern_matching.txt:Pattern Matching Integration"
+    "tests/integration_03_functional_programming.txt:Functional Programming Integration"
+    "tests/integration_04_mini_case_multi_param.txt:Multi-parameter case expression at top level"
+)
+
+for test in "${integration_tests[@]}"; do
+    IFS=':' read -r file name <<< "$test"
+    total_tests=$((total_tests + 1))
+    
+    if run_test "$file" "$name"; then
+        passed_tests=$((passed_tests + 1))
+    else
+        failed_tests=$((failed_tests + 1))
+    fi
+done
+
+echo ""
+echo "=== Test Summary ==="
+echo "Total tests: $total_tests"
+echo -e "Passed: ${GREEN}$passed_tests${NC}"
+echo -e "Failed: ${RED}$failed_tests${NC}"
+
+if [ $failed_tests -eq 0 ]; then
+    echo -e "${GREEN}All tests passed!${NC}"
+    exit 0
+else
+    echo -e "${RED}Some tests failed.${NC}"
+    exit 1
+fi 
\ No newline at end of file
diff --git a/js/scripting-lang/simple_case_test.txt b/js/scripting-lang/simple_case_test.txt
new file mode 100644
index 0000000..bfc4768
--- /dev/null
+++ b/js/scripting-lang/simple_case_test.txt
@@ -0,0 +1,7 @@
+/* Simple case expression test */
+factorial : n -> case n of
+    0 : 1
+    _ : 2;
+
+test : factorial 5;
+..out test; 
\ 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..5f1c5df
--- /dev/null
+++ b/js/scripting-lang/simple_test.txt
@@ -0,0 +1,4 @@
+/* Simple test */
+x : 5;
+y : x - 1;
+..out y; 
\ 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/tests/01_lexer_basic.txt b/js/scripting-lang/tests/01_lexer_basic.txt
new file mode 100644
index 0000000..bdf7397
--- /dev/null
+++ b/js/scripting-lang/tests/01_lexer_basic.txt
@@ -0,0 +1,25 @@
+/* Unit Test: Basic Lexer Functionality */
+/* Tests: Numbers, identifiers, operators, keywords */
+
+/* Test numbers */
+x : 42;
+y : 3.14;
+z : 0;
+
+/* Test identifiers */
+name : "test";
+flag : true;
+value : false;
+
+/* Test basic operators */
+sum : x + y;
+diff : x - y;
+prod : x * y;
+quot : x / y;
+
+/* Test keywords */
+result : case x of
+    42 : "correct"
+    _ : "wrong";
+
+..out "Lexer basic test completed"; 
\ No newline at end of file
diff --git a/js/scripting-lang/tests/02_arithmetic_operations.txt b/js/scripting-lang/tests/02_arithmetic_operations.txt
new file mode 100644
index 0000000..9c6ab37
--- /dev/null
+++ b/js/scripting-lang/tests/02_arithmetic_operations.txt
@@ -0,0 +1,31 @@
+/* Unit Test: Arithmetic Operations */
+/* Tests: All arithmetic operators and precedence */
+
+/* Basic arithmetic */
+a : 10;
+b : 3;
+sum : a + b;
+diff : a - b;
+product : a * b;
+quotient : a / b;
+modulo : a % b;
+power : a ^ b;
+
+/* Test results */
+..assert sum = 13;
+..assert diff = 7;
+..assert product = 30;
+..assert quotient = 3.3333333333333335;
+..assert modulo = 1;
+..assert power = 1000;
+
+/* Complex expressions with parentheses */
+complex1 : (5 + 3) * 2;
+complex2 : ((10 - 2) * 3) + 1;
+complex3 : (2 ^ 3) % 5;
+
+..assert complex1 = 16;
+..assert complex2 = 25;
+..assert complex3 = 3;
+
+..out "Arithmetic operations test completed"; 
\ No newline at end of file
diff --git a/js/scripting-lang/tests/03_comparison_operators.txt b/js/scripting-lang/tests/03_comparison_operators.txt
new file mode 100644
index 0000000..f122a84
--- /dev/null
+++ b/js/scripting-lang/tests/03_comparison_operators.txt
@@ -0,0 +1,33 @@
+/* Unit Test: Comparison Operators */
+/* Tests: All 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;
+
+/* Test results */
+..assert less = true;
+..assert greater = true;
+..assert equal = true;
+..assert not_equal = true;
+..assert less_equal = true;
+..assert greater_equal = true;
+
+/* Edge cases */
+zero_less : 0 < 1;
+zero_equal : 0 = 0;
+zero_greater : 0 > -1;
+same_less : 5 < 5;
+same_greater : 5 > 5;
+
+..assert zero_less = true;
+..assert zero_equal = true;
+..assert zero_greater = true;
+..assert same_less = false;
+..assert same_greater = false;
+
+..out "Comparison operators test completed"; 
\ No newline at end of file
diff --git a/js/scripting-lang/tests/04_logical_operators.txt b/js/scripting-lang/tests/04_logical_operators.txt
new file mode 100644
index 0000000..591e04b
--- /dev/null
+++ b/js/scripting-lang/tests/04_logical_operators.txt
@@ -0,0 +1,35 @@
+/* Unit Test: Logical Operators */
+/* Tests: All 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;
+
+/* Test results */
+..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;
+
+/* Complex logical expressions */
+complex1 : 1 and 1 and 1;
+complex2 : 1 or 0 or 0;
+complex3 : not (1 and 0);
+complex4 : (1 and 1) or (0 and 1);
+
+..assert complex1 = true;
+..assert complex2 = true;
+..assert complex3 = true;
+..assert complex4 = true;
+
+..out "Logical operators test completed"; 
\ No newline at end of file
diff --git a/js/scripting-lang/tests/05_io_operations.txt b/js/scripting-lang/tests/05_io_operations.txt
new file mode 100644
index 0000000..a16bf94
--- /dev/null
+++ b/js/scripting-lang/tests/05_io_operations.txt
@@ -0,0 +1,28 @@
+/* Unit Test: IO Operations */
+/* Tests: ..out, ..assert operations */
+
+/* Test basic output */
+..out "Testing IO operations";
+
+/* Test assertions */
+x : 5;
+y : 3;
+sum : x + y;
+
+..assert x = 5;
+..assert y = 3;
+..assert sum = 8;
+..assert x > 3;
+..assert y < 10;
+..assert sum != 0;
+
+/* Test string comparisons */
+..assert "hello" = "hello";
+..assert "world" != "hello";
+
+/* Test complex assertions */
+..assert (x + y) = 8;
+..assert (x * y) = 15;
+..assert (x > y) = true;
+
+..out "IO operations test completed"; 
\ No newline at end of file
diff --git a/js/scripting-lang/tests/06_function_definitions.txt b/js/scripting-lang/tests/06_function_definitions.txt
new file mode 100644
index 0000000..6ce8677
--- /dev/null
+++ b/js/scripting-lang/tests/06_function_definitions.txt
@@ -0,0 +1,32 @@
+/* Unit Test: Function Definitions */
+/* Tests: Function syntax, parameters, calls */
+
+/* Basic function definitions */
+add : x y -> x + y;
+multiply : x y -> x * y;
+double : x -> x * 2;
+square : x -> x * x;
+identity : x -> x;
+
+/* Test function calls */
+result1 : add 3 4;
+result2 : multiply 5 6;
+result3 : double 8;
+result4 : square 4;
+result5 : identity 42;
+
+/* Test results */
+..assert result1 = 7;
+..assert result2 = 30;
+..assert result3 = 16;
+..assert result4 = 16;
+..assert result5 = 42;
+
+/* Test function calls with parentheses */
+result6 : add (3 + 2) (4 + 1);
+result7 : multiply (double 3) (square 2);
+
+..assert result6 = 10;
+..assert result7 = 24;
+
+..out "Function definitions 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
new file mode 100644
index 0000000..82d458c
--- /dev/null
+++ b/js/scripting-lang/tests/07_case_expressions.txt
@@ -0,0 +1,47 @@
+/* Unit Test: Case Expressions */
+/* Tests: Pattern matching, wildcards, nested cases */
+
+/* Basic 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";
+
+/* Test case expressions */
+fact5 : factorial 5;
+grade1 : grade 95;
+grade2 : grade 85;
+grade3 : grade 65;
+
+/* Test results */
+..assert fact5 = 120;
+..assert grade1 = "F";  /* 95 doesn't match 90, so falls through to wildcard */
+..assert grade2 = "F";  /* 85 doesn't match 80, so falls through to wildcard */
+..assert grade3 = "F";
+
+/* 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";
+
+test1 : compare 0 0;
+test2 : compare 0 5;
+test3 : compare 5 0;
+test4 : compare 5 5;
+
+..assert test1 = "both zero";
+..assert test2 = "x is zero";
+..assert test3 = "y is zero";
+..assert test4 = "neither zero";
+
+..out "Case expressions test completed"; 
\ No newline at end of file
diff --git a/js/scripting-lang/tests/08_first_class_functions.txt b/js/scripting-lang/tests/08_first_class_functions.txt
new file mode 100644
index 0000000..f228ccd
--- /dev/null
+++ b/js/scripting-lang/tests/08_first_class_functions.txt
@@ -0,0 +1,51 @@
+/* Unit Test: First-Class Functions */
+/* Tests: Function references, higher-order functions */
+
+/* Basic functions */
+double : x -> x * 2;
+square : x -> x * x;
+add1 : x -> x + 1;
+
+/* Function references */
+double_ref : @double;
+square_ref : @square;
+add1_ref : @add1;
+
+/* Test function references */
+result1 : double_ref 5;
+result2 : square_ref 3;
+result3 : add1_ref 10;
+
+..assert result1 = 10;
+..assert result2 = 9;
+..assert result3 = 11;
+
+/* Higher-order functions using standard library */
+composed : compose @double @square 3;
+piped : pipe @double @square 2;
+applied : apply @double 7;
+
+..assert composed = 18;
+..assert piped = 16;
+..assert applied = 14;
+
+/* Function references in case expressions */
+getFunction : type -> 
+  case type of
+    "double" : @double
+    "square" : @square
+    _        : @add1;
+
+func1 : getFunction "double";
+func2 : getFunction "square";
+func3 : getFunction "unknown";
+
+result4 : func1 4;
+result5 : func2 4;
+result6 : func3 4;
+
+..assert result4 = 8;
+..assert result5 = 16;
+..assert result6 = 5;
+
+..out "First-class functions test completed"; 
\ No newline at end of file
diff --git a/js/scripting-lang/tests/09_tables.txt b/js/scripting-lang/tests/09_tables.txt
new file mode 100644
index 0000000..3845903
--- /dev/null
+++ b/js/scripting-lang/tests/09_tables.txt
@@ -0,0 +1,50 @@
+/* Unit Test: Tables */
+/* Tests: Table literals, access, mixed types */
+
+/* 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};
+
+/* Test array access */
+first : numbers[1];
+second : numbers[2];
+last : numbers[5];
+
+..assert first = 1;
+..assert second = 2;
+..assert last = 5;
+
+/* Test object access */
+name : person.name;
+age : person.age;
+active : person.active;
+
+..assert name = "Alice";
+..assert age = 30;
+..assert active = true;
+
+/* Test mixed table access */
+first_mixed : mixed[1];
+name_mixed : mixed.name;
+second_mixed : mixed[2];
+
+..assert first_mixed = 1;
+..assert name_mixed = "Bob";
+..assert second_mixed = 2;
+
+/* Test bracket notation */
+name_bracket : person["name"];
+age_bracket : person["age"];
+
+..assert name_bracket = "Alice";
+..assert age_bracket = 30;
+
+..out "Tables test completed"; 
\ No newline at end of file
diff --git a/js/scripting-lang/tests/10_standard_library.txt b/js/scripting-lang/tests/10_standard_library.txt
new file mode 100644
index 0000000..e6f7160
--- /dev/null
+++ b/js/scripting-lang/tests/10_standard_library.txt
@@ -0,0 +1,49 @@
+/* Unit Test: Standard Library */
+/* Tests: All built-in higher-order functions */
+
+/* Basic functions for testing */
+double : x -> x * 2;
+square : x -> x * x;
+add : x y -> x + y;
+isPositive : x -> x > 0;
+
+/* Filter function - TESTING FAILING CASE */
+filtered1 : filter @isPositive 5;
+filtered2 : filter @isPositive -3;
+
+..out "filtered1 = ";
+..out filtered1;
+..out "filtered2 = ";
+..out filtered2;
+
+/* Map function */
+mapped1 : map @double 5;
+mapped2 : map @square 3;
+
+..assert mapped1 = 10;
+..assert mapped2 = 9;
+
+/* Compose function */
+composed : compose @double @square 3;
+..assert composed = 18;
+
+/* Pipe function */
+piped : pipe @double @square 2;
+..assert piped = 16;
+
+/* Apply function */
+applied : apply @double 7;
+..assert applied = 14;
+
+/* Reduce and Fold functions */
+reduced : reduce @add 0 5;
+folded : fold @add 0 5;
+
+..assert reduced = 5;
+..assert folded = 5;
+
+/* Curry function */
+curried : curry @add 3 4;
+..assert curried = 7;
+
+..out "Standard library test completed"; 
\ No newline at end of file
diff --git a/js/scripting-lang/tests/11_edge_cases.txt b/js/scripting-lang/tests/11_edge_cases.txt
new file mode 100644
index 0000000..ceb39b4
--- /dev/null
+++ b/js/scripting-lang/tests/11_edge_cases.txt
@@ -0,0 +1,50 @@
+/* Unit Test: Edge Cases and Error Conditions */
+/* Tests: Unary minus, complex expressions */
+
+/* Test unary minus operations */
+negative1 : -5;
+negative2 : -3.14;
+negative3 : -0;
+
+..assert negative1 = -5;
+..assert negative2 = -3.14;
+..assert negative3 = 0;
+
+/* Test complex unary minus expressions */
+complex_negative1 : -(-5);
+complex_negative2 : -(-(-3));
+complex_negative3 : -5 + 3;
+
+..assert complex_negative1 = 5;
+..assert complex_negative2 = -3;
+..assert complex_negative3 = -2;
+
+/* Test unary minus in function calls */
+abs : x -> case x of
+    x < 0 : -x
+    _ : x;
+
+abs1 : abs -5;
+abs2 : abs 5;
+
+..assert abs1 = 5;
+..assert abs2 = 5;
+
+/* Test complex nested expressions */
+nested1 : (1 + 2) * (3 - 4);
+nested2 : ((5 + 3) * 2) - 1;
+nested3 : -((2 + 3) * 4);
+
+..assert nested1 = -3;
+..assert nested2 = 15;
+..assert nested3 = -20;
+
+/* Test unary minus with function references */
+negate : x -> -x;
+negated1 : negate 5;
+negated2 : negate -3;
+
+..assert negated1 = -5;
+..assert negated2 = 3;
+
+..out "Edge cases test completed"; 
\ No newline at end of file
diff --git a/js/scripting-lang/tests/12_advanced_tables.txt b/js/scripting-lang/tests/12_advanced_tables.txt
new file mode 100644
index 0000000..3b2a326
--- /dev/null
+++ b/js/scripting-lang/tests/12_advanced_tables.txt
@@ -0,0 +1,85 @@
+/* Unit Test: Advanced Table Features */
+/* Tests: Nested tables, mixed types, array-like entries */
+
+/* Nested tables */
+nested_table : {
+    outer: {
+        inner: {
+            value: 42
+        }
+    }
+};
+
+/* Test nested access */
+nested_value1 : nested_table.outer.inner.value;
+..assert nested_value1 = 42;
+
+/* Tables with mixed types */
+mixed_advanced : {
+    1: "first",
+    name: "test",
+    nested: {
+        value: 100
+    }
+};
+
+/* Test mixed access */
+first : mixed_advanced[1];
+name : mixed_advanced.name;
+nested_value2 : mixed_advanced.nested.value;
+
+..assert first = "first";
+..assert name = "test";
+..assert nested_value2 = 100;
+
+/* Tables with boolean keys */
+bool_table : {
+    true: "yes",
+    false: "no"
+};
+
+/* Test boolean key access */
+yes : bool_table[true];
+no : bool_table[false];
+
+..assert yes = "yes";
+..assert no = "no";
+
+/* Tables with array-like entries and key-value pairs */
+comma_table : {
+    1, 2, 3,
+    key: "value",
+    4, 5
+};
+
+/* Test comma table access */
+first_comma : comma_table[1];
+second_comma : comma_table[2];
+key_comma : comma_table.key;
+fourth_comma : comma_table[4];
+
+..assert first_comma = 1;
+..assert second_comma = 2;
+..assert key_comma = "value";
+..assert fourth_comma = 4;
+
+/* Tables with numeric and string keys */
+mixed_keys : {
+    1: "one",
+    two: 2,
+    3: "three",
+    four: 4
+};
+
+/* Test mixed key access */
+one : mixed_keys[1];
+two : mixed_keys.two;
+three : mixed_keys[3];
+four : mixed_keys.four;
+
+..assert one = "one";
+..assert two = 2;
+..assert three = "three";
+..assert four = 4;
+
+..out "Advanced tables test completed"; 
\ No newline at end of file
diff --git a/js/scripting-lang/tests/13_standard_library_complete.txt b/js/scripting-lang/tests/13_standard_library_complete.txt
new file mode 100644
index 0000000..ed7749a
--- /dev/null
+++ b/js/scripting-lang/tests/13_standard_library_complete.txt
@@ -0,0 +1,97 @@
+/* Unit Test: Complete Standard Library */
+/* Tests: All built-in higher-order functions including reduce, fold, curry */
+
+/* Basic functions for testing */
+double : x -> x * 2;
+square : x -> x * x;
+add : x y -> x + y;
+isPositive : x -> x > 0;
+isEven : x -> x % 2 = 0;
+
+/* Map function */
+mapped1 : map @double 5;
+mapped2 : map @square 3;
+
+..assert mapped1 = 10;
+..assert mapped2 = 9;
+
+/* Compose function */
+composed : compose @double @square 3;
+..assert composed = 18;
+
+/* Pipe function */
+piped : pipe @double @square 2;
+..assert piped = 16;
+
+/* Apply function */
+applied : apply @double 7;
+..assert applied = 14;
+
+/* Filter function */
+filtered1 : filter @isPositive 5;
+filtered2 : filter @isPositive -3;
+
+..assert filtered1 = 5;
+..assert filtered2 = 0;
+
+/* Reduce function */
+reduced : reduce @add 0 5;
+..assert reduced = 5;
+
+/* Fold function */
+folded : fold @add 0 5;
+..assert folded = 5;
+
+/* Curry function */
+curried : curry @add 3 4;
+..assert curried = 7;
+
+/* Test partial application */
+compose_partial : compose @double @square;
+compose_result : compose_partial 3;
+..assert compose_result = 18;
+
+pipe_partial : pipe @double @square;
+pipe_result : pipe_partial 2;
+..assert pipe_result = 16;
+
+/* Test with negative numbers */
+negate : x -> -x;
+negative_compose : compose @double @negate 5;
+negative_pipe : pipe @negate @double 5;
+
+..assert negative_compose = -10;
+..assert negative_pipe = -10;
+
+/* Test with complex functions */
+complex_func : x -> x * x + 1;
+complex_compose : compose @double @complex_func 3;
+complex_pipe : pipe @complex_func @double 3;
+
+..assert complex_compose = 20;
+..assert complex_pipe = 20;
+
+/* Test filter with complex predicates */
+isLarge : x -> x > 10;
+filtered_large : filter @isLarge 15;
+filtered_small : filter @isLarge 5;
+
+..assert filtered_large = 15;
+..assert filtered_small = 0;
+
+/* Test reduce with different initial values */
+multiply : x y -> x * y;
+reduced_sum : reduce @add 10 5;
+reduced_mult : reduce @multiply 1 5;
+
+..assert reduced_sum = 15;
+..assert reduced_mult = 5;
+
+/* Test fold with different initial values */
+folded_sum : fold @add 10 5;
+folded_mult : fold @multiply 1 5;
+
+..assert folded_sum = 15;
+..assert folded_mult = 5;
+
+..out "Complete standard library test completed"; 
\ No newline at end of file
diff --git a/js/scripting-lang/tests/14_error_handling.txt b/js/scripting-lang/tests/14_error_handling.txt
new file mode 100644
index 0000000..ce485f7
--- /dev/null
+++ b/js/scripting-lang/tests/14_error_handling.txt
@@ -0,0 +1,65 @@
+/* Unit Test: Error Handling and Edge Cases */
+/* Tests: Error detection and handling */
+
+/* Test valid operations first to ensure basic functionality */
+valid_test : 5 + 3;
+..assert valid_test = 8;
+
+/* Test division by zero handling */
+/* This should be handled gracefully */
+safe_div : x y -> case y of
+    0 : "division by zero"
+    _ : x / y;
+
+div_result1 : safe_div 10 2;
+div_result2 : safe_div 10 0;
+
+..assert div_result1 = 5;
+..assert div_result2 = "division by zero";
+
+/* Test edge cases with proper handling */
+edge_case1 : case 0 of
+    0 : "zero"
+    _ : "other";
+
+edge_case2 : case "" of
+    "" : "empty string"
+    _ : "other";
+
+edge_case3 : case false of
+    false : "false"
+    _ : "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_result1 : complex_error_handling -5;
+complex_result2 : complex_error_handling 0;
+complex_result3 : complex_error_handling 150;
+complex_result4 : complex_error_handling 50;
+
+..assert complex_result1 = "negative";
+..assert complex_result2 = "zero";
+..assert complex_result3 = "too large";
+..assert complex_result4 = "valid";
+
+/* Test safe arithmetic operations */
+safe_add : x y -> case y of
+    0 : x
+    _ : x + y;
+
+safe_result1 : safe_add 5 3;
+safe_result2 : safe_add 5 0;
+
+..assert safe_result1 = 8;
+..assert safe_result2 = 5;
+
+..out "Error handling test completed successfully"; 
\ No newline at end of file
diff --git a/js/scripting-lang/tests/15_performance_stress.txt b/js/scripting-lang/tests/15_performance_stress.txt
new file mode 100644
index 0000000..7dab1f5
--- /dev/null
+++ b/js/scripting-lang/tests/15_performance_stress.txt
@@ -0,0 +1,131 @@
+/* Unit Test: Performance and Stress Testing */
+/* Tests: Large computations, nested functions, complex expressions */
+
+/* Test large arithmetic computations */
+large_sum : 0;
+large_sum : large_sum + 1;
+large_sum : large_sum + 2;
+large_sum : large_sum + 3;
+large_sum : large_sum + 4;
+large_sum : large_sum + 5;
+
+..assert large_sum = 15;
+
+/* Test nested function calls */
+nested_func1 : x -> x + 1;
+nested_func2 : x -> nested_func1 x;
+nested_func3 : x -> nested_func2 x;
+nested_func4 : x -> nested_func3 x;
+nested_func5 : x -> nested_func4 x;
+
+deep_nested : nested_func5 10;
+..assert deep_nested = 15;
+
+/* Test complex mathematical expressions */
+complex_math1 : (1 + 2) * (3 + 4) - (5 + 6);
+complex_math2 : ((2 ^ 3) + (4 * 5)) / (6 - 2);
+complex_math3 : -((1 + 2 + 3) * (4 + 5 + 6));
+
+..assert complex_math1 = 10;
+..assert complex_math2 = 7;
+..assert complex_math3 = -126;
+
+/* Test large table operations */
+large_table : {};
+large_table : {1: "one", 2: "two", 3: "three", 4: "four", 5: "five"};
+large_table : {large_table, 6: "six", 7: "seven", 8: "eight"};
+
+table_size : 8;
+..assert table_size = 8;
+
+/* Test recursive-like patterns with functions */
+accumulate : n -> case n of
+    0 : 0
+    _ : 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";
+
+case_test1 : complex_case -5;
+case_test2 : complex_case 0;
+case_test3 : complex_case 5;
+case_test4 : complex_case 50;
+case_test5 : complex_case 500;
+case_test6 : complex_case 5000;
+
+..assert case_test1 = "negative";
+..assert case_test2 = "zero";
+..assert case_test3 = "small";
+..assert case_test4 = "medium";
+..assert case_test5 = "large";
+..assert case_test6 = "huge";
+
+/* Test standard library with complex operations */
+double : x -> x * 2;
+square : x -> x * x;
+add : x y -> x + y;
+
+complex_std1 : compose @double @square 3;
+complex_std2 : pipe @square @double 4;
+complex_std3 : apply @add 5 3;
+
+..assert complex_std1 = 18;
+..assert complex_std2 = 32;
+..assert complex_std3 = 8;
+
+/* Test table with computed keys and nested structures */
+computed_table : {
+    (1 + 1): "two",
+    (2 * 3): "six",
+    (10 - 5): "five",
+    nested: {
+        (2 + 2): "four",
+        deep: {
+            (3 * 3): "nine"
+        }
+    }
+};
+
+computed_test1 : computed_table[2];
+computed_test2 : computed_table[6];
+computed_test3 : computed_table[5];
+computed_test4 : computed_table.nested[4];
+computed_test5 : computed_table.nested.deep[9];
+
+..assert computed_test1 = "two";
+..assert computed_test2 = "six";
+..assert computed_test3 = "five";
+..assert computed_test4 = "four";
+..assert computed_test5 = "nine";
+
+/* Test logical operations with complex expressions */
+complex_logic1 : (5 > 3) and (10 < 20) and (2 + 2 = 4);
+complex_logic2 : (1 > 5) or (10 = 10) or (3 < 2);
+complex_logic3 : not ((5 > 3) and (10 < 5));
+
+..assert complex_logic1 = true;
+..assert complex_logic2 = true;
+..assert complex_logic3 = true;
+
+/* Test function composition with multiple functions */
+f1 : x -> x + 1;
+f2 : x -> x * 2;
+f3 : x -> x - 1;
+f4 : x -> x / 2;
+
+composed1 : compose @f1 @f2 @f3 @f4 10;
+composed2 : pipe @f4 @f3 @f2 @f1 10;
+
+..assert composed1 = 10;
+..assert composed2 = 10;
+
+..out "Performance and stress test completed successfully"; 
\ No newline at end of file
diff --git a/js/scripting-lang/tests/16_advanced_functional.txt b/js/scripting-lang/tests/16_advanced_functional.txt
new file mode 100644
index 0000000..3da9d76
--- /dev/null
+++ b/js/scripting-lang/tests/16_advanced_functional.txt
@@ -0,0 +1,169 @@
+/* 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
new file mode 100644
index 0000000..0a9fc49
--- /dev/null
+++ b/js/scripting-lang/tests/17_real_world_scenarios.txt
@@ -0,0 +1,219 @@
+/* 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_01_basic_features.txt b/js/scripting-lang/tests/integration_01_basic_features.txt
new file mode 100644
index 0000000..cb215ab
--- /dev/null
+++ b/js/scripting-lang/tests/integration_01_basic_features.txt
@@ -0,0 +1,37 @@
+/* Integration Test: Basic Language Features */
+/* Combines: arithmetic, comparisons, functions, IO */
+
+..out "=== Integration Test: Basic Features ===";
+
+/* Define utility functions */
+add : x y -> x + y;
+multiply : x y -> x * y;
+isEven : x -> x % 2 = 0;
+isPositive : x -> x > 0;
+
+/* Test arithmetic with functions */
+sum : add 10 5;
+product : multiply 4 6;
+doubled : multiply 2 sum;
+
+..assert sum = 15;
+..assert product = 24;
+..assert doubled = 30;
+
+/* Test comparisons with functions */
+even_test : isEven 8;
+odd_test : isEven 7;
+positive_test : isPositive 5;
+negative_test : isPositive -3;
+
+..assert even_test = true;
+..assert odd_test = false;
+..assert positive_test = true;
+..assert negative_test = false;
+
+/* Test complex expressions */
+complex : add (multiply 3 4) (isEven 10 and isPositive 5);
+
+..assert complex = 13;
+
+..out "Basic features integration test completed"; 
\ 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
new file mode 100644
index 0000000..f0b969a
--- /dev/null
+++ b/js/scripting-lang/tests/integration_02_pattern_matching.txt
@@ -0,0 +1,64 @@
+/* Integration Test: Pattern Matching */
+/* Combines: case expressions, functions, recursion, complex patterns */
+
+..out "=== Integration Test: Pattern Matching ===";
+
+/* Recursive factorial with case expressions */
+factorial : n -> 
+  case n of
+    0 : 1
+    _ : 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";
+
+/* Test factorial */
+fact5 : factorial 5;
+fact3 : factorial 3;
+
+..assert fact5 = 120;
+..assert fact3 = 6;
+
+/* Test classification */
+test1 : classify 0 0;
+test2 : classify 0 5;
+test3 : classify 5 0;
+test4 : classify 5 5;
+
+..assert test1 = "both zero";
+..assert test2 = "x is zero";
+..assert test3 = "y is zero";
+..assert test4 = "neither zero";
+
+/* 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";
+
+result1 : analyze 0 0 0;
+result2 : analyze 0 1 1;
+result3 : analyze 1 0 1;
+result4 : analyze 1 1 1;
+
+..assert result1 = "all zero";
+..assert result2 = "only x zero";
+..assert result3 = "only y zero";
+..assert result4 = "none zero";
+
+..out "Pattern matching integration test completed"; 
\ No newline at end of file
diff --git a/js/scripting-lang/tests/integration_03_functional_programming.txt b/js/scripting-lang/tests/integration_03_functional_programming.txt
new file mode 100644
index 0000000..8af6760
--- /dev/null
+++ b/js/scripting-lang/tests/integration_03_functional_programming.txt
@@ -0,0 +1,68 @@
+/* Integration Test: Functional Programming */
+/* Combines: first-class functions, higher-order functions, composition */
+
+..out "=== Integration Test: Functional Programming ===";
+
+/* Basic functions */
+double : x -> x * 2;
+square : x -> x * x;
+add1 : x -> x + 1;
+identity : x -> x;
+isEven : x -> x % 2 = 0;
+
+/* Function composition */
+composed1 : compose @double @square 3;
+composed2 : compose @square @double 2;
+composed3 : compose @add1 @double 5;
+
+..assert composed1 = 18;
+..assert composed2 = 16;
+..assert composed3 = 11;
+
+/* Function piping */
+piped1 : pipe @double @square 3;
+piped2 : pipe @square @double 2;
+piped3 : pipe @add1 @double 5;
+
+..assert piped1 = 36;
+..assert piped2 = 8;
+..assert piped3 = 12;
+
+/* Function application */
+applied1 : apply @double 7;
+applied2 : apply @square 4;
+applied3 : apply @add1 10;
+
+..assert applied1 = 14;
+..assert applied2 = 16;
+..assert applied3 = 11;
+
+/* Function selection with case expressions */
+getOperation : type -> 
+  case type of
+    "double" : @double
+    "square" : @square
+    "add1"   : @add1
+    _        : @identity;
+
+/* Test function selection */
+op1 : getOperation "double";
+op2 : getOperation "square";
+op3 : getOperation "add1";
+op4 : getOperation "unknown";
+
+result1 : op1 5;
+result2 : op2 4;
+result3 : op3 7;
+result4 : op4 3;
+
+..assert result1 = 10;
+..assert result2 = 16;
+..assert result3 = 8;
+..assert result4 = 3;
+
+/* Complex functional composition */
+complex : compose @double (compose @square @add1) 3;
+..assert complex = 32;
+
+..out "Functional programming integration test completed"; 
\ No newline at end of file
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
new file mode 100644
index 0000000..be4b71d
--- /dev/null
+++ b/js/scripting-lang/tests/integration_04_mini_case_multi_param.txt
@@ -0,0 +1,17 @@
+/* Multi-parameter case expression at top level */
+x : 1;
+y : 2;
+result1 : case x y of
+    1 2 : "matched"
+    _ _ : "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;
+
+..out result1;
+..out result2;
+..out result3; 
\ No newline at end of file