1/**
2 * Copyright (c) 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#ifndef ES2PANDA_UTIL_COMMON_H
17#define ES2PANDA_UTIL_COMMON_H
18
19#include <functional>
20#include <iostream>
21#include <vector>
22#include <set>
23#include <string>
24#include <string_view>
25
26#include "assembler/assembly-function.h"
27#include "assembler/assembly-literals.h"
28#include "assembler/assembly-program.h"
29#include "assembler/assembly-record.h"
30
31namespace panda::es2panda {
32struct CompileContextInfo;
33struct PkgInfo;
34};
35
36namespace panda::es2panda::util {
37const std::string NPM_ENTRIES = "npmEntries.txt";
38const std::string IS_COMMONJS = "isCommonjs";
39// The format of ohmurl for non-SO files are start with '@normalized:N'.
40const std::string NORMALIZED_OHMURL_NOT_SO = "@normalized:N";
41const std::string MODULE_RECORD_IDX = "moduleRecordIdx";
42const std::string GLOBAL_TYPE_NAME = "_GLOBAL";
43
44constexpr char NORMALIZED_OHMURL_SEPARATOR = '&';
45constexpr char NORMALIZED_OHMURL_PREFIX = '@';
46constexpr char SLASH_TAG = '/';
47constexpr char CHAR_VERTICAL_LINE = '|';
48
49constexpr size_t BUNDLE_NAME_POS = 2U;
50constexpr size_t NORMALIZED_IMPORT_POS = 3U;
51constexpr size_t VERSION_POS = 4U;
52
53std::vector<std::string> Split(const std::string &str, const char delimiter);
54bool IsExternalPkgNames(const std::string &ohmurl, const std::set<std::string> &externalPkgNames);
55std::string GetRecordNameFromNormalizedOhmurl(const std::string &ohmurl);
56std::string GetPkgNameFromNormalizedOhmurl(const std::string &ohmurl);
57std::string GetPkgNameFromNormalizedImport(const std::string &normalizedImport);
58std::string UpdatePackageVersionIfNeeded(const std::string &ohmurl,
59                                         const std::unordered_map<std::string, PkgInfo> &pkgContextInfo);
60bool RecordNotGeneratedFromBytecode(std::string recordName);
61
62template<bool isConst, typename T>
63using ConstReferenceIf = typename std::conditional<isConst, const T &, T &>::type;
64
65template<bool isConst>
66using ImportTraverser = std::function<void(ConstReferenceIf<isConst, std::string>)>;
67
68template <bool isConst>
69void VisitStaticImports(ConstReferenceIf<isConst, pandasm::Program> program,
70                        ConstReferenceIf<isConst, pandasm::Record> record,
71                        const ImportTraverser<isConst> &cb)
72{
73    for (const pandasm::Field &field : record.field_list) {
74        if (field.name == util::MODULE_RECORD_IDX) {
75            auto moduleLiteralKey = field.metadata->GetValue().value().GetValue<std::string>();
76            auto iter = program.literalarray_table.find(moduleLiteralKey);
77            ASSERT(iter != program.literalarray_table.end());
78            auto &array = iter->second;
79            uint32_t importSize = std::get<uint32_t>(iter->second.literals_[0].value_);
80            for (size_t idx = 1; idx < importSize + 1; ++idx) {
81                cb(std::get<std::string>(array.literals_[idx].value_));
82            }
83        }
84    }
85}
86
87// Only visit dynamic imports for import("xxxx") expression
88template <bool isConst>
89void VisitDyanmicImports(ConstReferenceIf<isConst, pandasm::Function> function, const ImportTraverser<isConst> &cb)
90{
91    for (auto iter = function.ins.begin(); iter != function.ins.end(); iter++) {
92        // Only visit dynamic imports for import("xxxx") expression, whose bytecode always is:
93        // lda.str -> dynamicimport
94        // The dynamicimport bytecode should not have label, otherwise the dyanmicimport might be a jump
95        // target and its parameter is a variable instead of a constant string expression (Check
96        // AbcCodeProcessor::AddJumpLabels for more details).
97        if (iter->opcode != pandasm::Opcode::DYNAMICIMPORT || iter->set_label) {
98            continue;
99        }
100        auto prevIns = iter - 1;
101        if (prevIns->opcode != pandasm::Opcode::LDA_STR) {
102            continue;
103        }
104        ASSERT(prevIns->ids.size() == 1);
105        cb(prevIns->ids[0]);  // 0: index of the string in lda.str bytecode
106    }
107}
108}  // namespace panda::es2panda::util
109
110#endif