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(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 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 })),
1133 }],
1134 ..Default::default()
1135 }
1136 .into()
1137 } else {
1138 ArrayLit {
1139 span: DUMMY_SP,
1140 elems: leading_element
1141 .take()
1142 .into_iter()
1143 .map(Some)
1144 .chain(expressions)
1145 .collect(),
1146 }
1147 .into()
1148 }
1149 }
1150
1151 fn reduce_element(
1152 &mut self,
1153 mut expressions: Vec<Option<ExprOrSpread>>,
1154 mut element: Option<ExprOrSpread>,
1155 leading_element: &mut Option<ExprOrSpread>,
1156 temp: &mut Option<Ident>,
1157 ) -> Vec<Option<ExprOrSpread>> {
1158 if contains_yield(&element) && !expressions.is_empty() {
1159 let has_assigned_temp = temp.is_some();
1160 if temp.is_none() {
1161 *temp = Some(self.declare_local(None));
1162 }
1163
1164 self.emit_assignment(
1165 temp.clone().unwrap().into(),
1166 if has_assigned_temp {
1167 CallExpr {
1168 span: DUMMY_SP,
1169 callee: temp
1170 .clone()
1171 .unwrap()
1172 .make_member(quote_ident!("concat"))
1173 .as_callee(),
1174 args: vec![Box::new(Expr::Array(ArrayLit {
1175 span: DUMMY_SP,
1176 elems: expressions.take(),
1177 }))
1178 .as_arg()],
1179 ..Default::default()
1180 }
1181 .into()
1182 } else {
1183 Box::new(
1184 ArrayLit {
1185 span: DUMMY_SP,
1186 elems: leading_element
1187 .take()
1188 .into_iter()
1189 .map(Some)
1190 .chain(expressions.take())
1191 .collect(),
1192 }
1193 .into(),
1194 )
1195 },
1196 None,
1197 );
1198 *leading_element = None;
1199 }
1200
1201 element.visit_mut_with(self);
1202 if element.is_some() {
1203 expressions.push(element);
1204 }
1205 expressions
1206 }
1207
1208 fn reduce_property(
1209 &mut self,
1210 mut expressions: Vec<Box<Expr>>,
1211 property: CompiledProp,
1212 temp: &mut Ident,
1213 ) -> Vec<Box<Expr>> {
1214 if match &property {
1215 CompiledProp::Prop(p) => contains_yield(p),
1216 CompiledProp::Accessor(g, s) => {
1217 g.as_ref().map_or(false, contains_yield) || s.as_ref().map_or(false, contains_yield)
1218 }
1219 } && !expressions.is_empty()
1220 {
1221 self.emit_stmt(
1222 ExprStmt {
1223 span: DUMMY_SP,
1224 expr: Expr::from_exprs(expressions.take()),
1225 }
1226 .into(),
1227 );
1228 }
1229
1230 let mut expression: Expr = match property {
1231 CompiledProp::Prop(p) => match p {
1232 Prop::Shorthand(p) => AssignExpr {
1233 span: p.span,
1234 op: op!("="),
1235 left: MemberExpr {
1236 span: DUMMY_SP,
1237 obj: temp.clone().into(),
1238 prop: MemberProp::Ident(p.clone().into()),
1239 }
1240 .into(),
1241 right: p.into(),
1242 }
1243 .into(),
1244 Prop::KeyValue(p) => AssignExpr {
1245 span: DUMMY_SP,
1246 op: op!("="),
1247 left: MemberExpr {
1248 span: DUMMY_SP,
1249 obj: temp.clone().into(),
1250 prop: p.key.into(),
1251 }
1252 .into(),
1253 right: p.value,
1254 }
1255 .into(),
1256 Prop::Assign(_) => {
1257 unreachable!("assignment property be removed before generator pass")
1258 }
1259 Prop::Getter(_) | Prop::Setter(_) => {
1260 unreachable!("getter/setter property be compiled as CompiledProp::Accessor")
1261 }
1262 Prop::Method(p) => AssignExpr {
1263 span: DUMMY_SP,
1264 op: op!("="),
1265 left: MemberExpr {
1266 span: DUMMY_SP,
1267 obj: temp.clone().into(),
1268 prop: p.key.into(),
1269 }
1270 .into(),
1271 right: p.function.into(),
1272 }
1273 .into(),
1274 },
1275 CompiledProp::Accessor(getter, setter) => {
1276 let key = getter
1277 .as_ref()
1278 .map(|v| v.key.clone())
1279 .unwrap_or_else(|| setter.as_ref().unwrap().key.clone());
1280
1281 let desc = ObjectLit {
1282 span: DUMMY_SP,
1283 props: getter
1284 .map(|g| KeyValueProp {
1285 key: quote_ident!("get").into(),
1286 value: Function {
1287 params: Vec::new(),
1288 span: g.span,
1289 body: g.body,
1290 is_generator: false,
1291 is_async: false,
1292 ..Default::default()
1293 }
1294 .into(),
1295 })
1296 .into_iter()
1297 .chain(setter.map(|s| {
1298 KeyValueProp {
1299 key: quote_ident!("set").into(),
1300 value: Function {
1301 params: vec![(*s.param).into()],
1302 span: s.span,
1303 body: s.body,
1304 is_generator: false,
1305 is_async: false,
1306 ..Default::default()
1307 }
1308 .into(),
1309 }
1310 }))
1311 .map(Prop::KeyValue)
1312 .map(Box::new)
1313 .map(PropOrSpread::Prop)
1314 .collect(),
1315 };
1316
1317 CallExpr {
1318 span: DUMMY_SP,
1319 callee: helper!(define_property),
1320 args: vec![
1321 temp.clone().as_arg(),
1322 prop_name_to_expr_value(key).as_arg(),
1323 desc.as_arg(),
1324 ],
1325 ..Default::default()
1326 }
1327 .into()
1328 }
1329 };
1330
1331 expression.visit_mut_with(self);
1332 if !expression.is_invalid() {
1333 expressions.push(Box::new(expression));
1334 }
1335 expressions
1336 }
1337
1338 fn visit_left_associative_bin_expr(&mut self, node: &mut BinExpr) -> Option<Expr> {
1339 if contains_yield(&node.right) {
1340 if matches!(node.op, op!("||") | op!("&&")) {
1341 return Some(self.visit_logical_bin_expr(node));
1342 }
1343
1344 node.left.visit_mut_with(self);
1354 node.left = self.cache_expression(node.left.take()).into();
1355 node.right.visit_mut_with(self);
1356 return None;
1357 }
1358
1359 node.visit_mut_children_with(self);
1360 None
1361 }
1362
1363 fn visit_logical_bin_expr(&mut self, node: &mut BinExpr) -> Expr {
1364 let result_label = self.define_label();
1394 let result_local = self.declare_local(None);
1395
1396 let left_span = node.left.span();
1397 node.left.visit_mut_with(self);
1398 self.emit_assignment(
1399 result_local.clone().into(),
1400 node.left.take(),
1401 Some(left_span),
1402 );
1403
1404 if node.op == op!("&&") {
1405 self.emit_break_when_false(
1407 result_label,
1408 Box::new(result_local.clone().into()),
1409 Some(left_span),
1410 )
1411 } else {
1412 self.emit_break_when_true(
1414 result_label,
1415 Box::new(result_local.clone().into()),
1416 Some(left_span),
1417 )
1418 }
1419
1420 let right_span = node.right.span();
1421 node.right.visit_mut_with(self);
1422 self.emit_assignment(
1423 result_local.clone().into(),
1424 node.right.take(),
1425 Some(right_span),
1426 );
1427 self.mark_label(result_label);
1428
1429 result_local.into()
1430 }
1431
1432 fn transform_and_emit_stmts(&mut self, stmts: Vec<Stmt>, start: usize) {
1433 for s in stmts.into_iter().skip(start) {
1434 self.transform_and_emit_stmt(s);
1435 }
1436 }
1437
1438 fn transform_and_emit_embedded_stmt(&mut self, node: Stmt) {
1439 if let Stmt::Block(block) = node {
1440 self.transform_and_emit_stmts(block.stmts, 0);
1441 } else {
1442 self.transform_and_emit_stmt(node);
1443 }
1444 }
1445
1446 fn transform_and_emit_stmt(&mut self, node: Stmt) {
1447 let _tracing = dev_span!("transform_and_emit_stmt");
1448
1449 let saved_in_statement_containing_yield = self.in_statement_containing_yield;
1450 if !self.in_statement_containing_yield {
1451 self.in_statement_containing_yield = contains_yield(&node);
1452 }
1453
1454 self.transform_and_emit_stmt_worker(node);
1455 self.in_statement_containing_yield = saved_in_statement_containing_yield;
1456 }
1457
1458 fn transform_and_emit_stmt_worker(&mut self, mut node: Stmt) {
1459 match node {
1460 Stmt::Block(s) => self.transform_and_emit_block(s),
1461 Stmt::Expr(s) => self.transform_and_emit_expr_stmt(s),
1462 Stmt::If(s) => self.transform_and_emit_if_stmt(s),
1463 Stmt::DoWhile(s) => self.transform_and_emit_do_stmt(s),
1464 Stmt::While(s) => self.transform_and_emit_while_stmt(s),
1465 Stmt::For(s) => self.transform_and_emit_for_stmt(s),
1466 Stmt::ForIn(s) => self.transform_and_emit_for_in_stmt(s),
1467 Stmt::Continue(s) => self.transform_and_emit_continue_stmt(s),
1468 Stmt::Break(s) => self.transform_and_emit_break_stmt(s),
1469 Stmt::Return(s) => self.transform_and_emit_return_stmt(s),
1470 Stmt::With(s) => self.transform_and_emit_with_stmt(s),
1471 Stmt::Switch(s) => self.transform_and_emit_switch_stmt(s),
1472 Stmt::Labeled(s) => self.transform_and_emit_labeled_stmt(s),
1473 Stmt::Throw(s) => self.transform_and_emit_throw_stmt(s),
1474 Stmt::Try(s) => self.transform_and_emit_try_stmt(*s),
1475 _ => {
1476 node.visit_mut_with(self);
1477
1478 self.emit_stmt(node);
1479 }
1480 }
1481 }
1482
1483 fn transform_and_emit_block(&mut self, mut node: BlockStmt) {
1484 if contains_yield(&node) {
1485 self.transform_and_emit_stmts(node.stmts, 0);
1486 } else {
1487 node.visit_mut_with(self);
1488 self.emit_stmt(node.into());
1489 }
1490 }
1491
1492 fn transform_and_emit_expr_stmt(&mut self, mut node: ExprStmt) {
1493 node.visit_mut_with(self);
1494
1495 self.emit_stmt(node.into());
1496 }
1497
1498 fn transform_and_emit_var_decl_list(&mut self, mut node: Box<VarDecl>) {
1499 for variable in &node.decls {
1500 self.hoist_variable_declaration(&Ident::from(variable.name.as_ident().unwrap()));
1501 }
1502
1503 let mut variables = self.get_initialized_variables(&mut node);
1504 let var_len = variables.len();
1505 let mut variables_written = 0;
1506 let mut pending_expressions = Vec::new();
1507 let mut cnt = 0;
1508
1509 while variables_written < var_len {
1510 #[cfg(debug_assertions)]
1511 debug!("variables_written: {} / {}", variables_written, var_len);
1512
1513 for (_i, variable) in variables.iter_mut().enumerate().skip(variables_written) {
1514 if contains_yield(&**variable) && cnt != 0 {
1515 break;
1516 }
1517
1518 let expr = self.transform_initialized_variable(variable.take());
1520
1521 pending_expressions.extend(expr.map(Expr::from).map(Box::new));
1522 cnt += 1;
1523 }
1524
1525 if cnt > 0 {
1526 variables_written += cnt;
1527 cnt = 0;
1528
1529 self.emit_stmt(
1530 ExprStmt {
1531 span: DUMMY_SP,
1532 expr: if pending_expressions.len() == 1 {
1533 pending_expressions.pop().unwrap()
1534 } else {
1535 SeqExpr {
1536 span: DUMMY_SP,
1537 exprs: take(&mut pending_expressions),
1538 }
1539 .into()
1540 },
1541 }
1542 .into(),
1543 )
1544 }
1545 }
1546 }
1547
1548 fn transform_initialized_variable(&mut self, mut node: VarDeclarator) -> Option<AssignExpr> {
1549 node.init.visit_mut_with(self);
1550
1551 node.init.map(|right| AssignExpr {
1552 span: node.span,
1553 op: op!("="),
1554 left: node.name.clone().try_into().unwrap(),
1555 right,
1556 })
1557 }
1558
1559 fn transform_and_emit_if_stmt(&mut self, mut node: IfStmt) {
1560 if contains_yield(&node) {
1561 if contains_yield(&node.cons) || contains_yield(&node.alt) {
1576 let end_label = self.define_label();
1577 let else_label = node.alt.as_ref().map(|_| self.define_label());
1578
1579 node.test.visit_mut_with(self);
1580 let span = node.test.span();
1581 self.emit_break_when_false(else_label.unwrap_or(end_label), node.test, Some(span));
1582
1583 self.transform_and_emit_embedded_stmt(*node.cons);
1584
1585 if let Some(alt) = node.alt {
1586 self.emit_break(end_label, None);
1587 self.mark_label(else_label.unwrap());
1588 self.transform_and_emit_embedded_stmt(*alt);
1589 }
1590 self.mark_label(end_label);
1591 } else {
1592 node.visit_mut_with(self);
1593 self.emit_stmt(node.into());
1594 }
1595 } else {
1596 node.visit_mut_with(self);
1597 self.emit_stmt(node.into());
1598 }
1599 }
1600
1601 fn transform_and_emit_do_stmt(&mut self, mut node: DoWhileStmt) {
1602 if contains_yield(&node) {
1603 let condition_label = self.define_label();
1619 let loop_label = self.define_label();
1620
1621 self.begin_loop_block(condition_label);
1622 self.mark_label(loop_label);
1623 self.transform_and_emit_embedded_stmt(*node.body);
1624 self.mark_label(condition_label);
1625 node.test.visit_mut_with(self);
1626 let span = node.test.span();
1627 self.emit_break_when_true(loop_label, node.test, Some(span));
1628 self.end_loop_block();
1629 } else {
1630 node.visit_mut_with(self);
1631 self.emit_stmt(node.into());
1632 }
1633 }
1634
1635 fn transform_and_emit_while_stmt(&mut self, mut node: WhileStmt) {
1636 let _tracing = dev_span!("transform_and_emit_while_stmt");
1637
1638 if contains_yield(&node) {
1639 let loop_label = self.define_label();
1654 let end_label = self.begin_loop_block(loop_label);
1655 self.mark_label(loop_label);
1656 node.test.visit_mut_with(self);
1657 self.emit_break_when_false(end_label, node.test, None);
1658 self.transform_and_emit_embedded_stmt(*node.body);
1659 self.emit_break(loop_label, None);
1660 self.end_loop_block();
1661 } else {
1662 node.visit_mut_with(self);
1663
1664 self.emit_stmt(node.into());
1665 }
1666 }
1667
1668 fn transform_and_emit_for_stmt(&mut self, mut node: ForStmt) {
1669 if contains_yield(&node) {
1670 let condition_label = self.define_label();
1689 let increment_label = self.define_label();
1690 let end_label = self.begin_loop_block(increment_label);
1691
1692 if let Some(init) = node.init {
1693 match init {
1694 VarDeclOrExpr::VarDecl(init) => {
1695 self.transform_and_emit_var_decl_list(init);
1696 }
1697 VarDeclOrExpr::Expr(mut init) => {
1698 init.visit_mut_with(self);
1699 self.emit_stmt(
1700 ExprStmt {
1701 span: init.span(),
1702 expr: init,
1703 }
1704 .into(),
1705 );
1706 }
1707 }
1708 }
1709
1710 self.mark_label(condition_label);
1711
1712 if let Some(mut cond) = node.test {
1713 cond.visit_mut_with(self);
1714 self.emit_break_when_false(end_label, cond, None);
1715 }
1716
1717 self.transform_and_emit_embedded_stmt(*node.body);
1718
1719 self.mark_label(increment_label);
1720
1721 if let Some(mut incrementor) = node.update {
1722 incrementor.visit_mut_with(self);
1723
1724 self.emit_stmt(
1725 ExprStmt {
1726 span: incrementor.span(),
1727 expr: incrementor,
1728 }
1729 .into(),
1730 );
1731 }
1732
1733 self.emit_break(condition_label, None);
1734 self.end_loop_block();
1735 } else {
1736 node.visit_mut_with(self);
1737 self.emit_stmt(node.into());
1738 }
1739 }
1740
1741 fn transform_and_emit_for_in_stmt(&mut self, mut node: ForInStmt) {
1742 if contains_yield(&node) {
1743 let keys_array = self.declare_local(None);
1765 let key = self.declare_local(None);
1766 let keys_index = private_ident!("_i");
1767
1768 self.hoist_variable_declaration(&keys_index);
1769
1770 self.emit_assignment(
1771 keys_array.clone().into(),
1772 Box::new(ArrayLit::dummy().into()),
1773 None,
1774 );
1775
1776 node.right.visit_mut_with(self);
1777 self.emit_stmt(
1778 ForInStmt {
1779 span: DUMMY_SP,
1780 left: ForHead::Pat(key.clone().into()),
1781 right: node.right.take(),
1782 body: Box::new(Stmt::Expr(ExprStmt {
1783 span: DUMMY_SP,
1784 expr: CallExpr {
1785 span: DUMMY_SP,
1786 callee: keys_array
1787 .clone()
1788 .make_member(quote_ident!("push"))
1789 .as_callee(),
1790 args: vec![key.as_arg()],
1791 ..Default::default()
1792 }
1793 .into(),
1794 })),
1795 }
1796 .into(),
1797 );
1798
1799 self.emit_assignment(keys_index.clone().into(), 0.into(), None);
1800
1801 let condition_label = self.define_label();
1802 let increment_label = self.define_label();
1803 let end_label = self.begin_loop_block(increment_label);
1804
1805 self.mark_label(condition_label);
1806 self.emit_break_when_false(
1807 end_label,
1808 Box::new(keys_index.clone().make_bin(
1809 op!("<"),
1810 keys_array.clone().make_member(quote_ident!("length")),
1811 )),
1812 None,
1813 );
1814
1815 let variable = match node.left {
1816 ForHead::VarDecl(initializer) => {
1817 for variable in initializer.decls.iter() {
1818 self.hoist_variable_declaration(&Ident::from(
1819 variable.name.as_ident().unwrap(),
1820 ));
1821 }
1822
1823 initializer.decls[0].name.clone()
1824 }
1825 ForHead::Pat(mut initializer) => {
1826 initializer.visit_mut_with(self);
1827 *initializer
1828 }
1829
1830 ForHead::UsingDecl(..) => {
1831 unreachable!("using declaration must be removed by previous pass")
1832 }
1833 };
1834 self.emit_assignment(
1835 variable.try_into().unwrap(),
1836 MemberExpr {
1837 span: DUMMY_SP,
1838 obj: Box::new(keys_array.into()),
1839 prop: MemberProp::Computed(ComputedPropName {
1840 span: DUMMY_SP,
1841 expr: Box::new(keys_index.clone().into()),
1842 }),
1843 }
1844 .into(),
1845 None,
1846 );
1847 self.transform_and_emit_embedded_stmt(*node.body);
1848
1849 self.mark_label(increment_label);
1850 self.emit_stmt(
1851 ExprStmt {
1852 span: DUMMY_SP,
1853 expr: UpdateExpr {
1854 span: DUMMY_SP,
1855 prefix: false,
1856 op: op!("++"),
1857 arg: Box::new(keys_index.clone().into()),
1858 }
1859 .into(),
1860 }
1861 .into(),
1862 );
1863
1864 self.emit_break(condition_label, None);
1865 self.end_loop_block();
1866 } else {
1867 node.visit_mut_with(self);
1868 self.emit_stmt(node.into());
1869 }
1870 }
1871
1872 fn transform_and_emit_continue_stmt(&mut self, node: ContinueStmt) {
1873 let label = self.find_continue_target(node.label.as_ref().map(|l| l.sym.clone()));
1874 if label.0 > 0 {
1875 self.emit_break(label, Some(node.span));
1876 } else {
1877 self.emit_stmt(node.into())
1880 }
1881 }
1882
1883 fn transform_and_emit_break_stmt(&mut self, node: BreakStmt) {
1884 let label = self.find_break_target(node.label.as_ref().map(|l| l.sym.clone()));
1885 if label.0 > 0 {
1886 self.emit_break(label, Some(node.span));
1887 } else {
1888 self.emit_stmt(node.into())
1891 }
1892 }
1893
1894 fn transform_and_emit_return_stmt(&mut self, mut s: ReturnStmt) {
1895 s.arg.visit_mut_with(self);
1896 self.emit_return(s.arg, Some(s.span))
1897 }
1898
1899 fn transform_and_emit_with_stmt(&mut self, mut node: WithStmt) {
1900 if contains_yield(&node) {
1901 node.obj.visit_mut_with(self);
1912 let obj = self.cache_expression(node.obj);
1913 self.begin_with_block(obj);
1914 self.transform_and_emit_embedded_stmt(*node.body);
1915 self.end_with_block();
1916 } else {
1917 node.visit_mut_with(self);
1918 self.emit_stmt(node.into());
1919 }
1920 }
1921
1922 fn transform_and_emit_switch_stmt(&mut self, mut node: SwitchStmt) {
1923 if contains_yield(&node.cases) {
1924 let end_label = self.begin_switch_block();
1957 node.discriminant.visit_mut_with(self);
1958 let expression = self.cache_expression(node.discriminant);
1959
1960 let mut clause_labels = Vec::new();
1964 let mut default_clause_index = -1i32;
1965
1966 for (i, clause) in node.cases.iter().enumerate() {
1967 clause_labels.push(self.define_label());
1968 if clause.test.is_none() && default_clause_index == -1 {
1969 default_clause_index = i as _;
1970 }
1971 }
1972
1973 let mut clauses_written = 0;
1978 let mut pending_clauses = Vec::new();
1979
1980 while clauses_written < node.cases.len() {
1981 #[cfg(debug_assertions)]
1982 debug!("clauses_written: {}", clauses_written);
1983
1984 let mut default_clauses_skipped = 0;
1985
1986 for (i, clause) in node.cases.iter_mut().enumerate().skip(clauses_written) {
1987 if clause.test.is_some() {
1988 if contains_yield(&clause.test) && !pending_clauses.is_empty() {
1989 break;
1990 }
1991
1992 clause.test.visit_mut_with(self);
1993 let span = clause.test.span();
1994 pending_clauses.push(SwitchCase {
1995 span: DUMMY_SP,
1996 test: clause.test.take(),
1997 cons: vec![self
1998 .create_inline_break(clause_labels[i], Some(span))
1999 .into()],
2000 })
2001 } else {
2002 default_clauses_skipped += 1;
2003 }
2004 }
2005
2006 if !pending_clauses.is_empty() {
2007 clauses_written += pending_clauses.len();
2008 self.emit_stmt(
2009 SwitchStmt {
2010 span: DUMMY_SP,
2011 discriminant: expression.clone().into(),
2012 cases: take(&mut pending_clauses),
2013 }
2014 .into(),
2015 );
2016 }
2017
2018 if default_clauses_skipped > 0 {
2019 clauses_written += default_clauses_skipped;
2020 }
2021 }
2022
2023 if default_clause_index >= 0 {
2024 self.emit_break(clause_labels[default_clause_index as usize], None);
2025 } else {
2026 self.emit_break(end_label, None);
2027 }
2028
2029 for (i, clause) in node.cases.into_iter().enumerate() {
2030 self.mark_label(clause_labels[i]);
2031 self.transform_and_emit_stmts(clause.cons, 0);
2032 }
2033
2034 self.end_switch_block()
2035 } else {
2036 node.visit_mut_with(self);
2037 self.emit_stmt(node.into())
2038 }
2039 }
2040
2041 fn transform_and_emit_labeled_stmt(&mut self, mut node: LabeledStmt) {
2042 #[cfg(debug_assertions)]
2043 debug!("transform_and_emit_labeled_stmt: {:?}", node.label);
2044
2045 if contains_yield(&node) {
2046 self.begin_labeled_block(node.label.sym);
2057 self.transform_and_emit_embedded_stmt(*node.body);
2058 self.end_labeled_block();
2059 } else {
2060 node.visit_mut_with(self);
2061 self.emit_stmt(node.into());
2062 }
2063 }
2064
2065 fn transform_and_emit_throw_stmt(&mut self, mut node: ThrowStmt) {
2066 node.arg.visit_mut_with(self);
2067 self.emit_throw(node.arg, Some(node.span))
2068 }
2069
2070 fn transform_and_emit_try_stmt(&mut self, mut node: TryStmt) {
2071 let _tracing = dev_span!("transform_and_emit_try_stmt");
2072
2073 if contains_yield(&node) {
2074 self.begin_exception_block();
2105 self.transform_and_emit_embedded_stmt(node.block.into());
2106 if let Some(catch) = node.handler {
2107 self.begin_catch_block(VarDeclarator {
2108 name: catch.param.clone().unwrap(),
2109 ..Take::dummy()
2110 });
2111 self.transform_and_emit_embedded_stmt(catch.body.into());
2112 }
2113
2114 if let Some(finalizer) = node.finalizer {
2115 self.begin_finally_block();
2116 self.transform_and_emit_embedded_stmt(finalizer.into());
2117 }
2118
2119 self.end_exception_block();
2120 } else {
2121 node.visit_mut_with(self);
2122 self.emit_stmt(node.into());
2123 }
2124 }
2125
2126 fn count_initial_nodes_without_yield<N>(&self, nodes: &[N]) -> usize
2127 where
2128 N: VisitWith<YieldFinder>,
2129 {
2130 for (i, node) in nodes.iter().enumerate() {
2131 if contains_yield(node) {
2132 return i;
2133 }
2134 }
2135
2136 0
2137 }
2138
2139 fn cache_expression(&mut self, node: Box<Expr>) -> Ident {
2140 match *node {
2141 Expr::Ident(i) => i,
2142 _ => {
2143 let span = node.span();
2144
2145 let temp = self.create_temp_variable();
2146 self.emit_assignment(temp.clone().into(), node, Some(span));
2147 temp
2148 }
2149 }
2150 }
2151
2152 fn declare_local(&mut self, name: Option<Atom>) -> Ident {
2153 let temp = name
2154 .map(|name| private_ident!(name))
2155 .unwrap_or_else(|| private_ident!("_tmp"));
2156
2157 self.hoist_variable_declaration(&temp);
2158 temp
2159 }
2160
2161 fn define_label(&mut self) -> Label {
2163 if self.label_offsets.is_none() {
2164 self.label_offsets = Some(Default::default());
2165 }
2166
2167 let label = Label(self.next_label_id as _);
2168 self.next_label_id += 1;
2169 #[cfg(debug_assertions)]
2170 debug!("define_label: {:?}", label);
2171
2172 if label.0 as usize >= self.label_offsets.as_ref().unwrap().len() {
2173 self.label_offsets
2174 .as_mut()
2175 .unwrap()
2176 .resize(label.0 as usize + 1, 0);
2177 }
2178 self.label_offsets.as_mut().unwrap()[label.0 as usize] = -1;
2179 label
2180 }
2181
2182 fn mark_label(&mut self, label: Label) {
2184 debug_assert!(self.label_offsets.is_some(), "No labels were defined.");
2185
2186 if label.0 as usize >= self.label_offsets.as_ref().unwrap().len() {
2187 self.label_offsets
2188 .as_mut()
2189 .unwrap()
2190 .resize(label.0 as usize + 1, Default::default());
2191 }
2192
2193 self.label_offsets.as_mut().unwrap()[label.0 as usize] =
2194 self.operations.as_deref().map_or(0, |v| v.len() as _);
2195
2196 #[cfg(debug_assertions)]
2197 debug!(
2198 "mark_label: {:?}; offset: {}",
2199 label,
2200 self.label_offsets.as_mut().unwrap()[label.0 as usize]
2201 );
2202 }
2203
2204 fn begin_block(&mut self, block: CodeBlock) -> Ptr<CodeBlock> {
2208 if self.blocks.is_none() {
2209 self.blocks = Some(Default::default());
2210 self.block_actions = Some(Default::default());
2211 self.block_offsets = Some(Default::default());
2212 self.block_stack = Some(Default::default());
2213 }
2214
2215 #[cfg(debug_assertions)]
2216 let index = self.block_actions.as_ref().unwrap().len();
2217
2218 #[cfg(debug_assertions)]
2219 if cfg!(debug_assertions) {
2220 debug!("Begin block {}: {:?}", index, block);
2221 }
2222
2223 let block = Rc::new(RefCell::new(block));
2224
2225 self.block_actions.as_mut().unwrap().push(BlockAction::Open);
2226 self.block_offsets
2227 .as_mut()
2228 .unwrap()
2229 .push(self.operations.as_ref().map_or(0, |v| v.len()));
2230 self.blocks.as_mut().unwrap().push(block.clone());
2231 self.block_stack.as_mut().unwrap().push(block.clone());
2232
2233 block
2234 }
2235
2236 fn end_block(&mut self) -> Ptr<CodeBlock> {
2238 let block = self.peek_block().expect("beginBlock was never called.");
2239
2240 #[cfg(debug_assertions)]
2241 let index = self.block_actions.as_ref().unwrap().len();
2242
2243 #[cfg(debug_assertions)]
2244 debug!("End block {}", index);
2245
2246 self.block_actions
2247 .as_mut()
2248 .unwrap()
2249 .push(BlockAction::Close);
2250 self.block_offsets
2251 .as_mut()
2252 .unwrap()
2253 .push(self.operations.as_ref().map_or(0, |v| v.len()));
2254 self.blocks.as_mut().unwrap().push(block.clone());
2255 self.block_stack.as_mut().unwrap().pop();
2256 block
2257 }
2258
2259 fn peek_block(&self) -> Option<Ptr<CodeBlock>> {
2261 self.block_stack.as_ref().and_then(|v| v.last().cloned())
2262 }
2263
2264 fn peek_block_kind(&self) -> Option<CodeBlockKind> {
2266 self.peek_block().map(|b| match &*b.borrow() {
2267 CodeBlock::With(..) => CodeBlockKind::With,
2268 CodeBlock::Exception(..) => CodeBlockKind::Exception,
2269 CodeBlock::Labeled(..) => CodeBlockKind::Labeled,
2270 CodeBlock::Switch(..) => CodeBlockKind::Switch,
2271 CodeBlock::Loop(..) => CodeBlockKind::Loop,
2272 })
2273 }
2274
2275 fn begin_with_block(&mut self, expr: Ident) {
2279 let start_label = self.define_label();
2280 let end_label = self.define_label();
2281 self.mark_label(start_label);
2282 self.begin_block(CodeBlock::With(WithBlock {
2283 expression: expr,
2284 start_label,
2285 end_label,
2286 }));
2287 }
2288
2289 fn end_with_block(&mut self) {
2291 debug_assert!(self.peek_block_kind() == Some(CodeBlockKind::With));
2292 let block = self.end_block();
2293 let b = block.borrow();
2294 if let CodeBlock::With(block) = &*b {
2295 self.mark_label(block.end_label);
2296 } else {
2297 unreachable!()
2298 }
2299 }
2300
2301 fn begin_exception_block(&mut self) -> Label {
2303 let _tracing = dev_span!("begin_exception_block");
2304
2305 let start_label = self.define_label();
2306 let end_label = self.define_label();
2307 self.mark_label(start_label);
2308 self.begin_block(CodeBlock::Exception(ExceptionBlock {
2309 state: ExceptionBlockState::Try,
2310 start_label,
2311 end_label,
2312 catch_variable: Default::default(),
2313 catch_label: Default::default(),
2314 finally_label: Default::default(),
2315 }));
2316 self.emit_nop();
2317 end_label
2318 }
2319
2320 fn begin_catch_block(&mut self, variable: VarDeclarator) {
2326 debug_assert!(self.peek_block_kind() == Some(CodeBlockKind::Exception));
2327
2328 let name = variable.name.expect_ident().into();
2329 self.hoist_variable_declaration(&name);
2330
2331 let peeked = self.peek_block().unwrap();
2333 let exception = peeked.borrow_mut();
2334 let mut exception = RefMut::map(exception, |v| match v {
2335 CodeBlock::Exception(v) => v,
2336 _ => unreachable!(),
2337 });
2338 debug_assert!(exception.state < ExceptionBlockState::Catch);
2339
2340 let end_label = exception.end_label;
2341 self.emit_break(end_label, None);
2342
2343 let catch_label = self.define_label();
2344 self.mark_label(catch_label);
2345 exception.state = ExceptionBlockState::Catch;
2346 exception.catch_variable = Some(name.clone());
2347 exception.catch_label = Some(catch_label);
2348
2349 self.emit_assignment(
2350 name.clone().into(),
2351 CallExpr {
2352 span: DUMMY_SP,
2353 callee: self
2354 .state
2355 .clone()
2356 .make_member(quote_ident!("sent"))
2357 .as_callee(),
2358 args: Vec::new(),
2359 ..Default::default()
2360 }
2361 .into(),
2362 None,
2363 );
2364
2365 self.emit_nop();
2366 }
2367
2368 fn begin_finally_block(&mut self) {
2370 let _tracing = dev_span!("begin_finally_block");
2371
2372 debug_assert!(self.peek_block_kind() == Some(CodeBlockKind::Exception));
2373
2374 let block = self.peek_block().unwrap();
2375 let mut b = block.borrow_mut();
2376 if let CodeBlock::Exception(block) = &mut *b {
2377 debug_assert!(block.state < ExceptionBlockState::Finally);
2378
2379 let end_label = block.end_label;
2380 self.emit_break(end_label, None);
2381
2382 let finally_label = self.define_label();
2383 self.mark_label(finally_label);
2384 block.state = ExceptionBlockState::Finally;
2385 block.finally_label = Some(finally_label);
2386 } else {
2387 unreachable!()
2388 }
2389 }
2390
2391 fn end_exception_block(&mut self) {
2393 debug_assert!(self.peek_block_kind() == Some(CodeBlockKind::Exception));
2394 let block = self.end_block();
2395 let mut b = block.borrow_mut();
2396 if let CodeBlock::Exception(block) = &mut *b {
2397 let state = block.state;
2398 if state < ExceptionBlockState::Finally {
2399 self.emit_break(block.end_label, None);
2400 } else {
2401 self.emit_endfinally();
2402 }
2403 self.mark_label(block.end_label);
2404 self.emit_nop();
2405 block.state = ExceptionBlockState::Done;
2406 } else {
2407 unreachable!()
2408 }
2409 }
2410
2411 fn begin_script_loop_block(&mut self) {
2414 self.begin_block(CodeBlock::Loop(LoopBlock {
2415 is_script: true,
2416 break_label: Label(-1),
2417 continue_label: Label(-1),
2418 }));
2419 }
2420
2421 fn begin_loop_block(&mut self, continue_label: Label) -> Label {
2428 let _tracing = dev_span!("begin_loop_block");
2429
2430 let break_label = self.define_label();
2431 self.begin_block(CodeBlock::Loop(LoopBlock {
2432 is_script: false,
2433 break_label,
2434 continue_label,
2435 }));
2436 break_label
2437 }
2438
2439 fn end_loop_block(&mut self) {
2442 debug_assert!(self.peek_block_kind() == Some(CodeBlockKind::Loop));
2443 let block = self.end_block();
2444 let block = block.borrow();
2445 if let CodeBlock::Loop(block) = &*block {
2446 let break_label = block.break_label;
2447 if !block.is_script {
2448 self.mark_label(break_label);
2449 }
2450 } else {
2451 unreachable!()
2452 }
2453 }
2454
2455 fn begin_script_switch_block(&mut self) {
2458 self.begin_block(CodeBlock::Switch(SwitchBlock {
2459 is_script: true,
2460 break_label: Label(-1),
2461 }));
2462 }
2463
2464 fn begin_switch_block(&mut self) -> Label {
2470 let break_label = self.define_label();
2471 self.begin_block(CodeBlock::Switch(SwitchBlock {
2472 is_script: false,
2473 break_label,
2474 }));
2475 break_label
2476 }
2477
2478 fn end_switch_block(&mut self) {
2481 debug_assert!(self.peek_block_kind() == Some(CodeBlockKind::Switch));
2482 let block = self.end_block();
2483 let block = block.borrow();
2484 if let CodeBlock::Switch(block) = &*block {
2485 let break_label = block.break_label;
2486 if !block.is_script {
2487 self.mark_label(break_label);
2488 }
2489 } else {
2490 unreachable!()
2491 }
2492 }
2493
2494 fn begin_script_labeled_block(&mut self, label_text: Atom) {
2495 self.begin_block(CodeBlock::Labeled(LabeledBlock {
2496 is_script: true,
2497 label_text,
2498 break_label: Label(-1),
2499 }));
2500 }
2501
2502 fn begin_labeled_block(&mut self, label_text: Atom) {
2503 let break_label = self.define_label();
2504 self.begin_block(CodeBlock::Labeled(LabeledBlock {
2505 is_script: false,
2506 label_text,
2507 break_label,
2508 }));
2509 }
2510
2511 fn end_labeled_block(&mut self) {
2512 let block = self.end_block();
2513 if !block.borrow().is_script() {
2514 let break_label = match &*block.borrow() {
2515 CodeBlock::Labeled(block) => block.break_label,
2516 _ => unreachable!(),
2517 };
2518 self.mark_label(break_label);
2519 }
2520 }
2521
2522 fn supports_unlabeled_break(&self, block: &CodeBlock) -> bool {
2524 matches!(block, CodeBlock::Switch(..) | CodeBlock::Loop(..))
2525 }
2526
2527 fn supports_labeled_break_or_continue(&self, block: &CodeBlock) -> bool {
2530 matches!(block, CodeBlock::Labeled(..))
2531 }
2532
2533 fn supports_unlabeled_continue(&self, block: &CodeBlock) -> bool {
2535 matches!(block, CodeBlock::Loop(..))
2536 }
2537
2538 fn has_immediate_containing_labeled_block(&self, label_text: &Atom, start: usize) -> bool {
2539 for i in (0..=start).rev() {
2540 let block = self.block_stack.as_ref().unwrap()[i].clone();
2541 if self.supports_labeled_break_or_continue(&block.borrow()) {
2542 if let CodeBlock::Labeled(block) = &*block.borrow() {
2543 if block.label_text == *label_text {
2544 return true;
2545 }
2546 } else {
2547 unreachable!()
2548 }
2549 } else {
2550 break;
2551 }
2552 }
2553
2554 false
2555 }
2556
2557 fn find_break_target(&self, label_text: Option<Atom>) -> Label {
2561 #[cfg(debug_assertions)]
2562 debug!("find_break_target: label_text={:?}", label_text);
2563
2564 if let Some(block_stack) = &self.block_stack {
2565 if let Some(label_text) = label_text {
2566 for i in (0..=block_stack.len() - 1).rev() {
2567 let block = &block_stack[i];
2568 if (self.supports_labeled_break_or_continue(&block.borrow())
2569 && block.borrow().label_text().unwrap() == label_text)
2570 || (self.supports_unlabeled_break(&block.borrow())
2571 && self.has_immediate_containing_labeled_block(&label_text, i - 1))
2572 {
2573 return block.borrow().break_label().unwrap();
2574 }
2575 }
2576 } else {
2577 for i in (0..=block_stack.len() - 1).rev() {
2578 let block = &block_stack[i];
2579 if self.supports_unlabeled_break(&block.borrow()) {
2580 return block.borrow().break_label().unwrap();
2581 }
2582 }
2583 }
2584 }
2585
2586 Label(0)
2587 }
2588
2589 fn find_continue_target(&self, label_text: Option<Atom>) -> Label {
2593 if let Some(block_stack) = &self.block_stack {
2594 if let Some(label_text) = label_text {
2595 for i in (0..=block_stack.len() - 1).rev() {
2596 let block = &block_stack[i];
2597 if self.supports_unlabeled_continue(&block.borrow())
2598 && self.has_immediate_containing_labeled_block(&label_text, i - 1)
2599 {
2600 return block.borrow().continue_label().unwrap();
2601 }
2602 }
2603 } else {
2604 for i in (0..=block_stack.len() - 1).rev() {
2605 let block = &block_stack[i];
2606 if self.supports_unlabeled_continue(&block.borrow()) {
2607 return block.borrow().continue_label().unwrap();
2608 }
2609 }
2610 }
2611 }
2612
2613 Label(0)
2614 }
2615
2616 fn create_label(&mut self, label: Option<Label>) -> Box<Expr> {
2619 if let Some(label) = label {
2620 if label.0 > 0 {
2621 #[cfg(debug_assertions)]
2622 debug!("create_label: label={:?}", label);
2623
2624 if self.label_exprs.is_none() {
2625 self.label_exprs = Some(Default::default());
2626 }
2627 let label_expressions = self.label_exprs.as_mut().unwrap();
2628 let expr = Loc {
2629 pos: BytePos(label.0 as _),
2630 value: -1,
2631 };
2632 if label_expressions.get(label.0 as usize).is_none() {
2633 if label.0 as usize >= label_expressions.len() {
2634 label_expressions.resize(label.0 as usize + 1, Vec::new());
2635 }
2636
2637 label_expressions[label.0 as usize] = vec![expr];
2638 } else {
2639 label_expressions
2640 .get_mut(label.0 as usize)
2641 .unwrap()
2642 .push(expr);
2643 }
2644 return Invalid {
2645 span: Span::new(BytePos(label.0 as _), BytePos(label.0 as _)),
2646 }
2647 .into();
2648 }
2649 }
2650
2651 Box::new(Invalid { span: DUMMY_SP }.into())
2652 }
2653
2654 fn create_instruction(&mut self, instruction: Instruction) -> Number {
2656 Number {
2663 span: DUMMY_SP,
2664 value: instruction as u16 as _,
2665 raw: None,
2666 }
2667 }
2668
2669 fn create_inline_break(&mut self, label: Label, span: Option<Span>) -> ReturnStmt {
2675 debug_assert!(label.0 >= 0, "Invalid label");
2676 let args = vec![
2677 Some(self.create_instruction(Instruction::Break).as_arg()),
2678 Some(self.create_label(Some(label)).as_arg()),
2679 ];
2680 ReturnStmt {
2681 span: span.unwrap_or(DUMMY_SP),
2682 arg: Some(
2683 ArrayLit {
2684 span: DUMMY_SP,
2685 elems: args,
2686 }
2687 .into(),
2688 ),
2689 }
2690 }
2691
2692 fn create_inline_return(&mut self, expr: Option<Box<Expr>>, loc: Option<Span>) -> ReturnStmt {
2697 ReturnStmt {
2698 span: loc.unwrap_or(DUMMY_SP),
2699 arg: Some(
2700 ArrayLit {
2701 span: DUMMY_SP,
2702 elems: match expr {
2703 Some(expr) => vec![
2704 Some(self.create_instruction(Instruction::Return).as_arg()),
2705 Some(expr.as_arg()),
2706 ],
2707 None => vec![Some(self.create_instruction(Instruction::Return).as_arg())],
2708 },
2709 }
2710 .into(),
2711 ),
2712 }
2713 }
2714
2715 fn create_generator_resume(&mut self, loc: Option<Span>) -> Box<Expr> {
2717 CallExpr {
2718 span: loc.unwrap_or(DUMMY_SP),
2719 callee: self
2720 .state
2721 .clone()
2722 .make_member(quote_ident!("sent"))
2723 .as_callee(),
2724 args: Vec::new(),
2725 ..Default::default()
2726 }
2727 .into()
2728 }
2729
2730 fn emit_nop(&mut self) {
2732 self.emit_worker(OpCode::Nop, None, None);
2733 }
2734
2735 fn emit_stmt(&mut self, stmt: Stmt) {
2739 if stmt.is_empty() {
2740 self.emit_nop();
2741 } else {
2742 self.emit_worker(OpCode::Statement, Some(OpArgs::Stmt(Box::new(stmt))), None);
2743 }
2744 }
2745
2746 fn emit_assignment(&mut self, left: AssignTarget, right: Box<Expr>, loc: Option<Span>) {
2752 self.emit_worker(OpCode::Assign, Some(OpArgs::PatAndExpr(left, right)), loc);
2753 }
2754
2755 fn emit_break(&mut self, label: Label, loc: Option<Span>) {
2760 self.emit_worker(OpCode::Break, Some(OpArgs::Label(label)), loc);
2761 }
2762
2763 fn emit_break_when_true(&mut self, label: Label, condition: Box<Expr>, loc: Option<Span>) {
2770 self.emit_worker(
2771 OpCode::BreakWhenTrue,
2772 Some(OpArgs::LabelExpr(label, condition)),
2773 loc,
2774 );
2775 }
2776
2777 fn emit_break_when_false(&mut self, label: Label, condition: Box<Expr>, loc: Option<Span>) {
2784 self.emit_worker(
2785 OpCode::BreakWhenFalse,
2786 Some(OpArgs::LabelExpr(label, condition)),
2787 loc,
2788 );
2789 }
2790
2791 fn emit_yield_star(&mut self, expr: Option<Box<Expr>>, loc: Option<Span>) {
2796 self.emit_worker(OpCode::YieldStar, Some(OpArgs::OptExpr(expr)), loc);
2797 }
2798
2799 fn emit_yield(&mut self, expr: Option<Box<Expr>>, loc: Option<Span>) {
2804 self.emit_worker(OpCode::Yield, Some(OpArgs::OptExpr(expr)), loc);
2805 }
2806
2807 fn emit_return(&mut self, expr: Option<Box<Expr>>, loc: Option<Span>) {
2812 self.emit_worker(OpCode::Return, Some(OpArgs::OptExpr(expr)), loc);
2813 }
2814
2815 fn emit_throw(&mut self, expr: Box<Expr>, loc: Option<Span>) {
2820 self.emit_worker(OpCode::Throw, Some(OpArgs::OptExpr(Some(expr))), loc);
2821 }
2822
2823 fn emit_endfinally(&mut self) {
2826 self.emit_worker(OpCode::Endfinally, None, None);
2827 }
2828
2829 fn emit_worker(&mut self, code: OpCode, args: Option<OpArgs>, loc: Option<Span>) {
2834 if self.operations.is_none() {
2835 self.operations = Some(Vec::new());
2836 self.operation_args = Some(Vec::new());
2837 self.operation_locs = Some(Vec::new());
2838 }
2839 if self.label_offsets.is_none() {
2840 let label = self.define_label();
2842 self.mark_label(label);
2843 }
2844 debug_assert!(self.operations.is_some());
2845 debug_assert_eq!(
2846 self.operations.as_ref().unwrap().len(),
2847 self.operation_args.as_ref().unwrap().len()
2848 );
2849 debug_assert_eq!(
2850 self.operations.as_ref().unwrap().len(),
2851 self.operation_locs.as_ref().unwrap().len()
2852 );
2853
2854 self.operations.as_mut().unwrap().push(code);
2855 self.operation_args.as_mut().unwrap().push(args);
2856 self.operation_locs
2857 .as_mut()
2858 .unwrap()
2859 .push(loc.unwrap_or(DUMMY_SP));
2860 }
2861
2862 fn build_stmts(&mut self) -> Vec<Stmt> {
2864 if let Some(ops) = self.operations.clone() {
2865 for (op_index, _) in ops.iter().enumerate() {
2866 self.write_operation(op_index);
2867 }
2868
2869 self.flush_final_label(ops.len());
2870 } else {
2871 self.flush_final_label(0);
2872 }
2873
2874 if let Some(clauses) = self.clauses.take() {
2875 let label_expr = self.state.clone().make_member(quote_ident!("label"));
2876 let switch_stmt = SwitchStmt {
2877 span: DUMMY_SP,
2878 discriminant: label_expr.into(),
2879 cases: clauses,
2880 };
2881 return vec![Stmt::Switch(switch_stmt)];
2882 }
2883
2884 if let Some(stmts) = self.stmts.take() {
2885 return stmts;
2886 }
2887
2888 Vec::new()
2889 }
2890
2891 fn flush_label(&mut self) {
2893 if self.stmts.is_none() {
2894 return;
2895 }
2896
2897 self.append_label(!self.last_operation_was_abrupt);
2898
2899 self.last_operation_was_abrupt = false;
2900 self.last_operation_was_completion = false;
2901 self.label_number += 1;
2902 }
2903
2904 fn flush_final_label(&mut self, op_index: usize) {
2906 if self.is_final_label_reachable(op_index) {
2907 self.try_enter_label(op_index);
2908 self.with_block_stack = None;
2909 self.write_return(None, None);
2910 }
2911
2912 if self.stmts.is_some() && self.clauses.is_some() {
2913 self.append_label(false);
2914 }
2915
2916 self.update_label_expression();
2917 }
2918
2919 fn is_final_label_reachable(&self, op_index: usize) -> bool {
2922 if !self.last_operation_was_completion {
2925 return true;
2926 }
2927
2928 if self.label_offsets.is_none() || self.label_exprs.is_none() {
2931 return false;
2932 }
2933
2934 for (label, label_offset) in self
2937 .label_offsets
2938 .as_ref()
2939 .unwrap()
2940 .iter()
2941 .copied()
2942 .enumerate()
2943 {
2944 if label_offset as usize == op_index
2945 && self.label_exprs.as_ref().unwrap().get(label).is_some()
2946 {
2947 return true;
2948 }
2949 }
2950
2951 false
2952 }
2953
2954 fn append_label(&mut self, mark_label_end: bool) {
2960 if cfg!(debug_assertions) {
2961 debug!(mark_label_end = mark_label_end, "append_label");
2962 }
2963
2964 if self.clauses.is_none() {
2965 self.clauses = Some(Default::default());
2966 }
2967
2968 #[allow(clippy::manual_unwrap_or_default)]
2969 let stmts = if let Some(mut stmts) = self.stmts.take() {
2970 if self.with_block_stack.is_some() {
2971 for (_i, with_block) in self
2976 .with_block_stack
2977 .as_ref()
2978 .unwrap()
2979 .iter()
2980 .enumerate()
2981 .rev()
2982 {
2983 let b = with_block.borrow();
2984 let with_block = match &*b {
2985 CodeBlock::With(v) => v,
2986 _ => {
2987 unreachable!()
2988 }
2989 };
2990
2991 stmts = vec![Stmt::With(WithStmt {
2992 span: DUMMY_SP,
2993 obj: Box::new(Expr::Ident(with_block.expression.clone())),
2994 body: Box::new(Stmt::Block(BlockStmt {
2995 span: DUMMY_SP,
2996 stmts,
2997 ..Default::default()
2998 })),
2999 })];
3000 }
3001 }
3002
3003 if cfg!(debug_assertions) {
3004 debug!(
3005 "current_exception_block = {:?}",
3006 self.current_exception_block
3007 );
3008 }
3009
3010 if let Some(current_exception_block) = self.current_exception_block.take() {
3011 let b = current_exception_block.borrow();
3012 let ExceptionBlock {
3013 start_label,
3014 catch_label,
3015 finally_label,
3016 end_label,
3017 ..
3018 } = match &*b {
3019 CodeBlock::Exception(v) => v,
3020 _ => {
3021 unreachable!()
3022 }
3023 };
3024
3025 let start_label = self.create_label(Some(*start_label));
3026 let catch_label = self.create_label(*catch_label);
3027 let finally_label = self.create_label(*finally_label);
3028 let end_label = self.create_label(Some(*end_label));
3029
3030 stmts.insert(
3031 0,
3032 ExprStmt {
3033 span: DUMMY_SP,
3034 expr: CallExpr {
3035 span: DUMMY_SP,
3036 callee: self
3037 .state
3038 .clone()
3039 .make_member(quote_ident!("trys"))
3040 .make_member(quote_ident!("push"))
3041 .as_callee(),
3042 args: vec![ArrayLit {
3043 span: DUMMY_SP,
3044 elems: vec![
3045 Some(start_label.as_arg()),
3046 Some(catch_label.as_arg()),
3047 Some(finally_label.as_arg()),
3048 Some(end_label.as_arg()),
3049 ],
3050 }
3051 .as_arg()],
3052 ..Default::default()
3053 }
3054 .into(),
3055 }
3056 .into(),
3057 );
3058 }
3059
3060 if mark_label_end {
3061 stmts.push(
3066 ExprStmt {
3067 span: DUMMY_SP,
3068 expr: AssignExpr {
3069 span: DUMMY_SP,
3070 op: op!("="),
3071 left: self.state.clone().make_member(quote_ident!("label")).into(),
3072 right: (self.label_number + 1).into(),
3073 }
3074 .into(),
3075 }
3076 .into(),
3077 );
3078 }
3079
3080 stmts
3081 } else {
3082 Default::default()
3083 };
3084
3085 self.clauses.as_mut().unwrap().push(SwitchCase {
3086 span: DUMMY_SP,
3087 test: Some(self.label_number.into()),
3088 cons: stmts,
3089 });
3090 }
3091
3092 #[tracing::instrument(skip(self))]
3093 fn try_enter_label(&mut self, op_index: usize) {
3094 if self.label_offsets.is_none() {
3095 return;
3096 }
3097
3098 for (label, label_offset) in self.label_offsets.clone().unwrap().into_iter().enumerate() {
3099 if label_offset as usize == op_index {
3100 self.flush_label();
3101
3102 if self.label_numbers.is_none() {
3103 self.label_numbers = Some(Vec::new());
3104 }
3105
3106 if let Some(v) = self
3107 .label_numbers
3108 .as_mut()
3109 .unwrap()
3110 .get_mut(self.label_number)
3111 {
3112 v.push(label);
3113 } else {
3114 if self.label_number >= self.label_numbers.as_ref().unwrap().len() {
3115 self.label_numbers
3116 .as_mut()
3117 .unwrap()
3118 .resize(self.label_number + 1, Vec::new());
3119 }
3120
3121 self.label_numbers.as_mut().unwrap()[self.label_number] = vec![label];
3122 }
3123 }
3124 }
3125 }
3126
3127 fn update_label_expression(&mut self) {
3129 if self.label_exprs.is_some() && self.label_numbers.is_some() {
3130 for (label_number, labels) in self.label_numbers.as_ref().unwrap().iter().enumerate() {
3131 for &label in labels {
3132 let exprs = self.label_exprs.as_mut().unwrap().get_mut(label);
3133 if let Some(exprs) = exprs {
3134 for expr in exprs {
3135 expr.value = label_number as _;
3136 #[cfg(debug_assertions)]
3137 debug!("Label {:?} = {:?} ({:?})", label, expr.value, expr.pos);
3138 }
3139 }
3140 }
3141 }
3142 }
3143 }
3144
3145 #[tracing::instrument(skip(self))]
3147 fn try_enter_or_leave_block(&mut self, op_index: usize) {
3148 if let Some(blocks) = &self.blocks {
3149 while self.block_index < self.block_actions.as_ref().unwrap().len()
3150 && self.block_offsets.as_ref().unwrap()[self.block_index] <= op_index
3151 {
3152 #[cfg(debug_assertions)]
3153 debug!("try_enter_or_leave_block: iter");
3154
3155 let block_index = self.block_index;
3156 self.block_index += 1;
3157
3158 if cfg!(debug_assertions) {
3159 debug!(block_index = block_index, "try_enter_or_leave_block")
3160 }
3161
3162 let block = blocks[block_index].clone();
3164 let block_action = self.block_actions.as_ref().unwrap()[block_index];
3165
3166 let b = block.borrow();
3167 match &*b {
3168 CodeBlock::Exception(_) => {
3169 if block_action == BlockAction::Open {
3170 self.exception_block_stack
3171 .get_or_insert_with(Default::default)
3172 .extend(self.current_exception_block.clone());
3173
3174 if self.stmts.is_none() {
3176 self.stmts = Some(Default::default());
3177 }
3178
3179 #[cfg(debug_assertions)]
3180 debug!("Current exception block: open = Some({:?})", block);
3181 self.current_exception_block = Some(block.clone());
3182 } else if block_action == BlockAction::Close {
3183 self.current_exception_block =
3184 self.exception_block_stack.as_mut().unwrap().pop();
3185 #[cfg(debug_assertions)]
3186 debug!(
3187 "Current exception block: close = {:?}",
3188 self.current_exception_block
3189 );
3190 }
3191 }
3192
3193 CodeBlock::With(_) => {
3194 if block_action == BlockAction::Open {
3195 if self.with_block_stack.is_none() {
3196 self.with_block_stack = Some(Default::default());
3197 }
3198
3199 self.with_block_stack.as_mut().unwrap().push(block.clone());
3200 } else if block_action == BlockAction::Close {
3201 self.with_block_stack.as_mut().unwrap().pop();
3202 }
3203 }
3204
3205 _ => {}
3206 }
3207 }
3208 }
3209 }
3210
3211 #[tracing::instrument(skip(self))]
3214 fn write_operation(&mut self, op_index: usize) {
3215 if cfg!(debug_assertions) {
3216 debug!("Writing operation {}", op_index);
3217 }
3218
3219 self.try_enter_label(op_index);
3220 self.try_enter_or_leave_block(op_index);
3221
3222 if self.last_operation_was_abrupt {
3224 return;
3225 }
3226
3227 self.last_operation_was_abrupt = false;
3228 self.last_operation_was_completion = false;
3229
3230 let opcode = self.operations.as_ref().unwrap()[op_index];
3231 if opcode == OpCode::Nop {
3232 return;
3233 } else if opcode == OpCode::Endfinally {
3234 self.write_end_finally();
3235 return;
3236 }
3237
3238 let args = self.operation_args.as_mut().unwrap()[op_index]
3239 .take()
3240 .expect("failed to take operation arguments");
3241 if opcode == OpCode::Statement {
3242 let args = args.expect_stmt();
3243 self.write_stmt(*args);
3244 return;
3245 }
3246
3247 let loc = self.operation_locs.as_ref().unwrap()[op_index];
3248
3249 match opcode {
3250 OpCode::Assign => {
3251 let args = args.expect_pat_and_expr();
3252 self.write_assign(args.0, args.1, Some(loc));
3253 }
3254 OpCode::Break => {
3255 let args = args.expect_label();
3256 self.write_break(args, Some(loc));
3257 }
3258 OpCode::BreakWhenTrue => {
3259 let args = args.expect_label_expr();
3260 self.write_break_when_true(args.0, args.1, Some(loc));
3261 }
3262 OpCode::BreakWhenFalse => {
3263 let args = args.expect_label_expr();
3264 self.write_break_when_false(args.0, args.1, Some(loc));
3265 }
3266 OpCode::Yield => {
3267 let args = args.expect_opt_expr();
3268
3269 self.write_yield(args, Some(loc));
3270 }
3271 OpCode::YieldStar => {
3272 let args = args.expect_opt_expr().unwrap();
3273
3274 self.write_yield_star(args, Some(loc));
3275 }
3276 OpCode::Return => {
3277 let args = args.expect_opt_expr();
3278
3279 self.write_return(args, Some(loc));
3280 }
3281 OpCode::Throw => {
3282 let args = args.expect_opt_expr().unwrap();
3283
3284 self.write_throw(args, Some(loc));
3285 }
3286 _ => {}
3287 }
3288 }
3289
3290 fn write_stmt(&mut self, stmt: Stmt) {
3292 if stmt.is_empty() {
3293 return;
3294 }
3295 match self.stmts {
3296 Some(ref mut stmts) => stmts.push(stmt),
3297 None => self.stmts = Some(vec![stmt]),
3298 }
3299 }
3300
3301 fn write_assign(&mut self, left: AssignTarget, right: Box<Expr>, op_loc: Option<Span>) {
3303 self.write_stmt(
3304 ExprStmt {
3305 span: op_loc.unwrap_or(DUMMY_SP),
3306 expr: AssignExpr {
3307 span: DUMMY_SP,
3308 op: op!("="),
3309 left,
3310 right,
3311 }
3312 .into(),
3313 }
3314 .into(),
3315 )
3316 }
3317
3318 fn write_throw(&mut self, expr: Box<Expr>, op_loc: Option<Span>) {
3323 self.last_operation_was_abrupt = true;
3324 self.last_operation_was_completion = true;
3325
3326 self.write_stmt(
3328 ThrowStmt {
3329 span: op_loc.unwrap_or(DUMMY_SP),
3330 arg: expr,
3331 }
3332 .into(),
3333 )
3334 }
3335
3336 fn write_return(&mut self, expr: Option<Box<Expr>>, op_loc: Option<Span>) {
3341 self.last_operation_was_abrupt = true;
3342 self.last_operation_was_completion = true;
3343
3344 let inst = self.create_instruction(Instruction::Return);
3345 self.write_stmt(
3346 ReturnStmt {
3347 span: op_loc.unwrap_or(DUMMY_SP),
3348 arg: Some(
3349 ArrayLit {
3350 span: DUMMY_SP,
3351 elems: match expr {
3352 Some(expr) => {
3353 vec![Some(inst.as_arg()), Some(expr.as_arg())]
3354 }
3355 _ => {
3356 vec![Some(inst.as_arg())]
3357 }
3358 },
3359 }
3360 .into(),
3361 ),
3362 }
3363 .into(),
3364 )
3365 }
3366
3367 fn write_break(&mut self, label: Label, op_loc: Option<Span>) {
3372 self.last_operation_was_abrupt = true;
3373
3374 let inst = self.create_instruction(Instruction::Break);
3375 let label = self.create_label(Some(label));
3376 self.write_stmt(
3377 ReturnStmt {
3378 span: op_loc.unwrap_or(DUMMY_SP),
3379 arg: Some(
3380 ArrayLit {
3381 span: DUMMY_SP,
3382 elems: vec![Some(inst.as_arg()), Some(label.as_arg())],
3383 }
3384 .into(),
3385 ),
3386 }
3387 .into(),
3388 )
3389 }
3390
3391 fn write_break_when_true(&mut self, label: Label, cond: Box<Expr>, op_loc: Option<Span>) {
3397 let inst = self.create_instruction(Instruction::Break);
3398 let label = self.create_label(Some(label));
3399 self.write_stmt(
3400 IfStmt {
3401 span: DUMMY_SP,
3402 test: cond,
3403 cons: Box::new(Stmt::Return(ReturnStmt {
3404 span: op_loc.unwrap_or(DUMMY_SP),
3405 arg: Some(
3406 ArrayLit {
3407 span: DUMMY_SP,
3408 elems: vec![Some(inst.as_arg()), Some(label.as_arg())],
3409 }
3410 .into(),
3411 ),
3412 })),
3413 alt: None,
3414 }
3415 .into(),
3416 )
3417 }
3418
3419 fn write_break_when_false(&mut self, label: Label, cond: Box<Expr>, op_loc: Option<Span>) {
3425 let inst = self.create_instruction(Instruction::Break);
3426 let label = self.create_label(Some(label));
3427 self.write_stmt(
3428 IfStmt {
3429 span: DUMMY_SP,
3430 test: UnaryExpr {
3431 span: DUMMY_SP,
3432 op: op!("!"),
3433 arg: cond,
3434 }
3435 .into(),
3436 cons: Box::new(Stmt::Return(ReturnStmt {
3437 span: op_loc.unwrap_or(DUMMY_SP),
3438 arg: Some(
3439 ArrayLit {
3440 span: DUMMY_SP,
3441 elems: vec![Some(inst.as_arg()), Some(label.as_arg())],
3442 }
3443 .into(),
3444 ),
3445 })),
3446 alt: None,
3447 }
3448 .into(),
3449 )
3450 }
3451
3452 fn write_yield(&mut self, expr: Option<Box<Expr>>, op_loc: Option<Span>) {
3457 self.last_operation_was_abrupt = true;
3458
3459 let inst = self.create_instruction(Instruction::Yield);
3460 let elems = match expr {
3461 Some(expr) => {
3462 vec![Some(inst.as_arg()), Some(expr.as_arg())]
3463 }
3464 None => {
3465 vec![Some(inst.as_arg())]
3466 }
3467 };
3468 self.write_stmt(
3469 ReturnStmt {
3470 span: op_loc.unwrap_or(DUMMY_SP),
3471 arg: Some(
3472 ArrayLit {
3473 span: DUMMY_SP,
3474 elems,
3475 }
3476 .into(),
3477 ),
3478 }
3479 .into(),
3480 );
3481 }
3482
3483 fn write_yield_star(&mut self, expr: Box<Expr>, op_loc: Option<Span>) {
3488 self.last_operation_was_abrupt = true;
3489
3490 let arg1 = self.create_instruction(Instruction::YieldStar);
3491 self.write_stmt(
3492 ReturnStmt {
3493 span: op_loc.unwrap_or(DUMMY_SP),
3494 arg: Some(
3495 ArrayLit {
3496 span: DUMMY_SP,
3497 elems: vec![Some(arg1.as_arg()), Some(expr.as_arg())],
3498 }
3499 .into(),
3500 ),
3501 }
3502 .into(),
3503 )
3504 }
3505
3506 fn write_end_finally(&mut self) {
3508 self.last_operation_was_abrupt = true;
3509
3510 let arg = self.create_instruction(Instruction::Endfinally);
3511 self.write_stmt(
3512 ReturnStmt {
3513 span: DUMMY_SP,
3514 arg: Some(
3515 ArrayLit {
3516 span: DUMMY_SP,
3517 elems: vec![Some(arg.as_arg())],
3518 }
3519 .into(),
3520 ),
3521 }
3522 .into(),
3523 )
3524 }
3525
3526 fn hoist_variable_declaration(&mut self, id: &Ident) {
3527 self.hoisted_vars.push(VarDeclarator {
3528 span: DUMMY_SP,
3529 name: id.clone().into(),
3530 init: None,
3531 definite: Default::default(),
3532 })
3533 }
3534
3535 fn get_initialized_variables<'a>(
3536 &self,
3537 initializer: &'a mut VarDecl,
3538 ) -> Vec<&'a mut VarDeclarator> {
3539 initializer
3540 .decls
3541 .iter_mut()
3542 .filter(|v| v.init.is_some())
3543 .collect()
3544 }
3545
3546 fn create_temp_variable(&mut self) -> Ident {
3547 let i = private_ident!("_");
3548
3549 self.hoisted_vars.push(VarDeclarator {
3550 span: DUMMY_SP,
3551 name: i.clone().into(),
3552 init: None,
3553 definite: Default::default(),
3554 });
3555
3556 i
3557 }
3558
3559 fn create_call_binding(
3561 &mut self,
3562 expr: Box<Expr>,
3563 is_new_call: bool,
3564 ) -> (Box<Expr>, Box<Expr>) {
3565 let mut callee = expr;
3566
3567 match &mut *callee {
3568 Expr::Ident(..) => (
3569 callee.clone(),
3570 if is_new_call {
3571 callee
3572 } else {
3573 Expr::undefined(DUMMY_SP)
3574 },
3575 ),
3576
3577 Expr::Member(MemberExpr { obj, .. }) if !is_new_call => {
3578 if obj.is_ident() {
3579 let this_arg = obj.clone();
3580 return (callee, this_arg);
3581 }
3582
3583 let this_arg = self.create_temp_variable();
3584 *obj = Box::new(obj.take().make_assign_to(op!("="), this_arg.clone().into()));
3585
3586 (callee, this_arg.into())
3587 }
3588
3589 _ => {
3590 if !is_new_call {
3591 (callee, Expr::undefined(DUMMY_SP))
3592 } else {
3593 let this_arg = self.create_temp_variable();
3594 let target = callee.make_assign_to(op!("="), this_arg.clone().into());
3595 (Box::new(target), this_arg.into())
3596 }
3597 }
3598 }
3599 }
3600}
3601
3602fn contains_yield<N>(node: &N) -> bool
3603where
3604 N: VisitWith<YieldFinder>,
3605{
3606 let mut v = YieldFinder { found: false };
3607 node.visit_with(&mut v);
3608 v.found
3609}
3610
3611struct YieldFinder {
3612 found: bool,
3613}
3614
3615impl Visit for YieldFinder {
3616 noop_visit_type!(fail);
3617
3618 fn visit_yield_expr(&mut self, _: &YieldExpr) {
3619 self.found = true;
3620 }
3621
3622 fn visit_arrow_expr(&mut self, f: &ArrowExpr) {
3623 f.params.visit_with(self);
3624 }
3625
3626 fn visit_function(&mut self, f: &Function) {
3627 f.decorators.visit_with(self);
3628 f.params.visit_with(self);
3629 }
3630}
3631
3632#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3633pub(super) struct Loc {
3634 pos: BytePos,
3635 value: i32,
3636}
3637
3638struct InvalidToLit<'a> {
3640 map: Option<&'a [Vec<Loc>]>,
3642}
3643
3644impl VisitMut for InvalidToLit<'_> {
3645 noop_visit_mut_type!(fail);
3646
3647 fn visit_mut_expr(&mut self, e: &mut Expr) {
3648 e.visit_mut_children_with(self);
3649
3650 if let Expr::Invalid(Invalid { span }) = e {
3651 if span.lo != BytePos(0) && span.lo == span.hi {
3652 if let Some(Loc { value, .. }) = self
3653 .map
3654 .iter()
3655 .flat_map(|v| v.iter())
3656 .flatten()
3657 .find(|loc| loc.pos == span.lo)
3658 {
3659 *e = (*value as usize).into();
3660 }
3661 }
3662 }
3663 }
3664
3665 fn visit_mut_seq_expr(&mut self, e: &mut SeqExpr) {
3666 e.visit_mut_children_with(self);
3667
3668 e.exprs.retain(|e| !e.is_invalid());
3669 }
3670
3671 fn visit_mut_opt_expr_or_spread(&mut self, e: &mut Option<ExprOrSpread>) {
3672 e.visit_mut_children_with(self);
3673
3674 if let Some(arg) = e {
3675 if arg.expr.is_invalid() {
3676 *e = None;
3677 }
3678 }
3679 }
3680}