jetcrab\api/engine.rs
1//! # JavaScript Engine API
2//!
3//! Provides the main execution engine for JavaScript code, combining parsing,
4//! semantic analysis, bytecode generation, and VM execution.
5//!
6//! ## Overview
7//!
8//! The Engine is the primary entry point for JavaScript execution:
9//!
10//! - **Source Code Input**: Accepts JavaScript source as strings
11//! - **Complete Pipeline**: Parsing → Analysis → Compilation → Execution
12//! - **Result Output**: Returns computed values or error messages
13//! - **Context Management**: Maintains execution state and context
14//!
15//! ## Execution Flow
16//!
17//! ```text
18//! Source Code → Parser → AST → Semantic Analysis → Bytecode → VM → Result
19//! ```
20//!
21//! ## Usage
22//!
23//! ```rust
24//! use jetcrab::api::Engine;
25//!
26//! let mut engine = Engine::new();
27//! let result = engine.evaluate("2 + 2 * 3")?;
28//! println!("Result: {:?}", result);
29//! ```
30
31use crate::bytecode::BytecodeGenerator;
32use crate::parser::Parser;
33use crate::runtime::Context;
34use crate::semantic::SemanticAnalyzer;
35use crate::vm::executor::Executor;
36use crate::vm::{Bytecode, Value};
37
38/// Main JavaScript execution engine
39///
40/// Combines all components needed for JavaScript execution:
41/// parsing, semantic analysis, bytecode generation, and VM execution.
42pub struct Engine {
43 context: Context,
44 executor: Executor,
45 generator: BytecodeGenerator,
46 analyzer: SemanticAnalyzer,
47}
48
49impl Default for Engine {
50 fn default() -> Self {
51 Self::new()
52 }
53}
54
55impl Engine {
56 pub fn new() -> Self {
57 Self {
58 context: Context::new(),
59 executor: Executor::new(),
60 generator: BytecodeGenerator::new(),
61 analyzer: SemanticAnalyzer::new(),
62 }
63 }
64
65 pub fn evaluate(&mut self, source: &str) -> Result<Value, String> {
66 let mut parser = Parser::new(source);
67 let ast = parser.parse().map_err(|e| format!("Parser error: {e}"))?;
68
69 self.analyzer
70 .analyze(&ast)
71 .map_err(|e| format!("Semantic error: {e}"))?;
72
73 let instructions = self.generator.generate(&ast);
74 let constants = self.generator.get_constants().clone();
75
76 let values: Vec<Value> = constants
77 .iter()
78 .map(|s| {
79 // Check if it's a string that starts and ends with quotes (string literal)
80 if s.starts_with('"') && s.ends_with('"') {
81 // Remove quotes and treat as string literal
82 let content = &s[1..s.len() - 1];
83 Value::String(content.to_string())
84 } else if s.starts_with("'") && s.ends_with("'") {
85 // Remove quotes and treat as string literal
86 let content = &s[1..s.len() - 1];
87 Value::String(content.to_string())
88 } else if let Ok(num) = s.parse::<f64>() {
89 // Check if it's actually a number (not a string that happens to be numeric)
90 if s.contains('.') || s.parse::<i64>().is_ok() {
91 Value::Number(num)
92 } else {
93 // If it's a string that looks like a number, keep it as string
94 Value::String(s.clone())
95 }
96 } else if s == "true" {
97 Value::Boolean(true)
98 } else if s == "false" {
99 Value::Boolean(false)
100 } else if s == "null" {
101 Value::Null
102 } else if s == "undefined" {
103 Value::Undefined
104 } else {
105 Value::String(s.clone())
106 }
107 })
108 .collect();
109
110 let bytecode = Bytecode::new(instructions);
111 self.executor
112 .execute(&bytecode, &values)
113 .map_err(|e| format!("Execution error: {}", e))?;
114
115 Ok(self.executor.stack_mut().pop().unwrap_or(Value::Undefined))
116 }
117
118 pub fn get_context(&self) -> &Context {
119 &self.context
120 }
121
122 pub fn get_context_mut(&mut self) -> &mut Context {
123 &mut self.context
124 }
125}