about summary refs log tree commit diff stats
path: root/js/baba-yaga/src/legacy/engine.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/baba-yaga/src/legacy/engine.js')
-rw-r--r--js/baba-yaga/src/legacy/engine.js289
1 files changed, 289 insertions, 0 deletions
diff --git a/js/baba-yaga/src/legacy/engine.js b/js/baba-yaga/src/legacy/engine.js
new file mode 100644
index 0000000..6afece3
--- /dev/null
+++ b/js/baba-yaga/src/legacy/engine.js
@@ -0,0 +1,289 @@
+// engine.js - Main Baba Yaga engine with improved error handling and configuration
+
+import { createLexer } from './lexer.js';
+import { createParser } from './parser.js';
+import { createInterpreter } from './interpreter.js';
+import { BabaYagaConfig } from '../core/config.js';
+import { InputValidator, SecurityValidator } from '../core/validation.js';
+import { BabaError } from '../core/error.js';
+
+/**
+ * Main Baba Yaga engine class
+ */
+export class BabaYagaEngine {
+  constructor(config = new BabaYagaConfig()) {
+    this.config = config;
+    this.validator = config.sandboxMode 
+      ? new SecurityValidator(config) 
+      : new InputValidator(config);
+    
+    // Performance tracking
+    this.stats = {
+      totalExecutions: 0,
+      totalTime: 0,
+      averageTime: 0,
+      errors: 0
+    };
+  }
+
+  /**
+   * Execute Baba Yaga source code
+   */
+  async execute(source, options = {}) {
+    const startTime = performance.now();
+    
+    try {
+      // Validate input
+      this.validator.validateSourceCode(source, options.filename || '<input>');
+      
+      // Lexical analysis
+      const lexer = createLexer(source);
+      const tokens = lexer.allTokens();
+      
+      if (this.config.enableDebugMode) {
+        console.log('[DEBUG] Tokens:', tokens.length);
+      }
+      
+      // Parsing
+      const parser = createParser(tokens, this.config.enableDebugMode, source);
+      const ast = parser.parse();
+      
+      // Validate AST
+      this.validator.validateAST(ast, source);
+      
+      if (this.config.enableDebugMode) {
+        console.log('[DEBUG] AST depth:', this.getASTDepth(ast));
+      }
+      
+      // Interpretation
+      const host = this.createHostInterface(source, options);
+      const interpreter = createInterpreter(ast, host);
+      
+      // Set up execution timeout
+      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,
+            source,
+            ['Reduce recursion depth', 'Optimize algorithm complexity', 'Increase maxExecutionTime']
+          ));
+        }, this.config.maxExecutionTime);
+      });
+      
+      const result = await Promise.race([executionPromise, timeoutPromise]);
+      clearTimeout(timeoutId);
+      
+      // Update statistics
+      const executionTime = performance.now() - startTime;
+      this.updateStats(executionTime, false);
+      
+      if (this.config.showTimings) {
+        console.log(`[TIMING] Execution completed in ${executionTime.toFixed(2)}ms`);
+      }
+      
+      return {
+        result,
+        executionTime,
+        success: true
+      };
+      
+    } 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
+        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']
+        };
+      }
+    }
+  }
+
+  /**
+   * Create host interface for interpreter
+   */
+  createHostInterface(source, options) {
+    return {
+      source,
+      scope: options.scope || new Map(),
+      io: {
+        out: (...args) => {
+          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
+      }
+    };
+  }
+
+  /**
+   * Get AST depth for validation
+   */
+  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
+   */
+  updateStats(executionTime, isError) {
+    this.stats.totalExecutions++;
+    this.stats.totalTime += executionTime;
+    this.stats.averageTime = this.stats.totalTime / this.stats.totalExecutions;
+    
+    if (isError) {
+      this.stats.errors++;
+    }
+  }
+
+  /**
+   * Get engine statistics
+   */
+  getStats() {
+    return {
+      ...this.stats,
+      errorRate: this.stats.totalExecutions > 0 ? this.stats.errors / this.stats.totalExecutions : 0
+    };
+  }
+
+  /**
+   * Reset statistics
+   */
+  resetStats() {
+    this.stats = {
+      totalExecutions: 0,
+      totalTime: 0,
+      averageTime: 0,
+      errors: 0
+    };
+  }
+
+  /**
+   * Validate configuration
+   */
+  validateConfig() {
+    return this.config.validate();
+  }
+
+  /**
+   * Update configuration
+   */
+  updateConfig(newConfig) {
+    if (newConfig instanceof BabaYagaConfig) {
+      this.config = newConfig;
+    } else {
+      this.config = this.config.merge(newConfig);
+    }
+    
+    // Update validator if security mode changed
+    this.validator = this.config.sandboxMode 
+      ? new SecurityValidator(this.config) 
+      : new InputValidator(this.config);
+  }
+}
+
+/**
+ * Convenience function for quick execution
+ */
+export async function execute(source, config = new BabaYagaConfig()) {
+  const engine = new BabaYagaEngine(config);
+  return engine.execute(source);
+}
+
+/**
+ * Create engine with preset configurations
+ */
+export function createEngine(preset = 'default') {
+  let config;
+  
+  switch (preset) {
+    case 'development':
+      config = BabaYagaConfig.development();
+      break;
+    case 'production':
+      config = BabaYagaConfig.production();
+      break;
+    case 'testing':
+      config = BabaYagaConfig.testing();
+      break;
+    case 'sandbox':
+      config = BabaYagaConfig.sandbox();
+      break;
+    default:
+      config = new BabaYagaConfig();
+  }
+  
+  return new BabaYagaEngine(config);
+}