swc_ecma_compiler/es2021/
logical_assignments.rs1use swc_common::{util::take::Take, DUMMY_SP};
2use swc_ecma_ast::*;
3use swc_ecma_utils::alias_ident_for;
4
5use crate::CompilerImpl;
6
7impl<'a> CompilerImpl<'a> {
8 pub(super) fn memorize_prop_for_logical_assignment(
10 &mut self,
11 c: ComputedPropName,
12 ) -> (ComputedPropName, ComputedPropName) {
13 let alias = alias_ident_for(&c.expr, "_ref");
14 self.es2021_logical_assignment_vars.push(VarDeclarator {
15 span: DUMMY_SP,
16 name: alias.clone().into(),
17 init: None,
18 definite: false,
19 });
20
21 (
22 ComputedPropName {
23 span: c.span,
24 expr: AssignExpr {
25 span: DUMMY_SP,
26 left: alias.clone().into(),
27 op: op!("="),
28 right: c.expr,
29 }
30 .into(),
31 },
32 ComputedPropName {
33 span: c.span,
34 expr: Box::new(alias.into()),
35 },
36 )
37 }
38
39 pub(crate) fn transform_logical_assignment(&mut self, e: &mut Expr) -> bool {
42 if let Expr::Assign(AssignExpr {
43 span,
44 op: op @ (op!("&&=") | op!("||=") | op!("??=")),
45 left: AssignTarget::Simple(left),
46 right,
47 }) = e
48 {
49 let (left_expr, r_assign_target) = match &mut *left {
50 SimpleAssignTarget::SuperProp(SuperPropExpr {
51 span,
52 obj,
53 prop: SuperProp::Computed(c),
54 }) => {
55 let (left, right) = self.memorize_prop_for_logical_assignment(c.take());
56
57 (
58 Box::new(
59 SuperPropExpr {
60 span: *span,
61 obj: *obj,
62 prop: SuperProp::Computed(left),
63 }
64 .into(),
65 ),
66 Box::new(
67 SuperPropExpr {
68 span: *span,
69 obj: *obj,
70 prop: SuperProp::Computed(right),
71 }
72 .into(),
73 ),
74 )
75 }
76 SimpleAssignTarget::Member(m) => {
77 let (left_obj, right_obj) = match *m.obj.take() {
78 obj @ Expr::This(_) => (obj.clone().into(), obj.into()),
80 obj => {
81 let alias = alias_ident_for(&obj, "_ref");
82 self.es2021_logical_assignment_vars.push(VarDeclarator {
83 span: DUMMY_SP,
84 name: alias.clone().into(),
85 init: None,
86 definite: false,
87 });
88
89 (
90 AssignExpr {
91 span: DUMMY_SP,
92 op: op!("="),
93 left: alias.clone().into(),
94 right: obj.into(),
95 }
96 .into(),
97 alias.into(),
98 )
99 }
100 };
101
102 let (left_prop, right_prop) = match m.prop.take() {
103 MemberProp::Computed(c) => {
104 let (left, right) = self.memorize_prop_for_logical_assignment(c);
105 (left.into(), right.into())
106 }
107 prop => (prop.clone(), prop),
108 };
109
110 (
111 MemberExpr {
112 span: DUMMY_SP,
113 obj: left_obj,
114 prop: left_prop,
115 }
116 .into(),
117 MemberExpr {
118 span: DUMMY_SP,
119 obj: right_obj,
120 prop: right_prop,
121 }
122 .into(),
123 )
124 }
125 _ => {
126 let expr: Box<Expr> = left.take().into();
127 (expr.clone(), expr)
128 }
129 };
130
131 let right = AssignExpr {
132 span: DUMMY_SP,
133 op: op!("="),
134 left: r_assign_target.try_into().unwrap(),
135 right: right.take(),
136 }
137 .into();
138
139 let op = match *op {
140 op!("??=") => op!("??"),
141 op!("&&=") => op!("&&"),
142 op!("||=") => op!("||"),
143 _ => unreachable!(),
144 };
145
146 *e = BinExpr {
147 span: *span,
148 op,
149 left: left_expr,
150 right,
151 }
152 .into();
153
154 return true;
155 }
156 false
157 }
158}