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 #[cfg(swc_ast_unknown)]
627 _ => panic!("unable to access unknown nodes"),
628 }
629 }
631 _ => {
632 node.left.visit_mut_with(self);
633 }
634 }
635 if node.op != op!("=") {
636 let left_of_right =
637 self.cache_expression(node.left.take().expect_simple().into());
638
639 node.right.visit_mut_with(self);
640
641 *e = AssignExpr {
642 span: node.right.span(),
643 op: node.op,
644 left: left_of_right.into(),
645 right: node.right.take(),
646 }
647 .into();
648 } else {
649 node.right.visit_mut_with(self);
650 }
651 }
652
653 Expr::Object(node) if node.props.iter().any(contains_yield) => {
654 let num_initial_properties = self.count_initial_nodes_without_yield(&node.props);
673
674 let mut temp = self.declare_local(None);
675 node.props
676 .iter_mut()
677 .take(num_initial_properties)
678 .for_each(|p| {
679 p.visit_mut_with(self);
680 });
681
682 self.emit_assignment(
683 temp.clone().into(),
684 ObjectLit {
685 span: DUMMY_SP,
686 props: node
687 .props
688 .iter_mut()
689 .take(num_initial_properties)
690 .map(|v| v.take())
691 .collect(),
692 }
693 .into(),
694 None,
695 );
696
697 let mut expressions = node
698 .props
699 .iter_mut()
700 .skip(num_initial_properties)
701 .map(|v| v.take())
702 .fold(Vec::<CompiledProp>::new(), |mut props, p| {
703 match p {
704 PropOrSpread::Spread(_) => {
705 unreachable!("spread should be removed before applying generator")
706 }
707 PropOrSpread::Prop(p) => match *p {
708 Prop::Getter(p) => {
709 if let Some(CompiledProp::Accessor(g, _)) =
710 props.iter_mut().find(|prev| match prev {
711 CompiledProp::Accessor(_, Some(s)) => {
712 s.key.eq_ignore_span(&p.key)
713 }
714 _ => false,
715 })
716 {
717 *g = Some(p);
718 } else {
719 props.push(CompiledProp::Accessor(Some(p), None))
720 }
721 }
722 Prop::Setter(p) => {
723 if let Some(CompiledProp::Accessor(_, s)) =
724 props.iter_mut().find(|prev| match prev {
725 CompiledProp::Accessor(Some(prev), _) => {
726 prev.key.eq_ignore_span(&p.key)
727 }
728 _ => false,
729 })
730 {
731 *s = Some(p);
732 } else {
733 props.push(CompiledProp::Accessor(None, Some(p)))
734 }
735 }
736 p => {
737 props.push(CompiledProp::Prop(p));
738 }
739 },
740 #[cfg(swc_ast_unknown)]
741 _ => panic!("unable to access unknown nodes"),
742 }
743
744 props
745 })
746 .into_iter()
747 .fold(Vec::new(), |exprs, property| {
748 self.reduce_property(exprs, property, &mut temp)
749 });
750
751 expressions.push(temp.into());
752
753 *e = *Expr::from_exprs(expressions);
754 }
755
756 Expr::Array(node) => {
757 *e = self.visit_elements(&mut node.elems, None, None);
758 }
759
760 _ => {
761 e.visit_mut_children_with(self);
762 }
763 }
764 }
765
766 fn visit_mut_call_expr(&mut self, node: &mut CallExpr) {
767 if !node.callee.is_import() && node.args.iter().any(contains_yield) {
768 node.callee.visit_mut_with(self);
780
781 let (target, this_arg) =
782 self.create_call_binding(node.callee.take().expect_expr(), false);
783
784 let callee = self.cache_expression(target);
785
786 let mut args = node.args.take().into_iter().map(Some).collect::<Vec<_>>();
787 let arg = self.visit_elements(&mut args, None, None);
788
789 let apply = callee.make_member(quote_ident!("apply"));
790
791 *node = CallExpr {
792 span: node.span,
793 callee: apply.as_callee(),
794 args: once(this_arg.as_arg()).chain(once(arg.as_arg())).collect(),
795 ..Default::default()
796 };
797 return;
798 }
799
800 node.visit_mut_children_with(self);
801 }
802
803 fn visit_mut_new_expr(&mut self, node: &mut NewExpr) {
804 if contains_yield(&node.args) {
805 node.callee.visit_mut_with(self);
817
818 let (target, this_arg) = self.create_call_binding(node.callee.take(), true);
819
820 let callee = self.cache_expression(target.make_member(quote_ident!("bind")).into());
821
822 let mut arg = if let Some(args) = node.args.take() {
823 let mut args = args.into_iter().map(Some).collect::<Vec<_>>();
824 Some(self.visit_elements(
825 &mut args,
826 Some(ExprOrSpread {
827 spread: None,
828 expr: Expr::undefined(DUMMY_SP),
829 }),
830 None,
831 ))
832 } else {
833 None
834 };
835
836 let apply = callee.apply(
837 node.span,
838 this_arg,
839 arg.take().map(|v| v.as_arg()).into_iter().collect(),
840 );
841
842 *node = NewExpr {
843 span: node.span,
844 callee: Box::new(apply),
845 args: None,
846 ..Default::default()
847 };
848 return;
849 }
850
851 node.visit_mut_children_with(self);
852 }
853
854 fn visit_mut_for_stmt(&mut self, node: &mut ForStmt) {
855 if self.in_statement_containing_yield {
856 self.begin_script_loop_block();
857 }
858
859 if let Some(VarDeclOrExpr::VarDecl(initializer)) = &mut node.init {
860 for variable in initializer.decls.iter_mut() {
861 self.hoist_variable_declaration(&Ident::from(variable.name.as_ident().unwrap()));
862 }
863
864 let variables = self.get_initialized_variables(initializer);
865
866 let mut exprs = variables
867 .into_iter()
868 .filter_map(|v| self.transform_initialized_variable(v.take()))
869 .map(Expr::from)
870 .map(Box::new)
871 .collect::<Vec<_>>();
872 node.init = if exprs.is_empty() {
873 None
874 } else {
875 Some(VarDeclOrExpr::Expr(if exprs.len() == 1 {
876 exprs.remove(0)
877 } else {
878 SeqExpr {
879 span: DUMMY_SP,
880 exprs,
881 }
882 .into()
883 }))
884 };
885 node.test.visit_mut_with(self);
886 node.update.visit_mut_with(self);
887 node.body.visit_mut_with(self);
888 } else {
889 node.visit_mut_children_with(self);
890 }
891
892 if self.in_statement_containing_yield {
893 self.end_loop_block();
894 }
895 }
896
897 fn visit_mut_do_while_stmt(&mut self, node: &mut DoWhileStmt) {
898 if self.in_statement_containing_yield {
899 self.begin_script_loop_block();
900 node.visit_mut_children_with(self);
901 self.end_loop_block();
902 } else {
903 node.visit_mut_children_with(self);
904 }
905 }
906
907 fn visit_mut_while_stmt(&mut self, node: &mut WhileStmt) {
908 if self.in_statement_containing_yield {
909 self.begin_script_loop_block();
910 node.visit_mut_children_with(self);
911 self.end_loop_block();
912 } else {
913 node.visit_mut_children_with(self);
914 }
915 }
916
917 fn visit_mut_return_stmt(&mut self, node: &mut ReturnStmt) {
918 node.arg.visit_mut_with(self);
919
920 *node = self.create_inline_return(node.arg.take(), Some(node.span));
921 }
922
923 fn visit_mut_switch_stmt(&mut self, node: &mut SwitchStmt) {
924 if self.in_statement_containing_yield {
925 self.begin_script_switch_block();
926 }
927
928 node.visit_mut_children_with(self);
929
930 if self.in_statement_containing_yield {
931 self.end_switch_block();
932 }
933 }
934
935 fn visit_mut_labeled_stmt(&mut self, node: &mut LabeledStmt) {
936 if self.in_statement_containing_yield {
937 self.begin_script_labeled_block(node.label.sym.clone());
938 }
939
940 node.visit_mut_children_with(self);
941
942 if self.in_statement_containing_yield {
943 self.end_labeled_block();
944 }
945 }
946
947 fn visit_mut_for_in_stmt(&mut self, node: &mut ForInStmt) {
948 if self.in_statement_containing_yield {
962 self.begin_script_loop_block();
963 }
964
965 if let ForHead::VarDecl(initializer) = &mut node.left {
966 for variable in &initializer.decls {
967 self.hoist_variable_declaration(&Ident::from(variable.name.as_ident().unwrap()));
968 }
969
970 node.right.visit_mut_with(self);
971 node.body.visit_mut_with(self);
972 } else {
973 node.visit_mut_children_with(self);
974 }
975
976 if self.in_statement_containing_yield {
977 self.end_loop_block();
978 }
979 }
980
981 #[tracing::instrument(level = "debug", skip_all)]
982 fn visit_mut_stmt(&mut self, node: &mut Stmt) {
983 match node {
984 Stmt::Break(b) => {
985 if self.in_statement_containing_yield {
986 let label = self.find_break_target(b.label.as_ref().map(|l| l.sym.clone()));
987 if label.0 > 0 {
988 *node = self.create_inline_break(label, Some(b.span)).into();
989 return;
990 }
991 }
992
993 node.visit_mut_children_with(self);
994 }
995 Stmt::Continue(s) => {
996 if self.in_statement_containing_yield {
997 let label = self.find_continue_target(s.label.as_ref().map(|l| l.sym.clone()));
998 if label.0 > 0 {
999 *node = self.create_inline_break(label, Some(s.span)).into();
1000 return;
1001 }
1002 }
1003
1004 node.visit_mut_children_with(self);
1005 }
1006
1007 Stmt::Decl(Decl::Var(v)) => {
1008 if contains_yield(&*v) {
1009 self.transform_and_emit_var_decl_list(v.take());
1010 node.take();
1011 return;
1012 }
1013
1014 for decl in v.decls.iter() {
1020 self.hoist_variable_declaration(&Ident::from(decl.name.as_ident().unwrap()));
1021 }
1022
1023 let variables = self.get_initialized_variables(v);
1024 if variables.is_empty() {
1025 node.take();
1026 return;
1027 }
1028
1029 let mut exprs = variables
1030 .into_iter()
1031 .filter_map(|v| self.transform_initialized_variable(v.take()))
1032 .map(Expr::from)
1033 .map(Box::new)
1034 .collect::<Vec<_>>();
1035
1036 if exprs.is_empty() {
1037 node.take();
1038 return;
1039 }
1040
1041 *node = ExprStmt {
1042 span: v.span,
1043 expr: if exprs.len() == 1 {
1044 exprs.remove(0)
1045 } else {
1046 SeqExpr {
1047 span: DUMMY_SP,
1048 exprs,
1049 }
1050 .into()
1051 },
1052 }
1053 .into();
1054 }
1055 Stmt::Decl(Decl::Fn(f)) => {
1056 self.hoisted_fns.push(f.take());
1057 node.take();
1058 }
1059 _ => {
1060 node.visit_mut_children_with(self);
1061 }
1062 }
1063 }
1064}
1065
1066enum CompiledProp {
1067 Prop(Prop),
1068 Accessor(Option<GetterProp>, Option<SetterProp>),
1069}
1070
1071impl Generator {
1072 fn visit_elements(
1073 &mut self,
1074 elements: &mut [Option<ExprOrSpread>],
1075 mut leading_element: Option<ExprOrSpread>,
1076 _loc: Option<Span>,
1077 ) -> Expr {
1078 let num_initial_elements = self.count_initial_nodes_without_yield(elements);
1089
1090 let mut temp = None;
1091 if num_initial_elements > 0 {
1092 temp = Some(self.declare_local(None));
1093
1094 elements[0..num_initial_elements]
1095 .iter_mut()
1096 .for_each(|e| e.visit_mut_with(self));
1097
1098 self.emit_assignment(
1099 temp.clone().unwrap().into(),
1100 ArrayLit {
1101 span: DUMMY_SP,
1102 elems: leading_element
1103 .take()
1104 .into_iter()
1105 .map(Some)
1106 .chain(
1107 elements
1108 .iter_mut()
1109 .take(num_initial_elements)
1110 .map(|e| e.take()),
1111 )
1112 .collect(),
1113 }
1114 .into(),
1115 None,
1116 );
1117 }
1118
1119 let mut expressions = elements
1120 .iter_mut()
1121 .skip(num_initial_elements)
1122 .map(|v| v.take())
1123 .fold(Vec::new(), |exprs, element| {
1124 self.reduce_element(exprs, element, &mut leading_element, &mut temp)
1125 });
1126
1127 if let Some(temp) = temp {
1128 CallExpr {
1129 span: DUMMY_SP,
1130 callee: temp.make_member(quote_ident!("concat")).as_callee(),
1131 args: vec![ExprOrSpread {
1132 spread: None,
1133 expr: Box::new(Expr::Array(ArrayLit {
1134 span: DUMMY_SP,
1135 elems: expressions
1136 .take()
1137 .into_iter()
1138 .map(|expr| match expr {
1139 Some(expr_or_spread) => match &*expr_or_spread.expr {
1140 Expr::Invalid(_) => None,
1141 _ => Some(expr_or_spread),
1142 },
1143 None => None,
1144 })
1145 .collect(),
1146 })),
1147 }],
1148 ..Default::default()
1149 }
1150 .into()
1151 } else {
1152 ArrayLit {
1153 span: DUMMY_SP,
1154 elems: leading_element
1155 .take()
1156 .into_iter()
1157 .map(Some)
1158 .chain(expressions.take().into_iter().map(|expr| match expr {
1159 Some(expr_or_spread) => match &*expr_or_spread.expr {
1160 Expr::Invalid(_) => None,
1161 _ => Some(expr_or_spread),
1162 },
1163 None => None,
1164 }))
1165 .collect(),
1166 }
1167 .into()
1168 }
1169 }
1170
1171 fn reduce_element(
1172 &mut self,
1173 mut expressions: Vec<Option<ExprOrSpread>>,
1174 mut element: Option<ExprOrSpread>,
1175 leading_element: &mut Option<ExprOrSpread>,
1176 temp: &mut Option<Ident>,
1177 ) -> Vec<Option<ExprOrSpread>> {
1178 if contains_yield(&element) && !expressions.is_empty() {
1179 let has_assigned_temp = temp.is_some();
1180 if temp.is_none() {
1181 *temp = Some(self.declare_local(None));
1182 }
1183
1184 self.emit_assignment(
1185 temp.clone().unwrap().into(),
1186 if has_assigned_temp {
1187 CallExpr {
1188 span: DUMMY_SP,
1189 callee: temp
1190 .clone()
1191 .unwrap()
1192 .make_member(quote_ident!("concat"))
1193 .as_callee(),
1194 args: vec![Box::new(Expr::Array(ArrayLit {
1195 span: DUMMY_SP,
1196 elems: expressions
1197 .take()
1198 .into_iter()
1199 .map(|expr| match expr {
1200 Some(expr_or_spread) => match &*expr_or_spread.expr {
1201 Expr::Invalid(_) => None,
1202 _ => Some(expr_or_spread),
1203 },
1204 None => None,
1205 })
1206 .collect(),
1207 }))
1208 .as_arg()],
1209 ..Default::default()
1210 }
1211 .into()
1212 } else {
1213 Box::new(
1214 ArrayLit {
1215 span: DUMMY_SP,
1216 elems: leading_element
1217 .take()
1218 .into_iter()
1219 .map(Some)
1220 .chain(expressions.take().into_iter().map(|expr| match expr {
1221 Some(expr_or_spread) => match &*expr_or_spread.expr {
1222 Expr::Invalid(_) => None,
1223 _ => Some(expr_or_spread),
1224 },
1225 None => None,
1226 }))
1227 .collect(),
1228 }
1229 .into(),
1230 )
1231 },
1232 None,
1233 );
1234 *leading_element = None;
1235 }
1236
1237 element.visit_mut_with(self);
1238 expressions.push(element);
1239 expressions
1240 }
1241
1242 fn reduce_property(
1243 &mut self,
1244 mut expressions: Vec<Box<Expr>>,
1245 property: CompiledProp,
1246 temp: &mut Ident,
1247 ) -> Vec<Box<Expr>> {
1248 if match &property {
1249 CompiledProp::Prop(p) => contains_yield(p),
1250 CompiledProp::Accessor(g, s) => {
1251 g.as_ref().is_some_and(contains_yield) || s.as_ref().is_some_and(contains_yield)
1252 }
1253 } && !expressions.is_empty()
1254 {
1255 self.emit_stmt(
1256 ExprStmt {
1257 span: DUMMY_SP,
1258 expr: Expr::from_exprs(expressions.take()),
1259 }
1260 .into(),
1261 );
1262 }
1263
1264 let mut expression: Expr = match property {
1265 CompiledProp::Prop(p) => match p {
1266 Prop::Shorthand(p) => AssignExpr {
1267 span: p.span,
1268 op: op!("="),
1269 left: MemberExpr {
1270 span: DUMMY_SP,
1271 obj: temp.clone().into(),
1272 prop: MemberProp::Ident(p.clone().into()),
1273 }
1274 .into(),
1275 right: p.into(),
1276 }
1277 .into(),
1278 Prop::KeyValue(p) => AssignExpr {
1279 span: DUMMY_SP,
1280 op: op!("="),
1281 left: MemberExpr {
1282 span: DUMMY_SP,
1283 obj: temp.clone().into(),
1284 prop: p.key.into(),
1285 }
1286 .into(),
1287 right: p.value,
1288 }
1289 .into(),
1290 Prop::Assign(_) => {
1291 unreachable!("assignment property be removed before generator pass")
1292 }
1293 Prop::Getter(_) | Prop::Setter(_) => {
1294 unreachable!("getter/setter property be compiled as CompiledProp::Accessor")
1295 }
1296 Prop::Method(p) => AssignExpr {
1297 span: DUMMY_SP,
1298 op: op!("="),
1299 left: MemberExpr {
1300 span: DUMMY_SP,
1301 obj: temp.clone().into(),
1302 prop: p.key.into(),
1303 }
1304 .into(),
1305 right: p.function.into(),
1306 }
1307 .into(),
1308 #[cfg(swc_ast_unknown)]
1309 _ => panic!("unable to access unknown nodes"),
1310 },
1311 CompiledProp::Accessor(getter, setter) => {
1312 let key = getter
1313 .as_ref()
1314 .map(|v| v.key.clone())
1315 .unwrap_or_else(|| setter.as_ref().unwrap().key.clone());
1316
1317 let desc = ObjectLit {
1318 span: DUMMY_SP,
1319 props: getter
1320 .map(|g| KeyValueProp {
1321 key: quote_ident!("get").into(),
1322 value: Function {
1323 params: Vec::new(),
1324 span: g.span,
1325 body: g.body,
1326 is_generator: false,
1327 is_async: false,
1328 ..Default::default()
1329 }
1330 .into(),
1331 })
1332 .into_iter()
1333 .chain(setter.map(|s| {
1334 KeyValueProp {
1335 key: quote_ident!("set").into(),
1336 value: Function {
1337 params: vec![(*s.param).into()],
1338 span: s.span,
1339 body: s.body,
1340 is_generator: false,
1341 is_async: false,
1342 ..Default::default()
1343 }
1344 .into(),
1345 }
1346 }))
1347 .map(Prop::KeyValue)
1348 .map(Box::new)
1349 .map(PropOrSpread::Prop)
1350 .collect(),
1351 };
1352
1353 CallExpr {
1354 span: DUMMY_SP,
1355 callee: helper!(define_property),
1356 args: vec![
1357 temp.clone().as_arg(),
1358 prop_name_to_expr_value(key).as_arg(),
1359 desc.as_arg(),
1360 ],
1361 ..Default::default()
1362 }
1363 .into()
1364 }
1365 };
1366
1367 expression.visit_mut_with(self);
1368 if !expression.is_invalid() {
1369 expressions.push(Box::new(expression));
1370 }
1371 expressions
1372 }
1373
1374 fn visit_left_associative_bin_expr(&mut self, node: &mut BinExpr) -> Option<Expr> {
1375 if contains_yield(&node.right) {
1376 if matches!(node.op, op!("||") | op!("&&")) {
1377 return Some(self.visit_logical_bin_expr(node));
1378 }
1379
1380 node.left.visit_mut_with(self);
1390 node.left = self.cache_expression(node.left.take()).into();
1391 node.right.visit_mut_with(self);
1392 return None;
1393 }
1394
1395 node.visit_mut_children_with(self);
1396 None
1397 }
1398
1399 fn visit_logical_bin_expr(&mut self, node: &mut BinExpr) -> Expr {
1400 let result_label = self.define_label();
1430 let result_local = self.declare_local(None);
1431
1432 let left_span = node.left.span();
1433 node.left.visit_mut_with(self);
1434 self.emit_assignment(
1435 result_local.clone().into(),
1436 node.left.take(),
1437 Some(left_span),
1438 );
1439
1440 if node.op == op!("&&") {
1441 self.emit_break_when_false(
1443 result_label,
1444 Box::new(result_local.clone().into()),
1445 Some(left_span),
1446 )
1447 } else {
1448 self.emit_break_when_true(
1450 result_label,
1451 Box::new(result_local.clone().into()),
1452 Some(left_span),
1453 )
1454 }
1455
1456 let right_span = node.right.span();
1457 node.right.visit_mut_with(self);
1458 self.emit_assignment(
1459 result_local.clone().into(),
1460 node.right.take(),
1461 Some(right_span),
1462 );
1463 self.mark_label(result_label);
1464
1465 result_local.into()
1466 }
1467
1468 fn transform_and_emit_stmts(&mut self, stmts: Vec<Stmt>, start: usize) {
1469 for s in stmts.into_iter().skip(start) {
1470 self.transform_and_emit_stmt(s);
1471 }
1472 }
1473
1474 fn transform_and_emit_embedded_stmt(&mut self, node: Stmt) {
1475 if let Stmt::Block(block) = node {
1476 self.transform_and_emit_stmts(block.stmts, 0);
1477 } else {
1478 self.transform_and_emit_stmt(node);
1479 }
1480 }
1481
1482 fn transform_and_emit_stmt(&mut self, node: Stmt) {
1483 let _tracing = dev_span!("transform_and_emit_stmt");
1484
1485 let saved_in_statement_containing_yield = self.in_statement_containing_yield;
1486 if !self.in_statement_containing_yield {
1487 self.in_statement_containing_yield = contains_yield(&node);
1488 }
1489
1490 self.transform_and_emit_stmt_worker(node);
1491 self.in_statement_containing_yield = saved_in_statement_containing_yield;
1492 }
1493
1494 fn transform_and_emit_stmt_worker(&mut self, mut node: Stmt) {
1495 match node {
1496 Stmt::Block(s) => self.transform_and_emit_block(s),
1497 Stmt::Expr(s) => self.transform_and_emit_expr_stmt(s),
1498 Stmt::If(s) => self.transform_and_emit_if_stmt(s),
1499 Stmt::DoWhile(s) => self.transform_and_emit_do_stmt(s),
1500 Stmt::While(s) => self.transform_and_emit_while_stmt(s),
1501 Stmt::For(s) => self.transform_and_emit_for_stmt(s),
1502 Stmt::ForIn(s) => self.transform_and_emit_for_in_stmt(s),
1503 Stmt::Continue(s) => self.transform_and_emit_continue_stmt(s),
1504 Stmt::Break(s) => self.transform_and_emit_break_stmt(s),
1505 Stmt::Return(s) => self.transform_and_emit_return_stmt(s),
1506 Stmt::With(s) => self.transform_and_emit_with_stmt(s),
1507 Stmt::Switch(s) => self.transform_and_emit_switch_stmt(s),
1508 Stmt::Labeled(s) => self.transform_and_emit_labeled_stmt(s),
1509 Stmt::Throw(s) => self.transform_and_emit_throw_stmt(s),
1510 Stmt::Try(s) => self.transform_and_emit_try_stmt(*s),
1511 _ => {
1512 node.visit_mut_with(self);
1513
1514 self.emit_stmt(node);
1515 }
1516 }
1517 }
1518
1519 fn transform_and_emit_block(&mut self, mut node: BlockStmt) {
1520 if contains_yield(&node) {
1521 self.transform_and_emit_stmts(node.stmts, 0);
1522 } else {
1523 node.visit_mut_with(self);
1524 self.emit_stmt(node.into());
1525 }
1526 }
1527
1528 fn transform_and_emit_expr_stmt(&mut self, mut node: ExprStmt) {
1529 node.visit_mut_with(self);
1530
1531 self.emit_stmt(node.into());
1532 }
1533
1534 fn transform_and_emit_var_decl_list(&mut self, mut node: Box<VarDecl>) {
1535 for variable in &node.decls {
1536 self.hoist_variable_declaration(&Ident::from(variable.name.as_ident().unwrap()));
1537 }
1538
1539 let mut variables = self.get_initialized_variables(&mut node);
1540 let var_len = variables.len();
1541 let mut variables_written = 0;
1542 let mut pending_expressions = Vec::new();
1543 let mut cnt = 0;
1544
1545 while variables_written < var_len {
1546 #[cfg(debug_assertions)]
1547 debug!("variables_written: {} / {}", variables_written, var_len);
1548
1549 for (_i, variable) in variables.iter_mut().enumerate().skip(variables_written) {
1550 if contains_yield(&**variable) && cnt != 0 {
1551 break;
1552 }
1553
1554 let expr = self.transform_initialized_variable(variable.take());
1556
1557 pending_expressions.extend(expr.map(Expr::from).map(Box::new));
1558 cnt += 1;
1559 }
1560
1561 if cnt > 0 {
1562 variables_written += cnt;
1563 cnt = 0;
1564
1565 self.emit_stmt(
1566 ExprStmt {
1567 span: DUMMY_SP,
1568 expr: if pending_expressions.len() == 1 {
1569 pending_expressions.pop().unwrap()
1570 } else {
1571 SeqExpr {
1572 span: DUMMY_SP,
1573 exprs: take(&mut pending_expressions),
1574 }
1575 .into()
1576 },
1577 }
1578 .into(),
1579 )
1580 }
1581 }
1582 }
1583
1584 fn transform_initialized_variable(&mut self, mut node: VarDeclarator) -> Option<AssignExpr> {
1585 node.init.visit_mut_with(self);
1586
1587 node.init.map(|right| AssignExpr {
1588 span: node.span,
1589 op: op!("="),
1590 left: node.name.clone().try_into().unwrap(),
1591 right,
1592 })
1593 }
1594
1595 fn transform_and_emit_if_stmt(&mut self, mut node: IfStmt) {
1596 if contains_yield(&node) {
1597 if contains_yield(&node.cons) || contains_yield(&node.alt) {
1612 let end_label = self.define_label();
1613 let else_label = node.alt.as_ref().map(|_| self.define_label());
1614
1615 node.test.visit_mut_with(self);
1616 let span = node.test.span();
1617 self.emit_break_when_false(else_label.unwrap_or(end_label), node.test, Some(span));
1618
1619 self.transform_and_emit_embedded_stmt(*node.cons);
1620
1621 if let Some(alt) = node.alt {
1622 self.emit_break(end_label, None);
1623 self.mark_label(else_label.unwrap());
1624 self.transform_and_emit_embedded_stmt(*alt);
1625 }
1626 self.mark_label(end_label);
1627 } else {
1628 node.visit_mut_with(self);
1629 self.emit_stmt(node.into());
1630 }
1631 } else {
1632 node.visit_mut_with(self);
1633 self.emit_stmt(node.into());
1634 }
1635 }
1636
1637 fn transform_and_emit_do_stmt(&mut self, mut node: DoWhileStmt) {
1638 if contains_yield(&node) {
1639 let condition_label = self.define_label();
1655 let loop_label = self.define_label();
1656
1657 self.begin_loop_block(condition_label);
1658 self.mark_label(loop_label);
1659 self.transform_and_emit_embedded_stmt(*node.body);
1660 self.mark_label(condition_label);
1661 node.test.visit_mut_with(self);
1662 let span = node.test.span();
1663 self.emit_break_when_true(loop_label, node.test, Some(span));
1664 self.end_loop_block();
1665 } else {
1666 node.visit_mut_with(self);
1667 self.emit_stmt(node.into());
1668 }
1669 }
1670
1671 fn transform_and_emit_while_stmt(&mut self, mut node: WhileStmt) {
1672 let _tracing = dev_span!("transform_and_emit_while_stmt");
1673
1674 if contains_yield(&node) {
1675 let loop_label = self.define_label();
1690 let end_label = self.begin_loop_block(loop_label);
1691 self.mark_label(loop_label);
1692 node.test.visit_mut_with(self);
1693 self.emit_break_when_false(end_label, node.test, None);
1694 self.transform_and_emit_embedded_stmt(*node.body);
1695 self.emit_break(loop_label, None);
1696 self.end_loop_block();
1697 } else {
1698 node.visit_mut_with(self);
1699
1700 self.emit_stmt(node.into());
1701 }
1702 }
1703
1704 fn transform_and_emit_for_stmt(&mut self, mut node: ForStmt) {
1705 if contains_yield(&node) {
1706 let condition_label = self.define_label();
1725 let increment_label = self.define_label();
1726 let end_label = self.begin_loop_block(increment_label);
1727
1728 if let Some(init) = node.init {
1729 match init {
1730 VarDeclOrExpr::VarDecl(init) => {
1731 self.transform_and_emit_var_decl_list(init);
1732 }
1733 VarDeclOrExpr::Expr(mut init) => {
1734 init.visit_mut_with(self);
1735 self.emit_stmt(
1736 ExprStmt {
1737 span: init.span(),
1738 expr: init,
1739 }
1740 .into(),
1741 );
1742 }
1743 #[cfg(swc_ast_unknown)]
1744 _ => panic!("unable to access unknown nodes"),
1745 }
1746 }
1747
1748 self.mark_label(condition_label);
1749
1750 if let Some(mut cond) = node.test {
1751 cond.visit_mut_with(self);
1752 self.emit_break_when_false(end_label, cond, None);
1753 }
1754
1755 self.transform_and_emit_embedded_stmt(*node.body);
1756
1757 self.mark_label(increment_label);
1758
1759 if let Some(mut incrementor) = node.update {
1760 incrementor.visit_mut_with(self);
1761
1762 self.emit_stmt(
1763 ExprStmt {
1764 span: incrementor.span(),
1765 expr: incrementor,
1766 }
1767 .into(),
1768 );
1769 }
1770
1771 self.emit_break(condition_label, None);
1772 self.end_loop_block();
1773 } else {
1774 node.visit_mut_with(self);
1775 self.emit_stmt(node.into());
1776 }
1777 }
1778
1779 fn transform_and_emit_for_in_stmt(&mut self, mut node: ForInStmt) {
1780 if contains_yield(&node) {
1781 let keys_array = self.declare_local(None);
1803 let key = self.declare_local(None);
1804 let keys_index = private_ident!("_i");
1805
1806 self.hoist_variable_declaration(&keys_index);
1807
1808 self.emit_assignment(
1809 keys_array.clone().into(),
1810 Box::new(ArrayLit::dummy().into()),
1811 None,
1812 );
1813
1814 node.right.visit_mut_with(self);
1815 self.emit_stmt(
1816 ForInStmt {
1817 span: DUMMY_SP,
1818 left: ForHead::Pat(key.clone().into()),
1819 right: node.right.take(),
1820 body: Box::new(Stmt::Expr(ExprStmt {
1821 span: DUMMY_SP,
1822 expr: CallExpr {
1823 span: DUMMY_SP,
1824 callee: keys_array
1825 .clone()
1826 .make_member(quote_ident!("push"))
1827 .as_callee(),
1828 args: vec![key.as_arg()],
1829 ..Default::default()
1830 }
1831 .into(),
1832 })),
1833 }
1834 .into(),
1835 );
1836
1837 self.emit_assignment(keys_index.clone().into(), 0.into(), None);
1838
1839 let condition_label = self.define_label();
1840 let increment_label = self.define_label();
1841 let end_label = self.begin_loop_block(increment_label);
1842
1843 self.mark_label(condition_label);
1844 self.emit_break_when_false(
1845 end_label,
1846 Box::new(keys_index.clone().make_bin(
1847 op!("<"),
1848 keys_array.clone().make_member(quote_ident!("length")),
1849 )),
1850 None,
1851 );
1852
1853 let variable = match node.left {
1854 ForHead::VarDecl(initializer) => {
1855 for variable in initializer.decls.iter() {
1856 self.hoist_variable_declaration(&Ident::from(
1857 variable.name.as_ident().unwrap(),
1858 ));
1859 }
1860
1861 initializer.decls[0].name.clone()
1862 }
1863 ForHead::Pat(mut initializer) => {
1864 initializer.visit_mut_with(self);
1865 *initializer
1866 }
1867
1868 ForHead::UsingDecl(..) => {
1869 unreachable!("using declaration must be removed by previous pass")
1870 }
1871
1872 #[cfg(swc_ast_unknown)]
1873 _ => panic!("unable to access unknown nodes"),
1874 };
1875 self.emit_assignment(
1876 variable.try_into().unwrap(),
1877 MemberExpr {
1878 span: DUMMY_SP,
1879 obj: Box::new(keys_array.into()),
1880 prop: MemberProp::Computed(ComputedPropName {
1881 span: DUMMY_SP,
1882 expr: Box::new(keys_index.clone().into()),
1883 }),
1884 }
1885 .into(),
1886 None,
1887 );
1888 self.transform_and_emit_embedded_stmt(*node.body);
1889
1890 self.mark_label(increment_label);
1891 self.emit_stmt(
1892 ExprStmt {
1893 span: DUMMY_SP,
1894 expr: UpdateExpr {
1895 span: DUMMY_SP,
1896 prefix: false,
1897 op: op!("++"),
1898 arg: Box::new(keys_index.clone().into()),
1899 }
1900 .into(),
1901 }
1902 .into(),
1903 );
1904
1905 self.emit_break(condition_label, None);
1906 self.end_loop_block();
1907 } else {
1908 node.visit_mut_with(self);
1909 self.emit_stmt(node.into());
1910 }
1911 }
1912
1913 fn transform_and_emit_continue_stmt(&mut self, node: ContinueStmt) {
1914 let label = self.find_continue_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_break_stmt(&mut self, node: BreakStmt) {
1925 let label = self.find_break_target(node.label.as_ref().map(|l| l.sym.clone()));
1926 if label.0 > 0 {
1927 self.emit_break(label, Some(node.span));
1928 } else {
1929 self.emit_stmt(node.into())
1932 }
1933 }
1934
1935 fn transform_and_emit_return_stmt(&mut self, mut s: ReturnStmt) {
1936 s.arg.visit_mut_with(self);
1937 self.emit_return(s.arg, Some(s.span))
1938 }
1939
1940 fn transform_and_emit_with_stmt(&mut self, mut node: WithStmt) {
1941 if contains_yield(&node) {
1942 node.obj.visit_mut_with(self);
1953 let obj = self.cache_expression(node.obj);
1954 self.begin_with_block(obj);
1955 self.transform_and_emit_embedded_stmt(*node.body);
1956 self.end_with_block();
1957 } else {
1958 node.visit_mut_with(self);
1959 self.emit_stmt(node.into());
1960 }
1961 }
1962
1963 fn transform_and_emit_switch_stmt(&mut self, mut node: SwitchStmt) {
1964 if contains_yield(&node.cases) {
1965 let end_label = self.begin_switch_block();
1998 node.discriminant.visit_mut_with(self);
1999 let expression = self.cache_expression(node.discriminant);
2000
2001 let mut clause_labels = Vec::new();
2005 let mut default_clause_index = -1i32;
2006
2007 for (i, clause) in node.cases.iter().enumerate() {
2008 clause_labels.push(self.define_label());
2009 if clause.test.is_none() && default_clause_index == -1 {
2010 default_clause_index = i as _;
2011 }
2012 }
2013
2014 let mut clauses_written = 0;
2019 let mut pending_clauses = Vec::new();
2020
2021 while clauses_written < node.cases.len() {
2022 #[cfg(debug_assertions)]
2023 debug!("clauses_written: {}", clauses_written);
2024
2025 let mut default_clauses_skipped = 0;
2026
2027 for (i, clause) in node.cases.iter_mut().enumerate().skip(clauses_written) {
2028 if clause.test.is_some() {
2029 if contains_yield(&clause.test) && !pending_clauses.is_empty() {
2030 break;
2031 }
2032
2033 clause.test.visit_mut_with(self);
2034 let span = clause.test.span();
2035 pending_clauses.push(SwitchCase {
2036 span: DUMMY_SP,
2037 test: clause.test.take(),
2038 cons: vec![self
2039 .create_inline_break(clause_labels[i], Some(span))
2040 .into()],
2041 })
2042 } else {
2043 default_clauses_skipped += 1;
2044 }
2045 }
2046
2047 if !pending_clauses.is_empty() {
2048 clauses_written += pending_clauses.len();
2049 self.emit_stmt(
2050 SwitchStmt {
2051 span: DUMMY_SP,
2052 discriminant: expression.clone().into(),
2053 cases: take(&mut pending_clauses),
2054 }
2055 .into(),
2056 );
2057 }
2058
2059 if default_clauses_skipped > 0 {
2060 clauses_written += default_clauses_skipped;
2061 }
2062 }
2063
2064 if default_clause_index >= 0 {
2065 self.emit_break(clause_labels[default_clause_index as usize], None);
2066 } else {
2067 self.emit_break(end_label, None);
2068 }
2069
2070 for (i, clause) in node.cases.into_iter().enumerate() {
2071 self.mark_label(clause_labels[i]);
2072 self.transform_and_emit_stmts(clause.cons, 0);
2073 }
2074
2075 self.end_switch_block()
2076 } else {
2077 node.visit_mut_with(self);
2078 self.emit_stmt(node.into())
2079 }
2080 }
2081
2082 fn transform_and_emit_labeled_stmt(&mut self, mut node: LabeledStmt) {
2083 #[cfg(debug_assertions)]
2084 debug!("transform_and_emit_labeled_stmt: {:?}", node.label);
2085
2086 if contains_yield(&node) {
2087 self.begin_labeled_block(node.label.sym);
2098 self.transform_and_emit_embedded_stmt(*node.body);
2099 self.end_labeled_block();
2100 } else {
2101 node.visit_mut_with(self);
2102 self.emit_stmt(node.into());
2103 }
2104 }
2105
2106 fn transform_and_emit_throw_stmt(&mut self, mut node: ThrowStmt) {
2107 node.arg.visit_mut_with(self);
2108 self.emit_throw(node.arg, Some(node.span))
2109 }
2110
2111 fn transform_and_emit_try_stmt(&mut self, mut node: TryStmt) {
2112 let _tracing = dev_span!("transform_and_emit_try_stmt");
2113
2114 if contains_yield(&node) {
2115 self.begin_exception_block();
2146 self.transform_and_emit_embedded_stmt(node.block.into());
2147 if let Some(catch) = node.handler {
2148 self.begin_catch_block(VarDeclarator {
2149 name: catch.param.clone().unwrap(),
2150 ..Take::dummy()
2151 });
2152 self.transform_and_emit_embedded_stmt(catch.body.into());
2153 }
2154
2155 if let Some(finalizer) = node.finalizer {
2156 self.begin_finally_block();
2157 self.transform_and_emit_embedded_stmt(finalizer.into());
2158 }
2159
2160 self.end_exception_block();
2161 } else {
2162 node.visit_mut_with(self);
2163 self.emit_stmt(node.into());
2164 }
2165 }
2166
2167 fn count_initial_nodes_without_yield<N>(&self, nodes: &[N]) -> usize
2168 where
2169 N: VisitWith<YieldFinder>,
2170 {
2171 for (i, node) in nodes.iter().enumerate() {
2172 if contains_yield(node) {
2173 return i;
2174 }
2175 }
2176
2177 0
2178 }
2179
2180 fn cache_expression(&mut self, node: Box<Expr>) -> Ident {
2181 match *node {
2182 Expr::Ident(i) => i,
2183 _ => {
2184 let span = node.span();
2185
2186 let temp = self.create_temp_variable();
2187 self.emit_assignment(temp.clone().into(), node, Some(span));
2188 temp
2189 }
2190 }
2191 }
2192
2193 fn declare_local(&mut self, name: Option<Atom>) -> Ident {
2194 let temp = name
2195 .map(|name| private_ident!(name))
2196 .unwrap_or_else(|| private_ident!("_tmp"));
2197
2198 self.hoist_variable_declaration(&temp);
2199 temp
2200 }
2201
2202 fn define_label(&mut self) -> Label {
2204 if self.label_offsets.is_none() {
2205 self.label_offsets = Some(Default::default());
2206 }
2207
2208 let label = Label(self.next_label_id as _);
2209 self.next_label_id += 1;
2210 #[cfg(debug_assertions)]
2211 debug!("define_label: {:?}", label);
2212
2213 if label.0 as usize >= self.label_offsets.as_ref().unwrap().len() {
2214 self.label_offsets
2215 .as_mut()
2216 .unwrap()
2217 .resize(label.0 as usize + 1, 0);
2218 }
2219 self.label_offsets.as_mut().unwrap()[label.0 as usize] = -1;
2220 label
2221 }
2222
2223 fn mark_label(&mut self, label: Label) {
2225 debug_assert!(self.label_offsets.is_some(), "No labels were defined.");
2226
2227 if label.0 as usize >= self.label_offsets.as_ref().unwrap().len() {
2228 self.label_offsets
2229 .as_mut()
2230 .unwrap()
2231 .resize(label.0 as usize + 1, Default::default());
2232 }
2233
2234 self.label_offsets.as_mut().unwrap()[label.0 as usize] =
2235 self.operations.as_deref().map_or(0, |v| v.len() as _);
2236
2237 #[cfg(debug_assertions)]
2238 debug!(
2239 "mark_label: {:?}; offset: {}",
2240 label,
2241 self.label_offsets.as_mut().unwrap()[label.0 as usize]
2242 );
2243 }
2244
2245 fn begin_block(&mut self, block: CodeBlock) -> Ptr<CodeBlock> {
2249 if self.blocks.is_none() {
2250 self.blocks = Some(Default::default());
2251 self.block_actions = Some(Default::default());
2252 self.block_offsets = Some(Default::default());
2253 self.block_stack = Some(Default::default());
2254 }
2255
2256 #[cfg(debug_assertions)]
2257 let index = self.block_actions.as_ref().unwrap().len();
2258
2259 #[cfg(debug_assertions)]
2260 if cfg!(debug_assertions) {
2261 debug!("Begin block {}: {:?}", index, block);
2262 }
2263
2264 let block = Rc::new(RefCell::new(block));
2265
2266 self.block_actions.as_mut().unwrap().push(BlockAction::Open);
2267 self.block_offsets
2268 .as_mut()
2269 .unwrap()
2270 .push(self.operations.as_ref().map_or(0, |v| v.len()));
2271 self.blocks.as_mut().unwrap().push(block.clone());
2272 self.block_stack.as_mut().unwrap().push(block.clone());
2273
2274 block
2275 }
2276
2277 fn end_block(&mut self) -> Ptr<CodeBlock> {
2279 let block = self.peek_block().expect("beginBlock was never called.");
2280
2281 #[cfg(debug_assertions)]
2282 let index = self.block_actions.as_ref().unwrap().len();
2283
2284 #[cfg(debug_assertions)]
2285 debug!("End block {}", index);
2286
2287 self.block_actions
2288 .as_mut()
2289 .unwrap()
2290 .push(BlockAction::Close);
2291 self.block_offsets
2292 .as_mut()
2293 .unwrap()
2294 .push(self.operations.as_ref().map_or(0, |v| v.len()));
2295 self.blocks.as_mut().unwrap().push(block.clone());
2296 self.block_stack.as_mut().unwrap().pop();
2297 block
2298 }
2299
2300 fn peek_block(&self) -> Option<Ptr<CodeBlock>> {
2302 self.block_stack.as_ref().and_then(|v| v.last().cloned())
2303 }
2304
2305 fn peek_block_kind(&self) -> Option<CodeBlockKind> {
2307 self.peek_block().map(|b| match &*b.borrow() {
2308 CodeBlock::With(..) => CodeBlockKind::With,
2309 CodeBlock::Exception(..) => CodeBlockKind::Exception,
2310 CodeBlock::Labeled(..) => CodeBlockKind::Labeled,
2311 CodeBlock::Switch(..) => CodeBlockKind::Switch,
2312 CodeBlock::Loop(..) => CodeBlockKind::Loop,
2313 })
2314 }
2315
2316 fn begin_with_block(&mut self, expr: Ident) {
2320 let start_label = self.define_label();
2321 let end_label = self.define_label();
2322 self.mark_label(start_label);
2323 self.begin_block(CodeBlock::With(WithBlock {
2324 expression: expr,
2325 start_label,
2326 end_label,
2327 }));
2328 }
2329
2330 fn end_with_block(&mut self) {
2332 debug_assert!(self.peek_block_kind() == Some(CodeBlockKind::With));
2333 let block = self.end_block();
2334 let b = block.borrow();
2335 if let CodeBlock::With(block) = &*b {
2336 self.mark_label(block.end_label);
2337 } else {
2338 unreachable!()
2339 }
2340 }
2341
2342 fn begin_exception_block(&mut self) -> Label {
2344 let _tracing = dev_span!("begin_exception_block");
2345
2346 let start_label = self.define_label();
2347 let end_label = self.define_label();
2348 self.mark_label(start_label);
2349 self.begin_block(CodeBlock::Exception(ExceptionBlock {
2350 state: ExceptionBlockState::Try,
2351 start_label,
2352 end_label,
2353 catch_variable: Default::default(),
2354 catch_label: Default::default(),
2355 finally_label: Default::default(),
2356 }));
2357 self.emit_nop();
2358 end_label
2359 }
2360
2361 fn begin_catch_block(&mut self, variable: VarDeclarator) {
2367 debug_assert!(self.peek_block_kind() == Some(CodeBlockKind::Exception));
2368
2369 let name = variable.name.expect_ident().into();
2370 self.hoist_variable_declaration(&name);
2371
2372 let peeked = self.peek_block().unwrap();
2374 let exception = peeked.borrow_mut();
2375 let mut exception = RefMut::map(exception, |v| match v {
2376 CodeBlock::Exception(v) => v,
2377 _ => unreachable!(),
2378 });
2379 debug_assert!(exception.state < ExceptionBlockState::Catch);
2380
2381 let end_label = exception.end_label;
2382 self.emit_break(end_label, None);
2383
2384 let catch_label = self.define_label();
2385 self.mark_label(catch_label);
2386 exception.state = ExceptionBlockState::Catch;
2387 exception.catch_variable = Some(name.clone());
2388 exception.catch_label = Some(catch_label);
2389
2390 self.emit_assignment(
2391 name.clone().into(),
2392 CallExpr {
2393 span: DUMMY_SP,
2394 callee: self
2395 .state
2396 .clone()
2397 .make_member(quote_ident!("sent"))
2398 .as_callee(),
2399 args: Vec::new(),
2400 ..Default::default()
2401 }
2402 .into(),
2403 None,
2404 );
2405
2406 self.emit_nop();
2407 }
2408
2409 fn begin_finally_block(&mut self) {
2411 let _tracing = dev_span!("begin_finally_block");
2412
2413 debug_assert!(self.peek_block_kind() == Some(CodeBlockKind::Exception));
2414
2415 let block = self.peek_block().unwrap();
2416 let mut b = block.borrow_mut();
2417 if let CodeBlock::Exception(block) = &mut *b {
2418 debug_assert!(block.state < ExceptionBlockState::Finally);
2419
2420 let end_label = block.end_label;
2421 self.emit_break(end_label, None);
2422
2423 let finally_label = self.define_label();
2424 self.mark_label(finally_label);
2425 block.state = ExceptionBlockState::Finally;
2426 block.finally_label = Some(finally_label);
2427 } else {
2428 unreachable!()
2429 }
2430 }
2431
2432 fn end_exception_block(&mut self) {
2434 debug_assert!(self.peek_block_kind() == Some(CodeBlockKind::Exception));
2435 let block = self.end_block();
2436 let mut b = block.borrow_mut();
2437 if let CodeBlock::Exception(block) = &mut *b {
2438 let state = block.state;
2439 if state < ExceptionBlockState::Finally {
2440 self.emit_break(block.end_label, None);
2441 } else {
2442 self.emit_endfinally();
2443 }
2444 self.mark_label(block.end_label);
2445 self.emit_nop();
2446 block.state = ExceptionBlockState::Done;
2447 } else {
2448 unreachable!()
2449 }
2450 }
2451
2452 fn begin_script_loop_block(&mut self) {
2455 self.begin_block(CodeBlock::Loop(LoopBlock {
2456 is_script: true,
2457 break_label: Label(-1),
2458 continue_label: Label(-1),
2459 }));
2460 }
2461
2462 fn begin_loop_block(&mut self, continue_label: Label) -> Label {
2469 let _tracing = dev_span!("begin_loop_block");
2470
2471 let break_label = self.define_label();
2472 self.begin_block(CodeBlock::Loop(LoopBlock {
2473 is_script: false,
2474 break_label,
2475 continue_label,
2476 }));
2477 break_label
2478 }
2479
2480 fn end_loop_block(&mut self) {
2483 debug_assert!(self.peek_block_kind() == Some(CodeBlockKind::Loop));
2484 let block = self.end_block();
2485 let block = block.borrow();
2486 if let CodeBlock::Loop(block) = &*block {
2487 let break_label = block.break_label;
2488 if !block.is_script {
2489 self.mark_label(break_label);
2490 }
2491 } else {
2492 unreachable!()
2493 }
2494 }
2495
2496 fn begin_script_switch_block(&mut self) {
2499 self.begin_block(CodeBlock::Switch(SwitchBlock {
2500 is_script: true,
2501 break_label: Label(-1),
2502 }));
2503 }
2504
2505 fn begin_switch_block(&mut self) -> Label {
2511 let break_label = self.define_label();
2512 self.begin_block(CodeBlock::Switch(SwitchBlock {
2513 is_script: false,
2514 break_label,
2515 }));
2516 break_label
2517 }
2518
2519 fn end_switch_block(&mut self) {
2522 debug_assert!(self.peek_block_kind() == Some(CodeBlockKind::Switch));
2523 let block = self.end_block();
2524 let block = block.borrow();
2525 if let CodeBlock::Switch(block) = &*block {
2526 let break_label = block.break_label;
2527 if !block.is_script {
2528 self.mark_label(break_label);
2529 }
2530 } else {
2531 unreachable!()
2532 }
2533 }
2534
2535 fn begin_script_labeled_block(&mut self, label_text: Atom) {
2536 self.begin_block(CodeBlock::Labeled(LabeledBlock {
2537 is_script: true,
2538 label_text,
2539 break_label: Label(-1),
2540 }));
2541 }
2542
2543 fn begin_labeled_block(&mut self, label_text: Atom) {
2544 let break_label = self.define_label();
2545 self.begin_block(CodeBlock::Labeled(LabeledBlock {
2546 is_script: false,
2547 label_text,
2548 break_label,
2549 }));
2550 }
2551
2552 fn end_labeled_block(&mut self) {
2553 let block = self.end_block();
2554 if !block.borrow().is_script() {
2555 let break_label = match &*block.borrow() {
2556 CodeBlock::Labeled(block) => block.break_label,
2557 _ => unreachable!(),
2558 };
2559 self.mark_label(break_label);
2560 }
2561 }
2562
2563 fn supports_unlabeled_break(&self, block: &CodeBlock) -> bool {
2565 matches!(block, CodeBlock::Switch(..) | CodeBlock::Loop(..))
2566 }
2567
2568 fn supports_labeled_break_or_continue(&self, block: &CodeBlock) -> bool {
2571 matches!(block, CodeBlock::Labeled(..))
2572 }
2573
2574 fn supports_unlabeled_continue(&self, block: &CodeBlock) -> bool {
2576 matches!(block, CodeBlock::Loop(..))
2577 }
2578
2579 fn has_immediate_containing_labeled_block(&self, label_text: &Atom, start: usize) -> bool {
2580 for i in (0..=start).rev() {
2581 let block = self.block_stack.as_ref().unwrap()[i].clone();
2582 if self.supports_labeled_break_or_continue(&block.borrow()) {
2583 if let CodeBlock::Labeled(block) = &*block.borrow() {
2584 if block.label_text == *label_text {
2585 return true;
2586 }
2587 } else {
2588 unreachable!()
2589 }
2590 } else {
2591 break;
2592 }
2593 }
2594
2595 false
2596 }
2597
2598 fn find_break_target(&self, label_text: Option<Atom>) -> Label {
2602 #[cfg(debug_assertions)]
2603 debug!("find_break_target: label_text={:?}", label_text);
2604
2605 if let Some(block_stack) = &self.block_stack {
2606 if let Some(label_text) = label_text {
2607 for i in (0..=block_stack.len() - 1).rev() {
2608 let block = &block_stack[i];
2609 if (self.supports_labeled_break_or_continue(&block.borrow())
2610 && block.borrow().label_text().unwrap() == label_text)
2611 || (self.supports_unlabeled_break(&block.borrow())
2612 && self.has_immediate_containing_labeled_block(&label_text, i - 1))
2613 {
2614 return block.borrow().break_label().unwrap();
2615 }
2616 }
2617 } else {
2618 for i in (0..=block_stack.len() - 1).rev() {
2619 let block = &block_stack[i];
2620 if self.supports_unlabeled_break(&block.borrow()) {
2621 return block.borrow().break_label().unwrap();
2622 }
2623 }
2624 }
2625 }
2626
2627 Label(0)
2628 }
2629
2630 fn find_continue_target(&self, label_text: Option<Atom>) -> Label {
2634 if let Some(block_stack) = &self.block_stack {
2635 if let Some(label_text) = label_text {
2636 for i in (0..=block_stack.len() - 1).rev() {
2637 let block = &block_stack[i];
2638 if self.supports_unlabeled_continue(&block.borrow())
2639 && self.has_immediate_containing_labeled_block(&label_text, i - 1)
2640 {
2641 return block.borrow().continue_label().unwrap();
2642 }
2643 }
2644 } else {
2645 for i in (0..=block_stack.len() - 1).rev() {
2646 let block = &block_stack[i];
2647 if self.supports_unlabeled_continue(&block.borrow()) {
2648 return block.borrow().continue_label().unwrap();
2649 }
2650 }
2651 }
2652 }
2653
2654 Label(0)
2655 }
2656
2657 fn create_label(&mut self, label: Option<Label>) -> Box<Expr> {
2660 if let Some(label) = label {
2661 if label.0 > 0 {
2662 #[cfg(debug_assertions)]
2663 debug!("create_label: label={:?}", label);
2664
2665 if self.label_exprs.is_none() {
2666 self.label_exprs = Some(Default::default());
2667 }
2668 let label_expressions = self.label_exprs.as_mut().unwrap();
2669 let expr = Loc {
2670 pos: BytePos(label.0 as _),
2671 value: -1,
2672 };
2673 if label_expressions.get(label.0 as usize).is_none() {
2674 if label.0 as usize >= label_expressions.len() {
2675 label_expressions.resize(label.0 as usize + 1, Vec::new());
2676 }
2677
2678 label_expressions[label.0 as usize] = vec![expr];
2679 } else {
2680 label_expressions
2681 .get_mut(label.0 as usize)
2682 .unwrap()
2683 .push(expr);
2684 }
2685 return Invalid {
2686 span: Span::new_with_checked(BytePos(label.0 as _), BytePos(label.0 as _)),
2687 }
2688 .into();
2689 }
2690 }
2691
2692 Box::new(Invalid { span: DUMMY_SP }.into())
2693 }
2694
2695 fn create_instruction(&mut self, instruction: Instruction) -> Number {
2697 Number {
2704 span: DUMMY_SP,
2705 value: instruction as u16 as _,
2706 raw: None,
2707 }
2708 }
2709
2710 fn create_inline_break(&mut self, label: Label, span: Option<Span>) -> ReturnStmt {
2716 debug_assert!(label.0 >= 0, "Invalid label");
2717 let args = vec![
2718 Some(self.create_instruction(Instruction::Break).as_arg()),
2719 Some(self.create_label(Some(label)).as_arg()),
2720 ];
2721 ReturnStmt {
2722 span: span.unwrap_or(DUMMY_SP),
2723 arg: Some(
2724 ArrayLit {
2725 span: DUMMY_SP,
2726 elems: args,
2727 }
2728 .into(),
2729 ),
2730 }
2731 }
2732
2733 fn create_inline_return(&mut self, expr: Option<Box<Expr>>, loc: Option<Span>) -> ReturnStmt {
2738 ReturnStmt {
2739 span: loc.unwrap_or(DUMMY_SP),
2740 arg: Some(
2741 ArrayLit {
2742 span: DUMMY_SP,
2743 elems: match expr {
2744 Some(expr) => vec![
2745 Some(self.create_instruction(Instruction::Return).as_arg()),
2746 Some(expr.as_arg()),
2747 ],
2748 None => vec![Some(self.create_instruction(Instruction::Return).as_arg())],
2749 },
2750 }
2751 .into(),
2752 ),
2753 }
2754 }
2755
2756 fn create_generator_resume(&mut self, loc: Option<Span>) -> Box<Expr> {
2758 CallExpr {
2759 span: loc.unwrap_or(DUMMY_SP),
2760 callee: self
2761 .state
2762 .clone()
2763 .make_member(quote_ident!("sent"))
2764 .as_callee(),
2765 args: Vec::new(),
2766 ..Default::default()
2767 }
2768 .into()
2769 }
2770
2771 fn emit_nop(&mut self) {
2773 self.emit_worker(OpCode::Nop, None, None);
2774 }
2775
2776 fn emit_stmt(&mut self, stmt: Stmt) {
2780 if stmt.is_empty() {
2781 self.emit_nop();
2782 } else {
2783 self.emit_worker(OpCode::Statement, Some(OpArgs::Stmt(Box::new(stmt))), None);
2784 }
2785 }
2786
2787 fn emit_assignment(&mut self, left: AssignTarget, right: Box<Expr>, loc: Option<Span>) {
2793 self.emit_worker(OpCode::Assign, Some(OpArgs::PatAndExpr(left, right)), loc);
2794 }
2795
2796 fn emit_break(&mut self, label: Label, loc: Option<Span>) {
2801 self.emit_worker(OpCode::Break, Some(OpArgs::Label(label)), loc);
2802 }
2803
2804 fn emit_break_when_true(&mut self, label: Label, condition: Box<Expr>, loc: Option<Span>) {
2811 self.emit_worker(
2812 OpCode::BreakWhenTrue,
2813 Some(OpArgs::LabelExpr(label, condition)),
2814 loc,
2815 );
2816 }
2817
2818 fn emit_break_when_false(&mut self, label: Label, condition: Box<Expr>, loc: Option<Span>) {
2825 self.emit_worker(
2826 OpCode::BreakWhenFalse,
2827 Some(OpArgs::LabelExpr(label, condition)),
2828 loc,
2829 );
2830 }
2831
2832 fn emit_yield_star(&mut self, expr: Option<Box<Expr>>, loc: Option<Span>) {
2837 self.emit_worker(OpCode::YieldStar, Some(OpArgs::OptExpr(expr)), loc);
2838 }
2839
2840 fn emit_yield(&mut self, expr: Option<Box<Expr>>, loc: Option<Span>) {
2845 self.emit_worker(OpCode::Yield, Some(OpArgs::OptExpr(expr)), loc);
2846 }
2847
2848 fn emit_return(&mut self, expr: Option<Box<Expr>>, loc: Option<Span>) {
2853 self.emit_worker(OpCode::Return, Some(OpArgs::OptExpr(expr)), loc);
2854 }
2855
2856 fn emit_throw(&mut self, expr: Box<Expr>, loc: Option<Span>) {
2861 self.emit_worker(OpCode::Throw, Some(OpArgs::OptExpr(Some(expr))), loc);
2862 }
2863
2864 fn emit_endfinally(&mut self) {
2867 self.emit_worker(OpCode::Endfinally, None, None);
2868 }
2869
2870 fn emit_worker(&mut self, code: OpCode, args: Option<OpArgs>, loc: Option<Span>) {
2875 if self.operations.is_none() {
2876 self.operations = Some(Vec::new());
2877 self.operation_args = Some(Vec::new());
2878 self.operation_locs = Some(Vec::new());
2879 }
2880 if self.label_offsets.is_none() {
2881 let label = self.define_label();
2883 self.mark_label(label);
2884 }
2885 debug_assert!(self.operations.is_some());
2886 debug_assert_eq!(
2887 self.operations.as_ref().unwrap().len(),
2888 self.operation_args.as_ref().unwrap().len()
2889 );
2890 debug_assert_eq!(
2891 self.operations.as_ref().unwrap().len(),
2892 self.operation_locs.as_ref().unwrap().len()
2893 );
2894
2895 self.operations.as_mut().unwrap().push(code);
2896 self.operation_args.as_mut().unwrap().push(args);
2897 self.operation_locs
2898 .as_mut()
2899 .unwrap()
2900 .push(loc.unwrap_or(DUMMY_SP));
2901 }
2902
2903 fn build_stmts(&mut self) -> Vec<Stmt> {
2905 if let Some(ops) = self.operations.clone() {
2906 for (op_index, _) in ops.iter().enumerate() {
2907 self.write_operation(op_index);
2908 }
2909
2910 self.flush_final_label(ops.len());
2911 } else {
2912 self.flush_final_label(0);
2913 }
2914
2915 if let Some(clauses) = self.clauses.take() {
2916 let label_expr = self.state.clone().make_member(quote_ident!("label"));
2917 let switch_stmt = SwitchStmt {
2918 span: DUMMY_SP,
2919 discriminant: label_expr.into(),
2920 cases: clauses,
2921 };
2922 return vec![Stmt::Switch(switch_stmt)];
2923 }
2924
2925 if let Some(stmts) = self.stmts.take() {
2926 return stmts;
2927 }
2928
2929 Vec::new()
2930 }
2931
2932 fn flush_label(&mut self) {
2934 if self.stmts.is_none() {
2935 return;
2936 }
2937
2938 self.append_label(!self.last_operation_was_abrupt);
2939
2940 self.last_operation_was_abrupt = false;
2941 self.last_operation_was_completion = false;
2942 self.label_number += 1;
2943 }
2944
2945 fn flush_final_label(&mut self, op_index: usize) {
2947 if self.is_final_label_reachable(op_index) {
2948 self.try_enter_label(op_index);
2949 self.with_block_stack = None;
2950 self.write_return(None, None);
2951 }
2952
2953 if self.stmts.is_some() && self.clauses.is_some() {
2954 self.append_label(false);
2955 }
2956
2957 self.update_label_expression();
2958 }
2959
2960 fn is_final_label_reachable(&self, op_index: usize) -> bool {
2963 if !self.last_operation_was_completion {
2966 return true;
2967 }
2968
2969 if self.label_offsets.is_none() || self.label_exprs.is_none() {
2972 return false;
2973 }
2974
2975 for (label, label_offset) in self
2978 .label_offsets
2979 .as_ref()
2980 .unwrap()
2981 .iter()
2982 .copied()
2983 .enumerate()
2984 {
2985 if label_offset as usize == op_index
2986 && self.label_exprs.as_ref().unwrap().get(label).is_some()
2987 {
2988 return true;
2989 }
2990 }
2991
2992 false
2993 }
2994
2995 fn append_label(&mut self, mark_label_end: bool) {
3001 if cfg!(debug_assertions) {
3002 debug!(mark_label_end = mark_label_end, "append_label");
3003 }
3004
3005 if self.clauses.is_none() {
3006 self.clauses = Some(Default::default());
3007 }
3008
3009 #[allow(clippy::manual_unwrap_or_default)]
3010 let stmts = if let Some(mut stmts) = self.stmts.take() {
3011 if self.with_block_stack.is_some() {
3012 for (_i, with_block) in self
3017 .with_block_stack
3018 .as_ref()
3019 .unwrap()
3020 .iter()
3021 .enumerate()
3022 .rev()
3023 {
3024 let b = with_block.borrow();
3025 let with_block = match &*b {
3026 CodeBlock::With(v) => v,
3027 _ => {
3028 unreachable!()
3029 }
3030 };
3031
3032 stmts = vec![Stmt::With(WithStmt {
3033 span: DUMMY_SP,
3034 obj: Box::new(Expr::Ident(with_block.expression.clone())),
3035 body: Box::new(Stmt::Block(BlockStmt {
3036 span: DUMMY_SP,
3037 stmts,
3038 ..Default::default()
3039 })),
3040 })];
3041 }
3042 }
3043
3044 if cfg!(debug_assertions) {
3045 debug!(
3046 "current_exception_block = {:?}",
3047 self.current_exception_block
3048 );
3049 }
3050
3051 if let Some(current_exception_block) = self.current_exception_block.take() {
3052 let b = current_exception_block.borrow();
3053 let ExceptionBlock {
3054 start_label,
3055 catch_label,
3056 finally_label,
3057 end_label,
3058 ..
3059 } = match &*b {
3060 CodeBlock::Exception(v) => v,
3061 _ => {
3062 unreachable!()
3063 }
3064 };
3065
3066 let start_label = self.create_label(Some(*start_label));
3067 let catch_label = self.create_label(*catch_label);
3068 let finally_label = self.create_label(*finally_label);
3069 let end_label = self.create_label(Some(*end_label));
3070
3071 stmts.insert(
3072 0,
3073 ExprStmt {
3074 span: DUMMY_SP,
3075 expr: CallExpr {
3076 span: DUMMY_SP,
3077 callee: self
3078 .state
3079 .clone()
3080 .make_member(quote_ident!("trys"))
3081 .make_member(quote_ident!("push"))
3082 .as_callee(),
3083 args: vec![ArrayLit {
3084 span: DUMMY_SP,
3085 elems: vec![
3086 Some(start_label.as_arg()),
3087 Some(catch_label.as_arg()),
3088 Some(finally_label.as_arg()),
3089 Some(end_label.as_arg()),
3090 ],
3091 }
3092 .as_arg()],
3093 ..Default::default()
3094 }
3095 .into(),
3096 }
3097 .into(),
3098 );
3099 }
3100
3101 if mark_label_end {
3102 stmts.push(
3107 ExprStmt {
3108 span: DUMMY_SP,
3109 expr: AssignExpr {
3110 span: DUMMY_SP,
3111 op: op!("="),
3112 left: self.state.clone().make_member(quote_ident!("label")).into(),
3113 right: (self.label_number + 1).into(),
3114 }
3115 .into(),
3116 }
3117 .into(),
3118 );
3119 }
3120
3121 stmts
3122 } else {
3123 Default::default()
3124 };
3125
3126 self.clauses.as_mut().unwrap().push(SwitchCase {
3127 span: DUMMY_SP,
3128 test: Some(self.label_number.into()),
3129 cons: stmts,
3130 });
3131 }
3132
3133 #[tracing::instrument(level = "debug", skip(self))]
3134 fn try_enter_label(&mut self, op_index: usize) {
3135 if self.label_offsets.is_none() {
3136 return;
3137 }
3138
3139 for (label, label_offset) in self.label_offsets.clone().unwrap().into_iter().enumerate() {
3140 if label_offset as usize == op_index {
3141 self.flush_label();
3142
3143 if self.label_numbers.is_none() {
3144 self.label_numbers = Some(Vec::new());
3145 }
3146
3147 if let Some(v) = self
3148 .label_numbers
3149 .as_mut()
3150 .unwrap()
3151 .get_mut(self.label_number)
3152 {
3153 v.push(label);
3154 } else {
3155 if self.label_number >= self.label_numbers.as_ref().unwrap().len() {
3156 self.label_numbers
3157 .as_mut()
3158 .unwrap()
3159 .resize(self.label_number + 1, Vec::new());
3160 }
3161
3162 self.label_numbers.as_mut().unwrap()[self.label_number] = vec![label];
3163 }
3164 }
3165 }
3166 }
3167
3168 fn update_label_expression(&mut self) {
3170 if self.label_exprs.is_some() && self.label_numbers.is_some() {
3171 for (label_number, labels) in self.label_numbers.as_ref().unwrap().iter().enumerate() {
3172 for &label in labels {
3173 let exprs = self.label_exprs.as_mut().unwrap().get_mut(label);
3174 if let Some(exprs) = exprs {
3175 for expr in exprs {
3176 expr.value = label_number as _;
3177 #[cfg(debug_assertions)]
3178 debug!("Label {:?} = {:?} ({:?})", label, expr.value, expr.pos);
3179 }
3180 }
3181 }
3182 }
3183 }
3184 }
3185
3186 #[tracing::instrument(level = "debug", skip(self))]
3188 fn try_enter_or_leave_block(&mut self, op_index: usize) {
3189 if let Some(blocks) = &self.blocks {
3190 while self.block_index < self.block_actions.as_ref().unwrap().len()
3191 && self.block_offsets.as_ref().unwrap()[self.block_index] <= op_index
3192 {
3193 #[cfg(debug_assertions)]
3194 debug!("try_enter_or_leave_block: iter");
3195
3196 let block_index = self.block_index;
3197 self.block_index += 1;
3198
3199 if cfg!(debug_assertions) {
3200 debug!(block_index = block_index, "try_enter_or_leave_block")
3201 }
3202
3203 let block = blocks[block_index].clone();
3205 let block_action = self.block_actions.as_ref().unwrap()[block_index];
3206
3207 let b = block.borrow();
3208 match &*b {
3209 CodeBlock::Exception(_) => {
3210 if block_action == BlockAction::Open {
3211 self.exception_block_stack
3212 .get_or_insert_with(Default::default)
3213 .extend(self.current_exception_block.clone());
3214
3215 if self.stmts.is_none() {
3217 self.stmts = Some(Default::default());
3218 }
3219
3220 #[cfg(debug_assertions)]
3221 debug!("Current exception block: open = Some({:?})", block);
3222 self.current_exception_block = Some(block.clone());
3223 } else if block_action == BlockAction::Close {
3224 self.current_exception_block =
3225 self.exception_block_stack.as_mut().unwrap().pop();
3226 #[cfg(debug_assertions)]
3227 debug!(
3228 "Current exception block: close = {:?}",
3229 self.current_exception_block
3230 );
3231 }
3232 }
3233
3234 CodeBlock::With(_) => {
3235 if block_action == BlockAction::Open {
3236 if self.with_block_stack.is_none() {
3237 self.with_block_stack = Some(Default::default());
3238 }
3239
3240 self.with_block_stack.as_mut().unwrap().push(block.clone());
3241 } else if block_action == BlockAction::Close {
3242 self.with_block_stack.as_mut().unwrap().pop();
3243 }
3244 }
3245
3246 _ => {}
3247 }
3248 }
3249 }
3250 }
3251
3252 #[tracing::instrument(level = "debug", skip(self))]
3255 fn write_operation(&mut self, op_index: usize) {
3256 if cfg!(debug_assertions) {
3257 debug!("Writing operation {}", op_index);
3258 }
3259
3260 self.try_enter_label(op_index);
3261 self.try_enter_or_leave_block(op_index);
3262
3263 if self.last_operation_was_abrupt {
3265 return;
3266 }
3267
3268 self.last_operation_was_abrupt = false;
3269 self.last_operation_was_completion = false;
3270
3271 let opcode = self.operations.as_ref().unwrap()[op_index];
3272 if opcode == OpCode::Nop {
3273 return;
3274 } else if opcode == OpCode::Endfinally {
3275 self.write_end_finally();
3276 return;
3277 }
3278
3279 let args = self.operation_args.as_mut().unwrap()[op_index]
3280 .take()
3281 .expect("failed to take operation arguments");
3282 if opcode == OpCode::Statement {
3283 let args = args.expect_stmt();
3284 self.write_stmt(*args);
3285 return;
3286 }
3287
3288 let loc = self.operation_locs.as_ref().unwrap()[op_index];
3289
3290 match opcode {
3291 OpCode::Assign => {
3292 let args = args.expect_pat_and_expr();
3293 self.write_assign(args.0, args.1, Some(loc));
3294 }
3295 OpCode::Break => {
3296 let args = args.expect_label();
3297 self.write_break(args, Some(loc));
3298 }
3299 OpCode::BreakWhenTrue => {
3300 let args = args.expect_label_expr();
3301 self.write_break_when_true(args.0, args.1, Some(loc));
3302 }
3303 OpCode::BreakWhenFalse => {
3304 let args = args.expect_label_expr();
3305 self.write_break_when_false(args.0, args.1, Some(loc));
3306 }
3307 OpCode::Yield => {
3308 let args = args.expect_opt_expr();
3309
3310 self.write_yield(args, Some(loc));
3311 }
3312 OpCode::YieldStar => {
3313 let args = args.expect_opt_expr().unwrap();
3314
3315 self.write_yield_star(args, Some(loc));
3316 }
3317 OpCode::Return => {
3318 let args = args.expect_opt_expr();
3319
3320 self.write_return(args, Some(loc));
3321 }
3322 OpCode::Throw => {
3323 let args = args.expect_opt_expr().unwrap();
3324
3325 self.write_throw(args, Some(loc));
3326 }
3327 _ => {}
3328 }
3329 }
3330
3331 fn write_stmt(&mut self, stmt: Stmt) {
3333 if stmt.is_empty() {
3334 return;
3335 }
3336 match self.stmts {
3337 Some(ref mut stmts) => stmts.push(stmt),
3338 None => self.stmts = Some(vec![stmt]),
3339 }
3340 }
3341
3342 fn write_assign(&mut self, left: AssignTarget, right: Box<Expr>, op_loc: Option<Span>) {
3344 self.write_stmt(
3345 ExprStmt {
3346 span: op_loc.unwrap_or(DUMMY_SP),
3347 expr: AssignExpr {
3348 span: DUMMY_SP,
3349 op: op!("="),
3350 left,
3351 right,
3352 }
3353 .into(),
3354 }
3355 .into(),
3356 )
3357 }
3358
3359 fn write_throw(&mut self, expr: Box<Expr>, op_loc: Option<Span>) {
3364 self.last_operation_was_abrupt = true;
3365 self.last_operation_was_completion = true;
3366
3367 self.write_stmt(
3369 ThrowStmt {
3370 span: op_loc.unwrap_or(DUMMY_SP),
3371 arg: expr,
3372 }
3373 .into(),
3374 )
3375 }
3376
3377 fn write_return(&mut self, expr: Option<Box<Expr>>, op_loc: Option<Span>) {
3382 self.last_operation_was_abrupt = true;
3383 self.last_operation_was_completion = true;
3384
3385 let inst = self.create_instruction(Instruction::Return);
3386 self.write_stmt(
3387 ReturnStmt {
3388 span: op_loc.unwrap_or(DUMMY_SP),
3389 arg: Some(
3390 ArrayLit {
3391 span: DUMMY_SP,
3392 elems: match expr {
3393 Some(expr) => {
3394 vec![Some(inst.as_arg()), Some(expr.as_arg())]
3395 }
3396 _ => {
3397 vec![Some(inst.as_arg())]
3398 }
3399 },
3400 }
3401 .into(),
3402 ),
3403 }
3404 .into(),
3405 )
3406 }
3407
3408 fn write_break(&mut self, label: Label, op_loc: Option<Span>) {
3413 self.last_operation_was_abrupt = true;
3414
3415 let inst = self.create_instruction(Instruction::Break);
3416 let label = self.create_label(Some(label));
3417 self.write_stmt(
3418 ReturnStmt {
3419 span: op_loc.unwrap_or(DUMMY_SP),
3420 arg: Some(
3421 ArrayLit {
3422 span: DUMMY_SP,
3423 elems: vec![Some(inst.as_arg()), Some(label.as_arg())],
3424 }
3425 .into(),
3426 ),
3427 }
3428 .into(),
3429 )
3430 }
3431
3432 fn write_break_when_true(&mut self, label: Label, cond: Box<Expr>, op_loc: Option<Span>) {
3438 let inst = self.create_instruction(Instruction::Break);
3439 let label = self.create_label(Some(label));
3440 self.write_stmt(
3441 IfStmt {
3442 span: DUMMY_SP,
3443 test: cond,
3444 cons: Box::new(Stmt::Return(ReturnStmt {
3445 span: op_loc.unwrap_or(DUMMY_SP),
3446 arg: Some(
3447 ArrayLit {
3448 span: DUMMY_SP,
3449 elems: vec![Some(inst.as_arg()), Some(label.as_arg())],
3450 }
3451 .into(),
3452 ),
3453 })),
3454 alt: None,
3455 }
3456 .into(),
3457 )
3458 }
3459
3460 fn write_break_when_false(&mut self, label: Label, cond: Box<Expr>, op_loc: Option<Span>) {
3466 let inst = self.create_instruction(Instruction::Break);
3467 let label = self.create_label(Some(label));
3468 self.write_stmt(
3469 IfStmt {
3470 span: DUMMY_SP,
3471 test: UnaryExpr {
3472 span: DUMMY_SP,
3473 op: op!("!"),
3474 arg: cond,
3475 }
3476 .into(),
3477 cons: Box::new(Stmt::Return(ReturnStmt {
3478 span: op_loc.unwrap_or(DUMMY_SP),
3479 arg: Some(
3480 ArrayLit {
3481 span: DUMMY_SP,
3482 elems: vec![Some(inst.as_arg()), Some(label.as_arg())],
3483 }
3484 .into(),
3485 ),
3486 })),
3487 alt: None,
3488 }
3489 .into(),
3490 )
3491 }
3492
3493 fn write_yield(&mut self, expr: Option<Box<Expr>>, op_loc: Option<Span>) {
3498 self.last_operation_was_abrupt = true;
3499
3500 let inst = self.create_instruction(Instruction::Yield);
3501 let elems = match expr {
3502 Some(expr) => {
3503 vec![Some(inst.as_arg()), Some(expr.as_arg())]
3504 }
3505 None => {
3506 vec![Some(inst.as_arg())]
3507 }
3508 };
3509 self.write_stmt(
3510 ReturnStmt {
3511 span: op_loc.unwrap_or(DUMMY_SP),
3512 arg: Some(
3513 ArrayLit {
3514 span: DUMMY_SP,
3515 elems,
3516 }
3517 .into(),
3518 ),
3519 }
3520 .into(),
3521 );
3522 }
3523
3524 fn write_yield_star(&mut self, expr: Box<Expr>, op_loc: Option<Span>) {
3529 self.last_operation_was_abrupt = true;
3530
3531 let arg1 = self.create_instruction(Instruction::YieldStar);
3532 self.write_stmt(
3533 ReturnStmt {
3534 span: op_loc.unwrap_or(DUMMY_SP),
3535 arg: Some(
3536 ArrayLit {
3537 span: DUMMY_SP,
3538 elems: vec![Some(arg1.as_arg()), Some(expr.as_arg())],
3539 }
3540 .into(),
3541 ),
3542 }
3543 .into(),
3544 )
3545 }
3546
3547 fn write_end_finally(&mut self) {
3549 self.last_operation_was_abrupt = true;
3550
3551 let arg = self.create_instruction(Instruction::Endfinally);
3552 self.write_stmt(
3553 ReturnStmt {
3554 span: DUMMY_SP,
3555 arg: Some(
3556 ArrayLit {
3557 span: DUMMY_SP,
3558 elems: vec![Some(arg.as_arg())],
3559 }
3560 .into(),
3561 ),
3562 }
3563 .into(),
3564 )
3565 }
3566
3567 fn hoist_variable_declaration(&mut self, id: &Ident) {
3568 self.hoisted_vars.push(VarDeclarator {
3569 span: DUMMY_SP,
3570 name: id.clone().into(),
3571 init: None,
3572 definite: Default::default(),
3573 })
3574 }
3575
3576 fn get_initialized_variables<'a>(
3577 &self,
3578 initializer: &'a mut VarDecl,
3579 ) -> Vec<&'a mut VarDeclarator> {
3580 initializer
3581 .decls
3582 .iter_mut()
3583 .filter(|v| v.init.is_some())
3584 .collect()
3585 }
3586
3587 fn create_temp_variable(&mut self) -> Ident {
3588 let i = private_ident!("_");
3589
3590 self.hoisted_vars.push(VarDeclarator {
3591 span: DUMMY_SP,
3592 name: i.clone().into(),
3593 init: None,
3594 definite: Default::default(),
3595 });
3596
3597 i
3598 }
3599
3600 fn create_call_binding(
3602 &mut self,
3603 expr: Box<Expr>,
3604 is_new_call: bool,
3605 ) -> (Box<Expr>, Box<Expr>) {
3606 let mut callee = expr;
3607
3608 match &mut *callee {
3609 Expr::Ident(..) => (
3610 callee.clone(),
3611 if is_new_call {
3612 callee
3613 } else {
3614 Expr::undefined(DUMMY_SP)
3615 },
3616 ),
3617
3618 Expr::Member(MemberExpr { obj, .. }) if !is_new_call => {
3619 if obj.is_ident() {
3620 let this_arg = obj.clone();
3621 return (callee, this_arg);
3622 }
3623
3624 let this_arg = self.create_temp_variable();
3625 *obj = Box::new(obj.take().make_assign_to(op!("="), this_arg.clone().into()));
3626
3627 (callee, this_arg.into())
3628 }
3629
3630 _ => {
3631 if !is_new_call {
3632 (callee, Expr::undefined(DUMMY_SP))
3633 } else {
3634 let this_arg = self.create_temp_variable();
3635 let target = callee.make_assign_to(op!("="), this_arg.clone().into());
3636 (Box::new(target), this_arg.into())
3637 }
3638 }
3639 }
3640 }
3641}
3642
3643fn contains_yield<N>(node: &N) -> bool
3644where
3645 N: VisitWith<YieldFinder>,
3646{
3647 let mut v = YieldFinder { found: false };
3648 node.visit_with(&mut v);
3649 v.found
3650}
3651
3652struct YieldFinder {
3653 found: bool,
3654}
3655
3656impl Visit for YieldFinder {
3657 noop_visit_type!(fail);
3658
3659 fn visit_yield_expr(&mut self, _: &YieldExpr) {
3660 self.found = true;
3661 }
3662
3663 fn visit_arrow_expr(&mut self, f: &ArrowExpr) {
3664 f.params.visit_with(self);
3665 }
3666
3667 fn visit_function(&mut self, f: &Function) {
3668 f.decorators.visit_with(self);
3669 f.params.visit_with(self);
3670 }
3671}
3672
3673#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3674pub(super) struct Loc {
3675 pos: BytePos,
3676 value: i32,
3677}
3678
3679struct InvalidToLit<'a> {
3681 map: Option<&'a [Vec<Loc>]>,
3683}
3684
3685impl VisitMut for InvalidToLit<'_> {
3686 noop_visit_mut_type!(fail);
3687
3688 fn visit_mut_expr(&mut self, e: &mut Expr) {
3689 e.visit_mut_children_with(self);
3690
3691 if let Expr::Invalid(Invalid { span }) = e {
3692 if span.lo != BytePos(0) && span.lo == span.hi {
3693 if let Some(Loc { value, .. }) = self
3694 .map
3695 .iter()
3696 .flat_map(|v| v.iter())
3697 .flatten()
3698 .find(|loc| loc.pos == span.lo)
3699 {
3700 *e = (*value as usize).into();
3701 }
3702 }
3703 }
3704 }
3705
3706 fn visit_mut_seq_expr(&mut self, e: &mut SeqExpr) {
3707 e.visit_mut_children_with(self);
3708
3709 e.exprs.retain(|e| !e.is_invalid());
3710 }
3711
3712 fn visit_mut_opt_expr_or_spread(&mut self, e: &mut Option<ExprOrSpread>) {
3713 e.visit_mut_children_with(self);
3714
3715 if let Some(arg) = e {
3716 if arg.expr.is_invalid() {
3717 *e = None;
3718 }
3719 }
3720 }
3721}