1 /**
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "destructuring.h"
17
18 #include <compiler/base/lreference.h>
19 #include <compiler/core/pandagen.h>
20 #include <ir/base/property.h>
21 #include <ir/base/spreadElement.h>
22 #include <ir/expressions/arrayExpression.h>
23 #include <ir/expressions/assignmentExpression.h>
24 #include <ir/expressions/identifier.h>
25 #include <ir/expressions/objectExpression.h>
26
27 namespace panda::es2panda::compiler {
28
GenRestElement(PandaGen * pg,const ir::SpreadElement * restElement,const DestructuringIterator & destIterator,bool isDeclaration)29 static void GenRestElement(PandaGen *pg, const ir::SpreadElement *restElement,
30 const DestructuringIterator &destIterator, bool isDeclaration)
31 {
32 VReg array = pg->AllocReg();
33 VReg index = pg->AllocReg();
34
35 auto *next = pg->AllocLabel();
36 auto *done = pg->AllocLabel();
37
38 DestructuringRestIterator iterator(destIterator);
39
40 // create left reference for rest element
41 LReference lref = LReference::CreateLRef(pg, restElement, isDeclaration);
42
43 // create an empty array first
44 pg->CreateEmptyArray(restElement);
45 pg->StoreAccumulator(restElement, array);
46
47 // index = 0
48 pg->LoadAccumulatorInt(restElement, 0);
49 pg->StoreAccumulator(restElement, index);
50
51 pg->SetLabel(restElement, next);
52
53 iterator.Step(done);
54 pg->StoreObjByValue(restElement, array, index);
55
56 // index++
57 pg->LoadAccumulatorInt(restElement, 1);
58 pg->Binary(restElement, lexer::TokenType::PUNCTUATOR_PLUS, index);
59 pg->StoreAccumulator(restElement, index);
60
61 pg->Branch(restElement, next);
62
63 pg->SetLabel(restElement, done);
64 pg->LoadAccumulator(restElement, array);
65
66 lref.SetValue();
67 }
68
GenArray(PandaGen * pg,const ir::ArrayExpression * array)69 static void GenArray(PandaGen *pg, const ir::ArrayExpression *array)
70 {
71 DestructuringIterator iterator(pg, array);
72
73 if (array->Elements().empty()) {
74 iterator.Close(false);
75 return;
76 }
77
78 DestructuringIteratorContext dstrCtx(pg, iterator);
79
80 for (const auto *element : array->Elements()) {
81 RegScope ers(pg);
82
83 if (element->IsRestElement()) {
84 GenRestElement(pg, element->AsRestElement(), iterator, array->IsDeclaration());
85 break;
86 }
87
88 // if a hole exist, just let the iterator step ahead
89 if (element->IsOmittedExpression()) {
90 iterator.Step();
91 continue;
92 }
93
94 const ir::Expression *init = nullptr;
95 const ir::Expression *target = element;
96
97 if (element->IsAssignmentPattern() || element->IsAssignmentExpression()) {
98 auto *assignment = element->IsAssignmentPattern() ? element->AsAssignmentPattern() :
99 element->AsAssignmentExpression();
100 target = assignment->Left();
101 init = assignment->Right();
102 }
103
104 LReference lref = LReference::CreateLRef(pg, target, array->IsDeclaration());
105 iterator.Step();
106
107 if (init) {
108 auto *assingValue = pg->AllocLabel();
109 auto *defaultInit = pg->AllocLabel();
110 pg->BranchIfStrictUndefined(element, defaultInit);
111 pg->LoadAccumulator(element, iterator.Result());
112 pg->Branch(element, assingValue);
113
114 pg->SetLabel(element, defaultInit);
115 init->Compile(pg);
116 pg->SetLabel(element, assingValue);
117 }
118
119 lref.SetValue();
120 }
121 }
122
GenObjectProperty(PandaGen * pg,const ir::ObjectExpression * object,const ir::Expression * element,VReg value)123 static void GenObjectProperty(PandaGen *pg, const ir::ObjectExpression *object,
124 const ir::Expression *element, VReg value)
125 {
126 RegScope propScope(pg);
127
128 const ir::Property *propExpr = element->AsProperty();
129
130 const ir::Expression *init = nullptr;
131 const ir::Expression *key = propExpr->Key();
132 const ir::Expression *target = propExpr->Value();
133
134 if (target->IsAssignmentPattern() || target->IsAssignmentExpression()) {
135 auto *assignment = target->IsAssignmentPattern() ? target->AsAssignmentPattern() :
136 target->AsAssignmentExpression();
137 init = assignment->Right();
138 target = assignment->Left();
139 }
140
141 LReference lref = LReference::CreateLRef(pg, target, object->IsDeclaration());
142
143 // load obj property from rhs, return undefined if no corresponding property exists
144 if (key->IsIdentifier() && !propExpr->IsComputed()) {
145 pg->LoadObjByName(element, value, key->AsIdentifier()->Name());
146 } else {
147 key->Compile(pg);
148 pg->LoadObjByValue(element, value);
149 }
150
151 if (init != nullptr) {
152 VReg loadedValue = pg->AllocReg();
153 pg->StoreAccumulator(element, loadedValue);
154 auto *getDefault = pg->AllocLabel();
155 auto *store = pg->AllocLabel();
156
157 pg->BranchIfStrictUndefined(element, getDefault);
158 pg->LoadAccumulator(element, loadedValue);
159 pg->Branch(element, store);
160
161 // load default value
162 pg->SetLabel(element, getDefault);
163 init->Compile(pg);
164
165 pg->SetLabel(element, store);
166 }
167
168 lref.SetValue();
169 }
170
GenObjectWithRest(PandaGen * pg,const ir::ObjectExpression * object,VReg rhs)171 static void GenObjectWithRest(PandaGen *pg, const ir::ObjectExpression *object, VReg rhs)
172 {
173 const auto &properties = object->Properties();
174
175 RegScope rs(pg);
176
177 if (properties.size() == 1) {
178 auto *element = properties[0];
179 ASSERT(element->IsRestElement());
180 VReg defaultProp = pg->AllocReg();
181 LReference lref = LReference::CreateLRef(pg, element, object->IsDeclaration());
182 pg->CreateObjectWithExcludedKeys(element, rhs, defaultProp, 0);
183 lref.SetValue();
184 return;
185 }
186
187 VReg propStart = pg->NextReg();
188
189 for (const auto *element : properties) {
190 if (element->IsRestElement()) {
191 RegScope restScope(pg);
192 LReference lref = LReference::CreateLRef(pg, element, object->IsDeclaration());
193 pg->CreateObjectWithExcludedKeys(element, rhs, propStart, properties.size() - 1);
194 lref.SetValue();
195 break;
196 }
197
198 VReg propName = pg->AllocReg();
199 const ir::Expression *key = element->AsProperty()->Key();
200 if (key->IsIdentifier()) {
201 pg->LoadAccumulatorString(key, key->AsIdentifier()->Name());
202 } else {
203 key->Compile(pg);
204 }
205 pg->StoreAccumulator(element, propName);
206
207 GenObjectProperty(pg, object, element, rhs);
208 }
209 }
210
GenObject(PandaGen * pg,const ir::ObjectExpression * object,VReg rhs)211 static void GenObject(PandaGen *pg, const ir::ObjectExpression *object, VReg rhs)
212 {
213 const auto &properties = object->Properties();
214
215 if (properties.empty() || properties.back()->IsRestElement()) {
216 auto *notNullish = pg->AllocLabel();
217 auto *nullish = pg->AllocLabel();
218
219 pg->LoadConst(object, Constant::JS_NULL);
220 pg->Condition(object, lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL, rhs, nullish);
221 pg->LoadConst(object, Constant::JS_UNDEFINED);
222 pg->Condition(object, lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL, rhs, nullish);
223 pg->Branch(object, notNullish);
224
225 pg->SetLabel(object, nullish);
226 pg->ThrowObjectNonCoercible(object);
227
228 pg->SetLabel(object, notNullish);
229
230 if (!properties.empty()) {
231 return GenObjectWithRest(pg, object, rhs);
232 }
233 }
234
235 for (const auto *element : properties) {
236 GenObjectProperty(pg, object, element, rhs);
237 }
238 }
239
Compile(PandaGen * pg,const ir::Expression * pattern)240 void Destructuring::Compile(PandaGen *pg, const ir::Expression *pattern)
241 {
242 RegScope rs(pg);
243
244 VReg rhs = pg->AllocReg();
245 pg->StoreAccumulator(pattern, rhs);
246
247 if (pattern->IsArrayPattern() || pattern->IsArrayExpression()) {
248 auto *arrExpr = pattern->IsArrayPattern() ? pattern->AsArrayPattern() :
249 pattern->AsArrayExpression();
250 GenArray(pg, arrExpr);
251 } else {
252 auto *objExpr = pattern->IsObjectPattern() ? pattern->AsObjectPattern() :
253 pattern->AsObjectExpression();
254 GenObject(pg, objExpr, rhs);
255 }
256
257 pg->LoadAccumulator(pattern, rhs);
258 }
259
260 } // namespace panda::es2panda::compiler
261