mirror of
https://github.com/openharmony/ark_ts2abc.git
synced 2026-07-01 09:24:57 -04:00
Add original es2panda compiler based on 05ddb192 of master
Change-Id: I26f663c67b42f6549c7777a88c8bf00bd845fc96 Signed-off-by: zhuoli72 <pengzhuoli@huawei.com>
This commit is contained in:
@@ -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)
|
||||
@@ -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`.
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 ¶ms)
|
||||
{
|
||||
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
|
||||
@@ -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 ¶ms);
|
||||
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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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(®s);
|
||||
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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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(®s);
|
||||
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(®s);
|
||||
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
|
||||
@@ -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 *> ®isters)
|
||||
{
|
||||
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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 *> &¶ms,
|
||||
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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
Reference in New Issue
Block a user