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