swc_ecma_compiler/es2021/
logical_assignments.rs

1use 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    /// Memorize computed property name for logical assignments
9    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    /// Transform logical assignment operators (&&=, ||=, ??=) to binary
40    /// expressions
41    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                        // TODO: local vars
79                        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}