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