• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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