13af6ab5fSopenharmony_ci/*
23af6ab5fSopenharmony_ci * Copyright (c) 2022 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 "symbolTable.h"
173af6ab5fSopenharmony_ci
183af6ab5fSopenharmony_ci#include <fstream>
193af6ab5fSopenharmony_ci#include <iostream>
203af6ab5fSopenharmony_ci#include <util/helpers.h>
213af6ab5fSopenharmony_ci
223af6ab5fSopenharmony_cinamespace panda::es2panda::util {
233af6ab5fSopenharmony_ciconst std::string SymbolTable::FIRST_LEVEL_SEPERATOR = "|";
243af6ab5fSopenharmony_ciconst std::string SymbolTable::SECOND_LEVEL_SEPERATOR = ";";
253af6ab5fSopenharmony_ciconst size_t FUNCTION_ITEM_NUMBER = 3;
263af6ab5fSopenharmony_ciconst size_t MODULE_ITEM_NUMBER = 1;
273af6ab5fSopenharmony_ci
283af6ab5fSopenharmony_cibool SymbolTable::Initialize(int targetApiVersion, std::string targetApiSubVersion)
293af6ab5fSopenharmony_ci{
303af6ab5fSopenharmony_ci    targetApiVersion_ = targetApiVersion;
313af6ab5fSopenharmony_ci    targetApiSubVersion_ = targetApiSubVersion;
323af6ab5fSopenharmony_ci    if (!symbolTable_.empty() && !ReadSymbolTable(symbolTable_)) {
333af6ab5fSopenharmony_ci        std::cerr << "Failed to open the symbol table file'" << std::endl;
343af6ab5fSopenharmony_ci        return false;
353af6ab5fSopenharmony_ci    }
363af6ab5fSopenharmony_ci
373af6ab5fSopenharmony_ci    if (!dumpSymbolTable_.empty()) {
383af6ab5fSopenharmony_ci        std::fstream fs;
393af6ab5fSopenharmony_ci        fs.open(panda::os::file::File::GetExtendedFilePath(dumpSymbolTable_),
403af6ab5fSopenharmony_ci            std::ios_base::out | std::ios_base::trunc);
413af6ab5fSopenharmony_ci        if (!fs.is_open()) {
423af6ab5fSopenharmony_ci            std::cerr << "Failed to create or open the output symbol table file '"
433af6ab5fSopenharmony_ci                      << dumpSymbolTable_ << "' during symbol table initialization." << std::endl
443af6ab5fSopenharmony_ci                      << "This error could be due to invalid file path, lack of write permissions, "
453af6ab5fSopenharmony_ci                      << "or the file being in use by another process." << std::endl;
463af6ab5fSopenharmony_ci            return false;
473af6ab5fSopenharmony_ci        }
483af6ab5fSopenharmony_ci        fs.close();
493af6ab5fSopenharmony_ci    }
503af6ab5fSopenharmony_ci
513af6ab5fSopenharmony_ci    return true;
523af6ab5fSopenharmony_ci}
533af6ab5fSopenharmony_ci
543af6ab5fSopenharmony_civoid SymbolTable::ReadRecordHashFunctionNames(const std::string &recordName, const std::string &funcInternalName,
553af6ab5fSopenharmony_ci                                              const std::string &specialFuncIndex)
563af6ab5fSopenharmony_ci{
573af6ab5fSopenharmony_ci    auto recordHashFunctionNames = originRecordHashFunctionNames_.find(recordName);
583af6ab5fSopenharmony_ci    if (specialFuncIndex == "0") {
593af6ab5fSopenharmony_ci        // 0: not anonymous, special or duplicate function
603af6ab5fSopenharmony_ci        if (recordHashFunctionNames == originRecordHashFunctionNames_.end())  {
613af6ab5fSopenharmony_ci            std::unordered_map<std::string, std::string> functionIndexNameMap {};
623af6ab5fSopenharmony_ci            originRecordHashFunctionNames_.insert({recordName, functionIndexNameMap});
633af6ab5fSopenharmony_ci        }
643af6ab5fSopenharmony_ci    } else {
653af6ab5fSopenharmony_ci        if (recordHashFunctionNames != originRecordHashFunctionNames_.end()) {
663af6ab5fSopenharmony_ci            recordHashFunctionNames->second.insert({specialFuncIndex, funcInternalName});
673af6ab5fSopenharmony_ci        } else {
683af6ab5fSopenharmony_ci            std::unordered_map<std::string, std::string> functionIndexNameMap {{specialFuncIndex, funcInternalName}};
693af6ab5fSopenharmony_ci            originRecordHashFunctionNames_.insert({recordName, functionIndexNameMap});
703af6ab5fSopenharmony_ci        }
713af6ab5fSopenharmony_ci    }
723af6ab5fSopenharmony_ci}
733af6ab5fSopenharmony_ci
743af6ab5fSopenharmony_cibool SymbolTable::ReadSymbolTable(const std::string &symbolTable)
753af6ab5fSopenharmony_ci{
763af6ab5fSopenharmony_ci    std::ifstream ifs;
773af6ab5fSopenharmony_ci    std::string line;
783af6ab5fSopenharmony_ci    ifs.open(panda::os::file::File::GetExtendedFilePath(symbolTable));
793af6ab5fSopenharmony_ci    if (!ifs.is_open()) {
803af6ab5fSopenharmony_ci        std::cerr << "Failed to open the symbol table file '"
813af6ab5fSopenharmony_ci                  << symbolTable << "' during symbol table reading." << std::endl
823af6ab5fSopenharmony_ci                  << "Please check if the file exists, the path is correct, "
833af6ab5fSopenharmony_ci                  << "and your program has the necessary permissions to access the file." << std::endl;
843af6ab5fSopenharmony_ci        return false;
853af6ab5fSopenharmony_ci    }
863af6ab5fSopenharmony_ci
873af6ab5fSopenharmony_ci    while (std::getline(ifs, line)) {
883af6ab5fSopenharmony_ci        auto itemList = GetStringItems(line, FIRST_LEVEL_SEPERATOR);
893af6ab5fSopenharmony_ci
903af6ab5fSopenharmony_ci        if (itemList.size() == FUNCTION_ITEM_NUMBER) {
913af6ab5fSopenharmony_ci            // read function info
923af6ab5fSopenharmony_ci            struct OriginFunctionInfo info(&allocator_);
933af6ab5fSopenharmony_ci            auto funcItems = GetStringItems(itemList[0], SECOND_LEVEL_SEPERATOR);
943af6ab5fSopenharmony_ci            auto classItems = GetStringItems(itemList[1], SECOND_LEVEL_SEPERATOR);
953af6ab5fSopenharmony_ci            auto lexItems = GetStringItems(itemList[2], SECOND_LEVEL_SEPERATOR);
963af6ab5fSopenharmony_ci
973af6ab5fSopenharmony_ci            info.recordName = funcItems[0].substr(0, funcItems[0].find_last_of("."));
983af6ab5fSopenharmony_ci            info.funcInternalName = funcItems[1];
993af6ab5fSopenharmony_ci            // 2: use the third element of the function as the hash of the function
1003af6ab5fSopenharmony_ci            info.funcHash = funcItems[2];
1013af6ab5fSopenharmony_ci
1023af6ab5fSopenharmony_ci            // 2 is to process each class name and its corresponding hash value
1033af6ab5fSopenharmony_ci            for (size_t i = 0; i < classItems.size(); i = i + 2) {
1043af6ab5fSopenharmony_ci                info.classHash.insert(std::pair<std::string, std::string>(classItems[i], classItems[i + 1]));
1053af6ab5fSopenharmony_ci            }
1063af6ab5fSopenharmony_ci            // 3 is to process a complete lexical environment entry
1073af6ab5fSopenharmony_ci            for (size_t i = 0; i < lexItems.size(); i = i + 3) {
1083af6ab5fSopenharmony_ci                auto name = std::string(lexItems[i]);
1093af6ab5fSopenharmony_ci                auto slot = std::atoi(std::string(lexItems[i + 1]).c_str());
1103af6ab5fSopenharmony_ci                auto type = std::atoi(std::string(lexItems[i + 2]).c_str());
1113af6ab5fSopenharmony_ci                info.lexenv.insert({slot, std::pair<std::string, int>(name, type)});
1123af6ab5fSopenharmony_ci            }
1133af6ab5fSopenharmony_ci
1143af6ab5fSopenharmony_ci            originFunctionInfo_.insert(std::pair<std::string, OriginFunctionInfo>(info.funcInternalName, info));
1153af6ab5fSopenharmony_ci            if (util::Helpers::IsDefaultApiVersion(targetApiVersion_, targetApiSubVersion_)) {
1163af6ab5fSopenharmony_ci                // index of function in its record's special function array
1173af6ab5fSopenharmony_ci                std::string specialFuncIndex{funcItems[3]};
1183af6ab5fSopenharmony_ci                ReadRecordHashFunctionNames(info.recordName, info.funcInternalName, specialFuncIndex);
1193af6ab5fSopenharmony_ci            }
1203af6ab5fSopenharmony_ci        } else if (itemList.size() == MODULE_ITEM_NUMBER) {
1213af6ab5fSopenharmony_ci            // read module info
1223af6ab5fSopenharmony_ci            auto moduleItems = GetStringItems(itemList[0], SECOND_LEVEL_SEPERATOR);
1233af6ab5fSopenharmony_ci            originModuleInfo_.insert(std::pair<std::string, std::string>(moduleItems[0], moduleItems[1]));
1243af6ab5fSopenharmony_ci        } else {
1253af6ab5fSopenharmony_ci            std::cerr << "Failed to read the symbol table line: '" << line
1263af6ab5fSopenharmony_ci                      << "' from the symbol table file '" << symbolTable << "' due to unrecognized format." << std::endl
1273af6ab5fSopenharmony_ci                      << "Please verify the format of the symbol table." << std::endl;
1283af6ab5fSopenharmony_ci        }
1293af6ab5fSopenharmony_ci    }
1303af6ab5fSopenharmony_ci    return true;
1313af6ab5fSopenharmony_ci}
1323af6ab5fSopenharmony_ci
1333af6ab5fSopenharmony_civoid SymbolTable::FillSymbolTable(const std::stringstream &content)
1343af6ab5fSopenharmony_ci{
1353af6ab5fSopenharmony_ci    std::lock_guard<std::mutex> lock(m_);
1363af6ab5fSopenharmony_ci    symbolTableContent_ << content.rdbuf();
1373af6ab5fSopenharmony_ci}
1383af6ab5fSopenharmony_ci
1393af6ab5fSopenharmony_civoid SymbolTable::WriteSymbolTable()
1403af6ab5fSopenharmony_ci{
1413af6ab5fSopenharmony_ci    std::fstream fs;
1423af6ab5fSopenharmony_ci    fs.open(panda::os::file::File::GetExtendedFilePath(dumpSymbolTable_),
1433af6ab5fSopenharmony_ci        std::ios_base::app | std::ios_base::in);
1443af6ab5fSopenharmony_ci    if (fs.is_open()) {
1453af6ab5fSopenharmony_ci        fs << symbolTableContent_.str();
1463af6ab5fSopenharmony_ci        fs.close();
1473af6ab5fSopenharmony_ci    }
1483af6ab5fSopenharmony_ci}
1493af6ab5fSopenharmony_ci
1503af6ab5fSopenharmony_cistd::vector<std::string_view> SymbolTable::GetStringItems(std::string_view input, const std::string &separator)
1513af6ab5fSopenharmony_ci{
1523af6ab5fSopenharmony_ci    std::vector<std::string_view> items;
1533af6ab5fSopenharmony_ci    size_t curPos = 0;
1543af6ab5fSopenharmony_ci    size_t lastPos = 0;
1553af6ab5fSopenharmony_ci
1563af6ab5fSopenharmony_ci    while ((curPos = input.find(separator, lastPos)) != std::string_view::npos) {
1573af6ab5fSopenharmony_ci        auto token = input.substr(lastPos, curPos - lastPos);
1583af6ab5fSopenharmony_ci        if (!token.empty()) {
1593af6ab5fSopenharmony_ci            items.push_back(token);
1603af6ab5fSopenharmony_ci        }
1613af6ab5fSopenharmony_ci        lastPos = curPos + separator.size();
1623af6ab5fSopenharmony_ci    }
1633af6ab5fSopenharmony_ci
1643af6ab5fSopenharmony_ci    auto tail = input.substr(lastPos);
1653af6ab5fSopenharmony_ci    if (!tail.empty()) {
1663af6ab5fSopenharmony_ci        items.push_back(tail);
1673af6ab5fSopenharmony_ci    }
1683af6ab5fSopenharmony_ci
1693af6ab5fSopenharmony_ci    return items;
1703af6ab5fSopenharmony_ci}
1713af6ab5fSopenharmony_ci}  // namespace panda::es2panda::util