• 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 <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