diff options
Diffstat (limited to 'js/baba-yaga/src/legacy/engine-optimized.js')
-rw-r--r-- | js/baba-yaga/src/legacy/engine-optimized.js | 526 |
1 files changed, 526 insertions, 0 deletions
diff --git a/js/baba-yaga/src/legacy/engine-optimized.js b/js/baba-yaga/src/legacy/engine-optimized.js new file mode 100644 index 0000000..5f78da7 --- /dev/null +++ b/js/baba-yaga/src/legacy/engine-optimized.js @@ -0,0 +1,526 @@ +// 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 || '<input>'); + + // 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); +} |