Files
ark_ts2abc/es2panda/compiler/core/function.cpp
T
zhuoli72 c3a2e0b34e Add original es2panda compiler based on 05ddb192 of master
Change-Id: I26f663c67b42f6549c7777a88c8bf00bd845fc96
Signed-off-by: zhuoli72 <pengzhuoli@huawei.com>
2022-06-28 21:29:11 +08:00

209 lines
6.2 KiB
C++

/**
* Copyright (c) 2021-2022 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 "function.h"
#include <binder/binder.h>
#include <util/helpers.h>
#include <binder/scope.h>
#include <binder/variable.h>
#include <compiler/base/lreference.h>
#include <compiler/core/pandagen.h>
#include <ir/base/classDefinition.h>
#include <ir/base/classProperty.h>
#include <ir/base/scriptFunction.h>
#include <ir/expressions/assignmentExpression.h>
#include <ir/expressions/identifier.h>
#include <ir/statements/blockStatement.h>
namespace panda::es2panda::compiler {
static void CompileSourceBlock(PandaGen *pg, const ir::BlockStatement *block)
{
bool hasReturn = false;
const auto &statements = block->Statements();
pg->SetFirstStmt(statements.empty() ? block : statements.front());
for (const auto *stmt : statements) {
stmt->Compile(pg);
if (stmt->IsReturnStatement()) {
hasReturn = true;
}
}
if (hasReturn) {
return;
}
pg->ImplicitReturn(statements.empty() ? block : statements.back());
}
static void CompileFunctionParameterDeclaration(PandaGen *pg, const ir::ScriptFunction *func)
{
ScopeContext scopeCtx(pg, func->Scope()->ParamScope());
uint32_t index = 0;
for (const auto *param : func->Params()) {
LReference ref = LReference::CreateLRef(pg, param, true);
[[maybe_unused]] binder::Variable *paramVar = ref.Variable();
if (ref.Kind() == ReferenceKind::DESTRUCTURING) {
util::StringView name = util::Helpers::ToStringView(pg->Allocator(), index);
paramVar = pg->Scope()->FindLocal(name, binder::ResolveBindingOptions::BINDINGS);
}
ASSERT(paramVar && paramVar->IsLocalVariable());
VReg paramReg = binder::Binder::MANDATORY_PARAMS_NUMBER + index++;
ASSERT(paramVar->LexicalBound() || paramVar->AsLocalVariable()->Vreg() == paramReg);
if (param->IsAssignmentPattern()) {
RegScope rs(pg);
pg->LoadAccumulator(func, paramReg);
auto *nonDefaultLabel = pg->AllocLabel();
if (ref.Kind() == ReferenceKind::DESTRUCTURING) {
auto *loadParamLabel = pg->AllocLabel();
pg->BranchIfNotUndefined(func, loadParamLabel);
param->AsAssignmentPattern()->Right()->Compile(pg);
pg->Branch(func, nonDefaultLabel);
pg->SetLabel(func, loadParamLabel);
pg->LoadAccumulator(func, paramReg);
pg->SetLabel(func, nonDefaultLabel);
ref.SetValue();
} else {
pg->BranchIfNotUndefined(func, nonDefaultLabel);
param->AsAssignmentPattern()->Right()->Compile(pg);
ref.SetValue();
pg->SetLabel(func, nonDefaultLabel);
}
continue;
}
if (param->IsRestElement()) {
pg->CopyRestArgs(param, func->Params().size() - 1);
} else if (ref.Kind() == ReferenceKind::DESTRUCTURING) {
pg->LoadAccumulator(func, paramReg);
} else {
continue;
}
ref.SetValue();
}
}
static void CompileInstanceFields(PandaGen *pg, const ir::ScriptFunction *decl)
{
const auto &statements = decl->Parent()->Parent()->Parent()->AsClassDefinition()->Body();
RegScope rs(pg);
auto thisReg = pg->AllocReg();
pg->GetThis(decl);
pg->StoreAccumulator(decl, thisReg);
for (auto const &stmt : statements) {
if (stmt->IsClassProperty()) {
const auto *prop = stmt->AsClassProperty();
if (!prop->Value()) {
pg->LoadConst(stmt, Constant::JS_UNDEFINED);
} else {
RegScope rsProp(pg);
prop->Value()->Compile(pg);
}
if (!prop->Key()->IsIdentifier()) {
PandaGen::Unimplemented();
}
pg->StoreObjByName(stmt, thisReg, prop->Key()->AsIdentifier()->Name());
}
}
}
static void CompileFunction(PandaGen *pg)
{
const auto *decl = pg->RootNode()->AsScriptFunction();
// TODO(szilagyia): move after super call
if (decl->IsConstructor()) {
CompileInstanceFields(pg, decl);
}
auto *funcParamScope = pg->TopScope()->ParamScope();
if (funcParamScope->NameVar()) {
RegScope rs(pg);
pg->GetFunctionObject(pg->RootNode());
pg->StoreAccToLexEnv(pg->RootNode(), funcParamScope->Find(funcParamScope->NameVar()->Name()), true);
}
CompileFunctionParameterDeclaration(pg, decl);
pg->FunctionEnter();
const ir::AstNode *body = decl->Body();
if (body->IsExpression()) {
body->Compile(pg);
pg->DirectReturn(decl);
} else {
CompileSourceBlock(pg, body->AsBlockStatement());
}
pg->FunctionExit();
}
static VReg CompileFunctionOrProgram(PandaGen *pg)
{
FunctionRegScope lrs(pg);
const auto *topScope = pg->TopScope();
if (pg->FunctionHasFinalizer()) {
ASSERT(topScope->IsFunctionScope());
TryContext tryCtx(pg);
pg->FunctionInit(tryCtx.GetCatchTable());
CompileFunction(pg);
} else {
pg->FunctionInit(nullptr);
if (topScope->IsFunctionScope()) {
CompileFunction(pg);
} else {
ASSERT(topScope->IsGlobalScope() || topScope->IsModuleScope());
CompileSourceBlock(pg, pg->RootNode()->AsBlockStatement());
}
}
return pg->GetEnvScope()->LexEnv();
}
void Function::Compile(PandaGen *pg)
{
VReg lexEnv = CompileFunctionOrProgram(pg);
pg->CopyFunctionArguments(pg->RootNode());
pg->InitializeLexEnv(pg->RootNode(), lexEnv);
pg->SortCatchTables();
}
} // namespace panda::es2panda::compiler