Add original es2panda compiler based on 05ddb192 of master

Change-Id: I26f663c67b42f6549c7777a88c8bf00bd845fc96
Signed-off-by: zhuoli72 <pengzhuoli@huawei.com>
This commit is contained in:
zhuoli72
2022-06-28 21:11:14 +08:00
parent 2769efc3c3
commit c3a2e0b34e
2270 changed files with 403063 additions and 0 deletions
+337
View File
@@ -0,0 +1,337 @@
# 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.
cmake_minimum_required (VERSION 3.5.0)
project (es2panda)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/out)
set(GENERATED_DIR ${OUTPUT_DIR}/gen)
set(GENERATED_STAMP ${OUTPUT_DIR}/gen_dir.stamp)
add_custom_target(es2panda-gen)
add_custom_command(
OUTPUT ${GENERATED_STAMP}
COMMAND ${CMAKE_COMMAND} -E make_directory ${OUTPUT_DIR}
COMMAND ${CMAKE_COMMAND} -E make_directory ${GENERATED_DIR}
COMMAND ${CMAKE_COMMAND} -E touch ${GENERATED_STAMP}
)
set(TEMPLATES
isa.h.erb
formats.h.erb
)
panda_isa_gen(
TEMPLATES ${TEMPLATES}
SOURCE ${CMAKE_CURRENT_LIST_DIR}/compiler/templates
DESTINATION ${GENERATED_DIR}
EXTRA_DEPENDENCIES ${GENERATED_STAMP}
)
add_dependencies(es2panda-gen isa_gen_es2panda)
function(gen_keywords TEMPLATE OUT_DIR)
set(TEMPLATE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/lexer/templates/${TEMPLATE})
string(REGEX REPLACE "\.erb$" "" NAME ${TEMPLATE})
string(REPLACE "\." "_" CUSTOM_TARGET ${NAME})
string(REPLACE "/" "_" CUSTOM_TARGET ${CUSTOM_TARGET})
set(CUSTOM_TARGET "panda_es2panda_parser_gen_${CUSTOM_TARGET}")
set(OUT_FILE ${OUT_DIR}/${NAME})
set(GENERATOR ${CMAKE_CURRENT_SOURCE_DIR}/lexer/scripts/keywords.rb)
add_custom_command(OUTPUT ${OUT_FILE}
COMMAND ruby ${GENERATOR} ${TEMPLATE_FILE} ${OUT_FILE}
DEPENDS ${GENERATED_STAMP} ${GENERATOR} ${TEMPLATE_FILE}
)
add_custom_target(${CUSTOM_TARGET} DEPENDS ${OUT_FILE})
add_dependencies(es2panda-gen ${CUSTOM_TARGET})
endfunction()
gen_keywords(keywords.h.erb ${GENERATED_DIR})
gen_keywords(keywordsMap.h.erb ${GENERATED_DIR})
set(ES2PANDA_LIB_SRC
es2panda.cpp
binder/binder.cpp
binder/declaration.cpp
binder/scope.cpp
binder/variable.cpp
compiler/base/catchTable.cpp
compiler/base/condition.cpp
compiler/base/destructuring.cpp
compiler/base/hoisting.cpp
compiler/base/iterators.cpp
compiler/base/lexenv.cpp
compiler/base/literals.cpp
compiler/base/lreference.cpp
compiler/core/compileQueue.cpp
compiler/core/compilerContext.cpp
compiler/core/compilerImpl.cpp
compiler/core/dynamicContext.cpp
compiler/core/emitter.cpp
compiler/core/envScope.cpp
compiler/core/function.cpp
compiler/core/inlineCache.cpp
compiler/core/labelTarget.cpp
compiler/core/moduleContext.cpp
compiler/core/pandagen.cpp
compiler/core/regAllocator.cpp
compiler/core/regScope.cpp
compiler/core/switchBuilder.cpp
compiler/debugger/debuginfoDumper.cpp
compiler/function/asyncFunctionBuilder.cpp
compiler/function/asyncGeneratorFunctionBuilder.cpp
compiler/function/functionBuilder.cpp
compiler/function/generatorFunctionBuilder.cpp
ir/astDump.cpp
ir/base/catchClause.cpp
ir/base/classDefinition.cpp
ir/base/classProperty.cpp
ir/base/decorator.cpp
ir/base/metaProperty.cpp
ir/base/methodDefinition.cpp
ir/base/property.cpp
ir/base/scriptFunction.cpp
ir/base/spreadElement.cpp
ir/base/templateElement.cpp
ir/expression.cpp
ir/expressions/arrayExpression.cpp
ir/expressions/arrowFunctionExpression.cpp
ir/expressions/assignmentExpression.cpp
ir/expressions/awaitExpression.cpp
ir/expressions/binaryExpression.cpp
ir/expressions/callExpression.cpp
ir/expressions/chainExpression.cpp
ir/expressions/classExpression.cpp
ir/expressions/conditionalExpression.cpp
ir/expressions/functionExpression.cpp
ir/expressions/identifier.cpp
ir/expressions/importExpression.cpp
ir/expressions/literal.cpp
ir/expressions/literals/bigIntLiteral.cpp
ir/expressions/literals/booleanLiteral.cpp
ir/expressions/literals/nullLiteral.cpp
ir/expressions/literals/numberLiteral.cpp
ir/expressions/literals/regExpLiteral.cpp
ir/expressions/literals/stringLiteral.cpp
ir/expressions/literals/taggedLiteral.cpp
ir/expressions/memberExpression.cpp
ir/expressions/newExpression.cpp
ir/expressions/objectExpression.cpp
ir/expressions/omittedExpression.cpp
ir/expressions/sequenceExpression.cpp
ir/expressions/superExpression.cpp
ir/expressions/taggedTemplateExpression.cpp
ir/expressions/templateLiteral.cpp
ir/expressions/thisExpression.cpp
ir/expressions/unaryExpression.cpp
ir/expressions/updateExpression.cpp
ir/expressions/yieldExpression.cpp
ir/module/exportAllDeclaration.cpp
ir/module/exportDefaultDeclaration.cpp
ir/module/exportNamedDeclaration.cpp
ir/module/exportSpecifier.cpp
ir/module/importDeclaration.cpp
ir/module/importDefaultSpecifier.cpp
ir/module/importNamespaceSpecifier.cpp
ir/module/importSpecifier.cpp
ir/statement.cpp
ir/statements/blockStatement.cpp
ir/statements/breakStatement.cpp
ir/statements/classDeclaration.cpp
ir/statements/continueStatement.cpp
ir/statements/debuggerStatement.cpp
ir/statements/doWhileStatement.cpp
ir/statements/emptyStatement.cpp
ir/statements/expressionStatement.cpp
ir/statements/forInStatement.cpp
ir/statements/forOfStatement.cpp
ir/statements/forUpdateStatement.cpp
ir/statements/functionDeclaration.cpp
ir/statements/ifStatement.cpp
ir/statements/labelledStatement.cpp
ir/statements/loopStatement.cpp
ir/statements/returnStatement.cpp
ir/statements/switchCaseStatement.cpp
ir/statements/switchStatement.cpp
ir/statements/throwStatement.cpp
ir/statements/tryStatement.cpp
ir/statements/variableDeclaration.cpp
ir/statements/variableDeclarator.cpp
ir/statements/whileStatement.cpp
ir/ts/tsAnyKeyword.cpp
ir/ts/tsArrayType.cpp
ir/ts/tsAsExpression.cpp
ir/ts/tsBigintKeyword.cpp
ir/ts/tsBooleanKeyword.cpp
ir/ts/tsClassImplements.cpp
ir/ts/tsConditionalType.cpp
ir/ts/tsConstructorType.cpp
ir/ts/tsEnumDeclaration.cpp
ir/ts/tsEnumMember.cpp
ir/ts/tsExternalModuleReference.cpp
ir/ts/tsFunctionType.cpp
ir/ts/tsImportEqualsDeclaration.cpp
ir/ts/tsImportType.cpp
ir/ts/tsIndexSignature.cpp
ir/ts/tsIndexedAccessType.cpp
ir/ts/tsInferType.cpp
ir/ts/tsInterfaceBody.cpp
ir/ts/tsInterfaceDeclaration.cpp
ir/ts/tsInterfaceHeritage.cpp
ir/ts/tsIntersectionType.cpp
ir/ts/tsLiteralType.cpp
ir/ts/tsMappedType.cpp
ir/ts/tsMethodSignature.cpp
ir/ts/tsModuleBlock.cpp
ir/ts/tsModuleDeclaration.cpp
ir/ts/tsNamedTupleMember.cpp
ir/ts/tsNeverKeyword.cpp
ir/ts/tsNonNullExpression.cpp
ir/ts/tsNullKeyword.cpp
ir/ts/tsNumberKeyword.cpp
ir/ts/tsObjectKeyword.cpp
ir/ts/tsParameterProperty.cpp
ir/ts/tsParenthesizedType.cpp
ir/ts/tsPrivateIdentifier.cpp
ir/ts/tsPropertySignature.cpp
ir/ts/tsQualifiedName.cpp
ir/ts/tsSignatureDeclaration.cpp
ir/ts/tsStringKeyword.cpp
ir/ts/tsThisType.cpp
ir/ts/tsTupleType.cpp
ir/ts/tsTypeAliasDeclaration.cpp
ir/ts/tsTypeAssertion.cpp
ir/ts/tsTypeLiteral.cpp
ir/ts/tsTypeOperator.cpp
ir/ts/tsTypeParameter.cpp
ir/ts/tsTypeParameterDeclaration.cpp
ir/ts/tsTypeParameterInstantiation.cpp
ir/ts/tsTypePredicate.cpp
ir/ts/tsTypeQuery.cpp
ir/ts/tsTypeReference.cpp
ir/ts/tsUndefinedKeyword.cpp
ir/ts/tsUnionType.cpp
ir/ts/tsUnknownKeyword.cpp
ir/ts/tsVoidKeyword.cpp
lexer/keywordsUtil.cpp
lexer/lexer.cpp
lexer/regexp/regexp.cpp
lexer/token/sourceLocation.cpp
lexer/token/token.cpp
parser/context/parserContext.cpp
parser/expressionParser.cpp
parser/parserImpl.cpp
parser/program/program.cpp
parser/statementParser.cpp
typescript/checker.cpp
typescript/core/binaryLikeExpression.cpp
typescript/core/destructuring.cpp
typescript/core/function.cpp
typescript/core/generics.cpp
typescript/core/helpers.cpp
typescript/core/object.cpp
typescript/core/typeCreation.cpp
typescript/core/typeElaboration.cpp
typescript/core/typeRelation.cpp
typescript/core/util.cpp
typescript/types/anyType.cpp
typescript/types/arrayType.cpp
typescript/types/bigintLiteralType.cpp
typescript/types/bigintType.cpp
typescript/types/booleanLiteralType.cpp
typescript/types/booleanType.cpp
typescript/types/constructorType.cpp
typescript/types/enumLiteralType.cpp
typescript/types/enumType.cpp
typescript/types/functionType.cpp
typescript/types/globalTypesHolder.cpp
typescript/types/indexInfo.cpp
typescript/types/interfaceType.cpp
typescript/types/neverType.cpp
typescript/types/nonPrimitiveType.cpp
typescript/types/nullType.cpp
typescript/types/numberLiteralType.cpp
typescript/types/numberType.cpp
typescript/types/objectDescriptor.cpp
typescript/types/objectLiteralType.cpp
typescript/types/objectType.cpp
typescript/types/signature.cpp
typescript/types/stringLiteralType.cpp
typescript/types/stringType.cpp
typescript/types/tupleType.cpp
typescript/types/type.cpp
typescript/types/typeParameter.cpp
typescript/types/typeReference.cpp
typescript/types/typeRelation.cpp
typescript/types/undefinedType.cpp
typescript/types/unionType.cpp
typescript/types/unknownType.cpp
typescript/types/voidType.cpp
util/bitset.cpp
util/helpers.cpp
util/ustring.cpp
)
add_library(es2panda-lib ${PANDA_DEFAULT_LIB_TYPE} ${ES2PANDA_LIB_SRC})
add_dependencies(es2panda-lib es2panda-gen)
set(ICU_INCLUDE_DIRS
${PANDA_THIRD_PARTY_SOURCES_DIR}/icu/icu4c/source/common
${PANDA_THIRD_PARTY_SOURCES_DIR}/icu/icu4c/source/i18n
${PANDA_THIRD_PARTY_SOURCES_DIR}/icu/icu4c/source
)
target_include_directories(es2panda-lib
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${OUTPUT_DIR}
PRIVATE ${ICU_INCLUDE_DIRS}
)
target_compile_options(es2panda-lib
PRIVATE -fexceptions -Werror=shadow
)
target_link_libraries(es2panda-lib
PUBLIC arkbase hmicuuc.z
PRIVATE arkassembler
)
if (PANDA_FUZZILLI)
target_compile_options(es2panda-lib
PRIVATE -fPIC
)
endif()
panda_add_sanitizers(TARGET es2panda-lib SANITIZERS ${PANDA_SANITIZERS_LIST})
panda_add_to_clang_tidy(TARGET es2panda-lib CHECKS
"-modernize-use-trailing-return-type"
"-llvmlibc-restrict-system-libc-headers"
"-llvmlibc-callee-namespace"
"-cert-dcl21-cpp"
"-cppcoreguidelines-macro-usage"
"-cppcoreguidelines-pro-bounds-pointer-arithmetic"
"-fuchsia-default-arguments-calls"
"-fuchsia-default-arguments-declarations"
"-readability-implicit-bool-conversion"
"-misc-non-private-member-variables-in-classes"
"-hicpp-signed-bitwise"
"-altera-struct-pack-align"
)
add_subdirectory(aot)
+43
View File
@@ -0,0 +1,43 @@
# Es2panda
All in one JavaScript/TypeScript parser and compiler.
## Usage
```sh
es2panda [OPTIONS] [input file] -- [arguments]
```
## Optional arguments
- `--debug-info`: Compile with debug info
- `--dump-assembly`: Dump pandasm
- `--dump-ast`: Dump the parsed AST
- `--dump-debug-info`: Dump debug info
- `--dump-size-stat`: Dump binary size statistics
- `--extension`: Parse the input as the given extension (options: js | ts | as)
- `--module`: Parse the input as module
- `--opt-level`: Compiler optimization level (options: 0 | 1 | 2)
- `--output`: Compiler binary output (.abc)
- `--parse-only`: Parse the input only
- `--strict`: Parse the input in strict mode
## Tail arguments
- `input`: input file
## Running the tests
```sh
pip install tqdm
```
```sh
python3 test/runner.py [OPTIONS] [build_directory]
```
### Optional arguments
- `--regression`: Run regression tests
- `--test262`: Run test262
- `--no-progress`: Don't show progress bar
### Tail arguments
- `build_directory`: Path to panda build directory
### Skip list
Skip list for the runtime: `test/test262skiplist.txt, test/test262skiplist-long.txt`.
+47
View File
@@ -0,0 +1,47 @@
# 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.
set(ES2PANDA_AOT_SRC
options.cpp
main.cpp
)
panda_add_executable(es2panda ${ES2PANDA_AOT_SRC})
target_link_libraries(es2panda es2panda-lib arkassembler arkbytecodeopt)
target_include_directories(es2panda PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
if (PANDA_FUZZILLI)
target_compile_options(es2panda
PRIVATE -fPIC
)
endif()
target_compile_options(es2panda
PRIVATE -Werror=shadow
)
panda_add_sanitizers(TARGET es2panda SANITIZERS ${PANDA_SANITIZERS_LIST})
panda_add_to_clang_tidy(TARGET es2panda CHECKS
"-modernize-use-trailing-return-type"
"-llvmlibc-restrict-system-libc-headers"
"-llvmlibc-callee-namespace"
"-cert-dcl21-cpp"
"-cppcoreguidelines-macro-usage"
"-cppcoreguidelines-pro-bounds-pointer-arithmetic"
"-fuchsia-default-arguments-calls"
"-fuchsia-default-arguments-declarations"
"-readability-implicit-bool-conversion"
"-misc-non-private-member-variables-in-classes"
"-hicpp-signed-bitwise"
"-altera-struct-pack-align"
)
+146
View File
@@ -0,0 +1,146 @@
/**
* 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 <assembly-literals.h>
#include <bytecode_optimizer/bytecodeopt_options.h>
#include <bytecode_optimizer/optimize_bytecode.h>
#include <mem/arena_allocator.h>
#include <mem/pool_manager.h>
#include <options.h>
#include <plugins/ecmascript/es2panda/es2panda.h>
#include <iostream>
#include <memory>
namespace panda::es2panda::aot {
using mem::MemConfig;
class MemManager {
public:
explicit MemManager()
{
constexpr auto COMPILER_SIZE = 128_MB;
MemConfig::Initialize(0, 0, COMPILER_SIZE, 0);
PoolManager::Initialize(PoolType::MMAP);
}
NO_COPY_SEMANTIC(MemManager);
NO_MOVE_SEMANTIC(MemManager);
~MemManager()
{
PoolManager::Finalize();
MemConfig::Finalize();
}
};
static int GenerateProgram(panda::pandasm::Program *prog, const std::string &output, int optLevel, bool dumpAsm,
bool dumpSize)
{
std::map<std::string, size_t> stat;
std::map<std::string, size_t> *statp = optLevel != 0 ? &stat : nullptr;
panda::pandasm::AsmEmitter::PandaFileToPandaAsmMaps maps {};
panda::pandasm::AsmEmitter::PandaFileToPandaAsmMaps *mapsp = optLevel != 0 ? &maps : nullptr;
#ifdef PANDA_WITH_BYTECODE_OPTIMIZER
if (optLevel != 0) {
const uint32_t COMPONENT_MASK = panda::Logger::Component::ASSEMBLER |
panda::Logger::Component::BYTECODE_OPTIMIZER |
panda::Logger::Component::COMPILER;
panda::Logger::InitializeStdLogging(panda::Logger::Level::ERROR, COMPONENT_MASK);
if (!panda::pandasm::AsmEmitter::Emit(output, *prog, statp, mapsp, true)) {
return 1;
}
panda::bytecodeopt::options.SetOptLevel(optLevel);
panda::bytecodeopt::OptimizeBytecode(prog, mapsp, output, true, true);
}
#endif
if (dumpAsm) {
es2panda::Compiler::DumpAsm(prog);
}
if (!panda::pandasm::AsmEmitter::Emit(output, *prog, statp, mapsp, true)) {
return 1;
}
if (dumpSize && optLevel != 0) {
size_t totalSize = 0;
std::cout << "Panda file size statistic:" << std::endl;
constexpr std::array<std::string_view, 2> INFO_STATS = {"instructions_number", "codesize"};
for (const auto &[name, size] : stat) {
if (find(INFO_STATS.begin(), INFO_STATS.end(), name) != INFO_STATS.end()) {
continue;
}
std::cout << name << " section: " << size << std::endl;
totalSize += size;
}
for (const auto &name : INFO_STATS) {
std::cout << name << ": " << stat.at(std::string(name)) << std::endl;
}
std::cout << "total: " << totalSize << std::endl;
}
return 0;
}
int Run(int argc, const char **argv)
{
auto options = std::make_unique<Options>();
if (!options->Parse(argc, argv)) {
std::cerr << options->ErrorMsg() << std::endl;
return 1;
}
es2panda::Compiler compiler(options->Extension(), options->ThreadCount());
es2panda::SourceFile input(options->SourceFile(), options->ParserInput(), options->ParseModule());
auto *program = compiler.Compile(input, options->CompilerOptions());
if (!program) {
const auto &err = compiler.GetError();
if (err.Message().empty() && options->ParseOnly()) {
return 0;
}
std::cout << err.TypeString() << ": " << err.Message();
std::cout << " [" << options->SourceFile() << ":" << err.Line() << ":" << err.Col() << "]" << std::endl;
return err.ErrorCode();
}
GenerateProgram(program, options->CompilerOutput(), options->OptLevel(), options->CompilerOptions().dumpAsm,
options->SizeStat());
delete program;
return 0;
}
} // namespace panda::es2panda::aot
int main(int argc, const char **argv)
{
panda::es2panda::aot::MemManager mm;
return panda::es2panda::aot::Run(argc, argv);
}
+163
View File
@@ -0,0 +1,163 @@
/*
* 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 "options.h"
#include <utils/pandargs.h>
#include <utility>
namespace panda::es2panda::aot {
template <class T>
T BaseName(T const &path, T const &delims = "/")
{
return path.substr(path.find_last_of(delims) + 1);
}
template <class T>
T RemoveExtension(T const &filename)
{
typename T::size_type const P(filename.find_last_of('.'));
return P > 0 && P != T::npos ? filename.substr(0, P) : filename;
}
// Options
Options::Options() : argparser_(new panda::PandArgParser()) {}
Options::~Options()
{
delete argparser_;
}
bool Options::Parse(int argc, const char **argv)
{
panda::PandArg<bool> opHelp("help", false, "Print this message and exit");
// parser
panda::PandArg<std::string> inputExtension("extension", "js",
"Parse the input as the given extension (options: js | ts | as)");
panda::PandArg<bool> opModule("module", false, "Parse the input as module");
panda::PandArg<bool> opParseOnly("parse-only", false, "Parse the input only");
panda::PandArg<bool> opDumpAst("dump-ast", false, "Dump the parsed AST");
// compiler
panda::PandArg<bool> opDumpAssembly("dump-assembly", false, "Dump pandasm");
panda::PandArg<bool> opDebugInfo("debug-info", false, "Compile with debug info");
panda::PandArg<bool> opDumpDebugInfo("dump-debug-info", false, "Dump debug info");
panda::PandArg<int> opOptLevel("opt-level", 0, "Compiler optimization level (options: 0 | 1 | 2)");
panda::PandArg<int> opThreadCount("thread", 0, "Number of worker theads");
panda::PandArg<bool> opSizeStat("dump-size-stat", false, "Dump size statistics");
panda::PandArg<std::string> outputFile("output", "", "Compiler binary output (.abc)");
// tail arguments
panda::PandArg<std::string> inputFile("input", "", "input file");
argparser_->Add(&opHelp);
argparser_->Add(&opModule);
argparser_->Add(&opDumpAst);
argparser_->Add(&opParseOnly);
argparser_->Add(&opDumpAssembly);
argparser_->Add(&opDebugInfo);
argparser_->Add(&opDumpDebugInfo);
argparser_->Add(&opOptLevel);
argparser_->Add(&opThreadCount);
argparser_->Add(&opSizeStat);
argparser_->Add(&inputExtension);
argparser_->Add(&outputFile);
argparser_->PushBackTail(&inputFile);
argparser_->EnableTail();
argparser_->EnableRemainder();
if (!argparser_->Parse(argc, argv) || inputFile.GetValue().empty() || opHelp.GetValue()) {
std::stringstream ss;
ss << argparser_->GetErrorString() << std::endl;
ss << "Usage: "
<< "es2panda"
<< " [OPTIONS] [input file] -- [arguments]" << std::endl;
ss << std::endl;
ss << "optional arguments:" << std::endl;
ss << argparser_->GetHelpString() << std::endl;
errorMsg_ = ss.str();
return false;
}
sourceFile_ = inputFile.GetValue();
std::ifstream inputStream(sourceFile_.c_str());
if (inputStream.fail()) {
errorMsg_ = "Failed to open file: ";
errorMsg_.append(sourceFile_);
return false;
}
std::stringstream ss;
ss << inputStream.rdbuf();
parserInput_ = ss.str();
sourceFile_ = BaseName(sourceFile_);
if (!outputFile.GetValue().empty()) {
compilerOutput_ = outputFile.GetValue();
} else {
compilerOutput_ = RemoveExtension(sourceFile_).append(".abc");
}
std::string extension = inputExtension.GetValue();
if (!extension.empty()) {
if (extension == "js") {
extension_ = es2panda::ScriptExtension::JS;
} else if (extension == "ts") {
extension_ = es2panda::ScriptExtension::TS;
} else if (extension == "as") {
extension_ = es2panda::ScriptExtension::AS;
} else {
errorMsg_ = "Invalid extension (available options: js, ts, as)";
return false;
}
}
optLevel_ = opOptLevel.GetValue();
threadCount_ = opThreadCount.GetValue();
if (opParseOnly.GetValue()) {
options_ |= OptionFlags::PARSE_ONLY;
}
if (opModule.GetValue()) {
options_ |= OptionFlags::PARSE_MODULE;
}
if (opSizeStat.GetValue()) {
options_ |= OptionFlags::SIZE_STAT;
}
compilerOptions_.dumpAsm = opDumpAssembly.GetValue();
compilerOptions_.dumpAst = opDumpAst.GetValue();
compilerOptions_.dumpDebugInfo = opDumpDebugInfo.GetValue();
compilerOptions_.isDebug = opDebugInfo.GetValue();
compilerOptions_.parseOnly = opParseOnly.GetValue();
return true;
}
} // namespace panda::es2panda::aot
+134
View File
@@ -0,0 +1,134 @@
/**
* 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.
*/
#ifndef ES2PANDA_AOT_OPTIONS_H
#define ES2PANDA_AOT_OPTIONS_H
#include <macros.h>
#include <plugins/ecmascript/es2panda/es2panda.h>
#include <exception>
#include <fstream>
#include <iostream>
namespace panda {
class PandArgParser;
class PandaArg;
} // namespace panda
namespace panda::es2panda::aot {
enum class OptionFlags {
DEFAULT = 0,
PARSE_ONLY = 1 << 1,
PARSE_MODULE = 1 << 2,
SIZE_STAT = 1 << 3,
};
inline std::underlying_type_t<OptionFlags> operator&(OptionFlags a, OptionFlags b)
{
using utype = std::underlying_type_t<OptionFlags>;
/* NOLINTNEXTLINE(hicpp-signed-bitwise) */
return static_cast<utype>(static_cast<utype>(a) & static_cast<utype>(b));
}
inline OptionFlags &operator|=(OptionFlags &a, OptionFlags b)
{
using utype = std::underlying_type_t<OptionFlags>;
/* NOLINTNEXTLINE(hicpp-signed-bitwise) */
return a = static_cast<OptionFlags>(static_cast<utype>(a) | static_cast<utype>(b));
}
class Options {
public:
Options();
NO_COPY_SEMANTIC(Options);
NO_MOVE_SEMANTIC(Options);
~Options();
bool Parse(int argc, const char **argv);
es2panda::ScriptExtension Extension() const
{
return extension_;
}
const es2panda::CompilerOptions &CompilerOptions() const
{
return compilerOptions_;
}
const std::string &ParserInput() const
{
return parserInput_;
}
const std::string &CompilerOutput() const
{
return compilerOutput_;
}
const std::string &SourceFile() const
{
return sourceFile_;
}
const std::string &ErrorMsg() const
{
return errorMsg_;
}
int OptLevel() const
{
return optLevel_;
}
int ThreadCount() const
{
return threadCount_;
}
bool ParseModule() const
{
return (options_ & OptionFlags::PARSE_MODULE) != 0;
}
bool ParseOnly() const
{
return (options_ & OptionFlags::PARSE_ONLY) != 0;
}
bool SizeStat() const
{
return (options_ & OptionFlags::SIZE_STAT) != 0;
}
private:
es2panda::ScriptExtension extension_ {es2panda::ScriptExtension::JS};
es2panda::CompilerOptions compilerOptions_ {};
OptionFlags options_ {OptionFlags::DEFAULT};
panda::PandArgParser *argparser_;
std::string parserInput_;
std::string compilerOutput_;
std::string result_;
std::string sourceFile_;
std::string errorMsg_;
int optLevel_ {0};
int threadCount_ {0};
};
} // namespace panda::es2panda::aot
#endif // AOT_OPTIONS_H
+509
View File
@@ -0,0 +1,509 @@
/**
* Copyright (c) 2021 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 "binder.h"
#include <util/helpers.h>
#include <binder/scope.h>
#include <binder/tsBinding.h>
#include <es2panda.h>
#include <ir/astNode.h>
#include <ir/base/catchClause.h>
#include <ir/base/classDefinition.h>
#include <ir/base/methodDefinition.h>
#include <ir/base/property.h>
#include <ir/base/scriptFunction.h>
#include <ir/base/spreadElement.h>
#include <ir/expressions/arrayExpression.h>
#include <ir/expressions/assignmentExpression.h>
#include <ir/expressions/identifier.h>
#include <ir/expressions/objectExpression.h>
#include <ir/statements/blockStatement.h>
#include <ir/statements/doWhileStatement.h>
#include <ir/statements/forInStatement.h>
#include <ir/statements/forOfStatement.h>
#include <ir/statements/forUpdateStatement.h>
#include <ir/statements/ifStatement.h>
#include <ir/statements/switchStatement.h>
#include <ir/statements/variableDeclaration.h>
#include <ir/statements/variableDeclarator.h>
#include <ir/statements/whileStatement.h>
namespace panda::es2panda::binder {
void Binder::InitTopScope()
{
if (program_->Kind() == parser::ScriptKind::MODULE) {
topScope_ = Allocator()->New<ModuleScope>(Allocator());
} else {
topScope_ = Allocator()->New<GlobalScope>(Allocator());
}
scope_ = topScope_;
}
ParameterDecl *Binder::AddParamDecl(const ir::AstNode *param)
{
ASSERT(scope_->IsFunctionParamScope() || scope_->IsCatchParamScope());
auto [decl, node] = static_cast<ParamScope *>(scope_)->AddParamDecl(Allocator(), param);
if (!node) {
return decl;
}
ThrowRedeclaration(node->Start(), decl->Name());
}
void Binder::ThrowRedeclaration(const lexer::SourcePosition &pos, const util::StringView &name)
{
lexer::LineIndex index(program_->SourceCode());
lexer::SourceLocation loc = index.GetLocation(pos);
std::stringstream ss;
ss << "Variable '" << name << "' has already been declared.";
throw Error(ErrorType::SYNTAX, ss.str(), loc.line, loc.col);
}
void Binder::IdentifierAnalysis()
{
ASSERT(program_->Ast());
ASSERT(scope_ == topScope_);
BuildFunction(topScope_, "main");
ResolveReferences(program_->Ast());
AddMandatoryParams();
}
void Binder::LookupReference(const util::StringView &name)
{
ScopeFindResult res = scope_->Find(name);
if (res.level == 0) {
return;
}
ASSERT(res.variable);
res.variable->SetLexical(res.scope);
}
void Binder::InstantiateArguments()
{
auto *iter = scope_;
while (true) {
Scope *scope = iter->IsFunctionParamScope() ? iter : iter->EnclosingVariableScope();
const auto *node = scope->Node();
if (scope->IsLoopScope()) {
iter = scope->Parent();
continue;
}
if (!node->IsScriptFunction()) {
break;
}
if (!node->AsScriptFunction()->IsArrow()) {
auto *argumentsVariable =
scope->AddDecl<ConstDecl, LocalVariable>(Allocator(), FUNCTION_ARGUMENTS, VariableFlags::INITIALIZED);
if (iter->IsFunctionParamScope()) {
if (!argumentsVariable) {
break;
}
scope = iter->AsFunctionParamScope()->GetFunctionScope();
scope->Bindings().insert({argumentsVariable->Name(), argumentsVariable});
}
scope->AsVariableScope()->AddFlag(VariableScopeFlags::USE_ARGS);
break;
}
iter = scope->Parent();
}
}
void Binder::LookupIdentReference(ir::Identifier *ident)
{
if (ident->Name().Is(FUNCTION_ARGUMENTS)) {
InstantiateArguments();
}
ScopeFindResult res = scope_->Find(ident->Name());
if (res.level != 0) {
ASSERT(res.variable);
res.variable->SetLexical(res.scope);
}
if (!res.variable) {
return;
}
if (res.variable->Declaration()->IsLetOrConstDecl() && !res.variable->HasFlag(VariableFlags::INITIALIZED)) {
ident->SetTdz();
}
ident->SetVariable(res.variable);
}
void Binder::BuildFunction(FunctionScope *funcScope, util::StringView name)
{
uint32_t idx = functionScopes_.size();
functionScopes_.push_back(funcScope);
std::stringstream ss;
ss << "func_" << name << "_" << std::to_string(idx);
util::UString internalName(ss.str(), Allocator());
funcScope->BindName(name, internalName.View());
}
void Binder::BuildScriptFunction(Scope *outerScope, const ir::ScriptFunction *scriptFunc)
{
if (scriptFunc->IsArrow()) {
VariableScope *outerVarScope = outerScope->EnclosingVariableScope();
outerVarScope->AddFlag(VariableScopeFlags::INNER_ARROW);
}
BuildFunction(scope_->AsFunctionScope(), util::Helpers::FunctionName(scriptFunc));
}
void Binder::BuildVarDeclaratorId(const ir::AstNode *parent, ir::AstNode *childNode)
{
childNode->SetParent(parent);
switch (childNode->Type()) {
case ir::AstNodeType::IDENTIFIER: {
const auto &name = childNode->AsIdentifier()->Name();
if (util::Helpers::IsGlobalIdentifier(childNode->AsIdentifier()->Name())) {
break;
}
auto *variable = scope_->FindLocal(name);
variable->AddFlag(VariableFlags::INITIALIZED);
break;
}
case ir::AstNodeType::OBJECT_PATTERN: {
for (auto *prop : childNode->AsObjectPattern()->Properties()) {
BuildVarDeclaratorId(childNode, prop);
}
break;
}
case ir::AstNodeType::ARRAY_PATTERN: {
for (auto *element : childNode->AsArrayPattern()->Elements()) {
BuildVarDeclaratorId(childNode, element);
}
break;
}
case ir::AstNodeType::ASSIGNMENT_PATTERN: {
ResolveReference(childNode, childNode->AsAssignmentPattern()->Right());
BuildVarDeclaratorId(childNode, childNode->AsAssignmentPattern()->Left());
break;
}
case ir::AstNodeType::PROPERTY: {
ResolveReference(childNode, childNode->AsProperty()->Key());
BuildVarDeclaratorId(childNode, childNode->AsProperty()->Value());
break;
}
case ir::AstNodeType::REST_ELEMENT: {
BuildVarDeclaratorId(childNode, childNode->AsRestElement()->Argument());
break;
}
default:
break;
}
}
void Binder::BuildVarDeclarator(ir::VariableDeclarator *varDecl)
{
if (varDecl->Parent()->AsVariableDeclaration()->Kind() == ir::VariableDeclaration::VariableDeclarationKind::VAR) {
ResolveReferences(varDecl);
return;
}
if (varDecl->Init()) {
ResolveReference(varDecl, varDecl->Init());
}
BuildVarDeclaratorId(varDecl, varDecl->Id());
}
void Binder::BuildClassDefinition(ir::ClassDefinition *classDef)
{
if (classDef->Parent()->IsClassDeclaration()) {
ScopeFindResult res = scope_->Find(classDef->Ident()->Name());
ASSERT(res.variable && res.variable->Declaration()->IsLetDecl());
res.variable->AddFlag(VariableFlags::INITIALIZED);
}
auto scopeCtx = LexicalScope<LocalScope>::Enter(this, classDef->Scope());
if (classDef->Super()) {
ResolveReference(classDef, classDef->Super());
}
if (classDef->Ident()) {
ScopeFindResult res = scope_->Find(classDef->Ident()->Name());
ASSERT(res.variable && res.variable->Declaration()->IsConstDecl());
res.variable->AddFlag(VariableFlags::INITIALIZED);
}
ResolveReference(classDef, classDef->Ctor());
for (auto *stmt : classDef->Body()) {
ResolveReference(classDef, stmt);
}
}
void Binder::BuildForUpdateLoop(ir::ForUpdateStatement *forUpdateStmt)
{
auto *loopScope = forUpdateStmt->Scope();
auto declScopeCtx = LexicalScope<LoopDeclarationScope>::Enter(this, loopScope->DeclScope());
if (forUpdateStmt->Init()) {
ResolveReference(forUpdateStmt, forUpdateStmt->Init());
}
if (forUpdateStmt->Update()) {
ResolveReference(forUpdateStmt, forUpdateStmt->Update());
}
auto loopCtx = LexicalScope<LoopScope>::Enter(this, loopScope);
if (forUpdateStmt->Test()) {
ResolveReference(forUpdateStmt, forUpdateStmt->Test());
}
ResolveReference(forUpdateStmt, forUpdateStmt->Body());
loopCtx.GetScope()->ConvertToVariableScope(Allocator());
}
void Binder::BuildForInOfLoop(const ir::Statement *parent, binder::LoopScope *loopScope, ir::AstNode *left,
ir::Expression *right, ir::Statement *body)
{
auto declScopeCtx = LexicalScope<LoopDeclarationScope>::Enter(this, loopScope->DeclScope());
ResolveReference(parent, right);
ResolveReference(parent, left);
auto loopCtx = LexicalScope<LoopScope>::Enter(this, loopScope);
ResolveReference(parent, body);
loopCtx.GetScope()->ConvertToVariableScope(Allocator());
}
void Binder::BuildCatchClause(ir::CatchClause *catchClauseStmt)
{
if (catchClauseStmt->Param()) {
auto paramScopeCtx = LexicalScope<CatchParamScope>::Enter(this, catchClauseStmt->Scope()->ParamScope());
ResolveReference(catchClauseStmt, catchClauseStmt->Param());
}
auto scopeCtx = LexicalScope<CatchScope>::Enter(this, catchClauseStmt->Scope());
ResolveReference(catchClauseStmt, catchClauseStmt->Body());
}
void Binder::ResolveReference(const ir::AstNode *parent, ir::AstNode *childNode)
{
childNode->SetParent(parent);
switch (childNode->Type()) {
case ir::AstNodeType::IDENTIFIER: {
auto *ident = childNode->AsIdentifier();
if (ident->IsReference()) {
LookupIdentReference(ident);
}
ResolveReferences(childNode);
break;
}
case ir::AstNodeType::SUPER_EXPRESSION: {
VariableScope *varScope = scope_->EnclosingVariableScope();
varScope->AddFlag(VariableScopeFlags::USE_SUPER);
ResolveReferences(childNode);
break;
}
case ir::AstNodeType::SCRIPT_FUNCTION: {
auto *scriptFunc = childNode->AsScriptFunction();
auto *funcScope = scriptFunc->Scope();
auto *outerScope = scope_;
{
auto paramScopeCtx = LexicalScope<FunctionParamScope>::Enter(this, funcScope->ParamScope());
for (auto *param : scriptFunc->Params()) {
ResolveReference(scriptFunc, param);
}
}
auto scopeCtx = LexicalScope<FunctionScope>::Enter(this, funcScope);
BuildScriptFunction(outerScope, scriptFunc);
ResolveReference(scriptFunc, scriptFunc->Body());
break;
}
case ir::AstNodeType::VARIABLE_DECLARATOR: {
BuildVarDeclarator(childNode->AsVariableDeclarator());
break;
}
case ir::AstNodeType::CLASS_DEFINITION: {
BuildClassDefinition(childNode->AsClassDefinition());
break;
}
case ir::AstNodeType::CLASS_PROPERTY: {
const ir::ScriptFunction *ctor = util::Helpers::GetContainingConstructor(childNode->AsClassProperty());
auto scopeCtx = LexicalScope<FunctionScope>::Enter(this, ctor->Scope());
ResolveReferences(childNode);
break;
}
case ir::AstNodeType::BLOCK_STATEMENT: {
auto scopeCtx = LexicalScope<Scope>::Enter(this, childNode->AsBlockStatement()->Scope());
ResolveReferences(childNode);
break;
}
case ir::AstNodeType::SWITCH_STATEMENT: {
auto scopeCtx = LexicalScope<LocalScope>::Enter(this, childNode->AsSwitchStatement()->Scope());
ResolveReferences(childNode);
break;
}
case ir::AstNodeType::DO_WHILE_STATEMENT: {
auto *doWhileStatement = childNode->AsDoWhileStatement();
{
auto loopScopeCtx = LexicalScope<LoopScope>::Enter(this, doWhileStatement->Scope());
ResolveReference(doWhileStatement, doWhileStatement->Body());
}
ResolveReference(doWhileStatement, doWhileStatement->Test());
break;
}
case ir::AstNodeType::WHILE_STATEMENT: {
auto *whileStatement = childNode->AsWhileStatement();
ResolveReference(whileStatement, whileStatement->Test());
auto loopScopeCtx = LexicalScope<LoopScope>::Enter(this, whileStatement->Scope());
ResolveReference(whileStatement, whileStatement->Body());
break;
}
case ir::AstNodeType::FOR_UPDATE_STATEMENT: {
BuildForUpdateLoop(childNode->AsForUpdateStatement());
break;
}
case ir::AstNodeType::FOR_IN_STATEMENT: {
auto *forInStmt = childNode->AsForInStatement();
BuildForInOfLoop(forInStmt, forInStmt->Scope(), forInStmt->Left(), forInStmt->Right(), forInStmt->Body());
break;
}
case ir::AstNodeType::FOR_OF_STATEMENT: {
auto *forOfStmt = childNode->AsForOfStatement();
BuildForInOfLoop(forOfStmt, forOfStmt->Scope(), forOfStmt->Left(), forOfStmt->Right(), forOfStmt->Body());
break;
}
case ir::AstNodeType::CATCH_CLAUSE: {
BuildCatchClause(childNode->AsCatchClause());
break;
}
default: {
ResolveReferences(childNode);
break;
}
}
}
void Binder::ResolveReferences(const ir::AstNode *parent)
{
parent->Iterate([this, parent](auto *childNode) { ResolveReference(parent, childNode); });
}
void Binder::AddMandatoryParam(const std::string_view &name)
{
ASSERT(scope_->IsFunctionVariableScope());
auto *decl = Allocator()->New<ParameterDecl>(name);
auto *param = Allocator()->New<LocalVariable>(decl, VariableFlags::VAR);
auto &funcParams = scope_->AsFunctionVariableScope()->ParamScope()->Params();
funcParams.insert(funcParams.begin(), param);
scope_->AsFunctionVariableScope()->Bindings().insert({decl->Name(), param});
}
void Binder::AddMandatoryParams(const MandatoryParams &params)
{
for (auto iter = params.rbegin(); iter != params.rend(); iter++) {
AddMandatoryParam(*iter);
}
}
void Binder::AddMandatoryParams()
{
ASSERT(scope_ == topScope_);
ASSERT(!functionScopes_.empty());
auto iter = functionScopes_.begin();
[[maybe_unused]] auto *funcScope = *iter++;
ASSERT(funcScope->IsGlobalScope() || funcScope->IsModuleScope());
AddMandatoryParams(FUNCTION_MANDATORY_PARAMS);
for (; iter != functionScopes_.end(); iter++) {
funcScope = *iter;
const auto *scriptFunc = funcScope->Node()->AsScriptFunction();
auto scopeCtx = LexicalScope<FunctionScope>::Enter(this, funcScope);
if (!scriptFunc->IsArrow()) {
AddMandatoryParams(FUNCTION_MANDATORY_PARAMS);
continue;
}
const ir::ScriptFunction *ctor = util::Helpers::GetContainingConstructor(scriptFunc);
bool lexicalFunctionObject {};
if (ctor && util::Helpers::GetClassDefiniton(ctor)->Super() &&
funcScope->HasFlag(VariableScopeFlags::USE_SUPER)) {
ASSERT(ctor->Scope()->HasFlag(VariableScopeFlags::INNER_ARROW));
ctor->Scope()->AddFlag(VariableScopeFlags::SET_LEXICAL_FUNCTION);
lexicalFunctionObject = true;
AddMandatoryParams(CTOR_ARROW_MANDATORY_PARAMS);
} else {
AddMandatoryParams(ARROW_MANDATORY_PARAMS);
}
LookupReference(MANDATORY_PARAM_NEW_TARGET);
LookupReference(MANDATORY_PARAM_THIS);
if (funcScope->HasFlag(VariableScopeFlags::USE_ARGS)) {
LookupReference(FUNCTION_ARGUMENTS);
}
if (lexicalFunctionObject) {
LookupReference(MANDATORY_PARAM_FUNC);
}
}
}
} // namespace panda::es2panda::binder
+210
View File
@@ -0,0 +1,210 @@
/**
* Copyright (c) 2021 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.
*/
#ifndef ES2PANDA_BINDER_BINDER_H
#define ES2PANDA_BINDER_BINDER_H
#include <binder/scope.h>
#include <binder/variableFlags.h>
#include <lexer/token/sourceLocation.h>
#include <macros.h>
#include <parser/program/program.h>
namespace panda::es2panda::ir {
class AstNode;
class BlockStatement;
class CatchClause;
class ClassDefinition;
class Expression;
class ForUpdateStatement;
class Identifier;
class ScriptFunction;
class Statement;
class VariableDeclarator;
} // namespace panda::es2panda::ir
namespace panda::es2panda::binder {
class Scope;
class VariableScope;
class Binder {
public:
explicit Binder(parser::Program *program) : program_(program), functionScopes_(Allocator()->Adapter()) {}
NO_COPY_SEMANTIC(Binder);
DEFAULT_MOVE_SEMANTIC(Binder);
~Binder() = default;
void InitTopScope();
void IdentifierAnalysis();
template <typename T, typename... Args>
T *AddDecl(const lexer::SourcePosition &pos, Args &&... args);
template <typename T, typename... Args>
T *AddTsDecl(const lexer::SourcePosition &pos, Args &&... args);
ParameterDecl *AddParamDecl(const ir::AstNode *param);
Scope *GetScope() const
{
return scope_;
}
GlobalScope *TopScope() const
{
return topScope_;
}
[[noreturn]] void ThrowRedeclaration(const lexer::SourcePosition &pos, const util::StringView &name);
template <typename T>
friend class LexicalScope;
inline ArenaAllocator *Allocator() const
{
return program_->Allocator();
}
const ArenaVector<FunctionScope *> &Functions() const
{
return functionScopes_;
}
ArenaVector<FunctionScope *> Functions()
{
return functionScopes_;
}
const parser::Program *Program() const
{
return program_;
}
static constexpr std::string_view FUNCTION_ARGUMENTS = "arguments";
static constexpr std::string_view MANDATORY_PARAM_FUNC = "=f";
static constexpr std::string_view MANDATORY_PARAM_NEW_TARGET = "=nt";
static constexpr std::string_view MANDATORY_PARAM_THIS = "=t";
static constexpr uint32_t MANDATORY_PARAM_FUNC_REG = 0;
static constexpr uint32_t MANDATORY_PARAMS_NUMBER = 3;
static constexpr std::string_view LEXICAL_MANDATORY_PARAM_FUNC = "!f";
static constexpr std::string_view LEXICAL_MANDATORY_PARAM_NEW_TARGET = "!nt";
static constexpr std::string_view LEXICAL_MANDATORY_PARAM_THIS = "!t";
private:
using MandatoryParams = std::array<std::string_view, MANDATORY_PARAMS_NUMBER>;
static constexpr MandatoryParams FUNCTION_MANDATORY_PARAMS = {MANDATORY_PARAM_FUNC, MANDATORY_PARAM_NEW_TARGET,
MANDATORY_PARAM_THIS};
static constexpr MandatoryParams ARROW_MANDATORY_PARAMS = {MANDATORY_PARAM_FUNC, LEXICAL_MANDATORY_PARAM_NEW_TARGET,
LEXICAL_MANDATORY_PARAM_THIS};
static constexpr MandatoryParams CTOR_ARROW_MANDATORY_PARAMS = {
LEXICAL_MANDATORY_PARAM_FUNC, LEXICAL_MANDATORY_PARAM_NEW_TARGET, LEXICAL_MANDATORY_PARAM_THIS};
void AddMandatoryParam(const std::string_view &name);
void AddMandatoryParams(const MandatoryParams &params);
void AddMandatoryParams();
void BuildFunction(FunctionScope *funcScope, util::StringView name);
void BuildScriptFunction(Scope *outerScope, const ir::ScriptFunction *scriptFunc);
void BuildClassDefinition(ir::ClassDefinition *classDef);
void LookupReference(const util::StringView &name);
void InstantiateArguments();
void BuildVarDeclarator(ir::VariableDeclarator *varDecl);
void BuildVarDeclaratorId(const ir::AstNode *parent, ir::AstNode *childNode);
void BuildForUpdateLoop(ir::ForUpdateStatement *forUpdateStmt);
void BuildForInOfLoop(const ir::Statement *parent, binder::LoopScope *loopScope, ir::AstNode *left,
ir::Expression *right, ir::Statement *body);
void BuildCatchClause(ir::CatchClause *catchClauseStmt);
void LookupIdentReference(ir::Identifier *ident);
void ResolveReference(const ir::AstNode *parent, ir::AstNode *childNode);
void ResolveReferences(const ir::AstNode *parent);
parser::Program *program_ {};
GlobalScope *topScope_ {};
Scope *scope_ {};
ArenaVector<FunctionScope *> functionScopes_;
};
template <typename T>
class LexicalScope {
public:
template <typename... Args>
explicit LexicalScope(Binder *binder, Args &&... args)
: LexicalScope(binder->Allocator()->New<T>(binder->Allocator(), binder->scope_, std::forward<Args>(args)...),
binder)
{
}
T *GetScope() const
{
return scope_;
}
~LexicalScope()
{
ASSERT(binder_);
binder_->scope_ = prevScope_;
}
[[nodiscard]] static LexicalScope<T> Enter(Binder *binder, T *scope)
{
LexicalScope<T> lexScope(scope, binder);
return lexScope;
}
DEFAULT_MOVE_SEMANTIC(LexicalScope);
private:
NO_COPY_SEMANTIC(LexicalScope);
explicit LexicalScope(T *scope, Binder *binder) : binder_(binder), scope_(scope), prevScope_(binder->scope_)
{
binder_->scope_ = scope_;
}
Binder *binder_ {};
T *scope_ {};
Scope *prevScope_ {};
};
template <typename T, typename... Args>
T *Binder::AddTsDecl(const lexer::SourcePosition &pos, Args &&... args)
{
T *decl = Allocator()->New<T>(std::forward<Args>(args)...);
if (scope_->AddTsDecl(Allocator(), decl, program_->Extension())) {
return decl;
}
ThrowRedeclaration(pos, decl->Name());
}
template <typename T, typename... Args>
T *Binder::AddDecl(const lexer::SourcePosition &pos, Args &&... args)
{
T *decl = Allocator()->New<T>(std::forward<Args>(args)...);
if (scope_->AddDecl(Allocator(), decl, program_->Extension())) {
return decl;
}
ThrowRedeclaration(pos, decl->Name());
}
} // namespace panda::es2panda::binder
#endif
+20
View File
@@ -0,0 +1,20 @@
/**
* 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 "declaration.h"
namespace panda::es2panda::binder {
} // namespace panda::es2panda::binder
+313
View File
@@ -0,0 +1,313 @@
/**
* Copyright (c) 2021 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.
*/
#ifndef ES2PANDA_COMPILER_SCOPES_DECLARATION_H
#define ES2PANDA_COMPILER_SCOPES_DECLARATION_H
#include <binder/variableFlags.h>
#include <macros.h>
#include <util/ustring.h>
namespace panda::es2panda::ir {
class AstNode;
class FunctionDeclaration;
class TSInterfaceDeclaration;
class ImportDeclaration;
} // namespace panda::es2panda::ir
namespace panda::es2panda::binder {
class Scope;
class LocalScope;
#define DECLARE_CLASSES(decl_kind, className) class className;
DECLARATION_KINDS(DECLARE_CLASSES)
#undef DECLARE_CLASSES
class Decl {
public:
virtual ~Decl() = default;
NO_COPY_SEMANTIC(Decl);
NO_MOVE_SEMANTIC(Decl);
virtual DeclType Type() const = 0;
const util::StringView &Name() const
{
return name_;
}
const ir::AstNode *Node() const
{
return node_;
}
#define DECLARE_CHECKS_CASTS(declKind, className) \
bool Is##className() const \
{ \
return Type() == DeclType::declKind; \
} \
className *As##className() \
{ \
ASSERT(Is##className()); \
return reinterpret_cast<className *>(this); \
} \
const className *As##className() const \
{ \
ASSERT(Is##className()); \
return reinterpret_cast<const className *>(this); \
}
DECLARATION_KINDS(DECLARE_CHECKS_CASTS)
#undef DECLARE_CHECKS_CASTS
void BindNode(const ir::AstNode *node)
{
node_ = node;
}
bool IsLetOrConstDecl() const
{
return IsLetDecl() || IsConstDecl();
}
protected:
explicit Decl(util::StringView name) : name_(name) {}
util::StringView name_;
const ir::AstNode *node_ {};
};
template <typename T>
class MultiDecl : public Decl {
public:
explicit MultiDecl(ArenaAllocator *allocator, util::StringView name)
: Decl(name), declarations_(allocator->Adapter())
{
}
const ArenaVector<T *> &Decls() const
{
return declarations_;
}
void Add(T *decl)
{
declarations_.push_back(decl);
}
private:
ArenaVector<T *> declarations_;
};
class EnumLiteralDecl : public Decl {
public:
explicit EnumLiteralDecl(util::StringView name, bool isConst) : Decl(name), isConst_(isConst) {}
DeclType Type() const override
{
return DeclType::ENUM_LITERAL;
}
bool IsConst() const
{
return isConst_;
}
void BindScope(LocalScope *scope)
{
scope_ = scope;
}
LocalScope *Scope()
{
return scope_;
}
private:
LocalScope *scope_ {};
bool isConst_ {};
};
class InterfaceDecl : public MultiDecl<ir::TSInterfaceDeclaration> {
public:
explicit InterfaceDecl(ArenaAllocator *allocator, util::StringView name) : MultiDecl(allocator, name) {}
DeclType Type() const override
{
return DeclType::INTERFACE;
}
};
class FunctionDecl : public MultiDecl<ir::FunctionDeclaration> {
public:
explicit FunctionDecl(ArenaAllocator *allocator, util::StringView name, const ir::AstNode *node)
: MultiDecl(allocator, name)
{
node_ = node;
}
DeclType Type() const override
{
return DeclType::FUNC;
}
};
class TypeParameterDecl : public Decl {
public:
explicit TypeParameterDecl(util::StringView name, const ir::AstNode *node);
DeclType Type() const override
{
return DeclType::TYPE_PARAMETER;
}
};
class EnumDecl : public Decl {
public:
explicit EnumDecl(util::StringView name) : Decl(name) {}
DeclType Type() const override
{
return DeclType::ENUM;
}
};
class TypeAliasDecl : public Decl {
public:
explicit TypeAliasDecl(util::StringView name) : Decl(name) {}
DeclType Type() const override
{
return DeclType::TYPE_ALIAS;
}
};
class NameSpaceDecl : public Decl {
public:
explicit NameSpaceDecl(util::StringView name) : Decl(name) {}
DeclType Type() const override
{
return DeclType::NAMESPACE;
}
};
class VarDecl : public Decl {
public:
explicit VarDecl(util::StringView name) : Decl(name) {}
DeclType Type() const override
{
return DeclType::VAR;
}
};
class LetDecl : public Decl {
public:
explicit LetDecl(util::StringView name) : Decl(name) {}
DeclType Type() const override
{
return DeclType::LET;
}
};
class ConstDecl : public Decl {
public:
explicit ConstDecl(util::StringView name) : Decl(name) {}
DeclType Type() const override
{
return DeclType::CONST;
}
};
class ParameterDecl : public Decl {
public:
explicit ParameterDecl(util::StringView name) : Decl(name) {}
DeclType Type() const override
{
return DeclType::PARAM;
}
};
class ImportDecl : public Decl {
public:
explicit ImportDecl(util::StringView importName, util::StringView localName)
: Decl(localName), importName_(importName)
{
}
explicit ImportDecl(util::StringView importName, util::StringView localName, const ir::AstNode *node)
: Decl(localName), importName_(importName)
{
BindNode(node);
}
const util::StringView &ImportName() const
{
return importName_;
}
const util::StringView &LocalName() const
{
return name_;
}
DeclType Type() const override
{
return DeclType::IMPORT;
}
private:
util::StringView importName_;
};
class ExportDecl : public Decl {
public:
explicit ExportDecl(util::StringView exportName, util::StringView localName)
: Decl(localName), exportName_(exportName)
{
}
explicit ExportDecl(util::StringView exportName, util::StringView localName, const ir::AstNode *node)
: Decl(localName), exportName_(exportName)
{
BindNode(node);
}
const util::StringView &ExportName() const
{
return exportName_;
}
const util::StringView &LocalName() const
{
return name_;
}
DeclType Type() const override
{
return DeclType::EXPORT;
}
private:
util::StringView exportName_;
};
} // namespace panda::es2panda::binder
#endif
+30
View File
@@ -0,0 +1,30 @@
/**
* 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.
*/
#ifndef ES2PANDA_COMPILER_SCOPES_ENUM_MEMBER_RESULT_H
#define ES2PANDA_COMPILER_SCOPES_ENUM_MEMBER_RESULT_H
#include <util/ustring.h>
#include <variant>
namespace panda::es2panda::binder {
// Note: if the bool operand is present, the expression cannot be evaluated during compliation
using EnumMemberResult = std::variant<double, util::StringView, bool>;
} // namespace panda::es2panda::binder
#endif
+505
View File
@@ -0,0 +1,505 @@
/**
* Copyright (c) 2021 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 "scope.h"
#include <binder/declaration.h>
#include <util/helpers.h>
#include <binder/tsBinding.h>
#include <binder/variable.h>
#include <binder/variableFlags.h>
#include <ir/astNode.h>
#include <ir/expressions/identifier.h>
#include <ir/module/exportAllDeclaration.h>
#include <ir/module/exportNamedDeclaration.h>
#include <ir/module/exportSpecifier.h>
#include <ir/module/importDeclaration.h>
#include <macros.h>
#include <util/ustring.h>
#include <algorithm>
#include <sstream>
namespace panda::es2panda::binder {
VariableScope *Scope::EnclosingVariableScope()
{
Scope *iter = this;
while (iter) {
if (iter->IsVariableScope()) {
return iter->AsVariableScope();
}
iter = iter->Parent();
}
return nullptr;
}
Variable *Scope::FindLocal(const util::StringView &name, ResolveBindingOptions options) const
{
if (options & ResolveBindingOptions::INTERFACES) {
util::StringView interfaceNameView(binder::TSBinding::ToTSBinding(name));
auto res = bindings_.find(interfaceNameView);
if (res != bindings_.end()) {
return res->second;
}
if (!(options & ResolveBindingOptions::BINDINGS)) {
return nullptr;
}
}
auto res = bindings_.find(name);
if (res == bindings_.end()) {
return nullptr;
}
return res->second;
}
ScopeFindResult Scope::Find(const util::StringView &name, ResolveBindingOptions options) const
{
uint32_t level = 0;
uint32_t lexLevel = 0;
const auto *iter = this;
while (iter != nullptr) {
Variable *v = iter->FindLocal(name, options);
if (v != nullptr) {
return {name, const_cast<Scope *>(iter), level, lexLevel, v};
}
if (iter->IsVariableScope()) {
level++;
if (iter->AsVariableScope()->NeedLexEnv()) {
lexLevel++;
}
}
iter = iter->Parent();
}
return {name, nullptr, 0, 0, nullptr};
}
Decl *Scope::FindDecl(const util::StringView &name) const
{
for (auto *it : decls_) {
if (it->Name() == name) {
return it;
}
}
return nullptr;
}
std::tuple<Scope *, bool> Scope::IterateShadowedVariables(const util::StringView &name, const VariableVisitior &visitor)
{
auto *iter = this;
while (true) {
auto *v = iter->FindLocal(name);
if (v && visitor(v)) {
return {iter, true};
}
if (iter->IsFunctionVariableScope()) {
break;
}
iter = iter->Parent();
}
return {iter, false};
}
bool Scope::AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
[[maybe_unused]] ScriptExtension extension)
{
VariableFlags flags = VariableFlags::NONE;
switch (newDecl->Type()) {
case DeclType::VAR: {
auto [scope, shadowed] = IterateShadowedVariables(
newDecl->Name(), [](const Variable *v) { return !v->HasFlag(VariableFlags::VAR); });
if (shadowed) {
return false;
}
VariableFlags varFlags = VariableFlags::HOIST_VAR | VariableFlags::LEXICAL_VAR;
if (scope->IsGlobalScope()) {
scope->Bindings().insert({newDecl->Name(), allocator->New<GlobalVariable>(newDecl, varFlags)});
} else {
scope->PropagateBinding<LocalVariable>(allocator, newDecl->Name(), newDecl, varFlags);
}
return true;
}
case DeclType::ENUM: {
bindings_.insert({newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)});
return true;
}
case DeclType::ENUM_LITERAL: {
bindings_.insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::ENUM_LITERAL)});
return true;
}
case DeclType::INTERFACE: {
bindings_.insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::INTERFACE)});
return true;
}
case DeclType::FUNC: {
flags = VariableFlags::HOIST;
[[fallthrough]];
}
default: {
if (currentVariable) {
return false;
}
auto [_, shadowed] = IterateShadowedVariables(
newDecl->Name(), [](const Variable *v) { return v->HasFlag(VariableFlags::LEXICAL_VAR); });
(void)_;
if (shadowed) {
return false;
}
bindings_.insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, flags)});
return true;
}
}
}
bool ParamScope::AddParam(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags)
{
ASSERT(newDecl->IsParameterDecl());
if (currentVariable) {
return false;
}
auto *param = allocator->New<LocalVariable>(newDecl, flags);
params_.push_back(param);
bindings_.insert({newDecl->Name(), param});
return true;
}
std::tuple<ParameterDecl *, const ir::AstNode *> ParamScope::AddParamDecl(ArenaAllocator *allocator,
const ir::AstNode *param)
{
const auto [name, pattern] = util::Helpers::ParamName(allocator, param, params_.size());
auto *decl = NewDecl<ParameterDecl>(allocator, name);
if (!AddParam(allocator, FindLocal(name), decl, VariableFlags::VAR)) {
return {decl, param};
}
if (!pattern) {
return {decl, nullptr};
}
std::vector<const ir::Identifier *> bindings = util::Helpers::CollectBindingNames(param);
for (const auto *binding : bindings) {
auto *varDecl = NewDecl<VarDecl>(allocator, binding->Name());
varDecl->BindNode(binding);
if (FindLocal(varDecl->Name())) {
return {decl, binding};
}
auto *paramVar = allocator->New<LocalVariable>(varDecl, VariableFlags::VAR);
bindings_.insert({varDecl->Name(), paramVar});
}
return {decl, nullptr};
}
void FunctionParamScope::BindName(ArenaAllocator *allocator, util::StringView name)
{
nameVar_ = AddDecl<ConstDecl, LocalVariable>(allocator, name, VariableFlags::INITIALIZED);
functionScope_->Bindings().insert({name, nameVar_});
}
bool FunctionParamScope::AddBinding([[maybe_unused]] ArenaAllocator *allocator,
[[maybe_unused]] Variable *currentVariable, [[maybe_unused]] Decl *newDecl,
[[maybe_unused]] ScriptExtension extension)
{
UNREACHABLE();
}
bool FunctionScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
[[maybe_unused]] ScriptExtension extension)
{
switch (newDecl->Type()) {
case DeclType::VAR: {
return AddVar<LocalVariable>(allocator, currentVariable, newDecl);
}
case DeclType::FUNC: {
return AddFunction<LocalVariable>(allocator, currentVariable, newDecl, extension);
}
case DeclType::ENUM: {
bindings_.insert({newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)});
return true;
}
case DeclType::ENUM_LITERAL: {
return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::ENUM_LITERAL);
}
case DeclType::INTERFACE: {
return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE);
}
default: {
return AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
}
}
}
bool GlobalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
[[maybe_unused]] ScriptExtension extension)
{
switch (newDecl->Type()) {
case DeclType::VAR: {
return AddVar<GlobalVariable>(allocator, currentVariable, newDecl);
}
case DeclType::FUNC: {
return AddFunction<GlobalVariable>(allocator, currentVariable, newDecl, extension);
}
case DeclType::ENUM: {
bindings_.insert({newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)});
return true;
}
case DeclType::ENUM_LITERAL: {
return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::ENUM_LITERAL);
}
case DeclType::INTERFACE: {
return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE);
}
default: {
return AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
}
}
return true;
}
// ModuleScope
bool ModuleScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
[[maybe_unused]] ScriptExtension extension)
{
switch (newDecl->Type()) {
case DeclType::VAR: {
return AddVar<LocalVariable>(allocator, currentVariable, newDecl);
}
case DeclType::FUNC: {
return AddFunction<LocalVariable>(allocator, currentVariable, newDecl, extension);
}
case DeclType::ENUM: {
bindings_.insert({newDecl->Name(), allocator->New<EnumVariable>(newDecl, false)});
return true;
}
case DeclType::ENUM_LITERAL: {
return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::ENUM_LITERAL);
}
case DeclType::INTERFACE: {
return AddTSBinding<LocalVariable>(allocator, currentVariable, newDecl, VariableFlags::INTERFACE);
}
case DeclType::IMPORT: {
return AddImport(allocator, currentVariable, newDecl);
}
case DeclType::EXPORT: {
return true;
}
default: {
return AddLexical<LocalVariable>(allocator, currentVariable, newDecl);
}
}
}
void ModuleScope::AddImportDecl(const ir::ImportDeclaration *importDecl, ImportDeclList &&decls)
{
auto res = imports_.emplace_back(importDecl, decls);
for (auto &decl : res.second) {
decl->BindNode(importDecl);
}
}
void ModuleScope::AddExportDecl(const ir::AstNode *exportDecl, ExportDecl *decl)
{
decl->BindNode(exportDecl);
ArenaVector<ExportDecl *> decls(allocator_->Adapter());
decls.push_back(decl);
AddExportDecl(exportDecl, std::move(decls));
}
void ModuleScope::AddExportDecl(const ir::AstNode *exportDecl, ExportDeclList &&decls)
{
auto res = exports_.emplace_back(exportDecl, decls);
for (auto &decl : res.second) {
decl->BindNode(exportDecl);
}
}
bool ModuleScope::AddImport(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl)
{
if (currentVariable && currentVariable->Declaration()->Type() != DeclType::VAR) {
return false;
}
if (newDecl->Node()->IsImportNamespaceSpecifier()) {
bindings_.insert({newDecl->Name(), allocator->New<LocalVariable>(newDecl, VariableFlags::READONLY)});
} else {
auto *variable = allocator->New<ModuleVariable>(newDecl, VariableFlags::NONE);
variable->ExoticName() = newDecl->AsImportDecl()->ImportName();
bindings_.insert({newDecl->Name(), variable});
}
return true;
}
bool ModuleScope::ExportAnalysis()
{
std::set<util::StringView> exportedNames;
for (const auto &[exportDecl, decls] : exports_) {
if (exportDecl->IsExportAllDeclaration()) {
const auto *exportAllDecl = exportDecl->AsExportAllDeclaration();
if (exportAllDecl->Exported() != nullptr) {
auto result = exportedNames.insert(exportAllDecl->Exported()->Name());
if (!result.second) {
return false;
}
}
continue;
}
if (exportDecl->IsExportNamedDeclaration()) {
const auto *exportNamedDecl = exportDecl->AsExportNamedDeclaration();
if (exportNamedDecl->Source()) {
continue;
}
}
for (const auto *decl : decls) {
binder::Variable *variable = FindLocal(decl->LocalName());
if (!variable) {
continue;
}
auto result = exportedNames.insert(decl->ExportName());
if (!result.second) {
return false;
}
if (!variable->IsModuleVariable()) {
variable->AddFlag(VariableFlags::LOCAL_EXPORT);
localExports_.insert({variable, decl->ExportName()});
}
}
}
return true;
}
// LocalScope
bool LocalScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
[[maybe_unused]] ScriptExtension extension)
{
return AddLocal(allocator, currentVariable, newDecl, extension);
}
void LoopDeclarationScope::ConvertToVariableScope(ArenaAllocator *allocator)
{
if (NeedLexEnv()) {
return;
}
for (auto &[name, var] : bindings_) {
if (!var->LexicalBound() || !var->Declaration()->IsLetOrConstDecl()) {
continue;
}
slotIndex_++;
loopType_ = ScopeType::LOOP_DECL;
auto *copiedVar = var->AsLocalVariable()->Copy(allocator, var->Declaration());
copiedVar->AddFlag(VariableFlags::INITIALIZED | VariableFlags::PER_ITERATION);
var->AddFlag(VariableFlags::LOOP_DECL);
loopScope_->Bindings().insert({name, copiedVar});
}
if (loopType_ == ScopeType::LOOP_DECL) {
slotIndex_ = std::max(slotIndex_, parent_->EnclosingVariableScope()->LexicalSlots());
initScope_ = allocator->New<LocalScope>(allocator, parent_);
initScope_->BindNode(node_);
initScope_->Bindings() = bindings_;
}
}
void LoopScope::ConvertToVariableScope(ArenaAllocator *allocator)
{
declScope_->ConvertToVariableScope(allocator);
if (loopType_ != ScopeType::LOCAL) {
return;
}
for (const auto &[_, var] : bindings_) {
(void)_;
if (var->LexicalBound() && var->Declaration()->IsLetDecl()) {
ASSERT(declScope_->NeedLexEnv());
loopType_ = ScopeType::LOOP;
break;
}
}
if (loopType_ == ScopeType::LOOP) {
slotIndex_ = std::max(slotIndex_, declScope_->LexicalSlots());
}
}
bool CatchParamScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
[[maybe_unused]] ScriptExtension extension)
{
return AddParam(allocator, currentVariable, newDecl, VariableFlags::INITIALIZED);
}
bool CatchScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
[[maybe_unused]] ScriptExtension extension)
{
if (!newDecl->IsVarDecl() && paramScope_->FindLocal(newDecl->Name())) {
return false;
}
return AddLocal(allocator, currentVariable, newDecl, extension);
}
} // namespace panda::es2panda::binder
+742
View File
@@ -0,0 +1,742 @@
/**
* Copyright (c) 2021 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.
*/
#ifndef ES2PANDA_COMPILER_SCOPES_SCOPE_H
#define ES2PANDA_COMPILER_SCOPES_SCOPE_H
#include <binder/declaration.h>
#include <binder/variable.h>
#include <parser/program/program.h>
#include <util/enumbitops.h>
#include <util/ustring.h>
#include <map>
#include <unordered_map>
#include <vector>
namespace panda::es2panda::compiler {
class IRNode;
} // namespace panda::es2panda::compiler
namespace panda::es2panda::binder {
#define DECLARE_CLASSES(type, className) class className;
SCOPE_TYPES(DECLARE_CLASSES)
#undef DECLARE_CLASSES
class Scope;
class VariableScope;
class Variable;
using VariableMap = ArenaUnorderedMap<util::StringView, Variable *>;
class ScopeFindResult {
public:
ScopeFindResult() = default;
ScopeFindResult(util::StringView n, Scope *s, uint32_t l, Variable *v) : ScopeFindResult(n, s, l, l, v) {}
ScopeFindResult(Scope *s, uint32_t l, uint32_t ll, Variable *v) : scope(s), level(l), lexLevel(ll), variable(v) {}
ScopeFindResult(util::StringView n, Scope *s, uint32_t l, uint32_t ll, Variable *v)
: name(n), scope(s), level(l), lexLevel(ll), variable(v)
{
}
util::StringView name {};
Scope *scope {};
uint32_t level {};
uint32_t lexLevel {};
Variable *variable {};
};
class Scope {
public:
virtual ~Scope() = default;
NO_COPY_SEMANTIC(Scope);
NO_MOVE_SEMANTIC(Scope);
virtual ScopeType Type() const = 0;
#define DECLARE_CHECKS_CASTS(scopeType, className) \
bool Is##className() const \
{ \
return Type() == ScopeType::scopeType; \
} \
className *As##className() \
{ \
ASSERT(Is##className()); \
return reinterpret_cast<className *>(this); \
} \
const className *As##className() const \
{ \
ASSERT(Is##className()); \
return reinterpret_cast<const className *>(this); \
}
SCOPE_TYPES(DECLARE_CHECKS_CASTS)
#undef DECLARE_CHECKS_CASTS
bool IsVariableScope() const
{
return Type() > ScopeType::LOCAL;
}
bool IsFunctionVariableScope() const
{
return Type() >= ScopeType::FUNCTION;
}
FunctionScope *AsFunctionVariableScope()
{
ASSERT(IsFunctionVariableScope());
return reinterpret_cast<FunctionScope *>(this);
}
const FunctionScope *AsFunctionVariableScope() const
{
ASSERT(IsFunctionVariableScope());
return reinterpret_cast<const FunctionScope *>(this);
}
VariableScope *AsVariableScope()
{
ASSERT(IsVariableScope());
return reinterpret_cast<VariableScope *>(this);
}
const VariableScope *AsVariableScope() const
{
ASSERT(IsVariableScope());
return reinterpret_cast<const VariableScope *>(this);
}
VariableScope *EnclosingVariableScope();
const ArenaVector<Decl *> &Decls() const
{
return decls_;
}
Scope *Parent()
{
return parent_;
}
const Scope *Parent() const
{
return parent_;
}
const compiler::IRNode *ScopeStart() const
{
return startIns_;
}
const compiler::IRNode *ScopeEnd() const
{
return endIns_;
}
void SetScopeStart(const compiler::IRNode *ins)
{
startIns_ = ins;
}
void SetScopeEnd(const compiler::IRNode *ins)
{
endIns_ = ins;
}
const ir::AstNode *Node() const
{
return node_;
}
void BindNode(const ir::AstNode *node)
{
node_ = node;
}
bool AddDecl(ArenaAllocator *allocator, Decl *decl, [[maybe_unused]] ScriptExtension extension)
{
decls_.push_back(decl);
return AddBinding(allocator, FindLocal(decl->Name()), decl, extension);
}
bool AddTsDecl(ArenaAllocator *allocator, Decl *decl, [[maybe_unused]] ScriptExtension extension)
{
decls_.push_back(decl);
return AddBinding(allocator, FindLocal(decl->Name(), ResolveBindingOptions::ALL), decl, extension);
}
template <typename T, typename... Args>
T *NewDecl(ArenaAllocator *allocator, Args &&... args);
template <typename DeclType, typename VariableType>
VariableType *AddDecl(ArenaAllocator *allocator, util::StringView name, VariableFlags flags);
template <typename DeclType = binder::LetDecl, typename VariableType = binder::LocalVariable>
static VariableType *CreateVar(ArenaAllocator *allocator, util::StringView name, VariableFlags flags,
const ir::AstNode *node);
template <typename T, typename... Args>
void PropagateBinding(ArenaAllocator *allocator, util::StringView name, Args &&... args);
VariableMap &Bindings()
{
return bindings_;
}
const VariableMap &Bindings() const
{
return bindings_;
}
virtual bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
[[maybe_unused]] ScriptExtension extension) = 0;
Variable *FindLocal(const util::StringView &name,
ResolveBindingOptions options = ResolveBindingOptions::BINDINGS) const;
ScopeFindResult Find(const util::StringView &name,
ResolveBindingOptions options = ResolveBindingOptions::BINDINGS) const;
Decl *FindDecl(const util::StringView &name) const;
protected:
explicit Scope(ArenaAllocator *allocator, Scope *parent)
: parent_(parent), decls_(allocator->Adapter()), bindings_(allocator->Adapter())
{
}
/**
* @return true - if the variable is shadowed
* false - otherwise
*/
using VariableVisitior = std::function<bool(const Variable *)>;
/**
* @return true - if the variable is shadowed
* false - otherwise
*/
std::tuple<Scope *, bool> IterateShadowedVariables(const util::StringView &name, const VariableVisitior &visitor);
bool AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
[[maybe_unused]] ScriptExtension extension);
Scope *parent_ {};
ArenaVector<Decl *> decls_;
VariableMap bindings_;
const ir::AstNode *node_ {};
const compiler::IRNode *startIns_ {};
const compiler::IRNode *endIns_ {};
};
class VariableScope : public Scope {
public:
~VariableScope() override = default;
NO_COPY_SEMANTIC(VariableScope);
NO_MOVE_SEMANTIC(VariableScope);
void AddFlag(VariableScopeFlags flag)
{
flags_ |= flag;
}
void ClearFlag(VariableScopeFlags flag)
{
flags_ &= ~flag;
}
bool HasFlag(VariableScopeFlags flag) const
{
return (flags_ & flag) != 0;
}
uint32_t NextSlot()
{
return slotIndex_++;
}
uint32_t LexicalSlots() const
{
return slotIndex_;
}
bool NeedLexEnv() const
{
return slotIndex_ != 0;
}
protected:
explicit VariableScope(ArenaAllocator *allocator, Scope *parent) : Scope(allocator, parent) {}
template <typename T>
bool AddVar(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl);
template <typename T>
bool AddFunction(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
[[maybe_unused]] ScriptExtension extension);
template <typename T>
bool AddTSBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags);
template <typename T>
bool AddLexical(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl);
VariableScopeFlags flags_ {};
uint32_t slotIndex_ {};
};
class ParamScope : public Scope {
public:
ScopeType Type() const override
{
return ScopeType::PARAM;
}
ArenaVector<LocalVariable *> &Params()
{
return params_;
}
const ArenaVector<LocalVariable *> &Params() const
{
return params_;
}
std::tuple<ParameterDecl *, const ir::AstNode *> AddParamDecl(ArenaAllocator *allocator, const ir::AstNode *param);
protected:
explicit ParamScope(ArenaAllocator *allocator, Scope *parent)
: Scope(allocator, parent), params_(allocator->Adapter())
{
}
bool AddParam(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, VariableFlags flags);
ArenaVector<LocalVariable *> params_;
};
class FunctionScope;
class FunctionParamScope : public ParamScope {
public:
explicit FunctionParamScope(ArenaAllocator *allocator, Scope *parent) : ParamScope(allocator, parent) {}
FunctionScope *GetFunctionScope() const
{
return functionScope_;
}
void BindFunctionScope(FunctionScope *funcScope)
{
functionScope_ = funcScope;
}
LocalVariable *NameVar() const
{
return nameVar_;
}
void BindName(ArenaAllocator *allocator, util::StringView name);
ScopeType Type() const override
{
return ScopeType::FUNCTION_PARAM;
}
bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
[[maybe_unused]] ScriptExtension extension) override;
friend class FunctionScope;
template <typename E, typename T>
friend class ScopeWithParamScope;
private:
FunctionScope *functionScope_ {};
LocalVariable *nameVar_ {};
};
template <typename E, typename T>
class ScopeWithParamScope : public E {
public:
explicit ScopeWithParamScope(ArenaAllocator *allocator, Scope *parent) : E(allocator, parent) {}
void BindParamScope(T *paramScope)
{
AssignParamScope(paramScope);
this->bindings_ = paramScope->Bindings();
}
void AssignParamScope(T *paramScope)
{
ASSERT(this->parent_ == paramScope);
ASSERT(this->bindings_.empty());
paramScope_ = paramScope;
}
T *ParamScope()
{
return paramScope_;
}
const T *ParamScope() const
{
return paramScope_;
}
protected:
T *paramScope_;
};
class FunctionScope : public ScopeWithParamScope<VariableScope, FunctionParamScope> {
public:
explicit FunctionScope(ArenaAllocator *allocator, Scope *parent) : ScopeWithParamScope(allocator, parent) {}
ScopeType Type() const override
{
return ScopeType::FUNCTION;
}
void BindName(util::StringView name, util::StringView internalName)
{
name_ = name;
internalName_ = internalName;
}
const util::StringView &Name() const
{
return name_;
}
const util::StringView &InternalName() const
{
return internalName_;
}
bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
[[maybe_unused]] ScriptExtension extension) override;
private:
util::StringView name_ {};
util::StringView internalName_ {};
};
class LocalScope : public Scope {
public:
explicit LocalScope(ArenaAllocator *allocator, Scope *parent) : Scope(allocator, parent) {}
ScopeType Type() const override
{
return ScopeType::LOCAL;
}
bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
[[maybe_unused]] ScriptExtension extension) override;
};
class CatchParamScope : public ParamScope {
public:
explicit CatchParamScope(ArenaAllocator *allocator, Scope *parent) : ParamScope(allocator, parent) {}
ScopeType Type() const override
{
return ScopeType::CATCH_PARAM;
}
bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
[[maybe_unused]] ScriptExtension extension) override;
friend class CatchScope;
};
class CatchScope : public ScopeWithParamScope<LocalScope, CatchParamScope> {
public:
explicit CatchScope(ArenaAllocator *allocator, Scope *parent) : ScopeWithParamScope(allocator, parent) {}
ScopeType Type() const override
{
return ScopeType::CATCH;
}
bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
[[maybe_unused]] ScriptExtension extension) override;
};
class LoopScope;
class LoopDeclarationScope : public VariableScope {
public:
explicit LoopDeclarationScope(ArenaAllocator *allocator, Scope *parent) : VariableScope(allocator, parent) {}
ScopeType Type() const override
{
return loopType_;
}
bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
[[maybe_unused]] ScriptExtension extension) override
{
return AddLocal(allocator, currentVariable, newDecl, extension);
}
Scope *InitScope()
{
if (NeedLexEnv()) {
return initScope_;
}
return this;
}
void ConvertToVariableScope(ArenaAllocator *allocator);
private:
friend class LoopScope;
LoopScope *loopScope_ {};
LocalScope *initScope_ {};
ScopeType loopType_ {ScopeType::LOCAL};
};
class LoopScope : public VariableScope {
public:
explicit LoopScope(ArenaAllocator *allocator, Scope *parent) : VariableScope(allocator, parent) {}
LoopDeclarationScope *DeclScope()
{
return declScope_;
}
void BindDecls(LoopDeclarationScope *declScope)
{
declScope_ = declScope;
declScope_->loopScope_ = this;
}
ScopeType Type() const override
{
return loopType_;
}
void ConvertToVariableScope(ArenaAllocator *allocator);
bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
[[maybe_unused]] ScriptExtension extension) override
{
return AddLocal(allocator, currentVariable, newDecl, extension);
}
protected:
LoopDeclarationScope *declScope_ {};
ScopeType loopType_ {ScopeType::LOCAL};
};
class GlobalScope : public FunctionScope {
public:
explicit GlobalScope(ArenaAllocator *allocator) : FunctionScope(allocator, nullptr)
{
auto *paramScope = allocator->New<FunctionParamScope>(allocator, this);
paramScope_ = paramScope;
}
ScopeType Type() const override
{
return ScopeType::GLOBAL;
}
bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
[[maybe_unused]] ScriptExtension extension) override;
};
class ModuleScope : public GlobalScope {
public:
template <typename K, typename V>
using ModuleEntry = ArenaVector<std::pair<K, V>>;
using ImportDeclList = ArenaVector<ImportDecl *>;
using ExportDeclList = ArenaVector<ExportDecl *>;
using LocalExportNameMap = ArenaMultiMap<binder::Variable *, util::StringView>;
explicit ModuleScope(ArenaAllocator *allocator)
: GlobalScope(allocator),
allocator_(allocator),
imports_(allocator_->Adapter()),
exports_(allocator_->Adapter()),
localExports_(allocator_->Adapter())
{
}
ScopeType Type() const override
{
return ScopeType::MODULE;
}
const ModuleEntry<const ir::ImportDeclaration *, ImportDeclList> &Imports() const
{
return imports_;
}
const ModuleEntry<const ir::AstNode *, ExportDeclList> &Exports() const
{
return exports_;
}
const LocalExportNameMap &LocalExports() const
{
return localExports_;
}
void AddImportDecl(const ir::ImportDeclaration *importDecl, ImportDeclList &&decls);
void AddExportDecl(const ir::AstNode *exportDecl, ExportDecl *decl);
void AddExportDecl(const ir::AstNode *exportDecl, ExportDeclList &&decls);
bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
[[maybe_unused]] ScriptExtension extension) override;
bool ExportAnalysis();
private:
bool AddImport(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl);
ArenaAllocator *allocator_;
ModuleEntry<const ir::ImportDeclaration *, ImportDeclList> imports_;
ModuleEntry<const ir::AstNode *, ExportDeclList> exports_;
LocalExportNameMap localExports_;
};
template <typename T>
bool VariableScope::AddVar(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl)
{
if (!currentVariable) {
bindings_.insert({newDecl->Name(), allocator->New<T>(newDecl, VariableFlags::HOIST_VAR)});
return true;
}
switch (currentVariable->Declaration()->Type()) {
case DeclType::VAR: {
currentVariable->Reset(newDecl, VariableFlags::HOIST_VAR);
break;
}
case DeclType::PARAM:
case DeclType::FUNC: {
break;
}
default: {
return false;
}
}
return true;
}
template <typename T>
bool VariableScope::AddFunction(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl,
[[maybe_unused]] ScriptExtension extension)
{
VariableFlags flags = (extension == ScriptExtension::JS) ? VariableFlags::HOIST_VAR : VariableFlags::HOIST;
if (!currentVariable) {
bindings_.insert({newDecl->Name(), allocator->New<T>(newDecl, flags)});
return true;
}
if (extension != ScriptExtension::JS || IsModuleScope()) {
return false;
}
switch (currentVariable->Declaration()->Type()) {
case DeclType::VAR:
case DeclType::FUNC: {
currentVariable->Reset(newDecl, VariableFlags::HOIST_VAR);
break;
}
default: {
return false;
}
}
return true;
}
template <typename T>
bool VariableScope::AddTSBinding(ArenaAllocator *allocator, [[maybe_unused]] Variable *currentVariable, Decl *newDecl,
VariableFlags flags)
{
ASSERT(!currentVariable);
bindings_.insert({newDecl->Name(), allocator->New<T>(newDecl, flags)});
return true;
}
template <typename T>
bool VariableScope::AddLexical(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl)
{
if (currentVariable) {
return false;
}
bindings_.insert({newDecl->Name(), allocator->New<T>(newDecl, VariableFlags::NONE)});
return true;
}
template <typename T, typename... Args>
T *Scope::NewDecl(ArenaAllocator *allocator, Args &&... args)
{
T *decl = allocator->New<T>(std::forward<Args>(args)...);
decls_.push_back(decl);
return decl;
}
template <typename DeclType, typename VariableType>
VariableType *Scope::AddDecl(ArenaAllocator *allocator, util::StringView name, VariableFlags flags)
{
if (FindLocal(name)) {
return nullptr;
}
auto *decl = allocator->New<DeclType>(name);
auto *variable = allocator->New<VariableType>(decl, flags);
decls_.push_back(decl);
bindings_.insert({decl->Name(), variable});
return variable;
}
template <typename DeclType, typename VariableType>
VariableType *Scope::CreateVar(ArenaAllocator *allocator, util::StringView name, VariableFlags flags,
const ir::AstNode *node)
{
auto *decl = allocator->New<DeclType>(name);
auto *variable = allocator->New<VariableType>(decl, flags);
decl->BindNode(node);
return variable;
}
template <typename T, typename... Args>
void Scope::PropagateBinding(ArenaAllocator *allocator, util::StringView name, Args &&... args)
{
auto res = bindings_.find(name);
if (res == bindings_.end()) {
bindings_.insert({name, allocator->New<T>(std::forward<Args>(args)...)});
return;
}
res->second->Reset(std::forward<Args>(args)...);
}
} // namespace panda::es2panda::binder
#endif
+44
View File
@@ -0,0 +1,44 @@
/**
* Copyright (c) 2021 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.
*/
#ifndef ES2PANDA_BINDER_TS_BINDING_H
#define ES2PANDA_BINDER_TS_BINDING_H
#include <util/ustring.h>
#include <variant>
namespace panda::es2panda::binder {
// Note: if the bool operand is present, the expression cannot be evaluated during compliation
using EnumMemberResult = std::variant<double, util::StringView, bool>;
class TSBinding : public util::UString {
public:
explicit TSBinding(ArenaAllocator *allocator, util::StringView name)
: util::UString(std::string {TS_PREFIX}, allocator)
{
Append(name);
}
static std::string ToTSBinding(util::StringView name)
{
return std::string {TS_PREFIX}.append(name.Utf8());
}
static constexpr std::string_view TS_PREFIX = "#";
};
} // namespace panda::es2panda::binder
#endif
+63
View File
@@ -0,0 +1,63 @@
/**
* Copyright (c) 2021 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 "variable.h"
#include <binder/scope.h>
#include <utility>
namespace panda::es2panda::binder {
LocalVariable::LocalVariable(Decl *decl, VariableFlags flags) : Variable(decl, flags)
{
if (decl->IsConstDecl()) {
flags_ |= VariableFlags::READONLY;
}
}
const util::StringView &Variable::Name() const
{
return decl_->Name();
}
LocalVariable *LocalVariable::Copy(ArenaAllocator *allocator, Decl *decl) const
{
auto *var = allocator->New<LocalVariable>(decl, flags_);
var->vreg_ = vreg_;
return var;
}
void LocalVariable::SetLexical(Scope *scope)
{
if (LexicalBound()) {
return;
}
VariableScope *varScope = scope->EnclosingVariableScope();
BindLexEnvSlot(varScope->NextSlot());
}
void GlobalVariable::SetLexical([[maybe_unused]] Scope *scope) {}
void ModuleVariable::SetLexical([[maybe_unused]] Scope *scope) {}
void EnumVariable::SetLexical([[maybe_unused]] Scope *scope) {}
void EnumVariable::ResetDecl(Decl *decl)
{
decl_ = decl;
}
} // namespace panda::es2panda::binder
+254
View File
@@ -0,0 +1,254 @@
/**
* Copyright (c) 2021 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.
*/
#ifndef ES2PANDA_COMPILER_SCOPES_VARIABLE_H
#define ES2PANDA_COMPILER_SCOPES_VARIABLE_H
#include <binder/enumMemberResult.h>
#include <binder/variableFlags.h>
#include <ir/irnode.h>
#include <macros.h>
#include <util/ustring.h>
#include <limits>
namespace panda::es2panda::checker {
class Type;
} // namespace panda::es2panda::checker
namespace panda::es2panda::binder {
class Decl;
class Scope;
class VariableScope;
#define DECLARE_CLASSES(type, className) class className;
VARIABLE_TYPES(DECLARE_CLASSES)
#undef DECLARE_CLASSES
class Variable {
public:
virtual ~Variable() = default;
NO_COPY_SEMANTIC(Variable);
NO_MOVE_SEMANTIC(Variable);
VariableType virtual Type() const = 0;
#define DECLARE_CHECKS_CASTS(variableType, className) \
bool Is##className() const \
{ \
return Type() == VariableType::variableType; \
} \
className *As##className() \
{ \
ASSERT(Is##className()); \
return reinterpret_cast<className *>(this); \
} \
const className *As##className() const \
{ \
ASSERT(Is##className()); \
return reinterpret_cast<const className *>(this); \
}
VARIABLE_TYPES(DECLARE_CHECKS_CASTS)
#undef DECLARE_CHECKS_CASTS
Decl *Declaration() const
{
return decl_;
}
VariableFlags Flags() const
{
return flags_;
}
checker::Type *TsType() const
{
return tsType_;
}
void SetTsType(checker::Type *tsType)
{
tsType_ = tsType;
}
void AddFlag(VariableFlags flag)
{
flags_ |= flag;
}
bool HasFlag(VariableFlags flag) const
{
return (flags_ & flag) != 0;
}
void RemoveFlag(VariableFlags flag)
{
flags_ &= ~flag;
}
void Reset(Decl *decl, VariableFlags flags)
{
decl_ = decl;
flags_ = flags;
}
bool LexicalBound() const
{
return HasFlag(VariableFlags::LEXICAL_BOUND);
}
const util::StringView &Name() const;
virtual void SetLexical(Scope *scope) = 0;
protected:
explicit Variable(Decl *decl, VariableFlags flags) : decl_(decl), flags_(flags) {}
Decl *decl_;
VariableFlags flags_ {};
checker::Type *tsType_ {};
};
class LocalVariable : public Variable {
public:
explicit LocalVariable(Decl *decl, VariableFlags flags);
VariableType Type() const override
{
return VariableType::LOCAL;
}
void BindVReg(compiler::VReg vreg)
{
ASSERT(!LexicalBound());
vreg_ = vreg;
}
void BindLexEnvSlot(uint32_t slot)
{
ASSERT(!LexicalBound());
AddFlag(VariableFlags::LEXICAL_BOUND);
vreg_ = slot;
}
compiler::VReg Vreg() const
{
return vreg_;
}
uint32_t LexIdx() const
{
ASSERT(LexicalBound());
return vreg_;
}
void SetLexical([[maybe_unused]] Scope *scope) override;
LocalVariable *Copy(ArenaAllocator *allocator, Decl *decl) const;
private:
uint32_t vreg_ {};
};
class GlobalVariable : public Variable {
public:
explicit GlobalVariable(Decl *decl, VariableFlags flags) : Variable(decl, flags) {}
VariableType Type() const override
{
return VariableType::GLOBAL;
}
void SetLexical([[maybe_unused]] Scope *scope) override;
};
class ModuleVariable : public Variable {
public:
explicit ModuleVariable(Decl *decl, VariableFlags flags) : Variable(decl, flags) {}
VariableType Type() const override
{
return VariableType::MODULE;
}
compiler::VReg &ModuleReg()
{
return moduleReg_;
}
compiler::VReg ModuleReg() const
{
return moduleReg_;
}
const util::StringView &ExoticName() const
{
return exoticName_;
}
util::StringView &ExoticName()
{
return exoticName_;
}
void SetLexical([[maybe_unused]] Scope *scope) override;
private:
compiler::VReg moduleReg_ {};
util::StringView exoticName_ {};
};
class EnumVariable : public Variable {
public:
explicit EnumVariable(Decl *decl, bool backReference = false)
: Variable(decl, VariableFlags::NONE), backReference_(backReference)
{
}
VariableType Type() const override
{
return VariableType::ENUM;
}
void SetValue(EnumMemberResult value)
{
value_ = value;
}
const EnumMemberResult &Value() const
{
return value_;
}
bool BackReference() const
{
return backReference_;
}
void SetBackReference()
{
backReference_ = true;
}
void ResetDecl(Decl *decl);
void SetLexical([[maybe_unused]] Scope *scope) override;
private:
EnumMemberResult value_ {false};
bool backReference_ {};
};
} // namespace panda::es2panda::binder
#endif
+143
View File
@@ -0,0 +1,143 @@
/**
* Copyright (c) 2021 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.
*/
#ifndef ES2PANDA_COMPILER_SCOPES_VARIABLE_FLAGS_H
#define ES2PANDA_COMPILER_SCOPES_VARIABLE_FLAGS_H
#include <util/enumbitops.h>
namespace panda::es2panda::binder {
#define DECLARATION_KINDS(_) \
_(VAR, VarDecl) \
_(LET, LetDecl) \
_(CONST, ConstDecl) \
_(FUNC, FunctionDecl) \
_(PARAM, ParameterDecl) \
_(IMPORT, ImportDecl) \
_(EXPORT, ExportDecl) \
/* TS */ \
_(TYPE_ALIAS, TypeAliasDecl) \
_(NAMESPACE, NameSpaceDecl) \
_(INTERFACE, InterfaceDecl) \
_(ENUM_LITERAL, EnumLiteralDecl) \
_(TYPE_PARAMETER, TypeParameterDecl) \
_(ENUM, EnumDecl)
enum class DeclType {
NONE,
#define DECLARE_TYPES(decl_kind, class_name) decl_kind,
DECLARATION_KINDS(DECLARE_TYPES)
#undef DECLARE_TYPES
};
#define SCOPE_TYPES(_) \
_(PARAM, ParamScope) \
_(CATCH_PARAM, CatchParamScope) \
_(FUNCTION_PARAM, FunctionParamScope) \
_(CATCH, CatchScope) \
_(LOCAL, LocalScope) \
/* Variable Scopes */ \
_(LOOP, LoopScope) \
_(LOOP_DECL, LoopDeclarationScope) \
_(FUNCTION, FunctionScope) \
_(GLOBAL, GlobalScope) \
_(MODULE, ModuleScope)
enum class ScopeType {
#define GEN_SCOPE_TYPES(type, class_name) type,
SCOPE_TYPES(GEN_SCOPE_TYPES)
#undef GEN_SCOPE_TYPES
};
enum class ResolveBindingOptions {
BINDINGS = 1U << 0U,
INTERFACES = 1U << 1U,
ALL = BINDINGS | INTERFACES,
};
DEFINE_BITOPS(ResolveBindingOptions)
#define VARIABLE_TYPES(_) \
_(LOCAL, LocalVariable) \
_(GLOBAL, GlobalVariable) \
_(MODULE, ModuleVariable) \
_(ENUM, EnumVariable)
enum class VariableType {
#define GEN_VARIABLE_TYPES(type, class_name) type,
VARIABLE_TYPES(GEN_VARIABLE_TYPES)
#undef GEN_VARIABLE_TYPES
};
enum class VariableKind {
NONE,
VAR,
LEXICAL,
FUNCTION,
MODULE,
};
enum class VariableFlags {
NONE = 0,
OPTIONAL = 1 << 0,
PROPERTY = 1 << 1,
METHOD = 1 << 2,
TYPE_ALIAS = 1 << 3,
INTERFACE = 1 << 4,
ENUM_LITERAL = 1 << 5,
READONLY = 1 << 6,
COMPUTED = 1 << 7,
COMPUTED_IDENT = 1 << 8,
COMPUTED_INDEX = 1 << 9,
INDEX_NAME = 1 << 10,
LOCAL_EXPORT = 1 << 12,
INFERED_IN_PATTERN = 1 << 13,
REST_ARG = 1 << 14,
INDEX_LIKE = COMPUTED_INDEX | INDEX_NAME,
LOOP_DECL = 1 << 25,
PER_ITERATION = 1 << 26,
LEXICAL_VAR = 1 << 27,
HOIST = 1 << 28,
VAR = 1 << 29,
INITIALIZED = 1 << 30,
LEXICAL_BOUND = 1 << 31,
HOIST_VAR = HOIST | VAR,
};
DEFINE_BITOPS(VariableFlags)
enum class LetOrConstStatus {
INITIALIZED,
UNINITIALIZED,
};
enum class VariableScopeFlags {
NONE = 0,
SET_LEXICAL_FUNCTION = 1U << 0U,
USE_ARGS = 1U << 2U,
USE_SUPER = 1U << 3U,
INNER_ARROW = 1U << 4U,
};
DEFINE_BITOPS(VariableScopeFlags)
} // namespace panda::es2panda::binder
#endif
+27
View File
@@ -0,0 +1,27 @@
/*
* 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 "catchTable.h"
#include <compiler/core/pandagen.h>
namespace panda::es2panda::compiler {
TryLabelSet::TryLabelSet(PandaGen *pg)
: try_(pg->AllocLabel(), pg->AllocLabel()), catch_(pg->AllocLabel(), pg->AllocLabel())
{
}
} // namespace panda::es2panda::compiler
+94
View File
@@ -0,0 +1,94 @@
/**
* 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.
*/
#ifndef ES2PANDA_COMPILER_BASE_CATCH_TABLE_H
#define ES2PANDA_COMPILER_BASE_CATCH_TABLE_H
#include <ir/irnode.h>
#include <compiler/core/labelPair.h>
namespace panda::es2panda::compiler {
class PandaGen;
class TryLabelSet {
public:
explicit TryLabelSet(PandaGen *pg);
~TryLabelSet() = default;
DEFAULT_COPY_SEMANTIC(TryLabelSet);
DEFAULT_MOVE_SEMANTIC(TryLabelSet);
const LabelPair &TryLabelPair() const
{
return try_;
}
const LabelPair &CatchLabelPair() const
{
return catch_;
}
Label *TryBegin() const
{
return try_.Begin();
}
Label *TryEnd() const
{
return try_.End();
}
Label *CatchBegin() const
{
return catch_.Begin();
}
Label *CatchEnd() const
{
return catch_.End();
}
private:
LabelPair try_;
LabelPair catch_;
};
class CatchTable {
public:
CatchTable(PandaGen *pg, uint32_t depth) : labelSet_(pg), depth_(depth) {}
~CatchTable() = default;
NO_COPY_SEMANTIC(CatchTable);
NO_MOVE_SEMANTIC(CatchTable);
const TryLabelSet &LabelSet() const
{
return labelSet_;
}
uint32_t Depth() const
{
return depth_;
}
private:
TryLabelSet labelSet_;
uint32_t depth_;
};
} // namespace panda::es2panda::compiler
#endif
+94
View File
@@ -0,0 +1,94 @@
/*
* 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 "condition.h"
#include <compiler/core/pandagen.h>
#include <ir/expressions/binaryExpression.h>
#include <ir/expressions/unaryExpression.h>
namespace panda::es2panda::compiler {
void Condition::Compile(PandaGen *pg, const ir::Expression *expr, Label *falseLabel)
{
if (expr->IsBinaryExpression()) {
const auto *binExpr = expr->AsBinaryExpression();
switch (binExpr->OperatorType()) {
case lexer::TokenType::PUNCTUATOR_EQUAL:
case lexer::TokenType::PUNCTUATOR_NOT_EQUAL:
case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL:
case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL:
case lexer::TokenType::PUNCTUATOR_LESS_THAN:
case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL:
case lexer::TokenType::PUNCTUATOR_GREATER_THAN:
case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: {
// This is a special case
// These operators are expressed via cmp instructions and the following
// if-else branches. Condition also expressed via cmp instruction and
// the following if-else.
// the goal of this method is to merge these two sequences of instructions.
RegScope rs(pg);
VReg lhs = pg->AllocReg();
binExpr->Left()->Compile(pg);
pg->StoreAccumulator(binExpr, lhs);
binExpr->Right()->Compile(pg);
pg->Condition(binExpr, binExpr->OperatorType(), lhs, falseLabel);
return;
}
case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: {
binExpr->Left()->Compile(pg);
pg->ToBoolean(binExpr);
pg->BranchIfFalse(binExpr, falseLabel);
binExpr->Right()->Compile(pg);
pg->ToBoolean(binExpr);
pg->BranchIfFalse(binExpr, falseLabel);
return;
}
case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: {
auto *endLabel = pg->AllocLabel();
binExpr->Left()->Compile(pg);
pg->ToBoolean(binExpr);
pg->BranchIfTrue(binExpr, endLabel);
binExpr->Right()->Compile(pg);
pg->ToBoolean(binExpr);
pg->BranchIfFalse(binExpr, falseLabel);
pg->SetLabel(binExpr, endLabel);
return;
}
default: {
break;
}
}
} else if (expr->IsUnaryExpression() &&
expr->AsUnaryExpression()->OperatorType() == lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK) {
expr->AsUnaryExpression()->Argument()->Compile(pg);
pg->Negate(expr);
pg->BranchIfFalse(expr, falseLabel);
return;
}
// General case including some binExpr i.E.(a+b)
expr->Compile(pg);
pg->ToBoolean(expr);
pg->BranchIfFalse(expr, falseLabel);
}
} // namespace panda::es2panda::compiler
+35
View File
@@ -0,0 +1,35 @@
/**
* 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.
*/
#ifndef ES2PANDA_COMPILER_BASE_CONDITION_H
#define ES2PANDA_COMPILER_BASE_CONDITION_H
#include <ir/expression.h>
namespace panda::es2panda::compiler {
class PandaGen;
class Label;
class Condition {
public:
Condition() = delete;
static void Compile(PandaGen *pg, const ir::Expression *expr, Label *falseLabel);
};
} // namespace panda::es2panda::compiler
#endif
+262
View File
@@ -0,0 +1,262 @@
/**
* 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 "destructuring.h"
#include <util/helpers.h>
#include <compiler/base/iterators.h>
#include <compiler/base/lreference.h>
#include <compiler/base/catchTable.h>
#include <compiler/core/pandagen.h>
#include <ir/base/property.h>
#include <ir/base/spreadElement.h>
#include <ir/expressions/arrayExpression.h>
#include <ir/expressions/assignmentExpression.h>
#include <ir/expressions/identifier.h>
#include <ir/expressions/objectExpression.h>
namespace panda::es2panda::compiler {
static void GenRestElement(PandaGen *pg, const ir::SpreadElement *restElement,
const DestructuringIterator &destIterator, bool isDeclaration)
{
VReg array = pg->AllocReg();
VReg index = pg->AllocReg();
auto *next = pg->AllocLabel();
auto *done = pg->AllocLabel();
DestructuringRestIterator iterator(destIterator);
// create left reference for rest element
LReference lref = LReference::CreateLRef(pg, restElement, isDeclaration);
// create an empty array first
pg->CreateEmptyArray(restElement);
pg->StoreAccumulator(restElement, array);
// index = 0
pg->LoadAccumulatorInt(restElement, 0);
pg->StoreAccumulator(restElement, index);
pg->SetLabel(restElement, next);
iterator.Step(done);
pg->StoreObjByValue(restElement, array, index);
// index++
pg->LoadAccumulatorInt(restElement, 1);
pg->Binary(restElement, lexer::TokenType::PUNCTUATOR_PLUS, index);
pg->StoreAccumulator(restElement, index);
pg->Branch(restElement, next);
pg->SetLabel(restElement, done);
pg->LoadAccumulator(restElement, array);
lref.SetValue();
}
static void GenArray(PandaGen *pg, const ir::ArrayExpression *array)
{
// RegScope rs(pg);
DestructuringIterator iterator(pg, array);
if (array->Elements().empty()) {
iterator.Close(false);
return;
}
TryContext tryCtx(pg);
const auto &labelSet = tryCtx.LabelSet();
pg->SetLabel(array, labelSet.TryBegin());
for (const auto *element : array->Elements()) {
RegScope ers(pg);
if (element->IsRestElement()) {
GenRestElement(pg, element->AsRestElement(), iterator, array->IsDeclaration());
break;
}
// if a hole exist, just let the iterator step ahead
if (element->IsOmittedExpression()) {
iterator.Step();
continue;
}
const ir::Expression *init = nullptr;
const ir::Expression *target = element;
if (element->IsAssignmentPattern()) {
target = element->AsAssignmentPattern()->Left();
init = element->AsAssignmentPattern()->Right();
}
LReference lref = LReference::CreateLRef(pg, target, array->IsDeclaration());
iterator.Step();
if (init) {
auto *assingValue = pg->AllocLabel();
auto *defaultInit = pg->AllocLabel();
pg->BranchIfUndefined(element, defaultInit);
pg->LoadAccumulator(element, iterator.Result());
pg->Branch(element, assingValue);
pg->SetLabel(element, defaultInit);
init->Compile(pg);
pg->SetLabel(element, assingValue);
}
lref.SetValue();
}
pg->SetLabel(array, labelSet.TryEnd());
// Normal completion
pg->LoadAccumulator(array, iterator.Done());
pg->BranchIfTrue(array, labelSet.CatchEnd());
iterator.Close(false);
pg->Branch(array, labelSet.CatchEnd());
Label *end = pg->AllocLabel();
pg->SetLabel(array, labelSet.CatchBegin());
pg->StoreAccumulator(array, iterator.Result());
pg->LoadAccumulator(array, iterator.Done());
pg->BranchIfTrue(array, end);
pg->LoadAccumulator(array, iterator.Result());
iterator.Close(true);
pg->SetLabel(array, end);
pg->LoadAccumulator(array, iterator.Result());
pg->EmitThrow(array);
pg->SetLabel(array, labelSet.CatchEnd());
}
static void GenObjectProperty(PandaGen *pg, const ir::ObjectExpression *object, const ir::Expression *element,
VReg value, VReg propReg)
{
RegScope propScope(pg);
VReg loadedValue = pg->AllocReg();
const ir::Property *propExpr = element->AsProperty();
const ir::Expression *init = nullptr;
const ir::Expression *key = propExpr->Key();
const ir::Expression *target = propExpr->Value();
if (target->IsAssignmentPattern()) {
init = target->AsAssignmentPattern()->Right();
target = target->AsAssignmentPattern()->Left();
}
// compile key
if (key->IsIdentifier()) {
pg->LoadAccumulatorString(key, key->AsIdentifier()->Name());
} else {
key->Compile(pg);
}
pg->StoreAccumulator(key, propReg);
LReference lref = LReference::CreateLRef(pg, target, object->IsDeclaration());
// load obj property from rhs, return undefined if no corresponding property exists
pg->LoadObjByValue(element, value, propReg);
pg->StoreAccumulator(element, loadedValue);
if (init != nullptr) {
auto *getDefault = pg->AllocLabel();
auto *store = pg->AllocLabel();
pg->BranchIfUndefined(element, getDefault);
pg->LoadAccumulator(element, loadedValue);
pg->Branch(element, store);
// load default value
pg->SetLabel(element, getDefault);
init->Compile(pg);
pg->SetLabel(element, store);
}
lref.SetValue();
}
static void GenObjectWithRest(PandaGen *pg, const ir::ObjectExpression *object, VReg rhs)
{
const auto &properties = object->Properties();
RegScope rs(pg);
VReg propStart = pg->NextReg();
for (const auto *element : properties) {
if (element->IsRestElement()) {
RegScope restScope(pg);
LReference lref = LReference::CreateLRef(pg, element, object->IsDeclaration());
pg->CreateObjectWithExcludedKeys(element, rhs, propStart, properties.size() - 1);
lref.SetValue();
break;
}
VReg propReg = pg->AllocReg();
GenObjectProperty(pg, object, element, rhs, propReg);
}
}
static void GenObject(PandaGen *pg, const ir::ObjectExpression *object, VReg rhs)
{
const auto &properties = object->Properties();
if (properties.empty() || properties.back()->IsRestElement()) {
auto *notNullish = pg->AllocLabel();
pg->LoadAccumulator(object, rhs);
pg->BranchIfCoercible(object, notNullish);
pg->ThrowObjectNonCoercible(object);
pg->SetLabel(object, notNullish);
if (!properties.empty()) {
return GenObjectWithRest(pg, object, rhs);
}
}
for (const auto *element : properties) {
RegScope rs(pg);
VReg propReg = pg->AllocReg();
GenObjectProperty(pg, object, element, rhs, propReg);
}
}
void Destructuring::Compile(PandaGen *pg, const ir::Expression *pattern)
{
RegScope rs(pg);
VReg rhs = pg->AllocReg();
pg->StoreAccumulator(pattern, rhs);
if (pattern->IsArrayPattern()) {
GenArray(pg, pattern->AsArrayPattern());
} else {
GenObject(pg, pattern->AsObjectPattern(), rhs);
}
pg->LoadAccumulator(pattern, rhs);
}
} // namespace panda::es2panda::compiler
+34
View File
@@ -0,0 +1,34 @@
/*
* 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.
*/
#ifndef ES2PANDA_COMPILER_BASE_DESTRUCTURING_H
#define ES2PANDA_COMPILER_BASE_DESTRUCTURING_H
#include <ir/expression.h>
namespace panda::es2panda::compiler {
class PandaGen;
class Destructuring {
public:
Destructuring() = delete;
static void Compile(PandaGen *pg, const ir::Expression *pattern);
};
} // namespace panda::es2panda::compiler
#endif
+81
View File
@@ -0,0 +1,81 @@
/**
* Copyright (c) 2021 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 "hoisting.h"
#include <ir/base/scriptFunction.h>
#include <binder/scope.h>
#include <compiler/core/pandagen.h>
namespace panda::es2panda::compiler {
static void HoistVar(PandaGen *pg, binder::Variable *var, const binder::VarDecl *decl)
{
auto *scope = pg->Scope();
if (scope->IsGlobalScope()) {
pg->LoadConst(decl->Node(), Constant::JS_UNDEFINED);
pg->StoreGlobalVar(decl->Node(), decl->Name());
return;
}
binder::ScopeFindResult result(decl->Name(), scope, 0, var);
pg->LoadConst(decl->Node(), Constant::JS_UNDEFINED);
pg->StoreAccToLexEnv(decl->Node(), result, true);
}
static void HoistFunction(PandaGen *pg, binder::Variable *var, const binder::FunctionDecl *decl)
{
const ir::ScriptFunction *scriptFunction = decl->Node()->AsScriptFunction();
auto *scope = pg->Scope();
const auto &internalName = scriptFunction->Scope()->InternalName();
if (scope->IsGlobalScope()) {
pg->DefineFunction(decl->Node(), scriptFunction, internalName);
pg->StoreGlobalVar(decl->Node(), var->Declaration()->Name());
return;
}
ASSERT(scope->IsFunctionScope() || scope->IsCatchScope() || scope->IsLocalScope() || scope->IsModuleScope());
binder::ScopeFindResult result(decl->Name(), scope, 0, var);
pg->DefineFunction(decl->Node(), scriptFunction, internalName);
pg->StoreAccToLexEnv(decl->Node(), result, true);
}
void Hoisting::Hoist(PandaGen *pg)
{
const auto *scope = pg->Scope();
for (const auto &[_, var] : scope->Bindings()) {
(void)_;
if (!var->HasFlag(binder::VariableFlags::HOIST)) {
continue;
}
const auto *decl = var->Declaration();
if (decl->IsVarDecl()) {
HoistVar(pg, var, decl->AsVarDecl());
} else {
ASSERT(decl->IsFunctionDecl());
HoistFunction(pg, var, decl->AsFunctionDecl());
}
}
}
} // namespace panda::es2panda::compiler
+30
View File
@@ -0,0 +1,30 @@
/**
* 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.
*/
#ifndef ES2PANDA_COMPILER_BASE_HOISTING_H
#define ES2PANDA_COMPILER_BASE_HOISTING_H
namespace panda::es2panda::compiler {
class PandaGen;
class Hoisting {
public:
static void Hoist(PandaGen *pg);
};
} // namespace panda::es2panda::compiler
#endif
+216
View File
@@ -0,0 +1,216 @@
/*
* 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 "iterators.h"
#include <compiler/core/pandagen.h>
#include <compiler/base/catchTable.h>
#include <compiler/function/functionBuilder.h>
namespace panda::es2panda::compiler {
// Iterator
Iterator::Iterator(PandaGen *pg, const ir::AstNode *node, IteratorType type)
: pg_(pg), node_(node), method_(pg->AllocReg()), iterator_(pg->AllocReg()), nextResult_(pg->AllocReg()), type_(type)
{
if (type_ == IteratorType::ASYNC) {
pg_->GetAsyncIterator(node);
} else {
pg_->GetIterator(node);
}
pg_->StoreAccumulator(node, iterator_);
pg_->LoadObjByName(node_, iterator_, "next");
pg_->StoreAccumulator(node_, method_);
pg_->ThrowIfNotObject(node_);
}
void Iterator::GetMethod(util::StringView name) const
{
pg_->GetMethod(node_, iterator_, name);
pg_->StoreAccumulator(node_, method_);
}
void Iterator::CallMethodWithValue() const
{
pg_->CallThis(node_, method_, 2);
}
void Iterator::CallMethod() const
{
pg_->CallThis(node_, method_, 1);
}
void Iterator::Next() const
{
CallMethod();
if (type_ == IteratorType::ASYNC) {
pg_->FuncBuilder()->Await(node_);
}
pg_->ThrowIfNotObject(node_);
pg_->StoreAccumulator(node_, nextResult_);
}
void Iterator::Complete() const
{
pg_->LoadObjByName(node_, nextResult_, "done");
pg_->ToBoolean(node_);
}
void Iterator::Value() const
{
pg_->LoadObjByName(node_, nextResult_, "value");
}
void Iterator::Close(bool abruptCompletion) const
{
if (type_ == IteratorType::SYNC) {
if (!abruptCompletion) {
pg_->LoadConst(node_, Constant::JS_HOLE);
}
pg_->CloseIterator(node_, iterator_);
return;
}
RegScope rs(pg_);
VReg completion = pg_->AllocReg();
VReg innerResult = pg_->AllocReg();
VReg innerResultType = pg_->AllocReg();
pg_->StoreAccumulator(node_, completion);
pg_->StoreConst(node_, innerResultType, Constant::JS_HOLE);
TryContext tryCtx(pg_);
const auto &labelSet = tryCtx.LabelSet();
Label *returnExits = pg_->AllocLabel();
pg_->SetLabel(node_, labelSet.TryBegin());
// 4. Let innerResult be GetMethod(iterator, "return").
GetMethod("return");
// 5. If innerResult.[[Type]] is normal, then
{
// b. If return is undefined, return Completion(completion).
pg_->BranchIfNotUndefined(node_, returnExits);
// a. Let return be innerResult.[[Value]].
pg_->LoadAccumulator(node_, completion);
if (abruptCompletion) {
pg_->EmitThrow(node_);
} else {
pg_->DirectReturn(node_);
}
pg_->SetLabel(node_, returnExits);
{
TryContext innerTryCtx(pg_);
const auto &innerLabelSet = innerTryCtx.LabelSet();
pg_->SetLabel(node_, innerLabelSet.TryBegin());
// c. Set innerResult to Call(return, iterator).
CallMethod();
// d. If innerResult.[[Type]] is normal, set innerResult to Await(innerResult.[[Value]]).
pg_->FuncBuilder()->Await(node_);
pg_->StoreAccumulator(node_, innerResult);
pg_->SetLabel(node_, innerLabelSet.TryEnd());
pg_->Branch(node_, innerLabelSet.CatchEnd());
pg_->SetLabel(node_, innerLabelSet.CatchBegin());
pg_->StoreAccumulator(node_, innerResult);
pg_->StoreAccumulator(node_, innerResultType);
pg_->SetLabel(node_, innerLabelSet.CatchEnd());
}
}
pg_->SetLabel(node_, labelSet.TryEnd());
pg_->Branch(node_, labelSet.CatchEnd());
pg_->SetLabel(node_, labelSet.CatchBegin());
pg_->StoreAccumulator(node_, innerResult);
pg_->StoreAccumulator(node_, innerResultType);
pg_->SetLabel(node_, labelSet.CatchEnd());
// 6. If completion.[[Type]] is throw, return Completion(completion).
if (abruptCompletion) {
pg_->LoadAccumulator(node_, completion);
pg_->EmitThrow(node_);
} else {
// 7. If innerResult.[[Type]] is throw, return Completion(innerResult).
pg_->LoadAccumulator(node_, innerResultType);
pg_->EmitRethrow(node_);
}
// 8. If Type(innerResult.[[Value]]) is not Object, throw a TypeError exception.
pg_->LoadAccumulator(node_, innerResult);
pg_->ThrowIfNotObject(node_);
}
DestructuringIterator::DestructuringIterator(PandaGen *pg, const ir::AstNode *node)
: Iterator(pg, node, IteratorType::SYNC), done_(pg->AllocReg()), result_(pg->AllocReg())
{
pg_->StoreConst(node, done_, Constant::JS_FALSE);
pg_->StoreConst(node, result_, Constant::JS_UNDEFINED);
}
void DestructuringIterator::Step(Label *doneTarget) const
{
TryContext tryCtx(pg_);
const auto &labelSet = tryCtx.LabelSet();
Label *normalClose = pg_->AllocLabel();
Label *noClose = pg_->AllocLabel();
pg_->SetLabel(node_, labelSet.TryBegin());
Next();
Complete();
pg_->StoreAccumulator(node_, done_);
pg_->BranchIfFalse(node_, normalClose);
pg_->StoreConst(node_, done_, Constant::JS_TRUE);
pg_->LoadConst(node_, Constant::JS_UNDEFINED);
OnIterDone(doneTarget);
pg_->Branch(node_, noClose);
pg_->SetLabel(node_, normalClose);
Value();
pg_->StoreAccumulator(node_, result_);
pg_->SetLabel(node_, noClose);
pg_->SetLabel(node_, labelSet.TryEnd());
pg_->Branch(node_, labelSet.CatchEnd());
pg_->SetLabel(node_, labelSet.CatchBegin());
pg_->StoreAccumulator(node_, result_);
pg_->StoreConst(node_, done_, Constant::JS_TRUE);
pg_->LoadAccumulator(node_, result_);
pg_->EmitThrow(node_);
pg_->SetLabel(node_, labelSet.CatchEnd());
}
void DestructuringIterator::OnIterDone([[maybe_unused]] Label *doneTarget) const
{
pg_->LoadConst(node_, Constant::JS_UNDEFINED);
}
void DestructuringRestIterator::OnIterDone([[maybe_unused]] Label *doneTarget) const
{
pg_->Branch(node_, doneTarget);
}
} // namespace panda::es2panda::compiler
+119
View File
@@ -0,0 +1,119 @@
/**
* 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.
*/
#ifndef ES2PANDA_COMPILER_BASE_ITERATORS_H
#define ES2PANDA_COMPILER_BASE_ITERATORS_H
#include <ir/irnode.h>
namespace panda::es2panda::ir {
class AstNode;
} // namespace panda::es2panda::ir
namespace panda::es2panda::compiler {
class PandaGen;
enum class IteratorType { SYNC, ASYNC };
class Iterator {
public:
Iterator(PandaGen *pg, const ir::AstNode *node, IteratorType type);
DEFAULT_COPY_SEMANTIC(Iterator);
DEFAULT_MOVE_SEMANTIC(Iterator);
~Iterator() = default;
IteratorType Type() const
{
return type_;
}
VReg Method() const
{
return method_;
}
VReg NextResult() const
{
return nextResult_;
}
const ir::AstNode *Node() const
{
return node_;
}
void GetMethod(util::StringView name) const;
void CallMethod() const;
void CallMethodWithValue() const;
void Next() const;
void Complete() const;
void Value() const;
void Close(bool abruptCompletion) const;
protected:
PandaGen *pg_;
const ir::AstNode *node_;
// These 3 regs must be allocated continously
VReg method_;
VReg iterator_;
VReg nextResult_;
IteratorType type_;
};
class DestructuringIterator : public Iterator {
public:
explicit DestructuringIterator(PandaGen *pg, const ir::AstNode *node);
DEFAULT_COPY_SEMANTIC(DestructuringIterator);
DEFAULT_MOVE_SEMANTIC(DestructuringIterator);
~DestructuringIterator() = default;
VReg Done() const
{
return done_;
}
VReg Result() const
{
return result_;
}
void Step(Label *doneTarget = nullptr) const;
virtual void OnIterDone([[maybe_unused]] Label *doneTarget) const;
friend class DestructuringRestIterator;
protected:
VReg done_;
VReg result_;
};
class DestructuringRestIterator : public DestructuringIterator {
public:
explicit DestructuringRestIterator(const DestructuringIterator &iterator) : DestructuringIterator(iterator) {}
DEFAULT_COPY_SEMANTIC(DestructuringRestIterator);
DEFAULT_MOVE_SEMANTIC(DestructuringRestIterator);
~DestructuringRestIterator() = default;
void OnIterDone([[maybe_unused]] Label *doneTarget) const override;
};
} // namespace panda::es2panda::compiler
#endif
+142
View File
@@ -0,0 +1,142 @@
/**
* Copyright (c) 2021 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 "lexenv.h"
#include <binder/variable.h>
#include <compiler/core/envScope.h>
#include <compiler/core/pandagen.h>
#include <compiler/core/moduleContext.h>
#include <ir/expressions/identifier.h>
namespace panda::es2panda::compiler {
// Helpers
static bool CheckTdz(const ir::AstNode *node)
{
return node->IsIdentifier() && node->AsIdentifier()->IsTdz();
}
static void CheckConstAssignment(PandaGen *pg, const ir::AstNode *node, binder::Variable *variable)
{
if (!variable->Declaration()->IsConstDecl()) {
return;
}
pg->ThrowConstAssignment(node, variable->Name());
}
// VirtualLoadVar
static void ExpandLoadLexVar(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result)
{
pg->LoadLexicalVar(node, result.lexLevel, result.variable->AsLocalVariable()->LexIdx());
pg->ThrowUndefinedIfHole(node, result.variable->Name());
}
static void ExpandLoadNormalVar(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result)
{
auto *local = result.variable->AsLocalVariable();
if (CheckTdz(node)) {
pg->LoadConst(node, Constant::JS_HOLE);
pg->ThrowUndefinedIfHole(node, local->Name());
} else {
pg->LoadAccumulator(node, local->Vreg());
}
}
void VirtualLoadVar::Expand(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result)
{
if (result.variable->LexicalBound()) {
ExpandLoadLexVar(pg, node, result);
} else {
ExpandLoadNormalVar(pg, node, result);
}
}
// VirtualStoreVar
static void StoreLocalExport(PandaGen *pg, const ir::AstNode *node, binder::Variable *variable)
{
if (!variable->HasFlag(binder::VariableFlags::LOCAL_EXPORT) || !pg->Scope()->IsModuleScope()) {
return;
}
auto range = pg->Scope()->AsModuleScope()->LocalExports().equal_range(variable);
for (auto it = range.first; it != range.second; ++it) {
if (it->second != "default") {
pg->StoreModuleVar(node, it->second);
}
}
}
static void ExpandStoreLexVar(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDecl)
{
binder::LocalVariable *local = result.variable->AsLocalVariable();
const auto *decl = result.variable->Declaration();
if (decl->IsLetOrConstDecl() && !isDecl) {
RegScope rs(pg);
VReg valueReg = pg->AllocReg();
pg->StoreAccumulator(node, valueReg);
ExpandLoadLexVar(pg, node, result);
if (decl->IsConstDecl()) {
pg->ThrowConstAssignment(node, local->Name());
}
pg->LoadAccumulator(node, valueReg);
}
pg->StoreLexicalVar(node, result.lexLevel, local->LexIdx());
StoreLocalExport(pg, node, local);
}
static void ExpandStoreNormalVar(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result,
bool isDecl)
{
auto *local = result.variable->AsLocalVariable();
VReg localReg = local->Vreg();
if (!isDecl) {
if (CheckTdz(node)) {
pg->LoadConst(node, Constant::JS_HOLE);
pg->ThrowUndefinedIfHole(node, local->Name());
}
CheckConstAssignment(pg, node, local);
}
pg->StoreAccumulator(node, localReg);
StoreLocalExport(pg, node, local);
}
void VirtualStoreVar::Expand(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDecl)
{
if (result.variable->LexicalBound()) {
ExpandStoreLexVar(pg, node, result, isDecl);
} else {
ExpandStoreNormalVar(pg, node, result, isDecl);
}
}
} // namespace panda::es2panda::compiler
+41
View File
@@ -0,0 +1,41 @@
/**
* 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.
*/
#ifndef ES2PANDA_COMPILER_SCOPES_LEXENV_H
#define ES2PANDA_COMPILER_SCOPES_LEXENV_H
#include <binder/scope.h>
#include <ir/irnode.h>
namespace panda::es2panda::compiler {
class PandaGen;
class VirtualLoadVar {
public:
VirtualLoadVar() = delete;
static void Expand(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result);
};
class VirtualStoreVar {
public:
VirtualStoreVar() = delete;
static void Expand(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDecl);
};
} // namespace panda::es2panda::compiler
#endif
+78
View File
@@ -0,0 +1,78 @@
/*
* 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 "literals.h"
#include <compiler/core/pandagen.h>
#include <ir/base/templateElement.h>
#include <ir/expressions/taggedTemplateExpression.h>
#include <ir/expressions/templateLiteral.h>
namespace panda::es2panda::compiler {
// Literals
void Literals::GetTemplateObject(PandaGen *pg, const ir::TaggedTemplateExpression *lit)
{
RegScope rs(pg);
VReg templateArg = pg->AllocReg();
VReg indexReg = pg->AllocReg();
VReg rawArr = pg->AllocReg();
VReg cookedArr = pg->AllocReg();
const ir::TemplateLiteral *templateLit = lit->Quasi();
pg->CreateEmptyArray(templateLit);
pg->StoreAccumulator(templateLit, rawArr);
pg->CreateEmptyArray(templateLit);
pg->StoreAccumulator(templateLit, cookedArr);
size_t elemIndex = 0;
for (const auto *element : templateLit->Quasis()) {
pg->LoadAccumulatorInt(element, elemIndex);
pg->StoreAccumulator(element, indexReg);
pg->LoadAccumulatorString(element, element->Raw());
pg->StoreObjByValue(element, rawArr, indexReg);
pg->LoadAccumulatorString(element, element->Cooked());
pg->StoreObjByValue(element, cookedArr, indexReg);
elemIndex++;
}
pg->CreateEmptyArray(lit);
pg->StoreAccumulator(lit, templateArg);
elemIndex = 0;
pg->LoadAccumulatorInt(lit, elemIndex);
pg->StoreAccumulator(lit, indexReg);
pg->LoadAccumulator(lit, rawArr);
pg->StoreObjByValue(lit, templateArg, indexReg);
elemIndex++;
pg->LoadAccumulatorInt(lit, elemIndex);
pg->StoreAccumulator(lit, indexReg);
pg->LoadAccumulator(lit, cookedArr);
pg->StoreObjByValue(lit, templateArg, indexReg);
pg->GetTemplateObject(lit, templateArg);
}
} // namespace panda::es2panda::compiler
+99
View File
@@ -0,0 +1,99 @@
/**
* 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.
*/
#ifndef ES2PANDA_COMPILER_BASE_LITERALS_H
#define ES2PANDA_COMPILER_BASE_LITERALS_H
#include <ir/expressions/literal.h>
#include <util/ustring.h>
#include <variant>
namespace panda::es2panda::ir {
class Literal;
} // namespace panda::es2panda::ir
namespace panda::es2panda::checker {
class Checker;
class Type;
} // namespace panda::es2panda::checker
namespace panda::es2panda::compiler {
class PandaGen;
class LiteralBuffer {
public:
explicit LiteralBuffer(ArenaAllocator *allocator) : literals_(allocator->Adapter()) {}
~LiteralBuffer() = default;
NO_COPY_SEMANTIC(LiteralBuffer);
NO_MOVE_SEMANTIC(LiteralBuffer);
void Add(ir::Literal *lit)
{
literals_.push_back(lit);
}
bool IsEmpty() const
{
return literals_.empty();
}
size_t Size() const
{
return literals_.size();
}
int32_t Index() const
{
return index_;
}
void ResetLiteral(size_t index, const ir::Literal *literal)
{
literals_[index] = literal;
}
const ArenaVector<const ir::Literal *> &Literals() const
{
return literals_;
}
void Insert(LiteralBuffer *other)
{
literals_.insert(literals_.end(), other->literals_.begin(), other->literals_.end());
other->literals_.clear();
}
void SetIndex(int32_t index)
{
index_ = index;
}
private:
ArenaVector<const ir::Literal *> literals_;
int32_t index_ {};
};
class Literals {
public:
Literals() = delete;
static void GetTemplateObject(PandaGen *pg, const ir::TaggedTemplateExpression *lit);
};
} // namespace panda::es2panda::compiler
#endif
+132
View File
@@ -0,0 +1,132 @@
/*
* 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 "lreference.h"
#include <binder/declaration.h>
#include <compiler/base/destructuring.h>
#include <compiler/core/pandagen.h>
#include <ir/base/spreadElement.h>
#include <ir/expressions/assignmentExpression.h>
#include <ir/expressions/identifier.h>
#include <ir/expressions/memberExpression.h>
#include <ir/statements/variableDeclaration.h>
#include <ir/statements/variableDeclarator.h>
namespace panda::es2panda::compiler {
// LReference
LReference::LReference(const ir::AstNode *node, PandaGen *pg, bool isDeclaration, ReferenceKind refKind,
binder::ScopeFindResult res)
: node_(node), pg_(pg), refKind_(refKind), res_(res), isDeclaration_(isDeclaration)
{
if (refKind == ReferenceKind::MEMBER) {
obj_ = pg_->AllocReg();
node_->AsMemberExpression()->CompileObject(pg_, obj_);
prop_ = node->AsMemberExpression()->CompileKey(pg_);
}
}
void LReference::GetValue()
{
switch (refKind_) {
case ReferenceKind::VAR_OR_GLOBAL: {
pg_->LoadVar(node_->AsIdentifier(), res_);
break;
}
case ReferenceKind::MEMBER: {
pg_->LoadObjProperty(node_, obj_, prop_);
break;
}
default: {
UNREACHABLE();
}
}
}
void LReference::SetValue()
{
switch (refKind_) {
case ReferenceKind::VAR_OR_GLOBAL: {
pg_->StoreVar(node_, res_, isDeclaration_);
break;
}
case ReferenceKind::MEMBER: {
if (node_->AsMemberExpression()->Object()->IsSuperExpression()) {
pg_->StoreSuperProperty(node_, obj_, prop_);
} else {
pg_->StoreObjProperty(node_, obj_, prop_);
}
break;
}
case ReferenceKind::DESTRUCTURING: {
Destructuring::Compile(pg_, node_->AsExpression());
break;
}
default: {
UNREACHABLE();
}
}
}
ReferenceKind LReference::Kind() const
{
return refKind_;
}
binder::Variable *LReference::Variable() const
{
return res_.variable;
}
LReference LReference::CreateLRef(PandaGen *pg, const ir::AstNode *node, bool isDeclaration)
{
switch (node->Type()) {
case ir::AstNodeType::IDENTIFIER: {
const util::StringView &name = node->AsIdentifier()->Name();
binder::ScopeFindResult res = pg->Scope()->Find(name);
return {node, pg, isDeclaration, ReferenceKind::VAR_OR_GLOBAL, res};
}
case ir::AstNodeType::MEMBER_EXPRESSION: {
return {node, pg, false, ReferenceKind::MEMBER, {}};
}
case ir::AstNodeType::VARIABLE_DECLARATION: {
ASSERT(node->AsVariableDeclaration()->Declarators().size() == 1);
return LReference::CreateLRef(pg, node->AsVariableDeclaration()->Declarators()[0]->Id(), true);
}
case ir::AstNodeType::VARIABLE_DECLARATOR: {
return LReference::CreateLRef(pg, node->AsVariableDeclarator()->Id(), true);
}
case ir::AstNodeType::ARRAY_PATTERN:
case ir::AstNodeType::OBJECT_PATTERN: {
return {node, pg, isDeclaration, ReferenceKind::DESTRUCTURING, {}};
}
case ir::AstNodeType::ASSIGNMENT_PATTERN: {
return LReference::CreateLRef(pg, node->AsAssignmentPattern()->Left(), true);
}
case ir::AstNodeType::REST_ELEMENT: {
return LReference::CreateLRef(pg, node->AsRestElement()->Argument(), true);
}
default: {
UNREACHABLE();
}
}
}
} // namespace panda::es2panda::compiler
+68
View File
@@ -0,0 +1,68 @@
/*
* 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.
*/
#ifndef ES2PANDA_COMPILER_BASE_LREFERENCE_H
#define ES2PANDA_COMPILER_BASE_LREFERENCE_H
#include <binder/scope.h>
#include <ir/irnode.h>
namespace panda::es2panda::ir {
class AstNode;
} // namespace panda::es2panda::ir
namespace panda::es2panda::compiler {
enum class ReferenceKind {
MEMBER,
VAR_OR_GLOBAL,
DESTRUCTURING,
};
enum class ReferenceFlags {
NONE = 0,
DECLARATION = 1U << 0U,
};
class PandaGen;
class LReference {
public:
LReference(const ir::AstNode *node, PandaGen *pg, bool isDeclaration, ReferenceKind refKind,
binder::ScopeFindResult res);
~LReference() = default;
NO_COPY_SEMANTIC(LReference);
NO_MOVE_SEMANTIC(LReference);
void GetValue();
void SetValue();
binder::Variable *Variable() const;
ReferenceKind Kind() const;
static LReference CreateLRef(PandaGen *pg, const ir::AstNode *node, bool isDeclaration);
private:
const ir::AstNode *node_;
PandaGen *pg_;
ReferenceKind refKind_;
binder::ScopeFindResult res_;
VReg obj_;
Operand prop_;
bool isDeclaration_;
};
} // namespace panda::es2panda::compiler
#endif
+155
View File
@@ -0,0 +1,155 @@
/*
* 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 "compileQueue.h"
#include <binder/binder.h>
#include <binder/scope.h>
#include <compiler/core/compilerContext.h>
#include <compiler/core/emitter.h>
#include <compiler/core/function.h>
#include <compiler/core/pandagen.h>
namespace panda::es2panda::compiler {
void CompileJob::Run()
{
std::unique_lock<std::mutex> lock(m_);
cond_.wait(lock, [this] { return dependencies_ == 0; });
ArenaAllocator allocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true);
PandaGen pg(&allocator, context_, scope_);
Function::Compile(&pg);
FunctionEmitter funcEmitter(&allocator, &pg);
funcEmitter.Generate();
context_->GetEmitter()->AddFunction(&funcEmitter);
if (dependant_) {
dependant_->Signal();
}
}
void CompileJob::DependsOn(CompileJob *job)
{
job->dependant_ = this;
dependencies_++;
}
void CompileJob::Signal()
{
{
std::lock_guard<std::mutex> lock(m_);
dependencies_--;
}
cond_.notify_one();
}
CompileQueue::CompileQueue(size_t threadCount)
{
threads_.reserve(threadCount);
for (size_t i = 0; i < threadCount; i++) {
threads_.push_back(os::thread::ThreadStart(Worker, this));
}
}
CompileQueue::~CompileQueue()
{
void *retval = nullptr;
std::unique_lock<std::mutex> lock(m_);
terminate_ = true;
lock.unlock();
jobsAvailable_.notify_all();
for (const auto handle_id : threads_) {
os::thread::ThreadJoin(handle_id, &retval);
}
}
void CompileQueue::Schedule(CompilerContext *context)
{
ASSERT(jobsCount_ == 0);
std::unique_lock<std::mutex> lock(m_);
const auto &functions = context->Binder()->Functions();
jobs_ = new CompileJob[functions.size()]();
for (auto *function : functions) {
jobs_[jobsCount_++].SetConext(context, function);
}
lock.unlock();
jobsAvailable_.notify_all();
}
void CompileQueue::Worker(CompileQueue *queue)
{
while (true) {
std::unique_lock<std::mutex> lock(queue->m_);
queue->jobsAvailable_.wait(lock, [queue]() { return queue->terminate_ || queue->jobsCount_ != 0; });
if (queue->terminate_) {
return;
}
lock.unlock();
queue->Consume();
queue->jobsFinished_.notify_one();
}
}
void CompileQueue::Consume()
{
std::unique_lock<std::mutex> lock(m_);
activeWorkers_++;
while (jobsCount_ > 0) {
--jobsCount_;
auto &job = jobs_[jobsCount_];
lock.unlock();
try {
job.Run();
} catch (const Error &e) {
lock.lock();
errors_.push_back(e);
lock.unlock();
}
lock.lock();
}
activeWorkers_--;
}
void CompileQueue::Wait()
{
std::unique_lock<std::mutex> lock(m_);
jobsFinished_.wait(lock, [this]() { return activeWorkers_ == 0 && jobsCount_ == 0; });
delete[] jobs_;
if (!errors_.empty()) {
// NOLINTNEXTLINE
throw errors_.front();
}
}
} // namespace panda::es2panda::compiler
+92
View File
@@ -0,0 +1,92 @@
/*
* 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.
*/
#ifndef ES2PANDA_COMPILER_CORE_COMPILEQUEUE_H
#define ES2PANDA_COMPILER_CORE_COMPILEQUEUE_H
#include <macros.h>
#include <os/thread.h>
#include <es2panda.h>
#include <condition_variable>
#include <mutex>
namespace panda::es2panda::binder {
class FunctionScope;
} // namespace panda::es2panda::binder
namespace panda::es2panda::compiler {
class CompilerContext;
class CompileJob {
public:
CompileJob() = default;
NO_COPY_SEMANTIC(CompileJob);
NO_MOVE_SEMANTIC(CompileJob);
~CompileJob() = default;
binder::FunctionScope *Scope() const
{
return scope_;
}
void SetConext(CompilerContext *context, binder::FunctionScope *scope)
{
context_ = context;
scope_ = scope;
}
void Run();
void DependsOn(CompileJob *job);
void Signal();
private:
std::mutex m_;
std::condition_variable cond_;
CompilerContext *context_ {};
binder::FunctionScope *scope_ {};
CompileJob *dependant_ {};
size_t dependencies_ {0};
};
class CompileQueue {
public:
explicit CompileQueue(size_t threadCount);
NO_COPY_SEMANTIC(CompileQueue);
NO_MOVE_SEMANTIC(CompileQueue);
~CompileQueue();
void Schedule(CompilerContext *context);
void Consume();
void Wait();
private:
static void Worker(CompileQueue *queue);
std::vector<os::thread::native_handle_type> threads_;
std::vector<Error> errors_;
std::mutex m_;
std::condition_variable jobsAvailable_;
std::condition_variable jobsFinished_;
CompileJob *jobs_ {};
size_t jobsCount_ {0};
size_t activeWorkers_ {0};
bool terminate_ {false};
};
} // namespace panda::es2panda::compiler
#endif
@@ -0,0 +1,27 @@
/*
* 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 "compilerContext.h"
#include <compiler/core/emitter.h>
namespace panda::es2panda::compiler {
CompilerContext::CompilerContext(binder::Binder *binder, bool isDebug)
: binder_(binder), emitter_(std::make_unique<class Emitter>(this)), isDebug_(isDebug)
{
}
} // namespace panda::es2panda::compiler
+82
View File
@@ -0,0 +1,82 @@
/**
* 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.
*/
#ifndef ES2PANDA_COMPILER_CORE_COMPILER_CONTEXT_H
#define ES2PANDA_COMPILER_CORE_COMPILER_CONTEXT_H
#include <macros.h>
#include <mem/arena_allocator.h>
#include <cstdint>
#include <mutex>
namespace panda::es2panda::binder {
class Binder;
} // namespace panda::es2panda::binder
namespace panda::es2panda::compiler {
class DebugInfo;
class Emitter;
class CompilerContext {
public:
CompilerContext(binder::Binder *binder, bool isDebug);
NO_COPY_SEMANTIC(CompilerContext);
NO_MOVE_SEMANTIC(CompilerContext);
~CompilerContext() = default;
binder::Binder *Binder() const
{
return binder_;
}
Emitter *GetEmitter() const
{
return emitter_.get();
}
int32_t LiteralCount() const
{
return literalBufferIdx_;
}
int32_t NewLiteralIndex()
{
std::lock_guard lock(m_);
return literalBufferIdx_++;
}
std::mutex &Mutex()
{
return m_;
}
bool IsDebug() const
{
return isDebug_;
}
private:
binder::Binder *binder_;
std::unique_ptr<Emitter> emitter_;
int32_t literalBufferIdx_ {0};
std::mutex m_;
bool isDebug_;
};
} // namespace panda::es2panda::compiler
#endif
+64
View File
@@ -0,0 +1,64 @@
/**
* Copyright (c) 2021 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 "compilerImpl.h"
#include <compiler/core/compileQueue.h>
#include <compiler/core/compilerContext.h>
#include <compiler/core/emitter.h>
#include <typescript/checker.h>
#include <es2panda.h>
#include <parser/program/program.h>
#include <iostream>
#include <thread>
namespace panda::es2panda::compiler {
CompilerImpl::CompilerImpl(size_t threadCount) : queue_(new CompileQueue(threadCount)) {}
CompilerImpl::~CompilerImpl()
{
delete queue_;
}
panda::pandasm::Program *CompilerImpl::Compile(parser::Program *program, const es2panda::CompilerOptions &options)
{
CompilerContext context(program->Binder(), options.isDebug);
if (program->Extension() == ScriptExtension::TS) {
ArenaAllocator localAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true);
auto checker = std::make_unique<checker::Checker>(&localAllocator, context.Binder());
checker->StartChecker();
/* TODO(): TS files are not yet compiled */
return nullptr;
}
queue_->Schedule(&context);
/* Main thread can also be used instead of idling */
queue_->Consume();
queue_->Wait();
return context.GetEmitter()->Finalize(options.dumpDebugInfo);
}
void CompilerImpl::DumpAsm(const panda::pandasm::Program *prog)
{
Emitter::DumpAsm(prog);
}
} // namespace panda::es2panda::compiler
+52
View File
@@ -0,0 +1,52 @@
/**
* 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.
*/
#ifndef ES2PANDA_COMPILER_INCLUDE_COMPILER_IMPL_H
#define ES2PANDA_COMPILER_INCLUDE_COMPILER_IMPL_H
#include <es2panda.h>
#include <macros.h>
#include <mem/arena_allocator.h>
#include <os/thread.h>
#include <string>
namespace panda::pandasm {
struct Program;
} // namespace panda::pandasm
namespace panda::es2panda::parser {
class Program;
} // namespace panda::es2panda::parser
namespace panda::es2panda::compiler {
class CompileQueue;
class CompilerImpl {
public:
explicit CompilerImpl(size_t threadCount);
~CompilerImpl();
NO_COPY_SEMANTIC(CompilerImpl);
NO_MOVE_SEMANTIC(CompilerImpl);
panda::pandasm::Program *Compile(parser::Program *program, const es2panda::CompilerOptions &options);
static void DumpAsm(const panda::pandasm::Program *prog);
private:
CompileQueue *queue_;
};
} // namespace panda::es2panda::compiler
#endif
+178
View File
@@ -0,0 +1,178 @@
/**
* Copyright (c) 2021 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 "dynamicContext.h"
#include <compiler/core/pandagen.h>
#include <compiler/base/catchTable.h>
#include <ir/expressions/identifier.h>
#include <ir/statements/tryStatement.h>
#include <ir/statements/blockStatement.h>
#include <ir/statements/labelledStatement.h>
namespace panda::es2panda::compiler {
DynamicContext::DynamicContext(PandaGen *pg, LabelTarget target) : pg_(pg), target_(target), prev_(pg_->dynamicContext_)
{
pg_->dynamicContext_ = this;
}
DynamicContext::~DynamicContext()
{
pg_->dynamicContext_ = prev_;
}
LabelContext::LabelContext(PandaGen *pg, const ir::LabelledStatement *labelledStmt)
: DynamicContext(pg, LabelTarget(labelledStmt->Ident()->Name())), labelledStmt_(labelledStmt)
{
if (!labelledStmt->Body()->IsBlockStatement()) {
return;
}
label_ = pg->AllocLabel();
target_.SetBreakTarget(label_);
}
LabelContext::~LabelContext()
{
if (!label_) {
return;
}
pg_->SetLabel(labelledStmt_, label_);
}
LexEnvContext::LexEnvContext(LoopEnvScope *envScope, PandaGen *pg, LabelTarget target)
: DynamicContext(pg, target), envScope_(envScope)
{
if (!envScope_->HasEnv()) {
return;
}
catchTable_ = pg_->CreateCatchTable();
const auto &labelSet = catchTable_->LabelSet();
const auto *node = envScope_->Scope()->Node();
pg_->SetLabel(node, labelSet.TryBegin());
}
LexEnvContext::~LexEnvContext()
{
if (!envScope_->HasEnv()) {
return;
}
const auto &labelSet = catchTable_->LabelSet();
const auto *node = envScope_->Scope()->Node();
pg_->SetLabel(node, labelSet.TryEnd());
pg_->Branch(node, labelSet.CatchEnd());
pg_->SetLabel(node, labelSet.CatchBegin());
pg_->PopLexEnv(node);
pg_->EmitThrow(node);
pg_->SetLabel(node, labelSet.CatchEnd());
pg_->PopLexEnv(node);
}
bool LexEnvContext::HasTryCatch() const
{
return envScope_->HasEnv();
}
void LexEnvContext::AbortContext([[maybe_unused]] ControlFlowChange cfc,
[[maybe_unused]] const util::StringView &targetLabel)
{
if (cfc == ControlFlowChange::CONTINUE || !envScope_->HasEnv()) {
return;
}
const auto *node = envScope_->Scope()->Node();
pg_->PopLexEnv(node);
}
IteratorContext::IteratorContext(PandaGen *pg, const Iterator &iterator, LabelTarget target)
: DynamicContext(pg, target), iterator_(iterator), catchTable_(pg->CreateCatchTable())
{
const auto &labelSet = catchTable_->LabelSet();
pg_->SetLabel(iterator_.Node(), labelSet.TryBegin());
}
IteratorContext::~IteratorContext()
{
const auto &labelSet = catchTable_->LabelSet();
const auto *node = iterator_.Node();
pg_->SetLabel(node, labelSet.TryEnd());
pg_->Branch(node, labelSet.CatchEnd());
pg_->SetLabel(node, labelSet.CatchBegin());
iterator_.Close(true);
pg_->SetLabel(node, labelSet.CatchEnd());
}
void IteratorContext::AbortContext([[maybe_unused]] ControlFlowChange cfc,
[[maybe_unused]] const util::StringView &targetLabel)
{
if (cfc == ControlFlowChange::CONTINUE && target_.ContinueLabel() == targetLabel) {
return;
}
iterator_.Close(false);
}
void TryContext::InitFinalizer()
{
ASSERT(tryStmt_);
if (!hasFinalizer_ || !tryStmt_->FinallyBlock()) {
return;
}
finalizerRun_ = pg_->AllocReg();
pg_->StoreConst(tryStmt_, finalizerRun_, Constant::JS_UNDEFINED);
}
void TryContext::InitCatchTable()
{
catchTable_ = pg_->CreateCatchTable();
}
const TryLabelSet &TryContext::LabelSet() const
{
return catchTable_->LabelSet();
}
bool TryContext::HasFinalizer() const
{
return hasFinalizer_;
}
void TryContext::EmitFinalizer()
{
if (!hasFinalizer_ || inFinalizer_ || !tryStmt_->FinallyBlock()) {
return;
}
inFinalizer_ = true;
tryStmt_->FinallyBlock()->Compile(pg_);
inFinalizer_ = false;
}
void TryContext::AbortContext([[maybe_unused]] ControlFlowChange cfc,
[[maybe_unused]] const util::StringView &targetLabel)
{
EmitFinalizer();
}
} // namespace panda::es2panda::compiler
+211
View File
@@ -0,0 +1,211 @@
/**
* Copyright (c) 2021 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.
*/
#ifndef ES2PANDA_COMPILER_CORE_DYNAMIC_CONTEXT_H
#define ES2PANDA_COMPILER_CORE_DYNAMIC_CONTEXT_H
#include <util/ustring.h>
#include <ir/irnode.h>
#include <compiler/core/labelTarget.h>
#include <compiler/base/iterators.h>
namespace panda::es2panda::ir {
class TryStatement;
class ForOfStatement;
class LabelledStatement;
} // namespace panda::es2panda::ir
namespace panda::es2panda::compiler {
class PandaGen;
class LoopEnvScope;
class CatchTable;
class TryLabelSet;
enum class DynamicContextType { NONE, LABEL, LEX_ENV, ITERATOR, TRY };
class DynamicContext {
public:
NO_COPY_SEMANTIC(DynamicContext);
NO_MOVE_SEMANTIC(DynamicContext);
~DynamicContext();
void *operator new(size_t) = delete;
void *operator new[](size_t) = delete;
virtual void AbortContext([[maybe_unused]] ControlFlowChange cfc,
[[maybe_unused]] const util::StringView &targetLabel) {};
virtual bool HasTryCatch() const
{
return false;
}
virtual bool HasFinalizer() const
{
return HasTryCatch();
}
virtual DynamicContextType Type() const = 0;
DynamicContext *Prev()
{
return prev_;
}
const DynamicContext *Prev() const
{
return prev_;
}
const LabelTarget &Target() const
{
return target_;
}
protected:
explicit DynamicContext(PandaGen *pg, LabelTarget target);
PandaGen *pg_;
LabelTarget target_;
DynamicContext *prev_ {};
};
class LabelContext : public DynamicContext {
public:
explicit LabelContext(PandaGen *pg, LabelTarget target) : DynamicContext(pg, target) {}
explicit LabelContext(PandaGen *pg, const ir::LabelledStatement *labelledStmt);
NO_COPY_SEMANTIC(LabelContext);
NO_MOVE_SEMANTIC(LabelContext);
~LabelContext();
DynamicContextType Type() const override
{
return DynamicContextType::LABEL;
}
private:
Label *label_ {};
const ir::LabelledStatement *labelledStmt_ {};
};
class LexEnvContext : public DynamicContext {
public:
explicit LexEnvContext(LoopEnvScope *envScope, PandaGen *pg, LabelTarget target);
NO_COPY_SEMANTIC(LexEnvContext);
NO_MOVE_SEMANTIC(LexEnvContext);
~LexEnvContext();
DynamicContextType Type() const override
{
return DynamicContextType::LEX_ENV;
}
bool HasTryCatch() const override;
void AbortContext([[maybe_unused]] ControlFlowChange cfc,
[[maybe_unused]] const util::StringView &targetLabel) override;
private:
LoopEnvScope *envScope_;
CatchTable *catchTable_ {};
};
class IteratorContext : public DynamicContext {
public:
explicit IteratorContext(PandaGen *pg, const Iterator &iterator, LabelTarget target);
NO_COPY_SEMANTIC(IteratorContext);
NO_MOVE_SEMANTIC(IteratorContext);
~IteratorContext();
DynamicContextType Type() const override
{
return DynamicContextType::ITERATOR;
}
const Iterator &GetIterator() const
{
return iterator_;
}
bool HasTryCatch() const override
{
return true;
}
void AbortContext([[maybe_unused]] ControlFlowChange cfc,
[[maybe_unused]] const util::StringView &targetLabel) override;
private:
const Iterator &iterator_;
CatchTable *catchTable_;
};
class TryContext : public DynamicContext {
public:
explicit TryContext(PandaGen *pg, const ir::TryStatement *tryStmt, bool hasFinalizer = true)
: DynamicContext(pg, {}), tryStmt_(tryStmt), hasFinalizer_(hasFinalizer)
{
InitCatchTable();
InitFinalizer();
}
explicit TryContext(PandaGen *pg) : DynamicContext(pg, {})
{
InitCatchTable();
}
NO_COPY_SEMANTIC(TryContext);
NO_MOVE_SEMANTIC(TryContext);
~TryContext() = default;
DynamicContextType Type() const override
{
return DynamicContextType::TRY;
}
bool HasTryCatch() const override
{
return true;
}
VReg FinalizerRun() const
{
return finalizerRun_;
}
CatchTable *GetCatchTable() const
{
return catchTable_;
}
const TryLabelSet &LabelSet() const;
bool HasFinalizer() const override;
void InitFinalizer();
void EmitFinalizer();
void AbortContext([[maybe_unused]] ControlFlowChange cfc,
[[maybe_unused]] const util::StringView &targetLabel) override;
private:
void InitCatchTable();
const ir::TryStatement *tryStmt_ {};
CatchTable *catchTable_ {};
VReg finalizerRun_ {};
bool hasFinalizer_ {};
bool inFinalizer_ {};
};
} // namespace panda::es2panda::compiler
#endif
+446
View File
@@ -0,0 +1,446 @@
/**
* Copyright (c) 2021 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 "emitter.h"
#include <binder/binder.h>
#include <util/helpers.h>
#include <binder/scope.h>
#include <binder/variable.h>
#include <compiler/base/literals.h>
#include <compiler/core/compilerContext.h>
#include <compiler/core/pandagen.h>
#include <compiler/debugger/debuginfoDumper.h>
#include <compiler/base/catchTable.h>
#include <es2panda.h>
#include <gen/isa.h>
#include <ir/expressions/literal.h>
#include <ir/statements/blockStatement.h>
#include <macros.h>
#include <parser/program/program.h>
#include <string>
#include <string_view>
#include <tuple>
#include <utility>
namespace panda::es2panda::compiler {
constexpr const auto LANG_EXT = panda::pandasm::extensions::Language::ECMASCRIPT;
FunctionEmitter::FunctionEmitter(ArenaAllocator *allocator, const PandaGen *pg)
: pg_(pg), literalBuffers_(allocator->Adapter())
{
func_ = allocator->New<panda::pandasm::Function>(pg->InternalName().Mutf8(), LANG_EXT);
size_t paramCount = pg->InternalParamCount();
func_->params.reserve(paramCount);
for (uint32_t i = 0; i < paramCount; ++i) {
func_->params.emplace_back(panda::pandasm::Type("any", 0), LANG_EXT);
}
func_->regs_num = pg->TotalRegsNum();
func_->return_type = panda::pandasm::Type("any", 0);
}
void FunctionEmitter::Generate()
{
GenFunctionInstructions();
GenVariablesDebugInfo();
GenSourceFileDebugInfo();
GenFunctionCatchTables();
GenFunctionICSize();
GenLiteralBuffers();
}
const ArenaSet<util::StringView> &FunctionEmitter::Strings() const
{
return pg_->Strings();
}
void FunctionEmitter::GenBufferLiterals(const LiteralBuffer *buff)
{
auto &[idx, array] = literalBuffers_.emplace_back();
idx = buff->Index();
array.reserve(buff->Literals().size() * 2);
for (const auto *literal : buff->Literals()) {
panda::pandasm::LiteralArray::Literal valueLit;
panda::pandasm::LiteralArray::Literal tagLit;
ir::LiteralTag tag = literal->Tag();
switch (tag) {
case ir::LiteralTag::BOOLEAN: {
valueLit.tag_ = panda::panda_file::LiteralTag::BOOL;
valueLit.value_ = literal->GetBoolean();
break;
}
case ir::LiteralTag::INTEGER: {
valueLit.tag_ = panda::panda_file::LiteralTag::INTEGER;
valueLit.value_ = literal->GetInt();
break;
}
case ir::LiteralTag::DOUBLE: {
valueLit.tag_ = panda::panda_file::LiteralTag::DOUBLE;
valueLit.value_ = literal->GetDouble();
break;
}
case ir::LiteralTag::STRING: {
valueLit.tag_ = panda::panda_file::LiteralTag::STRING;
valueLit.value_ = literal->GetString().Mutf8();
break;
}
case ir::LiteralTag::ACCESSOR: {
valueLit.tag_ = panda::panda_file::LiteralTag::ACCESSOR;
valueLit.value_ = static_cast<uint8_t>(0);
break;
}
case ir::LiteralTag::METHOD: {
valueLit.tag_ = panda::panda_file::LiteralTag::METHOD;
valueLit.value_ = literal->GetMethod().Mutf8();
break;
}
case ir::LiteralTag::GENERATOR_METHOD: {
valueLit.tag_ = panda::panda_file::LiteralTag::GENERATORMETHOD;
valueLit.value_ = literal->GetMethod().Mutf8();
break;
}
case ir::LiteralTag::ASYNC_GENERATOR_METHOD: {
valueLit.tag_ = panda::panda_file::LiteralTag::ASYNCGENERATORMETHOD;
valueLit.value_ = literal->GetMethod().Mutf8();
break;
}
case ir::LiteralTag::NULL_VALUE: {
valueLit.tag_ = panda::panda_file::LiteralTag::NULLVALUE;
valueLit.value_ = static_cast<uint8_t>(0);
break;
}
default:
break;
}
tagLit.tag_ = panda::panda_file::LiteralTag::TAGVALUE;
tagLit.value_ = static_cast<uint8_t>(valueLit.tag_);
array.emplace_back(tagLit);
array.emplace_back(valueLit);
}
}
util::StringView FunctionEmitter::SourceCode() const
{
return pg_->Binder()->Program()->SourceCode();
}
static Format MatchFormat(const IRNode *node, const Formats &formats)
{
std::array<const VReg *, IRNode::MAX_REG_OPERAND> regs {};
auto regCnt = node->Registers(&regs);
auto registers = Span<const VReg *>(regs.data(), regs.data() + regCnt);
const auto *iter = formats.begin();
for (; iter != formats.end(); iter++) {
auto format = *iter;
size_t limit = 0;
for (const auto &formatItem : format.GetFormatItem()) {
if (formatItem.IsVReg()) {
limit = 1 << formatItem.Bitwidth();
break;
}
}
if (std::all_of(registers.begin(), registers.end(), [limit](const VReg *reg) { return *reg < limit; })) {
return format;
}
}
UNREACHABLE();
return *iter;
}
static size_t GetIRNodeWholeLength(const IRNode *node)
{
Formats formats = node->GetFormats();
if (formats.empty()) {
return 0;
}
size_t len = 1;
const auto format = MatchFormat(node, formats);
for (auto fi : format.GetFormatItem()) {
len += fi.Bitwidth() / 8;
}
return len;
}
static std::string WholeLine(const util::StringView &source, lexer::SourceRange range)
{
return source.Substr(range.start.index, range.end.index).EscapeSymbol<util::StringView::Mutf8Encode>();
}
void FunctionEmitter::GenInstructionDebugInfo(const IRNode *ins, panda::pandasm::Ins *pandaIns)
{
const ir::AstNode *astNode = ins->Node();
ASSERT(astNode != nullptr);
if (astNode == FIRST_NODE_OF_FUNCTION) {
astNode = pg_->Debuginfo().firstStmt;
if (!astNode) {
return;
}
}
pandaIns->ins_debug.line_number = astNode->Range().start.line + 1;
if (pg_->IsDebug()) {
size_t insLen = GetIRNodeWholeLength(ins);
if (insLen != 0) {
pandaIns->ins_debug.bound_left = offset_;
pandaIns->ins_debug.bound_right = offset_ + insLen;
}
offset_ += insLen;
pandaIns->ins_debug.whole_line = WholeLine(SourceCode(), astNode->Range());
}
}
void FunctionEmitter::GenFunctionInstructions()
{
func_->ins.reserve(pg_->Insns().size());
for (const auto *ins : pg_->Insns()) {
auto &pandaIns = func_->ins.emplace_back();
ins->Transform(&pandaIns);
GenInstructionDebugInfo(ins, &pandaIns);
}
}
void FunctionEmitter::GenFunctionICSize()
{
panda::pandasm::AnnotationData funcAnnotationData("_ESAnnotation");
panda::pandasm::AnnotationElement icSizeAnnotationElement(
"icSize", std::make_unique<panda::pandasm::ScalarValue>(
panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U32>(pg_->IcSize())));
funcAnnotationData.AddElement(std::move(icSizeAnnotationElement));
panda::pandasm::AnnotationElement parameterLengthAnnotationElement(
"parameterLength",
std::make_unique<panda::pandasm::ScalarValue>(
panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U32>(pg_->FormalParametersCount())));
funcAnnotationData.AddElement(std::move(parameterLengthAnnotationElement));
panda::pandasm::AnnotationElement funcNameAnnotationElement(
"funcName",
std::make_unique<panda::pandasm::ScalarValue>(
panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::STRING>(pg_->FunctionName().Mutf8())));
funcAnnotationData.AddElement(std::move(funcNameAnnotationElement));
func_->metadata->AddAnnotations({funcAnnotationData});
}
void FunctionEmitter::GenFunctionCatchTables()
{
func_->catch_blocks.reserve(pg_->CatchList().size());
for (const auto *catchBlock : pg_->CatchList()) {
const auto &labelSet = catchBlock->LabelSet();
auto &pandaCatchBlock = func_->catch_blocks.emplace_back();
pandaCatchBlock.try_begin_label = labelSet.TryBegin()->Id();
pandaCatchBlock.try_end_label = labelSet.TryEnd()->Id();
pandaCatchBlock.catch_begin_label = labelSet.CatchBegin()->Id();
pandaCatchBlock.catch_end_label = labelSet.CatchEnd()->Id();
}
}
void FunctionEmitter::GenLiteralBuffers()
{
for (const auto *buff : pg_->BuffStorage()) {
GenBufferLiterals(buff);
}
}
void FunctionEmitter::GenSourceFileDebugInfo()
{
func_->source_file = std::string {pg_->Binder()->Program()->SourceFile()};
if (!pg_->IsDebug()) {
return;
}
if (pg_->RootNode()->IsProgram()) {
func_->source_code = SourceCode().EscapeSymbol<util::StringView::Mutf8Encode>();
}
}
void FunctionEmitter::GenScopeVariableInfo(const binder::Scope *scope)
{
const auto *startIns = scope->ScopeStart();
const auto *endIns = scope->ScopeEnd();
uint32_t start = 0;
uint32_t count = 0;
for (const auto *it : pg_->Insns()) {
if (startIns == it) {
start = count;
} else if (endIns == it) {
auto varsLength = static_cast<uint32_t>(count - start + 1);
for (const auto &[name, variable] : scope->Bindings()) {
if (!variable->IsLocalVariable() || variable->LexicalBound()) {
continue;
}
auto &variableDebug = func_->local_variable_debug.emplace_back();
variableDebug.name = name.Mutf8();
variableDebug.signature = "any";
variableDebug.signature_type = "any";
variableDebug.reg = static_cast<int32_t>(variable->AsLocalVariable()->Vreg());
variableDebug.start = start;
variableDebug.length = static_cast<uint32_t>(varsLength);
}
break;
}
count++;
}
}
void FunctionEmitter::GenVariablesDebugInfo()
{
if (!pg_->IsDebug()) {
return;
}
for (const auto *scope : pg_->Debuginfo().variableDebugInfo) {
GenScopeVariableInfo(scope);
}
}
// Emitter
Emitter::Emitter(const CompilerContext *context)
{
prog_ = new panda::pandasm::Program();
prog_->lang = panda::pandasm::extensions::Language::ECMASCRIPT;
prog_->function_table.reserve(context->Binder()->Functions().size());
GenESAnnoatationRecord();
GenESModuleModeRecord(context->Binder()->Program()->Kind() == parser::ScriptKind::MODULE);
}
Emitter::~Emitter()
{
delete prog_;
}
void Emitter::GenESAnnoatationRecord()
{
auto annotationRecord = panda::pandasm::Record("_ESAnnotation", LANG_EXT);
annotationRecord.metadata->SetAttribute("external");
annotationRecord.metadata->SetAccessFlags(panda::ACC_ANNOTATION);
prog_->record_table.emplace(annotationRecord.name, std::move(annotationRecord));
}
void Emitter::GenESModuleModeRecord(bool isModule)
{
auto modeRecord = panda::pandasm::Record("_ESModuleMode", LANG_EXT);
modeRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC);
auto modeField = panda::pandasm::Field(LANG_EXT);
modeField.name = "isModule";
modeField.type = panda::pandasm::Type("u8", 0);
modeField.metadata->SetValue(
panda::pandasm::ScalarValue::Create<panda::pandasm::Value::Type::U8>(static_cast<uint8_t>(isModule)));
modeRecord.field_list.emplace_back(std::move(modeField));
prog_->record_table.emplace(modeRecord.name, std::move(modeRecord));
}
void Emitter::AddFunction(FunctionEmitter *func)
{
std::lock_guard<std::mutex> lock(m_);
for (const auto &str : func->Strings()) {
prog_->strings.insert(str.Mutf8());
}
for (auto &[idx, buf] : func->LiteralBuffers()) {
auto literalArrayInstance = panda::pandasm::LiteralArray(std::move(buf));
prog_->literalarray_table.emplace(std::to_string(idx), std::move(literalArrayInstance));
}
auto *function = func->Function();
prog_->function_table.emplace(function->name, std::move(*function));
}
void Emitter::DumpAsm(const panda::pandasm::Program *prog)
{
auto &ss = std::cout;
ss << ".language ECMAScript" << std::endl << std::endl;
for (auto &[name, func] : prog->function_table) {
ss << ".function any " << name << '(';
for (uint32_t i = 0; i < func.GetParamsNum(); i++) {
ss << "any a" << std::to_string(i);
if (i != func.GetParamsNum() - 1) {
ss << ", ";
}
}
ss << ") {" << std::endl;
for (const auto &ins : func.ins) {
ss << (ins.set_label ? "" : "\t") << ins.ToString("", true, func.GetTotalRegs()) << std::endl;
}
ss << "}" << std::endl << std::endl;
for (const auto &ct : func.catch_blocks) {
ss << ".catchall " << ct.try_begin_label << ", " << ct.try_end_label << ", " << ct.catch_begin_label
<< std::endl
<< std::endl;
}
}
ss << std::endl;
}
panda::pandasm::Program *Emitter::Finalize(bool dumpDebugInfo)
{
if (dumpDebugInfo) {
debuginfo::DebugInfoDumper dumper(prog_);
dumper.Dump();
}
auto *prog = prog_;
prog_ = nullptr;
return prog;
}
} // namespace panda::es2panda::compiler
+115
View File
@@ -0,0 +1,115 @@
/**
* 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.
*/
#ifndef ES2PANDA_COMPILER_IR_EMITTER_H
#define ES2PANDA_COMPILER_IR_EMITTER_H
#include <assembly-literals.h>
#include <ir/astNode.h>
#include <lexer/token/sourceLocation.h>
#include <macros.h>
#include <util/ustring.h>
#include <list>
#include <mutex>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
namespace panda::pandasm {
struct Program;
struct Function;
struct Ins;
} // namespace panda::pandasm
namespace panda::es2panda::ir {
class Statement;
} // namespace panda::es2panda::ir
namespace panda::es2panda::binder {
class Scope;
} // namespace panda::es2panda::binder
namespace panda::es2panda::compiler {
class PandaGen;
class LiteralBuffer;
class DebugInfo;
class Label;
class IRNode;
class CompilerContext;
class FunctionEmitter {
public:
explicit FunctionEmitter(ArenaAllocator *allocator, const PandaGen *pg);
~FunctionEmitter() = default;
NO_COPY_SEMANTIC(FunctionEmitter);
NO_MOVE_SEMANTIC(FunctionEmitter);
panda::pandasm::Function *Function()
{
return func_;
}
auto &LiteralBuffers()
{
return literalBuffers_;
}
void Generate();
const ArenaSet<util::StringView> &Strings() const;
private:
void GenInstructionDebugInfo(const IRNode *ins, panda::pandasm::Ins *pandaIns);
void GenFunctionInstructions();
void GenFunctionCatchTables();
void GenFunctionICSize();
void GenScopeVariableInfo(const binder::Scope *scope);
void GenSourceFileDebugInfo();
void GenVariablesDebugInfo();
util::StringView SourceCode() const;
void GenLiteralBuffers();
void GenBufferLiterals(const LiteralBuffer *buff);
const PandaGen *pg_;
panda::pandasm::Function *func_ {};
ArenaVector<std::pair<int32_t, std::vector<panda::pandasm::LiteralArray::Literal>>> literalBuffers_;
size_t offset_ {0};
};
class Emitter {
public:
explicit Emitter(const CompilerContext *context);
~Emitter();
NO_COPY_SEMANTIC(Emitter);
NO_MOVE_SEMANTIC(Emitter);
void AddFunction(FunctionEmitter *func);
static void DumpAsm(const panda::pandasm::Program *prog);
panda::pandasm::Program *Finalize(bool dumpDebugInfo);
private:
void GenESAnnoatationRecord();
void GenESModuleModeRecord(bool isModule);
std::mutex m_;
panda::pandasm::Program *prog_;
};
} // namespace panda::es2panda::compiler
#endif
+84
View File
@@ -0,0 +1,84 @@
/*
* 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 "envScope.h"
#include <compiler/core/pandagen.h>
#include <ir/statement.h>
namespace panda::es2panda::compiler {
ScopeContext::ScopeContext(PandaGen *pg, binder::Scope *newScope) : pg_(pg), prevScope_(pg_->scope_)
{
pg_->scope_ = newScope;
}
ScopeContext::~ScopeContext()
{
pg_->scope_ = prevScope_;
}
void EnvScope::Initialize(PandaGen *pg, VReg lexEnv)
{
pg_ = pg;
prev_ = pg_->envScope_;
lexEnv_ = lexEnv;
pg_->envScope_ = this;
}
EnvScope::~EnvScope()
{
if (!pg_) {
return;
}
pg_->envScope_ = prev_;
}
void LoopEnvScope::CopyBindings(PandaGen *pg, binder::VariableScope *scope, binder::VariableFlags flag)
{
if (!HasEnv()) {
return;
}
Initialize(pg, pg->AllocReg());
pg_->NewLexEnv(scope_->Node(), scope->LexicalSlots());
pg_->StoreAccumulator(scope_->Node(), lexEnv_);
ASSERT(scope->NeedLexEnv());
for (const auto &[_, variable] : scope_->Bindings()) {
(void)_;
if (!variable->HasFlag(flag)) {
continue;
}
pg->LoadLexicalVar(scope_->Node(), 1, variable->AsLocalVariable()->LexIdx());
pg->StoreLexicalVar(scope_->Parent()->Node(), 0, variable->AsLocalVariable()->LexIdx());
}
}
void LoopEnvScope::CopyPetIterationCtx()
{
if (!HasEnv()) {
return;
}
pg_->CopyLexEnv(scope_->Node());
pg_->StoreAccumulator(scope_->Node(), lexEnv_);
}
} // namespace panda::es2panda::compiler
+123
View File
@@ -0,0 +1,123 @@
/*
* 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.
*/
#ifndef ES2PANDA_COMPILER_CORE_ENV_SCOPE_H
#define ES2PANDA_COMPILER_CORE_ENV_SCOPE_H
#include <binder/scope.h>
#include <ir/irnode.h>
#include <compiler/core/dynamicContext.h>
#include <compiler/core/regScope.h>
#include <compiler/core/labelTarget.h>
namespace panda::es2panda::ir {
class AstNode;
class Statement;
} // namespace panda::es2panda::ir
namespace panda::es2panda::compiler {
class PandaGen;
class ScopeContext {
public:
explicit ScopeContext(PandaGen *pg, binder::Scope *newScope);
~ScopeContext();
NO_COPY_SEMANTIC(ScopeContext);
NO_MOVE_SEMANTIC(ScopeContext);
private:
PandaGen *pg_;
binder::Scope *prevScope_;
};
class EnvScope {
public:
explicit EnvScope() = default;
NO_COPY_SEMANTIC(EnvScope);
NO_MOVE_SEMANTIC(EnvScope);
~EnvScope();
void Initialize(PandaGen *pg, VReg lexEnv);
VReg LexEnv() const
{
return lexEnv_;
}
EnvScope *Prev() const
{
return prev_;
}
protected:
friend class PandaGen;
PandaGen *pg_ {};
EnvScope *prev_ {};
VReg lexEnv_ {};
};
class LoopEnvScope : public EnvScope {
public:
explicit LoopEnvScope(PandaGen *pg, binder::LoopScope *scope, LabelTarget target)
: scope_(NeedEnv(scope) ? scope : nullptr), regScope_(pg, scope), lexEnvCtx_(this, pg, target)
{
CopyBindings(pg, scope, binder::VariableFlags::PER_ITERATION);
}
explicit LoopEnvScope(PandaGen *pg, LabelTarget target, binder::LoopScope *scope)
: scope_(NeedEnv(scope) ? scope : nullptr), regScope_(pg), lexEnvCtx_(this, pg, target)
{
CopyBindings(pg, scope, binder::VariableFlags::PER_ITERATION);
}
explicit LoopEnvScope(PandaGen *pg, binder::LoopDeclarationScope *scope)
: scope_(NeedEnv(scope) ? scope : nullptr), regScope_(pg), lexEnvCtx_(this, pg, {})
{
CopyBindings(pg, scope, binder::VariableFlags::LOOP_DECL);
}
binder::VariableScope *Scope() const
{
ASSERT(HasEnv());
return scope_;
}
bool HasEnv() const
{
return scope_ != nullptr;
}
void CopyPetIterationCtx();
private:
static bool NeedEnv(binder::VariableScope *scope)
{
return scope->IsVariableScope() && scope->AsVariableScope()->NeedLexEnv();
}
void CopyBindings(PandaGen *pg, binder::VariableScope *scope, binder::VariableFlags flag);
binder::VariableScope *scope_ {};
LocalRegScope regScope_;
LexEnvContext lexEnvCtx_;
};
} // namespace panda::es2panda::compiler
#endif
+208
View File
@@ -0,0 +1,208 @@
/**
* 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
+32
View File
@@ -0,0 +1,32 @@
/*
* 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.
*/
#ifndef ES2PANDA_COMPILER_CORE_FUNCTION_H
#define ES2PANDA_COMPILER_CORE_FUNCTION_H
namespace panda::es2panda::compiler {
class PandaGen;
class Function {
public:
Function() = delete;
static void Compile(PandaGen *pg);
};
} // namespace panda::es2panda::compiler
#endif
+40
View File
@@ -0,0 +1,40 @@
/**
* 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 "inlineCache.h"
#include <limits>
namespace panda::es2panda::compiler {
size_t InlineCache::Size() const
{
return size_;
}
uint32_t InlineCache::Offset(uint32_t slotSize)
{
uint32_t offset = size_ + slotSize;
constexpr uint32_t LIMIT = std::numeric_limits<uint16_t>::max();
if (offset > LIMIT) {
return LIMIT;
}
size_ = offset;
return offset;
}
} // namespace panda::es2panda::compiler
+36
View File
@@ -0,0 +1,36 @@
/**
* 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.
*/
#ifndef ES2PANDA_COMPILER_IR_INLINE_CACHE_H
#define ES2PANDA_COMPILER_IR_INLINE_CACHE_H
#include <macros.h>
namespace panda::es2panda::compiler {
class InlineCache {
public:
explicit InlineCache() = default;
size_t Size() const;
uint32_t Offset(uint32_t slotSize);
private:
size_t size_ {};
};
} // namespace panda::es2panda::compiler
#endif
+43
View File
@@ -0,0 +1,43 @@
/**
* 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.
*/
#ifndef ES2PANDA_COMPILER_CORE_LABEL_PAIR_H
#define ES2PANDA_COMPILER_CORE_LABEL_PAIR_H
#include <macros.h>
#include <ir/irnode.h>
namespace panda::es2panda::compiler {
class LabelPair {
public:
LabelPair(Label *begin, Label *end) : begin_(begin), end_(end) {}
Label *Begin() const
{
return begin_;
}
Label *End() const
{
return end_;
}
protected:
Label *begin_ {};
Label *end_ {};
};
} // namespace panda::es2panda::compiler
#endif
+27
View File
@@ -0,0 +1,27 @@
/**
* 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 "labelTarget.h"
#include <compiler/core/pandagen.h>
namespace panda::es2panda::compiler {
LabelTarget::LabelTarget(PandaGen *pg)
: LabelPair(pg->AllocLabel(), pg->AllocLabel()), breakLabel_(BREAK_LABEL), continueLabel_(CONTINUE_LABEL)
{
}
} // namespace panda::es2panda::compiler
+88
View File
@@ -0,0 +1,88 @@
/**
* Copyright (c) 2021 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.
*/
#ifndef ES2PANDA_COMPILER_CORE_LABEL_TARGET_H
#define ES2PANDA_COMPILER_CORE_LABEL_TARGET_H
#include <ir/irnode.h>
#include <compiler/core/labelPair.h>
#include <unordered_map>
namespace panda::es2panda::ir {
class AstNode;
class Identifier;
} // namespace panda::es2panda::ir
namespace panda::es2panda::compiler {
class LabelTarget;
class PandaGen;
enum class ControlFlowChange {
CONTINUE,
BREAK,
};
class LabelTarget : public LabelPair {
public:
explicit LabelTarget(PandaGen *pg);
explicit LabelTarget(const util::StringView &label) : LabelTarget(nullptr, label) {}
explicit LabelTarget(Label *target, const util::StringView &label)
: LabelPair(target, nullptr), breakLabel_(label), continueLabel_(label)
{
}
LabelTarget() : LabelPair(nullptr, nullptr) {};
~LabelTarget() = default;
DEFAULT_COPY_SEMANTIC(LabelTarget);
DEFAULT_MOVE_SEMANTIC(LabelTarget);
const util::StringView &BreakLabel() const
{
return breakLabel_;
}
Label *BreakTarget() const
{
return begin_;
}
void SetBreakTarget(Label *label)
{
begin_ = label;
}
const util::StringView &ContinueLabel() const
{
return continueLabel_;
}
Label *ContinueTarget() const
{
return end_;
}
static constexpr std::string_view BREAK_LABEL = "#b";
static constexpr std::string_view CONTINUE_LABEL = "#c";
private:
util::StringView breakLabel_ {};
util::StringView continueLabel_ {};
};
} // namespace panda::es2panda::compiler
#endif
+84
View File
@@ -0,0 +1,84 @@
/**
* Copyright (c) 2021 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 "moduleContext.h"
#include <binder/scope.h>
#include <binder/variable.h>
#include <compiler/base/lreference.h>
#include <compiler/core/pandagen.h>
#include <ir/expressions/literals/stringLiteral.h>
#include <ir/module/exportAllDeclaration.h>
#include <ir/module/exportNamedDeclaration.h>
#include <ir/module/importDeclaration.h>
namespace panda::es2panda::compiler {
void CompileImports(PandaGen *pg, binder::ModuleScope *scope)
{
for (const auto &[importDecl, decls] : scope->Imports()) {
pg->ImportModule(importDecl, importDecl->Source()->Str());
VReg moduleReg = pg->AllocReg();
pg->StoreAccumulator(importDecl, moduleReg);
for (const auto *decl : decls) {
binder::Variable *v = scope->FindLocal(decl->LocalName());
if (!v->IsModuleVariable()) {
ASSERT(decl->ImportName() == "*");
binder::ScopeFindResult result(decl->LocalName(), scope, 0, v);
pg->StoreAccToLexEnv(decl->Node(), result, true);
} else {
v->AsModuleVariable()->ModuleReg() = moduleReg;
}
}
}
}
void CompileExports(PandaGen *pg, const binder::ModuleScope *scope)
{
for (const auto &[exportDecl, decls] : scope->Exports()) {
if (exportDecl->IsExportAllDeclaration()) {
pg->ImportModule(exportDecl, exportDecl->AsExportAllDeclaration()->Source()->Str());
} else if (exportDecl->IsExportNamedDeclaration() && exportDecl->AsExportNamedDeclaration()->Source()) {
pg->ImportModule(exportDecl, exportDecl->AsExportNamedDeclaration()->Source()->Str());
} else {
continue;
}
VReg moduleReg = pg->AllocReg();
pg->StoreAccumulator(exportDecl, moduleReg);
if (exportDecl->IsExportAllDeclaration()) {
pg->StoreModuleVar(exportDecl, decls.front()->ExportName());
continue;
}
pg->CopyModule(exportDecl, moduleReg);
for (const auto *decl : decls) {
pg->LoadObjByName(decl->Node(), moduleReg, decl->LocalName());
pg->StoreModuleVar(decl->Node(), decl->ExportName());
}
}
}
void ModuleContext::Compile(PandaGen *pg, binder::ModuleScope *scope)
{
CompileImports(pg, scope);
CompileExports(pg, scope);
}
} // namespace panda::es2panda::compiler
+39
View File
@@ -0,0 +1,39 @@
/**
* 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.
*/
#ifndef ES2PANDA_COMPILER_CORE_MODULE_CONTEXT_H
#define ES2PANDA_COMPILER_CORE_MODULE_CONTEXT_H
#include <util/ustring.h>
#include <vector>
namespace panda::es2panda::binder {
class Variable;
class ModuleScope;
} // namespace panda::es2panda::binder
namespace panda::es2panda::compiler {
class PandaGen;
class ModuleContext {
public:
ModuleContext() = delete;
static void Compile(PandaGen *pg, binder::ModuleScope *scope);
};
} // namespace panda::es2panda::compiler
#endif
File diff suppressed because it is too large Load Diff
+421
View File
@@ -0,0 +1,421 @@
/**
* 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.
*/
#ifndef ES2PANDA_COMPILER_CORE_PANDAGEN_H
#define ES2PANDA_COMPILER_CORE_PANDAGEN_H
#include <compiler/core/envScope.h>
#include <compiler/core/inlineCache.h>
#include <compiler/core/regAllocator.h>
#include <compiler/core/regScope.h>
#include <ir/irnode.h>
#include <lexer/token/tokenType.h>
#include <macros.h>
#include <unordered_map>
namespace panda::es2panda::binder {
class FunctionScope;
class ScopeFindResult;
class Scope;
} // namespace panda::es2panda::binder
namespace panda::es2panda::ir {
class AstNode;
class ScriptFunction;
class Statement;
class Expression;
class Identifier;
} // namespace panda::es2panda::ir
namespace panda::es2panda::compiler {
class FunctionBuilder;
class CompilerContext;
class LiteralBuffer;
class DynamicContext;
class CatchTable;
enum class Constant {
JS_NAN,
JS_HOLE,
JS_INFINITY,
JS_UNDEFINED,
JS_NULL,
JS_TRUE,
JS_FALSE,
JS_SYMBOL,
JS_GLOBAL,
};
class DebugInfo {
public:
explicit DebugInfo(ArenaAllocator *allocator) : variableDebugInfo(allocator->Adapter()) {};
DEFAULT_COPY_SEMANTIC(DebugInfo);
DEFAULT_MOVE_SEMANTIC(DebugInfo);
~DebugInfo() = default;
ArenaVector<const binder::Scope *> variableDebugInfo;
const ir::Statement *firstStmt {};
};
class PandaGen {
public:
explicit PandaGen(ArenaAllocator *allocator, CompilerContext *context, binder::FunctionScope *scope)
: allocator_(allocator),
context_(context),
builder_(nullptr),
debugInfo_(allocator_),
topScope_(scope),
scope_(topScope_),
rootNode_(scope->Node()),
insns_(allocator_->Adapter()),
catchList_(allocator_->Adapter()),
strings_(allocator_->Adapter()),
buffStorage_(allocator_->Adapter()),
sa_(this),
ra_(this),
rra_(this)
{
}
~PandaGen() = default;
NO_COPY_SEMANTIC(PandaGen);
NO_MOVE_SEMANTIC(PandaGen);
inline ArenaAllocator *Allocator() const
{
return allocator_;
}
const ArenaSet<util::StringView> &Strings() const
{
return strings_;
}
const ArenaVector<CatchTable *> &CatchList() const
{
return catchList_;
}
binder::FunctionScope *TopScope() const
{
return topScope_;
}
binder::Scope *Scope() const
{
return scope_;
}
const ir::AstNode *RootNode() const
{
return rootNode_;
}
ArenaList<IRNode *> &Insns()
{
return insns_;
}
const ArenaList<IRNode *> &Insns() const
{
return insns_;
}
VReg AllocReg()
{
return usedRegs_++;
}
VReg NextReg() const
{
return usedRegs_;
}
uint32_t TotalRegsNum() const
{
return totalRegs_;
}
size_t LabelCount() const
{
return labelId_;
}
const DebugInfo &Debuginfo() const
{
return debugInfo_;
}
FunctionBuilder *FuncBuilder() const
{
return builder_;
}
EnvScope *GetEnvScope() const
{
return envScope_;
}
const ArenaVector<compiler::LiteralBuffer *> &BuffStorage() const
{
return buffStorage_;
}
uint32_t IcSize() const
{
return ic_.Size();
}
bool IsDebug() const;
uint32_t ParamCount() const;
uint32_t FormalParametersCount() const;
uint32_t InternalParamCount() const;
const util::StringView &InternalName() const;
const util::StringView &FunctionName() const;
binder::Binder *Binder() const;
Label *AllocLabel();
VReg LexEnv() const;
bool FunctionHasFinalizer() const;
void FunctionInit(CatchTable* catchTable);
void FunctionEnter();
void FunctionExit();
LiteralBuffer *NewLiteralBuffer();
int32_t AddLiteralBuffer(LiteralBuffer *buf);
void InitializeLexEnv(const ir::AstNode *node, VReg lexEnv);
void CopyFunctionArguments(const ir::AstNode *node);
void GetFunctionObject(const ir::AstNode *node);
void GetNewTarget(const ir::AstNode *node);
void GetThis(const ir::AstNode *node);
void SetThis(const ir::AstNode *node);
void LoadVar(const ir::Identifier *node, const binder::ScopeFindResult &result);
void StoreVar(const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDeclaration);
void StoreAccumulator(const ir::AstNode *node, VReg vreg);
void LoadAccFromArgs(const ir::AstNode *node);
void LoadObjProperty(const ir::AstNode *node, VReg obj, const Operand &prop);
void LoadObjByName(const ir::AstNode *node, VReg obj, const util::StringView &prop);
void StoreObjProperty(const ir::AstNode *node, VReg obj, const Operand &prop);
void StoreOwnProperty(const ir::AstNode *node, VReg obj, const Operand &prop);
void DeleteObjProperty(const ir::AstNode *node, VReg obj, const Operand &prop);
void LoadAccumulator(const ir::AstNode *node, VReg reg);
void LoadGlobalVar(const ir::AstNode *node, const util::StringView &name);
void StoreGlobalVar(const ir::AstNode *node, const util::StringView &name);
void StoreGlobalLet(const ir::AstNode *node, const util::StringView &name);
void TryLoadGlobalByValue(const ir::AstNode *node, VReg key);
void TryStoreGlobalByValue(const ir::AstNode *node, VReg key);
void TryLoadGlobalByName(const ir::AstNode *node, const util::StringView &name);
void TryStoreGlobalByName(const ir::AstNode *node, const util::StringView &name);
void LoadAccFromLexEnv(const ir::AstNode *node, const binder::ScopeFindResult &result);
void StoreAccToLexEnv(const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDeclaration);
void LoadAccumulatorString(const ir::AstNode *node, const util::StringView &str);
void LoadAccumulatorFloat(const ir::AstNode *node, double num);
void LoadAccumulatorInt(const ir::AstNode *node, int32_t num);
void LoadAccumulatorInt(const ir::AstNode *node, size_t num);
void LoadConst(const ir::AstNode *node, Constant id);
void StoreConst(const ir::AstNode *node, VReg reg, Constant id);
void MoveVreg(const ir::AstNode *node, VReg vd, VReg vs);
void SetLabel(const ir::AstNode *node, Label *label);
void Branch(const ir::AstNode *node, class Label *label);
bool CheckControlFlowChange();
Label *ControlFlowChangeBreak(const ir::Identifier *label = nullptr);
Label *ControlFlowChangeContinue(const ir::Identifier *label);
void Condition(const ir::AstNode *node, lexer::TokenType op, VReg lhs, class Label *ifFalse);
void Unary(const ir::AstNode *node, lexer::TokenType op, VReg operand);
void Binary(const ir::AstNode *node, lexer::TokenType op, VReg lhs);
void BranchIfUndefined(const ir::AstNode *node, class Label *target);
void BranchIfNotUndefined(const ir::AstNode *node, class Label *target);
void BranchIfHole(const ir::AstNode *node, class Label *target);
void BranchIfTrue(const ir::AstNode *node, class Label *target);
void BranchIfNotTrue(const ir::AstNode *node, class Label *target);
void BranchIfFalse(const ir::AstNode *node, class Label *target);
void BranchIfCoercible(const ir::AstNode *node, class Label *target);
void EmitThrow(const ir::AstNode *node);
void EmitRethrow(const ir::AstNode *node);
void EmitReturn(const ir::AstNode *node);
void EmitReturnUndefined(const ir::AstNode *node);
void ValidateClassDirectReturn(const ir::AstNode *node);
void DirectReturn(const ir::AstNode *node);
void ImplicitReturn(const ir::AstNode *node);
void EmitAwait(const ir::AstNode *node);
void CallThis(const ir::AstNode *node, VReg startReg, size_t argCount);
void Call(const ir::AstNode *node, VReg startReg, size_t argCount);
void CallSpread(const ir::AstNode *node, VReg func, VReg thisReg, VReg args);
void SuperCall(const ir::AstNode *node, VReg startReg, size_t argCount);
void SuperCallSpread(const ir::AstNode *node, VReg vs);
void LoadHomeObject(const ir::AstNode *node);
void NewObject(const ir::AstNode *node, VReg startReg, size_t argCount);
void DefineFunction(const ir::AstNode *node, const ir::ScriptFunction *realNode, const util::StringView &name);
void TypeOf(const ir::AstNode *node);
void NewObjSpread(const ir::AstNode *node, VReg obj, VReg target);
void GetUnmappedArgs(const ir::AstNode *node);
void Negate(const ir::AstNode *node);
void ToBoolean(const ir::AstNode *node);
void ToNumber(const ir::AstNode *node, VReg arg);
void CreateGeneratorObj(const ir::AstNode *node, VReg funcObj);
void ResumeGenerator(const ir::AstNode *node, VReg genObj);
void GetResumeMode(const ir::AstNode *node, VReg genObj);
void AsyncFunctionEnter(const ir::AstNode *node);
void AsyncFunctionAwait(const ir::AstNode *node, VReg asyncFuncObj);
void AsyncFunctionResolve(const ir::AstNode *node, VReg asyncFuncObj);
void AsyncFunctionReject(const ir::AstNode *node, VReg asyncFuncObj);
void GetMethod(const ir::AstNode *node, VReg obj, const util::StringView &name);
void GeneratorYield(const ir::AstNode *node, VReg genObj);
void GeneratorComplete(const ir::AstNode *node, VReg genObj);
void CreateAsyncGeneratorObj(const ir::AstNode *node, VReg funcObj);
void CreateIterResultObject(const ir::AstNode *node, bool done);
void SuspendGenerator(const ir::AstNode *node, VReg genObj);
void SuspendAsyncGenerator(const ir::AstNode *node, VReg asyncGenObj);
void AsyncGeneratorResolve(const ir::AstNode *node, VReg asyncGenObj);
void AsyncGeneratorReject(const ir::AstNode *node, VReg asyncGenObj);
void GetTemplateObject(const ir::AstNode *node, VReg value);
void CopyRestArgs(const ir::AstNode *node, uint32_t index);
void GetPropIterator(const ir::AstNode *node);
void GetNextPropName(const ir::AstNode *node, VReg iter);
void CreateEmptyObject(const ir::AstNode *node);
void CreateObjectWithBuffer(const ir::AstNode *node, uint32_t idx);
void CreateObjectHavingMethod(const ir::AstNode *node, uint32_t idx);
void SetObjectWithProto(const ir::AstNode *node, VReg proto, VReg obj);
void CopyDataProperties(const ir::AstNode *node, VReg dst, VReg src);
void DefineGetterSetterByValue(const ir::AstNode *node, VReg obj, VReg name, VReg getter, VReg setter,
bool setName);
void CreateEmptyArray(const ir::AstNode *node);
void CreateArray(const ir::AstNode *node, const ArenaVector<ir::Expression *> &elements, VReg obj);
void CreateArrayWithBuffer(const ir::AstNode *node, uint32_t idx);
void StoreArraySpread(const ir::AstNode *node, VReg array, VReg index);
void ThrowIfNotObject(const ir::AstNode *node);
void ThrowThrowNotExist(const ir::AstNode *node);
void GetIterator(const ir::AstNode *node);
void GetAsyncIterator(const ir::AstNode *node);
void CreateObjectWithExcludedKeys(const ir::AstNode *node, VReg obj, VReg argStart, size_t argCount);
void ThrowObjectNonCoercible(const ir::AstNode *node);
void CloseIterator(const ir::AstNode *node, VReg iter);
void DefineClassWithBuffer(const ir::AstNode *node, const util::StringView &ctorId, int32_t litIdx, VReg lexenv,
VReg base);
void ImportModule(const ir::AstNode *node, const util::StringView &name);
void LoadModuleVariable(const ir::AstNode *node, VReg module, const util::StringView &name);
void StoreModuleVar(const ir::AstNode *node, const util::StringView &name);
void CopyModule(const ir::AstNode *node, VReg module);
void StSuperByName(const ir::AstNode *node, VReg obj, const util::StringView &key);
void LdSuperByName(const ir::AstNode *node, VReg obj, const util::StringView &key);
void StSuperByValue(const ir::AstNode *node, VReg obj, VReg prop);
void LdSuperByValue(const ir::AstNode *node, VReg obj, VReg prop);
void StoreSuperProperty(const ir::AstNode *node, VReg obj, const Operand &prop);
void LoadSuperProperty(const ir::AstNode *node, VReg obj, const Operand &prop);
void LdLexEnv(const ir::AstNode *node);
void PopLexEnv(const ir::AstNode *node);
void CopyLexEnv(const ir::AstNode *node);
void NewLexEnv(const ir::AstNode *node, uint32_t num);
void LoadLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot);
void StoreLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot);
void ThrowIfSuperNotCorrectCall(const ir::AstNode *node, int64_t num);
void ThrowUndefinedIfHole(const ir::AstNode *node, const util::StringView &name);
void ThrowConstAssignment(const ir::AstNode *node, const util::StringView &name);
uint32_t TryDepth() const;
CatchTable *CreateCatchTable();
void SortCatchTables();
void LoadObjByIndex(const ir::AstNode *node, VReg obj, int64_t index);
void LoadObjByValue(const ir::AstNode *node, VReg obj, VReg prop);
void StoreObjByName(const ir::AstNode *node, VReg obj, const util::StringView &prop);
void StoreObjByIndex(const ir::AstNode *node, VReg obj, int64_t index);
void StoreObjByValue(const ir::AstNode *node, VReg obj, VReg prop);
void StOwnByName(const ir::AstNode *node, VReg obj, const util::StringView &prop);
void StOwnByValue(const ir::AstNode *node, VReg obj, VReg prop);
void StOwnByIndex(const ir::AstNode *node, VReg obj, int64_t index);
static Operand ToNamedPropertyKey(const ir::Expression *prop, bool isComputed);
Operand ToPropertyKey(const ir::Expression *prop, bool isComputed);
VReg LoadPropertyKey(const ir::Expression *prop, bool isComputed);
void SetFirstStmt(const ir::Statement *stmt)
{
debugInfo_.firstStmt = stmt;
}
[[noreturn]] static void Unimplemented()
{
throw Error(ErrorType::GENERIC, "Unimplemented code path");
}
private:
ArenaAllocator *allocator_;
CompilerContext *context_;
FunctionBuilder *builder_;
DebugInfo debugInfo_;
binder::FunctionScope *topScope_;
binder::Scope *scope_;
const ir::AstNode *rootNode_;
ArenaList<IRNode *> insns_;
ArenaVector<CatchTable *> catchList_;
ArenaSet<util::StringView> strings_;
ArenaVector<LiteralBuffer *> buffStorage_;
EnvScope *envScope_ {};
DynamicContext *dynamicContext_ {};
InlineCache ic_;
SimpleAllocator sa_;
RegAllocator ra_;
RangeRegAllocator rra_;
uint32_t usedRegs_ {0};
uint32_t totalRegs_ {0};
friend class ScopeContext;
friend class RegScope;
friend class LocalRegScope;
friend class LoopRegScope;
friend class ParamRegScope;
friend class FunctionRegScope;
friend class EnvScope;
friend class LoopEnvScope;
friend class DynamicContext;
size_t labelId_ {0};
};
} // namespace panda::es2panda::compiler
#endif
+159
View File
@@ -0,0 +1,159 @@
/*
* 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 "regAllocator.h"
#include <compiler/core/pandagen.h>
#include <algorithm>
namespace panda::es2panda::compiler {
// RegAllocatorBase
void AllocatorBase::PushBack(IRNode *ins)
{
pg_->Insns().push_back(ins);
}
ArenaAllocator *AllocatorBase::Allocator() const
{
return pg_->Allocator();
}
// SimpleAllocator
Label *SimpleAllocator::AllocLabel(std::string &&id)
{
const auto *lastInsNode = pg_->Insns().empty() ? FIRST_NODE_OF_FUNCTION : pg_->Insns().back()->Node();
return Alloc<Label>(lastInsNode, std::move(id));
}
// FrontAllocator
FrontAllocator::FrontAllocator(PandaGen *pg)
: AllocatorBase(pg), insn_(std::move(pg_->Insns()), pg_->Allocator()->Adapter())
{
}
FrontAllocator::~FrontAllocator()
{
pg_->Insns().splice(pg_->Insns().end(), std::move(insn_));
}
// RegAllocatorBase
VReg RegAllocatorBase::Spill(IRNode *ins, VReg reg)
{
VReg spillReg = pg_->AllocReg();
VReg origin = spillIndex_++;
Add<MovDyn>(ins->Node(), spillReg, origin);
Add<MovDyn>(ins->Node(), origin, reg);
return origin;
}
void RegAllocatorBase::Restore(IRNode *ins)
{
spillIndex_--;
VReg spillReg = spillIndex_;
VReg origin = regEnd_ + spillIndex_;
Add<MovDyn>(ins->Node(), origin, spillReg);
}
// RegAllocator
void RegAllocator::Run(IRNode *ins)
{
ASSERT(spillIndex_ == 0);
std::array<VReg *, IRNode::MAX_REG_OPERAND> regs {};
auto regCnt = ins->Registers(&regs);
auto registers = Span<VReg *>(regs.data(), regs.data() + regCnt);
if (CheckRegIndices(ins, registers)) {
PushBack(ins);
return;
}
RegScope regScope(pg_);
regEnd_ = pg_->NextReg();
for (auto *reg : registers) {
if (IsRegisterCorrect(reg)) {
continue;
}
const auto actualReg = *reg;
*reg = Spill(ins, actualReg);
}
PushBack(ins);
while (spillIndex_ != 0) {
Restore(ins);
}
}
// RangeRegAllocator
void RangeRegAllocator::Run(IRNode *ins, VReg rangeStart, size_t argCount)
{
ASSERT(spillIndex_ == 0);
const auto rangeEnd = rangeStart + argCount;
std::array<VReg *, IRNode::MAX_REG_OPERAND> regs {};
auto regCnt = ins->Registers(&regs);
auto registers = Span<VReg *>(regs.data(), regs.data() + regCnt);
if (CheckRegIndices(ins, registers)) {
PushBack(ins);
return;
}
RegScope regScope(pg_);
regEnd_ = pg_->NextReg();
auto *iter = registers.begin();
auto *iterEnd = iter + registers.size() - 1;
while (iter != iterEnd) {
VReg *reg = *iter;
const auto actualReg = *reg;
*reg = Spill(ins, actualReg);
iter++;
}
VReg *regStartReg = *iter;
VReg reg = rangeStart++;
*regStartReg = Spill(ins, reg);
while (rangeStart != rangeEnd) {
reg = rangeStart++;
Spill(ins, reg);
}
PushBack(ins);
while (spillIndex_ != 0) {
Restore(ins);
}
}
} // namespace panda::es2panda::compiler
+166
View File
@@ -0,0 +1,166 @@
/**
* 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.
*/
#ifndef ES2PANDA_COMPILER_CORE_REG_ALLOCATOR_H
#define ES2PANDA_COMPILER_CORE_REG_ALLOCATOR_H
#include <gen/isa.h>
#include <macros.h>
namespace panda::es2panda::ir {
class AstNode;
} // namespace panda::es2panda::ir
namespace panda::es2panda::compiler {
class PandaGen;
class AllocatorBase {
public:
explicit AllocatorBase(PandaGen *pg) : pg_(pg) {};
NO_COPY_SEMANTIC(AllocatorBase);
NO_MOVE_SEMANTIC(AllocatorBase);
~AllocatorBase() = default;
protected:
void PushBack(IRNode *ins);
ArenaAllocator *Allocator() const;
template <typename T, typename... Args>
T *Alloc(const ir::AstNode *node, Args &&... args)
{
return Allocator()->New<T>(node, std::forward<Args>(args)...);
}
template <typename T, typename... Args>
void Add(const ir::AstNode *node, Args &&... args)
{
return PushBack(Alloc<T>(node, std::forward<Args>(args)...));
}
PandaGen *pg_;
};
class SimpleAllocator : public AllocatorBase {
public:
explicit SimpleAllocator(PandaGen *pg) : AllocatorBase(pg) {};
NO_COPY_SEMANTIC(SimpleAllocator);
NO_MOVE_SEMANTIC(SimpleAllocator);
~SimpleAllocator() = default;
Label *AllocLabel(std::string &&id);
void AddLabel(Label *label)
{
PushBack(label);
}
template <typename T, typename... Args>
void Emit(const ir::AstNode *node, Args &&... args)
{
Add<T>(node, std::forward<Args>(args)...);
}
};
class FrontAllocator : public AllocatorBase {
public:
explicit FrontAllocator(PandaGen *pg);
NO_COPY_SEMANTIC(FrontAllocator);
NO_MOVE_SEMANTIC(FrontAllocator);
~FrontAllocator();
private:
ArenaList<IRNode *> insn_;
};
class RegAllocatorBase : public AllocatorBase {
public:
explicit RegAllocatorBase(PandaGen *pg) : AllocatorBase(pg) {}
NO_COPY_SEMANTIC(RegAllocatorBase);
NO_MOVE_SEMANTIC(RegAllocatorBase);
~RegAllocatorBase() = default;
protected:
inline bool CheckRegIndices(IRNode *ins, const Span<VReg *> &registers)
{
Formats formats = ins->GetFormats();
limit_ = 0;
for (const auto &format : formats) {
for (const auto &formatItem : format.GetFormatItem()) {
if (formatItem.IsVReg()) {
limit_ = 1 << formatItem.Bitwidth();
break;
}
}
if (std::all_of(registers.begin(), registers.end(),
[this](const VReg *reg) { return IsRegisterCorrect(reg); })) {
return true;
}
}
return false;
}
inline bool IsRegisterCorrect(const VReg *reg) const
{
return *reg < limit_;
}
VReg Spill(IRNode *ins, VReg reg);
void Restore(IRNode *ins);
VReg spillIndex_ {0};
VReg regEnd_ {0};
size_t limit_ {0};
};
class RegAllocator : public RegAllocatorBase {
public:
explicit RegAllocator(PandaGen *pg) : RegAllocatorBase(pg) {}
NO_COPY_SEMANTIC(RegAllocator);
NO_MOVE_SEMANTIC(RegAllocator);
~RegAllocator() = default;
template <typename T, typename... Args>
void Emit(const ir::AstNode *node, Args &&... args)
{
auto *ins = Alloc<T>(node, std::forward<Args>(args)...);
Run(ins);
}
private:
void Run(IRNode *ins);
};
class RangeRegAllocator : public RegAllocatorBase {
public:
explicit RangeRegAllocator(PandaGen *pg) : RegAllocatorBase(pg) {}
NO_COPY_SEMANTIC(RangeRegAllocator);
NO_MOVE_SEMANTIC(RangeRegAllocator);
~RangeRegAllocator() = default;
template <typename T, typename... Args>
void Emit(const ir::AstNode *node, VReg rangeStart, size_t argCount, Args &&... args)
{
auto *ins = Alloc<T>(node, std::forward<Args>(args)...);
Run(ins, rangeStart, argCount);
}
private:
void Run(IRNode *ins, VReg rangeStart, size_t argCount);
};
} // namespace panda::es2panda::compiler
#endif
+135
View File
@@ -0,0 +1,135 @@
/*
* 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 "regScope.h"
#include <binder/binder.h>
#include <binder/scope.h>
#include <binder/variable.h>
#include <compiler/base/hoisting.h>
#include <compiler/core/compilerContext.h>
#include <compiler/core/pandagen.h>
#include <compiler/core/moduleContext.h>
namespace panda::es2panda::compiler {
// RegScope
RegScope::RegScope(PandaGen *pg) : pg_(pg), regBase_(pg_->usedRegs_) {}
RegScope::~RegScope()
{
pg_->totalRegs_ = std::max(pg_->totalRegs_, pg_->usedRegs_);
pg_->usedRegs_ = regBase_;
}
void RegScope::DebuggerCloseScope()
{
if (!pg_->IsDebug()) {
return;
}
pg_->scope_->SetScopeEnd(pg_->insns_.back());
}
// LocalRegScope
LocalRegScope::LocalRegScope(PandaGen *pg) : RegScope(pg) {}
LocalRegScope::LocalRegScope(PandaGen *pg, binder::Scope *scope) : RegScope(pg)
{
prevScope_ = pg_->scope_;
pg_->scope_ = scope;
for (const auto &[_, var] : scope->Bindings()) {
(void)_;
if (!var->LexicalBound() && var->IsLocalVariable()) {
var->AsLocalVariable()->BindVReg(pg->AllocReg());
}
}
if (pg_->IsDebug()) {
pg_->scope_->SetScopeStart(pg_->insns_.back());
pg_->debugInfo_.variableDebugInfo.push_back(pg_->scope_);
}
Hoisting::Hoist(pg_);
}
LocalRegScope::~LocalRegScope()
{
if (!prevScope_) {
return;
}
DebuggerCloseScope();
pg_->scope_ = prevScope_;
}
// FunctionRegScope
FunctionRegScope::FunctionRegScope(PandaGen *pg) : RegScope(pg), envScope_(pg->Allocator()->New<EnvScope>())
{
ASSERT(pg_->Scope()->IsFunctionVariableScope());
ASSERT(pg_->NextReg() == binder::Binder::MANDATORY_PARAM_FUNC_REG);
const auto *funcScope = pg_->Scope()->AsFunctionVariableScope();
for (auto *param : funcScope->ParamScope()->Params()) {
VReg paramReg = pg_->AllocReg();
if (!param->LexicalBound()) {
param->BindVReg(paramReg);
}
}
envScope_->Initialize(pg_, pg->AllocReg());
for (const auto &[_, var] : funcScope->Bindings()) {
(void)_;
if (var->Declaration()->IsParameterDecl()) {
continue;
}
if (!var->LexicalBound() && var->IsLocalVariable()) {
var->AsLocalVariable()->BindVReg(pg->AllocReg());
}
}
if (pg_->IsDebug()) {
pg_->debugInfo_.variableDebugInfo.push_back(funcScope);
}
pg_->LoadAccFromArgs(pg_->rootNode_);
if (funcScope->IsModuleScope()) {
ModuleContext::Compile(pg_, pg_->scope_->AsModuleScope());
}
Hoisting::Hoist(pg);
}
FunctionRegScope::~FunctionRegScope()
{
if (pg_->IsDebug()) {
pg_->topScope_->SetScopeStart(pg_->insns_.front());
}
DebuggerCloseScope();
envScope_->~EnvScope();
}
} // namespace panda::es2panda::compiler
+93
View File
@@ -0,0 +1,93 @@
/*
* 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.
*/
#ifndef ES2PANDA_COMPILER_CORE_REG_SCOPE_H
#define ES2PANDA_COMPILER_CORE_REG_SCOPE_H
#include <macros.h>
#include <binder/scope.h>
namespace panda::es2panda::ir {
class AstNode;
} // namespace panda::es2panda::ir
namespace panda::es2panda::compiler {
class EnvScope;
class PandaGen;
class RegScope {
public:
explicit RegScope(PandaGen *pg);
NO_COPY_SEMANTIC(RegScope);
NO_MOVE_SEMANTIC(RegScope);
~RegScope();
void *operator new(size_t) = delete;
void *operator new[](size_t) = delete;
protected:
void DebuggerCloseScope();
PandaGen *pg_;
uint32_t regBase_;
};
class LocalRegScope : public RegScope {
public:
explicit LocalRegScope(PandaGen *pg, binder::Scope *scope);
explicit LocalRegScope(PandaGen *pg);
NO_COPY_SEMANTIC(LocalRegScope);
NO_MOVE_SEMANTIC(LocalRegScope);
~LocalRegScope();
void *operator new(size_t) = delete;
void *operator new[](size_t) = delete;
private:
binder::Scope *prevScope_ {};
};
class LoopRegScope : public RegScope {
public:
explicit LoopRegScope(PandaGen *pg, binder::LoopScope *scope);
NO_COPY_SEMANTIC(LoopRegScope);
NO_MOVE_SEMANTIC(LoopRegScope);
~LoopRegScope();
void *operator new(size_t) = delete;
void *operator new[](size_t) = delete;
private:
binder::Scope *prevScope_ {};
};
class FunctionRegScope : public RegScope {
public:
explicit FunctionRegScope(PandaGen *pg);
NO_COPY_SEMANTIC(FunctionRegScope);
NO_MOVE_SEMANTIC(FunctionRegScope);
~FunctionRegScope();
void *operator new(size_t) = delete;
void *operator new[](size_t) = delete;
private:
EnvScope *envScope_;
};
} // namespace panda::es2panda::compiler
#endif
+76
View File
@@ -0,0 +1,76 @@
/**
* Copyright (c) 2021 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 "switchBuilder.h"
#include <ir/expression.h>
#include <ir/statements/switchStatement.h>
#include <ir/statements/switchCaseStatement.h>
#include <compiler/core/pandagen.h>
#include <compiler/core/labelTarget.h>
#include <typescript/checker.h>
namespace panda::es2panda::compiler {
// SwitchBuilder
SwitchBuilder::SwitchBuilder(PandaGen *pg, const ir::SwitchStatement *stmt)
: pg_(pg), end_(pg->AllocLabel()), labelCtx_(pg, LabelTarget(end_, LabelTarget::BREAK_LABEL)), stmt_(stmt)
{
for (size_t i = 0; i < stmt_->Cases().size(); i++) {
caseLabels_.push_back(pg_->AllocLabel());
}
}
SwitchBuilder::~SwitchBuilder()
{
pg_->SetLabel(stmt_, end_);
}
void SwitchBuilder::SetCaseTarget(uint32_t index)
{
pg_->SetLabel(stmt_->Cases()[index], caseLabels_[index]);
}
void SwitchBuilder::CompileTagOfSwitch(VReg tag)
{
stmt_->Discriminant()->Compile(pg_);
pg_->StoreAccumulator(stmt_->Discriminant(), tag);
}
void SwitchBuilder::CompileCaseStatements(uint32_t index)
{
for (const auto *stmt : stmt_->Cases()[index]->Consequent()) {
stmt->Compile(pg_);
}
}
void SwitchBuilder::JumpIfCase(VReg tag, uint32_t index)
{
const ir::SwitchCaseStatement *caseTarget = stmt_->Cases()[index];
caseTarget->Test()->Compile(pg_);
pg_->Condition(caseTarget, lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL, tag, caseLabels_[index]);
}
void SwitchBuilder::JumpToDefault(uint32_t defaultIndex)
{
const ir::SwitchCaseStatement *defaultTarget = stmt_->Cases()[defaultIndex];
pg_->Branch(defaultTarget, caseLabels_[defaultIndex]);
}
void SwitchBuilder::Break()
{
pg_->Branch(stmt_, end_);
}
} // namespace panda::es2panda::compiler
+53
View File
@@ -0,0 +1,53 @@
/**
* Copyright (c) 2021 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.
*/
#ifndef ES2PANDA_COMPILER_CORE_SWITCH_BUILDER_H
#define ES2PANDA_COMPILER_CORE_SWITCH_BUILDER_H
#include <ir/irnode.h>
#include <compiler/core/dynamicContext.h>
namespace panda::es2panda::ir {
class SwitchStatement;
} // namespace panda::es2panda::ir
namespace panda::es2panda::compiler {
class PandaGen;
class Label;
class SwitchBuilder {
public:
SwitchBuilder(PandaGen *pg, const ir::SwitchStatement *stmt);
NO_COPY_SEMANTIC(SwitchBuilder);
NO_MOVE_SEMANTIC(SwitchBuilder);
~SwitchBuilder();
void SetCaseTarget(uint32_t index);
void CompileTagOfSwitch(VReg tag);
void CompileCaseStatements(uint32_t index);
void JumpIfCase(VReg tag, uint32_t index);
void JumpToDefault(uint32_t defaultIndex);
void Break();
private:
PandaGen *pg_;
Label *end_;
LabelContext labelCtx_;
const ir::SwitchStatement *stmt_;
std::vector<Label *> caseLabels_;
};
} // namespace panda::es2panda::compiler
#endif
@@ -0,0 +1,236 @@
/*
* 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 "debuginfoDumper.h"
#include <macros.h>
#include <sstream>
#include <string>
namespace panda::es2panda::debuginfo {
DebugInfoDumper::DebugInfoDumper(const pandasm::Program *prog) : prog_(prog) {}
static const char *PutComma(bool comma)
{
return comma ? "," : "";
}
template <typename T>
void DebugInfoDumper::WrapArray(const char *name, const std::vector<T> &array, bool comma)
{
ss_ << std::endl;
Indent();
ss_ << "\"" << name << "\": "
<< "[";
if (array.empty()) {
ss_ << "]" << PutComma(comma);
return;
}
ss_ << "\n";
indent_++;
// dump VariableDebugInfo in reverse order to match ts2panda
// NOLINTNEXTLINE
if constexpr (std::is_same_v<T, pandasm::debuginfo::LocalVariable>) {
typename std::vector<T>::const_reverse_iterator elem;
for (elem = array.rbegin(); elem != array.rend(); ++elem) {
Indent();
WriteVariableInfo(*elem);
(std::next(elem) == array.rend()) ? ss_ << "" : ss_ << ",";
ss_ << "\n";
}
// NOLINTNEXTLINE
} else {
typename std::vector<T>::const_iterator elem;
for (elem = array.begin(); elem != array.end(); ++elem) {
Indent();
// NOLINTNEXTLINE
if constexpr (std::is_same_v<T, pandasm::Ins>) {
WriteIns(*elem);
// NOLINTNEXTLINE
} else if constexpr (std::is_same_v<T, pandasm::Function::Parameter>) {
ss_ << "\"" << (*elem).type.GetName() << "\"";
// NOLINTNEXTLINE
} else if constexpr (std::is_same_v<T, std::string>) {
ss_ << "\"" << *elem << "\"";
// NOLINTNEXTLINE
} else if constexpr (std::is_same_v<T, std::variant<int64_t, double>>) {
if (std::holds_alternative<int64_t>(*elem)) {
ss_ << std::to_string(std::get<int64_t>(*elem));
} else {
ss_ << std::to_string(std::get<double>(*elem));
}
// NOLINTNEXTLINE
} else {
ss_ << std::to_string(*elem);
}
(std::next(elem) == array.end()) ? ss_ << "" : ss_ << ",";
ss_ << "\n";
}
}
indent_--;
Indent();
ss_ << "]" << PutComma(comma);
}
void DebugInfoDumper::WriteIns(const pandasm::Ins &ins)
{
ss_ << "{";
{
pandasm::Ins insCopy;
insCopy.opcode = ins.opcode;
insCopy.set_label = ins.set_label;
insCopy.label = ins.label;
WriteProperty("opcode", insCopy.ToString());
}
indent_++;
WrapArray("regs", ins.regs);
WrapArray("ids", ins.ids);
WrapArray("imms", ins.imms);
ss_ << std::endl;
Indent();
ss_ << "\"label\": "
<< "\"" << ins.label << "\",";
WritePosInfo(ins.ins_debug);
indent_--;
Indent();
ss_ << "}";
}
void DebugInfoDumper::WriteMetaData(const std::vector<pandasm::AnnotationData> &metaData)
{
for (const auto &it : metaData) {
for (const auto &elem : it.GetElements()) {
pandasm::ScalarValue *value = elem.GetValue()->GetAsScalar();
if (value->GetType() == pandasm::Value::Type::STRING) {
WriteProperty(elem.GetName().c_str(), value->GetValue<std::string>(), false);
} else if (value->GetType() == pandasm::Value::Type::U32) {
WriteProperty(elem.GetName().c_str(), value->GetValue<size_t>());
}
}
}
}
void DebugInfoDumper::WritePosInfo(const pandasm::debuginfo::Ins &posInfo)
{
ss_ << std::endl;
Indent();
ss_ << "\"debug_pos_info\": {";
WriteProperty("boundLeft", posInfo.bound_left);
WriteProperty("boundRight", posInfo.bound_right);
WriteProperty("sourecLineNum", static_cast<int32_t>(posInfo.line_number));
WriteProperty("wholeLine", posInfo.whole_line, false);
Indent();
ss_ << "}" << std::endl;
}
void DebugInfoDumper::WriteVariableInfo(const pandasm::debuginfo::LocalVariable &localVariableDebug)
{
ss_ << "{";
WriteProperty("name", localVariableDebug.name);
WriteProperty("signature", localVariableDebug.signature);
WriteProperty("signatureType", localVariableDebug.signature_type);
WriteProperty("reg", localVariableDebug.reg);
WriteProperty("start", static_cast<size_t>(localVariableDebug.start));
WriteProperty("length", static_cast<size_t>(localVariableDebug.length), false);
Indent();
ss_ << "}";
}
void DebugInfoDumper::Dump()
{
ss_ << "{\n";
indent_++;
Indent();
ss_ << "\"functions\": [" << std::endl;
auto iter = prog_->function_table.begin();
for (; iter != prog_->function_table.end(); ++iter) {
indent_++;
Indent();
ss_ << "{";
WriteProperty("name", iter->first);
ss_ << std::endl;
indent_++;
Indent();
ss_ << "\"signature\": {";
WriteProperty("retType", iter->second.return_type.GetName());
indent_++;
WrapArray("params", iter->second.params, false);
indent_ -= 2U;
ss_ << std::endl;
Indent();
ss_ << "},";
WrapArray("ins", iter->second.ins);
WrapArray("variables", iter->second.local_variable_debug);
WriteProperty("sourceFile", iter->second.source_file);
WriteProperty("sourceCode", iter->second.source_code);
// icSize - parameterLength - funcName
WriteMetaData(iter->second.metadata->GetAnnotations());
indent_--;
Indent();
ss_ << "}";
if (std::next(iter) != prog_->function_table.end()) {
ss_ << ",";
}
ss_ << std::endl;
}
indent_--;
Indent();
ss_ << "]" << std::endl;
ss_ << "}";
ss_ << std::endl;
std::cout << ss_.str();
}
void DebugInfoDumper::WriteProperty(const char *key, const Value &value, bool comma)
{
ss_ << std::endl;
indent_++;
Indent();
ss_ << "\"" << key << "\": ";
if (std::holds_alternative<std::string>(value)) {
ss_ << "\"" << std::get<std::string>(value) << "\"";
} else if (std::holds_alternative<size_t>(value)) {
ss_ << std::to_string(std::get<size_t>(value));
} else if (std::holds_alternative<int32_t>(value)) {
ss_ << std::to_string(std::get<int32_t>(value));
}
comma ? ss_ << "," : ss_ << std::endl;
indent_--;
}
void DebugInfoDumper::Indent()
{
for (int32_t i = 0; i <= indent_; i++) {
ss_ << " ";
}
}
} // namespace panda::es2panda::debuginfo
@@ -0,0 +1,53 @@
/*
* 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.
*/
#ifndef ES2PANDA_COMPILER_DEBUGGER_DEBUGINFO_DUMPER_H
#define ES2PANDA_COMPILER_DEBUGGER_DEBUGINFO_DUMPER_H
#include <assembly-ins.h>
#include <assembly-program.h>
#include <macros.h>
namespace panda::es2panda::debuginfo {
using Value = std::variant<std::string, size_t, int32_t>;
class DebugInfoDumper {
public:
explicit DebugInfoDumper(const pandasm::Program *prog);
~DebugInfoDumper() = default;
NO_COPY_SEMANTIC(DebugInfoDumper);
NO_MOVE_SEMANTIC(DebugInfoDumper);
void Dump();
private:
template <typename T>
void WrapArray(const char *name, const std::vector<T> &array, bool comma = true);
void WriteIns(const pandasm::Ins &ins);
void WriteMetaData(const std::vector<pandasm::AnnotationData> &metaData);
void WriteProperty(const char *key, const Value &value, bool comma = true);
void WritePosInfo(const pandasm::debuginfo::Ins &posInfo);
void WriteVariableInfo(const pandasm::debuginfo::LocalVariable &localVariableDebug);
void Indent();
const pandasm::Program *prog_;
std::stringstream ss_;
int32_t indent_ {0};
};
} // namespace panda::es2panda::debuginfo
#endif // UTIL_DEBUGINFO_DUMPER_H
@@ -0,0 +1,53 @@
/*
* 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 "asyncFunctionBuilder.h"
#include <compiler/core/pandagen.h>
#include <compiler/base/catchTable.h>
#include <ir/base/scriptFunction.h>
namespace panda::es2panda::compiler {
void AsyncFunctionBuilder::DirectReturn(const ir::AstNode *node) const
{
pg_->AsyncFunctionResolve(node, funcObj_);
pg_->EmitReturn(node);
}
void AsyncFunctionBuilder::ImplicitReturn(const ir::AstNode *node) const
{
pg_->LoadConst(node, Constant::JS_UNDEFINED);
DirectReturn(node);
}
void AsyncFunctionBuilder::Prepare(const ir::ScriptFunction *node) const
{
pg_->AsyncFunctionEnter(node);
pg_->StoreAccumulator(node, funcObj_);
pg_->SetLabel(node, catchTable_->LabelSet().TryBegin());
}
void AsyncFunctionBuilder::CleanUp(const ir::ScriptFunction *node) const
{
const auto &labelSet = catchTable_->LabelSet();
pg_->SetLabel(node, labelSet.TryEnd());
pg_->SetLabel(node, labelSet.CatchBegin());
pg_->AsyncFunctionReject(node, funcObj_);
pg_->EmitReturn(node);
pg_->SetLabel(node, labelSet.CatchEnd());
}
} // namespace panda::es2panda::compiler
@@ -0,0 +1,48 @@
/*
* 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.
*/
#ifndef ES2PANDA_COMPILER_FUNCTION_ASYNC_FUNCTION_BUILDER_H
#define ES2PANDA_COMPILER_FUNCTION_ASYNC_FUNCTION_BUILDER_H
#include <ir/irnode.h>
#include <compiler/function/functionBuilder.h>
namespace panda::es2panda::compiler {
class PandaGen;
class AsyncFunctionBuilder : public FunctionBuilder {
public:
explicit AsyncFunctionBuilder(PandaGen *pg, CatchTable *catchTable) : FunctionBuilder(pg, catchTable) {}
~AsyncFunctionBuilder() override = default;
NO_COPY_SEMANTIC(AsyncFunctionBuilder);
NO_MOVE_SEMANTIC(AsyncFunctionBuilder);
void Prepare(const ir::ScriptFunction *node) const override;
void CleanUp(const ir::ScriptFunction *node) const override;
void DirectReturn(const ir::AstNode *node) const override;
void ImplicitReturn(const ir::AstNode *node) const override;
protected:
BuilderType BuilderKind() const override
{
return BuilderType::ASYNC;
}
};
} // namespace panda::es2panda::compiler
#endif
@@ -0,0 +1,106 @@
/**
* Copyright (c) 2021 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 "asyncGeneratorFunctionBuilder.h"
#include <compiler/base/catchTable.h>
#include <compiler/core/pandagen.h>
#include <ir/base/scriptFunction.h>
namespace panda::es2panda::compiler {
void AsyncGeneratorFunctionBuilder::Prepare(const ir::ScriptFunction *node) const
{
VReg callee = FunctionReg(node);
pg_->CreateAsyncGeneratorObj(node, callee);
pg_->StoreAccumulator(node, funcObj_);
pg_->SuspendGenerator(node, funcObj_);
pg_->SetLabel(node, catchTable_->LabelSet().TryBegin());
}
void AsyncGeneratorFunctionBuilder::CleanUp(const ir::ScriptFunction *node) const
{
const auto &labelSet = catchTable_->LabelSet();
pg_->SetLabel(node, labelSet.TryEnd());
pg_->SetLabel(node, labelSet.CatchBegin());
pg_->AsyncGeneratorReject(node, funcObj_);
pg_->EmitReturn(node);
pg_->SetLabel(node, labelSet.CatchEnd());
}
void AsyncGeneratorFunctionBuilder::DirectReturn(const ir::AstNode *node) const
{
pg_->AsyncGeneratorResolve(node, funcObj_);
pg_->EmitReturn(node);
}
void AsyncGeneratorFunctionBuilder::ImplicitReturn(const ir::AstNode *node) const
{
pg_->LoadConst(node, Constant::JS_UNDEFINED);
DirectReturn(node);
}
void AsyncGeneratorFunctionBuilder::Yield(const ir::AstNode *node)
{
Await(node);
RegScope rs(pg_);
VReg completionType = pg_->AllocReg();
VReg completionValue = pg_->AllocReg();
AsyncYield(node, completionType, completionValue);
auto *notReturnCompletion = pg_->AllocLabel();
auto *normalCompletion = pg_->AllocLabel();
auto *notThrowCompletion = pg_->AllocLabel();
// 27.6.3.8.8.a. If resumptionValue.[[Type]] is not return
pg_->LoadAccumulatorInt(node, static_cast<int32_t>(ResumeMode::RETURN));
pg_->Condition(node, lexer::TokenType::PUNCTUATOR_EQUAL, completionType, notReturnCompletion);
// 27.6.3.8.8.b. Let awaited be Await(resumptionValue.[[Value]]).
pg_->LoadAccumulator(node, completionValue);
pg_->AsyncFunctionAwait(node, funcObj_);
SuspendResumeExecution(node, completionType, completionValue);
// 27.6.3.8.8.c. If awaited.[[Type]] is throw, return Completion(awaited).
pg_->LoadAccumulatorInt(node, static_cast<int32_t>(ResumeMode::THROW));
pg_->Condition(node, lexer::TokenType::PUNCTUATOR_EQUAL, completionType, normalCompletion);
pg_->LoadAccumulator(node, completionValue);
pg_->EmitThrow(node);
pg_->SetLabel(node, normalCompletion);
// 27.6.3.8.8.d. Assert: awaited.[[Type]] is normal.
// 27.6.3.8.8.e. Return Completion { [[Type]]: return, [[Value]]: awaited.[[Value]], [[Target]]: empty }.
pg_->ControlFlowChangeBreak();
pg_->LoadAccumulator(node, completionValue);
pg_->DirectReturn(node);
pg_->SetLabel(node, notReturnCompletion);
// 27.6.3.8.8.a. return Completion(resumptionValue).
pg_->LoadAccumulatorInt(node, static_cast<int32_t>(ResumeMode::THROW));
pg_->Condition(node, lexer::TokenType::PUNCTUATOR_EQUAL, completionType, notThrowCompletion);
pg_->LoadAccumulator(node, completionValue);
pg_->EmitThrow(node);
pg_->SetLabel(node, notThrowCompletion);
pg_->LoadAccumulator(node, completionValue);
}
IteratorType AsyncGeneratorFunctionBuilder::GeneratorKind() const
{
return IteratorType::ASYNC;
}
} // namespace panda::es2panda::compiler
@@ -0,0 +1,51 @@
/**
* Copyright (c) 2021 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.
*/
#ifndef ES2PANDA_COMPILER_FUNCTION_ASYNC_GENERATOR_FUNCTION_BUILDER_H
#define ES2PANDA_COMPILER_FUNCTION_ASYNC_GENERATOR_FUNCTION_BUILDER_H
#include <ir/irnode.h>
#include <compiler/function/asyncFunctionBuilder.h>
namespace panda::es2panda::compiler {
class PandaGen;
class AsyncGeneratorFunctionBuilder : public FunctionBuilder {
public:
explicit AsyncGeneratorFunctionBuilder(PandaGen *pg, CatchTable *catchTable) : FunctionBuilder(pg, catchTable) {}
~AsyncGeneratorFunctionBuilder() override = default;
NO_COPY_SEMANTIC(AsyncGeneratorFunctionBuilder);
NO_MOVE_SEMANTIC(AsyncGeneratorFunctionBuilder);
void Prepare(const ir::ScriptFunction *node) const override;
void CleanUp(const ir::ScriptFunction *node) const override;
void DirectReturn(const ir::AstNode *node) const override;
void ImplicitReturn(const ir::AstNode *node) const override;
void Yield(const ir::AstNode *node) override;
protected:
BuilderType BuilderKind() const override
{
return BuilderType::ASYNC_GENERATOR;
}
IteratorType GeneratorKind() const override;
};
} // namespace panda::es2panda::compiler
#endif
@@ -0,0 +1,312 @@
/*
* 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 "functionBuilder.h"
#include <binder/binder.h>
#include <util/helpers.h>
#include <ir/statement.h>
#include <ir/base/scriptFunction.h>
#include <compiler/base/iterators.h>
#include <compiler/core/pandagen.h>
namespace panda::es2panda::compiler {
FunctionBuilder::FunctionBuilder(PandaGen *pg, CatchTable *catchTable)
: pg_(pg), catchTable_(catchTable), funcObj_(pg_->AllocReg())
{
}
IteratorType FunctionBuilder::GeneratorKind() const
{
return IteratorType::SYNC;
}
void FunctionBuilder::DirectReturn(const ir::AstNode *node) const
{
pg_->EmitReturn(node);
}
void FunctionBuilder::ImplicitReturn(const ir::AstNode *node) const
{
const auto *rootNode = pg_->RootNode();
if (!rootNode->IsScriptFunction() || !rootNode->AsScriptFunction()->IsConstructor()) {
pg_->EmitReturnUndefined(node);
return;
}
pg_->GetThis(rootNode);
pg_->ThrowIfSuperNotCorrectCall(rootNode, 0);
pg_->EmitReturn(node);
}
void FunctionBuilder::AsyncYield(const ir::AstNode *node, VReg completionType, VReg completionValue) const
{
ASSERT(BuilderKind() == BuilderType::ASYNC_GENERATOR);
pg_->GeneratorYield(node, funcObj_);
pg_->SuspendAsyncGenerator(node, funcObj_);
resumeGenerator(node, completionType, completionValue);
}
void FunctionBuilder::SuspendResumeExecution(const ir::AstNode *node, VReg completionType, VReg completionValue) const
{
ASSERT(BuilderKind() == BuilderType::ASYNC || BuilderKind() == BuilderType::ASYNC_GENERATOR ||
BuilderKind() == BuilderType::GENERATOR);
pg_->SuspendGenerator(node, funcObj_);
resumeGenerator(node, completionType, completionValue);
}
void FunctionBuilder::resumeGenerator(const ir::AstNode *node, VReg completionType, VReg completionValue) const
{
ASSERT(BuilderKind() == BuilderType::ASYNC || BuilderKind() == BuilderType::ASYNC_GENERATOR ||
BuilderKind() == BuilderType::GENERATOR);
pg_->ResumeGenerator(node, funcObj_);
pg_->StoreAccumulator(node, completionValue);
pg_->GetResumeMode(node, funcObj_);
pg_->StoreAccumulator(node, completionType);
}
VReg FunctionBuilder::FunctionReg(const ir::ScriptFunction *node) const
{
binder::FunctionScope *scope = node->Scope();
auto res = scope->Find(binder::Binder::MANDATORY_PARAM_FUNC);
ASSERT(res.level == 0 && res.variable->IsLocalVariable());
return res.variable->AsLocalVariable()->Vreg();
}
void FunctionBuilder::Await(const ir::AstNode *node)
{
if (BuilderKind() == BuilderType::NORMAL) {
// TODO(frobert): Implement top-level await
PandaGen::Unimplemented();
}
ASSERT(BuilderKind() == BuilderType::ASYNC || BuilderKind() == BuilderType::ASYNC_GENERATOR);
RegScope rs(pg_);
VReg completionType = pg_->AllocReg();
VReg completionValue = pg_->AllocReg();
pg_->AsyncFunctionAwait(node, funcObj_);
SuspendResumeExecution(node, completionType, completionValue);
HandleCompletion(node, completionType, completionValue);
}
void FunctionBuilder::HandleCompletion(const ir::AstNode *node, VReg completionType, VReg completionValue)
{
// .return(value)
pg_->LoadAccumulatorInt(node, static_cast<int32_t>(ResumeMode::RETURN));
auto *notRetLabel = pg_->AllocLabel();
pg_->Condition(node, lexer::TokenType::PUNCTUATOR_EQUAL, completionType, notRetLabel);
if (!handleReturn_) {
handleReturn_ = true;
pg_->ControlFlowChangeBreak();
handleReturn_ = false;
}
pg_->LoadAccumulator(node, completionValue);
pg_->DirectReturn(node);
// .throw(value)
pg_->SetLabel(node, notRetLabel);
pg_->LoadAccumulatorInt(node, static_cast<int32_t>(ResumeMode::THROW));
auto *not_throw_label = pg_->AllocLabel();
pg_->Condition(node, lexer::TokenType::PUNCTUATOR_EQUAL, completionType, not_throw_label);
pg_->LoadAccumulator(node, completionValue);
pg_->EmitThrow(node);
// .next(value)
pg_->SetLabel(node, not_throw_label);
pg_->LoadAccumulator(node, completionValue);
}
void FunctionBuilder::YieldStar(const ir::AstNode *node)
{
ASSERT(BuilderKind() == BuilderType::GENERATOR || BuilderKind() == BuilderType::ASYNC_GENERATOR);
RegScope rs(pg_);
auto *loopStart = pg_->AllocLabel();
auto *returnCompletion = pg_->AllocLabel();
auto *throwCompletion = pg_->AllocLabel();
auto *callMethod = pg_->AllocLabel();
auto *normalOrThrowCompletion = pg_->AllocLabel();
auto *iteratorComplete = pg_->AllocLabel();
// 4. Let iteratorRecord be ? GetIterator(value, generatorKind).
Iterator iterator(pg_, node, GeneratorKind());
// 6. Let received be NormalCompletion(undefined).
VReg receivedValue = iterator.NextResult();
VReg receivedType = pg_->AllocReg();
VReg nextMethod = pg_->AllocReg();
VReg exitReturn = pg_->AllocReg();
pg_->StoreConst(node, receivedValue, Constant::JS_UNDEFINED);
pg_->LoadAccumulatorInt(node, static_cast<int32_t>(ResumeMode::NEXT));
pg_->StoreAccumulator(node, receivedType);
pg_->MoveVreg(node, nextMethod, iterator.Method());
// 7. Repeat
pg_->SetLabel(node, loopStart);
pg_->StoreConst(node, exitReturn, Constant::JS_FALSE);
// a. If received.[[Type]] is normal, then
pg_->LoadAccumulatorInt(node, static_cast<int32_t>(ResumeMode::NEXT));
pg_->Condition(node, lexer::TokenType::PUNCTUATOR_STRICT_EQUAL, receivedType, throwCompletion);
pg_->MoveVreg(node, iterator.Method(), nextMethod);
pg_->Branch(node, callMethod);
// b. Else if received.[[Type]] is throw, then
pg_->SetLabel(node, throwCompletion);
pg_->LoadAccumulatorInt(node, static_cast<int32_t>(ResumeMode::THROW));
pg_->Condition(node, lexer::TokenType::PUNCTUATOR_STRICT_EQUAL, receivedType, returnCompletion);
// i. Let throw be ? GetMethod(iterator, "throw").
iterator.GetMethod("throw");
// ii. If throw is not undefined, then
pg_->BranchIfNotUndefined(node, callMethod);
// iii. Else,
// 1. NOTE: If iterator does not have a throw method, this throw is going to terminate the yield* loop. But first we
// need to give iterator a chance to clean up.
// 2. Let closeCompletion be Completion { [[Type]]: normal, [[Value]]: empty, [[Target]]: empty }.
// 3. If generatorKind is async, perform ? AsyncIteratorClose(iteratorRecord, closeCompletion).
// 4. Else, perform ? IteratorClose(iteratorRecord, closeCompletion).
iterator.Close(false);
// 5. NOTE: The next step throws a TypeError to indicate that there was a yield* protocol violation: iterator does
// not have a throw method.
// 6. Throw a TypeError exception.
pg_->ThrowThrowNotExist(node);
// c. Else,
// i. Assert: received.[[Type]] is return.
pg_->SetLabel(node, returnCompletion);
pg_->StoreConst(node, exitReturn, Constant::JS_TRUE);
// ii. Let return be ? GetMethod(iterator, "return").
iterator.GetMethod("return");
// iii. If return is undefined, then
pg_->BranchIfNotUndefined(node, callMethod);
// 1. If generatorKind is async, set received.[[Value]] to ? Await(received.[[Value]]).
pg_->ControlFlowChangeBreak();
pg_->LoadAccumulator(node, receivedValue);
if (GeneratorKind() == IteratorType::ASYNC) {
Await(node);
}
// 2. Return Completion(received).
pg_->DirectReturn(node);
pg_->SetLabel(node, callMethod);
// i. Let innerResult be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]], « received.[[Value]] »).
// 1. Let innerResult be ? Call(throw, iterator, « received.[[Value]] »).
// iv. Let innerReturnResult be ? Call(return, iterator, « received.[[Value]] »).
iterator.CallMethodWithValue();
// ii. ii. If generatorKind is async, set innerResult to ? Await(innerResult).
// 2. If generatorKind is async, set innerResult to ? Await(innerResult).
// v. If generatorKind is async, set innerReturnResult to ? Await(innerReturnResult).
if (GeneratorKind() == IteratorType::ASYNC) {
Await(node);
}
pg_->StoreAccumulator(node, receivedValue);
// ii. If Type(innerResult) is not Object, throw a TypeError exception.
// 4. If Type(innerResult) is not Object, throw a TypeError exception.
// vi. If Type(innerReturnResult) is not Object, throw a TypeError exception.
pg_->ThrowIfNotObject(node);
// iv. Let done be ? IteratorComplete(innerResult).
// v. Let done be ? IteratorComplete(innerResult).
// vii. Let done be ? IteratorComplete(innerReturnResult).
iterator.Complete();
pg_->BranchIfTrue(node, iteratorComplete);
pg_->LoadAccumulator(node, receivedValue);
// vi. If generatorKind is async, set received to AsyncGeneratorYield(? IteratorValue(innerResult)).
// 7. If generatorKind is async, set received to AsyncGeneratorYield(? IteratorValue(innerResult)).
// ix. If generatorKind is async, set received to AsyncGeneratorYield(? IteratorValue(innerReturnResult)).
if (GeneratorKind() == IteratorType::ASYNC) {
iterator.Value();
// 27.6.3.8 AsyncGeneratorYield
// 5. Set value to ? Await(value).
Await(node);
// 6. Set generator.[[AsyncGeneratorState]] to suspendedYield.
AsyncYield(node, receivedType, receivedValue);
// a. If resumptionValue.[[Type]] is not return
pg_->LoadAccumulatorInt(node, static_cast<int32_t>(ResumeMode::RETURN));
pg_->Condition(node, lexer::TokenType::PUNCTUATOR_EQUAL, receivedType, loopStart);
// b. Let awaited be Await(resumptionValue.[[Value]]).
pg_->LoadAccumulator(node, receivedValue);
pg_->AsyncFunctionAwait(node, funcObj_);
SuspendResumeExecution(node, receivedType, receivedValue);
// c. If awaited.[[Type]] is throw, return Completion(awaited).
pg_->LoadAccumulatorInt(node, static_cast<int32_t>(ResumeMode::THROW));
// d. Assert: awaited.[[Type]] is normal.
// e. Return Completion { [[Type]]: return, [[Value]]: awaited.[[Value]], [[Target]]: empty }.
pg_->Condition(node, lexer::TokenType::PUNCTUATOR_EQUAL, receivedType, returnCompletion);
} else {
// vii. Else, set received to GeneratorYield(innerResult).
// 8. Else, set received to GeneratorYield(innerResult).
// x. Else, set received to GeneratorYield(innerReturnResult).
pg_->GeneratorYield(node, funcObj_);
SuspendResumeExecution(node, receivedType, receivedValue);
}
pg_->Branch(node, loopStart);
// v. If done is true, then
// 6. If done is true, then
// viii. If done is true, then
pg_->SetLabel(node, iteratorComplete);
pg_->LoadAccumulator(node, exitReturn);
pg_->BranchIfFalse(node, normalOrThrowCompletion);
// 1. Let value be ? IteratorValue(innerReturnResult).
iterator.Value();
if (pg_->CheckControlFlowChange()) {
pg_->StoreAccumulator(node, receivedValue);
pg_->ControlFlowChangeBreak();
pg_->LoadAccumulator(node, receivedValue);
}
// 2. Return Completion { [[Type]]: return, [[Value]]: value, [[Target]]: empty }.
pg_->DirectReturn(node);
pg_->SetLabel(node, normalOrThrowCompletion);
// 1. Return ? IteratorValue(innerResult).
// a. Return ? IteratorValue(innerResult).
iterator.Value();
}
} // namespace panda::es2panda::compiler
@@ -0,0 +1,91 @@
/**
* 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.
*/
#ifndef ES2PANDA_COMPILER_FUNCTION_FUNCTION_BUILDER_H
#define ES2PANDA_COMPILER_FUNCTION_FUNCTION_BUILDER_H
#include <macros.h>
#include <ir/irnode.h>
namespace panda::es2panda::ir {
class ScriptFunction;
} // namespace panda::es2panda::ir
namespace panda::es2panda::compiler {
class PandaGen;
class CatchTable;
enum class IteratorType;
enum class ResumeMode {
RETURN,
THROW,
NEXT,
};
class FunctionBuilder {
public:
enum class BuilderType {
NORMAL,
GENERATOR,
ASYNC,
ASYNC_GENERATOR,
};
explicit FunctionBuilder(PandaGen *pg, CatchTable *catchTable);
virtual ~FunctionBuilder() = default;
NO_COPY_SEMANTIC(FunctionBuilder);
NO_MOVE_SEMANTIC(FunctionBuilder);
virtual void Prepare([[maybe_unused]] const ir::ScriptFunction *node) const {};
virtual void CleanUp([[maybe_unused]] const ir::ScriptFunction *node) const {};
virtual void DirectReturn(const ir::AstNode *node) const;
virtual void ImplicitReturn(const ir::AstNode *node) const;
virtual void Await(const ir::AstNode *node);
virtual void YieldStar(const ir::AstNode *node);
virtual void Yield([[maybe_unused]] const ir::AstNode *node)
{
UNREACHABLE();
};
protected:
virtual BuilderType BuilderKind() const
{
return BuilderType::NORMAL;
}
virtual IteratorType GeneratorKind() const;
void SuspendResumeExecution(const ir::AstNode *node, VReg completionType, VReg completionValue) const;
void AsyncYield(const ir::AstNode *node, VReg completionType, VReg completionValue) const;
VReg FunctionReg(const ir::ScriptFunction *node) const;
void HandleCompletion(const ir::AstNode *node, VReg completionType, VReg completionValue);
PandaGen *pg_;
CatchTable *catchTable_;
VReg funcObj_ {};
bool handleReturn_ {};
private:
void resumeGenerator(const ir::AstNode *node, VReg completionType, VReg completionValue) const;
};
} // namespace panda::es2panda::compiler
#endif
@@ -0,0 +1,71 @@
/*
* 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 "generatorFunctionBuilder.h"
#include <compiler/core/pandagen.h>
#include <compiler/base/catchTable.h>
#include <ir/base/scriptFunction.h>
namespace panda::es2panda::compiler {
void GeneratorFunctionBuilder::Prepare(const ir::ScriptFunction *node) const
{
VReg callee = FunctionReg(node);
pg_->CreateGeneratorObj(node, callee);
pg_->StoreAccumulator(node, funcObj_);
pg_->SuspendGenerator(node, funcObj_);
pg_->SetLabel(node, catchTable_->LabelSet().TryBegin());
}
void GeneratorFunctionBuilder::CleanUp(const ir::ScriptFunction *node) const
{
const auto &labelSet = catchTable_->LabelSet();
pg_->SetLabel(node, labelSet.TryEnd());
pg_->SetLabel(node, labelSet.CatchBegin());
pg_->GeneratorComplete(node, funcObj_);
pg_->EmitThrow(node);
pg_->SetLabel(node, labelSet.CatchEnd());
}
void GeneratorFunctionBuilder::DirectReturn(const ir::AstNode *node) const
{
pg_->GeneratorComplete(node, funcObj_);
pg_->CreateIterResultObject(node, true);
pg_->EmitReturn(node);
}
void GeneratorFunctionBuilder::ImplicitReturn(const ir::AstNode *node) const
{
pg_->LoadConst(node, Constant::JS_UNDEFINED);
DirectReturn(node);
}
void GeneratorFunctionBuilder::Yield(const ir::AstNode *node)
{
RegScope rs(pg_);
VReg completionType = pg_->AllocReg();
VReg completionValue = pg_->AllocReg();
pg_->CreateIterResultObject(node, false);
pg_->GeneratorYield(node, funcObj_);
SuspendResumeExecution(node, completionType, completionValue);
HandleCompletion(node, completionType, completionValue);
}
} // namespace panda::es2panda::compiler
@@ -0,0 +1,64 @@
/**
* 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.
*/
#ifndef ES2PANDA_COMPILER_FUNCTION_GENERATOR_FUNCTION_BUILDER_H
#define ES2PANDA_COMPILER_FUNCTION_GENERATOR_FUNCTION_BUILDER_H
#include <ir/irnode.h>
#include <compiler/function/functionBuilder.h>
namespace panda::es2panda::ir {
class YieldExpression;
} // namespace panda::es2panda::ir
namespace panda::es2panda::compiler {
class PandaGen;
enum class GeneratorState {
UNDEFINED = 0,
SUSPENDED_START,
SUSPENDED_YIELD,
EXECUTING,
COMPLETED,
AWAITING_RETURN,
};
class GeneratorFunctionBuilder : public FunctionBuilder {
public:
explicit GeneratorFunctionBuilder(PandaGen *pg, CatchTable *catchTable) : FunctionBuilder(pg, catchTable) {}
~GeneratorFunctionBuilder() override = default;
NO_COPY_SEMANTIC(GeneratorFunctionBuilder);
NO_MOVE_SEMANTIC(GeneratorFunctionBuilder);
void Prepare(const ir::ScriptFunction *node) const override;
void CleanUp(const ir::ScriptFunction *node) const override;
void DirectReturn(const ir::AstNode *node) const override;
void ImplicitReturn(const ir::AstNode *node) const override;
void Yield(const ir::AstNode *node) override;
protected:
BuilderType BuilderKind() const override
{
return BuilderType::GENERATOR;
}
};
} // namespace panda::es2panda::compiler
#endif
+83
View File
@@ -0,0 +1,83 @@
% def get_format_name(mnemonic)
% return "#{mnemonic.gsub('.', '_').upcase}" + "_FORMATS"
% end
% def get_format_item_name(mnemonic, index)
% return "#{mnemonic.gsub('.', '_').upcase}" + "_FORMAT_ITEMS_" + index.to_s
% end
/**
* 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.
*/
// Autogenerated file -- DO NOT EDIT!
#ifndef ES2PANDA_COMPILER_GEN_FORMATS_H
#define ES2PANDA_COMPILER_GEN_FORMATS_H
#include <ir/irnode.h>
namespace panda::es2panda::compiler {
% def get_operand_kind(op, insn)
% if op.reg?
% if op.src? and op.dst?
% return "OperandKind::SRC_DST_VREG"
% elsif op.src?
% return "OperandKind::SRC_VREG"
% elsif op.dst?
% return "OperandKind::DST_VREG"
% end
% return nil
% elsif op.imm?
% is_jump = insn.properties.include? 'jump'
% return is_jump ? "OperandKind::LABEL" : "OperandKind::IMM"
% elsif op.id?
% is_string_id = insn.properties.include? 'string_id'
% return is_string_id ? "OperandKind::STRING_ID" : "OperandKind::ID"
% else
% return nil
% end
% end
%
% def make_format(fmt, insn)
% operands = fmt.operands.map {|op| "{#{get_operand_kind(op, insn)}, #{op.width}}"}
% return operands
% end
%
% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group|
% insn = group.first
% formats = group.map {|i| make_format(i,insn) }
% empty = false
% formats.each.with_index do |fmt, index|
% if fmt.length != 0
constexpr std::array<const FormatItem, <%= fmt.length %>> <%= get_format_item_name(mnemonic, index) %> = {{
<%= fmt.join(", ") %>
}};
% else
% empty = true
% end
% end
%
% if empty
constexpr std::array<const Format, 0> <%= get_format_name(mnemonic) %> = {{}};
% else
constexpr std::array<const Format, <%= formats.length %>> <%= get_format_name(mnemonic) %> = {{
% format_items = (0..(formats.length - 1)).map {|index| "{" + get_format_item_name(mnemonic, index) + ".data(), " + get_format_item_name(mnemonic, index) + ".size()}" }
<%= format_items.join(", ") %>
%
}};
% end
% end
} // namespace panda::es2panda::compiler
#endif
+232
View File
@@ -0,0 +1,232 @@
% def get_node_kind(mnemonic)
% return "#{mnemonic.gsub('.', '_').upcase}"
% end
%
% def get_format_name(mnemonic)
% return "#{mnemonic.gsub('.', '_').upcase}" + "_FORMATS"
% end
/**
* 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.
*/
// Autogenerated file -- DO NOT EDIT!
#ifndef ES2PANDA_COMPILER_GEN_IR_ISA_H
#define ES2PANDA_COMPILER_GEN_IR_ISA_H
#include <ir/irnode.h>
#include <gen/formats.h>
#include <assembly-ins.h>
namespace panda::es2panda::compiler {
class Label : public IRNode {
public:
explicit Label(const ir::AstNode* node, std::string id) : IRNode(node), id_(std::move(id)) {}
static constexpr std::string_view PREFIX = "LABEL_";
Formats GetFormats() const override
{
return Span<const Format>(nullptr, nullptr);
}
const std::string &Id() const
{
return id_;
}
size_t Registers([[maybe_unused]] std::array<VReg*, MAX_REG_OPERAND>* regs) override
{
return 0;
}
size_t Registers([[maybe_unused]] std::array<const VReg*, MAX_REG_OPERAND>* regs) const override
{
return 0;
}
void Transform(pandasm::Ins *ins) const override
{
ins->opcode = pandasm::Opcode::INVALID;
ins->set_label = true;
ins->label = id_;
}
private:
std::string id_;
};
% def insn2node(insn)
% mnemonic = insn.mnemonic.split('.')
% return mnemonic.map{|el| el == '64' ? 'Wide' : el.capitalize}.join()
% end
%
% def is_VReg (name)
% if name == :v
% return true
% end
% end
%
% def is_Acc(name)
% if name == :acc
% return true
% end
% end
%
% def is_Imm(name)
% if name == :imm
% return true
% end
% end
%
% def is_Id(name)
% if %i[method_id type_id field_id string_id stringId callsite_id literalarray_id].include?(name)
% return true
% end
% end
%
% def get_operand_type(name, name_tmp, insn, map)
% if is_VReg (name_tmp)
% map['reg'].push("#{name}_")
% return 'VReg'
% elsif is_Imm(name_tmp)
% if insn.properties.include? 'jump'
% map['lbl'].push("#{name}_")
% return "Label*"
% end
% map['imm'].push("#{name}_")
% if insn.sig.include? 'imm:f64'
% return 'double'
% end
% return 'int64_t'
% elsif is_Id(name_tmp)
% map['str'].push("#{name}_")
% return 'util::StringView'
% else
% return nil
% end
% end
%
% def get_operands(sig)
% return [] unless sig.include? ' '
% _, operands = sig.match(/(\S+) (.+)/).captures
% operands = operands.split(', ')
% end
%
% def get_ctor_args(insn)
% operands = get_operands(insn.sig)
% ops = Array.new
% ctor_args = Array.new
% op_map = Hash.new { |h, k| h[k] = [] }
% operands.map do |operand|
% operand_parts = operand.split(':')
% case operand_parts.size
% when 1
% name = operand_parts[0]
% when 2
% name, _ = operand_parts
% when 3
% name, _, _ = operand_parts
% else
% raise 'Unexpected operand string'
% end
%
% name_tmp = name_tmp = name.to_s.gsub(/[0-9]/, '').to_sym;
%
% if is_Id(name_tmp)
% name = "stringId"
% end
%
% ops.push(name)
% type = get_operand_type(name, name_tmp, insn, op_map)
% ctor_args.push("#{type} #{name}")
% end
% return ops,ctor_args,op_map
% end
%
% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group|
% insn = group.first
% node_kind = get_node_kind(mnemonic)
% class_name = insn2node(insn)
% base_class = "IRNode"
% ops_list,ctor_arg_list,op_map = get_ctor_args(insn)
% ctor_args = "const ir::AstNode* node" + (ctor_arg_list.length == 0 ? "" : ", ") + ctor_arg_list.map {|arg| "#{arg}"}.join(", ")
% members = ctor_arg_list.map {|arg| "#{arg}_;"}.join("\n ")
% registers = op_map['reg'].map {|reg| "&#{reg}"}.join(", ")
% ops = (ops_list.length == 0 ? "" : ", ") + ops_list.map { |op| "#{op}_(#{op})"}.join(", ")
class <%= class_name %> : public <%= base_class %>
{
public:
explicit <%= class_name %>(<%= ctor_args %>) : <%= base_class %>(node)<%= ops %> {}
Formats GetFormats() const override {
return Span<const Format>(<%= get_format_name(insn.mnemonic) %>);
}
size_t Registers([[maybe_unused]] std::array<VReg*, MAX_REG_OPERAND>* regs) override
{
% reg_cnt = 0
% for reg in op_map['reg']
(*regs)[<%= reg_cnt %>] = &<%= reg %>;
% reg_cnt+=1;
% end
return <%= reg_cnt %>;
}
size_t Registers([[maybe_unused]] std::array<const VReg*, MAX_REG_OPERAND>* regs) const override
{
% reg_cnt = 0
% for reg in op_map['reg']
(*regs)[<%= reg_cnt %>] = &<%= reg %>;
% reg_cnt+=1;
% end
return <%= reg_cnt %>;
}
void Transform(pandasm::Ins* ins) const override {
ins->opcode = pandasm::Opcode::<%= node_kind %>;
% if op_map['reg'].length != 0
ins->regs.reserve(<%= op_map['reg'].length %>);
% end
% if op_map['imm'].length != 0
ins->imms.reserve(<%= op_map['imm'].length %>);
% end
% if op_map['str'].length + op_map['lbl'].length != 0
ins->ids.reserve(<%= op_map['str'].length + op_map['lbl'].length %>);
% end
% for reg in op_map['reg']
ins->regs.emplace_back(<%= reg %>);
% end
% for imm in op_map['imm']
ins->imms.emplace_back(<%= imm %>);
% end
% for str in op_map['str']
ins->ids.emplace_back(<%= str %>.Mutf8());
% end
% for lbl in op_map['lbl']
ins->ids.emplace_back(<%= lbl %>->Id());
% end
}
% if ops_list.length != 0
private:
<%= members %>
% end
};
% end
} // namespace panda::es2panda::compiler
#endif
+76
View File
@@ -0,0 +1,76 @@
/**
* Copyright (c) 2021 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 "es2panda.h"
#include <compiler/core/compileQueue.h>
#include <compiler/core/compilerContext.h>
#include <compiler/core/compilerImpl.h>
#include <parser/parserImpl.h>
#include <parser/program/program.h>
#include <iostream>
#include <thread>
namespace panda::es2panda {
// Compiler
constexpr size_t DEFAULT_THREAD_COUNT = 2;
Compiler::Compiler(ScriptExtension ext) : Compiler(ext, DEFAULT_THREAD_COUNT) {}
Compiler::Compiler(ScriptExtension ext, size_t threadCount)
: parser_(new parser::ParserImpl(ext)), compiler_(new compiler::CompilerImpl(threadCount))
{
}
Compiler::~Compiler()
{
delete parser_;
delete compiler_;
}
panda::pandasm::Program *Compiler::Compile(const SourceFile &input, const CompilerOptions &options)
{
/* TODO(dbatyai): pass string view */
std::string fname(input.fileName);
std::string src(input.source);
try {
auto ast = input.isModule ? parser_->ParseModule(fname, src) : parser_->ParseScript(fname, src);
if (options.dumpAst) {
std::cout << ast.Dump() << std::endl;
}
if (options.parseOnly) {
return nullptr;
}
auto *prog = compiler_->Compile(&ast, options);
return prog;
} catch (const class Error &e) {
error_ = e;
return nullptr;
}
}
void Compiler::DumpAsm(const panda::pandasm::Program *prog)
{
compiler::CompilerImpl::DumpAsm(prog);
}
} // namespace panda::es2panda
+160
View File
@@ -0,0 +1,160 @@
/**
* Copyright (c) 2021 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.
*/
#ifndef ES2PANDA_PUBLIC_H
#define ES2PANDA_PUBLIC_H
#include <macros.h>
#include <string>
namespace panda::pandasm {
struct Program;
} // namespace panda::pandasm
namespace panda::es2panda {
namespace parser {
class ParserImpl;
} // namespace parser
namespace compiler {
class CompilerImpl;
} // namespace compiler
enum class ScriptExtension {
JS,
TS,
AS,
};
struct SourceFile {
SourceFile(std::string_view fn, std::string_view s) : fileName(fn), source(s) {};
SourceFile(std::string_view fn, std::string_view s, bool m) : fileName(fn), source(s), isModule(m) {};
std::string_view fileName {};
std::string_view source {};
bool isModule {false};
};
struct CompilerOptions {
bool isDebug {false};
bool dumpAst {false};
bool dumpAsm {false};
bool dumpDebugInfo {false};
bool parseOnly {false};
};
enum class ErrorType {
GENERIC,
SYNTAX,
TYPE,
};
class Error : public std::exception {
public:
Error() noexcept = default;
explicit Error(ErrorType type, std::string_view message) noexcept : type_(type), message_(message) {}
explicit Error(ErrorType type, std::string_view message, size_t line, size_t column) noexcept
: type_(type), message_(message), line_(line), col_(column)
{
}
~Error() override = default;
DEFAULT_COPY_SEMANTIC(Error);
DEFAULT_MOVE_SEMANTIC(Error);
ErrorType Type() const noexcept
{
return type_;
}
const char *TypeString() const noexcept
{
switch (type_) {
case ErrorType::SYNTAX:
return "SyntaxError";
case ErrorType::TYPE:
return "TypeError";
default:
break;
}
return "Error";
}
const char *what() const noexcept override
{
return message_.c_str();
}
int ErrorCode() const noexcept
{
return errorCode_;
}
const std::string &Message() const noexcept
{
return message_;
}
size_t Line() const
{
return line_;
}
size_t Col() const
{
return col_;
}
private:
ErrorType type_ {ErrorType::GENERIC};
std::string message_;
size_t line_ {};
size_t col_ {};
int errorCode_ {1};
};
class Compiler {
public:
explicit Compiler(ScriptExtension ext);
explicit Compiler(ScriptExtension ext, size_t threadCount);
~Compiler();
NO_COPY_SEMANTIC(Compiler);
NO_MOVE_SEMANTIC(Compiler);
panda::pandasm::Program *Compile(const SourceFile &input, const CompilerOptions &options);
inline panda::pandasm::Program *Compile(const SourceFile &input)
{
CompilerOptions options;
return Compile(input, options);
}
static void DumpAsm(const panda::pandasm::Program *prog);
const Error &GetError() const noexcept
{
return error_;
}
private:
parser::ParserImpl *parser_;
compiler::CompilerImpl *compiler_;
Error error_;
};
} // namespace panda::es2panda
#endif
+243
View File
@@ -0,0 +1,243 @@
/**
* Copyright (c) 2021 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 "astDump.h"
#include <ir/astNode.h>
#include <cmath>
#include <iostream>
namespace panda::es2panda::ir {
AstDumper::AstDumper(const BlockStatement *program, util::StringView sourceCode) : index_(sourceCode), indent_(0)
{
SerializeObject(reinterpret_cast<const ir::AstNode *>(program));
}
void AstDumper::Add(std::initializer_list<AstDumper::Property> props)
{
AddList<std::initializer_list<AstDumper::Property>>(props);
}
void AstDumper::Add(const AstDumper::Property &prop)
{
Serialize(prop);
}
const char *AstDumper::ModifierToString(ModifierFlags flags)
{
if (flags & ModifierFlags::PRIVATE) {
return "private";
}
if (flags & ModifierFlags::PROTECTED) {
return "protected";
}
if (flags & ModifierFlags::PUBLIC) {
return "public";
}
return nullptr;
}
const char *AstDumper::TypeOperatorToString(TSOperatorType operatorType)
{
if (operatorType == TSOperatorType::KEYOF) {
return "keyof";
}
if (operatorType == TSOperatorType::READONLY) {
return "readonly";
}
if (operatorType == TSOperatorType::UNIQUE) {
return "unique";
}
return nullptr;
}
void AstDumper::Serialize(const AstDumper::Property &prop)
{
SerializePropKey(prop.Key());
const auto &value = prop.Value();
if (std::holds_alternative<const char *>(value)) {
SerializeString(std::get<const char *>(value));
} else if (std::holds_alternative<util::StringView>(value)) {
SerializeString(std::get<util::StringView>(value));
} else if (std::holds_alternative<bool>(value)) {
SerializeBoolean(std::get<bool>(value));
} else if (std::holds_alternative<double>(value)) {
SerializeNumber(std::get<double>(value));
} else if (std::holds_alternative<const ir::AstNode *>(value)) {
SerializeObject(std::get<const ir::AstNode *>(value));
} else if (std::holds_alternative<std::vector<const ir::AstNode *>>(value)) {
SerializeArray(std::get<std::vector<const ir::AstNode *>>(value));
} else if (std::holds_alternative<lexer::TokenType>(value)) {
SerializeToken(std::get<lexer::TokenType>(value));
} else if (std::holds_alternative<std::initializer_list<Property>>(value)) {
SerializePropList(std::get<std::initializer_list<Property>>(value));
} else if (std::holds_alternative<Property::Constant>(value)) {
SerializeConstant(std::get<Property::Constant>(value));
}
}
void AstDumper::SerializeToken(lexer::TokenType token)
{
ss_ << "\"" << lexer::TokenToString(token) << "\"";
}
void AstDumper::SerializePropKey(const char *str)
{
ss_ << std::endl;
Indent();
SerializeString(str);
ss_ << ": ";
}
void AstDumper::SerializeString(const char *str)
{
ss_ << "\"" << str << "\"";
}
void AstDumper::SerializeString(const util::StringView &str)
{
ss_ << "\"" << str.Utf8() << "\"";
}
void AstDumper::SerializeNumber(size_t number)
{
ss_ << number;
}
void AstDumper::SerializeNumber(double number)
{
if (std::isinf(number)) {
ss_ << "\"Infinity\"";
} else {
ss_ << number;
}
}
void AstDumper::SerializeBoolean(bool boolean)
{
ss_ << (boolean ? "true" : "false");
}
void AstDumper::SerializeConstant(Property::Constant constant)
{
switch (constant) {
case Property::Constant::PROP_NULL: {
ss_ << "null";
break;
}
case Property::Constant::EMPTY_ARRAY: {
ss_ << "[]";
break;
}
default: {
UNREACHABLE();
}
}
}
void AstDumper::SerializePropList(std::initializer_list<AstDumper::Property> props)
{
Wrap([this, &props]() -> void {
for (const auto *it = props.begin(); it != props.end(); ++it) {
Serialize(*it);
if (std::next(it) != props.end()) {
ss_ << ',';
}
}
});
}
void AstDumper::SerializeArray(std::vector<const ir::AstNode *> array)
{
Wrap(
[this, &array]() -> void {
for (auto it = array.begin(); it != array.end(); ++it) {
ss_ << std::endl;
Indent();
SerializeObject(*it);
if (std::next(it) != array.end()) {
ss_ << ',';
}
}
},
'[', ']');
}
void AstDumper::SerializeObject(const ir::AstNode *object)
{
Wrap([this, object]() -> void {
object->Dump(this);
SerializeLoc(object->Range());
});
}
void AstDumper::Wrap(const WrapperCb &cb, char delimStart, char delimEnd)
{
ss_ << delimStart;
indent_++;
cb();
ss_ << std::endl;
indent_--;
Indent();
ss_ << delimEnd;
}
void AstDumper::SerializeLoc(const lexer::SourceRange &loc)
{
ss_ << ',';
SerializePropKey("loc");
Wrap([this, &loc]() -> void {
SerializePropKey("start");
SerializeSourcePosition(loc.start);
ss_ << ',';
SerializePropKey("end");
SerializeSourcePosition(loc.end);
});
}
void AstDumper::SerializeSourcePosition(const lexer::SourcePosition &pos)
{
lexer::SourceLocation loc = index_.GetLocation(pos);
Wrap([this, &loc]() -> void {
SerializePropKey("line");
SerializeNumber(loc.line);
ss_ << ',';
SerializePropKey("column");
SerializeNumber(loc.col);
});
}
void AstDumper::Indent()
{
for (int32_t i = 0; i < indent_; i++) {
ss_ << " ";
}
}
} // namespace panda::es2panda::ir
+206
View File
@@ -0,0 +1,206 @@
/**
* Copyright (c) 2021 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.
*/
#ifndef ES2PANDA_IR_ASTDUMP_H
#define ES2PANDA_IR_ASTDUMP_H
#include <ir/astNode.h>
#include <lexer/token/sourceLocation.h>
#include <lexer/token/tokenType.h>
#include <util/ustring.h>
#include <sstream>
#include <variant>
namespace panda::es2panda::ir {
class AstDumper {
public:
class Nullable {
public:
explicit Nullable(const ir::AstNode *node) : node_(node) {}
const ir::AstNode *Node() const
{
return node_;
}
private:
const ir::AstNode *node_;
};
class Optional {
public:
using Val = std::variant<const char *, const ir::AstNode *, bool>;
explicit Optional(const ir::AstNode *node) : value_(node) {}
explicit Optional(const char *string) : value_(const_cast<char *>(string)) {}
explicit Optional(bool boolean) : value_(boolean) {}
const Val &Value() const
{
return value_;
}
private:
Val value_;
};
class Property {
public:
class Ignore {
public:
Ignore() = default;
};
enum class Constant {
PROP_NULL,
EMPTY_ARRAY,
};
using Val =
std::variant<const char *, lexer::TokenType, std::initializer_list<Property>, util::StringView, bool,
double, const ir::AstNode *, std::vector<const ir::AstNode *>, Constant, Nullable, Ignore>;
Property(const char *key, const char *string) : key_(key), value_(string) {}
Property(const char *key, util::StringView str) : key_(key), value_(str) {}
Property(const char *key, bool boolean) : key_(key), value_(boolean) {}
Property(const char *key, double number) : key_(key), value_(number) {}
Property(const char *key, lexer::TokenType token) : key_(key), value_(token) {}
Property(const char *key, std::initializer_list<Property> props) : key_(key), value_(props) {}
Property(const char *key, const ir::AstNode *node) : key_(key), value_(const_cast<ir::AstNode *>(node)) {}
Property(const char *key, Constant constant) : key_(key), value_(constant) {}
Property(const char *key, Nullable nullable) : key_(key)
{
if (nullable.Node()) {
value_ = nullable.Node();
} else {
value_ = Property::Constant::PROP_NULL;
}
}
Property(const char *key, Optional optional) : key_(key)
{
const auto &value = optional.Value();
if (std::holds_alternative<const ir::AstNode *>(value) && std::get<const ir::AstNode *>(value)) {
value_ = std::get<const ir::AstNode *>(value);
return;
}
if (std::holds_alternative<const char *>(value) && std::get<const char *>(value)) {
value_ = std::get<const char *>(value);
return;
}
if (std::holds_alternative<bool>(value) && std::get<bool>(value)) {
value_ = std::get<bool>(value);
return;
}
value_ = Ignore();
}
template <typename T>
Property(const char *key, const ArenaVector<T> &array) : key_(key)
{
if (array.empty()) {
value_ = Constant::EMPTY_ARRAY;
return;
}
std::vector<const ir::AstNode *> nodes;
nodes.reserve(array.size());
for (auto &it : array) {
nodes.push_back(it);
}
value_ = std::move(nodes);
}
const char *Key() const
{
return key_;
}
const Val &Value() const
{
return value_;
}
private:
const char *key_;
Val value_ {false};
};
explicit AstDumper(const BlockStatement *program, util::StringView sourceCode);
void Add(std::initializer_list<Property> props);
void Add(const AstDumper::Property &prop);
static const char *ModifierToString(ModifierFlags flags);
static const char *TypeOperatorToString(TSOperatorType operatorType);
std::string Str() const
{
return ss_.str();
}
private:
using WrapperCb = std::function<void()>;
template <typename T>
void AddList(T props)
{
for (auto it = props.begin(); it != props.end();) {
Serialize(*it);
do {
if (++it == props.end()) {
return;
}
} while (std::holds_alternative<Property::Ignore>((*it).Value()));
ss_ << ',';
}
}
void Indent();
void Serialize(const AstDumper::Property &prop);
void SerializePropKey(const char *str);
void SerializeString(const char *str);
void SerializeString(const util::StringView &str);
void SerializeNumber(size_t number);
void SerializeNumber(double number);
void SerializeBoolean(bool boolean);
void SerializeObject(const ir::AstNode *object);
void SerializeToken(lexer::TokenType token);
void SerializePropList(std::initializer_list<AstDumper::Property> props);
void SerializeConstant(Property::Constant constant);
void Wrap(const WrapperCb &cb, char delimStart = '{', char delimEnd = '}');
void SerializeLoc(const lexer::SourceRange &loc);
void SerializeSourcePosition(const lexer::SourcePosition &pos);
void SerializeArray(std::vector<const ir::AstNode *> array);
lexer::LineIndex index_;
std::stringstream ss_;
int32_t indent_;
};
} // namespace panda::es2panda::ir
#endif // ASTDUMP_H
+277
View File
@@ -0,0 +1,277 @@
/**
* Copyright (c) 2021 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.
*/
#ifndef ES2PANDA_IR_ASTNODE_H
#define ES2PANDA_IR_ASTNODE_H
#include <ir/astNodeMapping.h>
#include <lexer/token/sourceLocation.h>
#include <util/enumbitops.h>
#include <functional>
#include <macros.h>
namespace panda::es2panda::compiler {
class PandaGen;
} // namespace panda::es2panda::compiler
namespace panda::es2panda::checker {
class Checker;
class Type;
} // namespace panda::es2panda::checker
namespace panda::es2panda::ir {
class AstNode;
using NodeTraverser = std::function<void(AstNode *)>;
enum class AstNodeType {
#define DECLARE_NODE_TYPES(nodeType, className) nodeType,
AST_NODE_MAPPING(DECLARE_NODE_TYPES)
#undef DECLARE_NODE_TYPES
#define DECLARE_NODE_TYPES(nodeType1, nodeType2, baseClass, reinterpretClass) nodeType1, nodeType2,
AST_NODE_REINTERPRET_MAPPING(DECLARE_NODE_TYPES)
#undef DECLARE_NODE_TYPES
};
enum class AstNodeFlags {
NO_OPTS = 0,
STRICT = (1U << 0U),
PARAMETER = (1U << 1U),
};
DEFINE_BITOPS(AstNodeFlags)
enum class ModifierFlags {
NONE = 0,
STATIC = 1 << 0,
ASYNC = 1 << 1,
PUBLIC = 1 << 2,
PROTECTED = 1 << 3,
PRIVATE = 1 << 4,
DECLARE = 1 << 5,
READONLY = 1 << 6,
OPTIONAL = 1 << 7,
DEFINITE = 1 << 8,
ABSTRACT = 1 << 9,
ACCESS = PUBLIC | PROTECTED | PRIVATE,
ALL = STATIC | ASYNC | ACCESS | DECLARE | READONLY | ABSTRACT,
ALLOWED_IN_CTOR_PARAMETER = ACCESS | READONLY,
};
DEFINE_BITOPS(ModifierFlags)
enum class ScriptFunctionFlags {
NONE = 0,
GENERATOR = 1 << 0,
ASYNC = 1 << 1,
ARROW = 1 << 2,
EXPRESSION = 1 << 3,
OVERLOAD = 1 << 4,
CONSTRUCTOR = 1 << 5,
METHOD = 1 << 6
};
DEFINE_BITOPS(ScriptFunctionFlags)
enum class TSOperatorType { READONLY, KEYOF, UNIQUE };
enum class MappedOption { NO_OPTS, PLUS, MINUS };
// Predefinitions
class AstDumper;
class Expression;
class Statement;
#define DECLARE_CLASSES(nodeType, className) class className;
AST_NODE_MAPPING(DECLARE_CLASSES)
#undef DECLARE_CLASSES
#define DECLARE_CLASSES(nodeType1, nodeType2, baseClass, reinterpretClass) class baseClass;
AST_NODE_REINTERPRET_MAPPING(DECLARE_CLASSES)
#undef DECLARE_CLASSES
class AstNode {
public:
explicit AstNode(AstNodeType type) : type_(type) {};
virtual ~AstNode() = default;
NO_COPY_SEMANTIC(AstNode);
NO_MOVE_SEMANTIC(AstNode);
bool IsProgram() const
{
return parent_ == nullptr;
}
#define DECLARE_IS_CHECKS(nodeType, className) \
bool Is##className() const \
{ \
return type_ == AstNodeType::nodeType; \
}
AST_NODE_MAPPING(DECLARE_IS_CHECKS)
#undef DECLARE_IS_CHECKS
#define DECLARE_IS_CHECKS(nodeType1, nodeType2, baseClass, reinterpretClass) \
bool Is##baseClass() const \
{ \
return type_ == AstNodeType::nodeType1; \
} \
bool Is##reinterpretClass() const \
{ \
return type_ == AstNodeType::nodeType2; \
}
AST_NODE_REINTERPRET_MAPPING(DECLARE_IS_CHECKS)
#undef DECLARE_IS_CHECKS
virtual bool IsStatement() const
{
return false;
}
virtual bool IsExpression() const
{
return false;
}
#define DECLARE_AS_CASTS(nodeType, className) \
className *As##className() \
{ \
ASSERT(Is##className()); \
return reinterpret_cast<className *>(this); \
} \
const className *As##className() const \
{ \
ASSERT(Is##className()); \
return reinterpret_cast<const className *>(this); \
}
AST_NODE_MAPPING(DECLARE_AS_CASTS)
#undef DECLARE_AS_CASTS
#define DECLARE_AS_CASTS(nodeType1, nodeType2, baseClass, reinterpretClass) \
baseClass *As##baseClass() \
{ \
ASSERT(Is##baseClass()); \
return reinterpret_cast<baseClass *>(this); \
} \
baseClass *As##reinterpretClass() \
{ \
ASSERT(Is##reinterpretClass()); \
return reinterpret_cast<baseClass *>(this); \
} \
const baseClass *As##baseClass() const \
{ \
ASSERT(Is##baseClass()); \
return reinterpret_cast<const baseClass *>(this); \
} \
const baseClass *As##reinterpretClass() const \
{ \
ASSERT(Is##reinterpretClass()); \
return reinterpret_cast<const baseClass *>(this); \
}
AST_NODE_REINTERPRET_MAPPING(DECLARE_AS_CASTS)
#undef DECLARE_AS_CASTS
Expression *AsExpression()
{
ASSERT(IsExpression());
return reinterpret_cast<Expression *>(this);
}
const Expression *AsExpression() const
{
ASSERT(IsExpression());
return reinterpret_cast<const Expression *>(this);
}
Statement *AsStatement()
{
ASSERT(IsStatement());
return reinterpret_cast<Statement *>(this);
}
const Statement *AsStatement() const
{
ASSERT(IsStatement());
return reinterpret_cast<const Statement *>(this);
}
void SetRange(const lexer::SourceRange &loc)
{
range_ = loc;
}
void SetStart(const lexer::SourcePosition &start)
{
range_.start = start;
}
void SetEnd(const lexer::SourcePosition &end)
{
range_.end = end;
}
const lexer::SourcePosition &Start() const
{
return range_.start;
}
const lexer::SourcePosition &End() const
{
return range_.end;
}
const lexer::SourceRange &Range() const
{
return range_;
}
AstNodeType Type() const
{
return type_;
}
const AstNode *Parent()
{
return parent_;
}
const AstNode *Parent() const
{
return parent_;
}
void SetParent(const AstNode *parent)
{
parent_ = parent;
}
virtual void Iterate(const NodeTraverser &cb) const = 0;
virtual void Dump(ir::AstDumper *dumper) const = 0;
virtual void Compile([[maybe_unused]] compiler::PandaGen *pg) const = 0;
virtual checker::Type *Check([[maybe_unused]] checker::Checker *checker) const = 0;
protected:
void SetType(AstNodeType type)
{
type_ = type;
}
const AstNode *parent_ {};
lexer::SourceRange range_ {};
AstNodeType type_;
};
} // namespace panda::es2panda::ir
#endif
+149
View File
@@ -0,0 +1,149 @@
/**
* 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.
*/
#ifndef ES2PANDA_IR_AST_NODE_MAPPING_H
#define ES2PANDA_IR_AST_NODE_MAPPING_H
#define AST_NODE_MAPPING(_) \
_(ARROW_FUNCTION_EXPRESSION, ArrowFunctionExpression) \
_(AWAIT_EXPRESSION, AwaitExpression) \
_(BIGINT_LITERAL, BigIntLiteral) \
_(BINARY_EXPRESSION, BinaryExpression) \
_(BLOCK_STATEMENT, BlockStatement) \
_(BOOLEAN_LITERAL, BooleanLiteral) \
_(BREAK_STATEMENT, BreakStatement) \
_(CALL_EXPRESSION, CallExpression) \
_(CATCH_CLAUSE, CatchClause) \
_(CHAIN_EXPRESSION, ChainExpression) \
_(CLASS_DEFINITION, ClassDefinition) \
_(CLASS_DECLARATION, ClassDeclaration) \
_(CLASS_EXPRESSION, ClassExpression) \
_(CLASS_PROPERTY, ClassProperty) \
_(CONDITIONAL_EXPRESSION, ConditionalExpression) \
_(CONTINUE_STATEMENT, ContinueStatement) \
_(DEBUGGER_STATEMENT, DebuggerStatement) \
_(DECORATOR, Decorator) \
_(DO_WHILE_STATEMENT, DoWhileStatement) \
_(EMPTY_STATEMENT, EmptyStatement) \
_(EXPORT_ALL_DECLARATION, ExportAllDeclaration) \
_(EXPORT_DEFAULT_DECLARATION, ExportDefaultDeclaration) \
_(EXPORT_NAMED_DECLARATION, ExportNamedDeclaration) \
_(EXPORT_SPECIFIER, ExportSpecifier) \
_(EXPRESSION_STATEMENT, ExpressionStatement) \
_(FOR_IN_STATEMENT, ForInStatement) \
_(FOR_OF_STATEMENT, ForOfStatement) \
_(FOR_UPDATE_STATEMENT, ForUpdateStatement) \
_(FUNCTION_DECLARATION, FunctionDeclaration) \
_(FUNCTION_EXPRESSION, FunctionExpression) \
_(IDENTIFIER, Identifier) \
_(IF_STATEMENT, IfStatement) \
_(IMPORT_DECLARATION, ImportDeclaration) \
_(IMPORT_EXPRESSION, ImportExpression) \
_(IMPORT_DEFAULT_SPECIFIER, ImportDefaultSpecifier) \
_(IMPORT_NAMESPACE_SPECIFIER, ImportNamespaceSpecifier) \
_(IMPORT_SPECIFIER, ImportSpecifier) \
_(LABELLED_STATEMENT, LabelledStatement) \
_(MEMBER_EXPRESSION, MemberExpression) \
_(META_PROPERTY_EXPRESSION, MetaProperty) \
_(METHOD_DEFINITION, MethodDefinition) \
_(NEW_EXPRESSION, NewExpression) \
_(NULL_LITERAL, NullLiteral) \
_(NUMBER_LITERAL, NumberLiteral) \
_(OMITTED_EXPRESSION, OmittedExpression) \
_(PROPERTY, Property) \
_(REGEXP_LITERAL, RegExpLiteral) \
_(RETURN_STATEMENT, ReturnStatement) \
_(SCRIPT_FUNCTION, ScriptFunction) \
_(SEQUENCE_EXPRESSION, SequenceExpression) \
_(STRING_LITERAL, StringLiteral) \
_(SUPER_EXPRESSION, SuperExpression) \
_(SWITCH_CASE_STATEMENT, SwitchCaseStatement) \
_(SWITCH_STATEMENT, SwitchStatement) \
_(TS_ENUM_DECLARATION, TSEnumDeclaration) \
_(TS_ENUM_MEMBER, TSEnumMember) \
_(TS_EXTERNAL_MODULE_REFERENCE, TSExternalModuleReference) \
_(TS_PRIVATE_IDENTIFIER, TSPrivateIdentifier) \
_(TS_NUMBER_KEYWORD, TSNumberKeyword) \
_(TS_ANY_KEYWORD, TSAnyKeyword) \
_(TS_STRING_KEYWORD, TSStringKeyword) \
_(TS_BOOLEAN_KEYWORD, TSBooleanKeyword) \
_(TS_VOID_KEYWORD, TSVoidKeyword) \
_(TS_UNDEFINED_KEYWORD, TSUndefinedKeyword) \
_(TS_UNKNOWN_KEYWORD, TSUnknownKeyword) \
_(TS_OBJECT_KEYWORD, TSObjectKeyword) \
_(TS_BIGINT_KEYWORD, TSBigintKeyword) \
_(TS_NEVER_KEYWORD, TSNeverKeyword) \
_(TS_NON_NULL_EXPRESSION, TSNonNullExpression) \
_(TS_NULL_KEYWORD, TSNullKeyword) \
_(TS_ARRAY_TYPE, TSArrayType) \
_(TS_UNION_TYPE, TSUnionType) \
_(TS_TYPE_LITERAL, TSTypeLiteral) \
_(TS_PROPERTY_SIGNATURE, TSPropertySignature) \
_(TS_METHOD_SIGNATURE, TSMethodSignature) \
_(TS_SIGNATURE_DECLARATION, TSSignatureDeclaration) \
_(TS_PARENT_TYPE, TSParenthesizedType) \
_(TS_LITERAL_TYPE, TSLiteralType) \
_(TS_INFER_TYPE, TSInferType) \
_(TS_CONDITIONAL_TYPE, TSConditionalType) \
_(TS_IMPORT_TYPE, TSImportType) \
_(TS_INTERSECTION_TYPE, TSIntersectionType) \
_(TS_MAPPED_TYPE, TSMappedType) \
_(TS_MODULE_BLOCK, TSModuleBlock) \
_(TS_THIS_TYPE, TSThisType) \
_(TS_TYPE_OPERATOR, TSTypeOperator) \
_(TS_TYPE_PARAMETER, TSTypeParameter) \
_(TS_TYPE_PARAMETER_DECLARATION, TSTypeParameterDeclaration) \
_(TS_TYPE_PARAMETER_INSTANTIATION, TSTypeParameterInstantiation) \
_(TS_TYPE_PREDICATE, TSTypePredicate) \
_(TS_PARAMETER_PROPERTY, TSParameterProperty) \
_(TS_MODULE_DECLARATION, TSModuleDeclaration) \
_(TS_IMPORT_EQUALS_DECLARATION, TSImportEqualsDeclaration) \
_(TS_FUNCTION_TYPE, TSFunctionType) \
_(TS_CONSTRUCTOR_TYPE, TSConstructorType) \
_(TS_TYPE_ALIAS_DECLARATION, TSTypeAliasDeclaration) \
_(TS_TYPE_REFERENCE, TSTypeReference) \
_(TS_QUALIFIED_NAME, TSQualifiedName) \
_(TS_INDEXED_ACCESS_TYPE, TSIndexedAccessType) \
_(TS_INTERFACE_DECLARATION, TSInterfaceDeclaration) \
_(TS_INTERFACE_BODY, TSInterfaceBody) \
_(TS_INTERFACE_HERITAGE, TSInterfaceHeritage) \
_(TS_TUPLE_TYPE, TSTupleType) \
_(TS_NAMED_TUPLE_MEMBER, TSNamedTupleMember) \
_(TS_INDEX_SIGNATURE, TSIndexSignature) \
_(TS_TYPE_QUERY, TSTypeQuery) \
_(TS_AS_EXPRESSION, TSAsExpression) \
_(TS_TYPE_ASSERTION, TSTypeAssertion) \
_(TAGGED_TEMPLATE_EXPRESSION, TaggedTemplateExpression) \
_(TAGGED_LITERAL, TaggedLiteral) \
_(TEMPLATE_ELEMENT, TemplateElement) \
_(TEMPLATE_LITERAL, TemplateLiteral) \
_(THIS_EXPRESSION, ThisExpression) \
_(THROW_STATEMENT, ThrowStatement) \
_(TRY_STATEMENT, TryStatement) \
_(UNARY_EXPRESSION, UnaryExpression) \
_(UPDATE_EXPRESSION, UpdateExpression) \
_(VARIABLE_DECLARATION, VariableDeclaration) \
_(VARIABLE_DECLARATOR, VariableDeclarator) \
_(WHILE_STATEMENT, WhileStatement) \
_(WITH_STATEMENT, WithStatement) \
_(YIELD_EXPRESSION, YieldExpression)
#define AST_NODE_REINTERPRET_MAPPING(_) \
_(ARRAY_EXPRESSION, ARRAY_PATTERN, ArrayExpression, ArrayPattern) \
_(ASSIGNMENT_EXPRESSION, ASSIGNMENT_PATTERN, AssignmentExpression, AssignmentPattern) \
_(OBJECT_EXPRESSION, OBJECT_PATTERN, ObjectExpression, ObjectPattern) \
_(SPREAD_ELEMENT, REST_ELEMENT, SpreadElement, RestElement)
#endif
+86
View File
@@ -0,0 +1,86 @@
/**
* Copyright (c) 2021 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 "catchClause.h"
#include <binder/scope.h>
#include <compiler/core/pandagen.h>
#include <compiler/base/lreference.h>
#include <typescript/checker.h>
#include <typescript/types/type.h>
#include <ir/astDump.h>
#include <ir/expression.h>
#include <ir/expressions/arrayExpression.h>
#include <ir/expressions/identifier.h>
#include <ir/expressions/objectExpression.h>
#include <ir/statements/blockStatement.h>
namespace panda::es2panda::ir {
void CatchClause::Iterate(const NodeTraverser &cb) const
{
if (param_) {
cb(param_);
}
cb(body_);
}
void CatchClause::Dump(ir::AstDumper *dumper) const
{
dumper->Add({{"type", "CatchClause"}, {"body", body_}, {"param", AstDumper::Nullable(param_)}});
}
void CatchClause::Compile([[maybe_unused]] compiler::PandaGen *pg) const
{
compiler::LocalRegScope lrs(pg, scope_->ParamScope());
if (param_) {
auto lref = compiler::LReference::CreateLRef(pg, param_, true);
lref.SetValue();
}
ASSERT(scope_ == body_->Scope());
body_->Compile(pg);
}
checker::Type *CatchClause::Check([[maybe_unused]] checker::Checker *checker) const
{
const ir::Expression *typeAnnotation = nullptr;
if (param_->IsIdentifier()) {
typeAnnotation = param_->AsIdentifier()->TypeAnnotation();
} else if (param_->IsArrayPattern()) {
typeAnnotation = param_->AsArrayPattern()->TypeAnnotation();
} else {
ASSERT(param_->IsObjectPattern());
typeAnnotation = param_->AsObjectPattern()->TypeAnnotation();
}
if (typeAnnotation) {
checker::Type *catchParamType = typeAnnotation->Check(checker);
if (!catchParamType->HasTypeFlag(checker::TypeFlag::ANY_OR_UNKNOWN)) {
checker->ThrowTypeError("Catch clause variable type annotation must be 'any' or 'unknown' if specified",
Start());
}
}
body_->Check(checker);
return nullptr;
}
} // namespace panda::es2panda::ir
+84
View File
@@ -0,0 +1,84 @@
/**
* Copyright (c) 2021 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.
*/
#ifndef ES2PANDA_IR_BASE_CATCH_CLAUSE_H
#define ES2PANDA_IR_BASE_CATCH_CLAUSE_H
#include <ir/statement.h>
namespace panda::es2panda::compiler {
class PandaGen;
} // namespace panda::es2panda::compiler
namespace panda::es2panda::checker {
class Checker;
class Type;
} // namespace panda::es2panda::checker
namespace panda::es2panda::binder {
class CatchScope;
} // namespace panda::es2panda::binder
namespace panda::es2panda::ir {
class BlockStatement;
class Expression;
class CatchClause : public Statement {
public:
explicit CatchClause(binder::CatchScope *scope, Expression *param, BlockStatement *body)
: Statement(AstNodeType::CATCH_CLAUSE), scope_(scope), param_(param), body_(body)
{
}
Expression *Param()
{
return param_;
}
const Expression *Param() const
{
return param_;
}
BlockStatement *Body()
{
return body_;
}
const BlockStatement *Body() const
{
return body_;
}
binder::CatchScope *Scope() const
{
return scope_;
}
void Iterate(const NodeTraverser &cb) const override;
void Dump(ir::AstDumper *dumper) const override;
void Compile([[maybe_unused]] compiler::PandaGen *pg) const override;
checker::Type *Check([[maybe_unused]] checker::Checker *checker) const override;
protected:
binder::CatchScope *scope_;
Expression *param_;
BlockStatement *body_;
};
} // namespace panda::es2panda::ir
#endif
+287
View File
@@ -0,0 +1,287 @@
/**
* Copyright (c) 2021 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 "classDefinition.h"
#include <util/helpers.h>
#include <binder/scope.h>
#include <compiler/base/literals.h>
#include <compiler/base/lreference.h>
#include <compiler/core/pandagen.h>
#include <typescript/checker.h>
#include <ir/astDump.h>
#include <ir/base/methodDefinition.h>
#include <ir/base/scriptFunction.h>
#include <ir/expression.h>
#include <ir/expressions/functionExpression.h>
#include <ir/expressions/identifier.h>
#include <ir/expressions/literals/nullLiteral.h>
#include <ir/expressions/literals/numberLiteral.h>
#include <ir/expressions/literals/stringLiteral.h>
#include <ir/expressions/literals/taggedLiteral.h>
#include <ir/ts/tsClassImplements.h>
#include <ir/ts/tsIndexSignature.h>
#include <ir/ts/tsTypeParameter.h>
#include <ir/ts/tsTypeParameterDeclaration.h>
#include <ir/ts/tsTypeParameterInstantiation.h>
namespace panda::es2panda::ir {
const FunctionExpression *ClassDefinition::Ctor() const
{
ASSERT(ctor_ != nullptr);
return ctor_->Value();
}
void ClassDefinition::Iterate(const NodeTraverser &cb) const
{
if (ident_) {
cb(ident_);
}
if (typeParams_) {
cb(typeParams_);
}
if (superClass_) {
cb(superClass_);
}
if (superTypeParams_) {
cb(superTypeParams_);
}
for (auto *it : implements_) {
cb(it);
}
cb(ctor_);
for (auto *it : body_) {
cb(it);
}
for (auto *it : indexSignatures_) {
cb(it);
}
}
void ClassDefinition::Dump(ir::AstDumper *dumper) const
{
dumper->Add({{"id", AstDumper::Nullable(ident_)},
{"typeParameters", AstDumper::Optional(typeParams_)},
{"superClass", AstDumper::Nullable(superClass_)},
{"superTypeParameters", AstDumper::Optional(superTypeParams_)},
{"implements", implements_},
{"constructor", ctor_},
{"body", body_},
{"indexSignatures", indexSignatures_}});
}
compiler::VReg ClassDefinition::CompileHeritageClause(compiler::PandaGen *pg) const
{
compiler::VReg baseReg = pg->AllocReg();
if (superClass_) {
superClass_->Compile(pg);
} else {
pg->LoadConst(this, compiler::Constant::JS_HOLE);
}
pg->StoreAccumulator(this, baseReg);
return baseReg;
}
void ClassDefinition::InitializeClassName(compiler::PandaGen *pg) const
{
if (!ident_) {
return;
}
compiler::LReference lref = compiler::LReference::CreateLRef(pg, ident_, true);
lref.SetValue();
}
// NOLINTNEXTLINE(google-runtime-references)
int32_t ClassDefinition::CreateClassStaticProperties(compiler::PandaGen *pg, util::BitSet &compiled) const
{
auto *buf = pg->NewLiteralBuffer();
compiler::LiteralBuffer staticBuf(pg->Allocator());
bool seenComputed = false;
std::unordered_map<util::StringView, size_t> propNameMap;
std::unordered_map<util::StringView, size_t> staticPropNameMap;
const auto &properties = body_;
for (size_t i = 0; i < properties.size(); i++) {
if (!properties[i]->IsMethodDefinition()) {
continue;
}
const ir::MethodDefinition *prop = properties[i]->AsMethodDefinition();
if (!util::Helpers::IsConstantPropertyKey(prop->Key(), prop->Computed()) ||
(prop->Computed() && util::Helpers::IsSpecialPropertyKey(prop->Key()))) {
seenComputed = true;
continue;
}
util::StringView name = util::Helpers::LiteralToPropName(prop->Key());
compiler::LiteralBuffer *literalBuf = prop->IsStatic() ? &staticBuf : buf;
auto &nameMap = prop->IsStatic() ? staticPropNameMap : propNameMap;
size_t bufferPos = literalBuf->Literals().size();
auto res = nameMap.insert({name, bufferPos});
if (res.second) {
if (seenComputed) {
break;
}
literalBuf->Add(pg->Allocator()->New<StringLiteral>(name));
literalBuf->Add(nullptr);
} else {
bufferPos = res.first->second;
}
Literal *value = nullptr;
switch (prop->Kind()) {
case ir::MethodDefinitionKind::METHOD: {
const ir::FunctionExpression *func = prop->Value()->AsFunctionExpression();
const util::StringView &internalName = func->Function()->Scope()->InternalName();
value = pg->Allocator()->New<TaggedLiteral>(LiteralTag::METHOD, internalName);
compiled.Set(i);
break;
}
case ir::MethodDefinitionKind::GET:
case ir::MethodDefinitionKind::SET: {
value = pg->Allocator()->New<NullLiteral>();
break;
}
default: {
UNREACHABLE();
}
}
literalBuf->ResetLiteral(bufferPos + 1, value);
}
uint32_t litPairs = buf->Size() / 2;
/* Static items are stored at the end of the buffer */
buf->Insert(&staticBuf);
/* The last literal item represents the offset of the first static property. The regular property literal count
* is divided by 2 as key/value pairs count as one. */
buf->Add(pg->Allocator()->New<NumberLiteral>(litPairs));
return pg->AddLiteralBuffer(buf);
}
void ClassDefinition::CompileMissingProperties(compiler::PandaGen *pg, const util::BitSet &compiled,
compiler::VReg classReg) const
{
const auto &properties = body_;
compiler::VReg protoReg = pg->AllocReg();
pg->LoadObjByName(this, classReg, "prototype");
pg->StoreAccumulator(this, protoReg);
for (size_t i = 0; i < properties.size(); i++) {
if (!properties[i]->IsMethodDefinition() || compiled.Test(i)) {
continue;
}
const ir::MethodDefinition *prop = properties[i]->AsMethodDefinition();
compiler::VReg dest = prop->IsStatic() ? classReg : protoReg;
compiler::RegScope rs(pg);
switch (prop->Kind()) {
case ir::MethodDefinitionKind::METHOD: {
compiler::Operand key = pg->ToPropertyKey(prop->Key(), prop->Computed());
pg->LoadAccumulator(this, dest);
const ir::FunctionExpression *func = prop->Value()->AsFunctionExpression();
func->Compile(pg);
pg->StoreOwnProperty(prop->Value()->Parent(), dest, key);
break;
}
case ir::MethodDefinitionKind::GET:
case ir::MethodDefinitionKind::SET: {
compiler::VReg keyReg = pg->LoadPropertyKey(prop->Key(), prop->Computed());
compiler::VReg undef = pg->AllocReg();
pg->LoadConst(this, compiler::Constant::JS_UNDEFINED);
pg->StoreAccumulator(this, undef);
compiler::VReg getter = undef;
compiler::VReg setter = undef;
pg->LoadAccumulator(this, dest);
compiler::VReg accessor = pg->AllocReg();
prop->Value()->Compile(pg);
pg->StoreAccumulator(prop->Value(), accessor);
if (prop->Kind() == ir::MethodDefinitionKind::GET) {
getter = accessor;
} else {
setter = accessor;
}
pg->DefineGetterSetterByValue(this, dest, keyReg, getter, setter, prop->Computed());
break;
}
default: {
UNREACHABLE();
}
}
}
pg->LoadAccumulator(this, classReg);
}
void ClassDefinition::Compile(compiler::PandaGen *pg) const
{
compiler::RegScope rs(pg);
compiler::VReg classReg = pg->AllocReg();
compiler::VReg lexenv = pg->LexEnv();
compiler::LocalRegScope lrs(pg, scope_);
compiler::VReg baseReg = CompileHeritageClause(pg);
util::StringView ctorId = ctor_->Function()->Scope()->InternalName();
util::BitSet compiled(body_.size());
int32_t bufIdx = CreateClassStaticProperties(pg, compiled);
pg->DefineClassWithBuffer(this, ctorId, bufIdx, lexenv, baseReg);
if (scope_->Parent()->IsGlobalScope() && ident_) {
pg->StoreGlobalLet(this, ident_->Name());
}
pg->StoreAccumulator(this, classReg);
InitializeClassName(pg);
CompileMissingProperties(pg, compiled, classReg);
}
checker::Type *ClassDefinition::Check([[maybe_unused]] checker::Checker *checker) const
{
// TODO(aszilagyi)
return checker->GlobalAnyType();
}
} // namespace panda::es2panda::ir
+142
View File
@@ -0,0 +1,142 @@
/**
* Copyright (c) 2021 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.
*/
#ifndef ES2PANDA_PARSER_INCLUDE_AST_CLASS_DEFINITION_H
#define ES2PANDA_PARSER_INCLUDE_AST_CLASS_DEFINITION_H
#include <ir/astNode.h>
#include <binder/variable.h>
#include <util/bitset.h>
namespace panda::es2panda::compiler {
class PandaGen;
} // namespace panda::es2panda::compiler
namespace panda::es2panda::checker {
class Checker;
class Type;
} // namespace panda::es2panda::checker
namespace panda::es2panda::binder {
class LocalScope;
} // namespace panda::es2panda::binder
namespace panda::es2panda::ir {
class Statement;
class Identifier;
class MethodDefinition;
class TSTypeParameterDeclaration;
class TSTypeParameterInstantiation;
class TSClassImplements;
class TSIndexSignature;
class ClassDefinition : public AstNode {
public:
explicit ClassDefinition(binder::LocalScope *scope, Identifier *ident, TSTypeParameterDeclaration *typeParams,
TSTypeParameterInstantiation *superTypeParams,
ArenaVector<TSClassImplements *> &&implements, MethodDefinition *ctor,
Expression *superClass, ArenaVector<Statement *> &&body,
ArenaVector<TSIndexSignature *> &&indexSignatures, bool declare, bool abstract)
: AstNode(AstNodeType::CLASS_DEFINITION),
scope_(scope),
ident_(ident),
typeParams_(typeParams),
superTypeParams_(superTypeParams),
implements_(std::move(implements)),
ctor_(ctor),
superClass_(superClass),
body_(std::move(body)),
indexSignatures_(std::move(indexSignatures)),
declare_(declare),
abstract_(abstract)
{
}
binder::LocalScope *Scope() const
{
return scope_;
}
const Identifier *Ident() const
{
return ident_;
}
Expression *Super()
{
return superClass_;
}
const Expression *Super() const
{
return superClass_;
}
bool Declare() const
{
return declare_;
}
bool Abstract() const
{
return abstract_;
}
ArenaVector<Statement *> &Body()
{
return body_;
}
const ArenaVector<Statement *> &Body() const
{
return body_;
}
MethodDefinition *Ctor()
{
ASSERT(ctor_ != nullptr);
return ctor_;
}
const FunctionExpression *Ctor() const;
void Iterate(const NodeTraverser &cb) const override;
void Dump(ir::AstDumper *dumper) const override;
void Compile([[maybe_unused]] compiler::PandaGen *pg) const override;
checker::Type *Check([[maybe_unused]] checker::Checker *checker) const override;
private:
compiler::VReg CompileHeritageClause(compiler::PandaGen *pg) const;
void InitializeClassName(compiler::PandaGen *pg) const;
int32_t CreateClassStaticProperties(compiler::PandaGen *pg, util::BitSet &compiled) const;
void CompileMissingProperties(compiler::PandaGen *pg, const util::BitSet &compiled, compiler::VReg classReg) const;
binder::LocalScope *scope_;
Identifier *ident_;
TSTypeParameterDeclaration *typeParams_;
TSTypeParameterInstantiation *superTypeParams_;
ArenaVector<TSClassImplements *> implements_;
MethodDefinition *ctor_;
Expression *superClass_;
ArenaVector<Statement *> body_;
ArenaVector<TSIndexSignature *> indexSignatures_;
bool declare_;
bool abstract_;
};
} // namespace panda::es2panda::ir
#endif
+68
View File
@@ -0,0 +1,68 @@
/**
* Copyright (c) 2021 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 "classProperty.h"
#include <ir/astDump.h>
#include <ir/base/decorator.h>
#include <ir/expression.h>
#include <cstdint>
#include <string>
namespace panda::es2panda::ir {
void ClassProperty::Iterate(const NodeTraverser &cb) const
{
cb(key_);
if (value_) {
cb(value_);
}
if (typeAnnotation_) {
cb(typeAnnotation_);
}
for (auto *it : decorators_) {
cb(it);
}
}
void ClassProperty::Dump(ir::AstDumper *dumper) const
{
dumper->Add({{"type", "ClassProperty"},
{"key", key_},
{"value", AstDumper::Optional(value_)},
{"accessibility", AstDumper::Optional(AstDumper::ModifierToString(modifiers_))},
{"abstract", AstDumper::Optional((modifiers_ & ModifierFlags::ABSTRACT) != 0)},
{"static", (modifiers_ & ModifierFlags::STATIC) != 0},
{"readonly", (modifiers_ & ModifierFlags::READONLY) != 0},
{"declare", (modifiers_ & ModifierFlags::DECLARE) != 0},
{"optional", (modifiers_ & ModifierFlags::OPTIONAL) != 0},
{"computed", isComputed_},
{"typeAnnotation", AstDumper::Optional(typeAnnotation_)},
{"definite", AstDumper::Optional(definite_)},
{"decorators", decorators_}});
}
void ClassProperty::Compile([[maybe_unused]] compiler::PandaGen *pg) const {}
checker::Type *ClassProperty::Check([[maybe_unused]] checker::Checker *checker) const
{
return nullptr;
}
} // namespace panda::es2panda::ir
+101
View File
@@ -0,0 +1,101 @@
/**
* Copyright (c) 2021 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.
*/
#ifndef ES2PANDA_PARSER_INCLUDE_AST_CLASS_PROPERTY_H
#define ES2PANDA_PARSER_INCLUDE_AST_CLASS_PROPERTY_H
#include <ir/statement.h>
namespace panda::es2panda::compiler {
class PandaGen;
} // namespace panda::es2panda::compiler
namespace panda::es2panda::checker {
class Checker;
class Type;
} // namespace panda::es2panda::checker
namespace panda::es2panda::ir {
class Expression;
class ClassProperty : public Statement {
public:
explicit ClassProperty(Expression *key, Expression *value, Expression *typeAnnotation, ModifierFlags modifiers,
ArenaVector<Decorator *> &&decorators, bool isComputed, bool definite)
: Statement(AstNodeType::CLASS_PROPERTY),
key_(key),
value_(value),
typeAnnotation_(typeAnnotation),
modifiers_(modifiers),
decorators_(std::move(decorators)),
isComputed_(isComputed),
definite_(definite)
{
}
const Expression *Key() const
{
return key_;
}
const Expression *Value() const
{
return value_;
}
const Expression *TypeAnnotation() const
{
return typeAnnotation_;
}
ModifierFlags Modifiers() const
{
return modifiers_;
}
const ArenaVector<Decorator *> &Decorators() const
{
return decorators_;
}
bool IsComputed() const
{
return isComputed_;
}
bool Definite() const
{
return definite_;
}
void Iterate(const NodeTraverser &cb) const override;
void Dump(ir::AstDumper *dumper) const override;
void Compile([[maybe_unused]] compiler::PandaGen *pg) const override;
checker::Type *Check([[maybe_unused]] checker::Checker *checker) const override;
private:
Expression *key_;
Expression *value_;
Expression *typeAnnotation_;
ModifierFlags modifiers_;
ArenaVector<Decorator *> decorators_;
bool isComputed_;
bool definite_;
};
} // namespace panda::es2panda::ir
#endif
+40
View File
@@ -0,0 +1,40 @@
/**
* 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 "decorator.h"
#include <ir/expression.h>
#include <ir/astDump.h>
namespace panda::es2panda::ir {
void Decorator::Iterate(const NodeTraverser &cb) const
{
cb(expr_);
}
void Decorator::Dump(ir::AstDumper *dumper) const
{
dumper->Add({{"type", "Decorator"}, {"expression", expr_}});
}
void Decorator::Compile([[maybe_unused]] compiler::PandaGen *pg) const {}
checker::Type *Decorator::Check([[maybe_unused]] checker::Checker *checker) const
{
return nullptr;
}
} // namespace panda::es2panda::ir
+53
View File
@@ -0,0 +1,53 @@
/**
* Copyright (c) 2021 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.
*/
#ifndef ES2PANDA_PARSER_INCLUDE_AST_DECORATOR_H
#define ES2PANDA_PARSER_INCLUDE_AST_DECORATOR_H
#include <ir/statement.h>
namespace panda::es2panda::compiler {
class PandaGen;
} // namespace panda::es2panda::compiler
namespace panda::es2panda::checker {
class Checker;
class Type;
} // namespace panda::es2panda::checker
namespace panda::es2panda::ir {
class Expression;
class Decorator : public Statement {
public:
explicit Decorator(Expression *expr) : Statement(AstNodeType::DECORATOR), expr_(expr) {}
const Expression *Expr() const
{
return expr_;
}
void Iterate(const NodeTraverser &cb) const override;
void Dump(ir::AstDumper *dumper) const override;
void Compile([[maybe_unused]] compiler::PandaGen *pg) const override;
checker::Type *Check([[maybe_unused]] checker::Checker *checker) const override;
private:
Expression *expr_;
};
} // namespace panda::es2panda::ir
#endif
+66
View File
@@ -0,0 +1,66 @@
/**
* Copyright (c) 2021 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 "metaProperty.h"
#include <compiler/core/pandagen.h>
#include <typescript/checker.h>
#include <ir/astDump.h>
namespace panda::es2panda::ir {
void MetaProperty::Iterate([[maybe_unused]] const NodeTraverser &cb) const {}
void MetaProperty::Dump(ir::AstDumper *dumper) const
{
const char *kind = nullptr;
switch (kind_) {
case MetaPropertyKind::NEW_TARGET: {
kind = "new.Target";
break;
}
case MetaPropertyKind::IMPORT_META: {
kind = "import.Meta";
break;
}
default: {
UNREACHABLE();
}
}
dumper->Add({{"type", "MetaProperty"}, {"kind", kind}});
}
void MetaProperty::Compile([[maybe_unused]] compiler::PandaGen *pg) const
{
if (kind_ == ir::MetaProperty::MetaPropertyKind::NEW_TARGET) {
pg->GetNewTarget(this);
return;
}
if (kind_ == ir::MetaProperty::MetaPropertyKind::IMPORT_META) {
// TODO()
pg->Unimplemented();
}
}
checker::Type *MetaProperty::Check([[maybe_unused]] checker::Checker *checker) const
{
// TODO(aszilagyi)
return checker->GlobalAnyType();
}
} // namespace panda::es2panda::ir
+54
View File
@@ -0,0 +1,54 @@
/**
* 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.
*/
#ifndef ES2PANDA_PARSER_INCLUDE_AST_META_PROPERTY_H
#define ES2PANDA_PARSER_INCLUDE_AST_META_PROPERTY_H
#include <ir/expression.h>
namespace panda::es2panda::compiler {
class PandaGen;
} // namespace panda::es2panda::compiler
namespace panda::es2panda::checker {
class Checker;
class Type;
} // namespace panda::es2panda::checker
namespace panda::es2panda::ir {
class MetaProperty : public Expression {
public:
enum class MetaPropertyKind { NEW_TARGET, IMPORT_META };
explicit MetaProperty(MetaPropertyKind kind) : Expression(AstNodeType::META_PROPERTY_EXPRESSION), kind_(kind) {}
MetaPropertyKind Kind() const
{
return kind_;
}
void Iterate(const NodeTraverser &cb) const override;
void Dump(ir::AstDumper *dumper) const override;
void Compile([[maybe_unused]] compiler::PandaGen *pg) const override;
checker::Type *Check([[maybe_unused]] checker::Checker *checker) const override;
private:
MetaPropertyKind kind_;
};
} // namespace panda::es2panda::ir
#endif
+92
View File
@@ -0,0 +1,92 @@
/**
* Copyright (c) 2021 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 "methodDefinition.h"
#include <ir/astDump.h>
#include <ir/base/decorator.h>
#include <ir/base/scriptFunction.h>
#include <ir/expression.h>
#include <ir/expressions/functionExpression.h>
#include <utility>
namespace panda::es2panda::ir {
const ScriptFunction *MethodDefinition::Function() const
{
return value_->Function();
}
void MethodDefinition::Iterate(const NodeTraverser &cb) const
{
cb(key_);
cb(value_);
for (auto *it : overloads_) {
cb(it);
}
for (auto *it : decorators_) {
cb(it);
}
}
void MethodDefinition::Dump(ir::AstDumper *dumper) const
{
const char *kind = nullptr;
switch (kind_) {
case MethodDefinitionKind::CONSTRUCTOR: {
kind = "constructor";
break;
}
case MethodDefinitionKind::METHOD: {
kind = "method";
break;
}
case MethodDefinitionKind::GET: {
kind = "get";
break;
}
case MethodDefinitionKind::SET: {
kind = "set";
break;
}
default: {
UNREACHABLE();
}
}
dumper->Add({{"type", "MethodDefinition"},
{"key", key_},
{"kind", kind},
{"accessibility", AstDumper::Optional(AstDumper::ModifierToString(modifiers_))},
{"static", (modifiers_ & ModifierFlags::STATIC) != 0},
{"optional", (modifiers_ & ModifierFlags::OPTIONAL) != 0},
{"computed", isComputed_},
{"value", value_},
{"overloads", overloads_},
{"decorators", decorators_}});
}
void MethodDefinition::Compile([[maybe_unused]] compiler::PandaGen *pg) const {}
checker::Type *MethodDefinition::Check([[maybe_unused]] checker::Checker *checker) const
{
return nullptr;
}
} // namespace panda::es2panda::ir
+127
View File
@@ -0,0 +1,127 @@
/**
* Copyright (c) 2021 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.
*/
#ifndef ES2PANDA_PARSER_INCLUDE_AST_METHOD_DEFINITION_H
#define ES2PANDA_PARSER_INCLUDE_AST_METHOD_DEFINITION_H
#include <ir/statement.h>
namespace panda::es2panda::compiler {
class PandaGen;
} // namespace panda::es2panda::compiler
namespace panda::es2panda::checker {
class Checker;
class Type;
} // namespace panda::es2panda::checker
namespace panda::es2panda::ir {
class Expression;
class FunctionExpression;
enum class MethodDefinitionKind { CONSTRUCTOR, METHOD, GET, SET };
class MethodDefinition : public Statement {
public:
explicit MethodDefinition(MethodDefinitionKind kind, Expression *key, FunctionExpression *value,
ModifierFlags modifiers, ArenaAllocator *allocator, ArenaVector<Decorator *> &&decorators,
bool isComputed)
: Statement(AstNodeType::METHOD_DEFINITION),
kind_(kind),
key_(key),
value_(value),
modifiers_(modifiers),
overloads_(allocator->Adapter()),
decorators_(std::move(decorators)),
isComputed_(isComputed)
{
}
MethodDefinitionKind Kind() const
{
return kind_;
}
ModifierFlags Modifiers() const
{
return modifiers_;
}
const Expression *Key() const
{
return key_;
}
const FunctionExpression *Value() const
{
return value_;
}
bool Computed() const
{
return isComputed_;
}
bool IsStatic() const
{
return (modifiers_ & ModifierFlags::STATIC) != 0;
}
bool IsOptional() const
{
return (modifiers_ & ModifierFlags::OPTIONAL) != 0;
}
const ArenaVector<MethodDefinition *> &Overloads() const
{
return overloads_;
}
const ArenaVector<Decorator *> &Decorators() const
{
return decorators_;
}
void SetOverloads(ArenaVector<MethodDefinition *> &&overloads)
{
overloads_ = std::move(overloads);
}
void AddOverload(MethodDefinition *overload)
{
overloads_.push_back(overload);
}
const ScriptFunction *Function() const;
void Iterate(const NodeTraverser &cb) const override;
void Dump(ir::AstDumper *dumper) const override;
void Compile([[maybe_unused]] compiler::PandaGen *pg) const override;
checker::Type *Check([[maybe_unused]] checker::Checker *checker) const override;
private:
MethodDefinitionKind kind_;
Expression *key_;
FunctionExpression *value_;
ModifierFlags modifiers_;
ArenaVector<MethodDefinition *> overloads_;
ArenaVector<Decorator *> decorators_;
bool isComputed_;
};
} // namespace panda::es2panda::ir
#endif
+138
View File
@@ -0,0 +1,138 @@
/**
* Copyright (c) 2021 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 "property.h"
#include <ir/astDump.h>
#include <ir/expression.h>
#include <ir/expressions/arrayExpression.h>
#include <ir/expressions/assignmentExpression.h>
#include <ir/expressions/objectExpression.h>
#include <ir/expressions/identifier.h>
#include <ir/expressions/literals/stringLiteral.h>
#include <ir/validationInfo.h>
namespace panda::es2panda::ir {
bool Property::ConventibleToPatternProperty()
{
// Object pattern can't contain getter or setter
if (IsAccessor() || isMethod_) {
return false;
}
switch (value_->Type()) {
case AstNodeType::OBJECT_EXPRESSION: {
return value_->AsObjectExpression()->ConvertibleToObjectPattern();
}
case AstNodeType::ARRAY_EXPRESSION: {
return value_->AsArrayExpression()->ConvertibleToArrayPattern();
}
case AstNodeType::ASSIGNMENT_EXPRESSION: {
return value_->AsAssignmentExpression()->ConvertibleToAssignmentPattern();
}
case AstNodeType::META_PROPERTY_EXPRESSION: {
return false;
}
default: {
break;
}
}
return true;
}
ValidationInfo Property::ValidateExpression()
{
ValidationInfo info;
if (!IsComputed() && !IsMethod() && !IsAccessor() && !IsShorthand()) {
bool currentIsProto = false;
if (key_->IsIdentifier()) {
currentIsProto = key_->AsIdentifier()->Name().Is("__proto__");
} else if (key_->IsStringLiteral()) {
currentIsProto = key_->AsStringLiteral()->Str().Is("__proto__");
}
if (currentIsProto) {
kind_ = PropertyKind::PROTO;
}
}
if (value_) {
if (value_->IsAssignmentPattern()) {
return {"Invalid shorthand property initializer.", value_->Start()};
}
if (value_->IsObjectExpression()) {
info = value_->AsObjectExpression()->ValidateExpression();
} else if (value_->IsArrayExpression()) {
info = value_->AsArrayExpression()->ValidateExpression();
}
}
return info;
}
void Property::Iterate(const NodeTraverser &cb) const
{
cb(key_);
cb(value_);
}
void Property::Dump(ir::AstDumper *dumper) const
{
const char *kind = nullptr;
switch (kind_) {
case PropertyKind::INIT: {
kind = "init";
break;
}
case PropertyKind::PROTO: {
kind = "proto";
break;
}
case PropertyKind::GET: {
kind = "get";
break;
}
case PropertyKind::SET: {
kind = "set";
break;
}
default: {
UNREACHABLE();
}
}
dumper->Add({{"type", "Property"},
{"method", isMethod_},
{"shorthand", isShorthand_},
{"computed", isComputed_},
{"key", key_},
{"value", value_},
{"kind", kind}});
}
void Property::Compile([[maybe_unused]] compiler::PandaGen *pg) const {}
checker::Type *Property::Check([[maybe_unused]] checker::Checker *checker) const
{
return nullptr;
}
} // namespace panda::es2panda::ir
+127
View File
@@ -0,0 +1,127 @@
/**
* Copyright (c) 2021 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.
*/
#ifndef ES2PANDA_PARSER_INCLUDE_AST_PROPERTY_H
#define ES2PANDA_PARSER_INCLUDE_AST_PROPERTY_H
#include <ir/expression.h>
#include <ir/validationInfo.h>
namespace panda::es2panda::compiler {
class PandaGen;
} // namespace panda::es2panda::compiler
namespace panda::es2panda::checker {
class Checker;
class Type;
} // namespace panda::es2panda::checker
namespace panda::es2panda::ir {
enum class PropertyKind { INIT, GET, SET, PROTO };
class Property : public Expression {
public:
explicit Property(Expression *key, Expression *value)
: Expression(AstNodeType::PROPERTY),
kind_(PropertyKind::INIT),
key_(key),
value_(value),
isMethod_(false),
isShorthand_(true),
isComputed_(false)
{
}
explicit Property(PropertyKind kind, Expression *key, Expression *value, bool isMethod, bool isComputed)
: Expression(AstNodeType::PROPERTY),
kind_(kind),
key_(key),
value_(value),
isMethod_(isMethod),
isShorthand_(false),
isComputed_(isComputed)
{
}
Expression *Key()
{
return key_;
}
const Expression *Key() const
{
return key_;
}
const Expression *Value() const
{
return value_;
}
Expression *Value()
{
return value_;
}
PropertyKind Kind() const
{
return kind_;
}
bool IsMethod() const
{
return isMethod_;
}
bool IsShorthand() const
{
return isShorthand_;
}
bool IsComputed() const
{
return isComputed_;
}
bool IsAccessor() const
{
return IsAccessorKind(kind_);
}
static bool IsAccessorKind(PropertyKind kind)
{
return kind == PropertyKind::GET || kind == PropertyKind::SET;
}
bool ConventibleToPatternProperty();
ValidationInfo ValidateExpression();
void Iterate(const NodeTraverser &cb) const override;
void Dump(ir::AstDumper *dumper) const override;
void Compile([[maybe_unused]] compiler::PandaGen *pg) const override;
checker::Type *Check([[maybe_unused]] checker::Checker *checker) const override;
private:
PropertyKind kind_;
Expression *key_;
Expression *value_;
bool isMethod_;
bool isShorthand_;
bool isComputed_;
};
} // namespace panda::es2panda::ir
#endif
+83
View File
@@ -0,0 +1,83 @@
/**
* Copyright (c) 2021 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 "scriptFunction.h"
#include <binder/scope.h>
#include <ir/astDump.h>
#include <ir/expression.h>
#include <ir/expressions/identifier.h>
#include <ir/statements/blockStatement.h>
#include <ir/ts/tsTypeParameter.h>
#include <ir/ts/tsTypeParameterDeclaration.h>
namespace panda::es2panda::ir {
size_t ScriptFunction::FormalParamsLength() const
{
size_t length = 0;
for (const auto *param : params_) {
if (param->IsRestElement() || param->IsAssignmentPattern()) {
break;
}
length++;
}
return length;
}
void ScriptFunction::Iterate(const NodeTraverser &cb) const
{
if (id_) {
cb(id_);
}
if (typeParams_) {
cb(typeParams_);
}
for (auto *it : params_) {
cb(it);
}
if (body_) {
cb(body_);
}
}
void ScriptFunction::Dump(ir::AstDumper *dumper) const
{
dumper->Add({{"type", "ScriptFunction"},
{"id", AstDumper::Nullable(id_)},
{"generator", IsGenerator()},
{"async", IsAsync()},
{"expression", ((flags_ & ir::ScriptFunctionFlags::EXPRESSION) != 0)},
{"params", params_},
{"returnType", AstDumper::Optional(returnTypeAnnotation_)},
{"typeParameters", AstDumper::Optional(typeParams_)},
{"declare", AstDumper::Optional(declare_)},
{"body", AstDumper::Optional(body_)}});
}
void ScriptFunction::Compile([[maybe_unused]] compiler::PandaGen *pg) const {}
checker::Type *ScriptFunction::Check([[maybe_unused]] checker::Checker *checker) const
{
return nullptr;
}
} // namespace panda::es2panda::ir
+166
View File
@@ -0,0 +1,166 @@
/**
* Copyright (c) 2021 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.
*/
#ifndef ES2PANDA_PARSER_INCLUDE_AST_SCRIPT_FUNCTION_H
#define ES2PANDA_PARSER_INCLUDE_AST_SCRIPT_FUNCTION_H
#include <ir/astNode.h>
#include <util/enumbitops.h>
namespace panda::es2panda::compiler {
class PandaGen;
} // namespace panda::es2panda::compiler
namespace panda::es2panda::checker {
class Checker;
class Type;
} // namespace panda::es2panda::checker
namespace panda::es2panda::binder {
class FunctionScope;
} // namespace panda::es2panda::binder
namespace panda::es2panda::ir {
class TSTypeParameterDeclaration;
class ScriptFunction : public AstNode {
public:
explicit ScriptFunction(binder::FunctionScope *scope, ArenaVector<Expression *> &&params,
TSTypeParameterDeclaration *typeParams, AstNode *body, Expression *returnTypeAnnotation,
ir::ScriptFunctionFlags flags, bool declare)
: AstNode(AstNodeType::SCRIPT_FUNCTION),
scope_(scope),
id_(nullptr),
params_(std::move(params)),
typeParams_(typeParams),
body_(body),
returnTypeAnnotation_(returnTypeAnnotation),
flags_(flags),
declare_(declare)
{
}
const Identifier *Id() const
{
return id_;
}
Identifier *Id()
{
return id_;
}
const ArenaVector<Expression *> &Params() const
{
return params_;
}
ArenaVector<Expression *> &Params()
{
return params_;
}
const TSTypeParameterDeclaration *TypeParams() const
{
return typeParams_;
}
const AstNode *Body() const
{
return body_;
}
AstNode *Body()
{
return body_;
}
const Expression *ReturnTypeAnnotation() const
{
return returnTypeAnnotation_;
}
bool IsGenerator() const
{
return (flags_ & ir::ScriptFunctionFlags::GENERATOR) != 0;
}
bool IsAsync() const
{
return (flags_ & ir::ScriptFunctionFlags::ASYNC) != 0;
}
bool IsArrow() const
{
return (flags_ & ir::ScriptFunctionFlags::ARROW) != 0;
}
bool IsOverload() const
{
return (flags_ & ir::ScriptFunctionFlags::OVERLOAD) != 0;
}
bool IsConstructor() const
{
return (flags_ & ir::ScriptFunctionFlags::CONSTRUCTOR) != 0;
}
bool IsMethod() const
{
return (flags_ & ir::ScriptFunctionFlags::METHOD) != 0;
}
bool Declare() const
{
return declare_;
}
void SetIdent(Identifier *id)
{
id_ = id;
}
void AddFlag(ir::ScriptFunctionFlags flags)
{
flags_ |= flags;
}
size_t FormalParamsLength() const;
binder::FunctionScope *Scope() const
{
return scope_;
}
void Iterate(const NodeTraverser &cb) const override;
void Dump(ir::AstDumper *dumper) const override;
void Compile([[maybe_unused]] compiler::PandaGen *pg) const override;
checker::Type *Check([[maybe_unused]] checker::Checker *checker) const override;
private:
binder::FunctionScope *scope_;
Identifier *id_;
ArenaVector<Expression *> params_;
TSTypeParameterDeclaration *typeParams_;
AstNode *body_;
Expression *returnTypeAnnotation_;
ir::ScriptFunctionFlags flags_;
bool declare_;
};
} // namespace panda::es2panda::ir
#endif
+105
View File
@@ -0,0 +1,105 @@
/**
* Copyright (c) 2021 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 "spreadElement.h"
#include <ir/astDump.h>
#include <ir/expressions/arrayExpression.h>
#include <ir/expressions/objectExpression.h>
namespace panda::es2panda::ir {
ValidationInfo SpreadElement::ValidateExpression()
{
ValidationInfo info;
switch (argument_->Type()) {
case AstNodeType::OBJECT_EXPRESSION: {
info = argument_->AsObjectExpression()->ValidateExpression();
break;
}
case AstNodeType::ARRAY_EXPRESSION: {
info = argument_->AsArrayExpression()->ValidateExpression();
break;
}
default: {
break;
}
}
return info;
}
bool SpreadElement::ConvertibleToRest(bool isDeclaration, bool allowPattern)
{
bool convResult = true;
switch (argument_->Type()) {
case AstNodeType::ARRAY_EXPRESSION: {
convResult = allowPattern && argument_->AsArrayExpression()->ConvertibleToArrayPattern();
break;
}
case AstNodeType::OBJECT_EXPRESSION: {
convResult = allowPattern && argument_->AsObjectExpression()->ConvertibleToObjectPattern();
break;
}
case AstNodeType::META_PROPERTY_EXPRESSION:
case AstNodeType::CHAIN_EXPRESSION:
case AstNodeType::ASSIGNMENT_EXPRESSION: {
convResult = false;
break;
}
case AstNodeType::MEMBER_EXPRESSION: {
convResult = !isDeclaration;
break;
}
default: {
break;
}
}
SetType(AstNodeType::REST_ELEMENT);
return convResult;
}
void SpreadElement::SetTsTypeAnnotation(Expression *typeAnnotation)
{
typeAnnotation_ = typeAnnotation;
}
void SpreadElement::Iterate(const NodeTraverser &cb) const
{
cb(argument_);
if (typeAnnotation_) {
cb(typeAnnotation_);
}
}
void SpreadElement::Dump(ir::AstDumper *dumper) const
{
dumper->Add({{"type", (type_ == AstNodeType::SPREAD_ELEMENT) ? "SpreadElement" : "RestElement"},
{"argument", argument_},
{"typeAnnotation", AstDumper::Optional(typeAnnotation_)}});
}
void SpreadElement::Compile([[maybe_unused]] compiler::PandaGen *pg) const {}
checker::Type *SpreadElement::Check([[maybe_unused]] checker::Checker *checker) const
{
return nullptr;
}
} // namespace panda::es2panda::ir
+68
View File
@@ -0,0 +1,68 @@
/**
* Copyright (c) 2021 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.
*/
#ifndef ES2PANDA_PARSER_INCLUDE_AST_SPREAD_ELEMENT_H
#define ES2PANDA_PARSER_INCLUDE_AST_SPREAD_ELEMENT_H
#include <ir/expression.h>
#include <ir/validationInfo.h>
namespace panda::es2panda::compiler {
class PandaGen;
} // namespace panda::es2panda::compiler
namespace panda::es2panda::checker {
class Checker;
class Type;
} // namespace panda::es2panda::checker
namespace panda::es2panda::ir {
class SpreadElement : public Expression {
public:
explicit SpreadElement(AstNodeType nodeType, Expression *argument) : Expression(nodeType), argument_(argument) {}
const Expression *Argument() const
{
return argument_;
}
Expression *Argument()
{
return argument_;
}
const Expression *TypeAnnotation() const
{
return typeAnnotation_;
}
ValidationInfo ValidateExpression();
bool ConvertibleToRest(bool isDeclaration, bool allowPattern = true);
void SetTsTypeAnnotation(Expression *typeAnnotation) override;
void Iterate(const NodeTraverser &cb) const override;
void Dump(ir::AstDumper *dumper) const override;
void Compile([[maybe_unused]] compiler::PandaGen *pg) const override;
checker::Type *Check([[maybe_unused]] checker::Checker *checker) const override;
private:
Expression *argument_;
Expression *typeAnnotation_ {};
};
} // namespace panda::es2panda::ir
#endif
+42
View File
@@ -0,0 +1,42 @@
/**
* 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 "templateElement.h"
#include <ir/astDump.h>
#include <util/ustring.h>
#include <utility>
namespace panda::es2panda::ir {
void TemplateElement::Iterate([[maybe_unused]] const NodeTraverser &cb) const {}
void TemplateElement::Dump(ir::AstDumper *dumper) const
{
dumper->Add({
{"type", "TemplateElement"},
{"value", {{"raw", "" /* raw_ */}, {"cooked", "" /* cooked_ */}}},
});
}
void TemplateElement::Compile([[maybe_unused]] compiler::PandaGen *pg) const {}
checker::Type *TemplateElement::Check([[maybe_unused]] checker::Checker *checker) const
{
return nullptr;
}
} // namespace panda::es2panda::ir
+64
View File
@@ -0,0 +1,64 @@
/**
* Copyright (c) 2021 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.
*/
#ifndef ES2PANDA_PARSER_INCLUDE_AST_TEMPLATE_ELEMENT_H
#define ES2PANDA_PARSER_INCLUDE_AST_TEMPLATE_ELEMENT_H
#include <ir/expression.h>
#include <util/ustring.h>
namespace panda::es2panda::compiler {
class PandaGen;
} // namespace panda::es2panda::compiler
namespace panda::es2panda::checker {
class Checker;
class Type;
} // namespace panda::es2panda::checker
namespace panda::es2panda::ir {
class TemplateElement : public Expression {
public:
explicit TemplateElement() : Expression(AstNodeType::TEMPLATE_ELEMENT) {}
explicit TemplateElement(util::StringView raw, util::StringView cooked)
: Expression(AstNodeType::TEMPLATE_ELEMENT), raw_(raw), cooked_(cooked)
{
}
const util::StringView &Raw() const
{
return raw_;
}
const util::StringView &Cooked() const
{
return cooked_;
}
void Iterate(const NodeTraverser &cb) const override;
void Dump(ir::AstDumper *dumper) const override;
void Compile([[maybe_unused]] compiler::PandaGen *pg) const override;
checker::Type *Check([[maybe_unused]] checker::Checker *checker) const override;
protected:
util::StringView raw_ {};
util::StringView cooked_ {};
};
} // namespace panda::es2panda::ir
#endif

Some files were not shown because too many files have changed in this diff Show More