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