// engine-optimized.js - High-performance Baba Yaga engine with all optimizations import { createOptimizedLexer, createLexerWithFallback } from './lexer-optimized.js'; import { createParser } from './parser.js'; import { createInterpreter } from './interpreter.js'; import { BabaYagaConfig } from './config.js'; import { InputValidator, SecurityValidator } from './validation.js'; import { BabaError } from './error.js'; import { ScopeStack, CompatibleScopeStack } from './scope-stack.js'; import { OptimizedBuiltins } from './builtins-optimized.js'; import { globalASTPool } from './ast-pool.js'; /** * High-performance Baba Yaga engine with all optimizations enabled */ export class OptimizedBabaYagaEngine { constructor(config = new BabaYagaConfig()) { this.config = config; this.validator = config.sandboxMode ? new SecurityValidator(config) : new InputValidator(config); // Initialize optimization components this.optimizedBuiltins = new OptimizedBuiltins(); this.astPool = globalASTPool; // Performance tracking with more detail this.stats = { totalExecutions: 0, totalTime: 0, averageTime: 0, errors: 0, lexingTime: 0, parsingTime: 0, interpretingTime: 0, optimizationStats: { lexerOptimizations: 0, scopeOptimizations: 0, builtinOptimizations: 0, astPoolHits: 0 } }; // Warm up optimization components if (config.enableOptimizations) { this.warmUp(); } } /** * Warm up optimization components for better initial performance */ warmUp() { // Warm up AST pools this.astPool.warmUp('BinaryExpression', 50); this.astPool.warmUp('FunctionCall', 30); this.astPool.warmUp('Identifier', 100); this.astPool.warmUp('NumberLiteral', 50); // Warm up with a simple program const warmupCode = 'x : 1 + 2; y : x * 3;'; try { this.executeSync(warmupCode, { silent: true }); } catch (error) { // Ignore warmup errors } } /** * Execute Baba Yaga source code with all optimizations */ async execute(source, options = {}) { const startTime = performance.now(); try { // Validate input this.validator.validateSourceCode(source, options.filename || ''); // Optimized lexical analysis const lexStart = performance.now(); const lexer = this.config.enableOptimizations ? createOptimizedLexer(source) : await createLexerWithFallback(source, false); const tokens = lexer.allTokens(); const lexTime = performance.now() - lexStart; if (this.config.enableDebugMode) { console.log(`[DEBUG] Lexing: ${lexTime.toFixed(2)}ms, Tokens: ${tokens.length}`); } // Parsing with AST pooling const parseStart = performance.now(); const parser = this.createOptimizedParser(tokens, source); const ast = parser.parse(); const parseTime = performance.now() - parseStart; // Validate AST this.validator.validateAST(ast, source); if (this.config.enableDebugMode) { console.log(`[DEBUG] Parsing: ${parseTime.toFixed(2)}ms, AST depth: ${this.getASTDepth(ast)}`); } // Optimized interpretation const interpretStart = performance.now(); const host = this.createOptimizedHostInterface(source, options); const interpreter = this.createOptimizedInterpreter(ast, host); // Set up execution timeout const result = await this.executeWithTimeout(interpreter, host); const interpretTime = performance.now() - interpretStart; // Update statistics const executionTime = performance.now() - startTime; this.updateStats(executionTime, false, lexTime, parseTime, interpretTime); if (this.config.showTimings) { console.log(`[TIMING] Total: ${executionTime.toFixed(2)}ms (Lex: ${lexTime.toFixed(2)}ms, Parse: ${parseTime.toFixed(2)}ms, Interpret: ${interpretTime.toFixed(2)}ms)`); } // Clean up AST if pooling is enabled if (this.config.enableOptimizations) { this.astPool.releaseTree(ast); } return { result, executionTime, success: true, breakdown: { lexingTime: lexTime, parsingTime: parseTime, interpretingTime: interpretTime } }; } catch (error) { const executionTime = performance.now() - startTime; this.updateStats(executionTime, true); // Format error for display if (error instanceof BabaError) { const formattedError = this.config.verboseErrors ? error.formatError() : error.message; return { error: formattedError, errorType: error.name, executionTime, success: false, suggestions: error.suggestions }; } else { // Unexpected error if (this.config.enableDebugMode) { console.error('[INTERNAL ERROR]', error); } return { error: 'Internal error occurred', errorType: 'InternalError', executionTime, success: false, suggestions: ['Report this as a bug', 'Check for malformed input'] }; } } } /** * Synchronous execution for simple cases */ executeSync(source, options = {}) { // Use Promise.resolve to handle async execute in sync context let result; let error; this.execute(source, options).then( res => { result = res; }, err => { error = err; } ); // Simple busy wait for sync execution (not recommended for production) const start = Date.now(); while (result === undefined && error === undefined && Date.now() - start < 1000) { // Wait } if (error) throw error; return result; } /** * Create optimized parser with AST pooling */ createOptimizedParser(tokens, source) { const parser = createParser(tokens, this.config.enableDebugMode, source); // If optimizations are enabled, wrap parser methods to use pooling if (this.config.enableOptimizations) { const originalParse = parser.parse.bind(parser); parser.parse = () => { const ast = originalParse(); this.stats.optimizationStats.astPoolHits += this.astPool.getStats().poolHits; return ast; }; } return parser; } /** * Create optimized interpreter with scope stack and built-in optimizations */ createOptimizedInterpreter(ast, host) { const interpreter = createInterpreter(ast, host); if (this.config.enableOptimizations) { // Replace scope with optimized scope stack const originalScope = interpreter.scope; const optimizedScope = new CompatibleScopeStack(); // Copy existing scope data for (const [key, value] of originalScope.entries()) { optimizedScope.set(key, value); } interpreter.scope = optimizedScope; // Inject optimized built-ins this.injectOptimizedBuiltins(interpreter); } return interpreter; } /** * Inject optimized built-in functions into interpreter */ injectOptimizedBuiltins(interpreter) { const originalVisitFunctionCall = interpreter.visitFunctionCall; interpreter.visitFunctionCall = (node) => { // Try optimized path first if (node.callee && node.callee.type === 'Identifier') { const functionName = node.callee.name; const args = node.arguments.map(arg => interpreter.visit(arg)); if (this.optimizedBuiltins.canOptimize(functionName, args)) { const result = this.optimizedBuiltins.execute(functionName, args, interpreter); if (result !== null) { this.stats.optimizationStats.builtinOptimizations++; return result; } } } // Fall back to standard implementation return originalVisitFunctionCall.call(interpreter, node); }; } /** * Create optimized host interface */ createOptimizedHostInterface(source, options) { const host = { source, scope: options.scope || new Map(), io: { out: (...args) => { if (options.silent) return; // Skip output in silent mode if (options.onOutput) { options.onOutput(...args); } else { console.log(...args); } }, in: () => { if (options.onInput) { return options.onInput(); } else { throw new BabaError('Input not available in this context'); } }, emit: (event) => { if (options.onEvent) { options.onEvent(event); } }, addListener: (topic, handler) => { if (options.onAddListener) { return options.onAddListener(topic, handler); } return () => {}; // No-op unsubscribe }, debug: this.config.enableDebugMode ? console.log : () => {}, ...this.config.ioHandlers } }; // Add optimization-specific extensions if (this.config.enableOptimizations) { host.optimizations = { builtins: this.optimizedBuiltins, astPool: this.astPool }; } return host; } /** * Execute interpreter with timeout protection */ async executeWithTimeout(interpreter, host) { let timeoutId; const executionPromise = new Promise((resolve, reject) => { try { const result = interpreter.interpret(); resolve(result); } catch (error) { reject(error); } }); const timeoutPromise = new Promise((_, reject) => { timeoutId = setTimeout(() => { reject(new BabaError( `Execution timeout after ${this.config.maxExecutionTime}ms`, null, host.source, ['Reduce recursion depth', 'Optimize algorithm complexity', 'Increase maxExecutionTime'] )); }, this.config.maxExecutionTime); }); try { const result = await Promise.race([executionPromise, timeoutPromise]); clearTimeout(timeoutId); return result; } catch (error) { clearTimeout(timeoutId); throw error; } } /** * Get AST depth for validation and debugging */ getASTDepth(node, depth = 0) { if (!node || typeof node !== 'object') { return depth; } let maxDepth = depth; // Check common AST node children const childFields = ['body', 'left', 'right', 'operand', 'callee', 'arguments', 'elements', 'discriminants', 'cases']; for (const field of childFields) { const child = node[field]; if (child) { if (Array.isArray(child)) { for (const item of child) { maxDepth = Math.max(maxDepth, this.getASTDepth(item, depth + 1)); } } else { maxDepth = Math.max(maxDepth, this.getASTDepth(child, depth + 1)); } } } return maxDepth; } /** * Update execution statistics with detailed breakdown */ updateStats(executionTime, isError, lexTime = 0, parseTime = 0, interpretTime = 0) { this.stats.totalExecutions++; this.stats.totalTime += executionTime; this.stats.averageTime = this.stats.totalTime / this.stats.totalExecutions; this.stats.lexingTime += lexTime; this.stats.parsingTime += parseTime; this.stats.interpretingTime += interpretTime; if (isError) { this.stats.errors++; } } /** * Get comprehensive engine statistics */ getStats() { const builtinStats = this.optimizedBuiltins.getStats(); const astPoolStats = this.astPool.getStats(); return { ...this.stats, errorRate: this.stats.totalExecutions > 0 ? this.stats.errors / this.stats.totalExecutions : 0, averageLexTime: this.stats.totalExecutions > 0 ? this.stats.lexingTime / this.stats.totalExecutions : 0, averageParseTime: this.stats.totalExecutions > 0 ? this.stats.parsingTime / this.stats.totalExecutions : 0, averageInterpretTime: this.stats.totalExecutions > 0 ? this.stats.interpretingTime / this.stats.totalExecutions : 0, optimizations: { builtinOptimizationRate: builtinStats.optimizationRate, astPoolHitRate: astPoolStats.hitRate, astPoolReuseRate: astPoolStats.reuseRate, totalOptimizations: this.stats.optimizationStats.builtinOptimizations + this.stats.optimizationStats.astPoolHits } }; } /** * Reset all statistics */ resetStats() { this.stats = { totalExecutions: 0, totalTime: 0, averageTime: 0, errors: 0, lexingTime: 0, parsingTime: 0, interpretingTime: 0, optimizationStats: { lexerOptimizations: 0, scopeOptimizations: 0, builtinOptimizations: 0, astPoolHits: 0 } }; this.optimizedBuiltins.resetStats(); this.astPool.resetStats(); } /** * Get optimization recommendations */ getOptimizationRecommendations() { const stats = this.getStats(); const recommendations = []; if (stats.optimizations.builtinOptimizationRate < 0.7) { recommendations.push('Consider using more built-in functions (map, filter, reduce) for better performance'); } if (stats.optimizations.astPoolHitRate < 0.5) { recommendations.push('Enable AST pooling for better memory efficiency'); } if (stats.averageLexTime > stats.averageParseTime) { recommendations.push('Lexing is taking longer than parsing - consider optimizing token patterns'); } if (stats.errorRate > 0.1) { recommendations.push('High error rate detected - consider input validation improvements'); } return recommendations; } /** * Create a performance profile for the current workload */ createPerformanceProfile() { const stats = this.getStats(); return { timestamp: new Date().toISOString(), config: this.config.summary(), performance: { totalExecutions: stats.totalExecutions, averageExecutionTime: stats.averageTime, breakdown: { lexing: stats.averageLexTime, parsing: stats.averageParseTime, interpreting: stats.averageInterpretTime }, optimizations: stats.optimizations }, recommendations: this.getOptimizationRecommendations() }; } } /** * Convenience function for optimized execution */ export async function executeOptimized(source, config = new BabaYagaConfig({ enableOptimizations: true })) { const engine = new OptimizedBabaYagaEngine(config); return engine.execute(source); } /** * Create optimized engine with preset configurations */ export function createOptimizedEngine(preset = 'performance') { let config; switch (preset) { case 'performance': config = new BabaYagaConfig({ enableOptimizations: true, enableDebugMode: false, strictMode: false, maxRecursionDepth: 2000, maxExecutionTime: 10000 }); break; case 'development': config = BabaYagaConfig.development(); config.enableOptimizations = true; break; case 'production': config = BabaYagaConfig.production(); config.enableOptimizations = true; break; default: config = new BabaYagaConfig({ enableOptimizations: true }); } return new OptimizedBabaYagaEngine(config); }