1use std::collections::{HashMap, HashSet};
2use std::sync::Arc;
3
4use indexmap::IndexMap;
5
6use crate::compiler::instruction::{Constant, Instruction};
7use crate::compiler::CompiledProgram;
8use crate::error::{Result, ZapcodeError};
9use crate::sandbox::{ResourceLimits, ResourceTracker};
10use crate::snapshot::ZapcodeSnapshot;
11use crate::trace::{ExecutionTrace, SpanBuilder, TraceStatus};
12use crate::value::{Closure, FunctionId, GeneratorObject, SuspendedFrame, Value};
13
14mod builtins;
15
16#[derive(Debug)]
18pub enum VmState {
19 Complete(Value),
20 Suspended {
21 function_name: String,
22 args: Vec<Value>,
23 snapshot: ZapcodeSnapshot,
24 },
25}
26
27#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
30pub(crate) enum ReceiverSource {
31 Global(String),
33 Local { frame_index: usize, slot: usize },
36}
37
38#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
40pub(crate) struct CallFrame {
41 pub(crate) func_index: Option<usize>,
42 pub(crate) ip: usize,
43 pub(crate) locals: Vec<Value>,
44 pub(crate) stack_base: usize,
45 pub(crate) this_value: Option<Value>,
47 pub(crate) receiver_source: Option<ReceiverSource>,
49}
50
51pub struct Vm {
53 pub(crate) program: CompiledProgram,
54 pub(crate) stack: Vec<Value>,
55 pub(crate) frames: Vec<CallFrame>,
56 pub(crate) globals: HashMap<String, Value>,
57 pub(crate) stdout: String,
58 pub(crate) limits: ResourceLimits,
59 pub(crate) tracker: ResourceTracker,
60 pub(crate) external_functions: HashSet<String>,
61 pub(crate) try_stack: Vec<TryInfo>,
62 last_receiver: Option<Value>,
64 last_receiver_source: Option<ReceiverSource>,
66 last_global_name: Option<String>,
68 last_load_source: Option<ReceiverSource>,
70 next_generator_id: u64,
72}
73
74#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
75pub(crate) struct TryInfo {
76 pub(crate) catch_ip: usize,
77 pub(crate) frame_depth: usize,
78 pub(crate) stack_depth: usize,
79}
80
81impl Vm {
82 fn new(
83 program: CompiledProgram,
84 limits: ResourceLimits,
85 external_functions: HashSet<String>,
86 ) -> Self {
87 let mut globals = HashMap::new();
88
89 builtins::register_globals(&mut globals);
91
92 Self {
93 program,
94 stack: Vec::new(),
95 frames: Vec::new(),
96 globals,
97 stdout: String::new(),
98 limits,
99 tracker: ResourceTracker::default(),
100 external_functions,
101 try_stack: Vec::new(),
102 last_receiver: None,
103 last_receiver_source: None,
104 last_global_name: None,
105 last_load_source: None,
106 next_generator_id: 0,
107 }
108 }
109
110 pub(crate) const BUILTIN_GLOBAL_NAMES: &'static [&'static str] =
112 &["console", "JSON", "Object", "Array", "Math", "Promise"];
113
114 #[allow(clippy::too_many_arguments)]
118 pub(crate) fn from_snapshot(
119 program: CompiledProgram,
120 stack: Vec<Value>,
121 frames: Vec<CallFrame>,
122 user_globals: HashMap<String, Value>,
123 try_stack: Vec<TryInfo>,
124 stdout: String,
125 limits: ResourceLimits,
126 external_functions: HashSet<String>,
127 ) -> Self {
128 let mut globals = HashMap::new();
129 builtins::register_globals(&mut globals);
131 for (k, v) in user_globals {
133 globals.insert(k, v);
134 }
135
136 Self {
137 program,
138 stack,
139 frames,
140 globals,
141 stdout,
142 limits,
143 tracker: ResourceTracker::default(),
144 external_functions,
145 try_stack,
146 last_receiver: None,
147 last_receiver_source: None,
148 last_global_name: None,
149 last_load_source: None,
150 next_generator_id: 0,
151 }
152 }
153
154 pub(crate) fn resume_execution(&mut self) -> Result<VmState> {
157 self.tracker.start();
158 self.execute()
159 }
160
161 fn push(&mut self, value: Value) -> Result<()> {
162 self.tracker.track_allocation(&self.limits)?;
163 self.stack.push(value);
164 Ok(())
165 }
166
167 fn pop(&mut self) -> Result<Value> {
168 self.stack
169 .pop()
170 .ok_or_else(|| ZapcodeError::RuntimeError("stack underflow".to_string()))
171 }
172
173 fn peek(&self) -> Result<&Value> {
174 self.stack
175 .last()
176 .ok_or_else(|| ZapcodeError::RuntimeError("stack underflow".to_string()))
177 }
178
179 fn current_frame(&self) -> &CallFrame {
180 self.frames.last().expect("internal error: no active frame")
183 }
184
185 fn current_frame_mut(&mut self) -> &mut CallFrame {
186 self.frames
187 .last_mut()
188 .expect("internal error: no active frame")
189 }
190
191 #[allow(dead_code)]
192 fn instructions(&self) -> &[Instruction] {
193 match self.current_frame().func_index {
194 Some(idx) => &self.program.functions[idx].instructions,
195 None => &self.program.instructions,
196 }
197 }
198
199 fn bind_params(params: &[ParamPattern], args: &[Value], local_count: usize) -> Vec<Value> {
202 let mut locals = Vec::with_capacity(local_count);
203 for (i, param) in params.iter().enumerate() {
204 match param {
205 ParamPattern::Ident(_) => {
206 locals.push(args.get(i).cloned().unwrap_or(Value::Undefined));
207 }
208 ParamPattern::Rest(_) => {
209 let rest: Vec<Value> = args[i..].to_vec();
210 locals.push(Value::Array(rest));
211 }
212 ParamPattern::DefaultValue { .. } => {
213 let val = args.get(i).cloned().unwrap_or(Value::Undefined);
214 locals.push(val);
216 }
217 _ => {
218 locals.push(args.get(i).cloned().unwrap_or(Value::Undefined));
219 }
220 }
221 }
222 locals
223 }
224
225 fn push_call_frame(
227 &mut self,
228 closure: &Closure,
229 args: &[Value],
230 this_value: Option<Value>,
231 ) -> Result<()> {
232 self.tracker.push_frame();
233 self.tracker.check_stack(&self.limits)?;
234
235 for (name, val) in &closure.captured {
237 if !self.globals.contains_key(name) {
238 self.globals.insert(name.clone(), val.clone());
239 }
240 }
241
242 let func = &self.program.functions[closure.func_id.0];
243 let locals = Self::bind_params(&func.params, args, func.local_count);
244
245 let receiver_source = if this_value.is_some() {
248 self.last_receiver_source.take()
249 } else {
250 self.last_receiver_source = None;
251 None
252 };
253
254 self.frames.push(CallFrame {
255 func_index: Some(closure.func_id.0),
256 ip: 0,
257 locals,
258 stack_base: self.stack.len(),
259 this_value,
260 receiver_source,
261 });
262 Ok(())
263 }
264
265 fn run(&mut self) -> Result<VmState> {
266 self.tracker.start();
267
268 self.frames.push(CallFrame {
270 func_index: None,
271 ip: 0,
272 locals: Vec::new(),
273 stack_base: 0,
274 this_value: None,
275 receiver_source: None,
276 });
277
278 self.execute()
279 }
280
281 fn execute(&mut self) -> Result<VmState> {
282 loop {
283 self.tracker.check_time(&self.limits)?;
285
286 let frame = self.frames.last().unwrap();
287 let instructions = match frame.func_index {
288 Some(idx) => &self.program.functions[idx].instructions,
289 None => &self.program.instructions,
290 };
291
292 if frame.ip >= instructions.len() {
293 if self.frames.len() <= 1 {
295 let result = if self.stack.is_empty() {
297 Value::Undefined
298 } else {
299 self.stack.pop().unwrap_or(Value::Undefined)
300 };
301 return Ok(VmState::Complete(result));
302 } else {
303 let frame = self.frames.pop().unwrap();
305 self.tracker.pop_frame();
306 if let Some(this_val) = frame.this_value {
308 self.stack.truncate(frame.stack_base);
309 self.push(this_val)?;
310 } else {
311 self.push(Value::Undefined)?;
312 }
313 continue;
314 }
315 }
316
317 let instr = instructions[frame.ip].clone();
318 let result = self.dispatch(instr);
319
320 match result {
321 Ok(Some(state)) => return Ok(state),
322 Ok(None) => {}
323 Err(err) => {
324 if let Some(try_info) = self.try_stack.pop() {
326 while self.frames.len() > try_info.frame_depth {
328 self.frames.pop();
329 self.tracker.pop_frame();
330 }
331 self.stack.truncate(try_info.stack_depth);
332
333 let error_val = Value::String(Arc::from(err.to_string()));
335 self.push(error_val)?;
336
337 self.current_frame_mut().ip = try_info.catch_ip;
339 } else {
340 return Err(err);
341 }
342 }
343 }
344 }
345 }
346
347 fn call_function_internal(&mut self, callee: &Value, args: Vec<Value>) -> Result<Value> {
350 let closure = match callee {
351 Value::Function(c) => c.clone(),
352 other => {
353 return Err(ZapcodeError::TypeError(format!(
354 "{} is not a function",
355 other.to_js_string()
356 )));
357 }
358 };
359
360 let target_frame_depth = self.frames.len();
361 self.push_call_frame(&closure, &args, None)?;
362
363 loop {
365 self.tracker.check_time(&self.limits)?;
366
367 let frame = self.frames.last().unwrap();
368 let instructions = match frame.func_index {
369 Some(idx) => &self.program.functions[idx].instructions,
370 None => &self.program.instructions,
371 };
372
373 if frame.ip >= instructions.len() {
374 if self.frames.len() > target_frame_depth + 1 {
376 self.frames.pop();
378 self.tracker.pop_frame();
379 self.push(Value::Undefined)?;
380 continue;
381 } else {
382 self.frames.pop();
384 self.tracker.pop_frame();
385 return Ok(Value::Undefined);
386 }
387 }
388
389 let instr = instructions[frame.ip].clone();
390 let result = self.dispatch(instr);
391
392 match result {
393 Ok(Some(VmState::Complete(val))) => {
394 return Ok(val);
397 }
398 Ok(Some(VmState::Suspended { .. })) => {
399 return Err(ZapcodeError::RuntimeError(
400 "cannot suspend inside array callback".to_string(),
401 ));
402 }
403 Ok(None) => {
404 if self.frames.len() == target_frame_depth {
406 return Ok(self.pop().unwrap_or(Value::Undefined));
408 }
409 }
410 Err(err) => {
411 if let Some(try_info) = self.try_stack.pop() {
413 while self.frames.len() > try_info.frame_depth {
414 self.frames.pop();
415 self.tracker.pop_frame();
416 }
417 self.stack.truncate(try_info.stack_depth);
418 let error_val = Value::String(Arc::from(err.to_string()));
419 self.push(error_val)?;
420 self.current_frame_mut().ip = try_info.catch_ip;
421 } else {
422 return Err(err);
423 }
424 }
425 }
426 }
427 }
428
429 fn call_element_callback(
433 &mut self,
434 callback: &Value,
435 item: &Value,
436 index: usize,
437 ) -> Result<Value> {
438 self.call_function_internal(callback, vec![item.clone(), Value::Int(index as i64)])
439 }
440
441 fn execute_array_callback_method(
443 &mut self,
444 arr: Vec<Value>,
445 method: &str,
446 all_args: Vec<Value>,
447 ) -> Result<Value> {
448 let callback = all_args.first().cloned().unwrap_or(Value::Undefined);
449
450 match method {
451 "map" => {
452 let mut result = Vec::with_capacity(arr.len());
453 for (i, item) in arr.iter().enumerate() {
454 result.push(self.call_element_callback(&callback, item, i)?);
455 }
456 Ok(Value::Array(result))
457 }
458 "filter" => {
459 let mut result = Vec::new();
460 for (i, item) in arr.iter().enumerate() {
461 if self.call_element_callback(&callback, item, i)?.is_truthy() {
462 result.push(item.clone());
463 }
464 }
465 Ok(Value::Array(result))
466 }
467 "forEach" => {
468 for (i, item) in arr.iter().enumerate() {
469 self.call_element_callback(&callback, item, i)?;
470 }
471 Ok(Value::Undefined)
472 }
473 "find" => {
474 for (i, item) in arr.iter().enumerate() {
475 if self.call_element_callback(&callback, item, i)?.is_truthy() {
476 return Ok(item.clone());
477 }
478 }
479 Ok(Value::Undefined)
480 }
481 "findIndex" => {
482 for (i, item) in arr.iter().enumerate() {
483 if self.call_element_callback(&callback, item, i)?.is_truthy() {
484 return Ok(Value::Int(i as i64));
485 }
486 }
487 Ok(Value::Int(-1))
488 }
489 "every" => {
490 for (i, item) in arr.iter().enumerate() {
491 if !self.call_element_callback(&callback, item, i)?.is_truthy() {
492 return Ok(Value::Bool(false));
493 }
494 }
495 Ok(Value::Bool(true))
496 }
497 "some" => {
498 for (i, item) in arr.iter().enumerate() {
499 if self.call_element_callback(&callback, item, i)?.is_truthy() {
500 return Ok(Value::Bool(true));
501 }
502 }
503 Ok(Value::Bool(false))
504 }
505 "reduce" => {
506 let mut acc = match all_args.get(1).cloned() {
507 Some(init) => Some(init),
508 None if !arr.is_empty() => Some(arr[0].clone()),
509 None => {
510 return Err(ZapcodeError::TypeError(
511 "Reduce of empty array with no initial value".to_string(),
512 ));
513 }
514 };
515 let start = if all_args.get(1).is_some() { 0 } else { 1 };
516 for (i, item) in arr.iter().enumerate().skip(start) {
517 acc = Some(self.call_function_internal(
518 &callback,
519 vec![acc.unwrap(), item.clone(), Value::Int(i as i64)],
520 )?);
521 }
522 Ok(acc.unwrap_or(Value::Undefined))
523 }
524 "sort" => {
525 let mut result = arr;
526 if matches!(callback, Value::Function(_)) {
527 let len = result.len();
530 for i in 1..len {
531 let mut j = i;
532 while j > 0 {
533 let cmp = self
534 .call_function_internal(
535 &callback,
536 vec![result[j - 1].clone(), result[j].clone()],
537 )?
538 .to_number();
539 if cmp > 0.0 {
540 result.swap(j - 1, j);
541 j -= 1;
542 } else {
543 break;
544 }
545 }
546 }
547 } else {
548 result.sort_by_key(|a| a.to_js_string());
549 }
550 Ok(Value::Array(result))
551 }
552 "flatMap" => {
553 let mut result = Vec::new();
554 for (i, item) in arr.iter().enumerate() {
555 match self.call_element_callback(&callback, item, i)? {
556 Value::Array(inner) => result.extend(inner),
557 other => result.push(other),
558 }
559 }
560 Ok(Value::Array(result))
561 }
562 _ => Err(ZapcodeError::TypeError(format!(
563 "Unknown array callback method: {}",
564 method
565 ))),
566 }
567 }
568
569 fn execute_promise_method(
572 &mut self,
573 promise: Value,
574 method: &str,
575 args: Vec<Value>,
576 ) -> Result<Option<Value>> {
577 let (status, value, reason) = if let Value::Object(ref map) = promise {
578 let status = match map.get("status") {
579 Some(Value::String(s)) => s.to_string(),
580 _ => "pending".to_string(),
581 };
582 let value = map.get("value").cloned().unwrap_or(Value::Undefined);
583 let reason = map.get("reason").cloned().unwrap_or(Value::Undefined);
584 (status, value, reason)
585 } else {
586 return Ok(None);
587 };
588
589 let on_fulfilled = args.first().cloned().unwrap_or(Value::Undefined);
590 let on_rejected = args.get(1).cloned().unwrap_or(Value::Undefined);
591
592 match method {
593 "then" => {
594 if status == "resolved" {
595 if matches!(on_fulfilled, Value::Function(_)) {
596 let result = self.call_function_internal(&on_fulfilled, vec![value])?;
597 Ok(Some(builtins::make_resolved_promise(result)))
598 } else {
599 Ok(Some(promise))
601 }
602 } else if status == "rejected" {
603 if matches!(on_rejected, Value::Function(_)) {
604 let result = self.call_function_internal(&on_rejected, vec![reason])?;
605 Ok(Some(builtins::make_resolved_promise(result)))
606 } else {
607 Ok(Some(promise))
609 }
610 } else {
611 Ok(Some(promise))
612 }
613 }
614 "catch" => {
615 if status == "rejected" {
616 let handler = args.first().cloned().unwrap_or(Value::Undefined);
617 if matches!(handler, Value::Function(_)) {
618 let result = self.call_function_internal(&handler, vec![reason])?;
619 Ok(Some(builtins::make_resolved_promise(result)))
620 } else {
621 Ok(Some(promise))
622 }
623 } else {
624 Ok(Some(promise))
626 }
627 }
628 "finally" => {
629 let handler = args.first().cloned().unwrap_or(Value::Undefined);
630 if matches!(handler, Value::Function(_)) {
631 self.call_function_internal(&handler, vec![])?;
633 }
634 Ok(Some(promise))
636 }
637 _ => Ok(None),
638 }
639 }
640
641 fn alloc_generator_id(&mut self) -> u64 {
642 let id = self.next_generator_id;
643 self.next_generator_id += 1;
644 id
645 }
646
647 fn generator_next(&mut self, mut gen_obj: GeneratorObject, arg: Value) -> Result<Value> {
648 if gen_obj.done {
649 return Ok(self.make_iterator_result(Value::Undefined, true));
650 }
651 for (name, val) in &gen_obj.captured {
652 if !self.globals.contains_key(name) {
653 self.globals.insert(name.clone(), val.clone());
654 }
655 }
656 let func_idx = gen_obj.func_id.0;
657 match gen_obj.suspended.take() {
658 None => {
659 let func = &self.program.functions[func_idx];
660 self.tracker.push_frame();
661 let mut locals = Vec::with_capacity(func.local_count);
662 for param in func.params.iter() {
663 match param {
664 ParamPattern::Ident(name) => {
665 let val = gen_obj
666 .captured
667 .iter()
668 .find(|(n, _)| n == name)
669 .map(|(_, v)| v.clone())
670 .unwrap_or(Value::Undefined);
671 locals.push(val);
672 }
673 ParamPattern::Rest(name) => {
674 let val = gen_obj
675 .captured
676 .iter()
677 .find(|(n, _)| n == name)
678 .map(|(_, v)| v.clone())
679 .unwrap_or(Value::Array(Vec::new()));
680 locals.push(val);
681 }
682 _ => {
683 locals.push(Value::Undefined);
684 }
685 }
686 }
687 let stack_base = self.stack.len();
688 self.frames.push(CallFrame {
689 func_index: Some(func_idx),
690 ip: 0,
691 locals,
692 stack_base,
693 this_value: None,
694 receiver_source: None,
695 });
696 self.run_generator_until_yield_or_return(gen_obj)
697 }
698 Some(suspended) => {
699 self.tracker.push_frame();
700 let stack_base = self.stack.len();
701 for val in &suspended.stack {
702 self.push(val.clone())?;
703 }
704 self.push(arg)?;
705 self.frames.push(CallFrame {
706 func_index: Some(func_idx),
707 ip: suspended.ip,
708 locals: suspended.locals,
709 stack_base,
710 this_value: None,
711 receiver_source: None,
712 });
713 self.run_generator_until_yield_or_return(gen_obj)
714 }
715 }
716 }
717
718 fn store_generator(&mut self, gen_obj: GeneratorObject) {
721 let gen_key = format!("__gen_{}", gen_obj.id);
722 if gen_obj.done {
723 self.globals.remove(&gen_key);
724 } else {
725 self.globals.insert(gen_key, Value::Generator(gen_obj));
726 }
727 }
728
729 fn finish_generator(&mut self, mut gen_obj: GeneratorObject, value: Value) -> Value {
731 gen_obj.done = true;
732 gen_obj.suspended = None;
733 self.store_generator(gen_obj);
734 self.make_iterator_result(value, true)
735 }
736
737 fn run_generator_until_yield_or_return(
738 &mut self,
739 mut gen_obj: GeneratorObject,
740 ) -> Result<Value> {
741 let target_frame_depth = self.frames.len() - 1;
742 loop {
743 self.tracker.check_time(&self.limits)?;
744 let frame = self.frames.last().unwrap();
745 let instructions = match frame.func_index {
746 Some(idx) => &self.program.functions[idx].instructions,
747 None => &self.program.instructions,
748 };
749 if frame.ip >= instructions.len() {
750 if self.frames.len() > target_frame_depth + 1 {
751 let frame = self.frames.pop().unwrap();
752 self.tracker.pop_frame();
753 if let Some(this_val) = frame.this_value {
754 self.stack.truncate(frame.stack_base);
755 self.push(this_val)?;
756 } else {
757 self.push(Value::Undefined)?;
758 }
759 continue;
760 }
761 let frame = self.frames.pop().unwrap();
762 self.tracker.pop_frame();
763 self.stack.truncate(frame.stack_base);
764 let result = self.finish_generator(gen_obj, Value::Undefined);
765 return Ok(result);
766 }
767 let instr = instructions[frame.ip].clone();
768 if matches!(instr, Instruction::Yield) {
769 self.current_frame_mut().ip += 1;
770 let yielded_value = self.pop()?;
771 let frame = self.frames.pop().unwrap();
772 self.tracker.pop_frame();
773 let frame_stack: Vec<Value> = self.stack.drain(frame.stack_base..).collect();
774 gen_obj.suspended = Some(SuspendedFrame {
775 ip: frame.ip,
776 locals: frame.locals,
777 stack: frame_stack,
778 });
779 gen_obj.done = false;
780 self.store_generator(gen_obj);
781 return Ok(self.make_iterator_result(yielded_value, false));
782 }
783 if matches!(instr, Instruction::Return) {
784 self.current_frame_mut().ip += 1;
785 let return_val = self.pop().unwrap_or(Value::Undefined);
786 if self.frames.len() > target_frame_depth + 1 {
787 let frame = self.frames.pop().unwrap();
788 self.tracker.pop_frame();
789 self.stack.truncate(frame.stack_base);
790 self.push(return_val)?;
791 continue;
792 }
793 let frame = self.frames.pop().unwrap();
794 self.tracker.pop_frame();
795 self.stack.truncate(frame.stack_base);
796 let result = self.finish_generator(gen_obj, return_val);
797 return Ok(result);
798 }
799 let result = self.dispatch(instr);
800 match result {
801 Ok(Some(VmState::Complete(val))) => return Ok(val),
802 Ok(Some(VmState::Suspended { .. })) => {
803 return Err(ZapcodeError::RuntimeError(
804 "cannot suspend inside a generator".to_string(),
805 ));
806 }
807 Ok(None) => {
808 if self.frames.len() == target_frame_depth {
809 let return_val = self.pop().unwrap_or(Value::Undefined);
810 let result = self.finish_generator(gen_obj, return_val);
811 return Ok(result);
812 }
813 }
814 Err(err) => {
815 if let Some(try_info) = self.try_stack.pop() {
816 while self.frames.len() > try_info.frame_depth {
817 self.frames.pop();
818 self.tracker.pop_frame();
819 }
820 self.stack.truncate(try_info.stack_depth);
821 let error_val = Value::String(Arc::from(err.to_string()));
822 self.push(error_val)?;
823 self.current_frame_mut().ip = try_info.catch_ip;
824 } else {
825 return Err(err);
826 }
827 }
828 }
829 }
830 }
831
832 fn make_iterator_result(&self, value: Value, done: bool) -> Value {
833 let mut obj = IndexMap::new();
834 obj.insert(Arc::from("value"), value);
835 obj.insert(Arc::from("done"), Value::Bool(done));
836 Value::Object(obj)
837 }
838
839 fn dispatch(&mut self, instr: Instruction) -> Result<Option<VmState>> {
840 self.current_frame_mut().ip += 1;
841
842 match instr {
843 Instruction::Push(constant) => {
844 let value = match constant {
845 Constant::Undefined => Value::Undefined,
846 Constant::Null => Value::Null,
847 Constant::Bool(b) => Value::Bool(b),
848 Constant::Int(n) => Value::Int(n),
849 Constant::Float(n) => Value::Float(n),
850 Constant::String(s) => Value::String(Arc::from(s.as_str())),
851 };
852 self.push(value)?;
853 }
854 Instruction::Pop => {
855 self.pop()?;
856 }
857 Instruction::Dup => {
858 let val = self.peek()?.clone();
859 self.push(val)?;
860 }
861 Instruction::LoadLocal(idx) => {
862 let frame_index = self.frames.len() - 1;
863 let frame = self.current_frame();
864 let val = frame.locals.get(idx).cloned().unwrap_or(Value::Undefined);
865 self.last_load_source = Some(ReceiverSource::Local {
866 frame_index,
867 slot: idx,
868 });
869 self.push(val)?;
870 }
871 Instruction::StoreLocal(idx) => {
872 let val = self.pop()?;
873 let frame = self.current_frame_mut();
874 while frame.locals.len() <= idx {
875 frame.locals.push(Value::Undefined);
876 }
877 frame.locals[idx] = val;
878 }
879 Instruction::LoadGlobal(name) => {
880 let val = self.globals.get(&name).cloned().unwrap_or(Value::Undefined);
881 self.last_global_name = Some(name.clone());
882 if Self::BUILTIN_GLOBAL_NAMES.contains(&name.as_str()) {
886 self.last_load_source = None;
887 } else {
888 self.last_load_source = Some(ReceiverSource::Global(name));
889 }
890 self.push(val)?;
891 }
892 Instruction::StoreGlobal(name) => {
893 let val = self.pop()?;
894 self.globals.insert(name, val);
895 }
896 Instruction::DeclareLocal(_) => {
897 let frame = self.current_frame_mut();
898 frame.locals.push(Value::Undefined);
899 }
900
901 Instruction::Add => {
903 let right = self.pop()?;
904 let left = self.pop()?;
905 let result = match (&left, &right) {
906 (Value::Int(a), Value::Int(b)) => match a.checked_add(*b) {
907 Some(r) => Value::Int(r),
908 None => Value::Float(*a as f64 + *b as f64),
909 },
910 (Value::Float(a), Value::Float(b)) => Value::Float(a + b),
911 (Value::Int(a), Value::Float(b)) => Value::Float(*a as f64 + b),
912 (Value::Float(a), Value::Int(b)) => Value::Float(a + *b as f64),
913 (Value::String(a), _) => {
914 let rhs = right.to_js_string();
915 let new_len = a.len().saturating_add(rhs.len());
916 if new_len > 10_000_000 {
917 return Err(ZapcodeError::AllocationLimitExceeded);
918 }
919 let mut s = a.to_string();
920 s.push_str(&rhs);
921 Value::String(Arc::from(s.as_str()))
922 }
923 (_, Value::String(b)) => {
924 let lhs = left.to_js_string();
925 let new_len = lhs.len().saturating_add(b.len());
926 if new_len > 10_000_000 {
927 return Err(ZapcodeError::AllocationLimitExceeded);
928 }
929 let mut s = lhs;
930 s.push_str(b);
931 Value::String(Arc::from(s.as_str()))
932 }
933 _ => Value::Float(left.to_number() + right.to_number()),
934 };
935 self.push(result)?;
936 }
937 Instruction::Sub => {
938 let right = self.pop()?;
939 let left = self.pop()?;
940 let result = match (&left, &right) {
941 (Value::Int(a), Value::Int(b)) => match a.checked_sub(*b) {
942 Some(r) => Value::Int(r),
943 None => Value::Float(*a as f64 - *b as f64),
944 },
945 _ => Value::Float(left.to_number() - right.to_number()),
946 };
947 self.push(result)?;
948 }
949 Instruction::Mul => {
950 let right = self.pop()?;
951 let left = self.pop()?;
952 let result = match (&left, &right) {
953 (Value::Int(a), Value::Int(b)) => match a.checked_mul(*b) {
954 Some(r) => Value::Int(r),
955 None => Value::Float(*a as f64 * *b as f64),
956 },
957 _ => Value::Float(left.to_number() * right.to_number()),
958 };
959 self.push(result)?;
960 }
961 Instruction::Div => {
962 let right = self.pop()?;
963 let left = self.pop()?;
964 let result = Value::Float(left.to_number() / right.to_number());
965 self.push(result)?;
966 }
967 Instruction::Rem => {
968 let right = self.pop()?;
969 let left = self.pop()?;
970 let result = match (&left, &right) {
971 (Value::Int(a), Value::Int(b)) if *b != 0 => Value::Int(a % b),
972 _ => Value::Float(left.to_number() % right.to_number()),
973 };
974 self.push(result)?;
975 }
976 Instruction::Pow => {
977 let right = self.pop()?;
978 let left = self.pop()?;
979 let result = Value::Float(left.to_number().powf(right.to_number()));
980 self.push(result)?;
981 }
982 Instruction::Neg => {
983 let val = self.pop()?;
984 let result = match val {
985 Value::Int(n) => Value::Int(-n),
986 _ => Value::Float(-val.to_number()),
987 };
988 self.push(result)?;
989 }
990 Instruction::BitNot => {
991 let val = self.pop()?;
992 let n = val.to_number() as i32;
993 self.push(Value::Int(!n as i64))?;
994 }
995 Instruction::BitAnd => {
996 let right = self.pop()?;
997 let left = self.pop()?;
998 let result = (left.to_number() as i32) & (right.to_number() as i32);
999 self.push(Value::Int(result as i64))?;
1000 }
1001 Instruction::BitOr => {
1002 let right = self.pop()?;
1003 let left = self.pop()?;
1004 let result = (left.to_number() as i32) | (right.to_number() as i32);
1005 self.push(Value::Int(result as i64))?;
1006 }
1007 Instruction::BitXor => {
1008 let right = self.pop()?;
1009 let left = self.pop()?;
1010 let result = (left.to_number() as i32) ^ (right.to_number() as i32);
1011 self.push(Value::Int(result as i64))?;
1012 }
1013 Instruction::Shl => {
1014 let right = self.pop()?;
1015 let left = self.pop()?;
1016 let shift = (right.to_number() as u32) & 0x1f;
1017 let result = (left.to_number() as i32) << shift;
1018 self.push(Value::Int(result as i64))?;
1019 }
1020 Instruction::Shr => {
1021 let right = self.pop()?;
1022 let left = self.pop()?;
1023 let shift = (right.to_number() as u32) & 0x1f;
1024 let result = (left.to_number() as i32) >> shift;
1025 self.push(Value::Int(result as i64))?;
1026 }
1027 Instruction::Ushr => {
1028 let right = self.pop()?;
1029 let left = self.pop()?;
1030 let shift = (right.to_number() as u32) & 0x1f;
1031 let result = (left.to_number() as u32) >> shift;
1032 self.push(Value::Int(result as i64))?;
1033 }
1034
1035 Instruction::Eq | Instruction::StrictEq => {
1037 let right = self.pop()?;
1038 let left = self.pop()?;
1039 self.push(Value::Bool(left.strict_eq(&right)))?;
1040 }
1041 Instruction::Neq | Instruction::StrictNeq => {
1042 let right = self.pop()?;
1043 let left = self.pop()?;
1044 self.push(Value::Bool(!left.strict_eq(&right)))?;
1045 }
1046 Instruction::Lt => {
1047 let right = self.pop()?;
1048 let left = self.pop()?;
1049 self.push(Value::Bool(left.to_number() < right.to_number()))?;
1050 }
1051 Instruction::Lte => {
1052 let right = self.pop()?;
1053 let left = self.pop()?;
1054 self.push(Value::Bool(left.to_number() <= right.to_number()))?;
1055 }
1056 Instruction::Gt => {
1057 let right = self.pop()?;
1058 let left = self.pop()?;
1059 self.push(Value::Bool(left.to_number() > right.to_number()))?;
1060 }
1061 Instruction::Gte => {
1062 let right = self.pop()?;
1063 let left = self.pop()?;
1064 self.push(Value::Bool(left.to_number() >= right.to_number()))?;
1065 }
1066
1067 Instruction::Not => {
1069 let val = self.pop()?;
1070 self.push(Value::Bool(!val.is_truthy()))?;
1071 }
1072
1073 Instruction::CreateArray(count) => {
1075 self.tracker.track_allocation(&self.limits)?;
1076 let mut arr = Vec::with_capacity(count);
1077 for _ in 0..count {
1078 arr.push(self.pop()?);
1079 }
1080 arr.reverse();
1081 self.push(Value::Array(arr))?;
1082 }
1083 Instruction::CreateObject(count) => {
1084 self.tracker.track_allocation(&self.limits)?;
1085 let mut obj = IndexMap::new();
1086 let mut entries = Vec::new();
1088 for _ in 0..count {
1089 let val = self.pop()?;
1090 let key = self.pop()?;
1091 entries.push((key, val));
1092 }
1093 entries.reverse();
1094 for (key, val) in entries {
1095 match key {
1096 Value::String(k) => {
1097 obj.insert(k, val);
1098 }
1099 _ => {
1100 let k: Arc<str> = Arc::from(key.to_js_string().as_str());
1101 obj.insert(k, val);
1102 }
1103 }
1104 }
1105 self.push(Value::Object(obj))?;
1106 }
1107 Instruction::GetProperty(name) => {
1108 let obj = self.pop()?;
1109 let result = self.get_property(&obj, &name)?;
1110 if matches!(result, Value::BuiltinMethod { .. } | Value::Function(_)) {
1112 self.last_receiver = Some(obj);
1113 self.last_receiver_source = self.last_load_source.take();
1114 } else {
1115 self.last_receiver_source = None;
1116 }
1117 self.push(result)?;
1118 }
1119 Instruction::SetProperty(name) => {
1120 let obj_val = self.pop()?;
1123 let value = self.pop()?;
1124 match obj_val {
1125 Value::Object(mut obj) => {
1126 obj.insert(Arc::from(name.as_str()), value);
1127 self.push(Value::Object(obj))?;
1129 }
1130 _ => {
1131 return Err(ZapcodeError::TypeError(format!(
1132 "cannot set property '{}' on {}",
1133 name,
1134 obj_val.type_name()
1135 )));
1136 }
1137 }
1138 }
1139 Instruction::GetIndex => {
1140 let index = self.pop()?;
1141 let obj = self.pop()?;
1142 let result = match (&obj, &index) {
1143 (Value::Array(arr), Value::Int(i)) => {
1144 arr.get(*i as usize).cloned().unwrap_or(Value::Undefined)
1145 }
1146 (Value::Array(arr), Value::Float(f)) => {
1147 arr.get(*f as usize).cloned().unwrap_or(Value::Undefined)
1148 }
1149 (Value::Object(map), Value::String(key)) => {
1150 map.get(key.as_ref()).cloned().unwrap_or(Value::Undefined)
1151 }
1152 (Value::Object(map), _) => {
1153 let key: Arc<str> = Arc::from(index.to_js_string().as_str());
1154 map.get(key.as_ref()).cloned().unwrap_or(Value::Undefined)
1155 }
1156 (Value::String(s), Value::Int(i)) => s
1157 .chars()
1158 .nth(*i as usize)
1159 .map(|c| Value::String(Arc::from(c.to_string().as_str())))
1160 .unwrap_or(Value::Undefined),
1161 _ => Value::Undefined,
1162 };
1163 self.push(result)?;
1164 }
1165 Instruction::SetIndex => {
1166 let index = self.pop()?;
1167 let mut obj = self.pop()?;
1168 let value = self.pop()?;
1169 match &mut obj {
1170 Value::Array(arr) => {
1171 let idx = match &index {
1172 Value::Int(i) if *i >= 0 => *i as usize,
1173 Value::Float(f) if *f >= 0.0 && *f == (*f as usize as f64) => {
1174 *f as usize
1175 }
1176 _ => {
1177 self.push(obj)?;
1179 return Ok(None);
1180 }
1181 };
1182 if idx > arr.len() + 1024 {
1184 return Err(ZapcodeError::RuntimeError(format!(
1185 "array index {} too far beyond length {}",
1186 idx,
1187 arr.len()
1188 )));
1189 }
1190 while arr.len() <= idx {
1191 arr.push(Value::Undefined);
1192 }
1193 arr[idx] = value;
1194 }
1195 Value::Object(map) => {
1196 let key: Arc<str> = Arc::from(index.to_js_string().as_str());
1197 map.insert(key, value);
1198 }
1199 _ => {}
1200 }
1201 self.push(obj)?;
1203 }
1204 Instruction::Spread => {
1205 }
1207 Instruction::In => {
1208 let right = self.pop()?;
1209 let left = self.pop()?;
1210 let result = match &right {
1211 Value::Object(map) => {
1212 let key = left.to_js_string();
1213 map.contains_key(key.as_str())
1214 }
1215 Value::Array(arr) => {
1216 if let Value::Int(i) = left {
1217 (i as usize) < arr.len()
1218 } else {
1219 false
1220 }
1221 }
1222 _ => false,
1223 };
1224 self.push(Value::Bool(result))?;
1225 }
1226 Instruction::InstanceOf => {
1227 let right = self.pop()?;
1228 let left = self.pop()?;
1229 let result = match (&left, &right) {
1231 (Value::Object(instance), Value::Object(class_obj)) => {
1232 if let (Some(inst_class), Some(class_name)) =
1233 (instance.get("__class__"), class_obj.get("__class_name__"))
1234 {
1235 inst_class == class_name
1236 } else {
1237 false
1238 }
1239 }
1240 _ => false,
1241 };
1242 self.push(Value::Bool(result))?;
1243 }
1244
1245 Instruction::CreateClosure(func_idx) => {
1247 let mut captured = Vec::new();
1249 for frame in &self.frames {
1251 let local_names = if let Some(fidx) = frame.func_index {
1252 &self.program.functions[fidx].local_names
1253 } else {
1254 &self.program.local_names
1255 };
1256 for (i, val) in frame.locals.iter().enumerate() {
1257 if let Some(name) = local_names.get(i) {
1258 captured.push((name.clone(), val.clone()));
1259 }
1260 }
1261 }
1262 let builtins = ["console", "Math", "JSON", "Object", "Array"];
1264 for (name, val) in &self.globals {
1265 if !builtins.contains(&name.as_str()) {
1266 captured.push((name.clone(), val.clone()));
1267 }
1268 }
1269 let closure = Closure {
1270 func_id: FunctionId(func_idx),
1271 captured,
1272 };
1273 self.push(Value::Function(closure))?;
1274 }
1275 Instruction::Call(arg_count) => {
1276 let mut args = Vec::with_capacity(arg_count);
1277 for _ in 0..arg_count {
1278 args.push(self.pop()?);
1279 }
1280 args.reverse();
1281
1282 let callee = self.pop()?;
1283 match callee {
1284 Value::Function(closure) => {
1285 let func_idx = closure.func_id.0;
1286 let is_generator = self.program.functions[func_idx].is_generator;
1287
1288 if is_generator {
1290 let params = self.program.functions[func_idx].params.clone();
1291 let gen_id = self.alloc_generator_id();
1292 let mut captured = closure.captured.clone();
1294 for (i, param) in params.iter().enumerate() {
1295 match param {
1296 ParamPattern::Ident(name) => {
1297 captured.push((
1298 name.clone(),
1299 args.get(i).cloned().unwrap_or(Value::Undefined),
1300 ));
1301 }
1302 ParamPattern::Rest(name) => {
1303 let rest: Vec<Value> = args[i..].to_vec();
1304 captured.push((name.clone(), Value::Array(rest)));
1305 }
1306 _ => {}
1307 }
1308 }
1309 let gen_obj = GeneratorObject {
1310 id: gen_id,
1311 func_id: closure.func_id,
1312 captured,
1313 suspended: None,
1314 done: false,
1315 };
1316 self.globals.insert(
1318 format!("__gen_{}", gen_id),
1319 Value::Generator(gen_obj.clone()),
1320 );
1321 self.push(Value::Generator(gen_obj))?;
1322 self.last_receiver = None;
1323 self.last_receiver_source = None;
1324 } else {
1325 let this_value = self.last_receiver.take();
1326 self.push_call_frame(&closure, &args, this_value)?;
1327 }
1328 }
1329 Value::BuiltinMethod {
1330 object_name,
1331 method_name,
1332 } => {
1333 let receiver = self.last_receiver.take();
1334 let result = match object_name.as_ref() {
1335 "__array__" => {
1336 if let Some(Value::Array(arr)) = &receiver {
1337 match method_name.as_ref() {
1339 "map" | "filter" | "forEach" | "find" | "findIndex"
1340 | "every" | "some" | "reduce" | "sort" | "flatMap" => {
1341 let result = self.execute_array_callback_method(
1342 arr.clone(),
1343 &method_name,
1344 args,
1345 )?;
1346 Some(result)
1347 }
1348 _ => builtins::call_builtin(
1349 &Value::Array(arr.clone()),
1350 &method_name,
1351 &args,
1352 &mut self.stdout,
1353 )?,
1354 }
1355 } else {
1356 None
1357 }
1358 }
1359 "__string__" => {
1360 if let Some(Value::String(s)) = &receiver {
1361 builtins::call_builtin(
1362 &Value::String(s.clone()),
1363 &method_name,
1364 &args,
1365 &mut self.stdout,
1366 )?
1367 } else {
1368 None
1369 }
1370 }
1371 "__generator__" => {
1372 if let Some(Value::Generator(gen_obj)) = receiver {
1373 match method_name.as_ref() {
1374 "next" => {
1375 let arg =
1376 args.into_iter().next().unwrap_or(Value::Undefined);
1377 let gen_key = format!("__gen_{}", gen_obj.id);
1381 if let Some(Value::Generator(g)) =
1382 self.globals.remove(&gen_key)
1383 {
1384 let result = self.generator_next(g, arg)?;
1385 Some(result)
1386 } else {
1387 Some(
1388 self.make_iterator_result(
1389 Value::Undefined,
1390 true,
1391 ),
1392 )
1393 }
1394 }
1395 "return" => {
1396 let val =
1397 args.into_iter().next().unwrap_or(Value::Undefined);
1398 let gen_key = format!("__gen_{}", gen_obj.id);
1399 if let Some(Value::Generator(g)) =
1400 self.globals.remove(&gen_key)
1401 {
1402 let result = self.finish_generator(g, val);
1403 Some(result)
1404 } else {
1405 Some(self.make_iterator_result(val, true))
1406 }
1407 }
1408 _ => None,
1409 }
1410 } else {
1411 None
1412 }
1413 }
1414 "__promise__" => {
1415 if let Some(promise) = receiver {
1416 self.execute_promise_method(promise, &method_name, args)?
1417 } else {
1418 None
1419 }
1420 }
1421 global_name => builtins::call_global_method(
1422 global_name,
1423 &method_name,
1424 &args,
1425 &mut self.stdout,
1426 )?,
1427 };
1428 match result {
1429 Some(val) => self.push(val)?,
1430 None => {
1431 return Err(ZapcodeError::TypeError(format!(
1432 "{}.{} is not a function",
1433 object_name, method_name
1434 )));
1435 }
1436 }
1437 }
1438 _ => {
1439 return Err(ZapcodeError::TypeError(format!(
1440 "{} is not a function",
1441 callee.to_js_string()
1442 )));
1443 }
1444 }
1445 }
1446 Instruction::Return => {
1447 let return_val = self.pop().unwrap_or(Value::Undefined);
1448
1449 if self.frames.len() <= 1 {
1450 return Ok(Some(VmState::Complete(return_val)));
1451 }
1452
1453 let frame = self.frames.pop().unwrap();
1454 self.tracker.pop_frame();
1455
1456 let actual_return = if let Some(ref this_val) = frame.this_value {
1460 if let Some(parent) = self.frames.last_mut() {
1462 if parent.this_value.is_some() {
1463 parent.this_value = Some(this_val.clone());
1464 }
1465 }
1466 if let Some(ref source) = frame.receiver_source {
1471 match source {
1472 ReceiverSource::Global(name) => {
1473 self.globals.insert(name.clone(), this_val.clone());
1474 }
1475 ReceiverSource::Local { frame_index, slot } => {
1476 if let Some(target_frame) = self.frames.get_mut(*frame_index) {
1477 while target_frame.locals.len() <= *slot {
1478 target_frame.locals.push(Value::Undefined);
1479 }
1480 target_frame.locals[*slot] = this_val.clone();
1481 }
1482 }
1483 }
1484 }
1485 if matches!(return_val, Value::Undefined) {
1486 this_val.clone()
1487 } else {
1488 return_val
1489 }
1490 } else {
1491 return_val
1492 };
1493
1494 self.stack.truncate(frame.stack_base);
1495 self.push(actual_return)?;
1496 }
1497 Instruction::CallExternal(name, arg_count) => {
1498 if !self.external_functions.contains(&name) {
1499 return Err(ZapcodeError::UnknownExternalFunction(name));
1500 }
1501 let mut args = Vec::with_capacity(arg_count);
1502 for _ in 0..arg_count {
1503 args.push(self.pop()?);
1504 }
1505 args.reverse();
1506 let snapshot = ZapcodeSnapshot::capture(self)?;
1508 return Ok(Some(VmState::Suspended {
1509 function_name: name,
1510 args,
1511 snapshot,
1512 }));
1513 }
1514
1515 Instruction::Jump(target) => {
1517 self.current_frame_mut().ip = target;
1518 }
1519 Instruction::JumpIfFalse(target) => {
1520 let val = self.pop()?;
1521 if !val.is_truthy() {
1522 self.current_frame_mut().ip = target;
1523 }
1524 }
1525 Instruction::JumpIfTrue(target) => {
1526 let val = self.pop()?;
1527 if val.is_truthy() {
1528 self.current_frame_mut().ip = target;
1529 }
1530 }
1531 Instruction::JumpIfNullish(target) => {
1532 let val = self.peek()?;
1533 if matches!(val, Value::Null | Value::Undefined) {
1534 self.current_frame_mut().ip = target;
1535 }
1536 }
1537
1538 Instruction::SetupLoop => {}
1540 Instruction::Break | Instruction::Continue => {
1541 }
1543
1544 Instruction::GetIterator => {
1546 let val = self.pop()?;
1547 match val {
1548 Value::Array(arr) => {
1549 let iter_obj = Value::Array(vec![Value::Array(arr), Value::Int(0)]);
1551 self.push(iter_obj)?;
1552 }
1553 Value::String(s) => {
1554 let chars: Vec<Value> = s
1555 .chars()
1556 .map(|c| Value::String(Arc::from(c.to_string().as_str())))
1557 .collect();
1558 let iter_obj = Value::Array(vec![Value::Array(chars), Value::Int(0)]);
1559 self.push(iter_obj)?;
1560 }
1561 Value::Generator(gen_obj) => {
1562 let iter_obj = Value::Array(vec![
1563 Value::String(Arc::from("__gen__")),
1564 Value::Int(gen_obj.id as i64),
1565 Value::Bool(false),
1566 ]);
1567 self.push(iter_obj)?;
1568 }
1569 _ => {
1570 return Err(ZapcodeError::TypeError(format!(
1571 "{} is not iterable",
1572 val.type_name()
1573 )));
1574 }
1575 }
1576 }
1577 Instruction::IteratorNext => {
1578 let iter = self.pop()?;
1579 if let Value::Array(ref items) = iter {
1581 if items.len() == 3 {
1582 if let Value::String(ref s) = items[0] {
1583 if s.as_ref() == "__gen__" {
1584 let gen_id = match &items[1] {
1585 Value::Int(id) => *id as u64,
1586 _ => {
1587 return Err(ZapcodeError::RuntimeError(
1588 "bad gen iter".into(),
1589 ))
1590 }
1591 };
1592 let gen_key = format!("__gen_{}", gen_id);
1593 let gen_obj = if let Some(Value::Generator(g)) =
1594 self.globals.remove(&gen_key)
1595 {
1596 g
1597 } else {
1598 self.push(Value::Array(vec![
1599 Value::String(Arc::from("__gen__")),
1600 Value::Int(gen_id as i64),
1601 Value::Bool(true),
1602 ]))?;
1603 self.push(Value::Undefined)?;
1604 return Ok(None);
1605 };
1606 let result = self.generator_next(gen_obj, Value::Undefined)?;
1607 if let Value::Object(ref obj) = result {
1608 let done = obj
1609 .get("done")
1610 .is_some_and(|v| matches!(v, Value::Bool(true)));
1611 let value =
1612 obj.get("value").cloned().unwrap_or(Value::Undefined);
1613 self.push(Value::Array(vec![
1614 Value::String(Arc::from("__gen__")),
1615 Value::Int(gen_id as i64),
1616 Value::Bool(done),
1617 ]))?;
1618 self.push(value)?;
1619 } else {
1620 self.push(iter)?;
1621 self.push(Value::Undefined)?;
1622 }
1623 return Ok(None);
1624 }
1625 }
1626 }
1627 }
1628 match iter {
1629 Value::Array(ref items) if items.len() == 2 => {
1630 let arr = match &items[0] {
1631 Value::Array(a) => a,
1632 _ => return Err(ZapcodeError::RuntimeError("invalid iterator".into())),
1633 };
1634 let idx = match &items[1] {
1635 Value::Int(i) => *i as usize,
1636 _ => return Err(ZapcodeError::RuntimeError("invalid iterator".into())),
1637 };
1638 if idx < arr.len() {
1639 let value = arr[idx].clone();
1640 let new_iter =
1642 Value::Array(vec![items[0].clone(), Value::Int((idx + 1) as i64)]);
1643 self.push(new_iter)?;
1645 self.push(value)?;
1646 } else {
1647 self.push(iter)?;
1649 self.push(Value::Undefined)?;
1650 }
1651 }
1652 _ => {
1653 return Err(ZapcodeError::RuntimeError("invalid iterator state".into()));
1654 }
1655 }
1656 }
1657 Instruction::IteratorDone => {
1658 let value = self.pop()?;
1659 let iter = self.peek()?;
1660 if let Value::Array(items) = iter {
1662 if items.len() == 3 {
1663 if let Value::String(ref s) = items[0] {
1664 if s.as_ref() == "__gen__" {
1665 let done = matches!(&items[2], Value::Bool(true));
1666 if !done {
1667 self.push(value)?;
1668 }
1669 self.push(Value::Bool(done))?;
1670 return Ok(None);
1671 }
1672 }
1673 }
1674 }
1675 let iter = self.peek()?;
1676 match iter {
1677 Value::Array(items) if items.len() == 2 => {
1678 let arr = match &items[0] {
1679 Value::Array(a) => a,
1680 _ => {
1681 self.push(value)?;
1682 self.push(Value::Bool(true))?;
1683 return Ok(None);
1684 }
1685 };
1686 let idx = match &items[1] {
1687 Value::Int(i) => *i as usize,
1688 _ => {
1689 self.push(value)?;
1690 self.push(Value::Bool(true))?;
1691 return Ok(None);
1692 }
1693 };
1694 let done = idx > arr.len();
1695 if !done {
1696 self.push(value)?;
1698 }
1699 self.push(Value::Bool(done))?;
1700 }
1701 _ => {
1702 self.push(value)?;
1703 self.push(Value::Bool(true))?;
1704 }
1705 }
1706 }
1707
1708 Instruction::SetupTry(catch_ip, _) => {
1710 self.try_stack.push(TryInfo {
1711 catch_ip,
1712 frame_depth: self.frames.len(),
1713 stack_depth: self.stack.len(),
1714 });
1715 }
1716 Instruction::Throw => {
1717 let val = self.pop()?;
1718 let msg = val.to_js_string();
1719 return Err(ZapcodeError::RuntimeError(msg));
1720 }
1721 Instruction::EndTry => {
1722 self.try_stack.pop();
1723 }
1724
1725 Instruction::TypeOf => {
1727 let val = self.pop()?;
1728 let type_str = val.type_name();
1729 self.push(Value::String(Arc::from(type_str)))?;
1730 }
1731
1732 Instruction::Void => {
1734 self.pop()?;
1735 self.push(Value::Undefined)?;
1736 }
1737
1738 Instruction::Increment => {
1740 let val = self.pop()?;
1741 let result = match val {
1742 Value::Int(n) => Value::Int(n + 1),
1743 _ => Value::Float(val.to_number() + 1.0),
1744 };
1745 self.push(result)?;
1746 }
1747 Instruction::Decrement => {
1748 let val = self.pop()?;
1749 let result = match val {
1750 Value::Int(n) => Value::Int(n - 1),
1751 _ => Value::Float(val.to_number() - 1.0),
1752 };
1753 self.push(result)?;
1754 }
1755
1756 Instruction::ConcatStrings(count) => {
1758 let mut parts = Vec::with_capacity(count);
1759 for _ in 0..count {
1760 parts.push(self.pop()?);
1761 }
1762 parts.reverse();
1763 let result: String = parts.iter().map(|v| v.to_js_string()).collect();
1764 self.push(Value::String(Arc::from(result.as_str())))?;
1765 }
1766
1767 Instruction::DestructureObject(keys) => {
1769 let obj = self.pop()?;
1770 for key in keys {
1771 let val = self.get_property(&obj, &key)?;
1772 self.push(val)?;
1773 }
1774 }
1775 Instruction::DestructureArray(count) => {
1776 let arr = self.pop()?;
1777 match arr {
1778 Value::Array(items) => {
1779 for i in 0..count {
1780 self.push(items.get(i).cloned().unwrap_or(Value::Undefined))?;
1781 }
1782 }
1783 _ => {
1784 for _ in 0..count {
1785 self.push(Value::Undefined)?;
1786 }
1787 }
1788 }
1789 }
1790
1791 Instruction::Nop => {}
1792
1793 Instruction::CreateGenerator(_func_idx) => {
1795 }
1797 Instruction::Yield => {
1798 return Err(ZapcodeError::RuntimeError(
1801 "yield can only be used inside a generator function".to_string(),
1802 ));
1803 }
1804
1805 Instruction::Await => {
1806 let val = self.pop()?;
1810 if builtins::is_promise(&val) {
1811 if let Value::Object(map) = &val {
1812 let status = map.get("status").cloned().unwrap_or(Value::Undefined);
1813 match status {
1814 Value::String(s) if s.as_ref() == "resolved" => {
1815 let inner = map.get("value").cloned().unwrap_or(Value::Undefined);
1816 self.push(inner)?;
1817 }
1818 Value::String(s) if s.as_ref() == "rejected" => {
1819 let reason = map.get("reason").cloned().unwrap_or(Value::Undefined);
1820 return Err(ZapcodeError::RuntimeError(format!(
1821 "Unhandled promise rejection: {}",
1822 reason.to_js_string()
1823 )));
1824 }
1825 _ => {
1826 self.push(val)?;
1828 }
1829 }
1830 } else {
1831 self.push(val)?;
1832 }
1833 } else {
1834 self.push(val)?;
1836 }
1837 }
1838
1839 Instruction::CreateClass {
1841 name,
1842 n_methods,
1843 n_statics,
1844 has_super,
1845 } => {
1846 let constructor = self.pop()?;
1853
1854 let mut prototype = IndexMap::new();
1856 for _ in 0..n_methods {
1857 let method_closure = self.pop()?;
1858 let method_name = self.pop()?;
1859 if let Value::String(mn) = method_name {
1860 prototype.insert(mn, method_closure);
1861 }
1862 }
1863
1864 let mut statics = IndexMap::new();
1866 for _ in 0..n_statics {
1867 let method_closure = self.pop()?;
1868 let method_name = self.pop()?;
1869 if let Value::String(mn) = method_name {
1870 statics.insert(mn, method_closure);
1871 }
1872 }
1873
1874 let super_class = if has_super { Some(self.pop()?) } else { None };
1876
1877 if let Some(Value::Object(ref sc)) = super_class {
1879 if let Some(Value::Object(super_proto)) = sc.get("__prototype__").cloned() {
1880 let mut merged = super_proto;
1882 for (k, v) in prototype {
1883 merged.insert(k, v);
1884 }
1885 prototype = merged;
1886 }
1887 }
1888
1889 let mut class_obj = IndexMap::new();
1891 class_obj.insert(
1892 Arc::from("__class_name__"),
1893 Value::String(Arc::from(name.as_str())),
1894 );
1895 class_obj.insert(Arc::from("__constructor__"), constructor);
1896 class_obj.insert(Arc::from("__prototype__"), Value::Object(prototype));
1897
1898 if let Some(sc) = super_class {
1900 class_obj.insert(Arc::from("__super__"), sc);
1901 }
1902
1903 for (k, v) in statics {
1905 class_obj.insert(k, v);
1906 }
1907
1908 self.push(Value::Object(class_obj))?;
1909 }
1910
1911 Instruction::Construct(arg_count) => {
1912 let mut args = Vec::with_capacity(arg_count);
1913 for _ in 0..arg_count {
1914 args.push(self.pop()?);
1915 }
1916 args.reverse();
1917
1918 let callee = self.pop()?;
1919
1920 match &callee {
1921 Value::Object(class_obj) if class_obj.contains_key("__class_name__") => {
1922 let mut instance = IndexMap::new();
1924
1925 if let Some(Value::Object(proto)) = class_obj.get("__prototype__") {
1927 for (k, v) in proto {
1928 instance.insert(k.clone(), v.clone());
1929 }
1930 }
1931
1932 if let Some(class_name) = class_obj.get("__class_name__") {
1934 instance.insert(Arc::from("__class__"), class_name.clone());
1935 }
1936
1937 let instance_val = Value::Object(instance);
1938
1939 if let Some(ctor) = class_obj.get("__constructor__") {
1941 if let Value::Function(closure) = ctor {
1942 self.last_receiver_source = None;
1945 self.push_call_frame(closure, &args, Some(instance_val))?;
1946 self.last_receiver = None;
1947 } else {
1948 self.push(instance_val)?;
1950 }
1951 } else {
1952 self.push(instance_val)?;
1954 }
1955 }
1956 Value::Function(closure) => {
1957 self.push_call_frame(closure, &args, None)?;
1959 self.last_receiver = None;
1960 }
1961 _ => {
1962 return Err(ZapcodeError::TypeError(format!(
1963 "{} is not a constructor",
1964 callee.to_js_string()
1965 )));
1966 }
1967 }
1968 }
1969
1970 Instruction::LoadThis => {
1971 let this_val = self
1973 .frames
1974 .iter()
1975 .rev()
1976 .find_map(|f| f.this_value.clone())
1977 .unwrap_or(Value::Undefined);
1978 self.push(this_val)?;
1979 }
1980 Instruction::StoreThis => {
1981 let val = self.pop()?;
1982 for frame in self.frames.iter_mut().rev() {
1984 if frame.this_value.is_some() {
1985 frame.this_value = Some(val);
1986 break;
1987 }
1988 }
1989 }
1990 Instruction::CallSuper(arg_count) => {
1991 let mut args = Vec::with_capacity(arg_count);
1992 for _ in 0..arg_count {
1993 args.push(self.pop()?);
1994 }
1995 args.reverse();
1996
1997 let this_val = self
1999 .frames
2000 .iter()
2001 .rev()
2002 .find_map(|f| f.this_value.clone())
2003 .unwrap_or(Value::Undefined);
2004
2005 let mut super_ctor = None;
2010 for val in self.globals.values() {
2011 if let Value::Object(obj) = val {
2012 if let Some(Value::Object(super_class)) = obj.get("__super__") {
2013 if let Some(ctor) = super_class.get("__constructor__") {
2014 super_ctor = Some(ctor.clone());
2015 break;
2016 }
2017 }
2018 }
2019 }
2020
2021 if let Some(Value::Function(closure)) = super_ctor {
2022 self.last_receiver_source = None;
2023 self.push_call_frame(&closure, &args, Some(this_val))?;
2024 self.last_receiver = None;
2025 } else {
2026 self.push(Value::Undefined)?;
2028 }
2029 }
2030 }
2031
2032 Ok(None)
2033 }
2034
2035 fn get_property(&self, obj: &Value, name: &str) -> Result<Value> {
2036 if matches!(obj, Value::Null | Value::Undefined) {
2038 return Err(ZapcodeError::TypeError(format!(
2039 "Cannot read properties of {} (reading '{}')",
2040 obj.to_js_string(),
2041 name
2042 )));
2043 }
2044 match obj {
2045 Value::Object(map) => {
2046 if let Some(val) = map.get(name) {
2048 if !matches!(val, Value::Undefined) {
2049 return Ok(val.clone());
2050 }
2051 }
2052 if builtins::is_promise(obj) && is_promise_method(name) {
2054 return Ok(Value::BuiltinMethod {
2055 object_name: Arc::from("__promise__"),
2056 method_name: Arc::from(name),
2057 });
2058 }
2059 if let Some(global_name) = &self.last_global_name {
2061 let known_globals = ["console", "Math", "JSON", "Object", "Array", "Promise"];
2062 if known_globals.contains(&global_name.as_str()) {
2063 return Ok(Value::BuiltinMethod {
2064 object_name: Arc::from(global_name.as_str()),
2065 method_name: Arc::from(name),
2066 });
2067 }
2068 }
2069 Ok(Value::Undefined)
2070 }
2071 Value::Array(arr) => match name {
2072 "length" => Ok(Value::Int(arr.len() as i64)),
2073 _ if is_array_method(name) => Ok(Value::BuiltinMethod {
2074 object_name: Arc::from("__array__"),
2075 method_name: Arc::from(name),
2076 }),
2077 _ => {
2078 if let Ok(idx) = name.parse::<usize>() {
2079 Ok(arr.get(idx).cloned().unwrap_or(Value::Undefined))
2080 } else {
2081 Ok(Value::Undefined)
2082 }
2083 }
2084 },
2085 Value::String(s) => match name {
2086 "length" => Ok(Value::Int(s.chars().count() as i64)),
2087 _ if is_string_method(name) => Ok(Value::BuiltinMethod {
2088 object_name: Arc::from("__string__"),
2089 method_name: Arc::from(name),
2090 }),
2091 _ => Ok(Value::Undefined),
2092 },
2093 Value::Generator(_) => match name {
2094 "next" | "return" | "throw" => Ok(Value::BuiltinMethod {
2095 object_name: Arc::from("__generator__"),
2096 method_name: Arc::from(name),
2097 }),
2098 _ => Ok(Value::Undefined),
2099 },
2100 _ => Ok(Value::Undefined),
2101 }
2102 }
2103}
2104
2105use crate::parser::ir::ParamPattern;
2107
2108fn is_array_method(name: &str) -> bool {
2109 matches!(
2110 name,
2111 "push"
2112 | "pop"
2113 | "shift"
2114 | "unshift"
2115 | "splice"
2116 | "slice"
2117 | "concat"
2118 | "join"
2119 | "reverse"
2120 | "sort"
2121 | "indexOf"
2122 | "lastIndexOf"
2123 | "includes"
2124 | "find"
2125 | "findIndex"
2126 | "map"
2127 | "filter"
2128 | "reduce"
2129 | "forEach"
2130 | "every"
2131 | "some"
2132 | "flat"
2133 | "flatMap"
2134 | "fill"
2135 | "at"
2136 | "entries"
2137 | "keys"
2138 | "values"
2139 )
2140}
2141
2142fn is_string_method(name: &str) -> bool {
2143 matches!(
2144 name,
2145 "charAt"
2146 | "charCodeAt"
2147 | "indexOf"
2148 | "lastIndexOf"
2149 | "includes"
2150 | "startsWith"
2151 | "endsWith"
2152 | "slice"
2153 | "substring"
2154 | "substr"
2155 | "toUpperCase"
2156 | "toLowerCase"
2157 | "trim"
2158 | "trimStart"
2159 | "trimEnd"
2160 | "trimLeft"
2161 | "trimRight"
2162 | "padStart"
2163 | "padEnd"
2164 | "repeat"
2165 | "replace"
2166 | "replaceAll"
2167 | "split"
2168 | "concat"
2169 | "at"
2170 | "match"
2171 | "search"
2172 | "normalize"
2173 )
2174}
2175
2176fn is_promise_method(name: &str) -> bool {
2177 matches!(name, "then" | "catch" | "finally")
2178}
2179
2180pub struct ZapcodeRun {
2182 source: String,
2183 #[allow(dead_code)]
2184 inputs: Vec<String>,
2185 external_functions: Vec<String>,
2186 limits: ResourceLimits,
2187}
2188
2189impl ZapcodeRun {
2190 pub fn new(
2191 source: String,
2192 inputs: Vec<String>,
2193 external_functions: Vec<String>,
2194 limits: ResourceLimits,
2195 ) -> Result<Self> {
2196 Ok(Self {
2197 source,
2198 inputs,
2199 external_functions,
2200 limits,
2201 })
2202 }
2203
2204 pub fn run(&self, input_values: Vec<(String, Value)>) -> Result<RunResult> {
2205 let mut root_span = SpanBuilder::new("zapcode.run");
2206
2207 let parse_span = SpanBuilder::new("parse");
2209 let program = match crate::parser::parse(&self.source) {
2210 Ok(p) => {
2211 root_span.add_child(parse_span.finish_ok());
2212 p
2213 }
2214 Err(e) => {
2215 root_span.add_child(parse_span.finish_error(&e.to_string()));
2216 let _trace = ExecutionTrace {
2217 root: root_span.finish(TraceStatus::Error),
2218 };
2219 return Err(e);
2220 }
2221 };
2222
2223 let compile_span = SpanBuilder::new("compile");
2225 let ext_set: HashSet<String> = self.external_functions.iter().cloned().collect();
2226 let compiled = match crate::compiler::compile_with_externals(&program, ext_set.clone()) {
2227 Ok(c) => {
2228 root_span.add_child(compile_span.finish_ok());
2229 c
2230 }
2231 Err(e) => {
2232 root_span.add_child(compile_span.finish_error(&e.to_string()));
2233 let _trace = ExecutionTrace {
2234 root: root_span.finish(TraceStatus::Error),
2235 };
2236 return Err(e);
2237 }
2238 };
2239
2240 let execute_span = SpanBuilder::new("execute");
2242 let mut vm = Vm::new(compiled, self.limits.clone(), ext_set);
2243
2244 for (name, value) in input_values {
2245 vm.globals.insert(name, value);
2246 }
2247
2248 let state = match vm.run() {
2249 Ok(s) => {
2250 let status = match &s {
2251 VmState::Complete(_) => TraceStatus::Ok,
2252 VmState::Suspended {
2253 function_name,
2254 args,
2255 ..
2256 } => {
2257 let mut span = execute_span;
2258 span.set_attr("zapcode.suspended_on", function_name);
2259 span.set_attr("zapcode.args_count", args.len());
2260 root_span.add_child(span.finish(TraceStatus::Ok));
2261 let trace = ExecutionTrace {
2262 root: root_span.finish_ok(),
2263 };
2264 return Ok(RunResult {
2265 state: s,
2266 stdout: vm.stdout,
2267 trace,
2268 });
2269 }
2270 };
2271 root_span.add_child(execute_span.finish(status));
2272 s
2273 }
2274 Err(e) => {
2275 root_span.add_child(execute_span.finish_error(&e.to_string()));
2276 let _trace = ExecutionTrace {
2277 root: root_span.finish(TraceStatus::Error),
2278 };
2279 return Err(e);
2280 }
2281 };
2282
2283 let trace = ExecutionTrace {
2284 root: root_span.finish_ok(),
2285 };
2286
2287 Ok(RunResult {
2288 state,
2289 stdout: vm.stdout,
2290 trace,
2291 })
2292 }
2293
2294 pub fn start(&self, input_values: Vec<(String, Value)>) -> Result<VmState> {
2298 let result = self.run(input_values)?;
2299 Ok(result.state)
2300 }
2301
2302 pub fn run_simple(&self) -> Result<Value> {
2303 let result = self.run(Vec::new())?;
2304 match result.state {
2305 VmState::Complete(v) => Ok(v),
2306 VmState::Suspended { function_name, .. } => Err(ZapcodeError::RuntimeError(format!(
2307 "execution suspended on external function '{}' — use run() instead",
2308 function_name
2309 ))),
2310 }
2311 }
2312}
2313
2314pub struct RunResult {
2316 pub state: VmState,
2317 pub stdout: String,
2318 pub trace: ExecutionTrace,
2320}
2321
2322pub fn eval_ts(source: &str) -> Result<Value> {
2324 let runner = ZapcodeRun::new(
2325 source.to_string(),
2326 Vec::new(),
2327 Vec::new(),
2328 ResourceLimits::default(),
2329 )?;
2330 runner.run_simple()
2331}
2332
2333pub fn eval_ts_with_output(source: &str) -> Result<(Value, String)> {
2335 let runner = ZapcodeRun::new(
2336 source.to_string(),
2337 Vec::new(),
2338 Vec::new(),
2339 ResourceLimits::default(),
2340 )?;
2341 let result = runner.run(Vec::new())?;
2342 match result.state {
2343 VmState::Complete(v) => Ok((v, result.stdout)),
2344 VmState::Suspended { function_name, .. } => Err(ZapcodeError::RuntimeError(format!(
2345 "execution suspended on external function '{}'",
2346 function_name
2347 ))),
2348 }
2349}