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 "lreference.h"
17
18#include <binder/declaration.h>
19#include <compiler/base/destructuring.h>
20#include <compiler/core/pandagen.h>
21#include <ir/base/classDefinition.h>
22#include <ir/base/spreadElement.h>
23#include <ir/expressions/assignmentExpression.h>
24#include <ir/expressions/identifier.h>
25#include <ir/expressions/memberExpression.h>
26#include <ir/statements/variableDeclaration.h>
27#include <ir/statements/variableDeclarator.h>
28#include <ir/ts/tsAsExpression.h>
29#include <ir/ts/tsSatisfiesExpression.h>
30#include <ir/ts/tsTypeAssertion.h>
31#include <ir/ts/tsNonNullExpression.h>
32
33namespace panda::es2panda::compiler {
34
35// LReference
36
37LReference::LReference(const ir::AstNode *node, PandaGen *pg, bool isDeclaration, ReferenceKind refKind,
38                       binder::ScopeFindResult res)
39    : node_(node), pg_(pg), refKind_(refKind), res_(res), isDeclaration_(isDeclaration)
40{
41    if (refKind == ReferenceKind::MEMBER) {
42        obj_ = pg_->AllocReg();
43
44        node_->AsMemberExpression()->CompileObject(pg_, obj_);
45        if (!node_->AsMemberExpression()->AccessPrivateProperty()) {
46            prop_ = node->AsMemberExpression()->CompileKey(pg_);
47        }
48    }
49}
50
51void LReference::GetValue()
52{
53    switch (refKind_) {
54        case ReferenceKind::VAR_OR_GLOBAL: {
55            pg_->LoadVar(node_->AsIdentifier(), res_);
56            break;
57        }
58        case ReferenceKind::MEMBER: {
59            if (node_->AsMemberExpression()->AccessPrivateProperty()) {
60                auto name = node_->AsMemberExpression()->Property()->AsPrivateIdentifier()->Name();
61                auto result = pg_->Scope()->FindPrivateName(name);
62                if (!result.result.isMethod) {
63                    pg_->LoadAccumulator(node_, obj_);
64                    pg_->LoadPrivateProperty(node_, result.lexLevel, result.result.slot);
65                    break;
66                }
67
68                if (result.result.isStatic) {
69                    pg_->LoadLexicalVar(node_, result.lexLevel, result.result.validateMethodSlot);
70                    pg_->Equal(node_, obj_);
71                    pg_->ThrowTypeErrorIfFalse(node_, "Object does not have private property");
72                } else {
73                    pg_->LoadAccumulator(node_, obj_);
74                    pg_->LoadPrivateProperty(node_, result.lexLevel, result.result.validateMethodSlot);
75                }
76                if (result.result.isSetter) {
77                    pg_->ThrowTypeError(node_, "Property is not defined with Getter");
78                }
79                if (result.result.isGetter) {
80                    pg_->LoadAccumulator(node_, obj_);
81                    pg_->LoadPrivateProperty(node_, result.lexLevel, result.result.slot);
82                    break;
83                }
84                pg_->LoadLexicalVar(node_, result.lexLevel, result.result.slot);
85            } else {
86                pg_->LoadObjProperty(node_, obj_, prop_);
87            }
88            break;
89        }
90        default: {
91            UNREACHABLE();
92        }
93    }
94}
95
96void LReference::SetValue()
97{
98    switch (refKind_) {
99        case ReferenceKind::VAR_OR_GLOBAL: {
100            pg_->StoreVar(node_, res_, isDeclaration_);
101            break;
102        }
103        case ReferenceKind::MEMBER: {
104            if (node_->AsMemberExpression()->Object()->IsSuperExpression()) {
105                pg_->StoreSuperProperty(node_, obj_, prop_);
106            } else if (node_->AsMemberExpression()->AccessPrivateProperty()) {
107                compiler::RegScope rs(pg_);
108                VReg valueReg =  pg_->AllocReg();
109
110                auto name = node_->AsMemberExpression()->Property()->AsPrivateIdentifier()->Name();
111                auto result = pg_->Scope()->FindPrivateName(name, true);
112                if (!result.result.isMethod) {
113                    pg_->StorePrivateProperty(node_, result.lexLevel, result.result.slot, obj_);
114                    break;
115                }
116                if (!result.result.isSetter) {
117                    pg_->ThrowTypeError(node_, "Method is not writable");
118                }
119                // store value
120                pg_->StoreAccumulator(node_, valueReg);
121
122                if (result.result.isStatic) {
123                    pg_->LoadLexicalVar(node_, result.lexLevel, result.result.validateMethodSlot);
124                    pg_->Equal(node_, obj_);
125                    pg_->ThrowTypeErrorIfFalse(node_, "Object does not have private property");
126                } else {
127                    pg_->LoadAccumulator(node_, obj_);
128                    pg_->LoadPrivateProperty(node_, result.lexLevel, result.result.validateMethodSlot);
129                }
130                pg_->LoadAccumulator(node_, valueReg);
131                pg_->StorePrivateProperty(node_, result.lexLevel, result.result.slot, obj_);
132            } else {
133                pg_->StoreObjProperty(node_, obj_, prop_);
134            }
135
136            break;
137        }
138        case ReferenceKind::DESTRUCTURING: {
139            Destructuring::Compile(pg_, node_->AsExpression());
140            break;
141        }
142        default: {
143            UNREACHABLE();
144        }
145    }
146}
147
148ReferenceKind LReference::Kind() const
149{
150    return refKind_;
151}
152
153binder::Variable *LReference::Variable() const
154{
155    return res_.variable;
156}
157
158LReference LReference::CreateLRef(PandaGen *pg, const ir::AstNode *node, bool isDeclaration)
159{
160    switch (node->Type()) {
161        case ir::AstNodeType::IDENTIFIER: {
162            const util::StringView &name = node->AsIdentifier()->Name();
163            binder::ScopeFindResult res = pg->Scope()->Find(name);
164
165            return {node, pg, isDeclaration, ReferenceKind::VAR_OR_GLOBAL, res};
166        }
167        case ir::AstNodeType::MEMBER_EXPRESSION: {
168            return {node, pg, false, ReferenceKind::MEMBER, {}};
169        }
170        case ir::AstNodeType::VARIABLE_DECLARATION: {
171            ASSERT(node->AsVariableDeclaration()->Declarators().size() == 1);
172            return LReference::CreateLRef(pg, node->AsVariableDeclaration()->Declarators()[0]->Id(), true);
173        }
174        case ir::AstNodeType::VARIABLE_DECLARATOR: {
175            return LReference::CreateLRef(pg, node->AsVariableDeclarator()->Id(), true);
176        }
177        case ir::AstNodeType::ARRAY_PATTERN:
178        case ir::AstNodeType::OBJECT_PATTERN:
179        case ir::AstNodeType::ARRAY_EXPRESSION:
180        case ir::AstNodeType::OBJECT_EXPRESSION: {
181            return {node, pg, isDeclaration, ReferenceKind::DESTRUCTURING, {}};
182        }
183        case ir::AstNodeType::ASSIGNMENT_PATTERN: {
184            return LReference::CreateLRef(pg, node->AsAssignmentPattern()->Left(), true);
185        }
186        case ir::AstNodeType::REST_ELEMENT: {
187            return LReference::CreateLRef(pg, node->AsRestElement()->Argument(), isDeclaration);
188        }
189        case ir::AstNodeType::EXPORT_DEFAULT_DECLARATION: {
190            // export default [anonymous class decl]
191            util::StringView name = parser::SourceTextModuleRecord::DEFAULT_LOCAL_NAME;
192            binder::ScopeFindResult res = pg->Scope()->Find(name);
193
194            return {node, pg, isDeclaration, ReferenceKind::VAR_OR_GLOBAL, res};
195        }
196        case ir::AstNodeType::TS_AS_EXPRESSION: {
197            return LReference::CreateLRef(pg, node->AsTSAsExpression()->Expr(), isDeclaration);
198        }
199        case ir::AstNodeType::TS_SATISFIES_EXPRESSION: {
200            return LReference::CreateLRef(pg, node->AsTSSatisfiesExpression()->Expr(), isDeclaration);
201        }
202        case ir::AstNodeType::TS_TYPE_ASSERTION: {
203            return LReference::CreateLRef(pg, node->AsTSTypeAssertion()->GetExpression(), isDeclaration);
204        }
205        case ir::AstNodeType::TS_NON_NULL_EXPRESSION: {
206            return LReference::CreateLRef(pg, node->AsTSNonNullExpression()->Expr(), isDeclaration);
207        }
208        default: {
209            UNREACHABLE();
210        }
211    }
212}
213
214}  // namespace panda::es2panda::compiler
215