1use crate::bytecode::{Chunk, NativeFunction, OpCode};
2use crate::value::{Value, ArithmeticOps, LogicalOps, ComparisonOps};
3use crate::native;
4use std::collections::HashMap;
5
6struct Scope {
8 variables: HashMap<String, Value>,
9}
10
11struct CallFrame {
13 param_names: Vec<String>,
15 return_address: usize,
17 stack_offset: usize,
19 locals: HashMap<String, Value>,
21}
22
23pub struct VM {
25 ip: usize,
27 stack: Vec<Value>,
29 scopes: Vec<Scope>,
31 frames: Vec<CallFrame>,
33 current_frame: Option<usize>,
35}
36
37
38pub fn execute_bytecode(chunk: &Chunk) -> Result<(), String> {
48 let mut vm = VM::new();
49 vm.interpret(chunk)
50}
51
52
53impl Default for VM {
54 fn default() -> Self {
55 Self::new()
56 }
57}
58
59impl VM {
60 pub fn new() -> Self {
62 let mut vm = VM {
63 ip: 0,
64 stack: Vec::new(),
65 scopes: vec![Scope { variables: HashMap::new() }], frames: Vec::new(),
67 current_frame: None,
68 };
69 vm.register_native_functions();
70 vm
71 }
72
73 fn register_native_functions(&mut self) {
75 self.define_native("print_value", 1, native::print_value);
76 }
77
78 fn define_native(
86 &mut self,
87 name: &str,
88 arity: u8,
89 function: fn(&[Value]) -> Result<Value, String>,
90 ) {
91 let native_fn = Value::NativeFunction(Box::new(NativeFunction {
92 name: name.to_string(),
93 arity,
94 function,
95 }));
96
97 self.set_variable(name.to_string(), native_fn);
98 }
99
100
101 pub fn interpret(&mut self, chunk: &Chunk) -> Result<(), String> {
111 self.ip = 0;
112 while self.ip < chunk.code.len() {
113 self.execute_instruction(chunk)?;
114 }
115
116 #[cfg(feature = "trace-execution")]
117 {
118 if !self.stack.is_empty() {
119 println!("\n=== Values on stack at end of execution ===");
120 for value in &self.stack {
121 println!("{}", value);
122 }
123 }
124 }
125
126 Ok(())
127 }
128
129 fn execute_instruction(&mut self, chunk: &Chunk) -> Result<(), String> {
139 let instruction = self.read_byte(chunk);
140 let op = OpCode::from_int(instruction)
141 .ok_or_else(|| format!("Unknown opcode: {}", instruction))?;
142
143 match op {
144 OpCode::Constant => {
145 let constant_idx = self.read_byte(chunk) as usize;
146 if constant_idx >= chunk.constants.len() {
147 return Err("Invalid constant index".to_string());
148 }
149 let constant = &chunk.constants[constant_idx];
150 self.stack.push(constant.clone());
151 }
152 OpCode::Add => {
153 self.binary_op(|a, b| a.add(b))?;
154 }
155 OpCode::Subtract => {
156 self.binary_op(|a, b| a.subtract(b))?;
157 }
158 OpCode::Multiply => {
159 self.binary_op(|a, b| a.multiply(b))?;
160 }
161 OpCode::Divide => {
162 self.binary_op(|a, b| a.divide(b))?;
163 }
164 OpCode::Negate => {
165 let value = self.pop()?;
166 self.stack.push(value.negate()?);
167 }
168 OpCode::Return => {
169 if let Some(frame_index) = self.current_frame {
170 let return_value = if self.stack.is_empty() {
171 Value::Unit(())
172 } else {
173 self.pop()?
174 };
175
176 let frame = &self.frames[frame_index];
177 let return_address = frame.return_address;
178 let stack_offset = frame.stack_offset;
179
180 while self.stack.len() > stack_offset {
181 self.pop()?;
182 }
183
184 self.stack.push(return_value);
185
186 self.ip = return_address;
187
188 self.frames.pop();
189 self.current_frame = if self.frames.is_empty() {
190 None
191 } else {
192 Some(self.frames.len() - 1)
193 };
194 } else {
195 self.ip = chunk.code.len();
196 }
197 }
198 OpCode::Print => {
199 let value = self.pop()?;
200 println!("{}", value);
201 }
202 OpCode::GetVariable => {
203 let var_index = self.read_byte(chunk) as usize;
204 if var_index >= chunk.identifiers.len() {
205 return Err("Invalid variable index".to_string());
206 }
207 let var_name = &chunk.identifiers[var_index];
208
209 let value = if let Some(frame_idx) = self.current_frame {
210 if let Some(value) = self.frames[frame_idx].locals.get(var_name) {
211 value.clone()
212 } else if let Some(value) = self.get_variable(var_name) {
213 value.clone()
214 } else {
215 return Err(format!("Undefined variable '{}'", var_name));
216 }
217 } else if let Some(value) = self.get_variable(var_name) {
218 value.clone()
219 } else {
220 return Err(format!("Undefined variable '{}'", var_name));
221 };
222
223 self.stack.push(value);
224 }
225 OpCode::SetVariable => {
226 if self.stack.is_empty() {
227 return Err("Stack underflow".to_string());
228 }
229 let var_index = self.read_byte(chunk) as usize;
230 if var_index >= chunk.identifiers.len() {
231 return Err("Invalid variable index".to_string());
232 }
233 let var_name = chunk.identifiers[var_index].clone();
234 let value = self.stack.last().unwrap().clone();
235
236 if let Some(frame_idx) = self.current_frame {
237 if self.frames[frame_idx].param_names.contains(&var_name) {
238 self.frames[frame_idx].locals.insert(var_name, value);
239 } else {
240 self.set_variable(var_name, value);
241 }
242 } else {
243 self.set_variable(var_name, value);
244 }
245 }
246 OpCode::Pop => {
247 self.pop()?;
248 }
249 OpCode::DefineFunction => {
250 let var_index = self.read_byte(chunk) as usize;
251 let constant_index = self.read_byte(chunk) as usize;
252
253 if var_index >= chunk.identifiers.len() || constant_index >= chunk.constants.len() {
254 return Err("Invalid index for function definition".to_string());
255 }
256
257 let var_name = chunk.identifiers[var_index].clone();
258 let value = &chunk.constants[constant_index];
259
260 self.set_variable(var_name, value.clone());
261 }
262 OpCode::Call => {
263 let arg_count = self.read_byte(chunk) as usize;
264
265 if self.stack.len() < arg_count + 1 {
266 return Err("Stack underflow during function call".to_string());
267 }
268
269 let function_pos = self.stack.len() - 1;
270 let function_value = self.stack[function_pos].clone();
271
272 match function_value {
273 Value::Function(func) => {
274 if arg_count != func.arity as usize {
275 return Err(format!(
276 "Expected {} arguments but got {}",
277 func.arity, arg_count
278 ));
279 }
280
281 let mut locals = HashMap::new();
282
283 for i in 0..arg_count {
284 if i < func.locals.len() {
285 let param_name = &func.locals[i];
286 let arg_value = self.stack[function_pos - arg_count + i].clone();
287 locals.insert(param_name.clone(), arg_value);
288 }
289 }
290
291 let frame = CallFrame {
292 param_names: func.locals.clone(),
293 return_address: self.ip,
294 stack_offset: function_pos - arg_count,
295 locals,
296 };
297
298 for _ in 0..=arg_count {
300 self.pop()?;
301 }
302
303 self.frames.push(frame);
304 self.current_frame = Some(self.frames.len() - 1);
305
306 self.ip = func.code_offset;
307 }
308 Value::NativeFunction(native_fn) => {
309 if arg_count != native_fn.arity as usize {
310 return Err(format!(
311 "Expected {} arguments but got {}",
312 native_fn.arity, arg_count
313 ));
314 }
315
316 let mut args = Vec::with_capacity(arg_count);
317 for i in 0..arg_count {
318 args.push(self.stack[function_pos - 1 - i].clone());
319 }
320
321 let result = (native_fn.function)(&args)?;
322 for _ in 0..=arg_count {
323 self.pop()?;
324 }
325
326 self.stack.push(result);
327 }
328 _ => return Err("Can only call functions".to_string()),
329 }
330 }
331 OpCode::Jump => {
332 let offset =
333 ((self.read_byte(chunk) as usize) << 8) | self.read_byte(chunk) as usize;
334 self.ip += offset;
335 }
336 OpCode::JumpIfFalse => {
337 let offset =
338 ((self.read_byte(chunk) as usize) << 8) | self.read_byte(chunk) as usize;
339 let condition = self.peek(0)?;
340
341 let is_truthy = match condition {
342 Value::Boolean(b) => *b,
343 _ => return Err("Condition must be a boolean".to_string()),
344 };
345
346 if !is_truthy {
347 self.ip += offset;
348 }
349 }
350 OpCode::BoolNot => {
351 let value = self.pop()?;
352 self.stack.push(value.not()?);
353 }
354 OpCode::BoolAnd => {
355 self.binary_op(|a, b| a.and(b))?;
356 }
357 OpCode::BoolOr => {
358 self.binary_op(|a, b| a.or(b))?;
359 }
360 OpCode::Greater => {
361 self.binary_op(|a, b| a.greater_than(b))?;
362 }
363 OpCode::Less => {
364 self.binary_op(|a, b| a.less_than(b))?;
365 }
366 OpCode::GreaterEqual => {
367 self.binary_op(|a, b| a.greater_than_equal(b))?;
368 }
369 OpCode::LessEqual => {
370 self.binary_op(|a, b| a.less_than_equal(b))?;
371 }
372 OpCode::Equal => {
373 self.binary_op(|a, b| a.equal(b))?;
374 }
375 OpCode::NotEqual => {
376 self.binary_op(|a, b| a.not_equal(b))?;
377 }
378 OpCode::BeginScope => {
379 self.scopes.push(Scope {
380 variables: HashMap::new(),
381 });
382 }
383 OpCode::EndScope => {
384 if self.scopes.len() <= 1 {
385 return Err("Cannot end global scope".to_string());
386 }
387 self.scopes.pop();
388 }
389 }
390
391 Ok(())
392 }
393
394 fn read_byte(&mut self, chunk: &Chunk) -> u8 {
404 let byte = chunk.code[self.ip];
405 self.ip += 1;
406 byte
407 }
408
409 fn pop(&mut self) -> Result<Value, String> {
415 self.stack
416 .pop()
417 .ok_or_else(|| "Stack underflow".to_string())
418 }
419
420 fn peek(&self, distance: usize) -> Result<&Value, String> {
430 if distance >= self.stack.len() {
431 return Err("Stack underflow".to_string());
432 }
433
434 Ok(&self.stack[self.stack.len() - 1 - distance])
435 }
436
437 fn binary_op<F>(&mut self, op: F) -> Result<(), String>
447 where
448 F: FnOnce(&Value, &Value) -> Result<Value, String>,
449 {
450 if self.stack.len() < 2 {
451 return Err("Stack underflow".to_string());
452 }
453 let b = self.pop()?;
454 let a = self.pop()?;
455 let result = op(&a, &b)?;
456 self.stack.push(result);
457 Ok(())
458 }
459
460 fn get_variable(&self, name: &str) -> Option<&Value> {
462 for scope in self.scopes.iter().rev() {
463 if let Some(value) = scope.variables.get(name) {
464 return Some(value);
465 }
466 }
467 None
468 }
469
470 fn set_variable(&mut self, name: String, value: Value) {
472 if let Some(current_scope) = self.scopes.last_mut() {
473 current_scope.variables.insert(name, value);
474 }
475 }
476}