13af6ab5fSopenharmony_ci/*
23af6ab5fSopenharmony_ci * Copyright (c) 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 "evaluate/helpers.h"
173af6ab5fSopenharmony_ci#include "evaluate/entityDeclarator-inl.h"
183af6ab5fSopenharmony_ci#include "evaluate/scopedDebugInfoPlugin-inl.h"
193af6ab5fSopenharmony_ci#include "evaluate/debugInfoDeserialization/debugInfoDeserializer.h"
203af6ab5fSopenharmony_ci
213af6ab5fSopenharmony_ci#include "checker/ETSchecker.h"
223af6ab5fSopenharmony_ci#include "parser/program/program.h"
233af6ab5fSopenharmony_ci#include "compiler/lowering/phase.h"
243af6ab5fSopenharmony_ci#include "compiler/lowering/util.h"
253af6ab5fSopenharmony_ci#include "compiler/lowering/scopesInit/scopesInitPhase.h"
263af6ab5fSopenharmony_ci#include "ir/statements/blockStatement.h"
273af6ab5fSopenharmony_ci
283af6ab5fSopenharmony_cinamespace ark::es2panda::evaluate {
293af6ab5fSopenharmony_ci
303af6ab5fSopenharmony_cinamespace {
313af6ab5fSopenharmony_ci
323af6ab5fSopenharmony_ciir::VariableDeclaration *CreateVariableDeclaration(checker::ETSChecker *checker, ir::Identifier *ident,
333af6ab5fSopenharmony_ci                                                   ir::Expression *init)
343af6ab5fSopenharmony_ci{
353af6ab5fSopenharmony_ci    auto *declarator = checker->AllocNode<ir::VariableDeclarator>(ir::VariableDeclaratorFlag::CONST, ident, init);
363af6ab5fSopenharmony_ci
373af6ab5fSopenharmony_ci    ArenaVector<ir::VariableDeclarator *> declarators(1, declarator, checker->Allocator()->Adapter());
383af6ab5fSopenharmony_ci    auto *declaration = checker->AllocNode<ir::VariableDeclaration>(
393af6ab5fSopenharmony_ci        ir::VariableDeclaration::VariableDeclarationKind::CONST, checker->Allocator(), std::move(declarators), false);
403af6ab5fSopenharmony_ci
413af6ab5fSopenharmony_ci    declarator->SetParent(declaration);
423af6ab5fSopenharmony_ci    return declaration;
433af6ab5fSopenharmony_ci}
443af6ab5fSopenharmony_ci
453af6ab5fSopenharmony_ci/**
463af6ab5fSopenharmony_ci * @brief Break function's last statement into variable declaration and return statement.
473af6ab5fSopenharmony_ci * Hence we ensure that expression will return result, and local variables
483af6ab5fSopenharmony_ci * could be updated by inserting `DebuggerAPI.setLocal<>` calls between result and return.
493af6ab5fSopenharmony_ci * @param checker used for allocation purposes only.
503af6ab5fSopenharmony_ci * @param methodName used for returned variable name generation.
513af6ab5fSopenharmony_ci * @param lastStatement function's last statement to break.
523af6ab5fSopenharmony_ci * @returns pair of created AST nodes for variable declaration and return statement.
533af6ab5fSopenharmony_ci */
543af6ab5fSopenharmony_cistd::pair<ir::VariableDeclaration *, ir::ReturnStatement *> BreakLastStatement(checker::ETSChecker *checker,
553af6ab5fSopenharmony_ci                                                                               util::StringView methodName,
563af6ab5fSopenharmony_ci                                                                               ir::ExpressionStatement *lastStatement)
573af6ab5fSopenharmony_ci{
583af6ab5fSopenharmony_ci    static constexpr std::string_view GENERATED_VAR_SUFFIX = "_generated_var";
593af6ab5fSopenharmony_ci
603af6ab5fSopenharmony_ci    ASSERT(checker);
613af6ab5fSopenharmony_ci    ASSERT(lastStatement);
623af6ab5fSopenharmony_ci    auto *allocator = checker->Allocator();
633af6ab5fSopenharmony_ci
643af6ab5fSopenharmony_ci    auto returnVariableNameView = [methodName, allocator]() {
653af6ab5fSopenharmony_ci        std::stringstream ss;
663af6ab5fSopenharmony_ci        ss << methodName << GENERATED_VAR_SUFFIX;
673af6ab5fSopenharmony_ci        util::UString variableName(ss.str(), allocator);
683af6ab5fSopenharmony_ci        return variableName.View();
693af6ab5fSopenharmony_ci    }();
703af6ab5fSopenharmony_ci    auto *variableIdent = checker->AllocNode<ir::Identifier>(returnVariableNameView, allocator);
713af6ab5fSopenharmony_ci    auto *exprInit = lastStatement->AsExpressionStatement()->GetExpression();
723af6ab5fSopenharmony_ci    auto *variableDeclaration = CreateVariableDeclaration(checker, variableIdent, exprInit);
733af6ab5fSopenharmony_ci
743af6ab5fSopenharmony_ci    auto *returnStatement = checker->AllocNode<ir::ReturnStatement>(variableIdent->Clone(allocator, nullptr));
753af6ab5fSopenharmony_ci
763af6ab5fSopenharmony_ci    // Unattach previous statement.
773af6ab5fSopenharmony_ci    lastStatement->SetParent(nullptr);
783af6ab5fSopenharmony_ci
793af6ab5fSopenharmony_ci    return std::make_pair(variableDeclaration, returnStatement);
803af6ab5fSopenharmony_ci}
813af6ab5fSopenharmony_ci
823af6ab5fSopenharmony_ci}  // namespace
833af6ab5fSopenharmony_ci
843af6ab5fSopenharmony_ciScopedDebugInfoPlugin::ScopedDebugInfoPlugin(parser::Program *globalProgram, checker::ETSChecker *checker,
853af6ab5fSopenharmony_ci                                             const CompilerOptions &options)
863af6ab5fSopenharmony_ci    : globalProgram_(globalProgram),
873af6ab5fSopenharmony_ci      checker_(checker),
883af6ab5fSopenharmony_ci      context_(options),
893af6ab5fSopenharmony_ci      irCheckHelper_(checker, globalProgram->VarBinder()->AsETSBinder()),
903af6ab5fSopenharmony_ci      debugInfoStorage_(options, checker->Allocator()),
913af6ab5fSopenharmony_ci      debugInfoDeserializer_(*this),
923af6ab5fSopenharmony_ci      pathResolver_(debugInfoStorage_),
933af6ab5fSopenharmony_ci      prologueEpilogueMap_(checker->Allocator()->Adapter()),
943af6ab5fSopenharmony_ci      proxyProgramsCache_(checker->Allocator()),
953af6ab5fSopenharmony_ci      entityDeclarator_(*this)
963af6ab5fSopenharmony_ci{
973af6ab5fSopenharmony_ci    ASSERT(globalProgram_);
983af6ab5fSopenharmony_ci    ASSERT(checker_);
993af6ab5fSopenharmony_ci
1003af6ab5fSopenharmony_ci    ValidateEvaluationOptions(options);
1013af6ab5fSopenharmony_ci
1023af6ab5fSopenharmony_ci    auto isContextValid = debugInfoStorage_.FillEvaluateContext(context_);
1033af6ab5fSopenharmony_ci    if (!isContextValid) {
1043af6ab5fSopenharmony_ci        LOG(FATAL, ES2PANDA) << "Can't create evaluate context" << std::endl;
1053af6ab5fSopenharmony_ci    }
1063af6ab5fSopenharmony_ci
1073af6ab5fSopenharmony_ci    CreateContextPrograms();
1083af6ab5fSopenharmony_ci}
1093af6ab5fSopenharmony_ci
1103af6ab5fSopenharmony_civoid ScopedDebugInfoPlugin::PreCheck()
1113af6ab5fSopenharmony_ci{
1123af6ab5fSopenharmony_ci    irCheckHelper_.PreCheck();
1133af6ab5fSopenharmony_ci
1143af6ab5fSopenharmony_ci    // Find evaluation method after parse and before any checks.
1153af6ab5fSopenharmony_ci    context_.FindEvaluationMethod(GetEvaluatedExpressionProgram());
1163af6ab5fSopenharmony_ci}
1173af6ab5fSopenharmony_ci
1183af6ab5fSopenharmony_civoid ScopedDebugInfoPlugin::PostCheck()
1193af6ab5fSopenharmony_ci{
1203af6ab5fSopenharmony_ci    ASSERT(prologueEpilogueMap_.empty());
1213af6ab5fSopenharmony_ci
1223af6ab5fSopenharmony_ci    [[maybe_unused]] auto inserted = InsertReturnStatement();
1233af6ab5fSopenharmony_ci    LOG(DEBUG, ES2PANDA) << "Evaluation method will return: " << std::boolalpha << inserted << std::noboolalpha;
1243af6ab5fSopenharmony_ci}
1253af6ab5fSopenharmony_ci
1263af6ab5fSopenharmony_cibool ScopedDebugInfoPlugin::InsertReturnStatement()
1273af6ab5fSopenharmony_ci{
1283af6ab5fSopenharmony_ci    auto *lastStatement = context_.lastStatement;
1293af6ab5fSopenharmony_ci    if (lastStatement == nullptr) {
1303af6ab5fSopenharmony_ci        // Last evaluation statement cannot return a value.
1313af6ab5fSopenharmony_ci        return false;
1323af6ab5fSopenharmony_ci    }
1333af6ab5fSopenharmony_ci    auto *returnType = lastStatement->GetExpression()->TsType();
1343af6ab5fSopenharmony_ci    if (returnType == nullptr || !returnType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE_RETURN)) {
1353af6ab5fSopenharmony_ci        // NOTE(dslynko): currently expression evaluation supports only primitives.
1363af6ab5fSopenharmony_ci        // In future this condition might be replaced with `returnType is not void`.
1373af6ab5fSopenharmony_ci        return false;
1383af6ab5fSopenharmony_ci    }
1393af6ab5fSopenharmony_ci
1403af6ab5fSopenharmony_ci    // As an example, the code below will transform
1413af6ab5fSopenharmony_ci    // ```
1423af6ab5fSopenharmony_ci    // localVar += 1                        // This expression returns new value of `localVar`.
1433af6ab5fSopenharmony_ci    // DebuggerAPI.setLocalInt(0, localVar) // Already generated by plugin.
1443af6ab5fSopenharmony_ci    // ```
1453af6ab5fSopenharmony_ci    // into
1463af6ab5fSopenharmony_ci    // ```
1473af6ab5fSopenharmony_ci    // const eval_file_generated_var = (localVar += 1)
1483af6ab5fSopenharmony_ci    // DebuggerAPI.setLocalInt(0, localVar)
1493af6ab5fSopenharmony_ci    // return eval_file_generated_var
1503af6ab5fSopenharmony_ci    // ```
1513af6ab5fSopenharmony_ci    // which will also modify method signature's return type.
1523af6ab5fSopenharmony_ci
1533af6ab5fSopenharmony_ci    auto *evalMethodStatements = context_.methodStatements;
1543af6ab5fSopenharmony_ci    auto &statementsList = evalMethodStatements->Statements();
1553af6ab5fSopenharmony_ci    // Omit the emplaced `DebuggerAPI.setLocal<>` calls and find the original last statement.
1563af6ab5fSopenharmony_ci    auto lastStatementIter = std::find(statementsList.rbegin(), statementsList.rend(), lastStatement);
1573af6ab5fSopenharmony_ci    ASSERT(lastStatementIter != statementsList.rend());
1583af6ab5fSopenharmony_ci
1593af6ab5fSopenharmony_ci    // Break the last user's statement into variable declaration and return statement.
1603af6ab5fSopenharmony_ci    auto *scope = compiler::NearestScope(lastStatement);
1613af6ab5fSopenharmony_ci    auto *scriptFunction = evalMethodStatements->Parent()->AsScriptFunction();
1623af6ab5fSopenharmony_ci    auto [variableDeclaration, returnStatement] =
1633af6ab5fSopenharmony_ci        BreakLastStatement(checker_, scriptFunction->Id()->Name(), lastStatement);
1643af6ab5fSopenharmony_ci
1653af6ab5fSopenharmony_ci    // Attach new nodes to statements block.
1663af6ab5fSopenharmony_ci    variableDeclaration->SetParent(evalMethodStatements);
1673af6ab5fSopenharmony_ci    *lastStatementIter = variableDeclaration;
1683af6ab5fSopenharmony_ci    returnStatement->SetParent(evalMethodStatements);
1693af6ab5fSopenharmony_ci    statementsList.emplace_back(returnStatement);
1703af6ab5fSopenharmony_ci
1713af6ab5fSopenharmony_ci    scriptFunction->AddFlag(ir::ScriptFunctionFlags::HAS_RETURN);
1723af6ab5fSopenharmony_ci    auto *signature = scriptFunction->Signature();
1733af6ab5fSopenharmony_ci    signature->AddSignatureFlag(checker::SignatureFlags::NEED_RETURN_TYPE);
1743af6ab5fSopenharmony_ci    signature->SetReturnType(returnType);
1753af6ab5fSopenharmony_ci
1763af6ab5fSopenharmony_ci    auto newNodeInitializer = [this, scope](ir::AstNode *node) {
1773af6ab5fSopenharmony_ci        auto *varBinder = GetETSBinder();
1783af6ab5fSopenharmony_ci        helpers::DoScopedAction(checker_, varBinder, GetEvaluatedExpressionProgram(), scope, nullptr,
1793af6ab5fSopenharmony_ci                                [this, varBinder, scope, node]() {
1803af6ab5fSopenharmony_ci                                    compiler::InitScopesPhaseETS::RunExternalNode(node, varBinder);
1813af6ab5fSopenharmony_ci                                    varBinder->HandleCustomNodes(node);
1823af6ab5fSopenharmony_ci                                    varBinder->ResolveReferencesForScope(node, scope);
1833af6ab5fSopenharmony_ci                                    node->Check(checker_);
1843af6ab5fSopenharmony_ci                                });
1853af6ab5fSopenharmony_ci    };
1863af6ab5fSopenharmony_ci    newNodeInitializer(variableDeclaration);
1873af6ab5fSopenharmony_ci    newNodeInitializer(returnStatement);
1883af6ab5fSopenharmony_ci
1893af6ab5fSopenharmony_ci    return true;
1903af6ab5fSopenharmony_ci}
1913af6ab5fSopenharmony_ci
1923af6ab5fSopenharmony_civoid ScopedDebugInfoPlugin::AddPrologueEpilogue(ir::BlockStatement *block)
1933af6ab5fSopenharmony_ci{
1943af6ab5fSopenharmony_ci    auto iter = prologueEpilogueMap_.find(block);
1953af6ab5fSopenharmony_ci    if (iter == prologueEpilogueMap_.end()) {
1963af6ab5fSopenharmony_ci        return;
1973af6ab5fSopenharmony_ci    }
1983af6ab5fSopenharmony_ci
1993af6ab5fSopenharmony_ci    // Prepend prologue.
2003af6ab5fSopenharmony_ci    auto &statements = block->Statements();
2013af6ab5fSopenharmony_ci    for (auto *stmt : iter->second.first) {
2023af6ab5fSopenharmony_ci        statements.insert(statements.begin(), stmt);
2033af6ab5fSopenharmony_ci    }
2043af6ab5fSopenharmony_ci
2053af6ab5fSopenharmony_ci    // Append epilogue.
2063af6ab5fSopenharmony_ci    for (auto *stmt : iter->second.second) {
2073af6ab5fSopenharmony_ci        statements.emplace_back(stmt);
2083af6ab5fSopenharmony_ci    }
2093af6ab5fSopenharmony_ci
2103af6ab5fSopenharmony_ci    prologueEpilogueMap_.erase(iter);
2113af6ab5fSopenharmony_ci}
2123af6ab5fSopenharmony_ci
2133af6ab5fSopenharmony_civarbinder::Variable *ScopedDebugInfoPlugin::FindIdentifier(ir::Identifier *ident)
2143af6ab5fSopenharmony_ci{
2153af6ab5fSopenharmony_ci    ASSERT(ident);
2163af6ab5fSopenharmony_ci
2173af6ab5fSopenharmony_ci    helpers::SafeStateScope s(checker_, GetETSBinder());
2183af6ab5fSopenharmony_ci
2193af6ab5fSopenharmony_ci    auto *var = FindLocalVariable(ident);
2203af6ab5fSopenharmony_ci    if (var != nullptr) {
2213af6ab5fSopenharmony_ci        return var;
2223af6ab5fSopenharmony_ci    }
2233af6ab5fSopenharmony_ci    var = FindGlobalVariable(ident);
2243af6ab5fSopenharmony_ci    if (var != nullptr) {
2253af6ab5fSopenharmony_ci        return var;
2263af6ab5fSopenharmony_ci    }
2273af6ab5fSopenharmony_ci    var = FindClass(ident);
2283af6ab5fSopenharmony_ci    if (var != nullptr) {
2293af6ab5fSopenharmony_ci        return var;
2303af6ab5fSopenharmony_ci    }
2313af6ab5fSopenharmony_ci    return FindGlobalFunction(ident);
2323af6ab5fSopenharmony_ci}
2333af6ab5fSopenharmony_ci
2343af6ab5fSopenharmony_civarbinder::Variable *ScopedDebugInfoPlugin::FindClass(ir::Identifier *ident)
2353af6ab5fSopenharmony_ci{
2363af6ab5fSopenharmony_ci    // The following algorithm is used:
2373af6ab5fSopenharmony_ci    // - Search for `import * as B from "C"` statements.
2383af6ab5fSopenharmony_ci    //   - If found, [Not implemented yet]
2393af6ab5fSopenharmony_ci    //   - Else, proceed.
2403af6ab5fSopenharmony_ci    // - Search classes which defined in the context file:
2413af6ab5fSopenharmony_ci    //   - If found, recreate its structure and return.
2423af6ab5fSopenharmony_ci    //   - Else, proceed.
2433af6ab5fSopenharmony_ci    // - Search through the imported entities extracted from imports/exports table:
2443af6ab5fSopenharmony_ci    //   - If the class was found, create parser::Program corresponding for the import source,
2453af6ab5fSopenharmony_ci    //     where the class could be recreated.
2463af6ab5fSopenharmony_ci    //   - Else, return nullptr.
2473af6ab5fSopenharmony_ci
2483af6ab5fSopenharmony_ci    // NOTE: support "import * as X".
2493af6ab5fSopenharmony_ci
2503af6ab5fSopenharmony_ci    ASSERT(ident);
2513af6ab5fSopenharmony_ci    LOG(DEBUG, ES2PANDA) << "ScopedDebugInfoPlugin: FindClass " << ident->Name();
2523af6ab5fSopenharmony_ci
2533af6ab5fSopenharmony_ci    auto *importerProgram = GetETSBinder()->Program();
2543af6ab5fSopenharmony_ci    const auto &identName = ident->Name();
2553af6ab5fSopenharmony_ci
2563af6ab5fSopenharmony_ci    // Search "import * as B" statements.
2573af6ab5fSopenharmony_ci    // NOTE: separate this into a method.
2583af6ab5fSopenharmony_ci    auto importPath = pathResolver_.FindNamedImportAll(context_.sourceFilePath.Utf8(), identName.Utf8());
2593af6ab5fSopenharmony_ci    if (!importPath.empty()) {
2603af6ab5fSopenharmony_ci        UNREACHABLE();
2613af6ab5fSopenharmony_ci        return nullptr;
2623af6ab5fSopenharmony_ci    }
2633af6ab5fSopenharmony_ci
2643af6ab5fSopenharmony_ci    // Search in the context file.
2653af6ab5fSopenharmony_ci    auto classId = debugInfoStorage_.FindClass(context_.sourceFilePath.Utf8(), identName.Utf8());
2663af6ab5fSopenharmony_ci    if (classId.IsValid()) {
2673af6ab5fSopenharmony_ci        return entityDeclarator_.ImportGlobalEntity(
2683af6ab5fSopenharmony_ci            context_.sourceFilePath, identName, importerProgram, identName,
2693af6ab5fSopenharmony_ci            [classId](auto *deserializer, auto *program, auto declSourcePath, auto declName) {
2703af6ab5fSopenharmony_ci                return deserializer->CreateIrClass(classId, program, declSourcePath, declName);
2713af6ab5fSopenharmony_ci            });
2723af6ab5fSopenharmony_ci    }
2733af6ab5fSopenharmony_ci
2743af6ab5fSopenharmony_ci    // Search in imported entities.
2753af6ab5fSopenharmony_ci    auto optFoundEntity = pathResolver_.FindImportedEntity(context_.sourceFilePath.Utf8(), identName.Utf8());
2763af6ab5fSopenharmony_ci    if (!optFoundEntity) {
2773af6ab5fSopenharmony_ci        return nullptr;
2783af6ab5fSopenharmony_ci    }
2793af6ab5fSopenharmony_ci
2803af6ab5fSopenharmony_ci    const auto &[entitySourceFile, entitySourceName] = optFoundEntity.value();
2813af6ab5fSopenharmony_ci
2823af6ab5fSopenharmony_ci    classId = debugInfoStorage_.FindClass(entitySourceFile, entitySourceName);
2833af6ab5fSopenharmony_ci    if (!classId.IsValid()) {
2843af6ab5fSopenharmony_ci        // The entity is not a class.
2853af6ab5fSopenharmony_ci        return nullptr;
2863af6ab5fSopenharmony_ci    }
2873af6ab5fSopenharmony_ci
2883af6ab5fSopenharmony_ci    // Must pass the name of class as declared in the found file.
2893af6ab5fSopenharmony_ci    return entityDeclarator_.ImportGlobalEntity(
2903af6ab5fSopenharmony_ci        entitySourceFile, entitySourceName, importerProgram, identName,
2913af6ab5fSopenharmony_ci        [classId](auto *deserializer, auto *program, auto declSourcePath, auto declName) {
2923af6ab5fSopenharmony_ci            return deserializer->CreateIrClass(classId, program, declSourcePath, declName);
2933af6ab5fSopenharmony_ci        });
2943af6ab5fSopenharmony_ci}
2953af6ab5fSopenharmony_ci
2963af6ab5fSopenharmony_civarbinder::Variable *ScopedDebugInfoPlugin::FindGlobalFunction(ir::Identifier *ident)
2973af6ab5fSopenharmony_ci{
2983af6ab5fSopenharmony_ci    // Correct overload resolution requires us to create all reachable functions with the given name,
2993af6ab5fSopenharmony_ci    // so that Checker later could choose the correct one.
3003af6ab5fSopenharmony_ci    ASSERT(ident);
3013af6ab5fSopenharmony_ci    LOG(DEBUG, ES2PANDA) << "ScopedDebugInfoPlugin: FindGlobalFunction " << ident->Name();
3023af6ab5fSopenharmony_ci
3033af6ab5fSopenharmony_ci    auto *allocator = Allocator();
3043af6ab5fSopenharmony_ci
3053af6ab5fSopenharmony_ci    auto *importerProgram = GetETSBinder()->Program();
3063af6ab5fSopenharmony_ci    auto identName = ident->Name();
3073af6ab5fSopenharmony_ci
3083af6ab5fSopenharmony_ci    ArenaVector<std::pair<parser::Program *, ArenaVector<ir::AstNode *>>> createdMethods(allocator->Adapter());
3093af6ab5fSopenharmony_ci
3103af6ab5fSopenharmony_ci    // Build every global function from the context file.
3113af6ab5fSopenharmony_ci    createdMethods.emplace_back(GetProgram(context_.sourceFilePath), ArenaVector<ir::AstNode *>(allocator->Adapter()));
3123af6ab5fSopenharmony_ci    auto &fromContextFile = createdMethods.back().second;
3133af6ab5fSopenharmony_ci
3143af6ab5fSopenharmony_ci    auto *var = entityDeclarator_.ImportGlobalEntity(
3153af6ab5fSopenharmony_ci        context_.sourceFilePath, identName, importerProgram, identName,
3163af6ab5fSopenharmony_ci        [&fromContextFile](auto *deserializer, auto *program, auto declSourcePath, auto declName) {
3173af6ab5fSopenharmony_ci            return deserializer->CreateIrGlobalMethods(fromContextFile, program, declSourcePath, declName);
3183af6ab5fSopenharmony_ci        });
3193af6ab5fSopenharmony_ci
3203af6ab5fSopenharmony_ci    // Then search in imports.
3213af6ab5fSopenharmony_ci    ArenaVector<EntityInfo> importedFunctions(allocator->Adapter());
3223af6ab5fSopenharmony_ci    pathResolver_.FindImportedFunctions(importedFunctions, context_.sourceFilePath.Utf8(), identName.Utf8());
3233af6ab5fSopenharmony_ci
3243af6ab5fSopenharmony_ci    // Build all the found functions.
3253af6ab5fSopenharmony_ci    for (const auto &[funcSourceFile, funcSourceName] : importedFunctions) {
3263af6ab5fSopenharmony_ci        createdMethods.emplace_back(GetProgram(funcSourceFile), ArenaVector<ir::AstNode *>(allocator->Adapter()));
3273af6ab5fSopenharmony_ci        auto &fromImported = createdMethods.back().second;
3283af6ab5fSopenharmony_ci
3293af6ab5fSopenharmony_ci        auto *importedVar = entityDeclarator_.ImportGlobalEntity(
3303af6ab5fSopenharmony_ci            funcSourceFile, funcSourceName, importerProgram, identName,
3313af6ab5fSopenharmony_ci            [&fromImported](auto *deserializer, auto *program, auto declSourcePath, auto declName) {
3323af6ab5fSopenharmony_ci                return deserializer->CreateIrGlobalMethods(fromImported, program, declSourcePath, declName);
3333af6ab5fSopenharmony_ci            });
3343af6ab5fSopenharmony_ci        if (importedVar != nullptr) {
3353af6ab5fSopenharmony_ci            ASSERT(var == nullptr || var == importedVar);
3363af6ab5fSopenharmony_ci            var = importedVar;
3373af6ab5fSopenharmony_ci        }
3383af6ab5fSopenharmony_ci    }
3393af6ab5fSopenharmony_ci
3403af6ab5fSopenharmony_ci    // Run Checker only after all functions are created, so that overloading could work correctly.
3413af6ab5fSopenharmony_ci    for (auto &[program, methods] : createdMethods) {
3423af6ab5fSopenharmony_ci        auto *globalClass = program->GlobalClass();
3433af6ab5fSopenharmony_ci        auto *globalClassScope = program->GlobalClassScope();
3443af6ab5fSopenharmony_ci        for (auto *method : methods) {
3453af6ab5fSopenharmony_ci            irCheckHelper_.CheckNewNode(method, globalClassScope, globalClass, program);
3463af6ab5fSopenharmony_ci        }
3473af6ab5fSopenharmony_ci    }
3483af6ab5fSopenharmony_ci
3493af6ab5fSopenharmony_ci    return var;
3503af6ab5fSopenharmony_ci}
3513af6ab5fSopenharmony_ci
3523af6ab5fSopenharmony_civarbinder::Variable *ScopedDebugInfoPlugin::FindGlobalVariable(ir::Identifier *ident)
3533af6ab5fSopenharmony_ci{
3543af6ab5fSopenharmony_ci    ASSERT(ident);
3553af6ab5fSopenharmony_ci    LOG(DEBUG, ES2PANDA) << "ScopedDebugInfoPlugin: FindGlobalVariable " << ident->Name();
3563af6ab5fSopenharmony_ci
3573af6ab5fSopenharmony_ci    auto *importerProgram = GetETSBinder()->Program();
3583af6ab5fSopenharmony_ci    auto identName = ident->Name();
3593af6ab5fSopenharmony_ci
3603af6ab5fSopenharmony_ci    // Search in the context file.
3613af6ab5fSopenharmony_ci    auto *var = entityDeclarator_.ImportGlobalEntity(context_.sourceFilePath, identName, importerProgram, identName,
3623af6ab5fSopenharmony_ci                                                     &DebugInfoDeserializer::CreateIrGlobalVariable);
3633af6ab5fSopenharmony_ci    if (var != nullptr) {
3643af6ab5fSopenharmony_ci        return var;
3653af6ab5fSopenharmony_ci    }
3663af6ab5fSopenharmony_ci
3673af6ab5fSopenharmony_ci    // Search within the imports.
3683af6ab5fSopenharmony_ci    auto optFoundEntity = pathResolver_.FindImportedEntity(context_.sourceFilePath.Utf8(), identName.Utf8());
3693af6ab5fSopenharmony_ci    if (!optFoundEntity) {
3703af6ab5fSopenharmony_ci        return nullptr;
3713af6ab5fSopenharmony_ci    }
3723af6ab5fSopenharmony_ci
3733af6ab5fSopenharmony_ci    const auto &[entitySourceFile, entitySourceName] = optFoundEntity.value();
3743af6ab5fSopenharmony_ci
3753af6ab5fSopenharmony_ci    // Search once again, but in the exported source. Must pass the name of entity as declared in the found file.
3763af6ab5fSopenharmony_ci    return entityDeclarator_.ImportGlobalEntity(entitySourceFile, entitySourceName, importerProgram, identName,
3773af6ab5fSopenharmony_ci                                                &DebugInfoDeserializer::CreateIrGlobalVariable);
3783af6ab5fSopenharmony_ci}
3793af6ab5fSopenharmony_ci
3803af6ab5fSopenharmony_civarbinder::Variable *ScopedDebugInfoPlugin::FindLocalVariable(ir::Identifier *ident)
3813af6ab5fSopenharmony_ci{
3823af6ab5fSopenharmony_ci    ASSERT(ident);
3833af6ab5fSopenharmony_ci    // Search local variables only in evaluation method.
3843af6ab5fSopenharmony_ci    if (helpers::GetEnclosingBlock(ident) != context_.methodStatements) {
3853af6ab5fSopenharmony_ci        return nullptr;
3863af6ab5fSopenharmony_ci    }
3873af6ab5fSopenharmony_ci
3883af6ab5fSopenharmony_ci    LOG(DEBUG, ES2PANDA) << "ScopedDebugInfoPlugin: FindLocalVariable " << ident->Name();
3893af6ab5fSopenharmony_ci
3903af6ab5fSopenharmony_ci    // NOTE: verify that function arguments are included.
3913af6ab5fSopenharmony_ci    const auto &localVariableTable = context_.extractor->GetLocalVariableTable(context_.methodId);
3923af6ab5fSopenharmony_ci    return debugInfoDeserializer_.CreateIrLocalVariable(ident, localVariableTable, context_.bytecodeOffset);
3933af6ab5fSopenharmony_ci}
3943af6ab5fSopenharmony_ci
3953af6ab5fSopenharmony_civoid ScopedDebugInfoPlugin::ValidateEvaluationOptions(const CompilerOptions &options)
3963af6ab5fSopenharmony_ci{
3973af6ab5fSopenharmony_ci    if (!options.isEtsModule) {
3983af6ab5fSopenharmony_ci        LOG(FATAL, ES2PANDA) << "Evaluation mode must be used in conjunction with ets-module option.";
3993af6ab5fSopenharmony_ci    }
4003af6ab5fSopenharmony_ci}
4013af6ab5fSopenharmony_ci
4023af6ab5fSopenharmony_civoid ScopedDebugInfoPlugin::CreateContextPrograms()
4033af6ab5fSopenharmony_ci{
4043af6ab5fSopenharmony_ci    debugInfoStorage_.EnumerateContextFiles([this](auto sourceFilePath, auto, auto, auto moduleName) {
4053af6ab5fSopenharmony_ci        CreateEmptyProgram(sourceFilePath, moduleName);
4063af6ab5fSopenharmony_ci        return true;
4073af6ab5fSopenharmony_ci    });
4083af6ab5fSopenharmony_ci}
4093af6ab5fSopenharmony_ci
4103af6ab5fSopenharmony_ciparser::Program *ScopedDebugInfoPlugin::CreateEmptyProgram(std::string_view sourceFilePath, std::string_view moduleName)
4113af6ab5fSopenharmony_ci{
4123af6ab5fSopenharmony_ci    auto *allocator = Allocator();
4133af6ab5fSopenharmony_ci
4143af6ab5fSopenharmony_ci    // Checker doesn't yet have `VarBinder`, must retrieve it from `globalProgram_`.
4153af6ab5fSopenharmony_ci    parser::Program *program = allocator->New<parser::Program>(allocator, GetETSBinder());
4163af6ab5fSopenharmony_ci    auto omitModuleName = moduleName.empty();
4173af6ab5fSopenharmony_ci    program->SetSource({sourceFilePath, "", globalProgram_->SourceFileFolder().Utf8(), !omitModuleName});
4183af6ab5fSopenharmony_ci    program->SetModuleInfo(moduleName, false, omitModuleName);
4193af6ab5fSopenharmony_ci    auto *etsScript =
4203af6ab5fSopenharmony_ci        allocator->New<ir::ETSScript>(allocator, ArenaVector<ir::Statement *>(allocator->Adapter()), program);
4213af6ab5fSopenharmony_ci    program->SetAst(etsScript);
4223af6ab5fSopenharmony_ci
4233af6ab5fSopenharmony_ci    helpers::AddExternalProgram(globalProgram_, program, moduleName);
4243af6ab5fSopenharmony_ci    proxyProgramsCache_.AddProgram(program);
4253af6ab5fSopenharmony_ci
4263af6ab5fSopenharmony_ci    return program;
4273af6ab5fSopenharmony_ci}
4283af6ab5fSopenharmony_ci
4293af6ab5fSopenharmony_ciparser::Program *ScopedDebugInfoPlugin::GetProgram(util::StringView fileName)
4303af6ab5fSopenharmony_ci{
4313af6ab5fSopenharmony_ci    auto *program = proxyProgramsCache_.GetProgram(fileName);
4323af6ab5fSopenharmony_ci    ASSERT(program);
4333af6ab5fSopenharmony_ci    return program;
4343af6ab5fSopenharmony_ci}
4353af6ab5fSopenharmony_ci
4363af6ab5fSopenharmony_ciparser::Program *ScopedDebugInfoPlugin::GetEvaluatedExpressionProgram()
4373af6ab5fSopenharmony_ci{
4383af6ab5fSopenharmony_ci    auto *program = GetETSBinder()->GetContext()->parserProgram;
4393af6ab5fSopenharmony_ci    ASSERT(program);
4403af6ab5fSopenharmony_ci    return program;
4413af6ab5fSopenharmony_ci}
4423af6ab5fSopenharmony_ci
4433af6ab5fSopenharmony_civarbinder::ETSBinder *ScopedDebugInfoPlugin::GetETSBinder()
4443af6ab5fSopenharmony_ci{
4453af6ab5fSopenharmony_ci    return globalProgram_->VarBinder()->AsETSBinder();
4463af6ab5fSopenharmony_ci}
4473af6ab5fSopenharmony_ci
4483af6ab5fSopenharmony_ciArenaAllocator *ScopedDebugInfoPlugin::Allocator()
4493af6ab5fSopenharmony_ci{
4503af6ab5fSopenharmony_ci    return checker_->Allocator();
4513af6ab5fSopenharmony_ci}
4523af6ab5fSopenharmony_ci
4533af6ab5fSopenharmony_ci}  // namespace ark::es2panda::evaluate
454