UNPKG

petcarescript

Version:

PetCareScript - A modern, expressive programming language designed for humans

1,422 lines (1,266 loc) 112 kB
/** * PetCareScript Interpreter * Executes the abstract syntax tree - VERSÃO MELHORADA E OTIMIZADA */ const { TokenType } = require('../lexer/tokens'); const Environment = require('./environment'); const { PCFunction, PCBlueprint, PCInstance, ParentProxy, ReturnException, BreakException, ContinueException } = require('../runtime/runtime'); class Interpreter { constructor() { this.globals = new Environment(); this.environment = this.globals; this.locals = new Map(); this.moduleCache = new Map(); this.defineNatives(); } // Métodos de módulos melhorados importModule(modulePath) { const fs = require('fs'); const path = require('path'); let resolvedPath = this.resolveModulePath(modulePath); if (this.moduleCache.has(resolvedPath)) { return this.moduleCache.get(resolvedPath); } try { const source = fs.readFileSync(resolvedPath, 'utf8'); const moduleEnvironment = new Environment(this.globals); const previousEnv = this.environment; this.environment = moduleEnvironment; const result = this.run(source); this.environment = previousEnv; this.moduleCache.set(resolvedPath, moduleEnvironment); return moduleEnvironment; } catch (error) { throw new Error(`Failed to import module '${modulePath}': ${error.message}`); } } requireModule(modulePath) { try { return require(modulePath); } catch (error) { return this.importModule(modulePath); } } exportValue(value) { if (!this.environment.exports) { this.environment.exports = {}; } Object.assign(this.environment.exports, value); return value; } resolveModulePath(modulePath) { const fs = require('fs'); const path = require('path'); if (modulePath.startsWith('./') || modulePath.startsWith('../')) { const currentDir = process.cwd(); let fullPath = path.resolve(currentDir, modulePath); if (!fullPath.endsWith('.pcs')) { fullPath += '.pcs'; } if (fs.existsSync(fullPath)) { return fullPath; } } if (path.isAbsolute(modulePath)) { let fullPath = modulePath; if (!fullPath.endsWith('.pcs')) { fullPath += '.pcs'; } if (fs.existsSync(fullPath)) { return fullPath; } } const coreModules = { 'core': path.join(__dirname, '../stdlib/core.pcs'), 'http': path.join(__dirname, '../stdlib/http.pcs'), 'database': path.join(__dirname, '../stdlib/database.pcs'), 'testing': path.join(__dirname, '../stdlib/testing.pcs'), 'fs': path.join(__dirname, '../stdlib/fs.pcs'), 'cli': path.join(__dirname, '../stdlib/cli.pcs') }; if (coreModules[modulePath]) { return coreModules[modulePath]; } const nodeModulesPath = path.join(process.cwd(), 'node_modules', modulePath); if (fs.existsSync(nodeModulesPath)) { return nodeModulesPath; } const pcsModulesPath = path.join(process.cwd(), 'pcs_modules', modulePath); if (fs.existsSync(pcsModulesPath)) { return pcsModulesPath; } throw new Error(`Module not found: ${modulePath}`); } defineNatives() { // Core time functions this.globals.define('currentTime', { arity: () => 0, call: () => Date.now() / 1000.0 }); this.globals.define('now', { arity: () => 0, call: () => new Date() }); this.globals.define('timestamp', { arity: () => 0, call: () => Date.now() }); // Enhanced String/Array functions this.globals.define('contains', { arity: () => 2, call: (interpreter, args) => { const [haystack, needle] = args; if (typeof haystack === 'string') { return haystack.includes(needle); } if (Array.isArray(haystack)) { return haystack.includes(needle); } if (typeof haystack === 'object' && haystack !== null) { return haystack.hasOwnProperty(needle); } return false; } }); // Enhanced type checking functions this.globals.define('typeOf', { arity: () => 1, call: (interpreter, args) => { const value = args[0]; if (value === null || value === undefined) return 'empty'; if (Array.isArray(value)) return 'array'; if (value instanceof Date) return 'date'; if (value instanceof RegExp) return 'regex'; return typeof value; } }); // Enhanced type conversion functions this.globals.define('toNumber', { arity: () => 1, call: (interpreter, args) => { const value = args[0]; if (typeof value === 'number') return value; if (typeof value === 'string') { const num = parseFloat(value); if (isNaN(num)) throw new Error('Cannot convert to number'); return num; } if (typeof value === 'boolean') return value ? 1 : 0; if (value instanceof Date) return value.getTime(); throw new Error('Cannot convert to number'); } }); this.globals.define('toString', { arity: () => 1, call: (interpreter, args) => { const value = args[0]; return this.stringify(value); } }); this.globals.define('toBoolean', { arity: () => 1, call: (interpreter, args) => { const value = args[0]; if (typeof value === 'boolean') return value; if (value === null || value === undefined) return false; if (typeof value === 'number') return value !== 0; if (typeof value === 'string') return value.length > 0; if (Array.isArray(value)) return value.length > 0; if (typeof value === 'object') return Object.keys(value).length > 0; return true; } }); this.globals.define('toArray', { arity: () => 1, call: (interpreter, args) => { const value = args[0]; if (Array.isArray(value)) return value; if (typeof value === 'string') return value.split(''); if (typeof value === 'object' && value !== null) return Object.values(value); return [value]; } }); // Enhanced type checking predicates this.globals.define('isNumber', { arity: () => 1, call: (interpreter, args) => typeof args[0] === 'number' && !isNaN(args[0]) }); this.globals.define('isString', { arity: () => 1, call: (interpreter, args) => typeof args[0] === 'string' }); this.globals.define('isBoolean', { arity: () => 1, call: (interpreter, args) => typeof args[0] === 'boolean' }); this.globals.define('isArray', { arity: () => 1, call: (interpreter, args) => Array.isArray(args[0]) }); this.globals.define('isObject', { arity: () => 1, call: (interpreter, args) => { const value = args[0]; return typeof value === 'object' && value !== null && !Array.isArray(value) && !(value instanceof Date); } }); this.globals.define('isFunction', { arity: () => 1, call: (interpreter, args) => { const value = args[0]; return typeof value === 'function' || (value && typeof value.call === 'function'); } }); this.globals.define('isDate', { arity: () => 1, call: (interpreter, args) => args[0] instanceof Date }); this.globals.define('isNull', { arity: () => 1, call: (interpreter, args) => args[0] === null }); this.globals.define('isUndefined', { arity: () => 1, call: (interpreter, args) => args[0] === undefined }); this.globals.define('isEmpty', { arity: () => 1, call: (interpreter, args) => { const value = args[0]; if (value === null || value === undefined) return true; if (typeof value === 'string') return value.length === 0; if (Array.isArray(value)) return value.length === 0; if (typeof value === 'object' && value !== null) return Object.keys(value).length === 0; if (typeof value === 'number') return value === 0; if (typeof value === 'boolean') return !value; return false; } }); this.globals.define('isNaN', { arity: () => 1, call: (interpreter, args) => isNaN(args[0]) }); this.globals.define('isFinite', { arity: () => 1, call: (interpreter, args) => isFinite(args[0]) }); // Size/length functions this.globals.define('length', { arity: () => 1, call: (interpreter, args) => { const value = args[0]; if (typeof value === 'string' || Array.isArray(value)) { return value.length; } if (typeof value === 'object' && value !== null) { return Object.keys(value).length; } throw new Error('Value does not support length operation'); } }); this.globals.define('size', { arity: () => 1, call: (interpreter, args) => { return this.globals.get('length').call(interpreter, args); } }); // Enhanced Array functions this.globals.define('push', { arity: () => 2, call: (interpreter, args) => { const [array, element] = args; if (!Array.isArray(array)) throw new Error('First argument must be an array'); array.push(element); return array; } }); this.globals.define('pop', { arity: () => 1, call: (interpreter, args) => { const [array] = args; if (!Array.isArray(array)) throw new Error('Argument must be an array'); return array.pop(); } }); this.globals.define('shift', { arity: () => 1, call: (interpreter, args) => { const [array] = args; if (!Array.isArray(array)) throw new Error('Argument must be an array'); return array.shift(); } }); this.globals.define('unshift', { arity: () => 2, call: (interpreter, args) => { const [array, element] = args; if (!Array.isArray(array)) throw new Error('First argument must be an array'); array.unshift(element); return array; } }); this.globals.define('slice', { arity: () => -1, call: (interpreter, args) => { const [array, start = 0, end] = args; if (!Array.isArray(array) && typeof array !== 'string') { throw new Error('First argument must be an array or string'); } return array.slice(start, end); } }); this.globals.define('splice', { arity: () => -1, call: (interpreter, args) => { const [array, start, deleteCount, ...items] = args; if (!Array.isArray(array)) throw new Error('First argument must be an array'); return array.splice(start, deleteCount, ...items); } }); this.globals.define('indexOf', { arity: () => 2, call: (interpreter, args) => { const [array, element] = args; if (!Array.isArray(array) && typeof array !== 'string') { throw new Error('First argument must be an array or string'); } return array.indexOf(element); } }); this.globals.define('lastIndexOf', { arity: () => 2, call: (interpreter, args) => { const [array, element] = args; if (!Array.isArray(array) && typeof array !== 'string') { throw new Error('First argument must be an array or string'); } return array.lastIndexOf(element); } }); this.globals.define('includes', { arity: () => 2, call: (interpreter, args) => { const [array, element] = args; if (!Array.isArray(array) && typeof array !== 'string') { throw new Error('First argument must be an array or string'); } return array.includes(element); } }); this.globals.define('reverse', { arity: () => 1, call: (interpreter, args) => { const [array] = args; if (!Array.isArray(array)) throw new Error('Argument must be an array'); return array.reverse(); } }); this.globals.define('sort', { arity: () => -1, call: (interpreter, args) => { const [array, compareFn] = args; if (!Array.isArray(array)) throw new Error('First argument must be an array'); if (compareFn) { return array.sort((a, b) => { if (compareFn && typeof compareFn.call === 'function') { return compareFn.call(interpreter, [a, b]); } return 0; }); } return array.sort(); } }); // NEW: sortBy function this.globals.define('sortBy', { arity: () => 2, call: (interpreter, args) => { const [array, keyFn] = args; if (!Array.isArray(array)) throw new Error('First argument must be an array'); return array.sort((a, b) => { let keyA, keyB; if (typeof keyFn === 'string') { keyA = a[keyFn]; keyB = b[keyFn]; } else if (keyFn && typeof keyFn.call === 'function') { keyA = keyFn.call(interpreter, [a]); keyB = keyFn.call(interpreter, [b]); } else { keyA = a; keyB = b; } if (keyA < keyB) return -1; if (keyA > keyB) return 1; return 0; }); } }); this.globals.define('find', { arity: () => 2, call: (interpreter, args) => { const [array, predicate] = args; if (!Array.isArray(array)) throw new Error('First argument must be an array'); return array.find(item => { if (predicate && typeof predicate.call === 'function') { return predicate.call(interpreter, [item]); } return false; }); } }); this.globals.define('findIndex', { arity: () => 2, call: (interpreter, args) => { const [array, predicate] = args; if (!Array.isArray(array)) throw new Error('First argument must be an array'); return array.findIndex(item => { if (predicate && typeof predicate.call === 'function') { return predicate.call(interpreter, [item]); } return false; }); } }); this.globals.define('filter', { arity: () => 2, call: (interpreter, args) => { const [array, predicate] = args; if (!Array.isArray(array)) throw new Error('First argument must be an array'); return array.filter(item => { if (predicate && typeof predicate.call === 'function') { return predicate.call(interpreter, [item]); } return false; }); } }); this.globals.define('map', { arity: () => 2, call: (interpreter, args) => { const [array, mapFn] = args; if (!Array.isArray(array)) throw new Error('First argument must be an array'); return array.map(item => { if (mapFn && typeof mapFn.call === 'function') { return mapFn.call(interpreter, [item]); } return item; }); } }); this.globals.define('forEach', { arity: () => 2, call: (interpreter, args) => { const [array, fn] = args; if (!Array.isArray(array)) throw new Error('First argument must be an array'); array.forEach(item => { if (fn && typeof fn.call === 'function') { fn.call(interpreter, [item]); } }); return null; } }); // NEW: every function this.globals.define('every', { arity: () => 2, call: (interpreter, args) => { const [array, predicate] = args; if (!Array.isArray(array)) throw new Error('First argument must be an array'); return array.every(item => { if (predicate && typeof predicate.call === 'function') { return predicate.call(interpreter, [item]); } return false; }); } }); // NEW: some function this.globals.define('some', { arity: () => 2, call: (interpreter, args) => { const [array, predicate] = args; if (!Array.isArray(array)) throw new Error('First argument must be an array'); return array.some(item => { if (predicate && typeof predicate.call === 'function') { return predicate.call(interpreter, [item]); } return false; }); } }); this.globals.define('reduce', { arity: () => -1, call: (interpreter, args) => { const [array, reduceFn, initialValue] = args; if (!Array.isArray(array)) throw new Error('First argument must be an array'); if (args.length > 2) { return array.reduce((acc, current) => { if (reduceFn && typeof reduceFn.call === 'function') { return reduceFn.call(interpreter, [acc, current]); } return acc; }, initialValue); } else { return array.reduce((acc, current) => { if (reduceFn && typeof reduceFn.call === 'function') { return reduceFn.call(interpreter, [acc, current]); } return acc; }); } } }); this.globals.define('join', { arity: () => 2, call: (interpreter, args) => { const [array, separator] = args; if (!Array.isArray(array)) throw new Error('First argument must be an array'); return array.join(separator || ','); } }); this.globals.define('concat', { arity: () => -1, call: (interpreter, args) => { const [array, ...others] = args; if (!Array.isArray(array)) throw new Error('First argument must be an array'); return array.concat(...others); } }); // Enhanced String functions this.globals.define('upper', { arity: () => 1, call: (interpreter, args) => { const [str] = args; if (typeof str !== 'string') throw new Error('Argument must be a string'); return str.toUpperCase(); } }); this.globals.define('lower', { arity: () => 1, call: (interpreter, args) => { const [str] = args; if (typeof str !== 'string') throw new Error('Argument must be a string'); return str.toLowerCase(); } }); this.globals.define('trim', { arity: () => 1, call: (interpreter, args) => { const [str] = args; if (typeof str !== 'string') throw new Error('Argument must be a string'); return str.trim(); } }); this.globals.define('split', { arity: () => 2, call: (interpreter, args) => { const [str, separator] = args; if (typeof str !== 'string') throw new Error('First argument must be a string'); return str.split(separator); } }); this.globals.define('replace', { arity: () => 3, call: (interpreter, args) => { const [str, search, replacement] = args; if (typeof str !== 'string') throw new Error('First argument must be a string'); return str.replace(search, replacement); } }); this.globals.define('charAt', { arity: () => 2, call: (interpreter, args) => { const [str, index] = args; if (typeof str !== 'string') throw new Error('First argument must be a string'); return str.charAt(index); } }); this.globals.define('substring', { arity: () => -1, call: (interpreter, args) => { const [str, start, end] = args; if (typeof str !== 'string') throw new Error('First argument must be a string'); return str.substring(start, end); } }); this.globals.define('startsWith', { arity: () => 2, call: (interpreter, args) => { const [str, prefix] = args; if (typeof str !== 'string') throw new Error('First argument must be a string'); return str.startsWith(prefix); } }); this.globals.define('endsWith', { arity: () => 2, call: (interpreter, args) => { const [str, suffix] = args; if (typeof str !== 'string') throw new Error('First argument must be a string'); return str.endsWith(suffix); } }); // ENHANCED OBJECT GLOBAL - VERSÃO COMPLETA E CORRIGIDA this.globals.define('Object', { keys: { arity: () => 1, call: (interpreter, args) => { const [obj] = args; if (typeof obj !== 'object' || obj === null) { throw new Error('Argument must be an object'); } return Object.keys(obj); } }, values: { arity: () => 1, call: (interpreter, args) => { const [obj] = args; if (typeof obj !== 'object' || obj === null) { throw new Error('Argument must be an object'); } return Object.values(obj); } }, entries: { arity: () => 1, call: (interpreter, args) => { const [obj] = args; if (typeof obj !== 'object' || obj === null) { throw new Error('Argument must be an object'); } return Object.entries(obj); } }, assign: { arity: () => -1, call: (interpreter, args) => { if (args.length < 1) { throw new Error('Object.assign requires at least 1 argument'); } const target = args[0]; const sources = args.slice(1); if (typeof target !== 'object' || target === null) { if (sources.length > 0 && typeof sources[0] === 'object' && sources[0] !== null) { return Object.assign({}, ...sources); } return {}; } for (const source of sources) { if (source !== null && source !== undefined) { Object.assign(target, source); } } return target; } }, hasOwnProperty: { arity: () => 2, call: (interpreter, args) => { const [obj, prop] = args; if (typeof obj !== 'object' || obj === null) { return false; } return Object.prototype.hasOwnProperty.call(obj, prop); } }, create: { arity: () => -1, call: (interpreter, args) => { const [proto, properties] = args; const obj = Object.create(proto); if (properties && typeof properties === 'object') { Object.assign(obj, properties); } return obj; } }, freeze: { arity: () => 1, call: (interpreter, args) => { const [obj] = args; if (typeof obj !== 'object' || obj === null) { throw new Error('Argument must be an object'); } return Object.freeze(obj); } }, seal: { arity: () => 1, call: (interpreter, args) => { const [obj] = args; if (typeof obj !== 'object' || obj === null) { throw new Error('Argument must be an object'); } return Object.seal(obj); } }, preventExtensions: { arity: () => 1, call: (interpreter, args) => { const [obj] = args; if (typeof obj !== 'object' || obj === null) { throw new Error('Argument must be an object'); } return Object.preventExtensions(obj); } }, isFrozen: { arity: () => 1, call: (interpreter, args) => { const [obj] = args; if (typeof obj !== 'object' || obj === null) { return true; } return Object.isFrozen(obj); } }, isSealed: { arity: () => 1, call: (interpreter, args) => { const [obj] = args; if (typeof obj !== 'object' || obj === null) { return true; } return Object.isSealed(obj); } }, isExtensible: { arity: () => 1, call: (interpreter, args) => { const [obj] = args; if (typeof obj !== 'object' || obj === null) { return false; } return Object.isExtensible(obj); } }, getOwnPropertyNames: { arity: () => 1, call: (interpreter, args) => { const [obj] = args; if (typeof obj !== 'object' || obj === null) { throw new Error('Argument must be an object'); } return Object.getOwnPropertyNames(obj); } }, getOwnPropertyDescriptor: { arity: () => 2, call: (interpreter, args) => { const [obj, prop] = args; if (typeof obj !== 'object' || obj === null) { return undefined; } return Object.getOwnPropertyDescriptor(obj, prop); } }, defineProperty: { arity: () => 3, call: (interpreter, args) => { const [obj, prop, descriptor] = args; if (typeof obj !== 'object' || obj === null) { throw new Error('First argument must be an object'); } return Object.defineProperty(obj, prop, descriptor); } } }); // ENHANCED GLOBAL FUNCTIONS FOR OBJECT COMPATIBILITY this.globals.define('keys', { arity: () => 1, call: (interpreter, args) => { const [obj] = args; if (typeof obj !== 'object' || obj === null) { throw new Error('Argument must be an object'); } return Object.keys(obj); } }); this.globals.define('values', { arity: () => 1, call: (interpreter, args) => { const [obj] = args; if (typeof obj !== 'object' || obj === null) { throw new Error('Argument must be an object'); } return Object.values(obj); } }); this.globals.define('entries', { arity: () => 1, call: (interpreter, args) => { const [obj] = args; if (typeof obj !== 'object' || obj === null) { throw new Error('Argument must be an object'); } return Object.entries(obj); } }); // NEW: hasProperty function - CORRIGIDO this.globals.define('hasProperty', { arity: () => 2, call: (interpreter, args) => { const [obj, prop] = args; if (typeof obj !== 'object' || obj === null) { return false; } return Object.prototype.hasOwnProperty.call(obj, prop); } }); this.globals.define('hasOwnProperty', { arity: () => 2, call: (interpreter, args) => { const [obj, prop] = args; if (typeof obj !== 'object' || obj === null) { return false; } return Object.prototype.hasOwnProperty.call(obj, prop); } }); // ENHANCED JSON functions this.globals.define('parseJSON', { arity: () => 1, call: (interpreter, args) => { const [str] = args; try { return JSON.parse(str); } catch (error) { throw new Error('Invalid JSON: ' + error.message); } } }); this.globals.define('stringifyJSON', { arity: () => -1, call: (interpreter, args) => { const [obj, replacer, space] = args; try { return JSON.stringify(obj, replacer, space); } catch (error) { throw new Error('Cannot stringify to JSON: ' + error.message); } } }); // ENHANCED JSON global object this.globals.define('JSON', { parse: { arity: () => 1, call: (interpreter, args) => { const [str] = args; try { return JSON.parse(str); } catch (error) { throw new Error('Invalid JSON: ' + error.message); } } }, stringify: { arity: () => -1, call: (interpreter, args) => { const [obj, replacer, space] = args; try { return JSON.stringify(obj, replacer, space); } catch (error) { throw new Error('Cannot stringify to JSON: ' + error.message); } } } }); // Enhanced Math functions this.globals.define('abs', { arity: () => 1, call: (interpreter, args) => Math.abs(args[0]) }); this.globals.define('max', { arity: () => -1, call: (interpreter, args) => Math.max(...args) }); this.globals.define('min', { arity: () => -1, call: (interpreter, args) => Math.min(...args) }); this.globals.define('sqrt', { arity: () => 1, call: (interpreter, args) => Math.sqrt(args[0]) }); this.globals.define('pow', { arity: () => 2, call: (interpreter, args) => Math.pow(args[0], args[1]) }); this.globals.define('floor', { arity: () => 1, call: (interpreter, args) => Math.floor(args[0]) }); this.globals.define('ceil', { arity: () => 1, call: (interpreter, args) => Math.ceil(args[0]) }); this.globals.define('round', { arity: () => 1, call: (interpreter, args) => Math.round(args[0]) }); this.globals.define('random', { arity: () => 0, call: (interpreter, args) => Math.random() }); this.globals.define('randomInt', { arity: () => 2, call: (interpreter, args) => { const [min, max] = args; return Math.floor(Math.random() * (max - min + 1)) + min; } }); // Enhanced Module system this.globals.define('import', { arity: () => 1, call: (interpreter, args) => { const modulePath = args[0]; return interpreter.importModule(modulePath); } }); this.globals.define('export', { arity: () => 1, call: (interpreter, args) => { const exportValue = args[0]; return interpreter.exportValue(exportValue); } }); this.globals.define('require', { arity: () => 1, call: (interpreter, args) => { const modulePath = args[0]; return interpreter.requireModule(modulePath); } }); // Database functions this.globals.define('connect', { arity: () => 1, call: (interpreter, args) => { const filename = args[0]; return this.createMockDatabase(filename); } }); this.globals.define('types', { arity: () => 0, call: (interpreter, args) => { return { INTEGER: 'INTEGER', TEXT: 'TEXT', REAL: 'REAL', BLOB: 'BLOB', PRIMARY_KEY: 'INTEGER PRIMARY KEY AUTOINCREMENT', TIMESTAMP: 'DATETIME DEFAULT CURRENT_TIMESTAMP', BOOLEAN: 'INTEGER', JSON: 'TEXT' }; } }); // HTTP/Server related functions this.globals.define('createServer', { arity: () => 1, call: (interpreter, args) => { const port = args[0] || 3000; return this.createMockServer(port, interpreter); } }); this.globals.define('get', { arity: () => -1, call: (interpreter, args) => { const url = args[0]; return Promise.resolve({ data: `Mock response from ${url}`, status: 200, headers: {} }); } }); // Enhanced middleware functions this.globals.define('cors', { arity: () => -1, call: (interpreter, args) => { const options = args[0] || {}; const origin = options.origin || '*'; const methods = options.methods || 'GET,HEAD,PUT,PATCH,POST,DELETE'; const allowedHeaders = options.allowedHeaders || 'Content-Type,Authorization'; return { name: 'CORS', type: 'middleware', arity: () => 3, call: (interpreterInstance, middlewareArgs) => { const [req, res, next] = middlewareArgs; console.log('🔧 CORS middleware applied'); res.headers = res.headers || {}; res.headers['Access-Control-Allow-Origin'] = origin; res.headers['Access-Control-Allow-Methods'] = methods; res.headers['Access-Control-Allow-Headers'] = allowedHeaders; if (req.method === 'OPTIONS') { res.statusCode = 200; console.log('🔧 CORS preflight response sent'); } if (next && typeof next.call === 'function') { next.call(interpreterInstance, []); } return null; }, toString: () => '[Middleware: CORS]' }; } }); this.globals.define('json', { arity: () => -1, call: (interpreter, args) => { const options = args[0] || {}; const limit = options.limit || '100kb'; return { name: 'JSON', type: 'middleware', arity: () => 3, call: (interpreterInstance, middlewareArgs) => { const [req, res, next] = middlewareArgs; console.log('🔧 JSON middleware applied'); if (req.body && typeof req.body === 'string') { try { req.body = JSON.parse(req.body); console.log('🔧 JSON body parsed'); } catch (error) { console.error('🔧 JSON parse error:', error.message); } } res.headers = res.headers || {}; res.headers['Content-Type'] = 'application/json'; if (next && typeof next.call === 'function') { next.call(interpreterInstance, []); } return null; }, toString: () => '[Middleware: JSON]' }; } }); this.globals.define('logger', { arity: () => -1, call: (interpreter, args) => { const options = args[0] || {}; const format = options.format || 'combined'; return { name: 'Logger', type: 'middleware', arity: () => 3, call: (interpreterInstance, middlewareArgs) => { const [req, res, next] = middlewareArgs; const timestamp = new Date().toISOString(); const userAgent = req.headers['user-agent'] || '-'; const contentLength = req.headers['content-length'] || '-'; if (format === 'combined') { console.log(`🔧 [${timestamp}] ${req.method} ${req.path} - ${req.headers['x-forwarded-for'] || '127.0.0.1'} "${userAgent}" ${contentLength}`); } else { console.log(`🔧 [${timestamp}] ${req.method} ${req.path}`); } if (next && typeof next.call === 'function') { next.call(interpreterInstance, []); } return null; }, toString: () => '[Middleware: Logger]' }; } }); // Enhanced Promise functions this.globals.define('Promise', { arity: () => 1, call: (interpreter, args) => { const executor = args[0]; return new Promise((resolve, reject) => { try { if (executor && typeof executor.call === 'function') { executor.call(interpreter, [resolve, reject]); } else if (typeof executor === 'function') { executor(resolve, reject); } else { reject(new Error('Promise executor must be a function')); } } catch (error) { reject(error); } }); } }); // NEW: Enhanced Async functions - timeout, retry, parallel this.globals.define('timeout', { arity: () => 2, call: (interpreter, args) => { const [fn, delay] = args; return setTimeout(() => { if (fn && typeof fn.call === 'function') { fn.call(interpreter, []); } else if (typeof fn === 'function') { fn(); } }, delay); } }); // NEW: retry function this.globals.define('retry', { arity: () => -1, call: async (interpreter, args) => { const [fn, maxRetries = 3, delayMs = 1000] = args; for (let attempt = 1; attempt <= maxRetries; attempt++) { try { if (fn && typeof fn.call === 'function') { return await fn.call(interpreter, []); } else if (typeof fn === 'function') { return await fn(); } } catch (error) { if (attempt === maxRetries) { throw new Error(`Failed after ${maxRetries} attempts: ${error.message}`); } // Wait before retry await new Promise(resolve => setTimeout(resolve, delayMs)); } } } }); // NEW: Enhanced parallel function this.globals.define('parallel', { arity: () => 1, call: (interpreter, args) => { const tasks = args[0]; if (!Array.isArray(tasks)) { throw new Error('Argument must be an array of tasks'); } return Promise.all(tasks.map(task => { if (task && typeof task.call === 'function') { return task.call(interpreter, []); } else if (typeof task === 'function') { return task(); } return task; })); } }); // Promise helpers this.globals.define('all', { arity: () => 1, call: (interpreter, args) => { const promises = args[0]; return Promise.all(promises); } }); // Enhanced Console functions this.globals.define('log', { arity: () => -1, call: (interpreter, args) => { console.log(...args.map(arg => this.stringify(arg))); return null; } }); this.globals.define('error', { arity: () => -1, call: (interpreter, args) => { console.error(...args.map(arg => this.stringify(arg))); return null; } }); this.globals.define('warn', { arity: () => -1, call: (interpreter, args) => { console.warn(...args.map(arg => this.stringify(arg))); return null; } }); this.globals.define('info', { arity: () => -1, call: (interpreter, args) => { console.info(...args.map(arg => this.stringify(arg))); return null; } }); // Date functions this.globals.define('createDate', { arity: () => -1, call: (interpreter, args) => { if (args.length === 0) { return new Date(); } return new Date(...args); } }); this.globals.define('formatDate', { arity: () => -1, call: (interpreter, args) => { const [date, format] = args; if (!(date instanceof Date)) { throw new Error('First argument must be a date'); } if (format) { return date.toLocaleDateString(undefined, format); } return date.toISOString(); } }); // Utility functions this.globals.define('range', { arity: () => -1, call: (interpreter, args) => { const [start, end, step = 1] = args; const result = []; for (let i = start; i < end; i += step) { result.push(i); } return result; } }); this.globals.define('repeat', { arity: () => 2, call: (interpreter, args) => { const [fn, times] = args; const results = []; for (let i = 0; i < times; i++) { if (fn && typeof fn.call === 'function') { results.push(fn.call(interpreter, [i])); } } return results; } }); this.globals.define('sleep', { arity: () => 1, call: (interpreter, args) => { const [ms] = args; return new Promise(resolve => setTimeout(resolve, ms)); } }); } // ENHANCED native method detection for arrays, strings, and objects getNativeMethod(object, methodName) { if (Array.isArray(object)) { switch (methodName) { case 'push': return { arity: () => 1, call: (interpreter, args) => { const element = args[0]; object.push(element); return object; } }; case 'pop': return { arity: () => 0, call: (interpreter, args) => object.pop() }; case 'shift': return { arity: () => 0, call: (interpreter, args) => object.shift() }; case 'unshift': return {