1 /**
2  * Copyright (c) 2021-2024 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 "property.h"
17 
18 #include "es2panda.h"
19 #include "checker/TSchecker.h"
20 #include "compiler/core/ETSGen.h"
21 #include "compiler/core/pandagen.h"
22 #include "ir/astDump.h"
23 #include "ir/srcDump.h"
24 
25 namespace ark::es2panda::ir {
Property([[maybe_unused]] Tag const tag, Property const &other, Expression *const key, Expression *const value)26 Property::Property([[maybe_unused]] Tag const tag, Property const &other, Expression *const key,
27                    Expression *const value)
28     : Property(other)
29 {
30     key_ = key;
31     value_ = value;
32 }
33 
Clone(ArenaAllocator *const allocator, AstNode *const parent)34 Property *Property::Clone(ArenaAllocator *const allocator, AstNode *const parent)
35 {
36     auto *const key = key_ != nullptr ? key_->Clone(allocator, nullptr)->AsExpression() : nullptr;
37     auto *const value = value_ != nullptr ? value_->Clone(allocator, nullptr)->AsExpression() : nullptr;
38 
39     if (auto *const clone = allocator->New<Property>(Tag {}, *this, key, value); clone != nullptr) {
40         if (key != nullptr) {
41             key->SetParent(clone);
42         }
43         if (value != nullptr) {
44             value->SetParent(clone);
45         }
46         if (parent != nullptr) {
47             clone->SetParent(parent);
48         }
49         return clone;
50     }
51 
52     throw Error(ErrorType::GENERIC, "", CLONE_ALLOCATION_ERROR);
53 }
54 
ConvertibleToPatternProperty()55 bool Property::ConvertibleToPatternProperty()
56 {
57     // Object pattern can't contain getter or setter
58     if (IsAccessor() || isMethod_) {
59         return false;
60     }
61 
62     switch (value_->Type()) {
63         case AstNodeType::OBJECT_EXPRESSION: {
64             return value_->AsObjectExpression()->ConvertibleToObjectPattern();
65         }
66         case AstNodeType::ARRAY_EXPRESSION: {
67             return value_->AsArrayExpression()->ConvertibleToArrayPattern();
68         }
69         case AstNodeType::ASSIGNMENT_EXPRESSION: {
70             return value_->AsAssignmentExpression()->ConvertibleToAssignmentPattern();
71         }
72         case AstNodeType::IDENTIFIER:
73         case AstNodeType::MEMBER_EXPRESSION:
74         case AstNodeType::ARRAY_PATTERN:
75         case AstNodeType::OBJECT_PATTERN:
76         case AstNodeType::ASSIGNMENT_PATTERN: {
77             break;
78         }
79         default: {
80             if (isShorthand_) {
81                 break;
82             }
83 
84             return false;
85         }
86     }
87 
88     return true;
89 }
90 
ValidateExpression()91 ValidationInfo Property::ValidateExpression()
92 {
93     ValidationInfo info;
94 
95     if (!IsComputed() && !IsMethod() && !IsAccessor() && !IsShorthand()) {
96         bool currentIsProto = false;
97 
98         if (key_->IsIdentifier()) {
99             currentIsProto = key_->AsIdentifier()->Name().Is("__proto__");
100         } else if (key_->IsStringLiteral()) {
101             currentIsProto = key_->AsStringLiteral()->Str().Is("__proto__");
102         }
103 
104         if (currentIsProto) {
105             kind_ = PropertyKind::PROTO;
106         }
107     }
108 
109     if (value_ != nullptr) {
110         if (value_->IsAssignmentPattern()) {
111             return {"Invalid shorthand property initializer.", value_->Start()};
112         }
113 
114         if (value_->IsObjectExpression()) {
115             info = value_->AsObjectExpression()->ValidateExpression();
116         } else if (value_->IsArrayExpression()) {
117             info = value_->AsArrayExpression()->ValidateExpression();
118         }
119     }
120 
121     return info;
122 }
123 
TransformChildren(const NodeTransformer &cb, std::string_view transformationName)124 void Property::TransformChildren(const NodeTransformer &cb, std::string_view transformationName)
125 {
126     if (auto *transformedNode = cb(key_); key_ != transformedNode) {
127         key_->SetTransformedNode(transformationName, transformedNode);
128         key_ = transformedNode->AsExpression();
129     }
130 
131     if (auto *transformedNode = cb(value_); value_ != transformedNode) {
132         value_->SetTransformedNode(transformationName, transformedNode);
133         value_ = transformedNode->AsExpression();
134     }
135 }
136 
Iterate(const NodeTraverser &cb) const137 void Property::Iterate(const NodeTraverser &cb) const
138 {
139     cb(key_);
140     cb(value_);
141 }
142 
Dump(ir::AstDumper *dumper) const143 void Property::Dump(ir::AstDumper *dumper) const
144 {
145     const char *kind = nullptr;
146 
147     switch (kind_) {
148         case PropertyKind::INIT: {
149             kind = "init";
150             break;
151         }
152         case PropertyKind::PROTO: {
153             kind = "proto";
154             break;
155         }
156         case PropertyKind::GET: {
157             kind = "get";
158             break;
159         }
160         case PropertyKind::SET: {
161             kind = "set";
162             break;
163         }
164         default: {
165             UNREACHABLE();
166         }
167     }
168 
169     dumper->Add({{"type", "Property"},
170                  {"method", isMethod_},
171                  {"shorthand", isShorthand_},
172                  {"computed", isComputed_},
173                  {"key", key_},
174                  {"value", value_},
175                  {"kind", kind}});
176 }
177 
Compile(compiler::PandaGen *pg) const178 void Property::Compile(compiler::PandaGen *pg) const
179 {
180     pg->GetAstCompiler()->Compile(this);
181 }
182 
Compile(compiler::ETSGen *etsg) const183 void Property::Compile(compiler::ETSGen *etsg) const
184 {
185     etsg->GetAstCompiler()->Compile(this);
186 }
187 
Dump(ir::SrcDumper *dumper) const188 void Property::Dump(ir::SrcDumper *dumper) const
189 {
190     if (kind_ == PropertyKind::INIT) {
191         key_->Dump(dumper);
192         dumper->Add(": ");
193         value_->Dump(dumper);
194     }
195 }
196 
Check(checker::TSChecker *checker)197 checker::Type *Property::Check(checker::TSChecker *checker)
198 {
199     return checker->GetAnalyzer()->Check(this);
200 }
201 
Check(checker::ETSChecker *checker)202 checker::Type *Property::Check(checker::ETSChecker *checker)
203 {
204     return checker->GetAnalyzer()->Check(this);
205 }
206 }  // namespace ark::es2panda::ir
207