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
51#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
55pub(crate) enum Continuation {
56 ArrayMap {
58 callback: Value,
59 source: Vec<Value>,
60 results: Vec<Value>,
61 next_index: usize,
62 caller_frame_depth: usize,
65 callback_frame_index: usize,
68 },
69 ArrayForEach {
71 callback: Value,
72 source: Vec<Value>,
73 next_index: usize,
74 caller_frame_depth: usize,
75 callback_frame_index: usize,
76 },
77}
78
79pub struct Vm {
81 pub(crate) program: CompiledProgram,
82 pub(crate) stack: Vec<Value>,
83 pub(crate) frames: Vec<CallFrame>,
84 pub(crate) globals: HashMap<String, Value>,
85 pub(crate) stdout: String,
86 pub(crate) limits: ResourceLimits,
87 pub(crate) tracker: ResourceTracker,
88 pub(crate) external_functions: HashSet<String>,
89 pub(crate) try_stack: Vec<TryInfo>,
90 pub(crate) continuations: Vec<Continuation>,
92 last_receiver: Option<Value>,
94 last_receiver_source: Option<ReceiverSource>,
96 last_global_name: Option<String>,
98 last_load_source: Option<ReceiverSource>,
100 next_generator_id: u64,
102}
103
104#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
105pub(crate) struct TryInfo {
106 pub(crate) catch_ip: usize,
107 pub(crate) frame_depth: usize,
108 pub(crate) stack_depth: usize,
109}
110
111impl Vm {
112 fn new(
113 program: CompiledProgram,
114 limits: ResourceLimits,
115 external_functions: HashSet<String>,
116 ) -> Self {
117 let mut globals = HashMap::new();
118
119 builtins::register_globals(&mut globals);
121
122 Self {
123 program,
124 stack: Vec::new(),
125 frames: Vec::new(),
126 globals,
127 stdout: String::new(),
128 limits,
129 tracker: ResourceTracker::default(),
130 external_functions,
131 try_stack: Vec::new(),
132 continuations: Vec::new(),
133 last_receiver: None,
134 last_receiver_source: None,
135 last_global_name: None,
136 last_load_source: None,
137 next_generator_id: 0,
138 }
139 }
140
141 pub(crate) const BUILTIN_GLOBAL_NAMES: &'static [&'static str] =
143 &["console", "JSON", "Object", "Array", "Math", "Promise"];
144
145 #[allow(clippy::too_many_arguments)]
149 pub(crate) fn from_snapshot(
150 program: CompiledProgram,
151 stack: Vec<Value>,
152 frames: Vec<CallFrame>,
153 user_globals: HashMap<String, Value>,
154 try_stack: Vec<TryInfo>,
155 continuations: Vec<Continuation>,
156 stdout: String,
157 limits: ResourceLimits,
158 external_functions: HashSet<String>,
159 ) -> Self {
160 let mut globals = HashMap::new();
161 builtins::register_globals(&mut globals);
163 for (k, v) in user_globals {
165 globals.insert(k, v);
166 }
167
168 Self {
169 program,
170 stack,
171 frames,
172 globals,
173 stdout,
174 limits,
175 tracker: ResourceTracker::default(),
176 external_functions,
177 try_stack,
178 continuations,
179 last_receiver: None,
180 last_receiver_source: None,
181 last_global_name: None,
182 last_load_source: None,
183 next_generator_id: 0,
184 }
185 }
186
187 pub(crate) fn resume_execution(&mut self) -> Result<VmState> {
190 self.tracker.start();
191 self.execute()
192 }
193
194 fn push(&mut self, value: Value) -> Result<()> {
195 self.tracker.track_allocation(&self.limits)?;
196 self.stack.push(value);
197 Ok(())
198 }
199
200 fn pop(&mut self) -> Result<Value> {
201 self.stack
202 .pop()
203 .ok_or_else(|| ZapcodeError::RuntimeError("stack underflow".to_string()))
204 }
205
206 fn peek(&self) -> Result<&Value> {
207 self.stack
208 .last()
209 .ok_or_else(|| ZapcodeError::RuntimeError("stack underflow".to_string()))
210 }
211
212 fn current_frame(&self) -> &CallFrame {
213 self.frames.last().expect("internal error: no active frame")
216 }
217
218 fn current_frame_mut(&mut self) -> &mut CallFrame {
219 self.frames
220 .last_mut()
221 .expect("internal error: no active frame")
222 }
223
224 #[allow(dead_code)]
225 fn instructions(&self) -> &[Instruction] {
226 match self.current_frame().func_index {
227 Some(idx) => &self.program.functions[idx].instructions,
228 None => &self.program.instructions,
229 }
230 }
231
232 fn bind_params(params: &[ParamPattern], args: &[Value], local_count: usize) -> Vec<Value> {
235 let mut locals = Vec::with_capacity(local_count);
236 for (i, param) in params.iter().enumerate() {
237 match param {
238 ParamPattern::Ident(_) => {
239 locals.push(args.get(i).cloned().unwrap_or(Value::Undefined));
240 }
241 ParamPattern::Rest(_) => {
242 let rest: Vec<Value> = args[i..].to_vec();
243 locals.push(Value::Array(rest));
244 }
245 ParamPattern::DefaultValue { .. } => {
246 let val = args.get(i).cloned().unwrap_or(Value::Undefined);
247 locals.push(val);
249 }
250 _ => {
251 locals.push(args.get(i).cloned().unwrap_or(Value::Undefined));
252 }
253 }
254 }
255 locals
256 }
257
258 fn push_call_frame(
260 &mut self,
261 closure: &Closure,
262 args: &[Value],
263 this_value: Option<Value>,
264 ) -> Result<()> {
265 self.tracker.push_frame();
266 self.tracker.check_stack(&self.limits)?;
267
268 for (name, val) in &closure.captured {
270 if !self.globals.contains_key(name) {
271 self.globals.insert(name.clone(), val.clone());
272 }
273 }
274
275 let func = &self.program.functions[closure.func_id.0];
276 let locals = Self::bind_params(&func.params, args, func.local_count);
277
278 let receiver_source = if this_value.is_some() {
281 self.last_receiver_source.take()
282 } else {
283 self.last_receiver_source = None;
284 None
285 };
286
287 self.frames.push(CallFrame {
288 func_index: Some(closure.func_id.0),
289 ip: 0,
290 locals,
291 stack_base: self.stack.len(),
292 this_value,
293 receiver_source,
294 });
295 Ok(())
296 }
297
298 fn run(&mut self) -> Result<VmState> {
299 self.tracker.start();
300
301 self.frames.push(CallFrame {
303 func_index: None,
304 ip: 0,
305 locals: Vec::new(),
306 stack_base: 0,
307 this_value: None,
308 receiver_source: None,
309 });
310
311 self.execute()
312 }
313
314 fn execute(&mut self) -> Result<VmState> {
315 loop {
316 self.tracker.check_time(&self.limits)?;
318
319 let frame = self.frames.last().unwrap();
320 let instructions = match frame.func_index {
321 Some(idx) => &self.program.functions[idx].instructions,
322 None => &self.program.instructions,
323 };
324
325 if frame.ip >= instructions.len() {
326 if self.frames.len() <= 1 {
328 let result = if self.stack.is_empty() {
330 Value::Undefined
331 } else {
332 self.stack.pop().unwrap_or(Value::Undefined)
333 };
334 return Ok(VmState::Complete(result));
335 } else {
336 let frame = self.frames.pop().unwrap();
338 self.tracker.pop_frame();
339 if let Some(this_val) = frame.this_value {
341 self.stack.truncate(frame.stack_base);
342 self.push(this_val)?;
343 } else {
344 self.push(Value::Undefined)?;
345 }
346 self.process_continuation()?;
348 continue;
349 }
350 }
351
352 let instr = instructions[frame.ip].clone();
353 let result = self.dispatch(instr);
354
355 match result {
356 Ok(Some(state)) => return Ok(state),
357 Ok(None) => {
358 if self.process_continuation()? {
361 continue;
362 }
363 }
364 Err(err) => {
365 if let Some(try_info) = self.try_stack.pop() {
367 while self.frames.len() > try_info.frame_depth {
369 self.frames.pop();
370 self.tracker.pop_frame();
371 }
372 self.stack.truncate(try_info.stack_depth);
373
374 let error_val = Value::String(Arc::from(err.to_string()));
376 self.push(error_val)?;
377
378 self.current_frame_mut().ip = try_info.catch_ip;
380 } else {
381 return Err(err);
382 }
383 }
384 }
385 }
386 }
387
388 fn process_continuation(&mut self) -> Result<bool> {
392 let cont = match self.continuations.last() {
393 Some(c) => c,
394 None => return Ok(false),
395 };
396
397 let (callback_frame_index, caller_frame_depth) = match cont {
401 Continuation::ArrayMap {
402 callback_frame_index,
403 caller_frame_depth,
404 ..
405 } => (*callback_frame_index, *caller_frame_depth),
406 Continuation::ArrayForEach {
407 callback_frame_index,
408 caller_frame_depth,
409 ..
410 } => (*callback_frame_index, *caller_frame_depth),
411 };
412
413 if self.frames.len() > callback_frame_index {
415 return Ok(false);
416 }
417
418 if self.frames.len() != caller_frame_depth {
421 return Ok(false);
422 }
423
424 let callback_result = self.pop()?;
428
429 let callback_result = if let Value::Object(ref map) = callback_result {
433 if !matches!(map.get("__promise__"), Some(Value::Bool(true))) {
434 callback_result
436 } else {
437 match map.get("status") {
438 Some(Value::String(s)) if s.as_ref() == "resolved" => {
439 map.get("value").cloned().unwrap_or(Value::Undefined)
440 }
441 Some(Value::String(s)) if s.as_ref() == "rejected" => {
442 let reason = map.get("reason").cloned().unwrap_or(Value::Undefined);
443 self.continuations.pop();
445 return Err(ZapcodeError::RuntimeError(format!(
446 "Unhandled promise rejection: {}",
447 reason.to_js_string()
448 )));
449 }
450 _ => callback_result,
451 }
452 }
453 } else {
454 callback_result
455 };
456
457 let cont = self.continuations.pop().unwrap();
459
460 match cont {
461 Continuation::ArrayMap {
462 callback,
463 source,
464 mut results,
465 next_index,
466 caller_frame_depth,
467 ..
468 } => {
469 results.push(callback_result);
470 let next = next_index + 1;
471
472 if next < source.len() {
473 let item = source[next].clone();
475 let closure = match &callback {
476 Value::Function(c) => c.clone(),
477 _ => unreachable!("callback validated at start"),
478 };
479 self.push_call_frame(&closure, &[item, Value::Int(next as i64)], None)?;
480 let new_frame_index = self.frames.len() - 1;
481 self.continuations.push(Continuation::ArrayMap {
483 callback,
484 source,
485 results,
486 next_index: next,
487 caller_frame_depth,
488 callback_frame_index: new_frame_index,
489 });
490 Ok(true)
491 } else {
492 self.push(Value::Array(results))?;
494 Ok(true)
495 }
496 }
497 Continuation::ArrayForEach {
498 callback,
499 source,
500 next_index,
501 caller_frame_depth,
502 ..
503 } => {
504 let next = next_index + 1;
505
506 if next < source.len() {
507 let item = source[next].clone();
508 let closure = match &callback {
509 Value::Function(c) => c.clone(),
510 _ => unreachable!("callback validated at start"),
511 };
512 self.push_call_frame(&closure, &[item, Value::Int(next as i64)], None)?;
513 let new_frame_index = self.frames.len() - 1;
514 self.continuations.push(Continuation::ArrayForEach {
515 callback,
516 source,
517 next_index: next,
518 caller_frame_depth,
519 callback_frame_index: new_frame_index,
520 });
521 Ok(true)
522 } else {
523 self.push(Value::Undefined)?;
524 Ok(true)
525 }
526 }
527 }
528 }
529
530 fn call_function_internal(&mut self, callee: &Value, args: Vec<Value>) -> Result<Value> {
533 let closure = match callee {
534 Value::Function(c) => c.clone(),
535 other => {
536 return Err(ZapcodeError::TypeError(format!(
537 "{} is not a function",
538 other.to_js_string()
539 )));
540 }
541 };
542
543 let target_frame_depth = self.frames.len();
544 self.push_call_frame(&closure, &args, None)?;
545
546 loop {
548 self.tracker.check_time(&self.limits)?;
549
550 let frame = self.frames.last().unwrap();
551 let instructions = match frame.func_index {
552 Some(idx) => &self.program.functions[idx].instructions,
553 None => &self.program.instructions,
554 };
555
556 if frame.ip >= instructions.len() {
557 if self.frames.len() > target_frame_depth + 1 {
559 self.frames.pop();
561 self.tracker.pop_frame();
562 self.push(Value::Undefined)?;
563 continue;
564 } else {
565 self.frames.pop();
567 self.tracker.pop_frame();
568 return Ok(Value::Undefined);
569 }
570 }
571
572 let instr = instructions[frame.ip].clone();
573 let result = self.dispatch(instr);
574
575 match result {
576 Ok(Some(VmState::Complete(val))) => {
577 return Ok(val);
580 }
581 Ok(Some(VmState::Suspended { .. })) => {
582 return Err(ZapcodeError::RuntimeError(
583 "cannot suspend inside array callback".to_string(),
584 ));
585 }
586 Ok(None) => {
587 if self.frames.len() == target_frame_depth {
589 return Ok(self.pop().unwrap_or(Value::Undefined));
591 }
592 }
593 Err(err) => {
594 if let Some(try_info) = self.try_stack.pop() {
596 while self.frames.len() > try_info.frame_depth {
597 self.frames.pop();
598 self.tracker.pop_frame();
599 }
600 self.stack.truncate(try_info.stack_depth);
601 let error_val = Value::String(Arc::from(err.to_string()));
602 self.push(error_val)?;
603 self.current_frame_mut().ip = try_info.catch_ip;
604 } else {
605 return Err(err);
606 }
607 }
608 }
609 }
610 }
611
612 fn call_element_callback(
616 &mut self,
617 callback: &Value,
618 item: &Value,
619 index: usize,
620 ) -> Result<Value> {
621 self.call_function_internal(callback, vec![item.clone(), Value::Int(index as i64)])
622 }
623
624 fn is_async_callback(&self, callback: &Value) -> bool {
626 if let Value::Function(closure) = callback {
627 if let Some(func) = self.program.functions.get(closure.func_id.0) {
628 return func.is_async;
629 }
630 }
631 false
632 }
633
634 fn start_continuation_map(
638 &mut self,
639 callback: Value,
640 arr: Vec<Value>,
641 ) -> Result<Option<Value>> {
642 if arr.is_empty() {
643 return Ok(Some(Value::Array(Vec::new())));
644 }
645
646 let closure = match &callback {
648 Value::Function(c) => c.clone(),
649 _ => {
650 return Err(ZapcodeError::TypeError(
651 "map callback is not a function".to_string(),
652 ))
653 }
654 };
655
656 let caller_frame_depth = self.frames.len();
657 let first_item = arr[0].clone();
658
659 self.push_call_frame(&closure, &[first_item, Value::Int(0)], None)?;
660 let callback_frame_index = self.frames.len() - 1;
661
662 self.continuations.push(Continuation::ArrayMap {
663 callback,
664 source: arr,
665 results: Vec::new(),
666 next_index: 0,
667 caller_frame_depth,
668 callback_frame_index,
669 });
670
671 Ok(None) }
673
674 fn start_continuation_foreach(
676 &mut self,
677 callback: Value,
678 arr: Vec<Value>,
679 ) -> Result<Option<Value>> {
680 if arr.is_empty() {
681 return Ok(Some(Value::Undefined));
682 }
683
684 let closure = match &callback {
686 Value::Function(c) => c.clone(),
687 _ => {
688 return Err(ZapcodeError::TypeError(
689 "forEach callback is not a function".to_string(),
690 ))
691 }
692 };
693
694 let caller_frame_depth = self.frames.len();
695 let first_item = arr[0].clone();
696
697 self.push_call_frame(&closure, &[first_item, Value::Int(0)], None)?;
698 let callback_frame_index = self.frames.len() - 1;
699
700 self.continuations.push(Continuation::ArrayForEach {
701 callback,
702 source: arr,
703 next_index: 0,
704 caller_frame_depth,
705 callback_frame_index,
706 });
707
708 Ok(None)
709 }
710
711 fn execute_array_callback_method(
715 &mut self,
716 arr: Vec<Value>,
717 method: &str,
718 all_args: Vec<Value>,
719 ) -> Result<Option<Value>> {
720 let callback = all_args.first().cloned().unwrap_or(Value::Undefined);
721
722 match method {
723 "map" => {
724 if self.is_async_callback(&callback) {
726 return self.start_continuation_map(callback, arr);
727 }
728 let mut result = Vec::with_capacity(arr.len());
729 for (i, item) in arr.iter().enumerate() {
730 result.push(self.call_element_callback(&callback, item, i)?);
731 }
732 Ok(Some(Value::Array(result)))
733 }
734 "filter" | "find" | "findIndex" | "every" | "some" | "reduce" | "sort" | "flatMap" => {
735 if self.is_async_callback(&callback) {
737 return Err(ZapcodeError::RuntimeError(format!(
738 ".{}() does not support async callbacks — use .map() or a for-of loop instead",
739 method
740 )));
741 }
742 match method {
743 "filter" => {
744 let mut result = Vec::new();
745 for (i, item) in arr.iter().enumerate() {
746 if self.call_element_callback(&callback, item, i)?.is_truthy() {
747 result.push(item.clone());
748 }
749 }
750 Ok(Some(Value::Array(result)))
751 }
752 "find" => {
753 for (i, item) in arr.iter().enumerate() {
754 if self.call_element_callback(&callback, item, i)?.is_truthy() {
755 return Ok(Some(item.clone()));
756 }
757 }
758 Ok(Some(Value::Undefined))
759 }
760 "findIndex" => {
761 for (i, item) in arr.iter().enumerate() {
762 if self.call_element_callback(&callback, item, i)?.is_truthy() {
763 return Ok(Some(Value::Int(i as i64)));
764 }
765 }
766 Ok(Some(Value::Int(-1)))
767 }
768 "every" => {
769 for (i, item) in arr.iter().enumerate() {
770 if !self.call_element_callback(&callback, item, i)?.is_truthy() {
771 return Ok(Some(Value::Bool(false)));
772 }
773 }
774 Ok(Some(Value::Bool(true)))
775 }
776 "some" => {
777 for (i, item) in arr.iter().enumerate() {
778 if self.call_element_callback(&callback, item, i)?.is_truthy() {
779 return Ok(Some(Value::Bool(true)));
780 }
781 }
782 Ok(Some(Value::Bool(false)))
783 }
784 "reduce" => {
785 let mut acc = match all_args.get(1).cloned() {
786 Some(init) => Some(init),
787 None if !arr.is_empty() => Some(arr[0].clone()),
788 None => {
789 return Err(ZapcodeError::TypeError(
790 "Reduce of empty array with no initial value".to_string(),
791 ));
792 }
793 };
794 let start = if all_args.get(1).is_some() { 0 } else { 1 };
795 for (i, item) in arr.iter().enumerate().skip(start) {
796 acc = Some(self.call_function_internal(
797 &callback,
798 vec![acc.unwrap(), item.clone(), Value::Int(i as i64)],
799 )?);
800 }
801 Ok(Some(acc.unwrap_or(Value::Undefined)))
802 }
803 "sort" => {
804 let mut result = arr;
805 if matches!(callback, Value::Function(_)) {
806 let len = result.len();
807 for i in 1..len {
808 let mut j = i;
809 while j > 0 {
810 let cmp = self
811 .call_function_internal(
812 &callback,
813 vec![result[j - 1].clone(), result[j].clone()],
814 )?
815 .to_number();
816 if cmp > 0.0 {
817 result.swap(j - 1, j);
818 j -= 1;
819 } else {
820 break;
821 }
822 }
823 }
824 } else {
825 result.sort_by_key(|a| a.to_js_string());
826 }
827 Ok(Some(Value::Array(result)))
828 }
829 "flatMap" => {
830 let mut result = Vec::new();
831 for (i, item) in arr.iter().enumerate() {
832 match self.call_element_callback(&callback, item, i)? {
833 Value::Array(inner) => result.extend(inner),
834 other => result.push(other),
835 }
836 }
837 Ok(Some(Value::Array(result)))
838 }
839 _ => unreachable!(),
840 }
841 }
842 "forEach" => {
843 if self.is_async_callback(&callback) {
845 return self.start_continuation_foreach(callback, arr);
846 }
847 for (i, item) in arr.iter().enumerate() {
848 self.call_element_callback(&callback, item, i)?;
849 }
850 Ok(Some(Value::Undefined))
851 }
852 _ => Err(ZapcodeError::TypeError(format!(
853 "Unknown array callback method: {}",
854 method
855 ))),
856 }
857 }
858
859 fn execute_promise_method(
862 &mut self,
863 promise: Value,
864 method: &str,
865 args: Vec<Value>,
866 ) -> Result<Option<Value>> {
867 let (status, value, reason) = if let Value::Object(ref map) = promise {
868 let status = match map.get("status") {
869 Some(Value::String(s)) => s.to_string(),
870 _ => "pending".to_string(),
871 };
872 let value = map.get("value").cloned().unwrap_or(Value::Undefined);
873 let reason = map.get("reason").cloned().unwrap_or(Value::Undefined);
874 (status, value, reason)
875 } else {
876 return Ok(None);
877 };
878
879 let on_fulfilled = args.first().cloned().unwrap_or(Value::Undefined);
880 let on_rejected = args.get(1).cloned().unwrap_or(Value::Undefined);
881
882 match method {
883 "then" => {
884 if status == "resolved" {
885 if matches!(on_fulfilled, Value::Function(_)) {
886 let result = self.call_function_internal(&on_fulfilled, vec![value])?;
887 Ok(Some(builtins::make_resolved_promise(result)))
888 } else {
889 Ok(Some(promise))
891 }
892 } else if status == "rejected" {
893 if matches!(on_rejected, Value::Function(_)) {
894 let result = self.call_function_internal(&on_rejected, vec![reason])?;
895 Ok(Some(builtins::make_resolved_promise(result)))
896 } else {
897 Ok(Some(promise))
899 }
900 } else {
901 Ok(Some(promise))
902 }
903 }
904 "catch" => {
905 if status == "rejected" {
906 let handler = args.first().cloned().unwrap_or(Value::Undefined);
907 if matches!(handler, Value::Function(_)) {
908 let result = self.call_function_internal(&handler, vec![reason])?;
909 Ok(Some(builtins::make_resolved_promise(result)))
910 } else {
911 Ok(Some(promise))
912 }
913 } else {
914 Ok(Some(promise))
916 }
917 }
918 "finally" => {
919 let handler = args.first().cloned().unwrap_or(Value::Undefined);
920 if matches!(handler, Value::Function(_)) {
921 self.call_function_internal(&handler, vec![])?;
923 }
924 Ok(Some(promise))
926 }
927 _ => Ok(None),
928 }
929 }
930
931 fn alloc_generator_id(&mut self) -> u64 {
932 let id = self.next_generator_id;
933 self.next_generator_id += 1;
934 id
935 }
936
937 fn generator_next(&mut self, mut gen_obj: GeneratorObject, arg: Value) -> Result<Value> {
938 if gen_obj.done {
939 return Ok(self.make_iterator_result(Value::Undefined, true));
940 }
941 for (name, val) in &gen_obj.captured {
942 if !self.globals.contains_key(name) {
943 self.globals.insert(name.clone(), val.clone());
944 }
945 }
946 let func_idx = gen_obj.func_id.0;
947 match gen_obj.suspended.take() {
948 None => {
949 let func = &self.program.functions[func_idx];
950 self.tracker.push_frame();
951 let mut locals = Vec::with_capacity(func.local_count);
952 for param in func.params.iter() {
953 match param {
954 ParamPattern::Ident(name) => {
955 let val = gen_obj
956 .captured
957 .iter()
958 .find(|(n, _)| n == name)
959 .map(|(_, v)| v.clone())
960 .unwrap_or(Value::Undefined);
961 locals.push(val);
962 }
963 ParamPattern::Rest(name) => {
964 let val = gen_obj
965 .captured
966 .iter()
967 .find(|(n, _)| n == name)
968 .map(|(_, v)| v.clone())
969 .unwrap_or(Value::Array(Vec::new()));
970 locals.push(val);
971 }
972 _ => {
973 locals.push(Value::Undefined);
974 }
975 }
976 }
977 let stack_base = self.stack.len();
978 self.frames.push(CallFrame {
979 func_index: Some(func_idx),
980 ip: 0,
981 locals,
982 stack_base,
983 this_value: None,
984 receiver_source: None,
985 });
986 self.run_generator_until_yield_or_return(gen_obj)
987 }
988 Some(suspended) => {
989 self.tracker.push_frame();
990 let stack_base = self.stack.len();
991 for val in &suspended.stack {
992 self.push(val.clone())?;
993 }
994 self.push(arg)?;
995 self.frames.push(CallFrame {
996 func_index: Some(func_idx),
997 ip: suspended.ip,
998 locals: suspended.locals,
999 stack_base,
1000 this_value: None,
1001 receiver_source: None,
1002 });
1003 self.run_generator_until_yield_or_return(gen_obj)
1004 }
1005 }
1006 }
1007
1008 fn store_generator(&mut self, gen_obj: GeneratorObject) {
1011 let gen_key = format!("__gen_{}", gen_obj.id);
1012 if gen_obj.done {
1013 self.globals.remove(&gen_key);
1014 } else {
1015 self.globals.insert(gen_key, Value::Generator(gen_obj));
1016 }
1017 }
1018
1019 fn finish_generator(&mut self, mut gen_obj: GeneratorObject, value: Value) -> Value {
1021 gen_obj.done = true;
1022 gen_obj.suspended = None;
1023 self.store_generator(gen_obj);
1024 self.make_iterator_result(value, true)
1025 }
1026
1027 fn run_generator_until_yield_or_return(
1028 &mut self,
1029 mut gen_obj: GeneratorObject,
1030 ) -> Result<Value> {
1031 let target_frame_depth = self.frames.len() - 1;
1032 loop {
1033 self.tracker.check_time(&self.limits)?;
1034 let frame = self.frames.last().unwrap();
1035 let instructions = match frame.func_index {
1036 Some(idx) => &self.program.functions[idx].instructions,
1037 None => &self.program.instructions,
1038 };
1039 if frame.ip >= instructions.len() {
1040 if self.frames.len() > target_frame_depth + 1 {
1041 let frame = self.frames.pop().unwrap();
1042 self.tracker.pop_frame();
1043 if let Some(this_val) = frame.this_value {
1044 self.stack.truncate(frame.stack_base);
1045 self.push(this_val)?;
1046 } else {
1047 self.push(Value::Undefined)?;
1048 }
1049 continue;
1050 }
1051 let frame = self.frames.pop().unwrap();
1052 self.tracker.pop_frame();
1053 self.stack.truncate(frame.stack_base);
1054 let result = self.finish_generator(gen_obj, Value::Undefined);
1055 return Ok(result);
1056 }
1057 let instr = instructions[frame.ip].clone();
1058 if matches!(instr, Instruction::Yield) {
1059 self.current_frame_mut().ip += 1;
1060 let yielded_value = self.pop()?;
1061 let frame = self.frames.pop().unwrap();
1062 self.tracker.pop_frame();
1063 let frame_stack: Vec<Value> = self.stack.drain(frame.stack_base..).collect();
1064 gen_obj.suspended = Some(SuspendedFrame {
1065 ip: frame.ip,
1066 locals: frame.locals,
1067 stack: frame_stack,
1068 });
1069 gen_obj.done = false;
1070 self.store_generator(gen_obj);
1071 return Ok(self.make_iterator_result(yielded_value, false));
1072 }
1073 if matches!(instr, Instruction::Return) {
1074 self.current_frame_mut().ip += 1;
1075 let return_val = self.pop().unwrap_or(Value::Undefined);
1076 if self.frames.len() > target_frame_depth + 1 {
1077 let frame = self.frames.pop().unwrap();
1078 self.tracker.pop_frame();
1079 self.stack.truncate(frame.stack_base);
1080 self.push(return_val)?;
1081 continue;
1082 }
1083 let frame = self.frames.pop().unwrap();
1084 self.tracker.pop_frame();
1085 self.stack.truncate(frame.stack_base);
1086 let result = self.finish_generator(gen_obj, return_val);
1087 return Ok(result);
1088 }
1089 let result = self.dispatch(instr);
1090 match result {
1091 Ok(Some(VmState::Complete(val))) => return Ok(val),
1092 Ok(Some(VmState::Suspended { .. })) => {
1093 return Err(ZapcodeError::RuntimeError(
1094 "cannot suspend inside a generator".to_string(),
1095 ));
1096 }
1097 Ok(None) => {
1098 if self.frames.len() == target_frame_depth {
1099 let return_val = self.pop().unwrap_or(Value::Undefined);
1100 let result = self.finish_generator(gen_obj, return_val);
1101 return Ok(result);
1102 }
1103 }
1104 Err(err) => {
1105 if let Some(try_info) = self.try_stack.pop() {
1106 while self.frames.len() > try_info.frame_depth {
1107 self.frames.pop();
1108 self.tracker.pop_frame();
1109 }
1110 self.stack.truncate(try_info.stack_depth);
1111 let error_val = Value::String(Arc::from(err.to_string()));
1112 self.push(error_val)?;
1113 self.current_frame_mut().ip = try_info.catch_ip;
1114 } else {
1115 return Err(err);
1116 }
1117 }
1118 }
1119 }
1120 }
1121
1122 fn make_iterator_result(&self, value: Value, done: bool) -> Value {
1123 let mut obj = IndexMap::new();
1124 obj.insert(Arc::from("value"), value);
1125 obj.insert(Arc::from("done"), Value::Bool(done));
1126 Value::Object(obj)
1127 }
1128
1129 fn dispatch(&mut self, instr: Instruction) -> Result<Option<VmState>> {
1130 self.current_frame_mut().ip += 1;
1131
1132 match instr {
1133 Instruction::Push(constant) => {
1134 let value = match constant {
1135 Constant::Undefined => Value::Undefined,
1136 Constant::Null => Value::Null,
1137 Constant::Bool(b) => Value::Bool(b),
1138 Constant::Int(n) => Value::Int(n),
1139 Constant::Float(n) => Value::Float(n),
1140 Constant::String(s) => Value::String(Arc::from(s.as_str())),
1141 };
1142 self.push(value)?;
1143 }
1144 Instruction::Pop => {
1145 self.pop()?;
1146 }
1147 Instruction::Dup => {
1148 let val = self.peek()?.clone();
1149 self.push(val)?;
1150 }
1151 Instruction::LoadLocal(idx) => {
1152 let frame_index = self.frames.len() - 1;
1153 let frame = self.current_frame();
1154 let val = frame.locals.get(idx).cloned().unwrap_or(Value::Undefined);
1155 self.last_load_source = Some(ReceiverSource::Local {
1156 frame_index,
1157 slot: idx,
1158 });
1159 self.push(val)?;
1160 }
1161 Instruction::StoreLocal(idx) => {
1162 let val = self.pop()?;
1163 let frame = self.current_frame_mut();
1164 while frame.locals.len() <= idx {
1165 frame.locals.push(Value::Undefined);
1166 }
1167 frame.locals[idx] = val;
1168 }
1169 Instruction::LoadGlobal(name) => {
1170 let val = self.globals.get(&name).cloned().unwrap_or(Value::Undefined);
1171 self.last_global_name = Some(name.clone());
1172 if Self::BUILTIN_GLOBAL_NAMES.contains(&name.as_str()) {
1176 self.last_load_source = None;
1177 } else {
1178 self.last_load_source = Some(ReceiverSource::Global(name));
1179 }
1180 self.push(val)?;
1181 }
1182 Instruction::StoreGlobal(name) => {
1183 let val = self.pop()?;
1184 self.globals.insert(name, val);
1185 }
1186 Instruction::DeclareLocal(_) => {
1187 let frame = self.current_frame_mut();
1188 frame.locals.push(Value::Undefined);
1189 }
1190
1191 Instruction::Add => {
1193 let right = self.pop()?;
1194 let left = self.pop()?;
1195 let result = match (&left, &right) {
1196 (Value::Int(a), Value::Int(b)) => match a.checked_add(*b) {
1197 Some(r) => Value::Int(r),
1198 None => Value::Float(*a as f64 + *b as f64),
1199 },
1200 (Value::Float(a), Value::Float(b)) => Value::Float(a + b),
1201 (Value::Int(a), Value::Float(b)) => Value::Float(*a as f64 + b),
1202 (Value::Float(a), Value::Int(b)) => Value::Float(a + *b as f64),
1203 (Value::String(a), _) => {
1204 let rhs = right.to_js_string();
1205 let new_len = a.len().saturating_add(rhs.len());
1206 if new_len > 10_000_000 {
1207 return Err(ZapcodeError::AllocationLimitExceeded);
1208 }
1209 let mut s = a.to_string();
1210 s.push_str(&rhs);
1211 Value::String(Arc::from(s.as_str()))
1212 }
1213 (_, Value::String(b)) => {
1214 let lhs = left.to_js_string();
1215 let new_len = lhs.len().saturating_add(b.len());
1216 if new_len > 10_000_000 {
1217 return Err(ZapcodeError::AllocationLimitExceeded);
1218 }
1219 let mut s = lhs;
1220 s.push_str(b);
1221 Value::String(Arc::from(s.as_str()))
1222 }
1223 _ => Value::Float(left.to_number() + right.to_number()),
1224 };
1225 self.push(result)?;
1226 }
1227 Instruction::Sub => {
1228 let right = self.pop()?;
1229 let left = self.pop()?;
1230 let result = match (&left, &right) {
1231 (Value::Int(a), Value::Int(b)) => match a.checked_sub(*b) {
1232 Some(r) => Value::Int(r),
1233 None => Value::Float(*a as f64 - *b as f64),
1234 },
1235 _ => Value::Float(left.to_number() - right.to_number()),
1236 };
1237 self.push(result)?;
1238 }
1239 Instruction::Mul => {
1240 let right = self.pop()?;
1241 let left = self.pop()?;
1242 let result = match (&left, &right) {
1243 (Value::Int(a), Value::Int(b)) => match a.checked_mul(*b) {
1244 Some(r) => Value::Int(r),
1245 None => Value::Float(*a as f64 * *b as f64),
1246 },
1247 _ => Value::Float(left.to_number() * right.to_number()),
1248 };
1249 self.push(result)?;
1250 }
1251 Instruction::Div => {
1252 let right = self.pop()?;
1253 let left = self.pop()?;
1254 let result = Value::Float(left.to_number() / right.to_number());
1255 self.push(result)?;
1256 }
1257 Instruction::Rem => {
1258 let right = self.pop()?;
1259 let left = self.pop()?;
1260 let result = match (&left, &right) {
1261 (Value::Int(a), Value::Int(b)) if *b != 0 => Value::Int(a % b),
1262 _ => Value::Float(left.to_number() % right.to_number()),
1263 };
1264 self.push(result)?;
1265 }
1266 Instruction::Pow => {
1267 let right = self.pop()?;
1268 let left = self.pop()?;
1269 let result = Value::Float(left.to_number().powf(right.to_number()));
1270 self.push(result)?;
1271 }
1272 Instruction::Neg => {
1273 let val = self.pop()?;
1274 let result = match val {
1275 Value::Int(n) => Value::Int(-n),
1276 _ => Value::Float(-val.to_number()),
1277 };
1278 self.push(result)?;
1279 }
1280 Instruction::BitNot => {
1281 let val = self.pop()?;
1282 let n = val.to_number() as i32;
1283 self.push(Value::Int(!n as i64))?;
1284 }
1285 Instruction::BitAnd => {
1286 let right = self.pop()?;
1287 let left = self.pop()?;
1288 let result = (left.to_number() as i32) & (right.to_number() as i32);
1289 self.push(Value::Int(result as i64))?;
1290 }
1291 Instruction::BitOr => {
1292 let right = self.pop()?;
1293 let left = self.pop()?;
1294 let result = (left.to_number() as i32) | (right.to_number() as i32);
1295 self.push(Value::Int(result as i64))?;
1296 }
1297 Instruction::BitXor => {
1298 let right = self.pop()?;
1299 let left = self.pop()?;
1300 let result = (left.to_number() as i32) ^ (right.to_number() as i32);
1301 self.push(Value::Int(result as i64))?;
1302 }
1303 Instruction::Shl => {
1304 let right = self.pop()?;
1305 let left = self.pop()?;
1306 let shift = (right.to_number() as u32) & 0x1f;
1307 let result = (left.to_number() as i32) << shift;
1308 self.push(Value::Int(result as i64))?;
1309 }
1310 Instruction::Shr => {
1311 let right = self.pop()?;
1312 let left = self.pop()?;
1313 let shift = (right.to_number() as u32) & 0x1f;
1314 let result = (left.to_number() as i32) >> shift;
1315 self.push(Value::Int(result as i64))?;
1316 }
1317 Instruction::Ushr => {
1318 let right = self.pop()?;
1319 let left = self.pop()?;
1320 let shift = (right.to_number() as u32) & 0x1f;
1321 let result = (left.to_number() as u32) >> shift;
1322 self.push(Value::Int(result as i64))?;
1323 }
1324
1325 Instruction::Eq | Instruction::StrictEq => {
1327 let right = self.pop()?;
1328 let left = self.pop()?;
1329 self.push(Value::Bool(left.strict_eq(&right)))?;
1330 }
1331 Instruction::Neq | Instruction::StrictNeq => {
1332 let right = self.pop()?;
1333 let left = self.pop()?;
1334 self.push(Value::Bool(!left.strict_eq(&right)))?;
1335 }
1336 Instruction::Lt => {
1337 let right = self.pop()?;
1338 let left = self.pop()?;
1339 self.push(Value::Bool(left.to_number() < right.to_number()))?;
1340 }
1341 Instruction::Lte => {
1342 let right = self.pop()?;
1343 let left = self.pop()?;
1344 self.push(Value::Bool(left.to_number() <= right.to_number()))?;
1345 }
1346 Instruction::Gt => {
1347 let right = self.pop()?;
1348 let left = self.pop()?;
1349 self.push(Value::Bool(left.to_number() > right.to_number()))?;
1350 }
1351 Instruction::Gte => {
1352 let right = self.pop()?;
1353 let left = self.pop()?;
1354 self.push(Value::Bool(left.to_number() >= right.to_number()))?;
1355 }
1356
1357 Instruction::Not => {
1359 let val = self.pop()?;
1360 self.push(Value::Bool(!val.is_truthy()))?;
1361 }
1362
1363 Instruction::CreateArray(count) => {
1365 self.tracker.track_allocation(&self.limits)?;
1366 let mut arr = Vec::with_capacity(count);
1367 for _ in 0..count {
1368 arr.push(self.pop()?);
1369 }
1370 arr.reverse();
1371 self.push(Value::Array(arr))?;
1372 }
1373 Instruction::CreateObject(count) => {
1374 self.tracker.track_allocation(&self.limits)?;
1375 let mut obj = IndexMap::new();
1376 let mut entries = Vec::new();
1378 for _ in 0..count {
1379 let val = self.pop()?;
1380 let key = self.pop()?;
1381 entries.push((key, val));
1382 }
1383 entries.reverse();
1384 for (key, val) in entries {
1385 match key {
1386 Value::String(k) => {
1387 obj.insert(k, val);
1388 }
1389 _ => {
1390 let k: Arc<str> = Arc::from(key.to_js_string().as_str());
1391 obj.insert(k, val);
1392 }
1393 }
1394 }
1395 self.push(Value::Object(obj))?;
1396 }
1397 Instruction::GetProperty(name) => {
1398 let obj = self.pop()?;
1399 let result = self.get_property(&obj, &name)?;
1400 if matches!(result, Value::BuiltinMethod { .. } | Value::Function(_)) {
1402 self.last_receiver = Some(obj);
1403 self.last_receiver_source = self.last_load_source.take();
1404 } else {
1405 self.last_receiver_source = None;
1406 }
1407 self.push(result)?;
1408 }
1409 Instruction::SetProperty(name) => {
1410 let obj_val = self.pop()?;
1413 let value = self.pop()?;
1414 match obj_val {
1415 Value::Object(mut obj) => {
1416 obj.insert(Arc::from(name.as_str()), value);
1417 self.push(Value::Object(obj))?;
1419 }
1420 _ => {
1421 return Err(ZapcodeError::TypeError(format!(
1422 "cannot set property '{}' on {}",
1423 name,
1424 obj_val.type_name()
1425 )));
1426 }
1427 }
1428 }
1429 Instruction::GetIndex => {
1430 let index = self.pop()?;
1431 let obj = self.pop()?;
1432 let result = match (&obj, &index) {
1433 (Value::Array(arr), Value::Int(i)) => {
1434 arr.get(*i as usize).cloned().unwrap_or(Value::Undefined)
1435 }
1436 (Value::Array(arr), Value::Float(f)) => {
1437 arr.get(*f as usize).cloned().unwrap_or(Value::Undefined)
1438 }
1439 (Value::Object(map), Value::String(key)) => {
1440 map.get(key.as_ref()).cloned().unwrap_or(Value::Undefined)
1441 }
1442 (Value::Object(map), _) => {
1443 let key: Arc<str> = Arc::from(index.to_js_string().as_str());
1444 map.get(key.as_ref()).cloned().unwrap_or(Value::Undefined)
1445 }
1446 (Value::String(s), Value::Int(i)) => s
1447 .chars()
1448 .nth(*i as usize)
1449 .map(|c| Value::String(Arc::from(c.to_string().as_str())))
1450 .unwrap_or(Value::Undefined),
1451 _ => Value::Undefined,
1452 };
1453 self.push(result)?;
1454 }
1455 Instruction::SetIndex => {
1456 let index = self.pop()?;
1457 let mut obj = self.pop()?;
1458 let value = self.pop()?;
1459 match &mut obj {
1460 Value::Array(arr) => {
1461 let idx = match &index {
1462 Value::Int(i) if *i >= 0 => *i as usize,
1463 Value::Float(f) if *f >= 0.0 && *f == (*f as usize as f64) => {
1464 *f as usize
1465 }
1466 _ => {
1467 self.push(obj)?;
1469 return Ok(None);
1470 }
1471 };
1472 if idx > arr.len() + 1024 {
1474 return Err(ZapcodeError::RuntimeError(format!(
1475 "array index {} too far beyond length {}",
1476 idx,
1477 arr.len()
1478 )));
1479 }
1480 while arr.len() <= idx {
1481 arr.push(Value::Undefined);
1482 }
1483 arr[idx] = value;
1484 }
1485 Value::Object(map) => {
1486 let key: Arc<str> = Arc::from(index.to_js_string().as_str());
1487 map.insert(key, value);
1488 }
1489 _ => {}
1490 }
1491 self.push(obj)?;
1493 }
1494 Instruction::Spread => {
1495 }
1497 Instruction::In => {
1498 let right = self.pop()?;
1499 let left = self.pop()?;
1500 let result = match &right {
1501 Value::Object(map) => {
1502 let key = left.to_js_string();
1503 map.contains_key(key.as_str())
1504 }
1505 Value::Array(arr) => {
1506 if let Value::Int(i) = left {
1507 (i as usize) < arr.len()
1508 } else {
1509 false
1510 }
1511 }
1512 _ => false,
1513 };
1514 self.push(Value::Bool(result))?;
1515 }
1516 Instruction::InstanceOf => {
1517 let right = self.pop()?;
1518 let left = self.pop()?;
1519 let result = match (&left, &right) {
1521 (Value::Object(instance), Value::Object(class_obj)) => {
1522 if let (Some(inst_class), Some(class_name)) =
1523 (instance.get("__class__"), class_obj.get("__class_name__"))
1524 {
1525 inst_class == class_name
1526 } else {
1527 false
1528 }
1529 }
1530 _ => false,
1531 };
1532 self.push(Value::Bool(result))?;
1533 }
1534
1535 Instruction::CreateClosure(func_idx) => {
1537 let mut captured = Vec::new();
1539 for frame in &self.frames {
1541 let local_names = if let Some(fidx) = frame.func_index {
1542 &self.program.functions[fidx].local_names
1543 } else {
1544 &self.program.local_names
1545 };
1546 for (i, val) in frame.locals.iter().enumerate() {
1547 if let Some(name) = local_names.get(i) {
1548 captured.push((name.clone(), val.clone()));
1549 }
1550 }
1551 }
1552 let builtins = ["console", "Math", "JSON", "Object", "Array"];
1554 for (name, val) in &self.globals {
1555 if !builtins.contains(&name.as_str()) {
1556 captured.push((name.clone(), val.clone()));
1557 }
1558 }
1559 let closure = Closure {
1560 func_id: FunctionId(func_idx),
1561 captured,
1562 };
1563 self.push(Value::Function(closure))?;
1564 }
1565 Instruction::Call(arg_count) => {
1566 let mut args = Vec::with_capacity(arg_count);
1567 for _ in 0..arg_count {
1568 args.push(self.pop()?);
1569 }
1570 args.reverse();
1571
1572 let callee = self.pop()?;
1573 match callee {
1574 Value::Function(closure) => {
1575 let func_idx = closure.func_id.0;
1576 let is_generator = self.program.functions[func_idx].is_generator;
1577
1578 if is_generator {
1580 let params = self.program.functions[func_idx].params.clone();
1581 let gen_id = self.alloc_generator_id();
1582 let mut captured = closure.captured.clone();
1584 for (i, param) in params.iter().enumerate() {
1585 match param {
1586 ParamPattern::Ident(name) => {
1587 captured.push((
1588 name.clone(),
1589 args.get(i).cloned().unwrap_or(Value::Undefined),
1590 ));
1591 }
1592 ParamPattern::Rest(name) => {
1593 let rest: Vec<Value> = args[i..].to_vec();
1594 captured.push((name.clone(), Value::Array(rest)));
1595 }
1596 _ => {}
1597 }
1598 }
1599 let gen_obj = GeneratorObject {
1600 id: gen_id,
1601 func_id: closure.func_id,
1602 captured,
1603 suspended: None,
1604 done: false,
1605 };
1606 self.globals.insert(
1608 format!("__gen_{}", gen_id),
1609 Value::Generator(gen_obj.clone()),
1610 );
1611 self.push(Value::Generator(gen_obj))?;
1612 self.last_receiver = None;
1613 self.last_receiver_source = None;
1614 } else {
1615 let this_value = self.last_receiver.take();
1616 self.push_call_frame(&closure, &args, this_value)?;
1617 }
1618 }
1619 Value::BuiltinMethod {
1620 object_name,
1621 method_name,
1622 } => {
1623 let receiver = self.last_receiver.take();
1624 let result = match object_name.as_ref() {
1625 "__array__" => {
1626 if let Some(Value::Array(arr)) = &receiver {
1627 match method_name.as_ref() {
1629 "map" | "filter" | "forEach" | "find" | "findIndex"
1630 | "every" | "some" | "reduce" | "sort" | "flatMap" => {
1631 match self.execute_array_callback_method(
1632 arr.clone(),
1633 &method_name,
1634 args,
1635 )? {
1636 Some(val) => Some(val),
1637 None => {
1638 return Ok(None);
1642 }
1643 }
1644 }
1645 _ => builtins::call_builtin(
1646 &Value::Array(arr.clone()),
1647 &method_name,
1648 &args,
1649 &mut self.stdout,
1650 )?,
1651 }
1652 } else {
1653 None
1654 }
1655 }
1656 "__string__" => {
1657 if let Some(Value::String(s)) = &receiver {
1658 builtins::call_builtin(
1659 &Value::String(s.clone()),
1660 &method_name,
1661 &args,
1662 &mut self.stdout,
1663 )?
1664 } else {
1665 None
1666 }
1667 }
1668 "__generator__" => {
1669 if let Some(Value::Generator(gen_obj)) = receiver {
1670 match method_name.as_ref() {
1671 "next" => {
1672 let arg =
1673 args.into_iter().next().unwrap_or(Value::Undefined);
1674 let gen_key = format!("__gen_{}", gen_obj.id);
1678 if let Some(Value::Generator(g)) =
1679 self.globals.remove(&gen_key)
1680 {
1681 let result = self.generator_next(g, arg)?;
1682 Some(result)
1683 } else {
1684 Some(
1685 self.make_iterator_result(
1686 Value::Undefined,
1687 true,
1688 ),
1689 )
1690 }
1691 }
1692 "return" => {
1693 let val =
1694 args.into_iter().next().unwrap_or(Value::Undefined);
1695 let gen_key = format!("__gen_{}", gen_obj.id);
1696 if let Some(Value::Generator(g)) =
1697 self.globals.remove(&gen_key)
1698 {
1699 let result = self.finish_generator(g, val);
1700 Some(result)
1701 } else {
1702 Some(self.make_iterator_result(val, true))
1703 }
1704 }
1705 _ => None,
1706 }
1707 } else {
1708 None
1709 }
1710 }
1711 "__promise__" => {
1712 if let Some(promise) = receiver {
1713 self.execute_promise_method(promise, &method_name, args)?
1714 } else {
1715 None
1716 }
1717 }
1718 global_name => builtins::call_global_method(
1719 global_name,
1720 &method_name,
1721 &args,
1722 &mut self.stdout,
1723 )?,
1724 };
1725 match result {
1726 Some(val) => self.push(val)?,
1727 None => {
1728 return Err(ZapcodeError::TypeError(format!(
1729 "{}.{} is not a function",
1730 object_name, method_name
1731 )));
1732 }
1733 }
1734 }
1735 _ => {
1736 return Err(ZapcodeError::TypeError(format!(
1737 "{} is not a function",
1738 callee.to_js_string()
1739 )));
1740 }
1741 }
1742 }
1743 Instruction::Return => {
1744 let return_val = self.pop().unwrap_or(Value::Undefined);
1745
1746 if self.frames.len() <= 1 {
1747 return Ok(Some(VmState::Complete(return_val)));
1748 }
1749
1750 let frame = self.frames.pop().unwrap();
1751 self.tracker.pop_frame();
1752
1753 let actual_return = if let Some(ref this_val) = frame.this_value {
1757 if let Some(parent) = self.frames.last_mut() {
1759 if parent.this_value.is_some() {
1760 parent.this_value = Some(this_val.clone());
1761 }
1762 }
1763 if let Some(ref source) = frame.receiver_source {
1768 match source {
1769 ReceiverSource::Global(name) => {
1770 self.globals.insert(name.clone(), this_val.clone());
1771 }
1772 ReceiverSource::Local { frame_index, slot } => {
1773 if let Some(target_frame) = self.frames.get_mut(*frame_index) {
1774 while target_frame.locals.len() <= *slot {
1775 target_frame.locals.push(Value::Undefined);
1776 }
1777 target_frame.locals[*slot] = this_val.clone();
1778 }
1779 }
1780 }
1781 }
1782 if matches!(return_val, Value::Undefined) {
1783 this_val.clone()
1784 } else {
1785 return_val
1786 }
1787 } else {
1788 return_val
1789 };
1790
1791 self.stack.truncate(frame.stack_base);
1792 self.push(actual_return)?;
1793 }
1794 Instruction::CallExternal(name, arg_count) => {
1795 if !self.external_functions.contains(&name) {
1796 return Err(ZapcodeError::UnknownExternalFunction(name));
1797 }
1798 let mut args = Vec::with_capacity(arg_count);
1799 for _ in 0..arg_count {
1800 args.push(self.pop()?);
1801 }
1802 args.reverse();
1803 let snapshot = ZapcodeSnapshot::capture(self)?;
1805 return Ok(Some(VmState::Suspended {
1806 function_name: name,
1807 args,
1808 snapshot,
1809 }));
1810 }
1811
1812 Instruction::Jump(target) => {
1814 self.current_frame_mut().ip = target;
1815 }
1816 Instruction::JumpIfFalse(target) => {
1817 let val = self.pop()?;
1818 if !val.is_truthy() {
1819 self.current_frame_mut().ip = target;
1820 }
1821 }
1822 Instruction::JumpIfTrue(target) => {
1823 let val = self.pop()?;
1824 if val.is_truthy() {
1825 self.current_frame_mut().ip = target;
1826 }
1827 }
1828 Instruction::JumpIfNullish(target) => {
1829 let val = self.peek()?;
1830 if matches!(val, Value::Null | Value::Undefined) {
1831 self.current_frame_mut().ip = target;
1832 }
1833 }
1834
1835 Instruction::SetupLoop => {}
1837 Instruction::Break | Instruction::Continue => {
1838 }
1840
1841 Instruction::GetIterator => {
1843 let val = self.pop()?;
1844 match val {
1845 Value::Array(arr) => {
1846 let iter_obj = Value::Array(vec![Value::Array(arr), Value::Int(0)]);
1848 self.push(iter_obj)?;
1849 }
1850 Value::String(s) => {
1851 let chars: Vec<Value> = s
1852 .chars()
1853 .map(|c| Value::String(Arc::from(c.to_string().as_str())))
1854 .collect();
1855 let iter_obj = Value::Array(vec![Value::Array(chars), Value::Int(0)]);
1856 self.push(iter_obj)?;
1857 }
1858 Value::Generator(gen_obj) => {
1859 let iter_obj = Value::Array(vec![
1860 Value::String(Arc::from("__gen__")),
1861 Value::Int(gen_obj.id as i64),
1862 Value::Bool(false),
1863 ]);
1864 self.push(iter_obj)?;
1865 }
1866 _ => {
1867 return Err(ZapcodeError::TypeError(format!(
1868 "{} is not iterable",
1869 val.type_name()
1870 )));
1871 }
1872 }
1873 }
1874 Instruction::IteratorNext => {
1875 let iter = self.pop()?;
1876 if let Value::Array(ref items) = iter {
1878 if items.len() == 3 {
1879 if let Value::String(ref s) = items[0] {
1880 if s.as_ref() == "__gen__" {
1881 let gen_id = match &items[1] {
1882 Value::Int(id) => *id as u64,
1883 _ => {
1884 return Err(ZapcodeError::RuntimeError(
1885 "bad gen iter".into(),
1886 ))
1887 }
1888 };
1889 let gen_key = format!("__gen_{}", gen_id);
1890 let gen_obj = if let Some(Value::Generator(g)) =
1891 self.globals.remove(&gen_key)
1892 {
1893 g
1894 } else {
1895 self.push(Value::Array(vec![
1896 Value::String(Arc::from("__gen__")),
1897 Value::Int(gen_id as i64),
1898 Value::Bool(true),
1899 ]))?;
1900 self.push(Value::Undefined)?;
1901 return Ok(None);
1902 };
1903 let result = self.generator_next(gen_obj, Value::Undefined)?;
1904 if let Value::Object(ref obj) = result {
1905 let done = obj
1906 .get("done")
1907 .is_some_and(|v| matches!(v, Value::Bool(true)));
1908 let value =
1909 obj.get("value").cloned().unwrap_or(Value::Undefined);
1910 self.push(Value::Array(vec![
1911 Value::String(Arc::from("__gen__")),
1912 Value::Int(gen_id as i64),
1913 Value::Bool(done),
1914 ]))?;
1915 self.push(value)?;
1916 } else {
1917 self.push(iter)?;
1918 self.push(Value::Undefined)?;
1919 }
1920 return Ok(None);
1921 }
1922 }
1923 }
1924 }
1925 match iter {
1926 Value::Array(ref items) if items.len() == 2 => {
1927 let arr = match &items[0] {
1928 Value::Array(a) => a,
1929 _ => return Err(ZapcodeError::RuntimeError("invalid iterator".into())),
1930 };
1931 let idx = match &items[1] {
1932 Value::Int(i) => *i as usize,
1933 _ => return Err(ZapcodeError::RuntimeError("invalid iterator".into())),
1934 };
1935 if idx < arr.len() {
1936 let value = arr[idx].clone();
1937 let new_iter =
1939 Value::Array(vec![items[0].clone(), Value::Int((idx + 1) as i64)]);
1940 self.push(new_iter)?;
1942 self.push(value)?;
1943 } else {
1944 self.push(iter)?;
1946 self.push(Value::Undefined)?;
1947 }
1948 }
1949 _ => {
1950 return Err(ZapcodeError::RuntimeError("invalid iterator state".into()));
1951 }
1952 }
1953 }
1954 Instruction::IteratorDone => {
1955 let value = self.pop()?;
1956 let iter = self.peek()?;
1957 if let Value::Array(items) = iter {
1959 if items.len() == 3 {
1960 if let Value::String(ref s) = items[0] {
1961 if s.as_ref() == "__gen__" {
1962 let done = matches!(&items[2], Value::Bool(true));
1963 if !done {
1964 self.push(value)?;
1965 }
1966 self.push(Value::Bool(done))?;
1967 return Ok(None);
1968 }
1969 }
1970 }
1971 }
1972 let iter = self.peek()?;
1973 match iter {
1974 Value::Array(items) if items.len() == 2 => {
1975 let arr = match &items[0] {
1976 Value::Array(a) => a,
1977 _ => {
1978 self.push(value)?;
1979 self.push(Value::Bool(true))?;
1980 return Ok(None);
1981 }
1982 };
1983 let idx = match &items[1] {
1984 Value::Int(i) => *i as usize,
1985 _ => {
1986 self.push(value)?;
1987 self.push(Value::Bool(true))?;
1988 return Ok(None);
1989 }
1990 };
1991 let done = idx > arr.len();
1992 if !done {
1993 self.push(value)?;
1995 }
1996 self.push(Value::Bool(done))?;
1997 }
1998 _ => {
1999 self.push(value)?;
2000 self.push(Value::Bool(true))?;
2001 }
2002 }
2003 }
2004
2005 Instruction::SetupTry(catch_ip, _) => {
2007 self.try_stack.push(TryInfo {
2008 catch_ip,
2009 frame_depth: self.frames.len(),
2010 stack_depth: self.stack.len(),
2011 });
2012 }
2013 Instruction::Throw => {
2014 let val = self.pop()?;
2015 let msg = val.to_js_string();
2016 return Err(ZapcodeError::RuntimeError(msg));
2017 }
2018 Instruction::EndTry => {
2019 self.try_stack.pop();
2020 }
2021
2022 Instruction::TypeOf => {
2024 let val = self.pop()?;
2025 let type_str = val.type_name();
2026 self.push(Value::String(Arc::from(type_str)))?;
2027 }
2028
2029 Instruction::Void => {
2031 self.pop()?;
2032 self.push(Value::Undefined)?;
2033 }
2034
2035 Instruction::Increment => {
2037 let val = self.pop()?;
2038 let result = match val {
2039 Value::Int(n) => Value::Int(n + 1),
2040 _ => Value::Float(val.to_number() + 1.0),
2041 };
2042 self.push(result)?;
2043 }
2044 Instruction::Decrement => {
2045 let val = self.pop()?;
2046 let result = match val {
2047 Value::Int(n) => Value::Int(n - 1),
2048 _ => Value::Float(val.to_number() - 1.0),
2049 };
2050 self.push(result)?;
2051 }
2052
2053 Instruction::ConcatStrings(count) => {
2055 let mut parts = Vec::with_capacity(count);
2056 for _ in 0..count {
2057 parts.push(self.pop()?);
2058 }
2059 parts.reverse();
2060 let result: String = parts.iter().map(|v| v.to_js_string()).collect();
2061 self.push(Value::String(Arc::from(result.as_str())))?;
2062 }
2063
2064 Instruction::DestructureObject(keys) => {
2066 let obj = self.pop()?;
2067 for key in keys {
2068 let val = self.get_property(&obj, &key)?;
2069 self.push(val)?;
2070 }
2071 }
2072 Instruction::DestructureArray(count) => {
2073 let arr = self.pop()?;
2074 match arr {
2075 Value::Array(items) => {
2076 for i in 0..count {
2077 self.push(items.get(i).cloned().unwrap_or(Value::Undefined))?;
2078 }
2079 }
2080 _ => {
2081 for _ in 0..count {
2082 self.push(Value::Undefined)?;
2083 }
2084 }
2085 }
2086 }
2087
2088 Instruction::Nop => {}
2089
2090 Instruction::CreateGenerator(_func_idx) => {
2092 }
2094 Instruction::Yield => {
2095 return Err(ZapcodeError::RuntimeError(
2098 "yield can only be used inside a generator function".to_string(),
2099 ));
2100 }
2101
2102 Instruction::Await => {
2103 let val = self.pop()?;
2107 if builtins::is_promise(&val) {
2108 if let Value::Object(map) = &val {
2109 let status = map.get("status").cloned().unwrap_or(Value::Undefined);
2110 match status {
2111 Value::String(s) if s.as_ref() == "resolved" => {
2112 let inner = map.get("value").cloned().unwrap_or(Value::Undefined);
2113 self.push(inner)?;
2114 }
2115 Value::String(s) if s.as_ref() == "rejected" => {
2116 let reason = map.get("reason").cloned().unwrap_or(Value::Undefined);
2117 return Err(ZapcodeError::RuntimeError(format!(
2118 "Unhandled promise rejection: {}",
2119 reason.to_js_string()
2120 )));
2121 }
2122 _ => {
2123 self.push(val)?;
2125 }
2126 }
2127 } else {
2128 self.push(val)?;
2129 }
2130 } else {
2131 self.push(val)?;
2133 }
2134 }
2135
2136 Instruction::CreateClass {
2138 name,
2139 n_methods,
2140 n_statics,
2141 has_super,
2142 } => {
2143 let constructor = self.pop()?;
2150
2151 let mut prototype = IndexMap::new();
2153 for _ in 0..n_methods {
2154 let method_closure = self.pop()?;
2155 let method_name = self.pop()?;
2156 if let Value::String(mn) = method_name {
2157 prototype.insert(mn, method_closure);
2158 }
2159 }
2160
2161 let mut statics = IndexMap::new();
2163 for _ in 0..n_statics {
2164 let method_closure = self.pop()?;
2165 let method_name = self.pop()?;
2166 if let Value::String(mn) = method_name {
2167 statics.insert(mn, method_closure);
2168 }
2169 }
2170
2171 let super_class = if has_super { Some(self.pop()?) } else { None };
2173
2174 if let Some(Value::Object(ref sc)) = super_class {
2176 if let Some(Value::Object(super_proto)) = sc.get("__prototype__").cloned() {
2177 let mut merged = super_proto;
2179 for (k, v) in prototype {
2180 merged.insert(k, v);
2181 }
2182 prototype = merged;
2183 }
2184 }
2185
2186 let mut class_obj = IndexMap::new();
2188 class_obj.insert(
2189 Arc::from("__class_name__"),
2190 Value::String(Arc::from(name.as_str())),
2191 );
2192 class_obj.insert(Arc::from("__constructor__"), constructor);
2193 class_obj.insert(Arc::from("__prototype__"), Value::Object(prototype));
2194
2195 if let Some(sc) = super_class {
2197 class_obj.insert(Arc::from("__super__"), sc);
2198 }
2199
2200 for (k, v) in statics {
2202 class_obj.insert(k, v);
2203 }
2204
2205 self.push(Value::Object(class_obj))?;
2206 }
2207
2208 Instruction::Construct(arg_count) => {
2209 let mut args = Vec::with_capacity(arg_count);
2210 for _ in 0..arg_count {
2211 args.push(self.pop()?);
2212 }
2213 args.reverse();
2214
2215 let callee = self.pop()?;
2216
2217 match &callee {
2218 Value::Object(class_obj) if class_obj.contains_key("__class_name__") => {
2219 let mut instance = IndexMap::new();
2221
2222 if let Some(Value::Object(proto)) = class_obj.get("__prototype__") {
2224 for (k, v) in proto {
2225 instance.insert(k.clone(), v.clone());
2226 }
2227 }
2228
2229 if let Some(class_name) = class_obj.get("__class_name__") {
2231 instance.insert(Arc::from("__class__"), class_name.clone());
2232 }
2233
2234 let instance_val = Value::Object(instance);
2235
2236 if let Some(ctor) = class_obj.get("__constructor__") {
2238 if let Value::Function(closure) = ctor {
2239 self.last_receiver_source = None;
2242 self.push_call_frame(closure, &args, Some(instance_val))?;
2243 self.last_receiver = None;
2244 } else {
2245 self.push(instance_val)?;
2247 }
2248 } else {
2249 self.push(instance_val)?;
2251 }
2252 }
2253 Value::Function(closure) => {
2254 self.push_call_frame(closure, &args, None)?;
2256 self.last_receiver = None;
2257 }
2258 _ => {
2259 return Err(ZapcodeError::TypeError(format!(
2260 "{} is not a constructor",
2261 callee.to_js_string()
2262 )));
2263 }
2264 }
2265 }
2266
2267 Instruction::LoadThis => {
2268 let this_val = self
2270 .frames
2271 .iter()
2272 .rev()
2273 .find_map(|f| f.this_value.clone())
2274 .unwrap_or(Value::Undefined);
2275 self.push(this_val)?;
2276 }
2277 Instruction::StoreThis => {
2278 let val = self.pop()?;
2279 for frame in self.frames.iter_mut().rev() {
2281 if frame.this_value.is_some() {
2282 frame.this_value = Some(val);
2283 break;
2284 }
2285 }
2286 }
2287 Instruction::CallSuper(arg_count) => {
2288 let mut args = Vec::with_capacity(arg_count);
2289 for _ in 0..arg_count {
2290 args.push(self.pop()?);
2291 }
2292 args.reverse();
2293
2294 let this_val = self
2296 .frames
2297 .iter()
2298 .rev()
2299 .find_map(|f| f.this_value.clone())
2300 .unwrap_or(Value::Undefined);
2301
2302 let mut super_ctor = None;
2307 for val in self.globals.values() {
2308 if let Value::Object(obj) = val {
2309 if let Some(Value::Object(super_class)) = obj.get("__super__") {
2310 if let Some(ctor) = super_class.get("__constructor__") {
2311 super_ctor = Some(ctor.clone());
2312 break;
2313 }
2314 }
2315 }
2316 }
2317
2318 if let Some(Value::Function(closure)) = super_ctor {
2319 self.last_receiver_source = None;
2320 self.push_call_frame(&closure, &args, Some(this_val))?;
2321 self.last_receiver = None;
2322 } else {
2323 self.push(Value::Undefined)?;
2325 }
2326 }
2327 }
2328
2329 Ok(None)
2330 }
2331
2332 fn get_property(&self, obj: &Value, name: &str) -> Result<Value> {
2333 if matches!(obj, Value::Null | Value::Undefined) {
2335 return Err(ZapcodeError::TypeError(format!(
2336 "Cannot read properties of {} (reading '{}')",
2337 obj.to_js_string(),
2338 name
2339 )));
2340 }
2341 match obj {
2342 Value::Object(map) => {
2343 if let Some(val) = map.get(name) {
2345 if !matches!(val, Value::Undefined) {
2346 return Ok(val.clone());
2347 }
2348 }
2349 if builtins::is_promise(obj) && is_promise_method(name) {
2351 return Ok(Value::BuiltinMethod {
2352 object_name: Arc::from("__promise__"),
2353 method_name: Arc::from(name),
2354 });
2355 }
2356 if let Some(global_name) = &self.last_global_name {
2358 let known_globals = ["console", "Math", "JSON", "Object", "Array", "Promise"];
2359 if known_globals.contains(&global_name.as_str()) {
2360 return Ok(Value::BuiltinMethod {
2361 object_name: Arc::from(global_name.as_str()),
2362 method_name: Arc::from(name),
2363 });
2364 }
2365 }
2366 Ok(Value::Undefined)
2367 }
2368 Value::Array(arr) => match name {
2369 "length" => Ok(Value::Int(arr.len() as i64)),
2370 _ if is_array_method(name) => Ok(Value::BuiltinMethod {
2371 object_name: Arc::from("__array__"),
2372 method_name: Arc::from(name),
2373 }),
2374 _ => {
2375 if let Ok(idx) = name.parse::<usize>() {
2376 Ok(arr.get(idx).cloned().unwrap_or(Value::Undefined))
2377 } else {
2378 Ok(Value::Undefined)
2379 }
2380 }
2381 },
2382 Value::String(s) => match name {
2383 "length" => Ok(Value::Int(s.chars().count() as i64)),
2384 _ if is_string_method(name) => Ok(Value::BuiltinMethod {
2385 object_name: Arc::from("__string__"),
2386 method_name: Arc::from(name),
2387 }),
2388 _ => Ok(Value::Undefined),
2389 },
2390 Value::Generator(_) => match name {
2391 "next" | "return" | "throw" => Ok(Value::BuiltinMethod {
2392 object_name: Arc::from("__generator__"),
2393 method_name: Arc::from(name),
2394 }),
2395 _ => Ok(Value::Undefined),
2396 },
2397 _ => Ok(Value::Undefined),
2398 }
2399 }
2400}
2401
2402use crate::parser::ir::ParamPattern;
2404
2405fn is_array_method(name: &str) -> bool {
2406 matches!(
2407 name,
2408 "push"
2409 | "pop"
2410 | "shift"
2411 | "unshift"
2412 | "splice"
2413 | "slice"
2414 | "concat"
2415 | "join"
2416 | "reverse"
2417 | "sort"
2418 | "indexOf"
2419 | "lastIndexOf"
2420 | "includes"
2421 | "find"
2422 | "findIndex"
2423 | "map"
2424 | "filter"
2425 | "reduce"
2426 | "forEach"
2427 | "every"
2428 | "some"
2429 | "flat"
2430 | "flatMap"
2431 | "fill"
2432 | "at"
2433 | "entries"
2434 | "keys"
2435 | "values"
2436 )
2437}
2438
2439fn is_string_method(name: &str) -> bool {
2440 matches!(
2441 name,
2442 "charAt"
2443 | "charCodeAt"
2444 | "indexOf"
2445 | "lastIndexOf"
2446 | "includes"
2447 | "startsWith"
2448 | "endsWith"
2449 | "slice"
2450 | "substring"
2451 | "substr"
2452 | "toUpperCase"
2453 | "toLowerCase"
2454 | "trim"
2455 | "trimStart"
2456 | "trimEnd"
2457 | "trimLeft"
2458 | "trimRight"
2459 | "padStart"
2460 | "padEnd"
2461 | "repeat"
2462 | "replace"
2463 | "replaceAll"
2464 | "split"
2465 | "concat"
2466 | "at"
2467 | "match"
2468 | "search"
2469 | "normalize"
2470 )
2471}
2472
2473fn is_promise_method(name: &str) -> bool {
2474 matches!(name, "then" | "catch" | "finally")
2475}
2476
2477pub struct ZapcodeRun {
2479 source: String,
2480 #[allow(dead_code)]
2481 inputs: Vec<String>,
2482 external_functions: Vec<String>,
2483 limits: ResourceLimits,
2484}
2485
2486impl ZapcodeRun {
2487 pub fn new(
2488 source: String,
2489 inputs: Vec<String>,
2490 external_functions: Vec<String>,
2491 limits: ResourceLimits,
2492 ) -> Result<Self> {
2493 Ok(Self {
2494 source,
2495 inputs,
2496 external_functions,
2497 limits,
2498 })
2499 }
2500
2501 pub fn run(&self, input_values: Vec<(String, Value)>) -> Result<RunResult> {
2502 let mut root_span = SpanBuilder::new("zapcode.run");
2503
2504 let parse_span = SpanBuilder::new("parse");
2506 let program = match crate::parser::parse(&self.source) {
2507 Ok(p) => {
2508 root_span.add_child(parse_span.finish_ok());
2509 p
2510 }
2511 Err(e) => {
2512 root_span.add_child(parse_span.finish_error(&e.to_string()));
2513 let _trace = ExecutionTrace {
2514 root: root_span.finish(TraceStatus::Error),
2515 };
2516 return Err(e);
2517 }
2518 };
2519
2520 let compile_span = SpanBuilder::new("compile");
2522 let ext_set: HashSet<String> = self.external_functions.iter().cloned().collect();
2523 let compiled = match crate::compiler::compile_with_externals(&program, ext_set.clone()) {
2524 Ok(c) => {
2525 root_span.add_child(compile_span.finish_ok());
2526 c
2527 }
2528 Err(e) => {
2529 root_span.add_child(compile_span.finish_error(&e.to_string()));
2530 let _trace = ExecutionTrace {
2531 root: root_span.finish(TraceStatus::Error),
2532 };
2533 return Err(e);
2534 }
2535 };
2536
2537 let execute_span = SpanBuilder::new("execute");
2539 let mut vm = Vm::new(compiled, self.limits.clone(), ext_set);
2540
2541 for (name, value) in input_values {
2542 vm.globals.insert(name, value);
2543 }
2544
2545 let state = match vm.run() {
2546 Ok(s) => {
2547 let status = match &s {
2548 VmState::Complete(_) => TraceStatus::Ok,
2549 VmState::Suspended {
2550 function_name,
2551 args,
2552 ..
2553 } => {
2554 let mut span = execute_span;
2555 span.set_attr("zapcode.suspended_on", function_name);
2556 span.set_attr("zapcode.args_count", args.len());
2557 root_span.add_child(span.finish(TraceStatus::Ok));
2558 let trace = ExecutionTrace {
2559 root: root_span.finish_ok(),
2560 };
2561 return Ok(RunResult {
2562 state: s,
2563 stdout: vm.stdout,
2564 trace,
2565 });
2566 }
2567 };
2568 root_span.add_child(execute_span.finish(status));
2569 s
2570 }
2571 Err(e) => {
2572 root_span.add_child(execute_span.finish_error(&e.to_string()));
2573 let _trace = ExecutionTrace {
2574 root: root_span.finish(TraceStatus::Error),
2575 };
2576 return Err(e);
2577 }
2578 };
2579
2580 let trace = ExecutionTrace {
2581 root: root_span.finish_ok(),
2582 };
2583
2584 Ok(RunResult {
2585 state,
2586 stdout: vm.stdout,
2587 trace,
2588 })
2589 }
2590
2591 pub fn start(&self, input_values: Vec<(String, Value)>) -> Result<VmState> {
2595 let result = self.run(input_values)?;
2596 Ok(result.state)
2597 }
2598
2599 pub fn run_simple(&self) -> Result<Value> {
2600 let result = self.run(Vec::new())?;
2601 match result.state {
2602 VmState::Complete(v) => Ok(v),
2603 VmState::Suspended { function_name, .. } => Err(ZapcodeError::RuntimeError(format!(
2604 "execution suspended on external function '{}' — use run() instead",
2605 function_name
2606 ))),
2607 }
2608 }
2609}
2610
2611pub struct RunResult {
2613 pub state: VmState,
2614 pub stdout: String,
2615 pub trace: ExecutionTrace,
2617}
2618
2619pub fn eval_ts(source: &str) -> Result<Value> {
2621 let runner = ZapcodeRun::new(
2622 source.to_string(),
2623 Vec::new(),
2624 Vec::new(),
2625 ResourceLimits::default(),
2626 )?;
2627 runner.run_simple()
2628}
2629
2630pub fn eval_ts_with_output(source: &str) -> Result<(Value, String)> {
2632 let runner = ZapcodeRun::new(
2633 source.to_string(),
2634 Vec::new(),
2635 Vec::new(),
2636 ResourceLimits::default(),
2637 )?;
2638 let result = runner.run(Vec::new())?;
2639 match result.state {
2640 VmState::Complete(v) => Ok((v, result.stdout)),
2641 VmState::Suspended { function_name, .. } => Err(ZapcodeError::RuntimeError(format!(
2642 "execution suspended on external function '{}'",
2643 function_name
2644 ))),
2645 }
2646}