diff options
Diffstat (limited to 'js/scripting-lang/lang.js')
-rw-r--r-- | js/scripting-lang/lang.js | 466 |
1 files changed, 290 insertions, 176 deletions
diff --git a/js/scripting-lang/lang.js b/js/scripting-lang/lang.js index 3ed32a1..070998e 100644 --- a/js/scripting-lang/lang.js +++ b/js/scripting-lang/lang.js @@ -5,6 +5,91 @@ import { lexer, TokenType } from './lexer.js'; import { parser } from './parser.js'; +// Cross-platform environment detection +const isNode = typeof process !== 'undefined' && process.versions && process.versions.node; +const isBun = typeof process !== 'undefined' && process.versions && process.versions.bun; +const isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined'; + +// Cross-platform debug flag +const DEBUG = (isNode && process.env.DEBUG) || (isBrowser && window.DEBUG) || false; + +// Cross-platform IO operations +const createReadline = () => { + if (isNode || isBun) { + const readline = require('readline'); + return readline.createInterface({ + input: process.stdin, + output: process.stdout + }); + } else if (isBrowser) { + // Browser fallback - use prompt() for now + return { + question: (prompt, callback) => { + const result = window.prompt(prompt); + callback(result); + }, + close: () => {} + }; + } else { + // Fallback for other environments + return { + question: (prompt, callback) => { + callback("fallback input"); + }, + close: () => {} + }; + } +}; + +const createFileSystem = () => { + if (isNode || isBun) { + return require('fs'); + } else if (isBrowser) { + // Browser fallback - return a mock filesystem + return { + readFile: (path, encoding, callback) => { + callback(new Error('File system not available in browser')); + }, + writeFile: (path, data, callback) => { + callback(new Error('File system not available in browser')); + } + }; + } else { + // Fallback for other environments + return { + readFile: (path, encoding, callback) => { + callback(new Error('File system not available in this environment')); + }, + writeFile: (path, data, callback) => { + callback(new Error('File system not available in this environment')); + } + }; + } +}; + +// Cross-platform console output +const safeConsoleLog = (message) => { + if (typeof console !== 'undefined') { + console.log(message); + } +}; + +const safeConsoleError = (message) => { + if (typeof console !== 'undefined') { + console.error(message); + } +}; + +// Cross-platform process exit +const safeExit = (code) => { + if (isNode || isBun) { + process.exit(code); + } else if (isBrowser) { + // In browser, we can't exit, but we can throw an error or redirect + throw new Error(`Process would exit with code ${code}`); + } +}; + /** * Environment interface for external system integration * @@ -47,6 +132,7 @@ import { parser } from './parser.js'; * function arguments and validation of input data. */ function initializeStandardLibrary(scope) { + /** * Map: Apply a function to a value or collection * @param {Function} f - Function to apply @@ -385,10 +471,10 @@ function initializeStandardLibrary(scope) { * application. */ scope.reduce = function(f, init, x) { - if (process.env.DEBUG) { - console.log(`[DEBUG] reduce: f =`, typeof f, f); - console.log(`[DEBUG] reduce: init =`, init); - console.log(`[DEBUG] reduce: x =`, x); + if (DEBUG) { + safeConsoleLog(`[DEBUG] reduce: f =`, typeof f, f); + safeConsoleLog(`[DEBUG] reduce: init =`, init); + safeConsoleLog(`[DEBUG] reduce: x =`, x); } if (typeof f !== 'function') { @@ -398,10 +484,10 @@ function initializeStandardLibrary(scope) { if (init === undefined) { // Partial application: return a function that waits for the remaining arguments return function(init, x) { - if (process.env.DEBUG) { - console.log(`[DEBUG] reduce returned function: f =`, typeof f, f); - console.log(`[DEBUG] reduce returned function: init =`, init); - console.log(`[DEBUG] reduce returned function: x =`, x); + if (DEBUG) { + safeConsoleLog(`[DEBUG] reduce returned function: f =`, typeof f, f); + safeConsoleLog(`[DEBUG] reduce returned function: init =`, init); + safeConsoleLog(`[DEBUG] reduce returned function: x =`, x); } if (x === undefined) { // Still partial application @@ -496,6 +582,12 @@ function initializeStandardLibrary(scope) { * operations through the combinator foundation. */ scope.add = function(x, y) { + if (y === undefined) { + // Partial application: return a function that waits for the second argument + return function(y) { + return x + y; + }; + } return x + y; }; @@ -506,6 +598,12 @@ function initializeStandardLibrary(scope) { * @returns {number} Difference of x and y */ scope.subtract = function(x, y) { + if (y === undefined) { + // Partial application: return a function that waits for the second argument + return function(y) { + return x - y; + }; + } return x - y; }; @@ -528,6 +626,12 @@ function initializeStandardLibrary(scope) { * operations through the combinator foundation. */ scope.multiply = function(x, y) { + if (y === undefined) { + // Partial application: return a function that waits for the second argument + return function(y) { + return x * y; + }; + } return x * y; }; @@ -539,6 +643,15 @@ function initializeStandardLibrary(scope) { * @throws {Error} When second argument is zero */ scope.divide = function(x, y) { + if (y === undefined) { + // Partial application: return a function that waits for the second argument + return function(y) { + if (y === 0) { + throw new Error('Division by zero'); + } + return x / y; + }; + } if (y === 0) { throw new Error('Division by zero'); } @@ -552,6 +665,12 @@ function initializeStandardLibrary(scope) { * @returns {number} Remainder of x divided by y */ scope.modulo = function(x, y) { + if (y === undefined) { + // Partial application: return a function that waits for the second argument + return function(y) { + return x % y; + }; + } return x % y; }; @@ -562,6 +681,12 @@ function initializeStandardLibrary(scope) { * @returns {number} x raised to the power of y */ scope.power = function(x, y) { + if (y === undefined) { + // Partial application: return a function that waits for the second argument + return function(y) { + return Math.pow(x, y); + }; + } return Math.pow(x, y); }; @@ -798,9 +923,9 @@ function initializeStandardLibrary(scope) { * transformations. */ scope.each = function(f, x) { - if (process.env.DEBUG) { - console.log(`[DEBUG] each called with: f=${typeof f}, x=${typeof x}`); - console.log(`[DEBUG] x value:`, x); + if (DEBUG) { + safeConsoleLog(`[DEBUG] each called with: f=${typeof f}, x=${typeof x}`); + safeConsoleLog(`[DEBUG] x value:`, x); } if (typeof f !== 'function') { @@ -1250,10 +1375,10 @@ function interpreter(ast, environment = null, initialState = {}) { let ioOperationsPerformed = false; // Debug: Check if combinators are available - if (process.env.DEBUG) { - console.log('[DEBUG] Available functions in global scope:', Object.keys(globalScope)); - console.log('[DEBUG] add function exists:', typeof globalScope.add === 'function'); - console.log('[DEBUG] subtract function exists:', typeof globalScope.subtract === 'function'); + if (DEBUG) { + safeConsoleLog('[DEBUG] Available functions in global scope:', Object.keys(globalScope)); + safeConsoleLog('[DEBUG] add function exists:', typeof globalScope.add === 'function'); + safeConsoleLog('[DEBUG] subtract function exists:', typeof globalScope.subtract === 'function'); } // Reset call stack tracker at the start of interpretation @@ -1380,8 +1505,8 @@ function interpreter(ast, environment = null, initialState = {}) { key = evalNode(entry.key); } // Special handling for FunctionDeclaration nodes - if (process.env.DEBUG) { - console.log(`[DEBUG] TableLiteral: entry.value.type = ${entry.value.type}`); + if (DEBUG) { + safeConsoleLog(`[DEBUG] TableLiteral: entry.value.type = ${entry.value.type}`); } if (entry.value.type === 'FunctionDeclaration') { // Don't evaluate the function body, just create the function @@ -1577,27 +1702,27 @@ function interpreter(ast, environment = null, initialState = {}) { if (typeof node.name === 'string') { // Regular function call with string name funcToCall = globalScope[node.name]; - if (process.env.DEBUG) { - console.log(`[DEBUG] FunctionCall: looking up function '${node.name}' in globalScope, found:`, typeof funcToCall); + if (DEBUG) { + safeConsoleLog(`[DEBUG] FunctionCall: looking up function '${node.name}' in globalScope, found:`, typeof funcToCall); } } else if (node.name.type === 'Identifier') { // Function call with identifier funcToCall = globalScope[node.name.value]; - if (process.env.DEBUG) { - console.log(`[DEBUG] FunctionCall: looking up function '${node.name.value}' in globalScope, found:`, typeof funcToCall); + if (DEBUG) { + safeConsoleLog(`[DEBUG] FunctionCall: looking up function '${node.name.value}' in globalScope, found:`, typeof funcToCall); } } else { // Function call from expression (e.g., parenthesized function, higher-order) funcToCall = evalNode(node.name); - if (process.env.DEBUG) { - console.log(`[DEBUG] FunctionCall: evaluated function expression, found:`, typeof funcToCall); + if (DEBUG) { + safeConsoleLog(`[DEBUG] FunctionCall: evaluated function expression, found:`, typeof funcToCall); } } - if (funcToCall instanceof Function) { + if (typeof funcToCall === 'function') { let args = node.args.map(evalNode); - if (process.env.DEBUG) { - console.log(`[DEBUG] FunctionCall: calling function with args:`, args); + if (DEBUG) { + safeConsoleLog(`[DEBUG] FunctionCall: calling function with args:`, args); } return funcToCall(...args); } @@ -1608,16 +1733,16 @@ function interpreter(ast, environment = null, initialState = {}) { ? node.value.map(evalNode) : [evalNode(node.value)]; - if (process.env.DEBUG) { - console.log(`[DEBUG] WhenExpression: whenValues =`, whenValues); + if (DEBUG) { + safeConsoleLog(`[DEBUG] WhenExpression: whenValues =`, whenValues); } for (const caseItem of node.cases) { // Handle both single patterns and arrays of patterns const patterns = caseItem.pattern.map(evalNode); - if (process.env.DEBUG) { - console.log(`[DEBUG] WhenExpression: patterns =`, patterns); + if (DEBUG) { + safeConsoleLog(`[DEBUG] WhenExpression: patterns =`, patterns); } // Check if patterns match the values @@ -1629,14 +1754,14 @@ function interpreter(ast, environment = null, initialState = {}) { const value = whenValues[i]; const pattern = patterns[i]; - if (process.env.DEBUG) { - console.log(`[DEBUG] WhenExpression: comparing value ${value} with pattern ${pattern}`); + if (DEBUG) { + safeConsoleLog(`[DEBUG] WhenExpression: comparing value ${value} with pattern ${pattern}`); } if (pattern === true) { // Wildcard pattern // Wildcard always matches - if (process.env.DEBUG) { - console.log(`[DEBUG] WhenExpression: wildcard matches`); + if (DEBUG) { + safeConsoleLog(`[DEBUG] WhenExpression: wildcard matches`); } continue; } else if (typeof pattern === 'object' && pattern.type === 'FunctionCall') { @@ -1652,20 +1777,20 @@ function interpreter(ast, environment = null, initialState = {}) { }; } const patternResult = evalNode(patternToEvaluate); - if (process.env.DEBUG) { - console.log(`[DEBUG] WhenExpression: boolean pattern result = ${patternResult}`); + if (DEBUG) { + safeConsoleLog(`[DEBUG] WhenExpression: boolean pattern result = ${patternResult}`); } if (!patternResult) { matches = false; - if (process.env.DEBUG) { - console.log(`[DEBUG] WhenExpression: boolean pattern does not match`); + if (DEBUG) { + safeConsoleLog(`[DEBUG] WhenExpression: boolean pattern does not match`); } break; - } else { - if (process.env.DEBUG) { - console.log(`[DEBUG] WhenExpression: boolean pattern matches`); + } else { + if (DEBUG) { + safeConsoleLog(`[DEBUG] WhenExpression: boolean pattern matches`); + } } - } } else if (typeof pattern === 'object' && pattern !== null && typeof value === 'object' && value !== null) { // Table pattern matching - check if all pattern properties exist in value let tableMatches = true; @@ -1677,31 +1802,31 @@ function interpreter(ast, environment = null, initialState = {}) { } if (!tableMatches) { matches = false; - if (process.env.DEBUG) { - console.log(`[DEBUG] WhenExpression: table pattern does not match`); + if (DEBUG) { + safeConsoleLog(`[DEBUG] WhenExpression: table pattern does not match`); } break; - } else { - if (process.env.DEBUG) { - console.log(`[DEBUG] WhenExpression: table pattern matches`); + } else { + if (DEBUG) { + safeConsoleLog(`[DEBUG] WhenExpression: table pattern matches`); + } } - } } else if (value !== pattern) { matches = false; - if (process.env.DEBUG) { - console.log(`[DEBUG] WhenExpression: pattern does not match`); + if (DEBUG) { + safeConsoleLog(`[DEBUG] WhenExpression: pattern does not match`); } break; } else { - if (process.env.DEBUG) { - console.log(`[DEBUG] WhenExpression: pattern matches`); + if (DEBUG) { + safeConsoleLog(`[DEBUG] WhenExpression: pattern matches`); } } } } - if (process.env.DEBUG) { - console.log(`[DEBUG] WhenExpression: case matches = ${matches}`); + if (DEBUG) { + safeConsoleLog(`[DEBUG] WhenExpression: case matches = ${matches}`); } if (matches) { @@ -1716,11 +1841,7 @@ function interpreter(ast, environment = null, initialState = {}) { case 'WildcardPattern': return true; case 'IOInExpression': - const readline = require('readline'); - const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout - }); + const rl = createReadline(); return new Promise((resolve) => { rl.question('', (input) => { @@ -1731,7 +1852,7 @@ function interpreter(ast, environment = null, initialState = {}) { }); case 'IOOutExpression': const outputValue = evalNode(node.value); - console.log(outputValue); + safeConsoleLog(outputValue); ioOperationsPerformed = true; return outputValue; case 'IOAssertExpression': @@ -1743,13 +1864,13 @@ function interpreter(ast, environment = null, initialState = {}) { case 'IOListenExpression': // Return current state from environment if available, otherwise placeholder if (environment && typeof environment.getCurrentState === 'function') { - if (process.env.DEBUG) { - console.log('[DEBUG] ..listen called - returning state from environment'); + if (DEBUG) { + safeConsoleLog('[DEBUG] ..listen called - returning state from environment'); } return environment.getCurrentState(); } else { - if (process.env.DEBUG) { - console.log('[DEBUG] ..listen called - returning placeholder state'); + if (DEBUG) { + safeConsoleLog('[DEBUG] ..listen called - returning placeholder state'); } return { status: 'placeholder', message: 'State not available in standalone mode' }; } @@ -1757,19 +1878,19 @@ function interpreter(ast, environment = null, initialState = {}) { const emitValue = evalNode(node.value); // Send value to environment if available, otherwise log to console if (environment && typeof environment.emitValue === 'function') { - if (process.env.DEBUG) { - console.log('[DEBUG] ..emit called - sending to environment'); + if (DEBUG) { + safeConsoleLog('[DEBUG] ..emit called - sending to environment'); } environment.emitValue(emitValue); } else { - console.log('[EMIT]', emitValue); + safeConsoleLog('[EMIT]', emitValue); } ioOperationsPerformed = true; return emitValue; case 'FunctionReference': const functionValue = globalScope[node.name]; - if (process.env.DEBUG) { - console.log(`[DEBUG] FunctionReference: looking up '${node.name}' in globalScope, found:`, typeof functionValue); + if (DEBUG) { + safeConsoleLog(`[DEBUG] FunctionReference: looking up '${node.name}' in globalScope, found:`, typeof functionValue); } if (functionValue === undefined) { throw new Error(`Function ${node.name} is not defined`); @@ -2016,16 +2137,16 @@ function interpreter(ast, environment = null, initialState = {}) { ? node.value.map(val => localEvalNodeWithScope(val, scope)) : [localEvalNodeWithScope(node.value, scope)]; - if (process.env.DEBUG) { - console.log(`[DEBUG] localEvalNodeWithScope WhenExpression: whenValues =`, whenValues); + if (DEBUG) { + safeConsoleLog(`[DEBUG] localEvalNodeWithScope WhenExpression: whenValues =`, whenValues); } for (const caseItem of node.cases) { // Handle both single patterns and arrays of patterns const patterns = caseItem.pattern.map(pat => localEvalNodeWithScope(pat, scope)); - if (process.env.DEBUG) { - console.log(`[DEBUG] localEvalNodeWithScope WhenExpression: patterns =`, patterns); + if (DEBUG) { + safeConsoleLog(`[DEBUG] localEvalNodeWithScope WhenExpression: patterns =`, patterns); } // Check if patterns match the values @@ -2037,14 +2158,14 @@ function interpreter(ast, environment = null, initialState = {}) { const value = whenValues[i]; const pattern = patterns[i]; - if (process.env.DEBUG) { - console.log(`[DEBUG] localEvalNodeWithScope WhenExpression: comparing value ${value} with pattern ${pattern}`); + if (DEBUG) { + safeConsoleLog(`[DEBUG] localEvalNodeWithScope WhenExpression: comparing value ${value} with pattern ${pattern}`); } if (pattern === true) { // Wildcard pattern // Wildcard always matches - if (process.env.DEBUG) { - console.log(`[DEBUG] localEvalNodeWithScope WhenExpression: wildcard matches`); + if (DEBUG) { + safeConsoleLog(`[DEBUG] localEvalNodeWithScope WhenExpression: wildcard matches`); } continue; } else if (typeof pattern === 'object' && pattern !== null && typeof value === 'object' && value !== null) { @@ -2058,31 +2179,31 @@ function interpreter(ast, environment = null, initialState = {}) { } if (!tableMatches) { matches = false; - if (process.env.DEBUG) { - console.log(`[DEBUG] localEvalNodeWithScope WhenExpression: table pattern does not match`); + if (DEBUG) { + safeConsoleLog(`[DEBUG] localEvalNodeWithScope WhenExpression: table pattern does not match`); } break; - } else { - if (process.env.DEBUG) { - console.log(`[DEBUG] localEvalNodeWithScope WhenExpression: table pattern matches`); + } else { + if (DEBUG) { + safeConsoleLog(`[DEBUG] localEvalNodeWithScope WhenExpression: table pattern matches`); + } } - } } else if (value !== pattern) { matches = false; - if (process.env.DEBUG) { - console.log(`[DEBUG] localEvalNodeWithScope WhenExpression: pattern does not match`); + if (DEBUG) { + safeConsoleLog(`[DEBUG] localEvalNodeWithScope WhenExpression: pattern does not match`); } break; } else { - if (process.env.DEBUG) { - console.log(`[DEBUG] localEvalNodeWithScope WhenExpression: pattern matches`); + if (DEBUG) { + safeConsoleLog(`[DEBUG] localEvalNodeWithScope WhenExpression: pattern matches`); } } } } - if (process.env.DEBUG) { - console.log(`[DEBUG] localEvalNodeWithScope WhenExpression: case matches = ${matches}`); + if (DEBUG) { + safeConsoleLog(`[DEBUG] localEvalNodeWithScope WhenExpression: case matches = ${matches}`); } if (matches) { @@ -2097,22 +2218,18 @@ function interpreter(ast, environment = null, initialState = {}) { case 'WildcardPattern': return true; case 'IOInExpression': - const readline = require('readline'); - const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout - }); + const rl2 = createReadline(); return new Promise((resolve) => { - rl.question('', (input) => { - rl.close(); + rl2.question('', (input) => { + rl2.close(); const num = parseInt(input); resolve(isNaN(num) ? input : num); }); }); case 'IOOutExpression': const localOutputValue = localEvalNodeWithScope(node.value, scope); - console.log(localOutputValue); + safeConsoleLog(localOutputValue); ioOperationsPerformed = true; return localOutputValue; case 'IOAssertExpression': @@ -2124,13 +2241,13 @@ function interpreter(ast, environment = null, initialState = {}) { case 'IOListenExpression': // Return current state from environment if available, otherwise placeholder if (environment && typeof environment.getCurrentState === 'function') { - if (process.env.DEBUG) { - console.log('[DEBUG] ..listen called - returning state from environment'); + if (DEBUG) { + safeConsoleLog('[DEBUG] ..listen called - returning state from environment'); } return environment.getCurrentState(); } else { - if (process.env.DEBUG) { - console.log('[DEBUG] ..listen called - returning placeholder state'); + if (DEBUG) { + safeConsoleLog('[DEBUG] ..listen called - returning placeholder state'); } return { status: 'placeholder', message: 'State not available in standalone mode' }; } @@ -2138,12 +2255,12 @@ function interpreter(ast, environment = null, initialState = {}) { const localEmitValue = localEvalNodeWithScope(node.value, scope); // Send value to environment if available, otherwise log to console if (environment && typeof environment.emitValue === 'function') { - if (process.env.DEBUG) { - console.log('[DEBUG] ..emit called - sending to environment'); + if (DEBUG) { + safeConsoleLog('[DEBUG] ..emit called - sending to environment'); } environment.emitValue(localEmitValue); } else { - console.log('[EMIT]', localEmitValue); + safeConsoleLog('[EMIT]', localEmitValue); } ioOperationsPerformed = true; return localEmitValue; @@ -2428,22 +2545,18 @@ function interpreter(ast, environment = null, initialState = {}) { case 'WildcardPattern': return true; case 'IOInExpression': - const readline = require('readline'); - const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout - }); + const rl3 = createReadline(); return new Promise((resolve) => { - rl.question('', (input) => { - rl.close(); + rl3.question('', (input) => { + rl3.close(); const num = parseInt(input); resolve(isNaN(num) ? input : num); }); }); case 'IOOutExpression': const localOutputValue = localEvalNode(node.value); - console.log(localOutputValue); + safeConsoleLog(localOutputValue); ioOperationsPerformed = true; return localOutputValue; case 'IOAssertExpression': @@ -2455,13 +2568,13 @@ function interpreter(ast, environment = null, initialState = {}) { case 'IOListenExpression': // Return current state from environment if available, otherwise placeholder if (environment && typeof environment.getCurrentState === 'function') { - if (process.env.DEBUG) { - console.log('[DEBUG] ..listen called - returning state from environment'); + if (DEBUG) { + safeConsoleLog('[DEBUG] ..listen called - returning state from environment'); } return environment.getCurrentState(); } else { - if (process.env.DEBUG) { - console.log('[DEBUG] ..listen called - returning placeholder state'); + if (DEBUG) { + safeConsoleLog('[DEBUG] ..listen called - returning placeholder state'); } return { status: 'placeholder', message: 'State not available in standalone mode' }; } @@ -2469,12 +2582,12 @@ function interpreter(ast, environment = null, initialState = {}) { const localEmitValue = localEvalNode(node.value); // Send value to environment if available, otherwise log to console if (environment && typeof environment.emitValue === 'function') { - if (process.env.DEBUG) { - console.log('[DEBUG] ..emit called - sending to environment'); + if (DEBUG) { + safeConsoleLog('[DEBUG] ..emit called - sending to environment'); } environment.emitValue(localEmitValue); } else { - console.log('[EMIT]', localEmitValue); + safeConsoleLog('[EMIT]', localEmitValue); } ioOperationsPerformed = true; return localEmitValue; @@ -2586,10 +2699,10 @@ function run(scriptContent, initialState = {}, environment = null) { * expressions and function applications. */ function debugLog(message, data = null) { - if (process.env.DEBUG) { - console.log(`[DEBUG] ${message}`); + if (DEBUG) { + safeConsoleLog(`[DEBUG] ${message}`); if (data) { - console.log(data); + safeConsoleLog(data); } } } @@ -2613,10 +2726,10 @@ function debugLog(message, data = null) { * execution pipeline. */ function debugError(message, error = null) { - if (process.env.DEBUG) { - console.error(`[DEBUG ERROR] ${message}`); + if (DEBUG) { + safeConsoleError(`[DEBUG ERROR] ${message}`); if (error) { - console.error(error); + safeConsoleError(error); } } } @@ -2677,8 +2790,8 @@ const callStackTracker = { 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}`); + if (DEBUG && this.stack.length % 100 === 0) { + safeConsoleLog(`[DEBUG] Call stack depth: ${this.stack.length}, Max: ${this.maxDepth}`); } }, @@ -2738,22 +2851,18 @@ const callStackTracker = { * workflow where tests and examples are stored as .txt files. */ async function readFile(filePath) { - // Check if we're in a browser environment - if (typeof window !== 'undefined') { - // Browser environment - would need to implement file input or fetch - throw new Error('File I/O not supported in browser environment'); - } + // Use cross-platform filesystem + const fs = createFileSystem(); - // Node.js or Bun environment - try { - // Try dynamic import for ES modules compatibility - const fs = await import('fs'); - return fs.readFileSync(filePath, 'utf8'); - } catch (error) { - // Fallback to require for older Node.js versions - const fs = require('fs'); - return fs.readFileSync(filePath, 'utf8'); - } + return new Promise((resolve, reject) => { + fs.readFile(filePath, 'utf8', (error, data) => { + if (error) { + reject(error); + } else { + resolve(data); + } + }); + }); } /** @@ -2807,50 +2916,50 @@ async function executeFile(filePath) { if (result instanceof Promise) { result.then(finalResult => { // Only output result if debug mode is enabled (no automatic final result output) - if (finalResult.result !== undefined && process.env.DEBUG) { - console.log(finalResult.result); + if (finalResult.result !== undefined && DEBUG) { + safeConsoleLog(finalResult.result); } // Print call stack statistics only in debug mode - if (process.env.DEBUG) { + if (DEBUG) { 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)); + safeConsoleLog('\n=== CALL STACK STATISTICS ==='); + safeConsoleLog('Maximum call stack depth:', stats.maxDepth); + safeConsoleLog('Function call counts:', JSON.stringify(stats.callCounts, null, 2)); } }).catch(error => { - console.error(`Error executing file: ${error.message}`); + safeConsoleError(`Error executing file: ${error.message}`); // Print call stack statistics on error only in debug mode - if (process.env.DEBUG) { + if (DEBUG) { 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)); + safeConsoleError('\n=== CALL STACK STATISTICS ON ERROR ==='); + safeConsoleError('Maximum call stack depth:', stats.maxDepth); + safeConsoleError('Function call counts:', JSON.stringify(stats.callCounts, null, 2)); } - process.exit(1); + safeExit(1); }); } else { // Only output result if debug mode is enabled (no automatic final result output) - if (result.result !== undefined && process.env.DEBUG) { - console.log(result.result); + if (result.result !== undefined && DEBUG) { + safeConsoleLog(result.result); } // Print call stack statistics only in debug mode - if (process.env.DEBUG) { + if (DEBUG) { 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)); + safeConsoleLog('\n=== CALL STACK STATISTICS ==='); + safeConsoleLog('Maximum call stack depth:', stats.maxDepth); + safeConsoleLog('Function call counts:', JSON.stringify(stats.callCounts, null, 2)); } } } catch (error) { - console.error(`Error executing file: ${error.message}`); + safeConsoleError(`Error executing file: ${error.message}`); // Print call stack statistics on error only in debug mode - if (process.env.DEBUG) { + if (DEBUG) { 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)); + safeConsoleError('\n=== CALL STACK STATISTICS ON ERROR ==='); + safeConsoleError('Maximum call stack depth:', stats.maxDepth); + safeConsoleError('Function call counts:', JSON.stringify(stats.callCounts, null, 2)); } - process.exit(1); + safeExit(1); } } @@ -2868,29 +2977,34 @@ async function executeFile(filePath) { * Exits with appropriate error codes for different failure scenarios. */ async function main() { + // Only run main function in Node.js/Bun environments + if (!isNode && !isBun) { + return; // Skip in browser environment + } + const args = process.argv.slice(2); if (args.length === 0) { - console.error('Usage: node lang.js <file>'); - console.error(' Provide a file path to execute'); - process.exit(1); + safeConsoleError('Usage: node lang.js <file>'); + safeConsoleError(' Provide a file path to execute'); + safeExit(1); } else if (args.length === 1) { // Execute the file const filePath = args[0]; await executeFile(filePath); } else { // Too many arguments - console.error('Usage: node lang.js <file>'); - console.error(' Provide exactly one file path to execute'); - process.exit(1); + safeConsoleError('Usage: node lang.js <file>'); + safeConsoleError(' Provide exactly one file path to execute'); + safeExit(1); } } -// Start the program only if this file is run directly -if (process.argv[1] && process.argv[1].endsWith('lang.js')) { +// Start the program only if this file is run directly in Node.js/Bun +if ((isNode || isBun) && process.argv[1] && process.argv[1].endsWith('lang.js')) { main().catch(error => { - console.error('Fatal error:', error.message); - process.exit(1); + safeConsoleError('Fatal error:', error.message); + safeExit(1); }); } |