13af6ab5fSopenharmony_ci/** 23af6ab5fSopenharmony_ci * Copyright (c) 2023-2024 Huawei Device Co., Ltd. 33af6ab5fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 43af6ab5fSopenharmony_ci * you may not use this file except in compliance with the License. 53af6ab5fSopenharmony_ci * You may obtain a copy of the License at 63af6ab5fSopenharmony_ci * 73af6ab5fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 83af6ab5fSopenharmony_ci * 93af6ab5fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 103af6ab5fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 113af6ab5fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 123af6ab5fSopenharmony_ci * See the License for the specific language governing permissions and 133af6ab5fSopenharmony_ci * limitations under the License. 143af6ab5fSopenharmony_ci */ 153af6ab5fSopenharmony_ci 163af6ab5fSopenharmony_ci#include "interfacePropertyDeclarations.h" 173af6ab5fSopenharmony_ci 183af6ab5fSopenharmony_ci#include "checker/ETSchecker.h" 193af6ab5fSopenharmony_ci#include "checker/types/type.h" 203af6ab5fSopenharmony_ci#include "compiler/lowering/util.h" 213af6ab5fSopenharmony_ci#include "ir/astNode.h" 223af6ab5fSopenharmony_ci#include "ir/expression.h" 233af6ab5fSopenharmony_ci#include "ir/expressions/identifier.h" 243af6ab5fSopenharmony_ci#include "ir/opaqueTypeNode.h" 253af6ab5fSopenharmony_ci#include "ir/statements/blockStatement.h" 263af6ab5fSopenharmony_ci#include "ir/ts/tsInterfaceBody.h" 273af6ab5fSopenharmony_ci#include "ir/base/classProperty.h" 283af6ab5fSopenharmony_ci#include "ir/ets/etsUnionType.h" 293af6ab5fSopenharmony_ci#include "ir/ets/etsNullishTypes.h" 303af6ab5fSopenharmony_ci 313af6ab5fSopenharmony_cinamespace ark::es2panda::compiler { 323af6ab5fSopenharmony_ci 333af6ab5fSopenharmony_cinamespace { 343af6ab5fSopenharmony_ci 353af6ab5fSopenharmony_civoid TransformOptionalFieldTypeAnnotation(checker::ETSChecker *const checker, ir::ClassProperty *const field) 363af6ab5fSopenharmony_ci{ 373af6ab5fSopenharmony_ci if (!field->IsOptionalDeclaration()) { 383af6ab5fSopenharmony_ci return; 393af6ab5fSopenharmony_ci } 403af6ab5fSopenharmony_ci 413af6ab5fSopenharmony_ci if (field->IsETSUnionType()) { 423af6ab5fSopenharmony_ci bool alreadyHasUndefined = false; 433af6ab5fSopenharmony_ci auto unionTypes = field->AsETSUnionType()->Types(); 443af6ab5fSopenharmony_ci for (const auto &type : unionTypes) { 453af6ab5fSopenharmony_ci if (type->IsETSUndefinedType()) { 463af6ab5fSopenharmony_ci alreadyHasUndefined = true; 473af6ab5fSopenharmony_ci break; 483af6ab5fSopenharmony_ci } 493af6ab5fSopenharmony_ci } 503af6ab5fSopenharmony_ci if (!alreadyHasUndefined) { 513af6ab5fSopenharmony_ci ArenaVector<ir::TypeNode *> types(field->AsETSUnionType()->Types(), checker->Allocator()->Adapter()); 523af6ab5fSopenharmony_ci types.push_back(checker->AllocNode<ir::ETSUndefinedType>()); 533af6ab5fSopenharmony_ci auto *const unionType = checker->AllocNode<ir::ETSUnionType>(std::move(types)); 543af6ab5fSopenharmony_ci field->SetTypeAnnotation(unionType); 553af6ab5fSopenharmony_ci } 563af6ab5fSopenharmony_ci } else { 573af6ab5fSopenharmony_ci ArenaVector<ir::TypeNode *> types(checker->Allocator()->Adapter()); 583af6ab5fSopenharmony_ci types.push_back(field->TypeAnnotation()); 593af6ab5fSopenharmony_ci types.push_back(checker->AllocNode<ir::ETSUndefinedType>()); 603af6ab5fSopenharmony_ci auto *const unionType = checker->AllocNode<ir::ETSUnionType>(std::move(types)); 613af6ab5fSopenharmony_ci field->SetTypeAnnotation(unionType); 623af6ab5fSopenharmony_ci } 633af6ab5fSopenharmony_ci field->ClearModifier(ir::ModifierFlags::OPTIONAL); 643af6ab5fSopenharmony_ci} 653af6ab5fSopenharmony_ci 663af6ab5fSopenharmony_ci} // namespace 673af6ab5fSopenharmony_ci 683af6ab5fSopenharmony_cistatic ir::MethodDefinition *GenerateGetterOrSetter(checker::ETSChecker *const checker, ir::ClassProperty *const field, 693af6ab5fSopenharmony_ci bool isSetter) 703af6ab5fSopenharmony_ci{ 713af6ab5fSopenharmony_ci auto classScope = NearestScope(field); 723af6ab5fSopenharmony_ci auto *paramScope = checker->Allocator()->New<varbinder::FunctionParamScope>(checker->Allocator(), classScope); 733af6ab5fSopenharmony_ci auto *functionScope = checker->Allocator()->New<varbinder::FunctionScope>(checker->Allocator(), paramScope); 743af6ab5fSopenharmony_ci 753af6ab5fSopenharmony_ci functionScope->BindParamScope(paramScope); 763af6ab5fSopenharmony_ci paramScope->BindFunctionScope(functionScope); 773af6ab5fSopenharmony_ci 783af6ab5fSopenharmony_ci auto flags = ir::ModifierFlags::PUBLIC; 793af6ab5fSopenharmony_ci flags |= ir::ModifierFlags::ABSTRACT; 803af6ab5fSopenharmony_ci 813af6ab5fSopenharmony_ci TransformOptionalFieldTypeAnnotation(checker, field); 823af6ab5fSopenharmony_ci ArenaVector<ir::Expression *> params(checker->Allocator()->Adapter()); 833af6ab5fSopenharmony_ci 843af6ab5fSopenharmony_ci if (isSetter) { 853af6ab5fSopenharmony_ci auto paramIdent = field->Key()->AsIdentifier()->Clone(checker->Allocator(), nullptr); 863af6ab5fSopenharmony_ci paramIdent->SetTsTypeAnnotation(field->TypeAnnotation()->Clone(checker->Allocator(), nullptr)); 873af6ab5fSopenharmony_ci paramIdent->TypeAnnotation()->SetParent(paramIdent); 883af6ab5fSopenharmony_ci 893af6ab5fSopenharmony_ci auto *const paramExpression = checker->AllocNode<ir::ETSParameterExpression>(paramIdent, nullptr); 903af6ab5fSopenharmony_ci paramExpression->SetRange(paramIdent->Range()); 913af6ab5fSopenharmony_ci auto *const paramVar = std::get<2>(paramScope->AddParamDecl(checker->Allocator(), paramExpression)); 923af6ab5fSopenharmony_ci 933af6ab5fSopenharmony_ci paramIdent->SetVariable(paramVar); 943af6ab5fSopenharmony_ci paramExpression->SetVariable(paramVar); 953af6ab5fSopenharmony_ci 963af6ab5fSopenharmony_ci params.push_back(paramExpression); 973af6ab5fSopenharmony_ci } 983af6ab5fSopenharmony_ci 993af6ab5fSopenharmony_ci auto signature = ir::FunctionSignature(nullptr, std::move(params), isSetter ? nullptr : field->TypeAnnotation()); 1003af6ab5fSopenharmony_ci 1013af6ab5fSopenharmony_ci auto *func = checker->AllocNode<ir::ScriptFunction>( 1023af6ab5fSopenharmony_ci checker->Allocator(), ir::ScriptFunction::ScriptFunctionData {nullptr, std::move(signature), 1033af6ab5fSopenharmony_ci isSetter ? ir::ScriptFunctionFlags::SETTER 1043af6ab5fSopenharmony_ci : ir::ScriptFunctionFlags::GETTER, 1053af6ab5fSopenharmony_ci flags, true}); 1063af6ab5fSopenharmony_ci 1073af6ab5fSopenharmony_ci func->SetRange(field->Range()); 1083af6ab5fSopenharmony_ci 1093af6ab5fSopenharmony_ci func->SetScope(functionScope); 1103af6ab5fSopenharmony_ci 1113af6ab5fSopenharmony_ci auto const &name = field->Key()->AsIdentifier()->Name(); 1123af6ab5fSopenharmony_ci auto methodIdent = checker->AllocNode<ir::Identifier>(name, checker->Allocator()); 1133af6ab5fSopenharmony_ci auto *decl = checker->Allocator()->New<varbinder::VarDecl>(name); 1143af6ab5fSopenharmony_ci auto var = functionScope->AddDecl(checker->Allocator(), decl, ScriptExtension::ETS); 1153af6ab5fSopenharmony_ci 1163af6ab5fSopenharmony_ci methodIdent->SetVariable(var); 1173af6ab5fSopenharmony_ci 1183af6ab5fSopenharmony_ci auto *funcExpr = checker->AllocNode<ir::FunctionExpression>(func); 1193af6ab5fSopenharmony_ci funcExpr->SetRange(func->Range()); 1203af6ab5fSopenharmony_ci func->AddFlag(ir::ScriptFunctionFlags::METHOD); 1213af6ab5fSopenharmony_ci 1223af6ab5fSopenharmony_ci auto *method = checker->AllocNode<ir::MethodDefinition>(ir::MethodDefinitionKind::METHOD, methodIdent, funcExpr, 1233af6ab5fSopenharmony_ci flags, checker->Allocator(), false); 1243af6ab5fSopenharmony_ci 1253af6ab5fSopenharmony_ci method->Id()->SetMutator(); 1263af6ab5fSopenharmony_ci method->SetRange(field->Range()); 1273af6ab5fSopenharmony_ci method->Function()->SetIdent(method->Id()->Clone(checker->Allocator(), nullptr)); 1283af6ab5fSopenharmony_ci method->Function()->AddModifier(method->Modifiers()); 1293af6ab5fSopenharmony_ci paramScope->BindNode(func); 1303af6ab5fSopenharmony_ci functionScope->BindNode(func); 1313af6ab5fSopenharmony_ci 1323af6ab5fSopenharmony_ci return method; 1333af6ab5fSopenharmony_ci} 1343af6ab5fSopenharmony_ci 1353af6ab5fSopenharmony_cistatic ir::Expression *UpdateInterfacePropertys(checker::ETSChecker *const checker, 1363af6ab5fSopenharmony_ci ir::TSInterfaceBody *const interface) 1373af6ab5fSopenharmony_ci{ 1383af6ab5fSopenharmony_ci if (interface->Body().empty()) { 1393af6ab5fSopenharmony_ci return interface; 1403af6ab5fSopenharmony_ci } 1413af6ab5fSopenharmony_ci 1423af6ab5fSopenharmony_ci auto propertyList = interface->Body(); 1433af6ab5fSopenharmony_ci ArenaVector<ir::AstNode *> newPropertyList(checker->Allocator()->Adapter()); 1443af6ab5fSopenharmony_ci 1453af6ab5fSopenharmony_ci auto scope = NearestScope(interface); 1463af6ab5fSopenharmony_ci ASSERT(scope->IsClassScope()); 1473af6ab5fSopenharmony_ci 1483af6ab5fSopenharmony_ci for (const auto &prop : propertyList) { 1493af6ab5fSopenharmony_ci if (!prop->IsClassProperty()) { 1503af6ab5fSopenharmony_ci newPropertyList.emplace_back(prop); 1513af6ab5fSopenharmony_ci continue; 1523af6ab5fSopenharmony_ci } 1533af6ab5fSopenharmony_ci auto getter = GenerateGetterOrSetter(checker, prop->AsClassProperty(), false); 1543af6ab5fSopenharmony_ci newPropertyList.emplace_back(getter); 1553af6ab5fSopenharmony_ci 1563af6ab5fSopenharmony_ci auto methodScope = scope->AsClassScope()->InstanceMethodScope(); 1573af6ab5fSopenharmony_ci auto name = getter->Key()->AsIdentifier()->Name(); 1583af6ab5fSopenharmony_ci 1593af6ab5fSopenharmony_ci auto *decl = checker->Allocator()->New<varbinder::FunctionDecl>(checker->Allocator(), name, getter); 1603af6ab5fSopenharmony_ci 1613af6ab5fSopenharmony_ci if (methodScope->AddDecl(checker->Allocator(), decl, ScriptExtension::ETS) == nullptr) { 1623af6ab5fSopenharmony_ci auto prevDecl = methodScope->FindDecl(name); 1633af6ab5fSopenharmony_ci ASSERT(prevDecl->IsFunctionDecl()); 1643af6ab5fSopenharmony_ci prevDecl->Node()->AsMethodDefinition()->AddOverload(getter); 1653af6ab5fSopenharmony_ci 1663af6ab5fSopenharmony_ci if (!prop->AsClassProperty()->IsReadonly()) { 1673af6ab5fSopenharmony_ci auto setter = GenerateGetterOrSetter(checker, prop->AsClassProperty(), true); 1683af6ab5fSopenharmony_ci newPropertyList.emplace_back(setter); 1693af6ab5fSopenharmony_ci prevDecl->Node()->AsMethodDefinition()->AddOverload(setter); 1703af6ab5fSopenharmony_ci } 1713af6ab5fSopenharmony_ci 1723af6ab5fSopenharmony_ci getter->Function()->Id()->SetVariable( 1733af6ab5fSopenharmony_ci methodScope->FindLocal(name, varbinder::ResolveBindingOptions::BINDINGS)); 1743af6ab5fSopenharmony_ci continue; 1753af6ab5fSopenharmony_ci } 1763af6ab5fSopenharmony_ci 1773af6ab5fSopenharmony_ci if (!prop->AsClassProperty()->IsReadonly()) { 1783af6ab5fSopenharmony_ci auto setter = GenerateGetterOrSetter(checker, prop->AsClassProperty(), true); 1793af6ab5fSopenharmony_ci newPropertyList.emplace_back(setter); 1803af6ab5fSopenharmony_ci getter->AddOverload(setter); 1813af6ab5fSopenharmony_ci } 1823af6ab5fSopenharmony_ci scope->AsClassScope()->InstanceFieldScope()->EraseBinding(name); 1833af6ab5fSopenharmony_ci } 1843af6ab5fSopenharmony_ci 1853af6ab5fSopenharmony_ci auto newInterface = checker->AllocNode<ir::TSInterfaceBody>(std::move(newPropertyList)); 1863af6ab5fSopenharmony_ci newInterface->SetRange(interface->Range()); 1873af6ab5fSopenharmony_ci newInterface->SetParent(interface->Parent()); 1883af6ab5fSopenharmony_ci 1893af6ab5fSopenharmony_ci return newInterface; 1903af6ab5fSopenharmony_ci} 1913af6ab5fSopenharmony_ci 1923af6ab5fSopenharmony_cibool InterfacePropertyDeclarationsPhase::Perform(public_lib::Context *ctx, parser::Program *program) 1933af6ab5fSopenharmony_ci{ 1943af6ab5fSopenharmony_ci for (const auto &[_, ext_programs] : program->ExternalSources()) { 1953af6ab5fSopenharmony_ci (void)_; 1963af6ab5fSopenharmony_ci for (auto *const extProg : ext_programs) { 1973af6ab5fSopenharmony_ci Perform(ctx, extProg); 1983af6ab5fSopenharmony_ci } 1993af6ab5fSopenharmony_ci } 2003af6ab5fSopenharmony_ci 2013af6ab5fSopenharmony_ci checker::ETSChecker *const checker = ctx->checker->AsETSChecker(); 2023af6ab5fSopenharmony_ci 2033af6ab5fSopenharmony_ci program->Ast()->TransformChildrenRecursively( 2043af6ab5fSopenharmony_ci [checker](ir::AstNode *const ast) -> ir::AstNode * { 2053af6ab5fSopenharmony_ci return ast->IsTSInterfaceBody() ? UpdateInterfacePropertys(checker, ast->AsTSInterfaceBody()) : ast; 2063af6ab5fSopenharmony_ci }, 2073af6ab5fSopenharmony_ci Name()); 2083af6ab5fSopenharmony_ci 2093af6ab5fSopenharmony_ci return true; 2103af6ab5fSopenharmony_ci} 2113af6ab5fSopenharmony_ci 2123af6ab5fSopenharmony_ci} // namespace ark::es2panda::compiler 213