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 "ETSfunction.h" 17 18#include "varbinder/varbinder.h" 19#include "varbinder/ETSBinder.h" 20#include "util/helpers.h" 21#include "varbinder/scope.h" 22#include "varbinder/variable.h" 23#include "compiler/base/lreference.h" 24#include "compiler/core/ETSGen.h" 25#include "compiler/core/envScope.h" 26#include "ir/base/spreadElement.h" 27#include "ir/base/scriptFunction.h" 28#include "ir/base/classDefinition.h" 29#include "ir/base/classProperty.h" 30#include "ir/ets/etsParameterExpression.h" 31#include "ir/expressions/identifier.h" 32#include "ir/statements/blockStatement.h" 33#include "ir/ts/tsEnumDeclaration.h" 34#include "ir/ts/tsEnumMember.h" 35#include "checker/types/ets/types.h" 36 37namespace ark::es2panda::compiler { 38void ETSFunction::CallImplicitCtor(ETSGen *etsg) 39{ 40 RegScope rs(etsg); 41 auto *superType = etsg->ContainingObjectType()->SuperType(); 42 43 if (superType == nullptr) { 44 etsg->CallExact(etsg->RootNode(), Signatures::BUILTIN_OBJECT_CTOR, etsg->GetThisReg()); 45 46 return; 47 } 48 49 auto res = std::find_if(superType->ConstructSignatures().cbegin(), superType->ConstructSignatures().cend(), 50 [](const checker::Signature *sig) { return sig->Params().empty(); }); 51 if (res == superType->ConstructSignatures().cend()) { 52 return; 53 } 54 55 etsg->CallExact(etsg->RootNode(), (*res)->InternalName(), etsg->GetThisReg()); 56} 57 58void ETSFunction::CompileSourceBlock(ETSGen *etsg, const ir::BlockStatement *block) 59{ 60 auto *scriptFunc = etsg->RootNode()->AsScriptFunction(); 61 62 if (scriptFunc->IsEnum()) { 63 // NOTE: add enum methods 64 } else if (scriptFunc->IsStaticBlock()) { 65 CompileAsStaticBlock(etsg); 66 } else if (scriptFunc->IsConstructor()) { 67 CompileAsConstructor(etsg, scriptFunc); 68 } 69 70 const auto &statements = block->Statements(); 71 72 if (statements.empty()) { 73 etsg->SetFirstStmt(block); 74 ExtendWithDefaultReturn(etsg, block, scriptFunc); 75 return; 76 } 77 78 etsg->SetFirstStmt(statements.front()); 79 80 etsg->CompileStatements(statements); 81 82 if (!statements.back()->IsReturnStatement()) { 83 ExtendWithDefaultReturn(etsg, statements.back(), scriptFunc); 84 } 85} 86 87void ETSFunction::ExtendWithDefaultReturn(ETSGen *etsg, const ir::AstNode *node, const ir::ScriptFunction *scriptFunc) 88{ 89 if (etsg->ReturnType()->IsETSVoidType()) { 90 etsg->EmitReturnVoid(node); 91 return; 92 } 93 94 if (scriptFunc->ReturnTypeAnnotation() != nullptr && scriptFunc->ReturnTypeAnnotation()->TsType() != nullptr && 95 scriptFunc->ReturnTypeAnnotation()->TsType()->IsETSAsyncFuncReturnType()) { 96 etsg->LoadDefaultValue(node, scriptFunc->ReturnTypeAnnotation()->TsType()); 97 } else { 98 etsg->LoadDefaultValue(node, scriptFunc->Signature()->ReturnType()); 99 } 100 etsg->ReturnAcc(node); 101} 102 103void ETSFunction::CompileAsStaticBlock(ETSGen *etsg) 104{ 105 const auto *classDef = etsg->ContainingObjectType()->GetDeclNode()->AsClassDefinition(); 106 107 auto const checkInitializer = [](ArenaVector<ir::AstNode *> const &nodes) -> bool { 108 for (auto const *const node : nodes) { 109 if (node->IsMethodDefinition() && node->AsClassElement()->Key()->IsIdentifier() && 110 node->AsClassElement()->Id()->Name() == compiler::Signatures::INIT_METHOD) { 111 return false; 112 } 113 } 114 return true; 115 }; 116 117 // Check if it is the Global class static constructor and the special '_$init$_" method exists 118 bool const compileInitializer = classDef->IsGlobal() ? checkInitializer(classDef->Body()) : true; 119 120 for (const auto *prop : classDef->Body()) { 121 if (!prop->IsClassProperty() || !prop->IsStatic()) { 122 continue; 123 } 124 125 // Don't compile variable initializers if they present in '_$init$_" method 126 auto *const item = prop->AsClassProperty(); 127 if (item->Value() != nullptr && 128 (compileInitializer || item->IsConst() || item->Value()->IsArrowFunctionExpression())) { 129 item->Compile(etsg); 130 } 131 } 132} 133 134void ETSFunction::CompileAsConstructor(ETSGen *etsg, const ir::ScriptFunction *scriptFunc) 135{ 136 if (scriptFunc->IsImplicitSuperCallNeeded()) { 137 CallImplicitCtor(etsg); 138 } 139 140 const auto *classDef = etsg->ContainingObjectType()->GetDeclNode()->AsClassDefinition(); 141 142 for (const auto *prop : classDef->Body()) { 143 if (prop->IsClassProperty() && !prop->IsStatic()) { 144 prop->AsClassProperty()->Compile(etsg); 145 } 146 } 147} 148 149void ETSFunction::CompileFunction(ETSGen *etsg) 150{ 151 if (const auto *decl = etsg->RootNode()->AsScriptFunction(); !decl->IsDeclare() && !decl->IsExternal()) { 152 if (auto *const body = decl->Body(); body != nullptr && body->IsBlockStatement()) { 153 CompileSourceBlock(etsg, body->AsBlockStatement()); 154 } 155 } 156} 157 158void ETSFunction::Compile(ETSGen *etsg) 159{ 160 FunctionRegScope lrs(etsg); 161 auto *topScope = etsg->TopScope(); 162 163 if (topScope->IsFunctionScope()) { 164 CompileFunction(etsg); 165 } else { 166 ASSERT(topScope->IsGlobalScope()); 167 CompileSourceBlock(etsg, etsg->RootNode()->AsBlockStatement()); 168 } 169 170 etsg->SortCatchTables(); 171} 172 173} // namespace ark::es2panda::compiler 174