about summary refs log tree commit diff stats
path: root/js/scripting-lang/lang.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/scripting-lang/lang.js')
-rw-r--r--js/scripting-lang/lang.js1796
1 files changed, 1574 insertions, 222 deletions
diff --git a/js/scripting-lang/lang.js b/js/scripting-lang/lang.js
index f91f842..3de7a0e 100644
--- a/js/scripting-lang/lang.js
+++ b/js/scripting-lang/lang.js
@@ -1,320 +1,1672 @@
 // 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
+function initializeStandardLibrary(scope) {
+    // Map: Apply a function to each element
+    scope.map = function(f, x) { 
+        // Handle function references by calling them if they're functions
+        if (typeof f === 'function') {
+            return f(x);
+        } else {
+            throw new Error('map: first argument must be a function');
+        }
+    };
+    
+    // Compose: Compose two functions (f ∘ g)(x) = f(g(x))
+    scope.compose = function(f, g, x) { 
+        if (typeof f === 'function' && typeof g === 'function') {
+            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
+    scope.curry = function(f, x, y) { 
+        if (typeof f === 'function') {
+            return f(x, y);
+        } else {
+            throw new Error('curry: first argument must be a function');
+        }
+    };
+    
+    // Apply: Apply a function to an argument (same as function call, but more explicit)
+    scope.apply = function(f, x) { 
+        if (typeof f === 'function') {
+            return f(x);
+        } else {
+            throw new Error('apply: first argument must be a function');
+        }
+    };
+    
+    // Pipe: Compose functions in left-to-right order (opposite of compose)
+    // pipe f g x = g f x
+    scope.pipe = function(f, g, x) { 
+        if (typeof f === 'function' && typeof g === 'function') {
+            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
+    scope.filter = function(p, x) { 
+        if (typeof p === 'function') {
+            return p(x) ? x : 0;
+        } else {
+            throw new Error('filter: first argument must be a function');
+        }
+    };
+    
+    // Reduce: Reduce to a single value using a binary function
+    // For now, we'll implement it as a higher-order function
+    scope.reduce = function(f, init, x) { 
+        if (typeof f === 'function') {
+            return f(init, x);
+        } else {
+            throw new Error('reduce: first argument must be a function');
+        }
+    };
+    
+    // Fold: Same as reduce, but more explicit about the folding direction
+    scope.fold = function(f, init, x) { 
+        if (typeof f === 'function') {
+            return f(init, x);
+        } else {
+            throw new Error('fold: first argument must be a function');
+        }
+    };
+}
+
 // Define the types of tokens
 const TokenType = {
     NUMBER: 'NUMBER',
     PLUS: 'PLUS',
+    MINUS: 'MINUS',
+    MULTIPLY: 'MULTIPLY',
+    DIVIDE: 'DIVIDE',
     IDENTIFIER: 'IDENTIFIER',
     ASSIGNMENT: 'ASSIGNMENT',
+    ARROW: 'ARROW',
+    CASE: 'CASE',
+    OF: 'OF',
+    WILDCARD: 'WILDCARD',
     FUNCTION: 'FUNCTION',
     LEFT_PAREN: 'LEFT_PAREN',
     RIGHT_PAREN: 'RIGHT_PAREN',
     LEFT_BRACE: 'LEFT_BRACE',
     RIGHT_BRACE: 'RIGHT_BRACE',
+    LEFT_BRACKET: 'LEFT_BRACKET',
+    RIGHT_BRACKET: 'RIGHT_BRACKET',
     SEMICOLON: 'SEMICOLON',
+    COMMA: 'COMMA',
+    DOT: 'DOT',
+    STRING: 'STRING',
+    TRUE: 'TRUE',
+    FALSE: 'FALSE',
+    AND: 'AND',
+    OR: 'OR',
+    XOR: 'XOR',
+    NOT: 'NOT',
+    EQUALS: 'EQUALS',
+    LESS_THAN: 'LESS_THAN',
+    GREATER_THAN: 'GREATER_THAN',
+    LESS_EQUAL: 'LESS_EQUAL',
+    GREATER_EQUAL: 'GREATER_EQUAL',
+    NOT_EQUAL: 'NOT_EQUAL',
+    MODULO: 'MODULO',
+    POWER: 'POWER',
+    IO_IN: 'IO_IN',
+    IO_OUT: 'IO_OUT',
+    IO_ASSERT: 'IO_ASSERT',
+    FUNCTION_REF: 'FUNCTION_REF'
 };
 
-// Lexer
+// Lexer - converts source code to tokens
 function lexer(input) {
-    const tokens = [];
     let current = 0;
-
+    const tokens = [];
+    
     while (current < input.length) {
         let char = input[current];
-
-        if (/\d/.test(char)) {
-            let value = '';
-            while (/\d/.test(char)) {
-                value += char;
-                char = input[++current];
-            }
-            tokens.push({
-                type: TokenType.NUMBER,
-                value
-            });
-            continue;
-        }
-
-        if (char === '+') {
-            tokens.push({
-                type: TokenType.PLUS
-            });
+        
+        // Skip whitespace
+        if (/\s/.test(char)) {
             current++;
             continue;
         }
-
-        if (/[a-z]/i.test(char)) {
-            let value = '';
-            while (/[a-z]/i.test(char)) {
-                value += char;
-                char = input[++current];
+        
+        // Skip comments
+        if (char === '/' && input[current + 1] === '*') {
+            let commentDepth = 1;
+            current += 2; // Skip /*
+            
+            while (current < input.length && commentDepth > 0) {
+                if (input[current] === '/' && input[current + 1] === '*') {
+                    commentDepth++;
+                    current += 2;
+                } else if (input[current] === '*' && input[current + 1] === '/') {
+                    commentDepth--;
+                    current += 2;
+                } else {
+                    current++;
+                }
             }
-            tokens.push({
-                type: TokenType.IDENTIFIER,
-                value
-            });
-            continue;
-        }
-
-        if (char === ':') {
-            tokens.push({
-                type: TokenType.ASSIGNMENT
-            });
-            current++;
-            continue;
-        }
-
-        if (char === '=') {
-            tokens.push({
-                type: TokenType.EQUAL
-            });
-            current++;
-            continue;
-        }
-
-        if (input.slice(current, current + 2) === 'if') {
-            tokens.push({
-                type: TokenType.IF
-            });
-            current += 2;
-            continue;
-        }
-
-        if (input.slice(current, current + 4) === 'else') {
-            tokens.push({
-                type: TokenType.ELSE
-            });
-            current += 4;
             continue;
         }
-
-        if (char === '(') {
-            tokens.push({
-                type: TokenType.LEFT_PAREN
-            });
-            current++;
-            continue;
-        }
-
-        if (char === ')') {
-            tokens.push({
-                type: TokenType.RIGHT_PAREN
-            });
-            current++;
+        
+        // Numbers
+        if (/[0-9]/.test(char)) {
+            let value = '';
+            while (current < input.length && /[0-9]/.test(input[current])) {
+                value += input[current];
+                current++;
+            }
+            
+            // Check for decimal point
+            if (current < input.length && input[current] === '.') {
+                value += input[current];
+                current++;
+                
+                // Parse decimal part
+                while (current < input.length && /[0-9]/.test(input[current])) {
+                    value += input[current];
+                    current++;
+                }
+                
+                tokens.push({
+                    type: TokenType.NUMBER,
+                    value: parseFloat(value)
+                });
+            } else {
+                tokens.push({
+                    type: TokenType.NUMBER,
+                    value: parseInt(value)
+                });
+            }
             continue;
         }
-
-        if (char === '{') {
-            tokens.push({
-                type: TokenType.LEFT_BRACE
-            });
-            current++;
+        
+        // Strings
+        if (char === '"') {
+            let value = '';
+            current++; // Skip opening quote
+            
+            while (current < input.length && input[current] !== '"') {
+                value += input[current];
+                current++;
+            }
+            
+            if (current < input.length) {
+                current++; // Skip closing quote
+                tokens.push({
+                    type: TokenType.STRING,
+                    value: value
+                });
+            } else {
+                throw new Error('Unterminated string');
+            }
             continue;
         }
-
-        if (char === '}') {
-            tokens.push({
-                type: TokenType.RIGHT_BRACE
-            });
-            current++;
+        
+        // Identifiers and keywords
+        if (/[a-zA-Z_]/.test(char)) {
+            let value = '';
+            while (current < input.length && /[a-zA-Z0-9_]/.test(input[current])) {
+                value += input[current];
+                current++;
+            }
+            
+            // Check for keywords
+            switch (value) {
+                case 'case':
+                    tokens.push({ type: TokenType.CASE });
+                    break;
+                case 'of':
+                    tokens.push({ type: TokenType.OF });
+                    break;
+                case 'function':
+                    tokens.push({ type: TokenType.FUNCTION });
+                    break;
+                case 'true':
+                    tokens.push({ type: TokenType.TRUE });
+                    break;
+                case 'false':
+                    tokens.push({ type: TokenType.FALSE });
+                    break;
+                case 'and':
+                    tokens.push({ type: TokenType.AND });
+                    break;
+                case 'or':
+                    tokens.push({ type: TokenType.OR });
+                    break;
+                case 'xor':
+                    tokens.push({ type: TokenType.XOR });
+                    break;
+                case 'not':
+                    tokens.push({ type: TokenType.NOT });
+                    break;
+                case '_':
+                    tokens.push({ type: TokenType.WILDCARD });
+                    break;
+                default:
+                    tokens.push({
+                        type: TokenType.IDENTIFIER,
+                        value: value
+                    });
+            }
             continue;
         }
-
-        if (input.slice(current, current + 8) === 'function') {
-            tokens.push({
-                type: TokenType.FUNCTION
-            });
-            current += 8;
-            continue;
+        
+        // Two-character operators
+        if (current + 1 < input.length) {
+            const twoChar = char + input[current + 1];
+            switch (twoChar) {
+                case '->':
+                    tokens.push({ type: TokenType.ARROW });
+                    current += 2;
+                    continue;
+                case '==':
+                    tokens.push({ type: TokenType.EQUALS });
+                    current += 2;
+                    continue;
+                case '!=':
+                    tokens.push({ type: TokenType.NOT_EQUAL });
+                    current += 2;
+                    continue;
+                case '<=':
+                    tokens.push({ type: TokenType.LESS_EQUAL });
+                    current += 2;
+                    continue;
+                case '>=':
+                    tokens.push({ type: TokenType.GREATER_EQUAL });
+                    current += 2;
+                    continue;
+                case '..':
+                    // Check for IO operations
+                    if (current + 2 < input.length) {
+                        const ioChar = input[current + 2];
+                        switch (ioChar) {
+                            case 'i':
+                                if (current + 3 < input.length && input[current + 3] === 'n') {
+                                    tokens.push({ type: TokenType.IO_IN });
+                                    current += 4;
+                                    continue;
+                                }
+                                break;
+                            case 'o':
+                                if (current + 3 < input.length && input[current + 3] === 'u') {
+                                    if (current + 4 < input.length && input[current + 4] === 't') {
+                                        tokens.push({ type: TokenType.IO_OUT });
+                                        current += 5;
+                                        continue;
+                                    }
+                                }
+                                break;
+                            case 'a':
+                                if (current + 3 < input.length && input[current + 3] === 's') {
+                                    if (current + 4 < input.length && input[current + 4] === 's') {
+                                        if (current + 5 < input.length && input[current + 5] === 'e') {
+                                            if (current + 6 < input.length && input[current + 6] === 'r') {
+                                                if (current + 7 < input.length && input[current + 7] === 't') {
+                                                    tokens.push({ type: TokenType.IO_ASSERT });
+                                                    current += 8;
+                                                    continue;
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                                break;
+                        }
+                    }
+                    // If we get here, it's not a complete IO operation, so skip the '..'
+                    current += 2;
+                    continue;
+            }
         }
-
-        if (char === ';') {
-            tokens.push({ type: TokenType.SEMICOLON });
-            current++;
-            continue;
+        
+        // Single character operators
+        switch (char) {
+            case '+':
+                tokens.push({ type: TokenType.PLUS });
+                break;
+            case '-':
+                tokens.push({ type: TokenType.MINUS });
+                break;
+            case '*':
+                tokens.push({ type: TokenType.MULTIPLY });
+                break;
+            case '/':
+                tokens.push({ type: TokenType.DIVIDE });
+                break;
+            case '%':
+                tokens.push({ type: TokenType.MODULO });
+                break;
+            case '^':
+                tokens.push({ type: TokenType.POWER });
+                break;
+            case ':':
+                tokens.push({ type: TokenType.ASSIGNMENT });
+                break;
+            case '(':
+                tokens.push({ type: TokenType.LEFT_PAREN });
+                break;
+            case ')':
+                tokens.push({ type: TokenType.RIGHT_PAREN });
+                break;
+            case '{':
+                tokens.push({ type: TokenType.LEFT_BRACE });
+                break;
+            case '}':
+                tokens.push({ type: TokenType.RIGHT_BRACE });
+                break;
+            case '[':
+                tokens.push({ type: TokenType.LEFT_BRACKET });
+                break;
+            case ']':
+                tokens.push({ type: TokenType.RIGHT_BRACKET });
+                break;
+            case ';':
+                tokens.push({ type: TokenType.SEMICOLON });
+                break;
+            case ',':
+                tokens.push({ type: TokenType.COMMA });
+                break;
+            case '.':
+                tokens.push({ type: TokenType.DOT });
+                break;
+            case '@':
+                tokens.push({ type: TokenType.FUNCTION_REF });
+                break;
+            case '_':
+                tokens.push({ type: TokenType.WILDCARD });
+                break;
+            case '=':
+                tokens.push({ type: TokenType.EQUALS });
+                break;
+            case '<':
+                tokens.push({ type: TokenType.LESS_THAN });
+                break;
+            case '>':
+                tokens.push({ type: TokenType.GREATER_THAN });
+                break;
+            default:
+                throw new Error(`Unexpected character: ${char}`);
         }
-
+        
         current++;
     }
-
+    
     return tokens;
 }
 
-// Parser
+// Parser - converts tokens to AST
 function parser(tokens) {
     let current = 0;
-
+    
     function walk() {
-        if (current >= tokens.length) {
-            return null; // Return null when there are no more tokens
+        function parseChainedDotAccess(tableExpr) {
+            let result = tableExpr;
+            
+            while (current < tokens.length && tokens[current].type === TokenType.DOT) {
+                current++; // Skip the dot
+                
+                if (current < tokens.length && tokens[current].type === TokenType.IDENTIFIER) {
+                    const key = {
+                        type: 'Identifier',
+                        value: tokens[current].value
+                    };
+                    current++;
+                    
+                    result = {
+                        type: 'TableAccess',
+                        table: result,
+                        key: key
+                    };
+                } else {
+                    throw new Error('Expected identifier after dot');
+                }
+            }
+            
+            return result;
         }
-
-        let token = tokens[current];
-
-        if (token.type === TokenType.NUMBER) {
-            current++;
-            return {
-                type: 'NumberLiteral',
-                value: token.value,
-            };
+        
+        function parseChainedTableAccess(tableExpr) {
+            if (current < tokens.length && tokens[current].type === TokenType.LEFT_BRACKET) {
+                current++; // Skip '['
+                const keyExpr = walk();
+                
+                if (current < tokens.length && tokens[current].type === TokenType.RIGHT_BRACKET) {
+                    current++; // Skip ']'
+                    
+                    const access = {
+                        type: 'TableAccess',
+                        table: tableExpr,
+                        key: keyExpr
+                    };
+                    
+                    // Check for chained access
+                    if (current < tokens.length && tokens[current].type === TokenType.DOT) {
+                        return parseChainedDotAccess(access);
+                    }
+                    
+                    // Check if this is a function call
+                    if (current < tokens.length && 
+                        (tokens[current].type === TokenType.IDENTIFIER || 
+                         tokens[current].type === TokenType.NUMBER ||
+                         tokens[current].type === TokenType.STRING ||
+                         tokens[current].type === TokenType.LEFT_PAREN)) {
+                        return parseFunctionCall(access);
+                    }
+                    
+                    return access;
+                } else {
+                    throw new Error('Expected closing bracket');
+                }
+            }
+            
+            // Check for dot access
+            if (current < tokens.length && tokens[current].type === TokenType.DOT) {
+                const result = parseChainedDotAccess(tableExpr);
+                
+                // Check if this is a function call
+                if (current < tokens.length && 
+                    (tokens[current].type === TokenType.IDENTIFIER || 
+                     tokens[current].type === TokenType.NUMBER ||
+                     tokens[current].type === TokenType.STRING ||
+                     tokens[current].type === TokenType.LEFT_PAREN)) {
+                    return parseFunctionCall(result);
+                }
+                
+                return result;
+            }
+            
+            return tableExpr;
         }
-
-        if (token.type === TokenType.PLUS) {
-            current++;
-            return {
-                type: 'PlusExpression',
-                left: walk(),
-                right: walk(),
-            };
+        
+        function detectAmbiguousFunctionCalls() {
+            // This is a placeholder for future ambiguous function call detection
+            // For now, we'll assume the parser handles function calls correctly
         }
-
-        if (token.type === TokenType.IDENTIFIER) {
-            current++;
+        
+        function parseFunctionCall(functionName) {
+            const args = [];
+            
+            // Parse arguments until we hit a semicolon or other terminator
+            while (current < tokens.length && 
+                   tokens[current].type !== TokenType.SEMICOLON &&
+                   tokens[current].type !== TokenType.RIGHT_PAREN &&
+                   tokens[current].type !== TokenType.RIGHT_BRACE &&
+                   tokens[current].type !== TokenType.COMMA) {
+                args.push(parseExpression());
+            }
+            
             return {
-                type: 'Identifier',
-                value: token.value,
+                type: 'FunctionCall',
+                name: functionName,
+                args: args
             };
         }
-
-        if (token.type === TokenType.ASSIGNMENT) {
-            current++;
-            return {
-                type: 'AssignmentExpression',
-                name: tokens[current - 2].value,
-                value: walk(),
-            };
+        
+        function parseExpression() {
+            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 ||
+                    tokens[current].type === TokenType.AND ||
+                    tokens[current].type === TokenType.OR ||
+                    tokens[current].type === TokenType.XOR)) {
+                
+                const operator = tokens[current].type;
+                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;
+                    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;
         }
-
-        if (token.type === TokenType.IF) {
-            current++;
-            let node = {
-                type: 'IfExpression',
-                test: walk(),
-                consequent: walk(),
-                alternate: tokens[current].type === TokenType.ELSE ? (current++, walk()) : null,
-            };
-            return node;
+        
+        function parseTerm() {
+            let left = parseFactor();
+            
+            while (current < tokens.length && 
+                   (tokens[current].type === TokenType.MULTIPLY || 
+                    tokens[current].type === TokenType.DIVIDE ||
+                    tokens[current].type === TokenType.MODULO)) {
+                
+                const operator = tokens[current].type;
+                current++;
+                const right = parseFactor();
+                
+                switch (operator) {
+                    case TokenType.MULTIPLY:
+                        left = { type: 'MultiplyExpression', left, right };
+                        break;
+                    case TokenType.DIVIDE:
+                        left = { type: 'DivideExpression', left, right };
+                        break;
+                    case TokenType.MODULO:
+                        left = { type: 'ModuloExpression', left, right };
+                        break;
+                }
+            }
+            
+            return left;
         }
+        
+        function parseFactor() {
+            let left = parsePrimary();
+            
+            while (current < tokens.length && tokens[current].type === TokenType.POWER) {
+                current++;
+                const right = parsePrimary();
+                left = { type: 'PowerExpression', left, right };
+            }
+            
+            return left;
+        }
+        
+        function parsePrimary() {
+            const token = tokens[current];
+            
+            if (token.type === TokenType.NOT) {
+                current++;
+                const operand = parsePrimary();
+                return { type: 'NotExpression', operand };
+            }
+            
+            if (token.type === TokenType.NUMBER) {
+                current++;
+                return {
+                    type: 'NumberLiteral',
+                    value: token.value
+                };
+            }
+            
+            if (token.type === TokenType.STRING) {
+                current++;
+                return {
+                    type: 'StringLiteral',
+                    value: token.value
+                };
+            }
+            
+            if (token.type === TokenType.TRUE) {
+                current++;
+                return {
+                    type: 'BooleanLiteral',
+                    value: true
+                };
+            }
+            
+            if (token.type === TokenType.FALSE) {
+                current++;
+                return {
+                    type: 'BooleanLiteral',
+                    value: false
+                };
+            }
+            
+            if (token.type === TokenType.LEFT_PAREN) {
+                current++; // Skip '('
+                const parenthesizedExpr = parseExpression();
+                
+                if (current < tokens.length && tokens[current].type === TokenType.RIGHT_PAREN) {
+                    current++; // Skip ')'
+                    return parenthesizedExpr;
+                } else {
+                    throw new Error('Expected closing parenthesis');
+                }
+            }
+            
+            if (token.type === TokenType.IDENTIFIER) {
+                const identifier = {
+                    type: 'Identifier',
+                    value: token.value
+                };
+                current++;
+                
+                // Check if this is an assignment
+                if (current < tokens.length && tokens[current].type === TokenType.ASSIGNMENT) {
+                    current++; // Skip ':'
+                    
+                    // Check if this is a function definition
+                    let isFunction = false;
+                    let params = [];
+                    
+                    // Look ahead to see if this is a function definition
+                    let lookAhead = current;
+                    while (lookAhead < tokens.length && 
+                           tokens[lookAhead].type !== TokenType.ARROW && 
+                           tokens[lookAhead].type !== TokenType.SEMICOLON) {
+                        if (tokens[lookAhead].type === TokenType.IDENTIFIER) {
+                            params.push(tokens[lookAhead].value);
+                        }
+                        lookAhead++;
+                    }
+                    
+                    if (lookAhead < tokens.length && tokens[lookAhead].type === TokenType.ARROW) {
+                        isFunction = true;
+                    }
+                    
+                    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
+                        };
+                    }
+                }
+                
+                // Check if this is table access
+                if (current < tokens.length && 
+                    (tokens[current].type === TokenType.LEFT_BRACKET ||
+                     tokens[current].type === TokenType.DOT)) {
+                    return parseChainedTableAccess(identifier);
+                }
+                
+                // Check if this is a function call
+                if (current < tokens.length && 
+                    (tokens[current].type === TokenType.IDENTIFIER || 
+                     tokens[current].type === TokenType.NUMBER ||
+                     tokens[current].type === TokenType.STRING ||
+                     tokens[current].type === TokenType.LEFT_PAREN)) {
+                    return parseFunctionCall(identifier);
+                }
+                
+                return identifier;
+            }
+            
+            if (token.type === TokenType.FUNCTION_REF) {
+                current++; // Skip '@'
+                if (current < tokens.length && tokens[current].type === TokenType.IDENTIFIER) {
+                    const funcName = tokens[current].value;
+                    current++;
+                    return {
+                        type: 'FunctionReference',
+                        name: funcName
+                    };
+                } else {
+                    throw new Error('Expected function name after @');
+                }
+            }
 
-        if (token.type === TokenType.FUNCTION) {
-            current++;
-            let node = {
-                type: 'FunctionDeclaration',
-                name: tokens[current++].value,
-                params: [],
-                body: [],
-            };
-            while (tokens[current].type !== TokenType.RIGHT_PAREN) {
-                node.params.push(tokens[current++].value);
+            if (token.type === TokenType.WILDCARD) {
+                current++; // Skip '_'
+                return { type: 'WildcardPattern' };
             }
-            current++; // Skip right paren
-            while (tokens[current].type !== TokenType.RIGHT_BRACE) {
-                node.body.push(walk());
+
+            if (token.type === TokenType.CASE) {
+                current++; // Skip 'case'
+                
+                // Parse the value being matched
+                const value = parseExpression();
+                
+                // Expect 'of'
+                if (tokens[current].type !== TokenType.OF) {
+                    throw new Error('Expected "of" after "case"');
+                }
+                current++; // Skip 'of'
+                
+                const cases = [];
+                
+                // Parse cases until we hit a semicolon or end
+                while (current < tokens.length && tokens[current].type !== TokenType.SEMICOLON) {
+                    const pattern = parseExpression();
+                    
+                    // 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 = parseExpression();
+                    cases.push({ 
+                        pattern: [pattern], 
+                        result: [result] 
+                    });
+                }
+                
+                return {
+                    type: 'CaseExpression',
+                    value: [value],
+                    cases,
+                };
             }
-            current++; // Skip right brace
-            return node;
-        }
+            
 
-        if (token.type === TokenType.IDENTIFIER && tokens[current + 1].type === TokenType.LEFT_PAREN) {
-            current++;
-            let node = {
-                type: 'FunctionCall',
-                name: token.value,
-                args: [],
-            };
-            current++; // Skip left paren
-            while (tokens[current].type !== TokenType.RIGHT_PAREN) {
-                node.args.push(walk());
+            
+            // If we get here, it's an operator token that should be handled by parseExpression
+            // But we need to handle it here to avoid circular dependency
+            if (token.type === TokenType.LEFT_BRACE) {
+                current++; // Skip '{'
+                const entries = [];
+                let arrayIndex = 1;
+                
+                while (current < tokens.length && tokens[current].type !== TokenType.RIGHT_BRACE) {
+                    // Skip leading commas
+                    if (tokens[current].type === TokenType.COMMA) {
+                        current++;
+                        continue;
+                    }
+                    
+                    let key = null;
+                    let value;
+                    
+                    // Check if this is a key-value pair or just a value
+                    if (current + 1 < tokens.length && tokens[current + 1].type === TokenType.ASSIGNMENT) {
+                        // This is a key-value pair: key: value
+                        if (tokens[current].type === TokenType.IDENTIFIER) {
+                            key = {
+                                type: 'Identifier',
+                                value: tokens[current].value
+                            };
+                            current++; // Skip the key
+                        } else if (tokens[current].type === TokenType.NUMBER) {
+                            key = {
+                                type: 'NumberLiteral',
+                                value: tokens[current].value,
+                            };
+                            current++; // Skip the key
+                        } else if (tokens[current].type === TokenType.STRING) {
+                            key = {
+                                type: 'StringLiteral',
+                                value: tokens[current].value,
+                            };
+                            current++; // Skip the key
+                        } else if (tokens[current].type === TokenType.TRUE) {
+                            key = {
+                                type: 'BooleanLiteral',
+                                value: true,
+                            };
+                            current++; // Skip the key
+                        } else if (tokens[current].type === TokenType.FALSE) {
+                            key = {
+                                type: 'BooleanLiteral',
+                                value: false,
+                            };
+                            current++; // Skip the key
+                        } else {
+                            throw new Error('Invalid key type in table literal');
+                        }
+                        
+                        current++; // Skip ':'
+                        value = parseExpression();
+                    } else {
+                        // This is just a value (array-like entry)
+                        value = parseExpression();
+                    }
+                    
+                    entries.push({ key, value });
+                    
+                    // Skip trailing commas
+                    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',
+                        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();
             }
-            current++; // Skip right paren
-            return node;
+            
+            // If we get here, we have an unexpected token
+            throw new Error(`Unexpected token in parsePrimary: ${token.type}`);
         }
-
-        if (token.type === TokenType.SEMICOLON) {
+        
+                // 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++;
-            return;
+            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 };
         }
-
-        throw new TypeError(token.type);
+        
+        // Simple wrapper that calls parsePrimary for all token types
+        return parsePrimary();
     }
-
-    let ast = {
+    
+    const ast = {
         type: 'Program',
-        body: [],
+        body: []
     };
-
+    
     while (current < tokens.length) {
         const node = walk();
-        if (node !== null) {
+        if (node) {
             ast.body.push(node);
         }
+        
+        // Skip semicolons
+        if (current < tokens.length && tokens[current].type === TokenType.SEMICOLON) {
+            current++;
+        }
     }
-
+    
     return ast;
 }
 
 // Interpreter
 function interpreter(ast) {
-    let globalScope = {};
-
+    const globalScope = {};
+    initializeStandardLibrary(globalScope);
+    
     function evalNode(node) {
+        if (!node) {
+            return undefined;
+        }
         switch (node.type) {
             case 'NumberLiteral':
-                return parseInt(node.value);
+                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;
+                        } else {
+                            // For other key types (numbers, strings), evaluate normally
+                            key = evalNode(entry.key);
+                        }
+                        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':
-                globalScope[node.name] = evalNode(node.value);
+                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':
-                return globalScope[node.value];
-            case 'IfExpression':
-                return evalNode(node.test) ? evalNode(node.consequent) : node.alternate ? evalNode(node.alternate) : undefined;
+                const identifierValue = globalScope[node.value];
+                if (identifierValue === undefined) {
+                    throw new Error(`Variable ${node.value} is not defined`);
+                }
+                return identifierValue;
             case 'FunctionDeclaration':
-                globalScope[node.name] = function() {
+                // 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]] = arguments[i];
+                        localScope[node.params[i]] = args[i];
                     }
-                    let lastResult;
-                    for (let bodyNode of node.body) {
-                        lastResult = evalNode(bodyNode);
-                    }
-                    return lastResult;
+                    return localEvalNodeWithScope(node.body, localScope);
                 };
-                return;
             case 'FunctionCall':
-                if (globalScope[node.name] instanceof Function) {
+                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 globalScope[node.name].apply(null, args);
+                    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(' ');
+                    }
+                }
+                throw new Error('No matching pattern found');
+            case 'WildcardPattern':
+                return true;
+            case 'IOInExpression':
+                const readline = require('readline');
+                const rl = readline.createInterface({
+                    input: process.stdin,
+                    output: process.stdout
+                });
+                
+                return new Promise((resolve) => {
+                    rl.question('', (input) => {
+                        rl.close();
+                        const num = parseInt(input);
+                        resolve(isNaN(num) ? input : num);
+                    });
+                });
+            case 'IOOutExpression':
+                const outputValue = evalNode(node.value);
+                console.log(outputValue);
+                return outputValue;
+            case 'IOAssertExpression':
+                const assertionValue = evalNode(node.value);
+                if (!assertionValue) {
+                    throw new Error('Assertion failed');
+                }
+                return assertionValue;
+            case 'FunctionReference':
+                const functionValue = globalScope[node.name];
+                if (functionValue === undefined) {
+                    throw new Error(`Function ${node.name} is not defined`);
                 }
-                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 evalNode(ast.body[0]);
+    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;
+                        } else {
+                            // For other key types (numbers, strings), evaluate normally
+                            key = localEvalNodeWithScope(entry.key, scope);
+                        }
+                        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 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 (matches) {
+                        const results = caseItem.result.map(res => localEvalNodeWithScope(res, scope));
+                        if (results.length === 1) {
+                            return results[0];
+                        }
+                        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);
+                    });
+                });
+            case 'IOOutExpression':
+                const localOutputValue = localEvalNodeWithScope(node.value, scope);
+                console.log(localOutputValue);
+                return localOutputValue;
+            case 'IOAssertExpression':
+                const localAssertionValue = localEvalNodeWithScope(node.value, scope);
+                if (!localAssertionValue) {
+                    throw new Error('Assertion failed');
+                }
+                return localAssertionValue;
+            case 'FunctionReference':
+                const localFunctionValue = globalScope[node.name];
+                if (localFunctionValue === undefined) {
+                    throw new Error(`Function ${node.name} is not defined`);
+                }
+                if (typeof localFunctionValue !== 'function') {
+                    throw new Error(`${node.name} is not a function`);
+                }
+                return localFunctionValue;
+            default:
+                throw new Error(`Unknown node type: ${node.type}`);
+        }
+    };
+
+    const localEvalNode = (node) => {
+        if (!node) {
+            return undefined;
+        }
+        switch (node.type) {
+            case 'NumberLiteral':
+                return parseFloat(node.value);
+            case 'StringLiteral':
+                return node.value;
+            case 'BooleanLiteral':
+                return node.value;
+            case 'PlusExpression':
+                return localEvalNode(node.left) + localEvalNode(node.right);
+            case 'MinusExpression':
+                return localEvalNode(node.left) - localEvalNode(node.right);
+            case 'MultiplyExpression':
+                return localEvalNode(node.left) * localEvalNode(node.right);
+            case 'DivideExpression':
+                const divisor = localEvalNode(node.right);
+                if (divisor === 0) {
+                    throw new Error('Division by zero');
+                }
+                return localEvalNode(node.left) / localEvalNode(node.right);
+            case 'ModuloExpression':
+                return localEvalNode(node.left) % localEvalNode(node.right);
+            case 'PowerExpression':
+                return Math.pow(localEvalNode(node.left), localEvalNode(node.right));
+            case 'EqualsExpression':
+                return localEvalNode(node.left) === localEvalNode(node.right);
+            case 'LessThanExpression':
+                return localEvalNode(node.left) < localEvalNode(node.right);
+            case 'GreaterThanExpression':
+                return localEvalNode(node.left) > localEvalNode(node.right);
+            case 'LessEqualExpression':
+                return localEvalNode(node.left) <= localEvalNode(node.right);
+            case 'GreaterEqualExpression':
+                return localEvalNode(node.left) >= localEvalNode(node.right);
+            case 'NotEqualExpression':
+                return localEvalNode(node.left) !== localEvalNode(node.right);
+            case 'AndExpression':
+                return localEvalNode(node.left) && localEvalNode(node.right);
+            case 'OrExpression':
+                return localEvalNode(node.left) || localEvalNode(node.right);
+            case 'XorExpression':
+                const leftVal = localEvalNode(node.left);
+                const rightVal = localEvalNode(node.right);
+                return (leftVal && !rightVal) || (!leftVal && rightVal);
+            case 'NotExpression':
+                return !localEvalNode(node.operand);
+            case 'TableLiteral':
+                const table = {};
+                let arrayIndex = 1;
+                
+                for (const entry of node.entries) {
+                    if (entry.key === null) {
+                        // Array-like entry: {1, 2, 3}
+                        table[arrayIndex] = localEvalNode(entry.value);
+                        arrayIndex++;
+                    } else {
+                        // Key-value entry: {name: "Alice", age: 30}
+                        let key;
+                        if (entry.key.type === 'Identifier') {
+                            // Convert identifier keys to strings
+                            key = entry.key.value;
+                        } else {
+                            // For other key types (numbers, strings), evaluate normally
+                            key = localEvalNode(entry.key);
+                        }
+                        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 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 (matches) {
+                        const results = caseItem.result.map(localEvalNode);
+                        if (results.length === 1) {
+                            return results[0];
+                        }
+                        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);
+                    });
+                });
+            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}`);
+        }
+    };
+
+    let lastResult;
+    for (let node of ast.body) {
+        if (node) {
+            lastResult = evalNode(node);
+        }
+    }
+    
+    if (lastResult instanceof Promise) {
+        return lastResult.then(result => {
+            return result;
+        });
+    }
+    
+    return lastResult;
 }
 
-// Usage
-// const tokens = lexer('2 + 2');
-// const ast = parser(tokens);
-// const result = interpreter(ast);
-// console.log(result); // 4
+// Debug logging function
+function debugLog(message, data = null) {
+    if (process.env.DEBUG) {
+        console.log(`[DEBUG] ${message}`);
+        if (data) {
+            console.log(data);
+        }
+    }
+}
 
-// const tokens2 = lexer('x : 2 + 2');
-// const ast2 = parser(tokens2);
-// const result2 = interpreter(ast2);
-// console.log(result2); 
+// Debug error function
+function debugError(message, error = null) {
+    if (process.env.DEBUG) {
+        console.error(`[DEBUG ERROR] ${message}`);
+        if (error) {
+            console.error(error);
+        }
+    }
+}
 
-const fs = require('fs');
+// Execute a file
+function executeFile(filePath) {
+    try {
+        const fs = require('fs');
+        const input = fs.readFileSync(filePath, 'utf8');
+        
+        debugLog('Input:', input);
+        
+        const tokens = lexer(input);
+        debugLog('Tokens:', tokens);
+        
+        const ast = parser(tokens);
+        debugLog('AST:', JSON.stringify(ast, null, 2));
+        
+        const result = interpreter(ast);
+        
+        if (result instanceof Promise) {
+            result.then(finalResult => {
+                if (finalResult !== undefined) {
+                    console.log(finalResult);
+                }
+            }).catch(error => {
+                console.error(`Error executing file: ${error.message}`);
+            });
+        } else {
+            if (result !== undefined) {
+                console.log(result);
+            }
+        }
+    } catch (error) {
+        console.error(`Error executing file: ${error.message}`);
+    }
+}
 
-// Read the input from a file
-const input = fs.readFileSync('input.txt', 'utf-8');
+// Check command line arguments
+const args = process.argv.slice(2);
 
-// Usage
-const tokens = lexer(input);
-const ast = parser(tokens);
-const result = interpreter(ast);
-console.log(result);
\ No newline at end of file
+if (args.length === 0) {
+    console.error('Usage: node lang.js <file>');
+    console.error('  Provide a file path to execute');
+    process.exit(1);
+} else if (args.length === 1) {
+    // Execute the file
+    const filePath = args[0];
+    executeFile(filePath);
+} else {
+    // Too many arguments
+    console.error('Usage: node lang.js <file>');
+    console.error('  Provide exactly one file path to execute');
+    process.exit(1);
+}
\ No newline at end of file