1use std::{
2 cell::{RefCell, RefMut},
3 iter::once,
4 mem::take,
5 rc::Rc,
6};
7
8use is_macro::Is;
9use swc_atoms::Atom;
10use swc_common::{
11 comments::Comments, util::take::Take, BytePos, EqIgnoreSpan, Mark, Span, Spanned,
12 SyntaxContext, DUMMY_SP,
13};
14use swc_ecma_ast::*;
15use swc_ecma_transforms_base::helper;
16use swc_ecma_utils::{
17 function::FnEnvHoister, private_ident, prop_name_to_expr_value, quote_ident, ExprFactory,
18};
19use swc_ecma_visit::{
20 noop_visit_mut_type, noop_visit_type, visit_mut_pass, Visit, VisitMut, VisitMutWith, VisitWith,
21};
22use tracing::debug;
23
24pub fn generator<C>(unresolved_mark: Mark, _comments: C) -> impl Pass
26where
27 C: Comments,
28{
29 visit_mut_pass(Wrapper {
30 unresolved_ctxt: SyntaxContext::empty().apply_mark(unresolved_mark),
31 })
32}
33
34struct Wrapper {
36 unresolved_ctxt: SyntaxContext,
37}
38
39macro_rules! dev_span {
40 ($($tt:tt)*) => {{
41 if cfg!(debug_assertions) {
42 Some(tracing::span!(tracing::Level::ERROR, $($tt)*).entered())
43 } else {
44 None
45 }
46 }};
47}
48
49impl VisitMut for Wrapper {
50 noop_visit_mut_type!(fail);
51
52 fn visit_mut_function(&mut self, f: &mut Function) {
53 f.visit_mut_children_with(self);
54
55 if f.is_generator {
56 let mut v = Generator::default();
57
58 let mut hoister = FnEnvHoister::new(self.unresolved_ctxt);
59 hoister.disable_super();
60 hoister.disable_this();
61
62 f.visit_mut_children_with(&mut hoister);
63
64 v.transform_and_emit_stmts(f.body.as_mut().unwrap().stmts.take(), 0);
65 f.is_generator = false;
66
67 let mut stmts = v.build_stmts();
68 stmts.visit_mut_with(&mut InvalidToLit {
69 map: v.label_exprs.as_deref(),
70 });
71 let inner_fn = Box::new(Function {
72 span: DUMMY_SP,
73 params: vec![Param {
74 span: DUMMY_SP,
75 decorators: Default::default(),
76 pat: Pat::Ident(v.state.clone().into()),
77 }],
78 decorators: Default::default(),
79 body: Some(BlockStmt {
80 stmts,
81 ..Default::default()
82 }),
83 is_generator: false,
84 is_async: false,
85 ..Default::default()
86 });
87 let generator_object = CallExpr {
88 span: DUMMY_SP,
89 callee: helper!(ts, ts_generator),
90 args: vec![
91 ThisExpr { span: DUMMY_SP }.as_arg(),
92 FnExpr {
93 ident: None,
94 function: inner_fn,
95 }
96 .as_arg(),
97 ],
98 ..Default::default()
99 }
100 .into();
101 let mut stmts = Vec::new();
102 if !v.hoisted_vars.is_empty() {
103 stmts.push(
104 VarDecl {
105 span: DUMMY_SP,
106 kind: VarDeclKind::Var,
107 declare: Default::default(),
108 decls: v.hoisted_vars.take(),
109 ..Default::default()
110 }
111 .into(),
112 )
113 }
114 let vars = hoister.to_decl();
115 if !vars.is_empty() {
116 stmts.push(
117 VarDecl {
118 span: DUMMY_SP,
119 kind: VarDeclKind::Var,
120 declare: Default::default(),
121 decls: vars,
122 ..Default::default()
123 }
124 .into(),
125 )
126 }
127 stmts.extend(v.hoisted_fns.into_iter().map(Decl::Fn).map(Stmt::Decl));
128
129 stmts.push(
130 ReturnStmt {
131 span: DUMMY_SP,
132 arg: Some(generator_object),
133 }
134 .into(),
135 );
136 f.body.as_mut().unwrap().stmts = stmts;
137 }
138 }
139}
140
141#[derive(Debug, Clone, Copy, PartialEq, Eq)]
142struct Label(isize);
143
144#[derive(Debug, Clone, Copy, PartialEq, Eq)]
145enum OpCode {
146 Nop,
148 Statement,
150 Assign,
152 Break,
154 BreakWhenTrue,
157 BreakWhenFalse,
160 Yield,
162 YieldStar,
165 Return,
167 Throw,
169 Endfinally,
171}
172
173#[derive(Debug, Is, Clone)]
174enum OpArgs {
175 Label(Label),
176 LabelExpr(Label, Box<Expr>),
177 Stmt(Box<Stmt>),
178 OptExpr(Option<Box<Expr>>),
179 PatAndExpr(AssignTarget, Box<Expr>),
180}
181
182#[derive(Debug, Clone, Copy, PartialEq, Eq)]
185enum BlockAction {
186 Open,
187 Close,
188}
189
190#[derive(Debug, Clone, Copy, PartialEq, Eq)]
192enum CodeBlockKind {
193 Exception,
194 With,
195 Switch,
196 Loop,
197 Labeled,
198}
199
200#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
202enum ExceptionBlockState {
203 Try,
204 Catch,
205 Finally,
206 Done,
207}
208
209#[derive(Debug)]
211enum CodeBlock {
212 Exception(ExceptionBlock),
213 Labeled(LabeledBlock),
214 Switch(SwitchBlock),
215 Loop(LoopBlock),
216 With(WithBlock),
217}
218
219impl CodeBlock {
220 fn is_script(&self) -> bool {
221 match self {
222 Self::Exception(..) => false,
223 Self::Labeled(b) => b.is_script,
224 Self::Switch(b) => b.is_script,
225 Self::Loop(b) => b.is_script,
226 Self::With(..) => false,
227 }
228 }
229
230 fn label_text(&self) -> Option<Atom> {
231 match self {
232 Self::Labeled(s) => Some(s.label_text.clone()),
233 _ => None,
234 }
235 }
236
237 fn break_label(&self) -> Option<Label> {
238 Some(match self {
239 Self::Labeled(b) => b.break_label,
240 Self::Switch(b) => b.break_label,
241 Self::Loop(b) => b.break_label,
242 _ => return None,
243 })
244 }
245
246 fn continue_label(&self) -> Option<Label> {
247 Some(match self {
248 Self::Loop(b) => b.continue_label,
249 _ => return None,
250 })
251 }
252}
253
254#[derive(Debug)]
256struct ExceptionBlock {
257 state: ExceptionBlockState,
258 start_label: Label,
259 catch_variable: Option<Ident>,
260 catch_label: Option<Label>,
261 finally_label: Option<Label>,
262 end_label: Label,
263}
264
265#[derive(Debug)]
268struct LabeledBlock {
269 label_text: Atom,
270 is_script: bool,
271 break_label: Label,
272}
273
274#[derive(Debug)]
277struct SwitchBlock {
278 is_script: bool,
279 break_label: Label,
280}
281
282#[derive(Debug)]
286struct LoopBlock {
287 continue_label: Label,
288 is_script: bool,
289 break_label: Label,
290}
291
292#[allow(unused)]
294#[derive(Debug)]
295struct WithBlock {
296 expression: Ident,
297 start_label: Label,
298 end_label: Label,
299}
300
301#[allow(dead_code)]
302#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
303enum Instruction {
304 Next = 0,
305 Throw = 1,
306 Return = 2,
307 Break = 3,
308 Yield = 4,
309 YieldStar = 5,
310 Catch = 6,
311 Endfinally = 7,
312}
313
314impl Instruction {
315 }
326
327struct Generator {
328 in_statement_containing_yield: bool,
329
330 blocks: Option<Vec<Ptr<CodeBlock>>>,
331 block_offsets: Option<Vec<usize>>,
332 block_actions: Option<Vec<BlockAction>>,
333 block_stack: Option<Vec<Ptr<CodeBlock>>>,
335
336 label_offsets: Option<Vec<i32>>,
337 label_exprs: Option<Vec<Vec<Loc>>>,
338 next_label_id: usize,
339
340 operations: Option<Vec<OpCode>>,
341 operation_args: Option<Vec<Option<OpArgs>>>,
342 operation_locs: Option<Vec<Span>>,
343
344 state: Ident,
345
346 block_index: usize,
347 label_number: usize,
348 label_numbers: Option<Vec<Vec<usize>>>,
349 last_operation_was_abrupt: bool,
350 last_operation_was_completion: bool,
351 clauses: Option<Vec<SwitchCase>>,
352 stmts: Option<Vec<Stmt>>,
353 exception_block_stack: Option<Vec<Ptr<CodeBlock>>>,
355 current_exception_block: Option<Ptr<CodeBlock>>,
357 with_block_stack: Option<Vec<Ptr<CodeBlock>>>,
359
360 hoisted_vars: Vec<VarDeclarator>,
361 hoisted_fns: Vec<FnDecl>,
362}
363
364type Ptr<T> = Rc<RefCell<T>>;
365
366impl Default for Generator {
367 fn default() -> Self {
368 Self {
369 in_statement_containing_yield: Default::default(),
370 blocks: Default::default(),
371 block_offsets: Default::default(),
372 block_actions: Default::default(),
373 block_stack: Default::default(),
374 label_offsets: Default::default(),
375 label_exprs: Default::default(),
376 next_label_id: 1,
377 operations: Default::default(),
378 operation_args: Default::default(),
379 operation_locs: Default::default(),
380 state: private_ident!("_state"),
381 block_index: Default::default(),
382 label_number: Default::default(),
383 label_numbers: Default::default(),
384 last_operation_was_abrupt: Default::default(),
385 last_operation_was_completion: Default::default(),
386 clauses: Default::default(),
387 stmts: Default::default(),
388 exception_block_stack: Default::default(),
389 current_exception_block: Default::default(),
390 with_block_stack: Default::default(),
391 hoisted_vars: Default::default(),
392 hoisted_fns: Default::default(),
393 }
394 }
395}
396
397impl VisitMut for Generator {
398 noop_visit_mut_type!(fail);
399
400 fn visit_mut_arrow_expr(&mut self, e: &mut ArrowExpr) {
401 e.params.visit_mut_with(self);
402 }
403
404 fn visit_mut_function(&mut self, e: &mut Function) {
405 e.params.visit_mut_with(self);
406 }
407
408 fn visit_mut_getter_prop(&mut self, _: &mut GetterProp) {}
409
410 fn visit_mut_setter_prop(&mut self, e: &mut SetterProp) {
411 e.param.visit_mut_with(self);
412 }
413
414 fn visit_mut_expr(&mut self, e: &mut Expr) {
415 match e {
416 Expr::Yield(node) => {
417 let resume_label = self.define_label();
426 node.arg.visit_mut_with(self);
427 if node.delegate {
428 let arg = node
429 .arg
430 .take()
431 .map(|e| CallExpr {
432 span: DUMMY_SP,
433 callee: helper!(ts, ts_values),
434 args: vec![e.as_arg()],
435 ..Default::default()
436 })
437 .map(Expr::from)
438 .map(Box::new);
439 self.emit_yield_star(arg, Some(node.span))
440 } else {
441 self.emit_yield(node.arg.take(), Some(node.span));
442 }
443
444 self.mark_label(resume_label);
445
446 *e = *self.create_generator_resume(Some(node.span));
447 }
448
449 Expr::Cond(node) => {
450 if contains_yield(&node.cons) || contains_yield(&node.alt) {
471 let when_false_label = self.define_label();
472 let result_label = self.define_label();
473 let result_local = self.declare_local(None);
474
475 node.test.visit_mut_with(self);
476 let cond_span = node.test.span();
477 self.emit_break_when_false(when_false_label, node.test.take(), Some(cond_span));
478
479 let cons_span = node.cons.span();
480 node.cons.visit_mut_with(self);
481 self.emit_assignment(
482 result_local.clone().into(),
483 node.cons.take(),
484 Some(cons_span),
485 );
486 self.emit_break(result_label, None);
487
488 self.mark_label(when_false_label);
489 let alt_span = node.cons.span();
490 node.alt.visit_mut_with(self);
491 self.emit_assignment(
492 result_local.clone().into(),
493 node.alt.take(),
494 Some(alt_span),
495 );
496
497 self.mark_label(result_label);
498
499 *e = result_local.into();
500 } else {
501 node.visit_mut_with(self);
502 }
503 }
504
505 Expr::Bin(node) => {
506 if node.op == op!("**") {
507 todo!("right-associative binary expression")
508 } else {
509 let new = self.visit_left_associative_bin_expr(node);
510 if let Some(new) = new {
511 *e = new;
512 }
513 }
514 }
515
516 Expr::Seq(node) => {
517 let mut pending_expressions = Vec::new();
519
520 for mut elem in node.exprs.take() {
521 if let Expr::Seq(mut elem) = *elem {
522 elem.visit_mut_with(self);
523 pending_expressions.extend(elem.exprs.take());
524 } else {
525 if contains_yield(&elem) && !pending_expressions.is_empty() {
526 self.emit_worker(
527 OpCode::Statement,
528 Some(OpArgs::Stmt(Box::new(
529 ExprStmt {
530 span: DUMMY_SP,
531 expr: if pending_expressions.len() == 1 {
532 pending_expressions.remove(0)
533 } else {
534 SeqExpr {
535 span: DUMMY_SP,
536 exprs: pending_expressions.take(),
537 }
538 .into()
539 },
540 }
541 .into(),
542 ))),
543 None,
544 );
545 }
546 elem.visit_mut_with(self);
547 pending_expressions.push(elem);
548 }
549 }
550
551 if pending_expressions.len() == 1 {
552 *e = *pending_expressions.remove(0);
553 } else {
554 node.exprs = pending_expressions;
555 }
556 }
557
558 Expr::Member(MemberExpr {
559 obj,
560 prop: MemberProp::Computed(prop),
561 ..
562 }) => {
563 if contains_yield(prop) {
564 *obj = self.cache_expression(obj.take()).into();
575 prop.visit_mut_with(self);
576 return;
577 }
578
579 e.visit_mut_children_with(self);
580 }
581
582 Expr::Assign(node) if contains_yield(&node.right) => {
583 match node.left.as_mut_simple() {
584 Some(SimpleAssignTarget::Member(left)) => {
585 match &mut left.prop {
586 MemberProp::Ident(..) | MemberProp::PrivateName(..) => {
587 left.obj.visit_mut_with(self);
597 let obj = self.cache_expression(left.obj.take());
598
599 left.obj = obj.into();
600 }
601 MemberProp::Computed(prop) => {
602 let prop_span = prop.span;
613
614 left.obj.visit_mut_with(self);
615 let obj = self.cache_expression(left.obj.take());
616
617 prop.visit_mut_with(self);
618 let prop = self.cache_expression(prop.expr.take());
619
620 left.obj = obj.into();
621 left.prop = MemberProp::Computed(ComputedPropName {
622 span: prop_span,
623 expr: prop.into(),
624 });
625 }
626 }
627 }
629 _ => {
630 node.left.visit_mut_with(self);
631 }
632 }
633 if node.op != op!("=") {
634 let left_of_right =
635 self.cache_expression(node.left.take().expect_simple().into());
636
637 node.right.visit_mut_with(self);
638
639 *e = AssignExpr {
640 span: node.right.span(),
641 op: node.op,
642 left: left_of_right.into(),
643 right: node.right.take(),
644 }
645 .into();
646 } else {
647 node.right.visit_mut_with(self);
648 }
649 }
650
651 Expr::Object(node) if node.props.iter().any(contains_yield) => {
652 let num_initial_properties = self.count_initial_nodes_without_yield(&node.props);
671
672 let mut temp = self.declare_local(None);
673 node.props
674 .iter_mut()
675 .take(num_initial_properties)
676 .for_each(|p| {
677 p.visit_mut_with(self);
678 });
679
680 self.emit_assignment(
681 temp.clone().into(),
682 ObjectLit {
683 span: DUMMY_SP,
684 props: node
685 .props
686 .iter_mut()
687 .take(num_initial_properties)
688 .map(|v| v.take())
689 .collect(),
690 }
691 .into(),
692 None,
693 );
694
695 let mut expressions = node
696 .props
697 .iter_mut()
698 .skip(num_initial_properties)
699 .map(|v| v.take())
700 .fold(Vec::<CompiledProp>::new(), |mut props, p| {
701 match p {
702 PropOrSpread::Spread(_) => {
703 unreachable!("spread should be removed before applying generator")
704 }
705 PropOrSpread::Prop(p) => match *p {
706 Prop::Getter(p) => {
707 if let Some(CompiledProp::Accessor(g, _)) =
708 props.iter_mut().find(|prev| match prev {
709 CompiledProp::Accessor(_, Some(s)) => {
710 s.key.eq_ignore_span(&p.key)
711 }
712 _ => false,
713 })
714 {
715 *g = Some(p);
716 } else {
717 props.push(CompiledProp::Accessor(Some(p), None))
718 }
719 }
720 Prop::Setter(p) => {
721 if let Some(CompiledProp::Accessor(_, s)) =
722 props.iter_mut().find(|prev| match prev {
723 CompiledProp::Accessor(Some(prev), _) => {
724 prev.key.eq_ignore_span(&p.key)
725 }
726 _ => false,
727 })
728 {
729 *s = Some(p);
730 } else {
731 props.push(CompiledProp::Accessor(None, Some(p)))
732 }
733 }
734 p => {
735 props.push(CompiledProp::Prop(p));
736 }
737 },
738 }
739
740 props
741 })
742 .into_iter()
743 .fold(Vec::new(), |exprs, property| {
744 self.reduce_property(exprs, property, &mut temp)
745 });
746
747 expressions.push(temp.into());
748
749 *e = *Expr::from_exprs(expressions);
750 }
751
752 Expr::Array(node) => {
753 *e = self.visit_elements(&mut node.elems, None, None);
754 }
755
756 _ => {
757 e.visit_mut_children_with(self);
758 }
759 }
760 }
761
762 fn visit_mut_call_expr(&mut self, node: &mut CallExpr) {
763 if !node.callee.is_import() && node.args.iter().any(contains_yield) {
764 node.callee.visit_mut_with(self);
776
777 let (target, this_arg) =
778 self.create_call_binding(node.callee.take().expect_expr(), false);
779
780 let callee = self.cache_expression(target);
781
782 let mut args = node.args.take().into_iter().map(Some).collect::<Vec<_>>();
783 let arg = self.visit_elements(&mut args, None, None);
784
785 let apply = callee.make_member(quote_ident!("apply"));
786
787 *node = CallExpr {
788 span: node.span,
789 callee: apply.as_callee(),
790 args: once(this_arg.as_arg()).chain(once(arg.as_arg())).collect(),
791 ..Default::default()
792 };
793 return;
794 }
795
796 node.visit_mut_children_with(self);
797 }
798
799 fn visit_mut_new_expr(&mut self, node: &mut NewExpr) {
800 if contains_yield(&node.args) {
801 node.callee.visit_mut_with(self);
813
814 let (target, this_arg) = self.create_call_binding(node.callee.take(), true);
815
816 let callee = self.cache_expression(target.make_member(quote_ident!("bind")).into());
817
818 let mut arg = if let Some(args) = node.args.take() {
819 let mut args = args.into_iter().map(Some).collect::<Vec<_>>();
820 Some(self.visit_elements(
821 &mut args,
822 Some(ExprOrSpread {
823 spread: None,
824 expr: Expr::undefined(DUMMY_SP),
825 }),
826 None,
827 ))
828 } else {
829 None
830 };
831
832 let apply = callee.apply(
833 node.span,
834 this_arg,
835 arg.take().map(|v| v.as_arg()).into_iter().collect(),
836 );
837
838 *node = NewExpr {
839 span: node.span,
840 callee: Box::new(apply),
841 args: None,
842 ..Default::default()
843 };
844 return;
845 }
846
847 node.visit_mut_children_with(self);
848 }
849
850 fn visit_mut_for_stmt(&mut self, node: &mut ForStmt) {
851 if self.in_statement_containing_yield {
852 self.begin_script_loop_block();
853 }
854
855 if let Some(VarDeclOrExpr::VarDecl(initializer)) = &mut node.init {
856 for variable in initializer.decls.iter_mut() {
857 self.hoist_variable_declaration(&Ident::from(variable.name.as_ident().unwrap()));
858 }
859
860 let variables = self.get_initialized_variables(initializer);
861
862 let mut exprs = variables
863 .into_iter()
864 .filter_map(|v| self.transform_initialized_variable(v.take()))
865 .map(Expr::from)
866 .map(Box::new)
867 .collect::<Vec<_>>();
868 node.init = if exprs.is_empty() {
869 None
870 } else {
871 Some(VarDeclOrExpr::Expr(if exprs.len() == 1 {
872 exprs.remove(0)
873 } else {
874 SeqExpr {
875 span: DUMMY_SP,
876 exprs,
877 }
878 .into()
879 }))
880 };
881 node.test.visit_mut_with(self);
882 node.update.visit_mut_with(self);
883 node.body.visit_mut_with(self);
884 } else {
885 node.visit_mut_children_with(self);
886 }
887
888 if self.in_statement_containing_yield {
889 self.end_loop_block();
890 }
891 }
892
893 fn visit_mut_do_while_stmt(&mut self, node: &mut DoWhileStmt) {
894 if self.in_statement_containing_yield {
895 self.begin_script_loop_block();
896 node.visit_mut_children_with(self);
897 self.end_loop_block();
898 } else {
899 node.visit_mut_children_with(self);
900 }
901 }
902
903 fn visit_mut_while_stmt(&mut self, node: &mut WhileStmt) {
904 if self.in_statement_containing_yield {
905 self.begin_script_loop_block();
906 node.visit_mut_children_with(self);
907 self.end_loop_block();
908 } else {
909 node.visit_mut_children_with(self);
910 }
911 }
912
913 fn visit_mut_return_stmt(&mut self, node: &mut ReturnStmt) {
914 node.arg.visit_mut_with(self);
915
916 *node = self.create_inline_return(node.arg.take(), Some(node.span));
917 }
918
919 fn visit_mut_switch_stmt(&mut self, node: &mut SwitchStmt) {
920 if self.in_statement_containing_yield {
921 self.begin_script_switch_block();
922 }
923
924 node.visit_mut_children_with(self);
925
926 if self.in_statement_containing_yield {
927 self.end_switch_block();
928 }
929 }
930
931 fn visit_mut_labeled_stmt(&mut self, node: &mut LabeledStmt) {
932 if self.in_statement_containing_yield {
933 self.begin_script_labeled_block(node.label.sym.clone());
934 }
935
936 node.visit_mut_children_with(self);
937
938 if self.in_statement_containing_yield {
939 self.end_labeled_block();
940 }
941 }
942
943 fn visit_mut_for_in_stmt(&mut self, node: &mut ForInStmt) {
944 if self.in_statement_containing_yield {
958 self.begin_script_loop_block();
959 }
960
961 if let ForHead::VarDecl(initializer) = &mut node.left {
962 for variable in &initializer.decls {
963 self.hoist_variable_declaration(&Ident::from(variable.name.as_ident().unwrap()));
964 }
965
966 node.right.visit_mut_with(self);
967 node.body.visit_mut_with(self);
968 } else {
969 node.visit_mut_children_with(self);
970 }
971
972 if self.in_statement_containing_yield {
973 self.end_loop_block();
974 }
975 }
976
977 #[tracing::instrument(level = "debug", skip_all)]
978 fn visit_mut_stmt(&mut self, node: &mut Stmt) {
979 match node {
980 Stmt::Break(b) => {
981 if self.in_statement_containing_yield {
982 let label = self.find_break_target(b.label.as_ref().map(|l| l.sym.clone()));
983 if label.0 > 0 {
984 *node = self.create_inline_break(label, Some(b.span)).into();
985 return;
986 }
987 }
988
989 node.visit_mut_children_with(self);
990 }
991 Stmt::Continue(s) => {
992 if self.in_statement_containing_yield {
993 let label = self.find_continue_target(s.label.as_ref().map(|l| l.sym.clone()));
994 if label.0 > 0 {
995 *node = self.create_inline_break(label, Some(s.span)).into();
996 return;
997 }
998 }
999
1000 node.visit_mut_children_with(self);
1001 }
1002
1003 Stmt::Decl(Decl::Var(v)) => {
1004 if contains_yield(&*v) {
1005 self.transform_and_emit_var_decl_list(v.take());
1006 node.take();
1007 return;
1008 }
1009
1010 for decl in v.decls.iter() {
1016 self.hoist_variable_declaration(&Ident::from(decl.name.as_ident().unwrap()));
1017 }
1018
1019 let variables = self.get_initialized_variables(v);
1020 if variables.is_empty() {
1021 node.take();
1022 return;
1023 }
1024
1025 let mut exprs = variables
1026 .into_iter()
1027 .filter_map(|v| self.transform_initialized_variable(v.take()))
1028 .map(Expr::from)
1029 .map(Box::new)
1030 .collect::<Vec<_>>();
1031
1032 if exprs.is_empty() {
1033 node.take();
1034 return;
1035 }
1036
1037 *node = ExprStmt {
1038 span: v.span,
1039 expr: if exprs.len() == 1 {
1040 exprs.remove(0)
1041 } else {
1042 SeqExpr {
1043 span: DUMMY_SP,
1044 exprs,
1045 }
1046 .into()
1047 },
1048 }
1049 .into();
1050 }
1051 Stmt::Decl(Decl::Fn(f)) => {
1052 self.hoisted_fns.push(f.take());
1053 node.take();
1054 }
1055 _ => {
1056 node.visit_mut_children_with(self);
1057 }
1058 }
1059 }
1060}
1061
1062enum CompiledProp {
1063 Prop(Prop),
1064 Accessor(Option<GetterProp>, Option<SetterProp>),
1065}
1066
1067impl Generator {
1068 fn visit_elements(
1069 &mut self,
1070 elements: &mut [Option<ExprOrSpread>],
1071 mut leading_element: Option<ExprOrSpread>,
1072 _loc: Option<Span>,
1073 ) -> Expr {
1074 let num_initial_elements = self.count_initial_nodes_without_yield(elements);
1085
1086 let mut temp = None;
1087 if num_initial_elements > 0 {
1088 temp = Some(self.declare_local(None));
1089
1090 elements[0..num_initial_elements]
1091 .iter_mut()
1092 .for_each(|e| e.visit_mut_with(self));
1093
1094 self.emit_assignment(
1095 temp.clone().unwrap().into(),
1096 ArrayLit {
1097 span: DUMMY_SP,
1098 elems: leading_element
1099 .take()
1100 .into_iter()
1101 .map(Some)
1102 .chain(
1103 elements
1104 .iter_mut()
1105 .take(num_initial_elements)
1106 .map(|e| e.take()),
1107 )
1108 .collect(),
1109 }
1110 .into(),
1111 None,
1112 );
1113 }
1114
1115 let mut expressions = elements
1116 .iter_mut()
1117 .skip(num_initial_elements)
1118 .map(|v| v.take())
1119 .fold(Vec::new(), |exprs, element| {
1120 self.reduce_element(exprs, element, &mut leading_element, &mut temp)
1121 });
1122
1123 if let Some(temp) = temp {
1124 CallExpr {
1125 span: DUMMY_SP,
1126 callee: temp.make_member(quote_ident!("concat")).as_callee(),
1127 args: vec![ExprOrSpread {
1128 spread: None,
1129 expr: Box::new(Expr::Array(ArrayLit {
1130 span: DUMMY_SP,
1131 elems: expressions
1132 .take()
1133 .into_iter()
1134 .map(|expr| match expr {
1135 Some(expr_or_spread) => match &*expr_or_spread.expr {
1136 Expr::Invalid(_) => None,
1137 _ => Some(expr_or_spread),
1138 },
1139 None => None,
1140 })
1141 .collect(),
1142 })),
1143 }],
1144 ..Default::default()
1145 }
1146 .into()
1147 } else {
1148 ArrayLit {
1149 span: DUMMY_SP,
1150 elems: leading_element
1151 .take()
1152 .into_iter()
1153 .map(Some)
1154 .chain(expressions.take().into_iter().map(|expr| match expr {
1155 Some(expr_or_spread) => match &*expr_or_spread.expr {
1156 Expr::Invalid(_) => None,
1157 _ => Some(expr_or_spread),
1158 },
1159 None => None,
1160 }))
1161 .collect(),
1162 }
1163 .into()
1164 }
1165 }
1166
1167 fn reduce_element(
1168 &mut self,
1169 mut expressions: Vec<Option<ExprOrSpread>>,
1170 mut element: Option<ExprOrSpread>,
1171 leading_element: &mut Option<ExprOrSpread>,
1172 temp: &mut Option<Ident>,
1173 ) -> Vec<Option<ExprOrSpread>> {
1174 if contains_yield(&element) && !expressions.is_empty() {
1175 let has_assigned_temp = temp.is_some();
1176 if temp.is_none() {
1177 *temp = Some(self.declare_local(None));
1178 }
1179
1180 self.emit_assignment(
1181 temp.clone().unwrap().into(),
1182 if has_assigned_temp {
1183 CallExpr {
1184 span: DUMMY_SP,
1185 callee: temp
1186 .clone()
1187 .unwrap()
1188 .make_member(quote_ident!("concat"))
1189 .as_callee(),
1190 args: vec![Box::new(Expr::Array(ArrayLit {
1191 span: DUMMY_SP,
1192 elems: expressions
1193 .take()
1194 .into_iter()
1195 .map(|expr| match expr {
1196 Some(expr_or_spread) => match &*expr_or_spread.expr {
1197 Expr::Invalid(_) => None,
1198 _ => Some(expr_or_spread),
1199 },
1200 None => None,
1201 })
1202 .collect(),
1203 }))
1204 .as_arg()],
1205 ..Default::default()
1206 }
1207 .into()
1208 } else {
1209 Box::new(
1210 ArrayLit {
1211 span: DUMMY_SP,
1212 elems: leading_element
1213 .take()
1214 .into_iter()
1215 .map(Some)
1216 .chain(expressions.take().into_iter().map(|expr| match expr {
1217 Some(expr_or_spread) => match &*expr_or_spread.expr {
1218 Expr::Invalid(_) => None,
1219 _ => Some(expr_or_spread),
1220 },
1221 None => None,
1222 }))
1223 .collect(),
1224 }
1225 .into(),
1226 )
1227 },
1228 None,
1229 );
1230 *leading_element = None;
1231 }
1232
1233 element.visit_mut_with(self);
1234 expressions.push(element);
1235 expressions
1236 }
1237
1238 fn reduce_property(
1239 &mut self,
1240 mut expressions: Vec<Box<Expr>>,
1241 property: CompiledProp,
1242 temp: &mut Ident,
1243 ) -> Vec<Box<Expr>> {
1244 if match &property {
1245 CompiledProp::Prop(p) => contains_yield(p),
1246 CompiledProp::Accessor(g, s) => {
1247 g.as_ref().is_some_and(contains_yield) || s.as_ref().is_some_and(contains_yield)
1248 }
1249 } && !expressions.is_empty()
1250 {
1251 self.emit_stmt(
1252 ExprStmt {
1253 span: DUMMY_SP,
1254 expr: Expr::from_exprs(expressions.take()),
1255 }
1256 .into(),
1257 );
1258 }
1259
1260 let mut expression: Expr = match property {
1261 CompiledProp::Prop(p) => match p {
1262 Prop::Shorthand(p) => AssignExpr {
1263 span: p.span,
1264 op: op!("="),
1265 left: MemberExpr {
1266 span: DUMMY_SP,
1267 obj: temp.clone().into(),
1268 prop: MemberProp::Ident(p.clone().into()),
1269 }
1270 .into(),
1271 right: p.into(),
1272 }
1273 .into(),
1274 Prop::KeyValue(p) => AssignExpr {
1275 span: DUMMY_SP,
1276 op: op!("="),
1277 left: MemberExpr {
1278 span: DUMMY_SP,
1279 obj: temp.clone().into(),
1280 prop: p.key.into(),
1281 }
1282 .into(),
1283 right: p.value,
1284 }
1285 .into(),
1286 Prop::Assign(_) => {
1287 unreachable!("assignment property be removed before generator pass")
1288 }
1289 Prop::Getter(_) | Prop::Setter(_) => {
1290 unreachable!("getter/setter property be compiled as CompiledProp::Accessor")
1291 }
1292 Prop::Method(p) => AssignExpr {
1293 span: DUMMY_SP,
1294 op: op!("="),
1295 left: MemberExpr {
1296 span: DUMMY_SP,
1297 obj: temp.clone().into(),
1298 prop: p.key.into(),
1299 }
1300 .into(),
1301 right: p.function.into(),
1302 }
1303 .into(),
1304 },
1305 CompiledProp::Accessor(getter, setter) => {
1306 let key = getter
1307 .as_ref()
1308 .map(|v| v.key.clone())
1309 .unwrap_or_else(|| setter.as_ref().unwrap().key.clone());
1310
1311 let desc = ObjectLit {
1312 span: DUMMY_SP,
1313 props: getter
1314 .map(|g| KeyValueProp {
1315 key: quote_ident!("get").into(),
1316 value: Function {
1317 params: Vec::new(),
1318 span: g.span,
1319 body: g.body,
1320 is_generator: false,
1321 is_async: false,
1322 ..Default::default()
1323 }
1324 .into(),
1325 })
1326 .into_iter()
1327 .chain(setter.map(|s| {
1328 KeyValueProp {
1329 key: quote_ident!("set").into(),
1330 value: Function {
1331 params: vec![(*s.param).into()],
1332 span: s.span,
1333 body: s.body,
1334 is_generator: false,
1335 is_async: false,
1336 ..Default::default()
1337 }
1338 .into(),
1339 }
1340 }))
1341 .map(Prop::KeyValue)
1342 .map(Box::new)
1343 .map(PropOrSpread::Prop)
1344 .collect(),
1345 };
1346
1347 CallExpr {
1348 span: DUMMY_SP,
1349 callee: helper!(define_property),
1350 args: vec![
1351 temp.clone().as_arg(),
1352 prop_name_to_expr_value(key).as_arg(),
1353 desc.as_arg(),
1354 ],
1355 ..Default::default()
1356 }
1357 .into()
1358 }
1359 };
1360
1361 expression.visit_mut_with(self);
1362 if !expression.is_invalid() {
1363 expressions.push(Box::new(expression));
1364 }
1365 expressions
1366 }
1367
1368 fn visit_left_associative_bin_expr(&mut self, node: &mut BinExpr) -> Option<Expr> {
1369 if contains_yield(&node.right) {
1370 if matches!(node.op, op!("||") | op!("&&")) {
1371 return Some(self.visit_logical_bin_expr(node));
1372 }
1373
1374 node.left.visit_mut_with(self);
1384 node.left = self.cache_expression(node.left.take()).into();
1385 node.right.visit_mut_with(self);
1386 return None;
1387 }
1388
1389 node.visit_mut_children_with(self);
1390 None
1391 }
1392
1393 fn visit_logical_bin_expr(&mut self, node: &mut BinExpr) -> Expr {
1394 let result_label = self.define_label();
1424 let result_local = self.declare_local(None);
1425
1426 let left_span = node.left.span();
1427 node.left.visit_mut_with(self);
1428 self.emit_assignment(
1429 result_local.clone().into(),
1430 node.left.take(),
1431 Some(left_span),
1432 );
1433
1434 if node.op == op!("&&") {
1435 self.emit_break_when_false(
1437 result_label,
1438 Box::new(result_local.clone().into()),
1439 Some(left_span),
1440 )
1441 } else {
1442 self.emit_break_when_true(
1444 result_label,
1445 Box::new(result_local.clone().into()),
1446 Some(left_span),
1447 )
1448 }
1449
1450 let right_span = node.right.span();
1451 node.right.visit_mut_with(self);
1452 self.emit_assignment(
1453 result_local.clone().into(),
1454 node.right.take(),
1455 Some(right_span),
1456 );
1457 self.mark_label(result_label);
1458
1459 result_local.into()
1460 }
1461
1462 fn transform_and_emit_stmts(&mut self, stmts: Vec<Stmt>, start: usize) {
1463 for s in stmts.into_iter().skip(start) {
1464 self.transform_and_emit_stmt(s);
1465 }
1466 }
1467
1468 fn transform_and_emit_embedded_stmt(&mut self, node: Stmt) {
1469 if let Stmt::Block(block) = node {
1470 self.transform_and_emit_stmts(block.stmts, 0);
1471 } else {
1472 self.transform_and_emit_stmt(node);
1473 }
1474 }
1475
1476 fn transform_and_emit_stmt(&mut self, node: Stmt) {
1477 let _tracing = dev_span!("transform_and_emit_stmt");
1478
1479 let saved_in_statement_containing_yield = self.in_statement_containing_yield;
1480 if !self.in_statement_containing_yield {
1481 self.in_statement_containing_yield = contains_yield(&node);
1482 }
1483
1484 self.transform_and_emit_stmt_worker(node);
1485 self.in_statement_containing_yield = saved_in_statement_containing_yield;
1486 }
1487
1488 fn transform_and_emit_stmt_worker(&mut self, mut node: Stmt) {
1489 match node {
1490 Stmt::Block(s) => self.transform_and_emit_block(s),
1491 Stmt::Expr(s) => self.transform_and_emit_expr_stmt(s),
1492 Stmt::If(s) => self.transform_and_emit_if_stmt(s),
1493 Stmt::DoWhile(s) => self.transform_and_emit_do_stmt(s),
1494 Stmt::While(s) => self.transform_and_emit_while_stmt(s),
1495 Stmt::For(s) => self.transform_and_emit_for_stmt(s),
1496 Stmt::ForIn(s) => self.transform_and_emit_for_in_stmt(s),
1497 Stmt::Continue(s) => self.transform_and_emit_continue_stmt(s),
1498 Stmt::Break(s) => self.transform_and_emit_break_stmt(s),
1499 Stmt::Return(s) => self.transform_and_emit_return_stmt(s),
1500 Stmt::With(s) => self.transform_and_emit_with_stmt(s),
1501 Stmt::Switch(s) => self.transform_and_emit_switch_stmt(s),
1502 Stmt::Labeled(s) => self.transform_and_emit_labeled_stmt(s),
1503 Stmt::Throw(s) => self.transform_and_emit_throw_stmt(s),
1504 Stmt::Try(s) => self.transform_and_emit_try_stmt(*s),
1505 _ => {
1506 node.visit_mut_with(self);
1507
1508 self.emit_stmt(node);
1509 }
1510 }
1511 }
1512
1513 fn transform_and_emit_block(&mut self, mut node: BlockStmt) {
1514 if contains_yield(&node) {
1515 self.transform_and_emit_stmts(node.stmts, 0);
1516 } else {
1517 node.visit_mut_with(self);
1518 self.emit_stmt(node.into());
1519 }
1520 }
1521
1522 fn transform_and_emit_expr_stmt(&mut self, mut node: ExprStmt) {
1523 node.visit_mut_with(self);
1524
1525 self.emit_stmt(node.into());
1526 }
1527
1528 fn transform_and_emit_var_decl_list(&mut self, mut node: Box<VarDecl>) {
1529 for variable in &node.decls {
1530 self.hoist_variable_declaration(&Ident::from(variable.name.as_ident().unwrap()));
1531 }
1532
1533 let mut variables = self.get_initialized_variables(&mut node);
1534 let var_len = variables.len();
1535 let mut variables_written = 0;
1536 let mut pending_expressions = Vec::new();
1537 let mut cnt = 0;
1538
1539 while variables_written < var_len {
1540 #[cfg(debug_assertions)]
1541 debug!("variables_written: {} / {}", variables_written, var_len);
1542
1543 for (_i, variable) in variables.iter_mut().enumerate().skip(variables_written) {
1544 if contains_yield(&**variable) && cnt != 0 {
1545 break;
1546 }
1547
1548 let expr = self.transform_initialized_variable(variable.take());
1550
1551 pending_expressions.extend(expr.map(Expr::from).map(Box::new));
1552 cnt += 1;
1553 }
1554
1555 if cnt > 0 {
1556 variables_written += cnt;
1557 cnt = 0;
1558
1559 self.emit_stmt(
1560 ExprStmt {
1561 span: DUMMY_SP,
1562 expr: if pending_expressions.len() == 1 {
1563 pending_expressions.pop().unwrap()
1564 } else {
1565 SeqExpr {
1566 span: DUMMY_SP,
1567 exprs: take(&mut pending_expressions),
1568 }
1569 .into()
1570 },
1571 }
1572 .into(),
1573 )
1574 }
1575 }
1576 }
1577
1578 fn transform_initialized_variable(&mut self, mut node: VarDeclarator) -> Option<AssignExpr> {
1579 node.init.visit_mut_with(self);
1580
1581 node.init.map(|right| AssignExpr {
1582 span: node.span,
1583 op: op!("="),
1584 left: node.name.clone().try_into().unwrap(),
1585 right,
1586 })
1587 }
1588
1589 fn transform_and_emit_if_stmt(&mut self, mut node: IfStmt) {
1590 if contains_yield(&node) {
1591 if contains_yield(&node.cons) || contains_yield(&node.alt) {
1606 let end_label = self.define_label();
1607 let else_label = node.alt.as_ref().map(|_| self.define_label());
1608
1609 node.test.visit_mut_with(self);
1610 let span = node.test.span();
1611 self.emit_break_when_false(else_label.unwrap_or(end_label), node.test, Some(span));
1612
1613 self.transform_and_emit_embedded_stmt(*node.cons);
1614
1615 if let Some(alt) = node.alt {
1616 self.emit_break(end_label, None);
1617 self.mark_label(else_label.unwrap());
1618 self.transform_and_emit_embedded_stmt(*alt);
1619 }
1620 self.mark_label(end_label);
1621 } else {
1622 node.visit_mut_with(self);
1623 self.emit_stmt(node.into());
1624 }
1625 } else {
1626 node.visit_mut_with(self);
1627 self.emit_stmt(node.into());
1628 }
1629 }
1630
1631 fn transform_and_emit_do_stmt(&mut self, mut node: DoWhileStmt) {
1632 if contains_yield(&node) {
1633 let condition_label = self.define_label();
1649 let loop_label = self.define_label();
1650
1651 self.begin_loop_block(condition_label);
1652 self.mark_label(loop_label);
1653 self.transform_and_emit_embedded_stmt(*node.body);
1654 self.mark_label(condition_label);
1655 node.test.visit_mut_with(self);
1656 let span = node.test.span();
1657 self.emit_break_when_true(loop_label, node.test, Some(span));
1658 self.end_loop_block();
1659 } else {
1660 node.visit_mut_with(self);
1661 self.emit_stmt(node.into());
1662 }
1663 }
1664
1665 fn transform_and_emit_while_stmt(&mut self, mut node: WhileStmt) {
1666 let _tracing = dev_span!("transform_and_emit_while_stmt");
1667
1668 if contains_yield(&node) {
1669 let loop_label = self.define_label();
1684 let end_label = self.begin_loop_block(loop_label);
1685 self.mark_label(loop_label);
1686 node.test.visit_mut_with(self);
1687 self.emit_break_when_false(end_label, node.test, None);
1688 self.transform_and_emit_embedded_stmt(*node.body);
1689 self.emit_break(loop_label, None);
1690 self.end_loop_block();
1691 } else {
1692 node.visit_mut_with(self);
1693
1694 self.emit_stmt(node.into());
1695 }
1696 }
1697
1698 fn transform_and_emit_for_stmt(&mut self, mut node: ForStmt) {
1699 if contains_yield(&node) {
1700 let condition_label = self.define_label();
1719 let increment_label = self.define_label();
1720 let end_label = self.begin_loop_block(increment_label);
1721
1722 if let Some(init) = node.init {
1723 match init {
1724 VarDeclOrExpr::VarDecl(init) => {
1725 self.transform_and_emit_var_decl_list(init);
1726 }
1727 VarDeclOrExpr::Expr(mut init) => {
1728 init.visit_mut_with(self);
1729 self.emit_stmt(
1730 ExprStmt {
1731 span: init.span(),
1732 expr: init,
1733 }
1734 .into(),
1735 );
1736 }
1737 }
1738 }
1739
1740 self.mark_label(condition_label);
1741
1742 if let Some(mut cond) = node.test {
1743 cond.visit_mut_with(self);
1744 self.emit_break_when_false(end_label, cond, None);
1745 }
1746
1747 self.transform_and_emit_embedded_stmt(*node.body);
1748
1749 self.mark_label(increment_label);
1750
1751 if let Some(mut incrementor) = node.update {
1752 incrementor.visit_mut_with(self);
1753
1754 self.emit_stmt(
1755 ExprStmt {
1756 span: incrementor.span(),
1757 expr: incrementor,
1758 }
1759 .into(),
1760 );
1761 }
1762
1763 self.emit_break(condition_label, None);
1764 self.end_loop_block();
1765 } else {
1766 node.visit_mut_with(self);
1767 self.emit_stmt(node.into());
1768 }
1769 }
1770
1771 fn transform_and_emit_for_in_stmt(&mut self, mut node: ForInStmt) {
1772 if contains_yield(&node) {
1773 let keys_array = self.declare_local(None);
1795 let key = self.declare_local(None);
1796 let keys_index = private_ident!("_i");
1797
1798 self.hoist_variable_declaration(&keys_index);
1799
1800 self.emit_assignment(
1801 keys_array.clone().into(),
1802 Box::new(ArrayLit::dummy().into()),
1803 None,
1804 );
1805
1806 node.right.visit_mut_with(self);
1807 self.emit_stmt(
1808 ForInStmt {
1809 span: DUMMY_SP,
1810 left: ForHead::Pat(key.clone().into()),
1811 right: node.right.take(),
1812 body: Box::new(Stmt::Expr(ExprStmt {
1813 span: DUMMY_SP,
1814 expr: CallExpr {
1815 span: DUMMY_SP,
1816 callee: keys_array
1817 .clone()
1818 .make_member(quote_ident!("push"))
1819 .as_callee(),
1820 args: vec![key.as_arg()],
1821 ..Default::default()
1822 }
1823 .into(),
1824 })),
1825 }
1826 .into(),
1827 );
1828
1829 self.emit_assignment(keys_index.clone().into(), 0.into(), None);
1830
1831 let condition_label = self.define_label();
1832 let increment_label = self.define_label();
1833 let end_label = self.begin_loop_block(increment_label);
1834
1835 self.mark_label(condition_label);
1836 self.emit_break_when_false(
1837 end_label,
1838 Box::new(keys_index.clone().make_bin(
1839 op!("<"),
1840 keys_array.clone().make_member(quote_ident!("length")),
1841 )),
1842 None,
1843 );
1844
1845 let variable = match node.left {
1846 ForHead::VarDecl(initializer) => {
1847 for variable in initializer.decls.iter() {
1848 self.hoist_variable_declaration(&Ident::from(
1849 variable.name.as_ident().unwrap(),
1850 ));
1851 }
1852
1853 initializer.decls[0].name.clone()
1854 }
1855 ForHead::Pat(mut initializer) => {
1856 initializer.visit_mut_with(self);
1857 *initializer
1858 }
1859
1860 ForHead::UsingDecl(..) => {
1861 unreachable!("using declaration must be removed by previous pass")
1862 }
1863 };
1864 self.emit_assignment(
1865 variable.try_into().unwrap(),
1866 MemberExpr {
1867 span: DUMMY_SP,
1868 obj: Box::new(keys_array.into()),
1869 prop: MemberProp::Computed(ComputedPropName {
1870 span: DUMMY_SP,
1871 expr: Box::new(keys_index.clone().into()),
1872 }),
1873 }
1874 .into(),
1875 None,
1876 );
1877 self.transform_and_emit_embedded_stmt(*node.body);
1878
1879 self.mark_label(increment_label);
1880 self.emit_stmt(
1881 ExprStmt {
1882 span: DUMMY_SP,
1883 expr: UpdateExpr {
1884 span: DUMMY_SP,
1885 prefix: false,
1886 op: op!("++"),
1887 arg: Box::new(keys_index.clone().into()),
1888 }
1889 .into(),
1890 }
1891 .into(),
1892 );
1893
1894 self.emit_break(condition_label, None);
1895 self.end_loop_block();
1896 } else {
1897 node.visit_mut_with(self);
1898 self.emit_stmt(node.into());
1899 }
1900 }
1901
1902 fn transform_and_emit_continue_stmt(&mut self, node: ContinueStmt) {
1903 let label = self.find_continue_target(node.label.as_ref().map(|l| l.sym.clone()));
1904 if label.0 > 0 {
1905 self.emit_break(label, Some(node.span));
1906 } else {
1907 self.emit_stmt(node.into())
1910 }
1911 }
1912
1913 fn transform_and_emit_break_stmt(&mut self, node: BreakStmt) {
1914 let label = self.find_break_target(node.label.as_ref().map(|l| l.sym.clone()));
1915 if label.0 > 0 {
1916 self.emit_break(label, Some(node.span));
1917 } else {
1918 self.emit_stmt(node.into())
1921 }
1922 }
1923
1924 fn transform_and_emit_return_stmt(&mut self, mut s: ReturnStmt) {
1925 s.arg.visit_mut_with(self);
1926 self.emit_return(s.arg, Some(s.span))
1927 }
1928
1929 fn transform_and_emit_with_stmt(&mut self, mut node: WithStmt) {
1930 if contains_yield(&node) {
1931 node.obj.visit_mut_with(self);
1942 let obj = self.cache_expression(node.obj);
1943 self.begin_with_block(obj);
1944 self.transform_and_emit_embedded_stmt(*node.body);
1945 self.end_with_block();
1946 } else {
1947 node.visit_mut_with(self);
1948 self.emit_stmt(node.into());
1949 }
1950 }
1951
1952 fn transform_and_emit_switch_stmt(&mut self, mut node: SwitchStmt) {
1953 if contains_yield(&node.cases) {
1954 let end_label = self.begin_switch_block();
1987 node.discriminant.visit_mut_with(self);
1988 let expression = self.cache_expression(node.discriminant);
1989
1990 let mut clause_labels = Vec::new();
1994 let mut default_clause_index = -1i32;
1995
1996 for (i, clause) in node.cases.iter().enumerate() {
1997 clause_labels.push(self.define_label());
1998 if clause.test.is_none() && default_clause_index == -1 {
1999 default_clause_index = i as _;
2000 }
2001 }
2002
2003 let mut clauses_written = 0;
2008 let mut pending_clauses = Vec::new();
2009
2010 while clauses_written < node.cases.len() {
2011 #[cfg(debug_assertions)]
2012 debug!("clauses_written: {}", clauses_written);
2013
2014 let mut default_clauses_skipped = 0;
2015
2016 for (i, clause) in node.cases.iter_mut().enumerate().skip(clauses_written) {
2017 if clause.test.is_some() {
2018 if contains_yield(&clause.test) && !pending_clauses.is_empty() {
2019 break;
2020 }
2021
2022 clause.test.visit_mut_with(self);
2023 let span = clause.test.span();
2024 pending_clauses.push(SwitchCase {
2025 span: DUMMY_SP,
2026 test: clause.test.take(),
2027 cons: vec![self
2028 .create_inline_break(clause_labels[i], Some(span))
2029 .into()],
2030 })
2031 } else {
2032 default_clauses_skipped += 1;
2033 }
2034 }
2035
2036 if !pending_clauses.is_empty() {
2037 clauses_written += pending_clauses.len();
2038 self.emit_stmt(
2039 SwitchStmt {
2040 span: DUMMY_SP,
2041 discriminant: expression.clone().into(),
2042 cases: take(&mut pending_clauses),
2043 }
2044 .into(),
2045 );
2046 }
2047
2048 if default_clauses_skipped > 0 {
2049 clauses_written += default_clauses_skipped;
2050 }
2051 }
2052
2053 if default_clause_index >= 0 {
2054 self.emit_break(clause_labels[default_clause_index as usize], None);
2055 } else {
2056 self.emit_break(end_label, None);
2057 }
2058
2059 for (i, clause) in node.cases.into_iter().enumerate() {
2060 self.mark_label(clause_labels[i]);
2061 self.transform_and_emit_stmts(clause.cons, 0);
2062 }
2063
2064 self.end_switch_block()
2065 } else {
2066 node.visit_mut_with(self);
2067 self.emit_stmt(node.into())
2068 }
2069 }
2070
2071 fn transform_and_emit_labeled_stmt(&mut self, mut node: LabeledStmt) {
2072 #[cfg(debug_assertions)]
2073 debug!("transform_and_emit_labeled_stmt: {:?}", node.label);
2074
2075 if contains_yield(&node) {
2076 self.begin_labeled_block(node.label.sym);
2087 self.transform_and_emit_embedded_stmt(*node.body);
2088 self.end_labeled_block();
2089 } else {
2090 node.visit_mut_with(self);
2091 self.emit_stmt(node.into());
2092 }
2093 }
2094
2095 fn transform_and_emit_throw_stmt(&mut self, mut node: ThrowStmt) {
2096 node.arg.visit_mut_with(self);
2097 self.emit_throw(node.arg, Some(node.span))
2098 }
2099
2100 fn transform_and_emit_try_stmt(&mut self, mut node: TryStmt) {
2101 let _tracing = dev_span!("transform_and_emit_try_stmt");
2102
2103 if contains_yield(&node) {
2104 self.begin_exception_block();
2135 self.transform_and_emit_embedded_stmt(node.block.into());
2136 if let Some(catch) = node.handler {
2137 self.begin_catch_block(VarDeclarator {
2138 name: catch.param.clone().unwrap(),
2139 ..Take::dummy()
2140 });
2141 self.transform_and_emit_embedded_stmt(catch.body.into());
2142 }
2143
2144 if let Some(finalizer) = node.finalizer {
2145 self.begin_finally_block();
2146 self.transform_and_emit_embedded_stmt(finalizer.into());
2147 }
2148
2149 self.end_exception_block();
2150 } else {
2151 node.visit_mut_with(self);
2152 self.emit_stmt(node.into());
2153 }
2154 }
2155
2156 fn count_initial_nodes_without_yield<N>(&self, nodes: &[N]) -> usize
2157 where
2158 N: VisitWith<YieldFinder>,
2159 {
2160 for (i, node) in nodes.iter().enumerate() {
2161 if contains_yield(node) {
2162 return i;
2163 }
2164 }
2165
2166 0
2167 }
2168
2169 fn cache_expression(&mut self, node: Box<Expr>) -> Ident {
2170 match *node {
2171 Expr::Ident(i) => i,
2172 _ => {
2173 let span = node.span();
2174
2175 let temp = self.create_temp_variable();
2176 self.emit_assignment(temp.clone().into(), node, Some(span));
2177 temp
2178 }
2179 }
2180 }
2181
2182 fn declare_local(&mut self, name: Option<Atom>) -> Ident {
2183 let temp = name
2184 .map(|name| private_ident!(name))
2185 .unwrap_or_else(|| private_ident!("_tmp"));
2186
2187 self.hoist_variable_declaration(&temp);
2188 temp
2189 }
2190
2191 fn define_label(&mut self) -> Label {
2193 if self.label_offsets.is_none() {
2194 self.label_offsets = Some(Default::default());
2195 }
2196
2197 let label = Label(self.next_label_id as _);
2198 self.next_label_id += 1;
2199 #[cfg(debug_assertions)]
2200 debug!("define_label: {:?}", label);
2201
2202 if label.0 as usize >= self.label_offsets.as_ref().unwrap().len() {
2203 self.label_offsets
2204 .as_mut()
2205 .unwrap()
2206 .resize(label.0 as usize + 1, 0);
2207 }
2208 self.label_offsets.as_mut().unwrap()[label.0 as usize] = -1;
2209 label
2210 }
2211
2212 fn mark_label(&mut self, label: Label) {
2214 debug_assert!(self.label_offsets.is_some(), "No labels were defined.");
2215
2216 if label.0 as usize >= self.label_offsets.as_ref().unwrap().len() {
2217 self.label_offsets
2218 .as_mut()
2219 .unwrap()
2220 .resize(label.0 as usize + 1, Default::default());
2221 }
2222
2223 self.label_offsets.as_mut().unwrap()[label.0 as usize] =
2224 self.operations.as_deref().map_or(0, |v| v.len() as _);
2225
2226 #[cfg(debug_assertions)]
2227 debug!(
2228 "mark_label: {:?}; offset: {}",
2229 label,
2230 self.label_offsets.as_mut().unwrap()[label.0 as usize]
2231 );
2232 }
2233
2234 fn begin_block(&mut self, block: CodeBlock) -> Ptr<CodeBlock> {
2238 if self.blocks.is_none() {
2239 self.blocks = Some(Default::default());
2240 self.block_actions = Some(Default::default());
2241 self.block_offsets = Some(Default::default());
2242 self.block_stack = Some(Default::default());
2243 }
2244
2245 #[cfg(debug_assertions)]
2246 let index = self.block_actions.as_ref().unwrap().len();
2247
2248 #[cfg(debug_assertions)]
2249 if cfg!(debug_assertions) {
2250 debug!("Begin block {}: {:?}", index, block);
2251 }
2252
2253 let block = Rc::new(RefCell::new(block));
2254
2255 self.block_actions.as_mut().unwrap().push(BlockAction::Open);
2256 self.block_offsets
2257 .as_mut()
2258 .unwrap()
2259 .push(self.operations.as_ref().map_or(0, |v| v.len()));
2260 self.blocks.as_mut().unwrap().push(block.clone());
2261 self.block_stack.as_mut().unwrap().push(block.clone());
2262
2263 block
2264 }
2265
2266 fn end_block(&mut self) -> Ptr<CodeBlock> {
2268 let block = self.peek_block().expect("beginBlock was never called.");
2269
2270 #[cfg(debug_assertions)]
2271 let index = self.block_actions.as_ref().unwrap().len();
2272
2273 #[cfg(debug_assertions)]
2274 debug!("End block {}", index);
2275
2276 self.block_actions
2277 .as_mut()
2278 .unwrap()
2279 .push(BlockAction::Close);
2280 self.block_offsets
2281 .as_mut()
2282 .unwrap()
2283 .push(self.operations.as_ref().map_or(0, |v| v.len()));
2284 self.blocks.as_mut().unwrap().push(block.clone());
2285 self.block_stack.as_mut().unwrap().pop();
2286 block
2287 }
2288
2289 fn peek_block(&self) -> Option<Ptr<CodeBlock>> {
2291 self.block_stack.as_ref().and_then(|v| v.last().cloned())
2292 }
2293
2294 fn peek_block_kind(&self) -> Option<CodeBlockKind> {
2296 self.peek_block().map(|b| match &*b.borrow() {
2297 CodeBlock::With(..) => CodeBlockKind::With,
2298 CodeBlock::Exception(..) => CodeBlockKind::Exception,
2299 CodeBlock::Labeled(..) => CodeBlockKind::Labeled,
2300 CodeBlock::Switch(..) => CodeBlockKind::Switch,
2301 CodeBlock::Loop(..) => CodeBlockKind::Loop,
2302 })
2303 }
2304
2305 fn begin_with_block(&mut self, expr: Ident) {
2309 let start_label = self.define_label();
2310 let end_label = self.define_label();
2311 self.mark_label(start_label);
2312 self.begin_block(CodeBlock::With(WithBlock {
2313 expression: expr,
2314 start_label,
2315 end_label,
2316 }));
2317 }
2318
2319 fn end_with_block(&mut self) {
2321 debug_assert!(self.peek_block_kind() == Some(CodeBlockKind::With));
2322 let block = self.end_block();
2323 let b = block.borrow();
2324 if let CodeBlock::With(block) = &*b {
2325 self.mark_label(block.end_label);
2326 } else {
2327 unreachable!()
2328 }
2329 }
2330
2331 fn begin_exception_block(&mut self) -> Label {
2333 let _tracing = dev_span!("begin_exception_block");
2334
2335 let start_label = self.define_label();
2336 let end_label = self.define_label();
2337 self.mark_label(start_label);
2338 self.begin_block(CodeBlock::Exception(ExceptionBlock {
2339 state: ExceptionBlockState::Try,
2340 start_label,
2341 end_label,
2342 catch_variable: Default::default(),
2343 catch_label: Default::default(),
2344 finally_label: Default::default(),
2345 }));
2346 self.emit_nop();
2347 end_label
2348 }
2349
2350 fn begin_catch_block(&mut self, variable: VarDeclarator) {
2356 debug_assert!(self.peek_block_kind() == Some(CodeBlockKind::Exception));
2357
2358 let name = variable.name.expect_ident().into();
2359 self.hoist_variable_declaration(&name);
2360
2361 let peeked = self.peek_block().unwrap();
2363 let exception = peeked.borrow_mut();
2364 let mut exception = RefMut::map(exception, |v| match v {
2365 CodeBlock::Exception(v) => v,
2366 _ => unreachable!(),
2367 });
2368 debug_assert!(exception.state < ExceptionBlockState::Catch);
2369
2370 let end_label = exception.end_label;
2371 self.emit_break(end_label, None);
2372
2373 let catch_label = self.define_label();
2374 self.mark_label(catch_label);
2375 exception.state = ExceptionBlockState::Catch;
2376 exception.catch_variable = Some(name.clone());
2377 exception.catch_label = Some(catch_label);
2378
2379 self.emit_assignment(
2380 name.clone().into(),
2381 CallExpr {
2382 span: DUMMY_SP,
2383 callee: self
2384 .state
2385 .clone()
2386 .make_member(quote_ident!("sent"))
2387 .as_callee(),
2388 args: Vec::new(),
2389 ..Default::default()
2390 }
2391 .into(),
2392 None,
2393 );
2394
2395 self.emit_nop();
2396 }
2397
2398 fn begin_finally_block(&mut self) {
2400 let _tracing = dev_span!("begin_finally_block");
2401
2402 debug_assert!(self.peek_block_kind() == Some(CodeBlockKind::Exception));
2403
2404 let block = self.peek_block().unwrap();
2405 let mut b = block.borrow_mut();
2406 if let CodeBlock::Exception(block) = &mut *b {
2407 debug_assert!(block.state < ExceptionBlockState::Finally);
2408
2409 let end_label = block.end_label;
2410 self.emit_break(end_label, None);
2411
2412 let finally_label = self.define_label();
2413 self.mark_label(finally_label);
2414 block.state = ExceptionBlockState::Finally;
2415 block.finally_label = Some(finally_label);
2416 } else {
2417 unreachable!()
2418 }
2419 }
2420
2421 fn end_exception_block(&mut self) {
2423 debug_assert!(self.peek_block_kind() == Some(CodeBlockKind::Exception));
2424 let block = self.end_block();
2425 let mut b = block.borrow_mut();
2426 if let CodeBlock::Exception(block) = &mut *b {
2427 let state = block.state;
2428 if state < ExceptionBlockState::Finally {
2429 self.emit_break(block.end_label, None);
2430 } else {
2431 self.emit_endfinally();
2432 }
2433 self.mark_label(block.end_label);
2434 self.emit_nop();
2435 block.state = ExceptionBlockState::Done;
2436 } else {
2437 unreachable!()
2438 }
2439 }
2440
2441 fn begin_script_loop_block(&mut self) {
2444 self.begin_block(CodeBlock::Loop(LoopBlock {
2445 is_script: true,
2446 break_label: Label(-1),
2447 continue_label: Label(-1),
2448 }));
2449 }
2450
2451 fn begin_loop_block(&mut self, continue_label: Label) -> Label {
2458 let _tracing = dev_span!("begin_loop_block");
2459
2460 let break_label = self.define_label();
2461 self.begin_block(CodeBlock::Loop(LoopBlock {
2462 is_script: false,
2463 break_label,
2464 continue_label,
2465 }));
2466 break_label
2467 }
2468
2469 fn end_loop_block(&mut self) {
2472 debug_assert!(self.peek_block_kind() == Some(CodeBlockKind::Loop));
2473 let block = self.end_block();
2474 let block = block.borrow();
2475 if let CodeBlock::Loop(block) = &*block {
2476 let break_label = block.break_label;
2477 if !block.is_script {
2478 self.mark_label(break_label);
2479 }
2480 } else {
2481 unreachable!()
2482 }
2483 }
2484
2485 fn begin_script_switch_block(&mut self) {
2488 self.begin_block(CodeBlock::Switch(SwitchBlock {
2489 is_script: true,
2490 break_label: Label(-1),
2491 }));
2492 }
2493
2494 fn begin_switch_block(&mut self) -> Label {
2500 let break_label = self.define_label();
2501 self.begin_block(CodeBlock::Switch(SwitchBlock {
2502 is_script: false,
2503 break_label,
2504 }));
2505 break_label
2506 }
2507
2508 fn end_switch_block(&mut self) {
2511 debug_assert!(self.peek_block_kind() == Some(CodeBlockKind::Switch));
2512 let block = self.end_block();
2513 let block = block.borrow();
2514 if let CodeBlock::Switch(block) = &*block {
2515 let break_label = block.break_label;
2516 if !block.is_script {
2517 self.mark_label(break_label);
2518 }
2519 } else {
2520 unreachable!()
2521 }
2522 }
2523
2524 fn begin_script_labeled_block(&mut self, label_text: Atom) {
2525 self.begin_block(CodeBlock::Labeled(LabeledBlock {
2526 is_script: true,
2527 label_text,
2528 break_label: Label(-1),
2529 }));
2530 }
2531
2532 fn begin_labeled_block(&mut self, label_text: Atom) {
2533 let break_label = self.define_label();
2534 self.begin_block(CodeBlock::Labeled(LabeledBlock {
2535 is_script: false,
2536 label_text,
2537 break_label,
2538 }));
2539 }
2540
2541 fn end_labeled_block(&mut self) {
2542 let block = self.end_block();
2543 if !block.borrow().is_script() {
2544 let break_label = match &*block.borrow() {
2545 CodeBlock::Labeled(block) => block.break_label,
2546 _ => unreachable!(),
2547 };
2548 self.mark_label(break_label);
2549 }
2550 }
2551
2552 fn supports_unlabeled_break(&self, block: &CodeBlock) -> bool {
2554 matches!(block, CodeBlock::Switch(..) | CodeBlock::Loop(..))
2555 }
2556
2557 fn supports_labeled_break_or_continue(&self, block: &CodeBlock) -> bool {
2560 matches!(block, CodeBlock::Labeled(..))
2561 }
2562
2563 fn supports_unlabeled_continue(&self, block: &CodeBlock) -> bool {
2565 matches!(block, CodeBlock::Loop(..))
2566 }
2567
2568 fn has_immediate_containing_labeled_block(&self, label_text: &Atom, start: usize) -> bool {
2569 for i in (0..=start).rev() {
2570 let block = self.block_stack.as_ref().unwrap()[i].clone();
2571 if self.supports_labeled_break_or_continue(&block.borrow()) {
2572 if let CodeBlock::Labeled(block) = &*block.borrow() {
2573 if block.label_text == *label_text {
2574 return true;
2575 }
2576 } else {
2577 unreachable!()
2578 }
2579 } else {
2580 break;
2581 }
2582 }
2583
2584 false
2585 }
2586
2587 fn find_break_target(&self, label_text: Option<Atom>) -> Label {
2591 #[cfg(debug_assertions)]
2592 debug!("find_break_target: label_text={:?}", label_text);
2593
2594 if let Some(block_stack) = &self.block_stack {
2595 if let Some(label_text) = label_text {
2596 for i in (0..=block_stack.len() - 1).rev() {
2597 let block = &block_stack[i];
2598 if (self.supports_labeled_break_or_continue(&block.borrow())
2599 && block.borrow().label_text().unwrap() == label_text)
2600 || (self.supports_unlabeled_break(&block.borrow())
2601 && self.has_immediate_containing_labeled_block(&label_text, i - 1))
2602 {
2603 return block.borrow().break_label().unwrap();
2604 }
2605 }
2606 } else {
2607 for i in (0..=block_stack.len() - 1).rev() {
2608 let block = &block_stack[i];
2609 if self.supports_unlabeled_break(&block.borrow()) {
2610 return block.borrow().break_label().unwrap();
2611 }
2612 }
2613 }
2614 }
2615
2616 Label(0)
2617 }
2618
2619 fn find_continue_target(&self, label_text: Option<Atom>) -> Label {
2623 if let Some(block_stack) = &self.block_stack {
2624 if let Some(label_text) = label_text {
2625 for i in (0..=block_stack.len() - 1).rev() {
2626 let block = &block_stack[i];
2627 if self.supports_unlabeled_continue(&block.borrow())
2628 && self.has_immediate_containing_labeled_block(&label_text, i - 1)
2629 {
2630 return block.borrow().continue_label().unwrap();
2631 }
2632 }
2633 } else {
2634 for i in (0..=block_stack.len() - 1).rev() {
2635 let block = &block_stack[i];
2636 if self.supports_unlabeled_continue(&block.borrow()) {
2637 return block.borrow().continue_label().unwrap();
2638 }
2639 }
2640 }
2641 }
2642
2643 Label(0)
2644 }
2645
2646 fn create_label(&mut self, label: Option<Label>) -> Box<Expr> {
2649 if let Some(label) = label {
2650 if label.0 > 0 {
2651 #[cfg(debug_assertions)]
2652 debug!("create_label: label={:?}", label);
2653
2654 if self.label_exprs.is_none() {
2655 self.label_exprs = Some(Default::default());
2656 }
2657 let label_expressions = self.label_exprs.as_mut().unwrap();
2658 let expr = Loc {
2659 pos: BytePos(label.0 as _),
2660 value: -1,
2661 };
2662 if label_expressions.get(label.0 as usize).is_none() {
2663 if label.0 as usize >= label_expressions.len() {
2664 label_expressions.resize(label.0 as usize + 1, Vec::new());
2665 }
2666
2667 label_expressions[label.0 as usize] = vec![expr];
2668 } else {
2669 label_expressions
2670 .get_mut(label.0 as usize)
2671 .unwrap()
2672 .push(expr);
2673 }
2674 return Invalid {
2675 span: Span::new_with_checked(BytePos(label.0 as _), BytePos(label.0 as _)),
2676 }
2677 .into();
2678 }
2679 }
2680
2681 Box::new(Invalid { span: DUMMY_SP }.into())
2682 }
2683
2684 fn create_instruction(&mut self, instruction: Instruction) -> Number {
2686 Number {
2693 span: DUMMY_SP,
2694 value: instruction as u16 as _,
2695 raw: None,
2696 }
2697 }
2698
2699 fn create_inline_break(&mut self, label: Label, span: Option<Span>) -> ReturnStmt {
2705 debug_assert!(label.0 >= 0, "Invalid label");
2706 let args = vec![
2707 Some(self.create_instruction(Instruction::Break).as_arg()),
2708 Some(self.create_label(Some(label)).as_arg()),
2709 ];
2710 ReturnStmt {
2711 span: span.unwrap_or(DUMMY_SP),
2712 arg: Some(
2713 ArrayLit {
2714 span: DUMMY_SP,
2715 elems: args,
2716 }
2717 .into(),
2718 ),
2719 }
2720 }
2721
2722 fn create_inline_return(&mut self, expr: Option<Box<Expr>>, loc: Option<Span>) -> ReturnStmt {
2727 ReturnStmt {
2728 span: loc.unwrap_or(DUMMY_SP),
2729 arg: Some(
2730 ArrayLit {
2731 span: DUMMY_SP,
2732 elems: match expr {
2733 Some(expr) => vec![
2734 Some(self.create_instruction(Instruction::Return).as_arg()),
2735 Some(expr.as_arg()),
2736 ],
2737 None => vec![Some(self.create_instruction(Instruction::Return).as_arg())],
2738 },
2739 }
2740 .into(),
2741 ),
2742 }
2743 }
2744
2745 fn create_generator_resume(&mut self, loc: Option<Span>) -> Box<Expr> {
2747 CallExpr {
2748 span: loc.unwrap_or(DUMMY_SP),
2749 callee: self
2750 .state
2751 .clone()
2752 .make_member(quote_ident!("sent"))
2753 .as_callee(),
2754 args: Vec::new(),
2755 ..Default::default()
2756 }
2757 .into()
2758 }
2759
2760 fn emit_nop(&mut self) {
2762 self.emit_worker(OpCode::Nop, None, None);
2763 }
2764
2765 fn emit_stmt(&mut self, stmt: Stmt) {
2769 if stmt.is_empty() {
2770 self.emit_nop();
2771 } else {
2772 self.emit_worker(OpCode::Statement, Some(OpArgs::Stmt(Box::new(stmt))), None);
2773 }
2774 }
2775
2776 fn emit_assignment(&mut self, left: AssignTarget, right: Box<Expr>, loc: Option<Span>) {
2782 self.emit_worker(OpCode::Assign, Some(OpArgs::PatAndExpr(left, right)), loc);
2783 }
2784
2785 fn emit_break(&mut self, label: Label, loc: Option<Span>) {
2790 self.emit_worker(OpCode::Break, Some(OpArgs::Label(label)), loc);
2791 }
2792
2793 fn emit_break_when_true(&mut self, label: Label, condition: Box<Expr>, loc: Option<Span>) {
2800 self.emit_worker(
2801 OpCode::BreakWhenTrue,
2802 Some(OpArgs::LabelExpr(label, condition)),
2803 loc,
2804 );
2805 }
2806
2807 fn emit_break_when_false(&mut self, label: Label, condition: Box<Expr>, loc: Option<Span>) {
2814 self.emit_worker(
2815 OpCode::BreakWhenFalse,
2816 Some(OpArgs::LabelExpr(label, condition)),
2817 loc,
2818 );
2819 }
2820
2821 fn emit_yield_star(&mut self, expr: Option<Box<Expr>>, loc: Option<Span>) {
2826 self.emit_worker(OpCode::YieldStar, Some(OpArgs::OptExpr(expr)), loc);
2827 }
2828
2829 fn emit_yield(&mut self, expr: Option<Box<Expr>>, loc: Option<Span>) {
2834 self.emit_worker(OpCode::Yield, Some(OpArgs::OptExpr(expr)), loc);
2835 }
2836
2837 fn emit_return(&mut self, expr: Option<Box<Expr>>, loc: Option<Span>) {
2842 self.emit_worker(OpCode::Return, Some(OpArgs::OptExpr(expr)), loc);
2843 }
2844
2845 fn emit_throw(&mut self, expr: Box<Expr>, loc: Option<Span>) {
2850 self.emit_worker(OpCode::Throw, Some(OpArgs::OptExpr(Some(expr))), loc);
2851 }
2852
2853 fn emit_endfinally(&mut self) {
2856 self.emit_worker(OpCode::Endfinally, None, None);
2857 }
2858
2859 fn emit_worker(&mut self, code: OpCode, args: Option<OpArgs>, loc: Option<Span>) {
2864 if self.operations.is_none() {
2865 self.operations = Some(Vec::new());
2866 self.operation_args = Some(Vec::new());
2867 self.operation_locs = Some(Vec::new());
2868 }
2869 if self.label_offsets.is_none() {
2870 let label = self.define_label();
2872 self.mark_label(label);
2873 }
2874 debug_assert!(self.operations.is_some());
2875 debug_assert_eq!(
2876 self.operations.as_ref().unwrap().len(),
2877 self.operation_args.as_ref().unwrap().len()
2878 );
2879 debug_assert_eq!(
2880 self.operations.as_ref().unwrap().len(),
2881 self.operation_locs.as_ref().unwrap().len()
2882 );
2883
2884 self.operations.as_mut().unwrap().push(code);
2885 self.operation_args.as_mut().unwrap().push(args);
2886 self.operation_locs
2887 .as_mut()
2888 .unwrap()
2889 .push(loc.unwrap_or(DUMMY_SP));
2890 }
2891
2892 fn build_stmts(&mut self) -> Vec<Stmt> {
2894 if let Some(ops) = self.operations.clone() {
2895 for (op_index, _) in ops.iter().enumerate() {
2896 self.write_operation(op_index);
2897 }
2898
2899 self.flush_final_label(ops.len());
2900 } else {
2901 self.flush_final_label(0);
2902 }
2903
2904 if let Some(clauses) = self.clauses.take() {
2905 let label_expr = self.state.clone().make_member(quote_ident!("label"));
2906 let switch_stmt = SwitchStmt {
2907 span: DUMMY_SP,
2908 discriminant: label_expr.into(),
2909 cases: clauses,
2910 };
2911 return vec![Stmt::Switch(switch_stmt)];
2912 }
2913
2914 if let Some(stmts) = self.stmts.take() {
2915 return stmts;
2916 }
2917
2918 Vec::new()
2919 }
2920
2921 fn flush_label(&mut self) {
2923 if self.stmts.is_none() {
2924 return;
2925 }
2926
2927 self.append_label(!self.last_operation_was_abrupt);
2928
2929 self.last_operation_was_abrupt = false;
2930 self.last_operation_was_completion = false;
2931 self.label_number += 1;
2932 }
2933
2934 fn flush_final_label(&mut self, op_index: usize) {
2936 if self.is_final_label_reachable(op_index) {
2937 self.try_enter_label(op_index);
2938 self.with_block_stack = None;
2939 self.write_return(None, None);
2940 }
2941
2942 if self.stmts.is_some() && self.clauses.is_some() {
2943 self.append_label(false);
2944 }
2945
2946 self.update_label_expression();
2947 }
2948
2949 fn is_final_label_reachable(&self, op_index: usize) -> bool {
2952 if !self.last_operation_was_completion {
2955 return true;
2956 }
2957
2958 if self.label_offsets.is_none() || self.label_exprs.is_none() {
2961 return false;
2962 }
2963
2964 for (label, label_offset) in self
2967 .label_offsets
2968 .as_ref()
2969 .unwrap()
2970 .iter()
2971 .copied()
2972 .enumerate()
2973 {
2974 if label_offset as usize == op_index
2975 && self.label_exprs.as_ref().unwrap().get(label).is_some()
2976 {
2977 return true;
2978 }
2979 }
2980
2981 false
2982 }
2983
2984 fn append_label(&mut self, mark_label_end: bool) {
2990 if cfg!(debug_assertions) {
2991 debug!(mark_label_end = mark_label_end, "append_label");
2992 }
2993
2994 if self.clauses.is_none() {
2995 self.clauses = Some(Default::default());
2996 }
2997
2998 #[allow(clippy::manual_unwrap_or_default)]
2999 let stmts = if let Some(mut stmts) = self.stmts.take() {
3000 if self.with_block_stack.is_some() {
3001 for (_i, with_block) in self
3006 .with_block_stack
3007 .as_ref()
3008 .unwrap()
3009 .iter()
3010 .enumerate()
3011 .rev()
3012 {
3013 let b = with_block.borrow();
3014 let with_block = match &*b {
3015 CodeBlock::With(v) => v,
3016 _ => {
3017 unreachable!()
3018 }
3019 };
3020
3021 stmts = vec![Stmt::With(WithStmt {
3022 span: DUMMY_SP,
3023 obj: Box::new(Expr::Ident(with_block.expression.clone())),
3024 body: Box::new(Stmt::Block(BlockStmt {
3025 span: DUMMY_SP,
3026 stmts,
3027 ..Default::default()
3028 })),
3029 })];
3030 }
3031 }
3032
3033 if cfg!(debug_assertions) {
3034 debug!(
3035 "current_exception_block = {:?}",
3036 self.current_exception_block
3037 );
3038 }
3039
3040 if let Some(current_exception_block) = self.current_exception_block.take() {
3041 let b = current_exception_block.borrow();
3042 let ExceptionBlock {
3043 start_label,
3044 catch_label,
3045 finally_label,
3046 end_label,
3047 ..
3048 } = match &*b {
3049 CodeBlock::Exception(v) => v,
3050 _ => {
3051 unreachable!()
3052 }
3053 };
3054
3055 let start_label = self.create_label(Some(*start_label));
3056 let catch_label = self.create_label(*catch_label);
3057 let finally_label = self.create_label(*finally_label);
3058 let end_label = self.create_label(Some(*end_label));
3059
3060 stmts.insert(
3061 0,
3062 ExprStmt {
3063 span: DUMMY_SP,
3064 expr: CallExpr {
3065 span: DUMMY_SP,
3066 callee: self
3067 .state
3068 .clone()
3069 .make_member(quote_ident!("trys"))
3070 .make_member(quote_ident!("push"))
3071 .as_callee(),
3072 args: vec![ArrayLit {
3073 span: DUMMY_SP,
3074 elems: vec![
3075 Some(start_label.as_arg()),
3076 Some(catch_label.as_arg()),
3077 Some(finally_label.as_arg()),
3078 Some(end_label.as_arg()),
3079 ],
3080 }
3081 .as_arg()],
3082 ..Default::default()
3083 }
3084 .into(),
3085 }
3086 .into(),
3087 );
3088 }
3089
3090 if mark_label_end {
3091 stmts.push(
3096 ExprStmt {
3097 span: DUMMY_SP,
3098 expr: AssignExpr {
3099 span: DUMMY_SP,
3100 op: op!("="),
3101 left: self.state.clone().make_member(quote_ident!("label")).into(),
3102 right: (self.label_number + 1).into(),
3103 }
3104 .into(),
3105 }
3106 .into(),
3107 );
3108 }
3109
3110 stmts
3111 } else {
3112 Default::default()
3113 };
3114
3115 self.clauses.as_mut().unwrap().push(SwitchCase {
3116 span: DUMMY_SP,
3117 test: Some(self.label_number.into()),
3118 cons: stmts,
3119 });
3120 }
3121
3122 #[tracing::instrument(level = "debug", skip(self))]
3123 fn try_enter_label(&mut self, op_index: usize) {
3124 if self.label_offsets.is_none() {
3125 return;
3126 }
3127
3128 for (label, label_offset) in self.label_offsets.clone().unwrap().into_iter().enumerate() {
3129 if label_offset as usize == op_index {
3130 self.flush_label();
3131
3132 if self.label_numbers.is_none() {
3133 self.label_numbers = Some(Vec::new());
3134 }
3135
3136 if let Some(v) = self
3137 .label_numbers
3138 .as_mut()
3139 .unwrap()
3140 .get_mut(self.label_number)
3141 {
3142 v.push(label);
3143 } else {
3144 if self.label_number >= self.label_numbers.as_ref().unwrap().len() {
3145 self.label_numbers
3146 .as_mut()
3147 .unwrap()
3148 .resize(self.label_number + 1, Vec::new());
3149 }
3150
3151 self.label_numbers.as_mut().unwrap()[self.label_number] = vec![label];
3152 }
3153 }
3154 }
3155 }
3156
3157 fn update_label_expression(&mut self) {
3159 if self.label_exprs.is_some() && self.label_numbers.is_some() {
3160 for (label_number, labels) in self.label_numbers.as_ref().unwrap().iter().enumerate() {
3161 for &label in labels {
3162 let exprs = self.label_exprs.as_mut().unwrap().get_mut(label);
3163 if let Some(exprs) = exprs {
3164 for expr in exprs {
3165 expr.value = label_number as _;
3166 #[cfg(debug_assertions)]
3167 debug!("Label {:?} = {:?} ({:?})", label, expr.value, expr.pos);
3168 }
3169 }
3170 }
3171 }
3172 }
3173 }
3174
3175 #[tracing::instrument(level = "debug", skip(self))]
3177 fn try_enter_or_leave_block(&mut self, op_index: usize) {
3178 if let Some(blocks) = &self.blocks {
3179 while self.block_index < self.block_actions.as_ref().unwrap().len()
3180 && self.block_offsets.as_ref().unwrap()[self.block_index] <= op_index
3181 {
3182 #[cfg(debug_assertions)]
3183 debug!("try_enter_or_leave_block: iter");
3184
3185 let block_index = self.block_index;
3186 self.block_index += 1;
3187
3188 if cfg!(debug_assertions) {
3189 debug!(block_index = block_index, "try_enter_or_leave_block")
3190 }
3191
3192 let block = blocks[block_index].clone();
3194 let block_action = self.block_actions.as_ref().unwrap()[block_index];
3195
3196 let b = block.borrow();
3197 match &*b {
3198 CodeBlock::Exception(_) => {
3199 if block_action == BlockAction::Open {
3200 self.exception_block_stack
3201 .get_or_insert_with(Default::default)
3202 .extend(self.current_exception_block.clone());
3203
3204 if self.stmts.is_none() {
3206 self.stmts = Some(Default::default());
3207 }
3208
3209 #[cfg(debug_assertions)]
3210 debug!("Current exception block: open = Some({:?})", block);
3211 self.current_exception_block = Some(block.clone());
3212 } else if block_action == BlockAction::Close {
3213 self.current_exception_block =
3214 self.exception_block_stack.as_mut().unwrap().pop();
3215 #[cfg(debug_assertions)]
3216 debug!(
3217 "Current exception block: close = {:?}",
3218 self.current_exception_block
3219 );
3220 }
3221 }
3222
3223 CodeBlock::With(_) => {
3224 if block_action == BlockAction::Open {
3225 if self.with_block_stack.is_none() {
3226 self.with_block_stack = Some(Default::default());
3227 }
3228
3229 self.with_block_stack.as_mut().unwrap().push(block.clone());
3230 } else if block_action == BlockAction::Close {
3231 self.with_block_stack.as_mut().unwrap().pop();
3232 }
3233 }
3234
3235 _ => {}
3236 }
3237 }
3238 }
3239 }
3240
3241 #[tracing::instrument(level = "debug", skip(self))]
3244 fn write_operation(&mut self, op_index: usize) {
3245 if cfg!(debug_assertions) {
3246 debug!("Writing operation {}", op_index);
3247 }
3248
3249 self.try_enter_label(op_index);
3250 self.try_enter_or_leave_block(op_index);
3251
3252 if self.last_operation_was_abrupt {
3254 return;
3255 }
3256
3257 self.last_operation_was_abrupt = false;
3258 self.last_operation_was_completion = false;
3259
3260 let opcode = self.operations.as_ref().unwrap()[op_index];
3261 if opcode == OpCode::Nop {
3262 return;
3263 } else if opcode == OpCode::Endfinally {
3264 self.write_end_finally();
3265 return;
3266 }
3267
3268 let args = self.operation_args.as_mut().unwrap()[op_index]
3269 .take()
3270 .expect("failed to take operation arguments");
3271 if opcode == OpCode::Statement {
3272 let args = args.expect_stmt();
3273 self.write_stmt(*args);
3274 return;
3275 }
3276
3277 let loc = self.operation_locs.as_ref().unwrap()[op_index];
3278
3279 match opcode {
3280 OpCode::Assign => {
3281 let args = args.expect_pat_and_expr();
3282 self.write_assign(args.0, args.1, Some(loc));
3283 }
3284 OpCode::Break => {
3285 let args = args.expect_label();
3286 self.write_break(args, Some(loc));
3287 }
3288 OpCode::BreakWhenTrue => {
3289 let args = args.expect_label_expr();
3290 self.write_break_when_true(args.0, args.1, Some(loc));
3291 }
3292 OpCode::BreakWhenFalse => {
3293 let args = args.expect_label_expr();
3294 self.write_break_when_false(args.0, args.1, Some(loc));
3295 }
3296 OpCode::Yield => {
3297 let args = args.expect_opt_expr();
3298
3299 self.write_yield(args, Some(loc));
3300 }
3301 OpCode::YieldStar => {
3302 let args = args.expect_opt_expr().unwrap();
3303
3304 self.write_yield_star(args, Some(loc));
3305 }
3306 OpCode::Return => {
3307 let args = args.expect_opt_expr();
3308
3309 self.write_return(args, Some(loc));
3310 }
3311 OpCode::Throw => {
3312 let args = args.expect_opt_expr().unwrap();
3313
3314 self.write_throw(args, Some(loc));
3315 }
3316 _ => {}
3317 }
3318 }
3319
3320 fn write_stmt(&mut self, stmt: Stmt) {
3322 if stmt.is_empty() {
3323 return;
3324 }
3325 match self.stmts {
3326 Some(ref mut stmts) => stmts.push(stmt),
3327 None => self.stmts = Some(vec![stmt]),
3328 }
3329 }
3330
3331 fn write_assign(&mut self, left: AssignTarget, right: Box<Expr>, op_loc: Option<Span>) {
3333 self.write_stmt(
3334 ExprStmt {
3335 span: op_loc.unwrap_or(DUMMY_SP),
3336 expr: AssignExpr {
3337 span: DUMMY_SP,
3338 op: op!("="),
3339 left,
3340 right,
3341 }
3342 .into(),
3343 }
3344 .into(),
3345 )
3346 }
3347
3348 fn write_throw(&mut self, expr: Box<Expr>, op_loc: Option<Span>) {
3353 self.last_operation_was_abrupt = true;
3354 self.last_operation_was_completion = true;
3355
3356 self.write_stmt(
3358 ThrowStmt {
3359 span: op_loc.unwrap_or(DUMMY_SP),
3360 arg: expr,
3361 }
3362 .into(),
3363 )
3364 }
3365
3366 fn write_return(&mut self, expr: Option<Box<Expr>>, op_loc: Option<Span>) {
3371 self.last_operation_was_abrupt = true;
3372 self.last_operation_was_completion = true;
3373
3374 let inst = self.create_instruction(Instruction::Return);
3375 self.write_stmt(
3376 ReturnStmt {
3377 span: op_loc.unwrap_or(DUMMY_SP),
3378 arg: Some(
3379 ArrayLit {
3380 span: DUMMY_SP,
3381 elems: match expr {
3382 Some(expr) => {
3383 vec![Some(inst.as_arg()), Some(expr.as_arg())]
3384 }
3385 _ => {
3386 vec![Some(inst.as_arg())]
3387 }
3388 },
3389 }
3390 .into(),
3391 ),
3392 }
3393 .into(),
3394 )
3395 }
3396
3397 fn write_break(&mut self, label: Label, op_loc: Option<Span>) {
3402 self.last_operation_was_abrupt = true;
3403
3404 let inst = self.create_instruction(Instruction::Break);
3405 let label = self.create_label(Some(label));
3406 self.write_stmt(
3407 ReturnStmt {
3408 span: op_loc.unwrap_or(DUMMY_SP),
3409 arg: Some(
3410 ArrayLit {
3411 span: DUMMY_SP,
3412 elems: vec![Some(inst.as_arg()), Some(label.as_arg())],
3413 }
3414 .into(),
3415 ),
3416 }
3417 .into(),
3418 )
3419 }
3420
3421 fn write_break_when_true(&mut self, label: Label, cond: Box<Expr>, op_loc: Option<Span>) {
3427 let inst = self.create_instruction(Instruction::Break);
3428 let label = self.create_label(Some(label));
3429 self.write_stmt(
3430 IfStmt {
3431 span: DUMMY_SP,
3432 test: cond,
3433 cons: Box::new(Stmt::Return(ReturnStmt {
3434 span: op_loc.unwrap_or(DUMMY_SP),
3435 arg: Some(
3436 ArrayLit {
3437 span: DUMMY_SP,
3438 elems: vec![Some(inst.as_arg()), Some(label.as_arg())],
3439 }
3440 .into(),
3441 ),
3442 })),
3443 alt: None,
3444 }
3445 .into(),
3446 )
3447 }
3448
3449 fn write_break_when_false(&mut self, label: Label, cond: Box<Expr>, op_loc: Option<Span>) {
3455 let inst = self.create_instruction(Instruction::Break);
3456 let label = self.create_label(Some(label));
3457 self.write_stmt(
3458 IfStmt {
3459 span: DUMMY_SP,
3460 test: UnaryExpr {
3461 span: DUMMY_SP,
3462 op: op!("!"),
3463 arg: cond,
3464 }
3465 .into(),
3466 cons: Box::new(Stmt::Return(ReturnStmt {
3467 span: op_loc.unwrap_or(DUMMY_SP),
3468 arg: Some(
3469 ArrayLit {
3470 span: DUMMY_SP,
3471 elems: vec![Some(inst.as_arg()), Some(label.as_arg())],
3472 }
3473 .into(),
3474 ),
3475 })),
3476 alt: None,
3477 }
3478 .into(),
3479 )
3480 }
3481
3482 fn write_yield(&mut self, expr: Option<Box<Expr>>, op_loc: Option<Span>) {
3487 self.last_operation_was_abrupt = true;
3488
3489 let inst = self.create_instruction(Instruction::Yield);
3490 let elems = match expr {
3491 Some(expr) => {
3492 vec![Some(inst.as_arg()), Some(expr.as_arg())]
3493 }
3494 None => {
3495 vec![Some(inst.as_arg())]
3496 }
3497 };
3498 self.write_stmt(
3499 ReturnStmt {
3500 span: op_loc.unwrap_or(DUMMY_SP),
3501 arg: Some(
3502 ArrayLit {
3503 span: DUMMY_SP,
3504 elems,
3505 }
3506 .into(),
3507 ),
3508 }
3509 .into(),
3510 );
3511 }
3512
3513 fn write_yield_star(&mut self, expr: Box<Expr>, op_loc: Option<Span>) {
3518 self.last_operation_was_abrupt = true;
3519
3520 let arg1 = self.create_instruction(Instruction::YieldStar);
3521 self.write_stmt(
3522 ReturnStmt {
3523 span: op_loc.unwrap_or(DUMMY_SP),
3524 arg: Some(
3525 ArrayLit {
3526 span: DUMMY_SP,
3527 elems: vec![Some(arg1.as_arg()), Some(expr.as_arg())],
3528 }
3529 .into(),
3530 ),
3531 }
3532 .into(),
3533 )
3534 }
3535
3536 fn write_end_finally(&mut self) {
3538 self.last_operation_was_abrupt = true;
3539
3540 let arg = self.create_instruction(Instruction::Endfinally);
3541 self.write_stmt(
3542 ReturnStmt {
3543 span: DUMMY_SP,
3544 arg: Some(
3545 ArrayLit {
3546 span: DUMMY_SP,
3547 elems: vec![Some(arg.as_arg())],
3548 }
3549 .into(),
3550 ),
3551 }
3552 .into(),
3553 )
3554 }
3555
3556 fn hoist_variable_declaration(&mut self, id: &Ident) {
3557 self.hoisted_vars.push(VarDeclarator {
3558 span: DUMMY_SP,
3559 name: id.clone().into(),
3560 init: None,
3561 definite: Default::default(),
3562 })
3563 }
3564
3565 fn get_initialized_variables<'a>(
3566 &self,
3567 initializer: &'a mut VarDecl,
3568 ) -> Vec<&'a mut VarDeclarator> {
3569 initializer
3570 .decls
3571 .iter_mut()
3572 .filter(|v| v.init.is_some())
3573 .collect()
3574 }
3575
3576 fn create_temp_variable(&mut self) -> Ident {
3577 let i = private_ident!("_");
3578
3579 self.hoisted_vars.push(VarDeclarator {
3580 span: DUMMY_SP,
3581 name: i.clone().into(),
3582 init: None,
3583 definite: Default::default(),
3584 });
3585
3586 i
3587 }
3588
3589 fn create_call_binding(
3591 &mut self,
3592 expr: Box<Expr>,
3593 is_new_call: bool,
3594 ) -> (Box<Expr>, Box<Expr>) {
3595 let mut callee = expr;
3596
3597 match &mut *callee {
3598 Expr::Ident(..) => (
3599 callee.clone(),
3600 if is_new_call {
3601 callee
3602 } else {
3603 Expr::undefined(DUMMY_SP)
3604 },
3605 ),
3606
3607 Expr::Member(MemberExpr { obj, .. }) if !is_new_call => {
3608 if obj.is_ident() {
3609 let this_arg = obj.clone();
3610 return (callee, this_arg);
3611 }
3612
3613 let this_arg = self.create_temp_variable();
3614 *obj = Box::new(obj.take().make_assign_to(op!("="), this_arg.clone().into()));
3615
3616 (callee, this_arg.into())
3617 }
3618
3619 _ => {
3620 if !is_new_call {
3621 (callee, Expr::undefined(DUMMY_SP))
3622 } else {
3623 let this_arg = self.create_temp_variable();
3624 let target = callee.make_assign_to(op!("="), this_arg.clone().into());
3625 (Box::new(target), this_arg.into())
3626 }
3627 }
3628 }
3629 }
3630}
3631
3632fn contains_yield<N>(node: &N) -> bool
3633where
3634 N: VisitWith<YieldFinder>,
3635{
3636 let mut v = YieldFinder { found: false };
3637 node.visit_with(&mut v);
3638 v.found
3639}
3640
3641struct YieldFinder {
3642 found: bool,
3643}
3644
3645impl Visit for YieldFinder {
3646 noop_visit_type!(fail);
3647
3648 fn visit_yield_expr(&mut self, _: &YieldExpr) {
3649 self.found = true;
3650 }
3651
3652 fn visit_arrow_expr(&mut self, f: &ArrowExpr) {
3653 f.params.visit_with(self);
3654 }
3655
3656 fn visit_function(&mut self, f: &Function) {
3657 f.decorators.visit_with(self);
3658 f.params.visit_with(self);
3659 }
3660}
3661
3662#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3663pub(super) struct Loc {
3664 pos: BytePos,
3665 value: i32,
3666}
3667
3668struct InvalidToLit<'a> {
3670 map: Option<&'a [Vec<Loc>]>,
3672}
3673
3674impl VisitMut for InvalidToLit<'_> {
3675 noop_visit_mut_type!(fail);
3676
3677 fn visit_mut_expr(&mut self, e: &mut Expr) {
3678 e.visit_mut_children_with(self);
3679
3680 if let Expr::Invalid(Invalid { span }) = e {
3681 if span.lo != BytePos(0) && span.lo == span.hi {
3682 if let Some(Loc { value, .. }) = self
3683 .map
3684 .iter()
3685 .flat_map(|v| v.iter())
3686 .flatten()
3687 .find(|loc| loc.pos == span.lo)
3688 {
3689 *e = (*value as usize).into();
3690 }
3691 }
3692 }
3693 }
3694
3695 fn visit_mut_seq_expr(&mut self, e: &mut SeqExpr) {
3696 e.visit_mut_children_with(self);
3697
3698 e.exprs.retain(|e| !e.is_invalid());
3699 }
3700
3701 fn visit_mut_opt_expr_or_spread(&mut self, e: &mut Option<ExprOrSpread>) {
3702 e.visit_mut_children_with(self);
3703
3704 if let Some(arg) = e {
3705 if arg.expr.is_invalid() {
3706 *e = None;
3707 }
3708 }
3709 }
3710}