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 25namespace ark::es2panda::ir { 26Property::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 34Property *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 55bool 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 91ValidationInfo 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 124void 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 137void Property::Iterate(const NodeTraverser &cb) const 138{ 139 cb(key_); 140 cb(value_); 141} 142 143void 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 178void Property::Compile(compiler::PandaGen *pg) const 179{ 180 pg->GetAstCompiler()->Compile(this); 181} 182 183void Property::Compile(compiler::ETSGen *etsg) const 184{ 185 etsg->GetAstCompiler()->Compile(this); 186} 187 188void 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 197checker::Type *Property::Check(checker::TSChecker *checker) 198{ 199 return checker->GetAnalyzer()->Check(this); 200} 201 202checker::Type *Property::Check(checker::ETSChecker *checker) 203{ 204 return checker->GetAnalyzer()->Check(this); 205} 206} // namespace ark::es2panda::ir 207