1 /**
2 * Copyright (c) 2021 - 2023 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 panda::es2panda::ir {
Property(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
34 // NOLINTNEXTLINE(google-default-arguments)
Clone(ArenaAllocator * const allocator,AstNode * const parent)35 Property *Property::Clone(ArenaAllocator *const allocator, AstNode *const parent)
36 {
37 auto *const key = key_ != nullptr ? key_->Clone(allocator)->AsExpression() : nullptr;
38 auto *const value = value_ != nullptr ? value_->Clone(allocator)->AsExpression() : nullptr;
39
40 if (auto *const clone = allocator->New<Property>(Tag {}, *this, key, value); clone != nullptr) {
41 if (key != nullptr) {
42 key->SetParent(clone);
43 }
44 if (value != nullptr) {
45 value->SetParent(clone);
46 }
47 if (parent != nullptr) {
48 clone->SetParent(parent);
49 }
50 return clone;
51 }
52
53 throw Error(ErrorType::GENERIC, "", CLONE_ALLOCATION_ERROR);
54 }
55
ConvertibleToPatternProperty()56 bool Property::ConvertibleToPatternProperty()
57 {
58 // Object pattern can't contain getter or setter
59 if (IsAccessor() || isMethod_) {
60 return false;
61 }
62
63 switch (value_->Type()) {
64 case AstNodeType::OBJECT_EXPRESSION: {
65 return value_->AsObjectExpression()->ConvertibleToObjectPattern();
66 }
67 case AstNodeType::ARRAY_EXPRESSION: {
68 return value_->AsArrayExpression()->ConvertibleToArrayPattern();
69 }
70 case AstNodeType::ASSIGNMENT_EXPRESSION: {
71 return value_->AsAssignmentExpression()->ConvertibleToAssignmentPattern();
72 }
73 case AstNodeType::IDENTIFIER:
74 case AstNodeType::MEMBER_EXPRESSION:
75 case AstNodeType::ARRAY_PATTERN:
76 case AstNodeType::OBJECT_PATTERN:
77 case AstNodeType::ASSIGNMENT_PATTERN: {
78 break;
79 }
80 default: {
81 if (isShorthand_) {
82 break;
83 }
84
85 return false;
86 }
87 }
88
89 return true;
90 }
91
ValidateExpression()92 ValidationInfo Property::ValidateExpression()
93 {
94 ValidationInfo info;
95
96 if (!IsComputed() && !IsMethod() && !IsAccessor() && !IsShorthand()) {
97 bool currentIsProto = false;
98
99 if (key_->IsIdentifier()) {
100 currentIsProto = key_->AsIdentifier()->Name().Is("__proto__");
101 } else if (key_->IsStringLiteral()) {
102 currentIsProto = key_->AsStringLiteral()->Str().Is("__proto__");
103 }
104
105 if (currentIsProto) {
106 kind_ = PropertyKind::PROTO;
107 }
108 }
109
110 if (value_ != nullptr) {
111 if (value_->IsAssignmentPattern()) {
112 return {"Invalid shorthand property initializer.", value_->Start()};
113 }
114
115 if (value_->IsObjectExpression()) {
116 info = value_->AsObjectExpression()->ValidateExpression();
117 } else if (value_->IsArrayExpression()) {
118 info = value_->AsArrayExpression()->ValidateExpression();
119 }
120 }
121
122 return info;
123 }
124
TransformChildren(const NodeTransformer & cb)125 void Property::TransformChildren(const NodeTransformer &cb)
126 {
127 key_ = cb(key_)->AsExpression();
128 value_ = cb(value_)->AsExpression();
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 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 dumper->Add("Property");
185 }
186
Check(checker::TSChecker * checker)187 checker::Type *Property::Check(checker::TSChecker *checker)
188 {
189 return checker->GetAnalyzer()->Check(this);
190 }
191
Check(checker::ETSChecker * checker)192 checker::Type *Property::Check(checker::ETSChecker *checker)
193 {
194 return checker->GetAnalyzer()->Check(this);
195 }
196 } // namespace panda::es2panda::ir
197