1use super::*;
5
6impl Interp {
7 pub(crate) fn tick(&mut self) -> bool {
9 self.steps += 1;
10 if self.steps > self.max_steps {
11 if !self.aborted {
12 self.log_progress("ABORT step budget");
13 }
14 self.aborted = true;
15 return true;
16 }
17 false
18 }
19
20 fn log_progress(&self, what: &str) {
21 let n = self.call_names.len();
22 let top: Vec<&str> = self.call_names.iter().rev().take(4).map(|s| s.as_str()).collect();
23 let (used, _) = crate::kernel::allocator::get_heap_stats();
24 crate::warn!(
25 "[JSPROF] {} steps={} depth={} t={}ms heap={}MB top={:?}",
26 what,
27 self.steps,
28 n,
29 crate::kernel::timer::get_system_time_ms(),
30 used / (1024 * 1024),
31 top
32 );
33 }
34
35 pub fn error(&self, msg: impl Into<String>) -> Value {
37 self.throw(msg)
38 }
39
40 pub fn type_error(&self, msg: impl Into<String>) -> Value {
46 self.error_of_kind("TypeError", msg)
47 }
48
49 pub fn range_error(&self, msg: impl Into<String>) -> Value {
51 self.error_of_kind("RangeError", msg)
52 }
53
54 fn error_of_kind(&self, kind: &str, msg: impl Into<String>) -> Value {
56 let err = self.throw(msg);
57 if let Value::Object(o) = &err {
58 let msg_str = o.borrow().props.get("message").map(|v| v.to_js_string()).unwrap_or_default();
59 o.borrow_mut().props.insert(
60 String::from("stack"),
61 Value::str(super::super::builtins::build_error_stack(kind, &msg_str)),
62 );
63 o.borrow_mut().props.insert(String::from("name"), Value::str(kind));
64 if let Some(Value::Object(ctor)) = self.global.borrow().vars.get(kind) {
65 if let Some(Value::Object(proto)) = ctor.borrow().props.get("prototype") {
66 o.borrow_mut().proto = Some(proto.clone());
67 }
68 }
69 }
70 err
71 }
72
73 pub(crate) fn throw(&self, msg: impl Into<String>) -> Value {
74 let o = Obj::plain();
76 let msg: String = msg.into();
77 let mut stack_str = if msg.is_empty() {
86 String::from("Error")
87 } else {
88 alloc::format!("Error: {msg}")
89 };
90 for name in self.call_names.iter().rev().take(12) {
91 stack_str.push_str("\n at ");
92 stack_str.push_str(name);
93 }
94 o.borrow_mut().props.insert(String::from("stack"), Value::str(stack_str));
95 o.borrow_mut()
96 .props
97 .insert(String::from("message"), Value::str(msg));
98 o.borrow_mut()
99 .props
100 .insert(String::from("name"), Value::str("Error"));
101 if let Some(Value::Object(ctor)) = self.global.borrow().vars.get("Error") {
105 if let Some(Value::Object(proto)) = ctor.borrow().props.get("prototype") {
106 o.borrow_mut().proto = Some(proto.clone());
107 }
108 }
109 Value::Object(o)
110 }
111
112 pub(crate) fn eval_source(&mut self, source: &str) -> Result<Value, Value> {
118 let mut parser = Parser::new_lazy(Lexer::new(source));
119 let program = parser.parse_program();
120 let errors = parser.error_count();
124 if errors > 0 {
125 crate::warn!("[JS] eval(): {} syntax error(s) recovered", errors);
126 for e in parser.errors().iter().take(3) {
127 crate::warn!("[JS] eval() SyntaxError: {}", e.message);
128 }
129 }
130 let scope = self.global.clone();
131 let global_this = self.global.borrow().vars.get("window").cloned().unwrap_or(Value::Undefined);
133 match self.exec_statements(&program.body, &scope, &global_this) {
134 Ok(Completion::Normal(v)) | Ok(Completion::Return(v)) => Ok(v),
135 Ok(_) => Ok(Value::Undefined),
136 Err(thrown) => Err(thrown),
137 }
138 }
139
140 pub(crate) fn exec_statements(
141 &mut self,
142 stmts: &[Statement],
143 scope: &Rc<RefCell<Scope>>,
144 this: &Value,
145 ) -> Result<Completion, Value> {
146 if !scope.borrow().is_block {
155 let mut names: Vec<String> = Vec::new();
156 collect_var_names(stmts, &mut names);
157 if !names.is_empty() {
158 let is_global = scope.borrow().parent.is_none();
161 let window = if is_global {
162 match scope_get(scope, "window") {
163 Some(Value::Object(w)) => Some(w),
164 _ => None,
165 }
166 } else {
167 None
168 };
169 let mut sc = scope.borrow_mut();
170 for n in names {
171 if sc.vars.contains_key(&n) {
172 continue;
173 }
174 let init = window
175 .as_ref()
176 .and_then(|w| w.borrow().props.get(n.as_str()).cloned())
177 .unwrap_or(Value::Undefined);
178 sc.vars.insert(n, init);
179 }
180 }
181 }
182 for s in stmts {
184 let fdecl = match s {
185 Statement::FunctionDeclaration { .. } => Some(s),
186 Statement::ExportDecl { declaration, .. }
187 if matches!(**declaration, Statement::FunctionDeclaration { .. }) =>
188 {
189 Some(&**declaration)
190 }
191 _ => None,
192 };
193 if let Some(Statement::FunctionDeclaration {
194 name,
195 params,
196 body,
197 is_async,
198 is_generator,
199 }) = fdecl
200 {
201 let f = self.make_function(
202 Some(name.clone()),
203 params.clone(),
204 body.clone(),
205 false,
206 *is_async,
207 *is_generator,
208 scope,
209 this,
210 );
211 if scope.borrow().is_block {
213 scope_declare(&var_scope(scope), name, f.clone());
214 }
215 scope_declare(scope, name, f);
216 }
217 }
218 let mut disposables: Vec<(Value, bool)> = Vec::new();
225 let mut last = Value::Undefined;
226 let mut outcome: Result<Completion, Value> = Ok(Completion::Normal(Value::Undefined));
227 for s in stmts {
228 if let Statement::VarDeclaration { kind, decls } = s {
229 if matches!(kind, VarKind::Using | VarKind::AwaitUsing) {
230 let is_await = matches!(kind, VarKind::AwaitUsing);
231 let mut bind_err = None;
232 for (pat, init) in decls {
233 let v = match init {
234 Some(e) => match self.eval(e, scope, this) {
235 Ok(v) => v,
236 Err(e) => {
237 bind_err = Some(e);
238 break;
239 }
240 },
241 None => Value::Undefined,
242 };
243 if let Err(e) = self.bind_pattern(pat, v.clone(), scope, this) {
244 bind_err = Some(e);
245 break;
246 }
247 if !matches!(v, Value::Undefined | Value::Null) {
248 disposables.push((v, is_await));
249 }
250 }
251 if let Some(e) = bind_err {
252 outcome = Err(e);
253 break;
254 }
255 last = Value::Undefined;
256 continue;
257 }
258 }
259 match self.exec_stmt(s, scope, this) {
260 Ok(Completion::Normal(v)) => last = v,
261 Ok(other) => {
262 outcome = Ok(other);
263 break;
264 }
265 Err(e) => {
266 outcome = Err(e);
267 break;
268 }
269 }
270 }
271 if disposables.is_empty() {
272 return match outcome {
273 Ok(Completion::Normal(_)) => Ok(Completion::Normal(last)),
274 other => other,
275 };
276 }
277 let mut pending_err: Option<Value> = match &outcome {
282 Err(e) => Some(e.clone()),
283 _ => None,
284 };
285 for (resource, is_await) in disposables.into_iter().rev() {
286 let key = if is_await {
287 "Symbol(Symbol.asyncDispose)"
288 } else {
289 "Symbol(Symbol.dispose)"
290 };
291 let method = match self.get_property(&resource, key) {
292 Ok(m) => m,
293 Err(e) => {
294 pending_err = Some(self.chain_suppressed(pending_err, e));
295 continue;
296 }
297 };
298 if matches!(method, Value::Undefined | Value::Null) {
299 continue;
300 }
301 let call_result = self.call_value(&method, resource, &[]);
302 let dispose_result = match call_result {
303 Ok(v) if is_await => self.await_value(v),
304 other => other,
305 };
306 if let Err(e) = dispose_result {
307 pending_err = Some(self.chain_suppressed(pending_err, e));
308 }
309 }
310 if let Some(e) = pending_err {
311 return Err(e);
312 }
313 match outcome {
314 Ok(Completion::Normal(_)) => Ok(Completion::Normal(last)),
315 other => other,
316 }
317 }
318
319 pub(crate) fn exec_stmt(
320 &mut self,
321 stmt: &Statement,
322 scope: &Rc<RefCell<Scope>>,
323 this: &Value,
324 ) -> Result<Completion, Value> {
325 if self.tick() {
326 return Err(Value::Undefined);
327 }
328 match stmt {
329 Statement::Empty => Ok(Completion::Normal(Value::Undefined)),
330 Statement::Expression(e) => {
331 let v = self.eval(e, scope, this)?;
332 Ok(Completion::Normal(v))
333 }
334 Statement::VarDeclaration { kind, decls } => {
335 let target = if matches!(kind, VarKind::Var) { var_scope(scope) } else { scope.clone() };
337 for (pat, init) in decls {
338 if init.is_none() && matches!(kind, VarKind::Var) {
340 if let Pattern::Identifier(name) = pat {
341 if target.borrow().vars.contains_key(name.as_str()) {
342 continue;
343 }
344 }
345 }
346 let v = match init {
347 Some(e) => self.eval(e, scope, this)?,
348 None => Value::Undefined,
349 };
350 if let Pattern::Identifier(name) = pat {
356 infer_function_name(&v, name);
357 }
358 self.bind_pattern(pat, v, &target, this)?;
359 }
360 Ok(Completion::Normal(Value::Undefined))
361 }
362 Statement::Block(body) => {
363 if block_has_lexical(body) {
367 let inner = Scope::block(scope.clone());
368 self.exec_statements(body, &inner, this)
369 } else {
370 self.exec_statements(body, scope, this)
371 }
372 }
373 Statement::FunctionDeclaration { .. } => {
374 Ok(Completion::Normal(Value::Undefined))
376 }
377 Statement::If {
378 test,
379 consequent,
380 alternate,
381 } => {
382 if self.eval(test, scope, this)?.truthy() {
383 self.exec_stmt(consequent, scope, this)
384 } else if let Some(alt) = alternate {
385 self.exec_stmt(alt, scope, this)
386 } else {
387 Ok(Completion::Normal(Value::Undefined))
388 }
389 }
390 Statement::While { test, body } => {
391 let own_label = self.pending_label.take();
392 while self.eval(test, scope, this)?.truthy() {
393 if self.tick() {
394 return Err(Value::Undefined);
395 }
396 match self.exec_stmt(body, scope, this)? {
397 Completion::Break(lbl) if lbl.is_none() || lbl == own_label => break,
398 Completion::Break(lbl) => return Ok(Completion::Break(lbl)),
399 Completion::Continue(lbl) if lbl.is_none() || lbl == own_label => {}
400 Completion::Continue(lbl) => return Ok(Completion::Continue(lbl)),
401 Completion::Normal(_) => {}
402 ret @ Completion::Return(_) => return Ok(ret),
403 }
404 }
405 Ok(Completion::Normal(Value::Undefined))
406 }
407 Statement::DoWhile { body, test } => {
408 let own_label = self.pending_label.take();
409 loop {
410 if self.tick() {
411 return Err(Value::Undefined);
412 }
413 match self.exec_stmt(body, scope, this)? {
414 Completion::Break(lbl) if lbl.is_none() || lbl == own_label => break,
415 Completion::Break(lbl) => return Ok(Completion::Break(lbl)),
416 Completion::Continue(lbl) if lbl.is_none() || lbl == own_label => {}
417 Completion::Continue(lbl) => return Ok(Completion::Continue(lbl)),
418 Completion::Normal(_) => {}
419 ret @ Completion::Return(_) => return Ok(ret),
420 }
421 if !self.eval(test, scope, this)?.truthy() {
422 break;
423 }
424 }
425 Ok(Completion::Normal(Value::Undefined))
426 }
427 Statement::For {
428 init,
429 test,
430 update,
431 body,
432 } => {
433 let own_label = self.pending_label.take();
434 let is_let_like = matches!(
442 init.as_deref(),
443 Some(Statement::VarDeclaration {
444 kind: VarKind::Let | VarKind::Const,
445 ..
446 })
447 );
448 let mut loop_scope = if is_let_like {
449 Scope::block(scope.clone())
450 } else {
451 scope.clone()
452 };
453 if let Some(init) = init {
454 self.exec_stmt(init, &loop_scope, this)?;
455 }
456 let let_names: Vec<String> = if is_let_like {
457 loop_scope.borrow().vars.keys().cloned().collect()
458 } else {
459 Vec::new()
460 };
461 loop {
462 if let Some(t) = test {
463 if !self.eval(t, &loop_scope, this)?.truthy() {
464 break;
465 }
466 }
467 if self.tick() {
468 return Err(Value::Undefined);
469 }
470 match self.exec_stmt(body, &loop_scope, this)? {
471 Completion::Break(lbl) if lbl.is_none() || lbl == own_label => break,
472 Completion::Break(lbl) => return Ok(Completion::Break(lbl)),
473 Completion::Continue(lbl) if lbl.is_none() || lbl == own_label => {}
474 Completion::Continue(lbl) => return Ok(Completion::Continue(lbl)),
475 Completion::Normal(_) => {}
476 ret @ Completion::Return(_) => return Ok(ret),
477 }
478 if is_let_like {
479 let next_scope = Scope::block(scope.clone());
480 for name in &let_names {
481 let v = scope_get(&loop_scope, name).unwrap_or(Value::Undefined);
482 next_scope.borrow_mut().vars.insert(name.clone(), v);
483 }
484 loop_scope = next_scope;
485 }
486 if let Some(u) = update {
487 self.eval(u, &loop_scope, this)?;
488 }
489 }
490 Ok(Completion::Normal(Value::Undefined))
491 }
492 Statement::ForIn {
493 decl_kind,
494 pattern,
495 object,
496 body,
497 of,
498 is_await,
499 } => {
500 let own_label = self.pending_label.take();
501 let is_let_like = matches!(decl_kind, Some(VarKind::Let) | Some(VarKind::Const));
506 let obj = self.eval(object, scope, this)?;
507 if *of && *is_await {
511 let async_iter_method =
512 self.get_property(&obj, "Symbol(Symbol.asyncIterator)")?;
513 if !matches!(async_iter_method, Value::Undefined | Value::Null) {
514 let iterator = self.call_value(&async_iter_method, obj, &[])?;
515 loop {
516 if self.tick() {
517 return Err(Value::Undefined);
518 }
519 let next_fn = self.get_property(&iterator, "next")?;
520 let result = self.call_value(&next_fn, iterator.clone(), &[])?;
521 let awaited = self.await_value(result)?;
522 let done = self.get_property(&awaited, "done")?.truthy();
523 if done {
524 break;
525 }
526 let value = self.get_property(&awaited, "value")?;
527 let iter_scope = if is_let_like { Scope::block(scope.clone()) } else { scope.clone() };
528 self.bind_pattern(pattern, value, &iter_scope, this)?;
529 match self.exec_stmt(body, &iter_scope, this)? {
530 Completion::Break(lbl) if lbl.is_none() || lbl == own_label => {
531 break
532 }
533 Completion::Break(lbl) => return Ok(Completion::Break(lbl)),
534 Completion::Continue(lbl)
535 if lbl.is_none() || lbl == own_label => {}
536 Completion::Continue(lbl) => return Ok(Completion::Continue(lbl)),
537 Completion::Normal(_) => {}
538 ret @ Completion::Return(_) => return Ok(ret),
539 }
540 }
541 return Ok(Completion::Normal(Value::Undefined));
542 }
543 let items = self.iterate_values(&obj, true);
544 for item in items {
545 if self.tick() {
546 return Err(Value::Undefined);
547 }
548 let awaited = self.await_value(item)?;
549 let iter_scope = if is_let_like { Scope::block(scope.clone()) } else { scope.clone() };
550 self.bind_pattern(pattern, awaited, &iter_scope, this)?;
551 match self.exec_stmt(body, &iter_scope, this)? {
552 Completion::Break(lbl) if lbl.is_none() || lbl == own_label => break,
553 Completion::Break(lbl) => return Ok(Completion::Break(lbl)),
554 Completion::Continue(lbl) if lbl.is_none() || lbl == own_label => {}
555 Completion::Continue(lbl) => return Ok(Completion::Continue(lbl)),
556 Completion::Normal(_) => {}
557 ret @ Completion::Return(_) => return Ok(ret),
558 }
559 }
560 return Ok(Completion::Normal(Value::Undefined));
561 }
562 let items = self.iterate_values(&obj, *of);
563 for item in items {
564 if self.tick() {
565 return Err(Value::Undefined);
566 }
567 let iter_scope = if is_let_like { Scope::block(scope.clone()) } else { scope.clone() };
568 self.bind_pattern(pattern, item, &iter_scope, this)?;
569 match self.exec_stmt(body, &iter_scope, this)? {
570 Completion::Break(lbl) if lbl.is_none() || lbl == own_label => break,
571 Completion::Break(lbl) => return Ok(Completion::Break(lbl)),
572 Completion::Continue(lbl) if lbl.is_none() || lbl == own_label => {}
573 Completion::Continue(lbl) => return Ok(Completion::Continue(lbl)),
574 Completion::Normal(_) => {}
575 ret @ Completion::Return(_) => return Ok(ret),
576 }
577 }
578 Ok(Completion::Normal(Value::Undefined))
579 }
580 Statement::Return(e) => {
581 let v = match e {
582 Some(e) => self.eval(e, scope, this)?,
583 None => Value::Undefined,
584 };
585 Ok(Completion::Return(v))
586 }
587 Statement::Break(label) => Ok(Completion::Break(label.clone())),
588 Statement::Continue(label) => Ok(Completion::Continue(label.clone())),
589 Statement::Labeled(label, inner) => {
590 self.pending_label = if matches!(
598 &**inner,
599 Statement::While { .. } | Statement::DoWhile { .. } | Statement::For { .. } | Statement::ForIn { .. }
600 ) {
601 Some(label.clone())
602 } else {
603 None
604 };
605 match self.exec_stmt(inner, scope, this)? {
606 Completion::Break(Some(lbl)) if lbl == *label => {
609 Ok(Completion::Normal(Value::Undefined))
610 }
611 other => Ok(other),
612 }
613 }
614 Statement::Switch {
615 discriminant,
616 cases,
617 } => {
618 let d = self.eval(discriminant, scope, this)?;
619 let mut start = None;
621 for (i, c) in cases.iter().enumerate() {
622 if let Some(test) = &c.test {
623 let tv = self.eval(test, scope, this)?;
624 if d.strict_eq(&tv) {
625 start = Some(i);
626 break;
627 }
628 }
629 }
630 if start.is_none() {
631 start = cases.iter().position(|c| c.test.is_none());
632 }
633 if let Some(s) = start {
634 for c in &cases[s..] {
635 match self.exec_statements(&c.body, scope, this)? {
636 Completion::Break(None) => {
640 return Ok(Completion::Normal(Value::Undefined))
641 }
642 Completion::Normal(_) => {} other => return Ok(other), }
645 }
646 }
647 Ok(Completion::Normal(Value::Undefined))
648 }
649 Statement::Throw(e) => {
650 let v = self.eval(e, scope, this)?;
651 Err(v)
652 }
653 Statement::Try {
654 block,
655 catch_param,
656 catch_block,
657 finally_block,
658 } => {
659 let result = self.exec_statements(block, scope, this);
660 let after_catch = match result {
661 Err(thrown) if !self.aborted && !self.is_suspending() && !self.is_gen_returning() => {
663 if let Some(cb) = catch_block {
664 { static N: core::sync::atomic::AtomicUsize = core::sync::atomic::AtomicUsize::new(0);
666 if N.fetch_add(1, core::sync::atomic::Ordering::Relaxed) < 120 {
667 let top: Vec<String> = self.call_names.iter().rev().take(8).cloned().collect();
668 let msg = super::calls::describe_thrown(&thrown, 1);
669 let first = msg.lines().take(2).collect::<Vec<_>>().join(" / ").chars().take(220).collect::<String>();
670 crate::warn!("[TMPCATCH] {} at {:?}", first, top);
671 }
672 }
673 let inner = Scope::block(scope.clone());
675 if let Some(p) = catch_param {
676 self.bind_pattern(p, thrown, &inner, this)?;
677 }
678 self.exec_statements(cb, &inner, this)
679 } else {
680 Err(thrown)
681 }
682 }
683 other => other,
684 };
685 if self.is_suspending() {
687 return after_catch;
688 }
689 if let Some(fb) = finally_block {
690 let fin = self.exec_statements(fb, scope, this)?;
692 if let Completion::Return(_) | Completion::Break(_) | Completion::Continue(_) = fin {
693 if let Some(r) = &mut self.gen_replay {
694 r.returning = None;
695 }
696 return Ok(fin);
697 }
698 }
699 after_catch
700 }
701 Statement::Import {
702 source,
703 default,
704 namespace,
705 named,
706 side_effect_only,
707 } => {
708 let exports = self.load_module(source)?;
709 if !side_effect_only {
710 let exp = exports.borrow();
711 if let Some(local) = default {
712 let v = exp.get("default").cloned().unwrap_or(Value::Undefined);
713 scope_declare(scope, local, v);
714 }
715 if let Some(ns) = namespace {
716 let o = Obj::plain();
718 {
719 let mut ob = o.borrow_mut();
720 for (k, v) in exp.iter() {
721 ob.props.insert(k.clone(), v.clone());
722 }
723 }
724 scope_declare(scope, ns, Value::Object(o));
725 }
726 for (orig, local) in named {
727 let v = exp.get(orig).cloned().unwrap_or(Value::Undefined);
728 scope_declare(scope, local, v);
729 }
730 }
731 Ok(Completion::Normal(Value::Undefined))
732 }
733 Statement::ExportDefault(expr) => {
734 let v = self.eval(expr, scope, this)?;
735 self.record_export(scope, "default", v);
736 Ok(Completion::Normal(Value::Undefined))
737 }
738 Statement::ExportDecl { declaration, names } => {
739 let c = self.exec_stmt(declaration, scope, this)?;
740 for name in names {
742 let v = scope_get(scope, name).unwrap_or(Value::Undefined);
743 self.record_export(scope, name, v);
744 }
745 Ok(c)
746 }
747 Statement::ExportNamed { specifiers, source } => {
748 match source {
749 Some(src) => {
751 let exports = self.load_module(src)?;
752 let exp = exports.borrow();
753 for (orig, public) in specifiers {
754 let v = exp.get(orig).cloned().unwrap_or(Value::Undefined);
755 self.record_export(scope, public, v);
756 }
757 }
758 None => {
760 for (local, public) in specifiers {
761 let v = scope_get(scope, local).unwrap_or(Value::Undefined);
762 self.record_export(scope, public, v);
763 }
764 }
765 }
766 Ok(Completion::Normal(Value::Undefined))
767 }
768 Statement::ExportAll { source } => {
769 let exports = self.load_module(source)?;
770 let exp = exports.borrow();
771 for (k, v) in exp.iter() {
772 if k != "default" {
774 self.record_export(scope, k, v.clone());
775 }
776 }
777 Ok(Completion::Normal(Value::Undefined))
778 }
779 }
780 }
781
782 pub(crate) fn record_export(&mut self, scope: &Rc<RefCell<Scope>>, name: &str, val: Value) {
785 if let Some(Value::Object(o)) = scope_get(scope, MODULE_EXPORTS_KEY) {
787 o.borrow_mut().props.insert(String::from(name), val);
788 }
789 }
790
791 pub(crate) fn load_module(
794 &mut self,
795 specifier: &str,
796 ) -> Result<Rc<RefCell<BTreeMap<String, Value>>>, Value> {
797 if let Some(rec) = self.modules.borrow().get(specifier) {
799 if let Some(ex) = &rec.exports {
800 return Ok(ex.clone());
801 }
802 }
803 let source = match self.modules.borrow().get(specifier) {
805 Some(rec) => rec.source.clone(),
806 None => {
807 let empty = Rc::new(RefCell::new(BTreeMap::new()));
808 return Ok(empty);
809 }
810 };
811 let exports = Rc::new(RefCell::new(BTreeMap::new()));
813 if let Some(rec) = self.modules.borrow_mut().get_mut(specifier) {
814 rec.exports = Some(exports.clone());
815 }
816 let module_scope = Scope::child(self.global.clone());
819 let collector = Obj::plain();
820 scope_declare(
821 &module_scope,
822 MODULE_EXPORTS_KEY,
823 Value::Object(collector.clone()),
824 );
825 let program = Parser::new_lazy(Lexer::new(&source)).parse_program();
826 let _ = self.exec_statements(&program.body, &module_scope, &Value::Undefined)?;
827 {
829 let cb = collector.borrow();
830 let mut ex = exports.borrow_mut();
831 for (k, v) in cb.props.iter() {
832 ex.insert(k.clone(), v.clone());
833 }
834 }
835 Ok(exports)
836 }
837
838}
839
840pub(crate) fn collect_var_names(stmts: &[Statement], out: &mut Vec<String>) {
843 for s in stmts {
844 collect_var_names_stmt(s, out);
845 }
846}
847
848fn collect_var_names_stmt(s: &Statement, out: &mut Vec<String>) {
849 match s {
850 Statement::VarDeclaration { kind: VarKind::Var, decls, .. } => {
851 for (pat, _) in decls {
852 collect_pattern_names(pat, out);
853 }
854 }
855 Statement::Block(body) => collect_var_names(body, out),
856 Statement::If { consequent, alternate, .. } => {
857 collect_var_names_stmt(consequent, out);
858 if let Some(a) = alternate {
859 collect_var_names_stmt(a, out);
860 }
861 }
862 Statement::While { body, .. } | Statement::DoWhile { body, .. } => collect_var_names_stmt(body, out),
863 Statement::For { init, body, .. } => {
864 if let Some(i) = init {
865 collect_var_names_stmt(i, out);
866 }
867 collect_var_names_stmt(body, out);
868 }
869 Statement::ForIn { decl_kind, pattern, body, .. } => {
870 if matches!(decl_kind, Some(VarKind::Var)) {
871 collect_pattern_names(pattern, out);
872 }
873 collect_var_names_stmt(body, out);
874 }
875 Statement::Labeled(_, body) => collect_var_names_stmt(body, out),
876 Statement::Switch { cases, .. } => {
877 for c in cases {
878 collect_var_names(&c.body, out);
879 }
880 }
881 Statement::Try { block, catch_block, finally_block, .. } => {
882 collect_var_names(block, out);
883 if let Some(b) = catch_block {
884 collect_var_names(b, out);
885 }
886 if let Some(b) = finally_block {
887 collect_var_names(b, out);
888 }
889 }
890 Statement::ExportDecl { declaration, .. } => collect_var_names_stmt(declaration, out),
891 _ => {}
892 }
893}
894
895fn collect_pattern_names(p: &Pattern, out: &mut Vec<String>) {
896 match p {
897 Pattern::Identifier(n) => {
898 if !out.contains(n) {
899 out.push(n.clone());
900 }
901 }
902 Pattern::Object(props) => {
903 for pr in props {
904 collect_pattern_names(&pr.value, out);
905 }
906 }
907 Pattern::Array(elems) => {
908 for e in elems {
909 if let Some(pat) = &e.pattern {
910 collect_pattern_names(pat, out);
911 }
912 }
913 }
914 Pattern::Expr(_) => {}
915 }
916}