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