* Copyright (c) 2021-2026 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ETSfunction.h"
#include "varbinder/varbinder.h"
#include "varbinder/ETSBinder.h"
#include "util/helpers.h"
#include "varbinder/scope.h"
#include "varbinder/variable.h"
#include "compiler/base/lreference.h"
#include "compiler/core/ETSGen.h"
#include "compiler/core/envScope.h"
#include "ir/base/spreadElement.h"
#include "ir/base/scriptFunction.h"
#include "ir/base/classDefinition.h"
#include "ir/base/classProperty.h"
#include "ir/ets/etsParameterExpression.h"
#include "ir/expressions/callExpression.h"
#include "ir/expressions/identifier.h"
#include "ir/statements/blockStatement.h"
#include "ir/statements/expressionStatement.h"
#include "ir/ts/tsEnumDeclaration.h"
#include "ir/ts/tsEnumMember.h"
namespace ark::es2panda::compiler {
void ETSFunction::CompileConstructorWithExplicitSuper(ETSGen *etsg, const ArenaVector<ir::Statement *> &statements)
{
bool fieldsInitialized = false;
for (const auto *stmt : statements) {
stmt->Compile(etsg);
if (!fieldsInitialized && stmt->IsExpressionStatement() &&
stmt->AsExpressionStatement()->GetExpression()->IsCallExpression() &&
stmt->AsExpressionStatement()->GetExpression()->AsCallExpression()->Callee()->IsSuperExpression()) {
CompileInstanceFieldInitializers(etsg);
fieldsInitialized = true;
}
}
ES2PANDA_ASSERT(fieldsInitialized);
}
void ETSFunction::CompileSourceBlock(ETSGen *etsg, const ir::BlockStatement *block)
{
auto *scriptFunc = etsg->RootNode()->AsScriptFunction();
if (scriptFunc->IsEnum()) {
} else if (scriptFunc->IsStaticBlock()) {
CompileAsStaticBlock(etsg);
} else if (scriptFunc->IsConstructor()) {
CompileAsConstructor(etsg, scriptFunc);
}
const auto &statements = block->Statements();
if (statements.empty()) {
etsg->SetFirstStmt(block);
ExtendWithDefaultReturn(etsg, block, scriptFunc);
return;
}
etsg->SetFirstStmt(statements.front());
if (scriptFunc->IsConstructor() && scriptFunc->IsExplicitSuperCall()) {
CompileConstructorWithExplicitSuper(etsg, statements);
} else {
etsg->CompileStatements(statements);
}
if (!statements.back()->IsReturnStatement()) {
ExtendWithDefaultReturn(etsg, statements.back(), scriptFunc);
}
}
void ETSFunction::ExtendWithDefaultReturn(ETSGen *etsg, const ir::AstNode *node, const ir::ScriptFunction *scriptFunc)
{
if (etsg->ReturnType()->IsETSVoidType()) {
etsg->EmitReturnVoid(node);
return;
}
etsg->LoadDefaultValue(node, scriptFunc->Signature()->ReturnType());
etsg->ReturnAcc(node);
}
void ETSFunction::CompileAsStaticBlock(ETSGen *etsg)
{
const auto *classDef = etsg->ContainingObjectType()->GetDeclNode()->AsClassDefinition();
if (classDef->IsGlobal() && classDef->IsInitInCctor()) {
return;
}
for (const auto *prop : classDef->Body()) {
if (!prop->IsClassProperty() || !prop->IsStatic()) {
continue;
}
auto *const item = prop->AsClassProperty();
if (item->Value() != nullptr) {
item->Compile(etsg);
}
}
}
void ETSFunction::CompileInstanceFieldInitializers(ETSGen *etsg)
{
if (etsg->RootNode()->AsScriptFunction()->IsExplicitThisCall()) {
return;
}
const auto *classDef = etsg->ContainingObjectType()->GetDeclNode()->AsClassDefinition();
for (const auto *prop : classDef->Body()) {
if (prop->IsClassProperty() && !prop->IsStatic()) {
prop->AsClassProperty()->Compile(etsg);
}
}
}
void ETSFunction::CompileAsConstructor(ETSGen *etsg, const ir::ScriptFunction *scriptFunc)
{
ES2PANDA_ASSERT(!scriptFunc->IsImplicitSuperCallNeeded());
ES2PANDA_ASSERT(!scriptFunc->IsExplicitThisCall() || !scriptFunc->IsExplicitSuperCall());
if (scriptFunc->IsExplicitSuperCall()) {
return;
}
CompileInstanceFieldInitializers(etsg);
}
void ETSFunction::CompileFunction(ETSGen *etsg)
{
const auto *decl = etsg->RootNode()->AsScriptFunction();
if (decl->IsDeclare() || decl->IsExternal()) {
return;
}
if (decl->Signature()->Owner()->GetDeclNode()->IsDeclare()) {
return;
}
if (auto *const body = decl->Body(); body != nullptr && body->IsBlockStatement()) {
CompileSourceBlock(etsg, body->AsBlockStatement());
}
}
void ETSFunction::Compile(ETSGen *etsg)
{
FunctionRegScope lrs(etsg);
auto *topScope = etsg->TopScope();
if (topScope->IsFunctionScope()) {
CompileFunction(etsg);
} else {
ES2PANDA_ASSERT(topScope->IsGlobalScope());
CompileSourceBlock(etsg, etsg->RootNode()->AsBlockStatement());
}
etsg->FinalizeRegAllocation();
etsg->SortCatchTables();
}
}