diff --git a/BUILD.gn b/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..7bf72fa8da96be752a0404820d398742621077d0 --- /dev/null +++ b/BUILD.gn @@ -0,0 +1,22 @@ +# 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. + +import("//ark/runtime_core/ark_config.gni") +import("//build/ohos.gni") + +group("ets_frontend") { + deps = [ + "./ts2panda:ark_ts2abc_build", + "./es2panda:es2panda_build", + ] +} \ No newline at end of file diff --git a/bundle.json b/bundle.json index 36f2d2379df2eaa05fdfbc398f42b8ca1f3b6699..931045866c577b9336e0d4b9aba98f02c198843c 100644 --- a/bundle.json +++ b/bundle.json @@ -4,7 +4,7 @@ "version": "3.1", "license": "Apache V2", "component": { - "name": "ark_frontend_tool", + "name": "ark_ts2abc", "subsystem": "ark", "syscap": [], "features": [], @@ -18,7 +18,9 @@ "third_party": [] }, "build": { - "sub_component": [], + "sub_component": [ + "//ark/ts2abc:ets_frontend" + ], "inner_kits": [], "test": [] } diff --git a/es2panda/BUILD.gn b/es2panda/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..ed44a5d72538891f9eba0b7e67dfd5b8342cc30d --- /dev/null +++ b/es2panda/BUILD.gn @@ -0,0 +1,481 @@ +# 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. + +import("//ark/runtime_core/ark_config.gni") +import("//build/ohos.gni") + +es2panda_src = [ + "es2panda.cpp", + "binder/binder.cpp", + "binder/declaration.cpp", + "binder/module.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/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" +] + +config("es2abc_config_src") { + include_dirs = [ + "./", + "./binder", + "./util", + "./compiler/base", + "./compiler/core", + "./compiler/debugger", + "./compiler/function", + "./ir", + "./ir/base", + "./ir/expressions", + "./ir/module", + "./ir/statements", + "./ir/ts", + "./parser", + "./parser/context", + "./lexer", + "./lexer/token", + "./lexer/regexp", + "./typescript", + "./typescript/types" + ] + + cflags = [ "-fexceptions" ] +} + +config("es2abc_config_common") { + + configs = [ + "$ark_root:ark_config", + "$sdk_libc_secshared_config", + "$ark_root/libpandafile:arkfile_public_config", + "$ark_root/libpandabase:arkbase_public_config", + "$ark_root/runtime:arkruntime_public_config", + "$ark_root/assembler:arkassembler_public_config", + ":es2abc_config_src", + ] + + if (enable_bytecode_optimizer) { + defines = [ "ENABLE_BYTECODE_OPT" ] + configs += [ + "$ark_root/compiler:arkcompiler_public_config", + "$ark_root/bytecode_optimizer:bytecodeopt_public_config", + ] + } +} + +# generate headers for es2panda parser +generated_header_dir = "${target_out_dir}/gen" +action_foreach("gen_keywords_headers") { + template_files = [ + "keywords.h.erb", + "keywordsMap.h.erb", + ] + keywords_templates_dir = "./lexer/templates" + keywords_generator = "./lexer/scripts/keywords.rb" + + sources = [] + foreach(file, template_files) { + sources += [ rebase_path("${keywords_templates_dir}/${file}") ] + } + outputs = [ "${generated_header_dir}/{{source_name_part}}" ] + + script = "scripts/gen_keywords.sh" + inputs = [ "${keywords_generator}" ] + args = [ + "-g", rebase_path("${keywords_generator}"), + "-t", "{{source}}", + "-o", "{{source_name_part}}", + "-d", rebase_path("${generated_header_dir}"), + ] +} + +# generate headers for es2panda compiler +isa_gen = "${ark_root}/isa/gen.rb" +isa_gen_data = "$root_gen_dir/isa/isa.yaml" +isa_gen_require = "${ark_root}/isa/isapi.rb" +action_foreach("gen_isa_headers") { + + deps = [ "//ark/runtime_core/isa:isa_combine" ] + + template_files = [ + "isa.h.erb", + "formats.h.erb", + ] + keywords_templates_dir = "./compiler/templates" + + sources = [] + foreach(file, template_files) { + sources += [ rebase_path("${keywords_templates_dir}/${file}") ] + } + outputs = [ "${generated_header_dir}/{{source_name_part}}" ] + + script = "scripts/gen_isa.sh" + inputs = [ + "${isa_gen}", + "${isa_gen_data}", + "${isa_gen_require}" + ] + args = [ + "-g", rebase_path("${isa_gen}"), + "-t", "{{source}}", + "-a", rebase_path("${isa_gen_data}"), + "-o", "{{source_name_part}}", + "-d", rebase_path("${generated_header_dir}"), + "-r", rebase_path("${isa_gen_require}"), + ] +} + +ohos_static_library("es2panda_lib") { + sources = es2panda_src + use_exceptions = true + + configs = [ ":es2abc_config_common" ] + + include_dirs = [ + "${target_out_dir}", + "//third_party/icu/icu4c/source/common", + "//third_party/icu/icu4c/source/i18n", + "//third_party/icu/icu4c/source ", + ] + + deps = [ + ":gen_keywords_headers", + ":gen_isa_headers", + "$ark_root/assembler:libarkassembler_frontend_static", + "$ark_root/libpandabase:libarkbase_frontend_static", + "$ark_root/libpandafile:libarkfile_frontend_static", + "$ark_root/libziparchive:libarkziparchive_frontend_static", + "//third_party/icu/icu4c:static_icuuc", + ] + + cflags = [ + "-Wno-c++20-designator", + "-Wno-implicit-fallthrough", + ] +} + +ohos_executable("es2panda") { + use_exceptions = true + sources = [ + "aot/options.cpp", + "aot/main.cpp", + ] + + include_dirs = [ "./aot" ] + + configs = [ ":es2abc_config_common" ] + + deps = [ + ":es2panda_lib", + ] + + if (is_linux) { + if (build_public_version) { + ldflags = [ "-static-libstdc++" ] + } else { + libs = [ libcpp_static_lib ] + } + } + + if (enable_bytecode_optimizer) { + deps += [ + "$ark_root/bytecode_optimizer:libarkbytecodeopt_frontend_static", + "$ark_root/compiler:libarkcompiler_frontend_static", + ] + } + + output_name = "es2abc" + install_enable = true + subsystem_name = "ark" +} + +if (is_linux) { + ohos_copy("es2abc_build") { + deps = [ ":es2panda" ] + sources = [ "${root_out_dir}/ark/ark/es2abc" ] + outputs = [ "${target_out_dir}/es2abc-tmp" ] + module_source_dir = "${root_out_dir}/ark/ark" + module_install_name = "es2abc" + } + + ohos_copy("es2abc_build_ets") { + deps = [ ":es2panda" ] + sources = [ "${root_out_dir}/ark/ark/es2abc" ] + outputs = [ "${root_out_dir}/ark/ark/es2abc-ets" ] + module_source_dir = "${root_out_dir}/ark/ark" + module_install_name = "es2abc" + } +} + +if (is_mingw) { + ohos_copy("es2abc_build_win") { + deps = [ ":es2panda" ] + sources = [ "${root_out_dir}/ark/ark/es2abc.exe" ] + outputs = [ "${target_out_dir}/es2abc-tmp" ] + module_source_dir = "${root_out_dir}/ark/ark" + module_install_name = "es2abc.exe" + } + + ohos_copy("es2abc_build_win_ets") { + deps = [ ":es2panda" ] + sources = [ "${root_out_dir}/ark/ark/es2abc.exe" ] + outputs = [ "${root_out_dir}/ark/ark/es2abc-win-ets" ] + module_source_dir = "${root_out_dir}/ark/ark" + module_install_name = "es2abc.exe" + } +} + +if (is_mac) { + ohos_copy("es2abc_build_mac") { + deps = [ ":es2panda" ] + sources = [ "${root_out_dir}/ark/ark/es2abc" ] + outputs = [ "${target_out_dir}/es2abc-tmp" ] + module_source_dir = "${root_out_dir}/ark/ark" + module_install_name = "es2abc" + } + + ohos_copy("es2abc_build_mac_ets") { + deps = [ ":es2panda" ] + sources = [ "${root_out_dir}/ark/ark/es2abc" ] + outputs = [ "${root_out_dir}/ark/ark/es2abc-mac-ets" ] + module_source_dir = "${root_out_dir}/ark/ark" + module_install_name = "es2abc" + } +} + +group("es2panda_build") { + build_tool_linux = "//build/toolchain/linux:clang_x64" + if (host_os == "linux") { + deps = [ ":es2panda(${build_tool_linux})" ] + } + + if (host_os == "mac") { + deps = [ ":es2panda(//build/toolchain/mac:clang_x64)" ] + } +} + +group("es2panda_build_win") { + deps = [ ":es2panda(//build/toolchain/mingw:mingw_x86_64)" ] +} diff --git a/es2panda/aot/main.cpp b/es2panda/aot/main.cpp index 8dbd680977fa6e901ca1e41d7f6dbc8235458125..79c5131dec17642a0799feb1dc1c771c6999f135 100644 --- a/es2panda/aot/main.cpp +++ b/es2panda/aot/main.cpp @@ -14,12 +14,18 @@ */ #include +#ifdef ENABLE_BYTECODE_OPT #include #include +#else +#include +#include +#include +#endif #include #include #include -#include +#include #include #include @@ -124,8 +130,8 @@ int Run(int argc, const char **argv) return 0; } - std::cout << err.TypeString() << ": " << err.Message(); - std::cout << " [" << options->SourceFile() << ":" << err.Line() << ":" << err.Col() << "]" << std::endl; + std::cerr << err.TypeString() << ": " << err.Message(); + std::cerr << " [" << options->SourceFile() << ":" << err.Line() << ":" << err.Col() << "]" << std::endl; return err.ErrorCode(); } diff --git a/es2panda/aot/options.cpp b/es2panda/aot/options.cpp index 9be3f001c5b1f2f8a6c5e7e5cd796649fe38f70d..9f72eac598d446a9f0b38324db70539060e0ed72 100644 --- a/es2panda/aot/options.cpp +++ b/es2panda/aot/options.cpp @@ -18,6 +18,7 @@ #include #include +#include namespace panda::es2panda::aot { diff --git a/es2panda/aot/options.h b/es2panda/aot/options.h index af8c8e3093a40394bd8679a28407a28d4dd16708..9b681e7f11c393c02d38bcb12ad22715e34947db 100644 --- a/es2panda/aot/options.h +++ b/es2panda/aot/options.h @@ -17,7 +17,7 @@ #define ES2PANDA_AOT_OPTIONS_H #include -#include +#include #include #include diff --git a/es2panda/binder/binder.cpp b/es2panda/binder/binder.cpp index d2a8b2ad397c8be9b3a5a17ca306bd6354d2d199..51c97a8fb969744c52f25b90dfba3454cceb44da 100644 --- a/es2panda/binder/binder.cpp +++ b/es2panda/binder/binder.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -80,7 +81,7 @@ void Binder::IdentifierAnalysis() ASSERT(program_->Ast()); ASSERT(scope_ == topScope_); - BuildFunction(topScope_, "main"); + BuildFunction(topScope_, MAIN_FUNC_NAME); ResolveReferences(program_->Ast()); AddMandatoryParams(); } @@ -158,16 +159,38 @@ void Binder::LookupIdentReference(ir::Identifier *ident) ident->SetVariable(res.variable); } -void Binder::BuildFunction(FunctionScope *funcScope, util::StringView name) +util::StringView Binder::BuildFunctionName(FunctionScope *funcScope, util::StringView name) { - uint32_t idx = functionScopes_.size(); - functionScopes_.push_back(funcScope); + // the first funcitonScope is for func_main_0 + if ((functionScopes_.size() == 1) && (name == MAIN_FUNC_NAME)) { + return name; + } + std::string name_str = std::string(name); + bool funcNameWithoutDot = (name_str.find(".") == std::string::npos); + bool funcNameWithoutBackslash = (name_str.find("\\") == std::string::npos); + + if (name != ANONYMOUS_FUNC_NAME && name != MAIN_FUNC_NAME && funcNameWithoutDot && funcNameWithoutBackslash + && std::find(functionNames_.begin(), functionNames_.end(), name) == functionNames_.end()) { + functionNames_.push_back(name); + return name; + } std::stringstream ss; - ss << "func_" << name << "_" << std::to_string(idx); + uint32_t idx = duplicateFunctionCount_++; + ss << "#" << std::to_string(idx) << "#"; + if (funcNameWithoutDot && funcNameWithoutBackslash) { + ss << name; + } util::UString internalName(ss.str(), Allocator()); + return internalName.View(); +} - funcScope->BindName(name, internalName.View()); +void Binder::BuildFunction(FunctionScope *funcScope, util::StringView name) +{ + functionScopes_.push_back(funcScope); + + util::StringView internalName = BuildFunctionName(funcScope, name); + funcScope->BindName(name, internalName); } void Binder::BuildScriptFunction(Scope *outerScope, const ir::ScriptFunction *scriptFunc) @@ -243,7 +266,14 @@ void Binder::BuildVarDeclarator(ir::VariableDeclarator *varDecl) void Binder::BuildClassDefinition(ir::ClassDefinition *classDef) { if (classDef->Parent()->IsClassDeclaration()) { - ScopeFindResult res = scope_->Find(classDef->Ident()->Name()); + util::StringView className; + if (classDef->Ident()) { + className = classDef->Ident()->Name(); + } else { + ASSERT(scope_->IsModuleScope()); + className = util::StringView("*default*"); + } + ScopeFindResult res = scope_->Find(className); ASSERT(res.variable && res.variable->Declaration()->IsLetDecl()); res.variable->AddFlag(VariableFlags::INITIALIZED); @@ -319,6 +349,13 @@ void Binder::BuildCatchClause(ir::CatchClause *catchClauseStmt) ResolveReference(catchClauseStmt, catchClauseStmt->Body()); } +void Binder::BuildNameSpace(const ir::ImportNamespaceSpecifier *namespaceSpecifier) +{ + const auto &name = namespaceSpecifier->Local()->Name(); + auto *variable = scope_->FindLocal(name); + variable->AddFlag(VariableFlags::INITIALIZED); +} + void Binder::ResolveReference(const ir::AstNode *parent, ir::AstNode *childNode) { childNode->SetParent(parent); @@ -430,6 +467,10 @@ void Binder::ResolveReference(const ir::AstNode *parent, ir::AstNode *childNode) BuildCatchClause(childNode->AsCatchClause()); break; } + case ir::AstNodeType::IMPORT_NAMESPACE_SPECIFIER: { + BuildNameSpace(childNode->AsImportNamespaceSpecifier()); + break; + } default: { ResolveReferences(childNode); break; diff --git a/es2panda/binder/binder.h b/es2panda/binder/binder.h index 28f4b038d2ecfe000b020cd6552496d5d681d9d0..ec95c9121d6288321a52901f0ba6c9cbaf1d66e5 100644 --- a/es2panda/binder/binder.h +++ b/es2panda/binder/binder.h @@ -30,6 +30,7 @@ class ClassDefinition; class Expression; class ForUpdateStatement; class Identifier; +class ImportNamespaceSpecifier; class ScriptFunction; class Statement; class VariableDeclarator; @@ -62,7 +63,7 @@ public: return scope_; } - GlobalScope *TopScope() const + FunctionScope *TopScope() const { return topScope_; } @@ -104,6 +105,9 @@ public: static constexpr std::string_view LEXICAL_MANDATORY_PARAM_NEW_TARGET = "!nt"; static constexpr std::string_view LEXICAL_MANDATORY_PARAM_THIS = "!t"; + static constexpr std::string_view MAIN_FUNC_NAME = "func_main_0"; + static constexpr std::string_view ANONYMOUS_FUNC_NAME = ""; + private: using MandatoryParams = std::array; @@ -119,6 +123,7 @@ private: void AddMandatoryParam(const std::string_view &name); void AddMandatoryParams(const MandatoryParams ¶ms); void AddMandatoryParams(); + util::StringView BuildFunctionName(FunctionScope *funcScope, util::StringView name); void BuildFunction(FunctionScope *funcScope, util::StringView name); void BuildScriptFunction(Scope *outerScope, const ir::ScriptFunction *scriptFunc); void BuildClassDefinition(ir::ClassDefinition *classDef); @@ -130,14 +135,17 @@ private: void BuildForInOfLoop(const ir::Statement *parent, binder::LoopScope *loopScope, ir::AstNode *left, ir::Expression *right, ir::Statement *body); void BuildCatchClause(ir::CatchClause *catchClauseStmt); + void BuildNameSpace(const ir::ImportNamespaceSpecifier *namespaceSpecifier); 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_ {}; + FunctionScope *topScope_ {}; Scope *scope_ {}; ArenaVector functionScopes_; + std::vector functionNames_; + size_t duplicateFunctionCount_ {1}; }; template diff --git a/es2panda/binder/declaration.h b/es2panda/binder/declaration.h index ab65a7579ac6db9768e837f80d82e57f8cbcdd62..3897bb1ac1db0178554120fedd05a6c96aeaa992 100644 --- a/es2panda/binder/declaration.h +++ b/es2panda/binder/declaration.h @@ -32,6 +32,12 @@ namespace panda::es2panda::binder { class Scope; class LocalScope; +enum class ModuleDeclKind { + NONE = 0, + IMPORT, + EXPORT, +}; + #define DECLARE_CLASSES(decl_kind, className) class className; DECLARATION_KINDS(DECLARE_CLASSES) #undef DECLARE_CLASSES @@ -82,18 +88,39 @@ public: return IsLetDecl() || IsConstDecl(); } + bool IsExport() const + { + return modDeclKind_ == ModuleDeclKind::EXPORT; + } + + bool IsImport() const + { + return modDeclKind_ == ModuleDeclKind::IMPORT; + } + + bool IsNormal() const + { + return modDeclKind_ == ModuleDeclKind::NONE; + } + protected: - explicit Decl(util::StringView name) : name_(name) {} + explicit Decl(util::StringView name, ModuleDeclKind modDeclKind = ModuleDeclKind::NONE) + : name_(name), modDeclKind_(modDeclKind) + { + } util::StringView name_; + ModuleDeclKind modDeclKind_; const ir::AstNode *node_ {}; }; template class MultiDecl : public Decl { public: - explicit MultiDecl(ArenaAllocator *allocator, util::StringView name) - : Decl(name), declarations_(allocator->Adapter()) + explicit MultiDecl(ArenaAllocator *allocator, + util::StringView name, + ModuleDeclKind modDeclKind = ModuleDeclKind::NONE) + : Decl(name, modDeclKind), declarations_(allocator->Adapter()) { } @@ -152,8 +179,11 @@ public: class FunctionDecl : public MultiDecl { public: - explicit FunctionDecl(ArenaAllocator *allocator, util::StringView name, const ir::AstNode *node) - : MultiDecl(allocator, name) + explicit FunctionDecl(ArenaAllocator *allocator, + util::StringView name, + const ir::AstNode *node, + ModuleDeclKind modDeclKind = ModuleDeclKind::NONE) + : MultiDecl(allocator, name, modDeclKind) { node_ = node; } @@ -206,7 +236,8 @@ public: class VarDecl : public Decl { public: - explicit VarDecl(util::StringView name) : Decl(name) {} + explicit VarDecl(util::StringView name, ModuleDeclKind modDeclKind = ModuleDeclKind::NONE) + : Decl(name, modDeclKind) {} DeclType Type() const override { @@ -216,7 +247,8 @@ public: class LetDecl : public Decl { public: - explicit LetDecl(util::StringView name) : Decl(name) {} + explicit LetDecl(util::StringView name, ModuleDeclKind modDeclKind = ModuleDeclKind::NONE) + : Decl(name, modDeclKind) {} DeclType Type() const override { @@ -226,7 +258,8 @@ public: class ConstDecl : public Decl { public: - explicit ConstDecl(util::StringView name) : Decl(name) {} + explicit ConstDecl(util::StringView name, ModuleDeclKind modDeclKind = ModuleDeclKind::NONE) + : Decl(name, modDeclKind) {} DeclType Type() const override { @@ -244,70 +277,6 @@ public: } }; -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 diff --git a/es2panda/binder/module.cpp b/es2panda/binder/module.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d1d7c65aa843588852a3cabaf3d3e7b4d76d180e --- /dev/null +++ b/es2panda/binder/module.cpp @@ -0,0 +1,214 @@ +/** + * 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 "module.h" + +#include + +namespace panda::es2panda::binder { + + int SourceTextModuleRecord::AddModuleRequest(const util::StringView source, lexer::SourcePosition sourcePos) + { + ASSERT(!source.Empty()); + int moduleRequestsSize = static_cast(moduleRequestsMap_.size()); + if (moduleRequestsMap_.find(source) == moduleRequestsMap_.end()) { + moduleRequests_.emplace_back(source); + } + auto insertedRes = moduleRequestsMap_.insert( + std::make_pair(source, ModuleRequest(moduleRequestsSize, sourcePos.index)) + ); + return insertedRes.first->second.idx; + } + + void SourceTextModuleRecord::AddImportEntry(const util::StringView importName, + const util::StringView localName, + const util::StringView moduleRequest, + const lexer::SourcePosition pos, + const lexer::SourcePosition sourcePos) + { + auto *importEntry = allocator_->New(pos); + importEntry->importName = importName; + importEntry->localName = localName; + importEntry->moduleRequest = AddModuleRequest(moduleRequest, sourcePos); + ASSERT(!importEntry->importName.Empty()); + ASSERT(!importEntry->localName.Empty()); + ASSERT(importEntry->exportName.Empty()); + ASSERT(importEntry->moduleRequest != -1); + regularImportEntries_.insert(std::make_pair(importEntry->localName, importEntry)); + } + + void SourceTextModuleRecord::AddEmptyImportEntry(const util::StringView moduleRequest, + const lexer::SourcePosition sourcePos) + { + AddModuleRequest(moduleRequest, sourcePos); + } + + void SourceTextModuleRecord::AddStarImportEntry(const ir::AstNode *moduleNode, + const util::StringView localName, + const util::StringView moduleRequest, + const lexer::SourcePosition pos, + const lexer::SourcePosition sourcePos) + { + auto *starImportEntry = allocator_->New(pos); + starImportEntry->moduleNode = moduleNode; + starImportEntry->localName = localName; + starImportEntry->moduleRequest = AddModuleRequest(moduleRequest, sourcePos); + ASSERT(starImportEntry->moduleNode != nullptr); + ASSERT(starImportEntry->importName.Empty()); + ASSERT(!starImportEntry->localName.Empty()); + ASSERT(starImportEntry->exportName.Empty()); + ASSERT(starImportEntry->moduleRequest != -1); + namespaceImportEntries_.push_back(starImportEntry); + } + + void SourceTextModuleRecord::AddLocalExportEntry(const util::StringView exportName, + const util::StringView localName, + const lexer::SourcePosition pos) + { + auto *localExportEntry = allocator_->New(pos); + localExportEntry->exportName = exportName; + localExportEntry->localName = localName; + ASSERT(localExportEntry->importName.Empty()); + ASSERT(!localExportEntry->localName.Empty()); + ASSERT(!localExportEntry->exportName.Empty()); + ASSERT(localExportEntry->moduleRequest == -1); + localExportEntries_.insert(std::make_pair(localExportEntry->localName, localExportEntry)); + } + + void SourceTextModuleRecord::AddIndirectExportEntry(const util::StringView importName, + const util::StringView exportName, + const util::StringView moduleRequest, + const lexer::SourcePosition pos, + const lexer::SourcePosition sourcePos) + { + auto *indirectExportEntry = allocator_->New(pos); + indirectExportEntry->importName = importName; + indirectExportEntry->exportName = exportName; + indirectExportEntry->moduleRequest = AddModuleRequest(moduleRequest, sourcePos); + ASSERT(!indirectExportEntry->importName.Empty()); + ASSERT(indirectExportEntry->localName.Empty()); + ASSERT(!indirectExportEntry->exportName.Empty()); + ASSERT(indirectExportEntry->moduleRequest != -1); + indirectExportEntries_.push_back(indirectExportEntry); + } + + void SourceTextModuleRecord::AddStarExportEntry(const util::StringView moduleRequest, + const lexer::SourcePosition pos, + const lexer::SourcePosition sourcePos) + { + auto *starExportEntry = allocator_->New(pos); + starExportEntry->moduleRequest = AddModuleRequest(moduleRequest, sourcePos); + ASSERT(starExportEntry->importName.Empty()); + ASSERT(starExportEntry->localName.Empty()); + ASSERT(starExportEntry->exportName.Empty()); + ASSERT(starExportEntry->moduleRequest != -1); + starExportEntries_.push_back(starExportEntry); + } + + const SourceTextModuleRecord::Entry *SourceTextModuleRecord::NextDuplicateExportEntry( + const Entry *entry, + const Entry *duplicate, + ArenaMap &exportNameEntries) + { + ASSERT(!entry->exportName.Empty()); + auto insertRes = exportNameEntries.insert(std::make_pair(entry->exportName, entry)); + + // successfully inserted when there has no duplicate entry + if (insertRes.second) { + return duplicate; + } + + // find [entry] has same export name with one of the exportNameEntries + if (duplicate == nullptr) { + // update duplicate entry if pre duplicate is null + duplicate = insertRes.first->second; + } + + // return the entry at the backward position + if (entry->position.index > duplicate->position.index) { + return entry; + } + + return duplicate; + } + + const SourceTextModuleRecord::Entry *SourceTextModuleRecord::SearchDupExport() + { + const SourceTextModuleRecord::Entry *duplicateEntry = nullptr; + ArenaMap exportNameEntries( + allocator_->Adapter()); + + for (auto const &entryUnit : localExportEntries_) { + duplicateEntry = NextDuplicateExportEntry(entryUnit.second, duplicateEntry, exportNameEntries); + } + + for (auto entry : indirectExportEntries_) { + duplicateEntry = NextDuplicateExportEntry(entry, duplicateEntry, exportNameEntries); + } + + return duplicateEntry; + } + + bool SourceTextModuleRecord::ValidateModuleRecordEntries(ModuleScope *moduleScope, + std::string &errorMessage, + lexer::SourcePosition &errorPos) + { + ASSERT(this == moduleScope->GetModuleRecord()); + const SourceTextModuleRecord::Entry *dupExportEntry = SearchDupExport(); + if (dupExportEntry != nullptr) { + errorMessage.append("Duplicate export name of '" + dupExportEntry->exportName.Mutf8() + "'"); + errorPos.index = dupExportEntry->position.index; + errorPos.line = dupExportEntry->position.line; + return false; + } + + for (const auto &entryUnit : localExportEntries_) { + const SourceTextModuleRecord::Entry *e = entryUnit.second; + ASSERT(!e->exportName.Empty()); + if (moduleScope->FindLocal(e->localName) == nullptr && !e->localName.Is("*default*")) { + errorMessage.append("Export name '" + e->localName.Mutf8() + "' is not defined"); + errorPos.index = e->position.index; + errorPos.line = e->position.line; + return false; + } + } + + /* Translate implicit indirectExport entry into explicit entry + * e.g. import { x } from 'test.js'; export { x } + * ---> + * import { x } from 'test.js'; export { x } from 'test.js'; + */ + for (auto it = localExportEntries_.begin(); it != localExportEntries_.end();) { + auto exportEntry = it->second; + ASSERT(!exportEntry->localName.Empty()); + auto importEntry = regularImportEntries_.find(exportEntry->localName); + if (importEntry != regularImportEntries_.end()) { + ASSERT(exportEntry->importName.Empty()); + ASSERT(exportEntry->moduleRequest == -1); + ASSERT(!importEntry->second->importName.Empty()); + ASSERT(importEntry->second->moduleRequest != -1); + exportEntry->importName = importEntry->second->importName; + exportEntry->moduleRequest = importEntry->second->moduleRequest; + exportEntry->localName = util::StringView(""); + exportEntry->position = importEntry->second->position; + indirectExportEntries_.push_back(exportEntry); + it = localExportEntries_.erase(it); + continue; + } + ++it; + } + return true; + } +} // namespace panda::es2panda::binder \ No newline at end of file diff --git a/es2panda/binder/module.h b/es2panda/binder/module.h new file mode 100644 index 0000000000000000000000000000000000000000..3f4885dcaad386ac64f0e28256c5a2100306962f --- /dev/null +++ b/es2panda/binder/module.h @@ -0,0 +1,172 @@ +/** + * 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_MODULE_H +#define ES2PANDA_COMPILER_SCOPES_MODULE_H + +#include +#include + +namespace panda::es2panda::ir { +class AstNode; +} // namespace panda::es2panda::ir + +namespace panda::es2panda::binder { + +class ModuleScope; + +class SourceTextModuleRecord { + public: + explicit SourceTextModuleRecord(ArenaAllocator *allocator) + : allocator_(allocator), + moduleRequestsMap_(allocator_->Adapter()), + moduleRequests_(allocator_->Adapter()), + localExportEntries_(allocator_->Adapter()), + regularImportEntries_(allocator_->Adapter()), + namespaceImportEntries_(allocator_->Adapter()), + starExportEntries_(allocator_->Adapter()), + indirectExportEntries_(allocator_->Adapter()) + { + } + + ~SourceTextModuleRecord() = default; + NO_COPY_SEMANTIC(SourceTextModuleRecord); + NO_MOVE_SEMANTIC(SourceTextModuleRecord); + + struct Entry { + lexer::SourcePosition position; + const ir::AstNode *moduleNode; + int moduleRequest; + util::StringView exportName; + util::StringView localName; + util::StringView importName; + + explicit Entry(lexer::SourcePosition pos) + : position(pos), + moduleNode(nullptr), + moduleRequest(-1) {} + }; + + struct ModuleRequest { + int idx; + int pos; + ModuleRequest(int idx, int pos) + : idx(idx), pos(pos) {} + }; + + // import x from 'test.js'; + // import {x} from 'test.js'; + // import {x as y} from 'test.js'; + // import defaultExport from 'test.js' + void AddImportEntry(const util::StringView importName, + const util::StringView localName, + const util::StringView moduleRequest, + const lexer::SourcePosition pos, + const lexer::SourcePosition sourcePos); + + // import 'test.js' + // import {} from 'test.js' + // export {} from 'test.js' + void AddEmptyImportEntry(const util::StringView moduleRequest, const lexer::SourcePosition sourcePos); + + // import * as x from 'test.js'; + void AddStarImportEntry(const ir::AstNode *moduleNode, + const util::StringView localName, + const util::StringView moduleRequest, + const lexer::SourcePosition pos, + const lexer::SourcePosition sourcePos); + + // export {x}; + // export {x as y}; + // export VariableStatement + // export Declaration + // export default ... + void AddLocalExportEntry(const util::StringView exportName, + const util::StringView localName, + const lexer::SourcePosition pos); + + // export {x} from 'test.js'; + // export {x as y} from 'test.js'; + // import { x } from 'test.js'; export { x } + void AddIndirectExportEntry(const util::StringView importName, + const util::StringView exportName, + const util::StringView moduleRequest, + const lexer::SourcePosition pos, + const lexer::SourcePosition sourcePos); + + // export * from 'test.js'; + void AddStarExportEntry(const util::StringView moduleRequest, + const lexer::SourcePosition pos, + const lexer::SourcePosition sourcePos); + + bool ValidateModuleRecordEntries(ModuleScope *moduleScope, + std::string &errorMessage, + lexer::SourcePosition &errorPos); + + using ModuleRequestMap = ArenaMap; + using LocalExportEntryMap = ArenaMultiMap; + using RegularImportEntryMap = ArenaMap; + + const ArenaVector &GetModuleRequests() const + { + return moduleRequests_; + } + + const LocalExportEntryMap &GetLocalExportEntries() const + { + return localExportEntries_; + } + + const RegularImportEntryMap &GetRegularImportEntries() const + { + return regularImportEntries_; + } + + const ArenaVector &GetNamespaceImportEntries() const + { + return namespaceImportEntries_; + } + + const ArenaVector &GetStarExportEntries() const + { + return starExportEntries_; + } + + const ArenaVector &GetIndirectExportEntries() const + { + return indirectExportEntries_; + } + + private: + int AddModuleRequest(const util::StringView source, lexer::SourcePosition sourcePos); + + const Entry *SearchDupExport(); + + const Entry *NextDuplicateExportEntry(const Entry *entry, + const Entry *duplicate, + ArenaMap &exportNameEntries); + + ArenaAllocator *allocator_; + ModuleRequestMap moduleRequestsMap_; + ArenaVector moduleRequests_; + LocalExportEntryMap localExportEntries_; + RegularImportEntryMap regularImportEntries_; + ArenaVector namespaceImportEntries_; + ArenaVector starExportEntries_; + ArenaVector indirectExportEntries_; +}; + +} // namespace panda::es2panda::binder +#endif \ No newline at end of file diff --git a/es2panda/binder/scope.cpp b/es2panda/binder/scope.cpp index 402bdd7a0c77989d8eb0451300936e38afe78d8d..41ba586293c150ea3748192cc00c1176eb12a36e 100644 --- a/es2panda/binder/scope.cpp +++ b/es2panda/binder/scope.cpp @@ -78,6 +78,23 @@ ScopeFindResult Scope::Find(const util::StringView &name, ResolveBindingOptions uint32_t lexLevel = 0; const auto *iter = this; + if (iter->IsFunctionParamScope()) { + Variable *v = iter->FindLocal(name, options); + + if (v != nullptr) { + return {name, const_cast(iter), level, lexLevel, v}; + } + + level++; + auto *funcVariableScope = iter->AsFunctionParamScope()->GetFunctionScope(); + + if (funcVariableScope->NeedLexEnv()) { + lexLevel++; + } + + iter = iter->Parent(); + } + while (iter != nullptr) { Variable *v = iter->FindLocal(name, options); @@ -131,6 +148,20 @@ std::tuple Scope::IterateShadowedVariables(const util::StringView return {iter, false}; } +bool Scope::IterateShadowedDefaultVariables(const Decl *newDecl) +{ + ASSERT(!newDecl->IsVarDecl()); + + auto *iter = this; + auto name = newDecl->Name(); + auto *v = iter->FindLocal(name); + if (v && (iter == this)) { + return true; + } + + return false; +} + bool Scope::AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension) { @@ -174,9 +205,10 @@ bool Scope::AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl return false; } - auto [_, shadowed] = IterateShadowedVariables( - newDecl->Name(), [](const Variable *v) { return v->HasFlag(VariableFlags::LEXICAL_VAR); }); - (void)_; + // auto [_, shadowed] = IterateShadowedVariables( + // newDecl->Name(), [](const Variable *v) { return v->HasFlag(VariableFlags::LEXICAL_VAR); }); + // (void)_; + bool shadowed = IterateShadowedDefaultVariables(newDecl); if (shadowed) { return false; @@ -253,10 +285,14 @@ bool FunctionScope::AddBinding(ArenaAllocator *allocator, Variable *currentVaria { switch (newDecl->Type()) { case DeclType::VAR: { - return AddVar(allocator, currentVariable, newDecl); + return newDecl->IsNormal() ? + AddVar(allocator, currentVariable, newDecl) : + AddVar(allocator, currentVariable, newDecl); } case DeclType::FUNC: { - return AddFunction(allocator, currentVariable, newDecl, extension); + return newDecl->IsNormal() ? + AddFunction(allocator, currentVariable, newDecl, extension) : + AddFunction(allocator, currentVariable, newDecl, extension); } case DeclType::ENUM: { bindings_.insert({newDecl->Name(), allocator->New(newDecl, false)}); @@ -324,109 +360,12 @@ bool ModuleScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariabl case DeclType::INTERFACE: { return AddTSBinding(allocator, currentVariable, newDecl, VariableFlags::INTERFACE); } - case DeclType::IMPORT: { - return AddImport(allocator, currentVariable, newDecl); - } - case DeclType::EXPORT: { - return true; - } default: { - return AddLexical(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 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(newDecl, VariableFlags::READONLY)}); - } else { - auto *variable = allocator->New(newDecl, VariableFlags::NONE); - variable->ExoticName() = newDecl->AsImportDecl()->ImportName(); - bindings_.insert({newDecl->Name(), variable}); - } - - return true; -} - -bool ModuleScope::ExportAnalysis() -{ - std::set 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 newDecl->IsNormal() ? + AddLexical(allocator, currentVariable, newDecl) : + AddLexical(allocator, currentVariable, newDecl); } } - - return true; } // LocalScope diff --git a/es2panda/binder/scope.h b/es2panda/binder/scope.h index 9621858f36bc2b887ed1fcbdbfc61b26cdb6b729..96c45f326107be19348125f5d4d4bfb568bb6d58 100644 --- a/es2panda/binder/scope.h +++ b/es2panda/binder/scope.h @@ -17,6 +17,7 @@ #define ES2PANDA_COMPILER_SCOPES_SCOPE_H #include +#include #include #include #include @@ -230,6 +231,8 @@ protected: */ std::tuple IterateShadowedVariables(const util::StringView &name, const VariableVisitior &visitor); + bool IterateShadowedDefaultVariables(const Decl *newDecl); + bool AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension); @@ -559,74 +562,52 @@ public: [[maybe_unused]] ScriptExtension extension) override; }; -class ModuleScope : public GlobalScope { +class ModuleScope : public FunctionScope { public: - template - using ModuleEntry = ArenaVector>; - using ImportDeclList = ArenaVector; - using ExportDeclList = ArenaVector; - using LocalExportNameMap = ArenaMultiMap; - explicit ModuleScope(ArenaAllocator *allocator) - : GlobalScope(allocator), - allocator_(allocator), - imports_(allocator_->Adapter()), - exports_(allocator_->Adapter()), - localExports_(allocator_->Adapter()) - { - } - - ScopeType Type() const override + : FunctionScope(allocator, nullptr), + moduleRecord_(new SourceTextModuleRecord(allocator)) { - return ScopeType::MODULE; + auto *paramScope = allocator->New(allocator, this); + paramScope_ = paramScope; } - const ModuleEntry &Imports() const + ~ModuleScope() { - return imports_; + delete moduleRecord_; } - const ModuleEntry &Exports() const + ScopeType Type() const override { - return exports_; + return ScopeType::MODULE; } - const LocalExportNameMap &LocalExports() const + SourceTextModuleRecord *GetModuleRecord() const { - return localExports_; + return moduleRecord_; } - 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 imports_; - ModuleEntry exports_; - LocalExportNameMap localExports_; + SourceTextModuleRecord *moduleRecord_; }; template bool VariableScope::AddVar(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl) { + VariableFlags flags = newDecl->IsNormal() ? VariableFlags::HOIST_VAR : + newDecl->IsImport() ? VariableFlags::HOIST_VAR | VariableFlags::IMPORT : + VariableFlags::HOIST_VAR | VariableFlags::LOCAL_EXPORT; if (!currentVariable) { - bindings_.insert({newDecl->Name(), allocator->New(newDecl, VariableFlags::HOIST_VAR)}); + bindings_.insert({newDecl->Name(), allocator->New(newDecl, flags)}); return true; } switch (currentVariable->Declaration()->Type()) { case DeclType::VAR: { - currentVariable->Reset(newDecl, VariableFlags::HOIST_VAR); + currentVariable->Reset(newDecl, flags); break; } case DeclType::PARAM: @@ -647,19 +628,23 @@ bool VariableScope::AddFunction(ArenaAllocator *allocator, Variable *currentVari { VariableFlags flags = (extension == ScriptExtension::JS) ? VariableFlags::HOIST_VAR : VariableFlags::HOIST; + flags = newDecl->IsNormal() ? flags : + newDecl->IsImport() ? flags | VariableFlags::IMPORT : + flags | VariableFlags::LOCAL_EXPORT; + if (!currentVariable) { bindings_.insert({newDecl->Name(), allocator->New(newDecl, flags)}); return true; } - if (extension != ScriptExtension::JS || IsModuleScope()) { + if (extension != ScriptExtension::JS) { return false; } switch (currentVariable->Declaration()->Type()) { case DeclType::VAR: case DeclType::FUNC: { - currentVariable->Reset(newDecl, VariableFlags::HOIST_VAR); + currentVariable->Reset(newDecl, flags); break; } default: { @@ -682,11 +667,14 @@ bool VariableScope::AddTSBinding(ArenaAllocator *allocator, [[maybe_unused]] Var template bool VariableScope::AddLexical(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl) { + VariableFlags flags = newDecl->IsNormal() ? VariableFlags::NONE : + newDecl->IsImport() ? VariableFlags::NONE | VariableFlags::IMPORT : + VariableFlags::NONE | VariableFlags::LOCAL_EXPORT; if (currentVariable) { return false; } - bindings_.insert({newDecl->Name(), allocator->New(newDecl, VariableFlags::NONE)}); + bindings_.insert({newDecl->Name(), allocator->New(newDecl, flags)}); return true; } diff --git a/es2panda/binder/variable.h b/es2panda/binder/variable.h index 4302048a8bf2ccafe9887e3574da5bfd7be16f1c..36190236d6e4e182382259dfd6d5d697cd7efe9b 100644 --- a/es2panda/binder/variable.h +++ b/es2panda/binder/variable.h @@ -182,31 +182,7 @@ public: 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 { diff --git a/es2panda/binder/variableFlags.h b/es2panda/binder/variableFlags.h index dee8b1475741544e27355e61683873cafe375fb3..26eafee84eeea5c7557a6662f4a88b1bf33ca7c2 100644 --- a/es2panda/binder/variableFlags.h +++ b/es2panda/binder/variableFlags.h @@ -26,8 +26,6 @@ namespace panda::es2panda::binder { _(CONST, ConstDecl) \ _(FUNC, FunctionDecl) \ _(PARAM, ParameterDecl) \ - _(IMPORT, ImportDecl) \ - _(EXPORT, ExportDecl) \ /* TS */ \ _(TYPE_ALIAS, TypeAliasDecl) \ _(NAMESPACE, NameSpaceDecl) \ @@ -104,6 +102,7 @@ enum class VariableFlags { COMPUTED_IDENT = 1 << 8, COMPUTED_INDEX = 1 << 9, INDEX_NAME = 1 << 10, + IMPORT = 1 << 11, LOCAL_EXPORT = 1 << 12, INFERED_IN_PATTERN = 1 << 13, REST_ARG = 1 << 14, diff --git a/es2panda/compiler/base/condition.cpp b/es2panda/compiler/base/condition.cpp index 644e9195fecef0aaa030ac05f26f19ebe9c77636..577d8c63e49a2a67b455939e124e1c9b00346dde 100644 --- a/es2panda/compiler/base/condition.cpp +++ b/es2panda/compiler/base/condition.cpp @@ -51,11 +51,9 @@ void Condition::Compile(PandaGen *pg, const ir::Expression *expr, Label *falseLa } 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; } @@ -63,11 +61,9 @@ void Condition::Compile(PandaGen *pg, const ir::Expression *expr, Label *falseLa 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; @@ -87,7 +83,6 @@ void Condition::Compile(PandaGen *pg, const ir::Expression *expr, Label *falseLa // General case including some binExpr i.E.(a+b) expr->Compile(pg); - pg->ToBoolean(expr); pg->BranchIfFalse(expr, falseLabel); } diff --git a/es2panda/compiler/base/destructuring.cpp b/es2panda/compiler/base/destructuring.cpp index 7ff756529f3b4f1b528f3245a35b19636af46963..5b3ac2e0c148ab1c32708c72e5fced9238427db2 100644 --- a/es2panda/compiler/base/destructuring.cpp +++ b/es2panda/compiler/base/destructuring.cpp @@ -223,9 +223,15 @@ static void GenObject(PandaGen *pg, const ir::ObjectExpression *object, VReg rhs if (properties.empty() || properties.back()->IsRestElement()) { auto *notNullish = pg->AllocLabel(); + auto *nullish = pg->AllocLabel(); - pg->LoadAccumulator(object, rhs); - pg->BranchIfCoercible(object, notNullish); + pg->LoadConst(object, Constant::JS_NULL); + pg->Condition(object, lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL, rhs, nullish); + pg->LoadConst(object, Constant::JS_UNDEFINED); + pg->Condition(object, lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL, rhs, nullish); + pg->Branch(object, notNullish); + + pg->SetLabel(object, nullish); pg->ThrowObjectNonCoercible(object); pg->SetLabel(object, notNullish); diff --git a/es2panda/compiler/base/hoisting.cpp b/es2panda/compiler/base/hoisting.cpp index 07621e8d630c5793019c81bf2641fc2da9f5b9e2..818082c6b95be8c22a04b147ae1d7c31475a0b42 100644 --- a/es2panda/compiler/base/hoisting.cpp +++ b/es2panda/compiler/base/hoisting.cpp @@ -31,10 +31,29 @@ static void HoistVar(PandaGen *pg, binder::Variable *var, const binder::VarDecl return; } + auto *iter = scope; + while (iter) { + if (iter->IsFunctionVariableScope()) { + break; + } + iter = iter->Parent(); + } + const auto *funcScope = iter->AsFunctionVariableScope(); + for (auto *param : funcScope->ParamScope()->Params()) { + if (param->Name() == decl->Name()) { + return; + } + } + binder::ScopeFindResult result(decl->Name(), scope, 0, var); pg->LoadConst(decl->Node(), Constant::JS_UNDEFINED); - pg->StoreAccToLexEnv(decl->Node(), result, true); + if (decl->IsNormal()) { + pg->StoreAccToLexEnv(decl->Node(), result, true); + } else { + ASSERT(scope->IsModuleScope()); + pg->StoreModuleVariable(decl->Node(), decl->Name()); + } } static void HoistFunction(PandaGen *pg, binder::Variable *var, const binder::FunctionDecl *decl) @@ -54,7 +73,12 @@ static void HoistFunction(PandaGen *pg, binder::Variable *var, const binder::Fun binder::ScopeFindResult result(decl->Name(), scope, 0, var); pg->DefineFunction(decl->Node(), scriptFunction, internalName); - pg->StoreAccToLexEnv(decl->Node(), result, true); + if (decl->IsNormal()) { + pg->StoreAccToLexEnv(decl->Node(), result, true); + } else { + ASSERT(scope->IsModuleScope()); + pg->StoreModuleVariable(decl->Node(), decl->Name()); + } } void Hoisting::Hoist(PandaGen *pg) diff --git a/es2panda/compiler/base/iterators.cpp b/es2panda/compiler/base/iterators.cpp index 1bf7ad888797b1fb5f2c829aab527b4979a09c8a..a3a2ee58fdbd862ba935cb7344e1b23ef17073be 100644 --- a/es2panda/compiler/base/iterators.cpp +++ b/es2panda/compiler/base/iterators.cpp @@ -35,24 +35,24 @@ Iterator::Iterator(PandaGen *pg, const ir::AstNode *node, IteratorType type) 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_->LoadObjByName(node_, iterator_, name); pg_->StoreAccumulator(node_, method_); } -void Iterator::CallMethodWithValue() const +void Iterator::CallMethodWithValue(VReg value) const { - pg_->CallThis(node_, method_, 2); + std::vector args = {method_, iterator_, value}; + pg_->CallThis(node_, args); } void Iterator::CallMethod() const { - pg_->CallThis(node_, method_, 1); + std::vector args = {method_, iterator_}; + pg_->CallThis(node_, args); } void Iterator::Next() const @@ -63,14 +63,13 @@ void Iterator::Next() const pg_->FuncBuilder()->Await(node_); } - pg_->ThrowIfNotObject(node_); pg_->StoreAccumulator(node_, nextResult_); + pg_->ThrowIfNotObject(node_, nextResult_); } void Iterator::Complete() const { pg_->LoadObjByName(node_, nextResult_, "done"); - pg_->ToBoolean(node_); } void Iterator::Value() const @@ -78,13 +77,60 @@ void Iterator::Value() const pg_->LoadObjByName(node_, nextResult_, "value"); } +void Iterator::CloseWithException() const +{ + if (type_ == IteratorType::SYNC) { + RegScope rs(pg_); + VReg exception = pg_->AllocReg(); + VReg constReg = pg_->AllocReg(); + Label *noReturn = pg_->AllocLabel(); + pg_->StoreAccumulator(node_, exception); + + pg_->LoadConst(node_, Constant::JS_TRUE); + pg_->StoreAccumulator(node_, constReg); + Complete(); + pg_->Condition(node_, lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL, constReg, noReturn); + + // close iterator + pg_->LoadObjByName(node_, iterator_, "return"); + pg_->StoreAccumulator(node_, nextResult_); + pg_->LoadConst(node_, Constant::JS_UNDEFINED); + pg_->Condition(node_, lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL, nextResult_, noReturn); + std::vector args = {nextResult_, iterator_}; + pg_->CallThis(node_, args); + + pg_->SetLabel(node_, noReturn); + pg_->LoadAccumulator(node_, exception); + pg_->EmitThrow(node_); + return; + } + + // support IteratorType::ASYNC later +} + + void Iterator::Close(bool abruptCompletion) const { if (type_ == IteratorType::SYNC) { - if (!abruptCompletion) { - pg_->LoadConst(node_, Constant::JS_HOLE); - } - pg_->CloseIterator(node_, iterator_); + // if (!abruptCompletion) { + // pg_->LoadConst(node_, Constant::JS_HOLE); + // } + // pg_->CloseIterator(node_, iterator_); + RegScope rs(pg_); + VReg innerResult = pg_->AllocReg(); + Label *noReturn = pg_->AllocLabel(); + + // close iterator + pg_->LoadObjByName(node_, iterator_, "return"); + pg_->StoreAccumulator(node_, nextResult_); + pg_->LoadConst(node_, Constant::JS_UNDEFINED); + pg_->Condition(node_, lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL, nextResult_, noReturn); + std::vector args = {nextResult_, iterator_}; + pg_->CallThis(node_, args); + pg_->StoreAccumulator(node_, innerResult); + pg_->ThrowIfNotObject(node_, innerResult); + + pg_->SetLabel(node_, noReturn); return; } @@ -160,7 +206,7 @@ void Iterator::Close(bool abruptCompletion) const // 8. If Type(innerResult.[[Value]]) is not Object, throw a TypeError exception. pg_->LoadAccumulator(node_, innerResult); - pg_->ThrowIfNotObject(node_); + pg_->ThrowIfNotObject(node_, innerResult); } DestructuringIterator::DestructuringIterator(PandaGen *pg, const ir::AstNode *node) diff --git a/es2panda/compiler/base/iterators.h b/es2panda/compiler/base/iterators.h index 0f23818d9ed2015bc8db01e274ba63b5a064dea1..efd699a3ae646731bee310f0f6c4f2f60d630bd1 100644 --- a/es2panda/compiler/base/iterators.h +++ b/es2panda/compiler/base/iterators.h @@ -57,11 +57,12 @@ public: void GetMethod(util::StringView name) const; void CallMethod() const; - void CallMethodWithValue() const; + void CallMethodWithValue(VReg value) const; void Next() const; void Complete() const; void Value() const; + void CloseWithException() const; void Close(bool abruptCompletion) const; protected: diff --git a/es2panda/compiler/base/lexenv.cpp b/es2panda/compiler/base/lexenv.cpp index f3410f06c2ff81e8e0a5a098f5909111720f2970..467b873efa7c710c24ac94127b8a35eb30012854 100644 --- a/es2panda/compiler/base/lexenv.cpp +++ b/es2panda/compiler/base/lexenv.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include namespace panda::es2panda::compiler { @@ -44,7 +43,10 @@ static void CheckConstAssignment(PandaGen *pg, const ir::AstNode *node, binder:: 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()); + const auto *decl = result.variable->Declaration(); + if (decl->IsLetOrConstDecl()) { + pg->ThrowUndefinedIfHole(node, result.variable->Name()); + } } static void ExpandLoadNormalVar(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result) @@ -70,21 +72,6 @@ void VirtualLoadVar::Expand(PandaGen *pg, const ir::AstNode *node, const binder: // 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(); @@ -107,8 +94,6 @@ static void ExpandStoreLexVar(PandaGen *pg, const ir::AstNode *node, const binde } pg->StoreLexicalVar(node, result.lexLevel, local->LexIdx()); - - StoreLocalExport(pg, node, local); } static void ExpandStoreNormalVar(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result, @@ -127,7 +112,6 @@ static void ExpandStoreNormalVar(PandaGen *pg, const ir::AstNode *node, const bi } pg->StoreAccumulator(node, localReg); - StoreLocalExport(pg, node, local); } void VirtualStoreVar::Expand(PandaGen *pg, const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDecl) diff --git a/es2panda/compiler/base/lreference.cpp b/es2panda/compiler/base/lreference.cpp index 6fd21e14eedd2b4be322b5746b6411bd6f70a279..0d375ceaecc75b1986c5796d6b7f4e261c208c7b 100644 --- a/es2panda/compiler/base/lreference.cpp +++ b/es2panda/compiler/base/lreference.cpp @@ -58,11 +58,11 @@ void LReference::GetValue() } } -void LReference::SetValue() +void LReference::SetValue(bool isInSetClassProto) { switch (refKind_) { case ReferenceKind::VAR_OR_GLOBAL: { - pg_->StoreVar(node_, res_, isDeclaration_); + pg_->StoreVar(node_, res_, isDeclaration_, isInSetClassProto); break; } case ReferenceKind::MEMBER: { diff --git a/es2panda/compiler/base/lreference.h b/es2panda/compiler/base/lreference.h index e7edf06f7b90d4f08a94bce2f7faaa85dea5c880..8a52c998aa9c85e46c51b97e216a1851e903aef7 100644 --- a/es2panda/compiler/base/lreference.h +++ b/es2panda/compiler/base/lreference.h @@ -47,7 +47,7 @@ public: NO_MOVE_SEMANTIC(LReference); void GetValue(); - void SetValue(); + void SetValue(bool isInSetClassProto = false); binder::Variable *Variable() const; ReferenceKind Kind() const; diff --git a/es2panda/compiler/core/compileQueue.cpp b/es2panda/compiler/core/compileQueue.cpp index 29460a7b3b4a59143e2c994747b7587c334251af..dc826a43f303fcf3bba289801ca86766eb91f9bf 100644 --- a/es2panda/compiler/core/compileQueue.cpp +++ b/es2panda/compiler/core/compileQueue.cpp @@ -37,7 +37,11 @@ void CompileJob::Run() FunctionEmitter funcEmitter(&allocator, &pg); funcEmitter.Generate(); - context_->GetEmitter()->AddFunction(&funcEmitter); + auto *emitter = context_->GetEmitter(); + emitter->AddFunction(&funcEmitter); + if (scope_->IsModuleScope()) { + emitter->AddSourceTextModuleRecord(&pg); + } if (dependant_) { dependant_->Signal(); diff --git a/es2panda/compiler/core/dynamicContext.cpp b/es2panda/compiler/core/dynamicContext.cpp index 73e9e9ddcb08b589c09a48c9d822fe1497086fb4..9c6b9a70470b08522d47c59e529f46ad2722b67f 100644 --- a/es2panda/compiler/core/dynamicContext.cpp +++ b/es2panda/compiler/core/dynamicContext.cpp @@ -118,7 +118,7 @@ IteratorContext::~IteratorContext() pg_->Branch(node, labelSet.CatchEnd()); pg_->SetLabel(node, labelSet.CatchBegin()); - iterator_.Close(true); + iterator_.CloseWithException(); pg_->SetLabel(node, labelSet.CatchEnd()); } diff --git a/es2panda/compiler/core/emitter.cpp b/es2panda/compiler/core/emitter.cpp index 6e617cb41f196d3b1ae3fdc361eed462f28af155..54847c53f658423e95b4fefce80771bec1ad796e 100644 --- a/es2panda/compiler/core/emitter.cpp +++ b/es2panda/compiler/core/emitter.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -64,6 +65,7 @@ void FunctionEmitter::Generate() GenFunctionCatchTables(); GenFunctionICSize(); GenLiteralBuffers(); + GenSourceTextModuleRecord(); } const ArenaSet &FunctionEmitter::Strings() const @@ -114,16 +116,21 @@ void FunctionEmitter::GenBufferLiterals(const LiteralBuffer *buff) valueLit.value_ = literal->GetMethod().Mutf8(); break; } - case ir::LiteralTag::GENERATOR_METHOD: { - valueLit.tag_ = panda::panda_file::LiteralTag::GENERATORMETHOD; - valueLit.value_ = literal->GetMethod().Mutf8(); + case ir::LiteralTag::METHODAFFILIATE: { + valueLit.tag_ = panda::panda_file::LiteralTag::METHODAFFILIATE; + valueLit.value_ = literal->GetMethodAffiliate(); break; } - case ir::LiteralTag::ASYNC_GENERATOR_METHOD: { - valueLit.tag_ = panda::panda_file::LiteralTag::ASYNCGENERATORMETHOD; + 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(0); @@ -139,6 +146,14 @@ void FunctionEmitter::GenBufferLiterals(const LiteralBuffer *buff) array.emplace_back(tagLit); array.emplace_back(valueLit); } + + // std::cout << " --- literal array buffer --- " << std::endl; + // for (auto a : array) { + // std::cout << "tag: " << static_cast::type>(a.tag_) << std::endl; + // std::visit( [](auto&& e) { + // std::cout << "value: " << e << std::endl; + // }, a.value_ ); + // } } util::StringView FunctionEmitter::SourceCode() const @@ -279,6 +294,134 @@ void FunctionEmitter::GenLiteralBuffers() } } +void FunctionEmitter::GenModuleRequests(binder::SourceTextModuleRecord *moduleRecord, + std::vector &moduleLiteralArray) +{ + auto &moduleRequests = moduleRecord->GetModuleRequests(); + panda::pandasm::LiteralArray::Literal moduleSize = { + .tag_ = panda::panda_file::LiteralTag::INTEGER, .value_ = static_cast(moduleRequests.size())}; + moduleLiteralArray.emplace_back(moduleSize); + for (auto request : moduleRequests) { + panda::pandasm::LiteralArray::Literal moduleRequest = { + .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = request.Mutf8()}; + moduleLiteralArray.emplace_back(moduleRequest); + } +} + +void FunctionEmitter::GenRegularImportEntries(binder::SourceTextModuleRecord *moduleRecord, + std::vector &moduleLiteralArray) +{ + auto ®ularImportEntries = moduleRecord->GetRegularImportEntries(); + panda::pandasm::LiteralArray::Literal entrySize = { + .tag_ = panda::panda_file::LiteralTag::INTEGER, + .value_ = static_cast(regularImportEntries.size())}; + moduleLiteralArray.emplace_back(entrySize); + for (auto it = regularImportEntries.begin(); it != regularImportEntries.end(); ++it) { + auto *entry = it->second; + panda::pandasm::LiteralArray::Literal localName = { + .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = entry->localName.Mutf8()}; + moduleLiteralArray.emplace_back(localName); + panda::pandasm::LiteralArray::Literal importName = { + .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = entry->importName.Mutf8()}; + moduleLiteralArray.emplace_back(importName); + panda::pandasm::LiteralArray::Literal moduleRequest = { + .tag_ = panda::panda_file::LiteralTag::METHODAFFILIATE, + .value_ = static_cast(entry->moduleRequest)}; + moduleLiteralArray.emplace_back(moduleRequest); + } +} + +void FunctionEmitter::GenNamespaceImportEntries(binder::SourceTextModuleRecord *moduleRecord, + std::vector &moduleLiteralArray) +{ + auto &namespaceImportEntries = moduleRecord->GetNamespaceImportEntries(); + panda::pandasm::LiteralArray::Literal entrySize = { + .tag_ = panda::panda_file::LiteralTag::INTEGER, + .value_ = static_cast(namespaceImportEntries.size())}; + moduleLiteralArray.emplace_back(entrySize); + for (const auto *entry : namespaceImportEntries) { + panda::pandasm::LiteralArray::Literal localName = { + .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = entry->localName.Mutf8()}; + moduleLiteralArray.emplace_back(localName); + panda::pandasm::LiteralArray::Literal moduleRequest = { + .tag_ = panda::panda_file::LiteralTag::METHODAFFILIATE, + .value_ = static_cast(entry->moduleRequest)}; + moduleLiteralArray.emplace_back(moduleRequest); + } +} + +void FunctionEmitter::GenLocalExportEntries(binder::SourceTextModuleRecord *moduleRecord, + std::vector &moduleLiteralArray) +{ + auto &localExportEntries = moduleRecord->GetLocalExportEntries(); + panda::pandasm::LiteralArray::Literal entrySize = { + .tag_ = panda::panda_file::LiteralTag::INTEGER, .value_ = static_cast(localExportEntries.size())}; + moduleLiteralArray.emplace_back(entrySize); + for (auto it = localExportEntries.begin(); it != localExportEntries.end(); ++it) { + auto *entry = it->second; + panda::pandasm::LiteralArray::Literal localName = { + .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = entry->localName.Mutf8()}; + moduleLiteralArray.emplace_back(localName); + panda::pandasm::LiteralArray::Literal exportName = { + .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = entry->exportName.Mutf8()}; + moduleLiteralArray.emplace_back(exportName); + } +} + +void FunctionEmitter::GenIndirectExportEntries(binder::SourceTextModuleRecord *moduleRecord, + std::vector &moduleLiteralArray) +{ + auto &indirectExportEntries = moduleRecord->GetIndirectExportEntries(); + panda::pandasm::LiteralArray::Literal entrySize = { + .tag_ = panda::panda_file::LiteralTag::INTEGER, .value_ = static_cast(indirectExportEntries.size())}; + moduleLiteralArray.emplace_back(entrySize); + for (const auto *entry : indirectExportEntries) { + panda::pandasm::LiteralArray::Literal exportName = { + .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = entry->exportName.Mutf8()}; + moduleLiteralArray.emplace_back(exportName); + panda::pandasm::LiteralArray::Literal importName = { + .tag_ = panda::panda_file::LiteralTag::STRING, .value_ = entry->importName.Mutf8()}; + moduleLiteralArray.emplace_back(importName); + panda::pandasm::LiteralArray::Literal moduleRequest = { + .tag_ = panda::panda_file::LiteralTag::METHODAFFILIATE, + .value_ = static_cast(entry->moduleRequest)}; + moduleLiteralArray.emplace_back(moduleRequest); + } +} + +void FunctionEmitter::GenStarExportEntries(binder::SourceTextModuleRecord *moduleRecord, + std::vector &moduleLiteralArray) +{ + auto &starExportEntries = moduleRecord->GetStarExportEntries(); + panda::pandasm::LiteralArray::Literal entrySize = { + .tag_ = panda::panda_file::LiteralTag::INTEGER, .value_ = static_cast(starExportEntries.size())}; + moduleLiteralArray.emplace_back(entrySize); + for (const auto *entry : starExportEntries) { + panda::pandasm::LiteralArray::Literal moduleRequest = { + .tag_ = panda::panda_file::LiteralTag::METHODAFFILIATE, + .value_ = static_cast(entry->moduleRequest)}; + moduleLiteralArray.emplace_back(moduleRequest); + } +} + +void FunctionEmitter::GenSourceTextModuleRecord() +{ + if (!pg_->TopScope()->IsModuleScope()) { + return; + } + + auto *moduleRecord = pg_->TopScope()->AsModuleScope()->GetModuleRecord(); + auto &[idx, array] = literalBuffers_.emplace_back(); + idx = pg_->ModuleBuffIndex(); + + GenModuleRequests(moduleRecord, array); + GenRegularImportEntries(moduleRecord, array); + GenNamespaceImportEntries(moduleRecord, array); + GenLocalExportEntries(moduleRecord, array); + GenIndirectExportEntries(moduleRecord, array); + GenStarExportEntries(moduleRecord, array); +} + void FunctionEmitter::GenSourceFileDebugInfo() { func_->source_file = std::string {pg_->Binder()->Program()->SourceFile()}; @@ -347,7 +490,7 @@ Emitter::Emitter(const CompilerContext *context) prog_->function_table.reserve(context->Binder()->Functions().size()); GenESAnnoatationRecord(); - GenESModuleModeRecord(context->Binder()->Program()->Kind() == parser::ScriptKind::MODULE); + GenerateESModuleRecord(context->Binder()->Program()->Kind() == parser::ScriptKind::MODULE); } Emitter::~Emitter() @@ -363,20 +506,28 @@ void Emitter::GenESAnnoatationRecord() prog_->record_table.emplace(annotationRecord.name, std::move(annotationRecord)); } -void Emitter::GenESModuleModeRecord(bool isModule) +void Emitter::GenerateESModuleRecord(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(static_cast(isModule))); - - modeRecord.field_list.emplace_back(std::move(modeField)); + if (isModule) { + auto ecmaModuleRecord = panda::pandasm::Record("_ESModuleRecord", LANG_EXT); + ecmaModuleRecord.metadata->SetAccessFlags(panda::ACC_PUBLIC); + prog_->record_table.emplace(ecmaModuleRecord.name, std::move(ecmaModuleRecord)); + } +} - prog_->record_table.emplace(modeRecord.name, std::move(modeRecord)); +void Emitter::AddSourceTextModuleRecord(PandaGen *pg) +{ + ASSERT(pg->TopScope()->IsModuleScope()); + auto iter = prog_->record_table.find("_ESModuleRecord"); + if (iter != prog_->record_table.end()) { + auto &rec = iter->second; + auto moduleIdxField = panda::pandasm::Field(LANG_EXT); + moduleIdxField.name = std::string {pg->Binder()->Program()->SourceFile()}; + moduleIdxField.type = panda::pandasm::Type("u32", 0); + moduleIdxField.metadata->SetValue(panda::pandasm::ScalarValue::Create( + static_cast(pg->ModuleBuffIndex()))); + rec.field_list.emplace_back(std::move(moduleIdxField)); + } } void Emitter::AddFunction(FunctionEmitter *func) diff --git a/es2panda/compiler/core/emitter.h b/es2panda/compiler/core/emitter.h index addf4b142b4daaeb21c86c5edcf424de01ea2c0b..1bad72d1a2dae602fdd6cf1139b3ffb0af82a5ed 100644 --- a/es2panda/compiler/core/emitter.h +++ b/es2panda/compiler/core/emitter.h @@ -41,6 +41,7 @@ class Statement; namespace panda::es2panda::binder { class Scope; +class SourceTextModuleRecord; } // namespace panda::es2panda::binder namespace panda::es2panda::compiler { @@ -85,6 +86,20 @@ private: void GenLiteralBuffers(); void GenBufferLiterals(const LiteralBuffer *buff); + void GenModuleRequests(binder::SourceTextModuleRecord *moduleRecord, + std::vector &moduleLiteralArray); + void GenRegularImportEntries(binder::SourceTextModuleRecord *moduleRecord, + std::vector &moduleLiteralArray); + void GenNamespaceImportEntries(binder::SourceTextModuleRecord *moduleRecord, + std::vector &moduleLiteralArray); + void GenLocalExportEntries(binder::SourceTextModuleRecord *moduleRecord, + std::vector &moduleLiteralArray); + void GenIndirectExportEntries(binder::SourceTextModuleRecord *moduleRecord, + std::vector &moduleLiteralArray); + void GenStarExportEntries(binder::SourceTextModuleRecord *moduleRecord, + std::vector &moduleLiteralArray); + void GenSourceTextModuleRecord(); + const PandaGen *pg_; panda::pandasm::Function *func_ {}; ArenaVector>> literalBuffers_; @@ -99,12 +114,13 @@ public: NO_MOVE_SEMANTIC(Emitter); void AddFunction(FunctionEmitter *func); + void AddSourceTextModuleRecord(PandaGen *pg); static void DumpAsm(const panda::pandasm::Program *prog); panda::pandasm::Program *Finalize(bool dumpDebugInfo); private: void GenESAnnoatationRecord(); - void GenESModuleModeRecord(bool isModule); + void GenerateESModuleRecord(bool isModule); std::mutex m_; panda::pandasm::Program *prog_; diff --git a/es2panda/compiler/core/envScope.cpp b/es2panda/compiler/core/envScope.cpp index 6e2fa13c78c7038bb1a0d4e2a0eb7405af141868..fab1cabf99e2f5d170ff8842387e635843e1d5c0 100644 --- a/es2panda/compiler/core/envScope.cpp +++ b/es2panda/compiler/core/envScope.cpp @@ -77,8 +77,22 @@ void LoopEnvScope::CopyPetIterationCtx() return; } - pg_->CopyLexEnv(scope_->Node()); + auto num = Scope()->LexicalSlots(); + std::vector lexicals{}; + for (uint32_t i = 0; i < num; i++) { + VReg lexical = pg_->AllocReg(); + pg_->LoadLexicalVar(scope_->Node(), 0, i); + pg_->StoreAccumulator(scope_->Node(), lexical); + lexicals.push_back(lexical); + } + + pg_->CopyLexEnv(scope_->Node(), num); pg_->StoreAccumulator(scope_->Node(), lexEnv_); + + for (uint32_t i = 0; i < num; i++) { + pg_->LoadAccumulator(scope_->Node(), lexicals[i]); + pg_->StoreLexicalVar(scope_->Node(), 0, i); + } } } // namespace panda::es2panda::compiler diff --git a/es2panda/compiler/core/function.cpp b/es2panda/compiler/core/function.cpp index 8625e3f28155c571f83e1abbde96feac25844436..3d93c0f9d31940177b0e747e6a900b2ade30fcf0 100644 --- a/es2panda/compiler/core/function.cpp +++ b/es2panda/compiler/core/function.cpp @@ -81,7 +81,7 @@ static void CompileFunctionParameterDeclaration(PandaGen *pg, const ir::ScriptFu if (ref.Kind() == ReferenceKind::DESTRUCTURING) { auto *loadParamLabel = pg->AllocLabel(); - pg->BranchIfNotUndefined(func, loadParamLabel); + pg->BranchIfStrictNotUndefined(func, loadParamLabel); param->AsAssignmentPattern()->Right()->Compile(pg); pg->Branch(func, nonDefaultLabel); @@ -91,7 +91,7 @@ static void CompileFunctionParameterDeclaration(PandaGen *pg, const ir::ScriptFu pg->SetLabel(func, nonDefaultLabel); ref.SetValue(); } else { - pg->BranchIfNotUndefined(func, nonDefaultLabel); + pg->BranchIfStrictNotUndefined(func, nonDefaultLabel); param->AsAssignmentPattern()->Right()->Compile(pg); ref.SetValue(); @@ -200,6 +200,7 @@ static VReg CompileFunctionOrProgram(PandaGen *pg) void Function::Compile(PandaGen *pg) { VReg lexEnv = CompileFunctionOrProgram(pg); + pg->SetModuleRecordBufferIndex(); pg->CopyFunctionArguments(pg->RootNode()); pg->InitializeLexEnv(pg->RootNode(), lexEnv); pg->SortCatchTables(); diff --git a/es2panda/compiler/core/moduleContext.cpp b/es2panda/compiler/core/moduleContext.cpp deleted file mode 100644 index 272a319c361a78ee4436ee60cf84cc30152e5f8f..0000000000000000000000000000000000000000 --- a/es2panda/compiler/core/moduleContext.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/** - * 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 -#include -#include -#include -#include -#include -#include -#include - -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 diff --git a/es2panda/compiler/core/moduleContext.h b/es2panda/compiler/core/moduleContext.h deleted file mode 100644 index da15b229feb4aa0fcc51b2146d6cc00bcb488010..0000000000000000000000000000000000000000 --- a/es2panda/compiler/core/moduleContext.h +++ /dev/null @@ -1,39 +0,0 @@ -/** - * 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 - -#include - -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 diff --git a/es2panda/compiler/core/pandagen.cpp b/es2panda/compiler/core/pandagen.cpp index 7d58fa71c45b4622695a76884a4c7035854e2eac..2f0e3dfa1f705152255017d084911f0a1efe6489 100644 --- a/es2panda/compiler/core/pandagen.cpp +++ b/es2panda/compiler/core/pandagen.cpp @@ -159,11 +159,12 @@ void PandaGen::CopyFunctionArguments(const ir::AstNode *node) { FrontAllocator fa(this); VReg targetReg = totalRegs_; + VReg lexerNextReg = topScope_->ParamScope()->Params().size() + 1; for (const auto *param : topScope_->ParamScope()->Params()) { if (param->LexicalBound()) { LoadAccumulator(node, targetReg++); - StoreLexicalVar(node, 0, param->LexIdx()); + StoreLexicalVar(node, 0, param->LexIdx(), lexerNextReg); } else { ra_.Emit(node, param->Vreg(), targetReg++); } @@ -182,6 +183,13 @@ int32_t PandaGen::AddLiteralBuffer(LiteralBuffer *buf) return buf->Index(); } +void PandaGen::SetModuleRecordBufferIndex() +{ + if (topScope_->IsModuleScope()) { + moduleBuffIndex_ = context_->NewLiteralIndex(); + } +} + void PandaGen::GetFunctionObject(const ir::AstNode *node) { LoadAccFromLexEnv(node, scope_->Find(binder::Binder::MANDATORY_PARAM_FUNC)); @@ -217,15 +225,26 @@ void PandaGen::LoadVar(const ir::Identifier *node, const binder::ScopeFindResult } if (var->IsModuleVariable()) { - LoadModuleVariable(node, var->AsModuleVariable()->ModuleReg(), var->AsModuleVariable()->ExoticName()); + LoadModuleVariable(node, var->Name(), var->Declaration()->IsExport()); + if (var->Declaration()->IsLetOrConstDecl()) + ThrowUndefinedIfHole(node, var->Name()); return; } ASSERT(var->IsLocalVariable()); + + if (var->Declaration()->IsLetOrConstDecl()) { + if (result.scope->IsGlobalScope()) { + TryLoadGlobalByName(node, result.name); + return; + } + } + LoadAccFromLexEnv(node, result); } -void PandaGen::StoreVar(const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDeclaration) +void PandaGen::StoreVar(const ir::AstNode *node, const binder::ScopeFindResult &result, + bool isDeclaration, bool isInSetClassProto) { binder::Variable *var = result.variable; @@ -240,11 +259,40 @@ void PandaGen::StoreVar(const ir::AstNode *node, const binder::ScopeFindResult & } if (var->IsModuleVariable()) { - ThrowConstAssignment(node, var->Name()); + if (!isDeclaration && var->Declaration()->IsConstDecl()) { + ThrowConstAssignment(node, var->Name()); + return; + } + + if (!isDeclaration && var->Declaration()->IsLetDecl()) { + VReg valueReg = AllocReg(); + StoreAccumulator(node, valueReg); + LoadModuleVariable(node, var->Name(), true); + ThrowUndefinedIfHole(node, var->Name()); + LoadAccumulator(node, valueReg); + } + + StoreModuleVariable(node, var->Name()); return; } ASSERT(var->IsLocalVariable()); + + if (isDeclaration && var->Declaration()->IsLetOrConstDecl()) { + if (!isInSetClassProto && result.scope->IsGlobalScope()) { + if (var->Declaration()->IsLetDecl()) { + StLetToGlobalRecord(node, var->Name()); + } else { + StConstToGlobalRecord(node, var->Name()); + } + return; + } + } + if (var->Declaration()->IsLetOrConstDecl() && result.scope->IsGlobalScope() && !isInSetClassProto) { + TryStoreGlobalByName(node, var->Name()); + return; + } + StoreAccToLexEnv(node, result, isDeclaration); } @@ -300,10 +348,10 @@ void PandaGen::StoreObjProperty(const ir::AstNode *node, VReg obj, const Operand StoreObjByName(node, obj, std::get(prop)); } -void PandaGen::StoreOwnProperty(const ir::AstNode *node, VReg obj, const Operand &prop) +void PandaGen::StoreOwnProperty(const ir::AstNode *node, VReg obj, const Operand &prop, const bool nameSetting) { if (std::holds_alternative(prop)) { - StOwnByValue(node, obj, std::get(prop)); + StOwnByValue(node, obj, std::get(prop), nameSetting); return; } @@ -313,7 +361,7 @@ void PandaGen::StoreOwnProperty(const ir::AstNode *node, VReg obj, const Operand } ASSERT(std::holds_alternative(prop)); - StOwnByName(node, obj, std::get(prop)); + StOwnByName(node, obj, std::get(prop), nameSetting); } void PandaGen::TryLoadGlobalByName(const ir::AstNode *node, const util::StringView &name) @@ -360,20 +408,22 @@ void PandaGen::StoreObjByIndex(const ir::AstNode *node, VReg obj, int64_t index) ra_.Emit(node, index, obj); } -void PandaGen::StOwnByName(const ir::AstNode *node, VReg obj, const util::StringView &prop) +void PandaGen::StOwnByName(const ir::AstNode *node, VReg obj, const util::StringView &prop, const bool nameSetting) { - ra_.Emit(node, prop, obj); + nameSetting ? ra_.Emit(node, prop, obj) : + ra_.Emit(node, prop, obj); strings_.insert(prop); } -void PandaGen::StOwnByValue(const ir::AstNode *node, VReg obj, VReg prop) +void PandaGen::StOwnByValue(const ir::AstNode *node, VReg obj, VReg prop, const bool nameSetting) { - ra_.Emit(node, obj, prop); + nameSetting ? ra_.Emit(node, obj, prop) : + ra_.Emit(node, obj, prop); } void PandaGen::StOwnByIndex(const ir::AstNode *node, VReg obj, int64_t index) { - ra_.Emit(node, index, obj); + ra_.Emit(node, obj, index); } void PandaGen::DeleteObjProperty(const ir::AstNode *node, VReg obj, const Operand &prop) @@ -415,7 +465,7 @@ void PandaGen::StoreGlobalVar(const ir::AstNode *node, const util::StringView &n void PandaGen::StoreGlobalLet(const ir::AstNode *node, const util::StringView &name) { - sa_.Emit(node, name); + sa_.Emit(node, name); strings_.insert(name); } @@ -455,6 +505,13 @@ void PandaGen::LoadAccumulatorInt(const ir::AstNode *node, size_t num) sa_.Emit(node, static_cast(num)); } +void PandaGen::LoadAccumulatorBigInt(const ir::AstNode *node, const util::StringView &num) +{ + util::StringView bigIntValue = num.Substr(0, num.Length()-1); + sa_.Emit(node, bigIntValue); + strings_.insert(bigIntValue); +} + void PandaGen::StoreConst(const ir::AstNode *node, VReg reg, Constant id) { LoadConst(node, id); @@ -646,7 +703,7 @@ void PandaGen::Unary(const ir::AstNode *node, lexer::TokenType op, VReg operand) break; } case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: { - sa_.Emit(node); + Negate(node); break; } case lexer::TokenType::PUNCTUATOR_PLUS_PLUS: { @@ -784,19 +841,35 @@ void PandaGen::Binary(const ir::AstNode *node, lexer::TokenType op, VReg lhs) void PandaGen::BranchIfUndefined(const ir::AstNode *node, Label *target) { - sa_.Emit(node); - BranchIfTrue(node, target); + VReg tmp = AllocReg(); + StoreAccumulator(node, tmp); + sa_.Emit(node); + ra_.Emit(node, tmp); + sa_.Emit(node, target); } void PandaGen::BranchIfNotUndefined(const ir::AstNode *node, Label *target) { - sa_.Emit(node); - BranchIfFalse(node, target); + VReg tmp = AllocReg(); + StoreAccumulator(node, tmp); + sa_.Emit(node); + ra_.Emit(node, tmp); + sa_.Emit(node, target); +} + +void PandaGen::BranchIfStrictNotUndefined(const ir::AstNode *node, class Label *target) +{ + VReg tmp = AllocReg(); + StoreAccumulator(node, tmp); + LoadConst(node, Constant::JS_UNDEFINED); + ra_.Emit(node, tmp); + sa_.Emit(node, target); } void PandaGen::BranchIfTrue(const ir::AstNode *node, Label *target) { - sa_.Emit(node, target); + sa_.Emit(node); + sa_.Emit(node, target); } void PandaGen::BranchIfNotTrue(const ir::AstNode *node, Label *target) @@ -807,13 +880,14 @@ void PandaGen::BranchIfNotTrue(const ir::AstNode *node, Label *target) void PandaGen::BranchIfFalse(const ir::AstNode *node, Label *target) { - sa_.Emit(node, target); + sa_.Emit(node); + sa_.Emit(node, target); } -void PandaGen::BranchIfCoercible(const ir::AstNode *node, Label *target) +void PandaGen::BranchIfNotFalse(const ir::AstNode *node, Label *target) { - sa_.Emit(node); - BranchIfTrue(node, target); + sa_.Emit(node); + sa_.Emit(node, target); } void PandaGen::EmitThrow(const ir::AstNode *node) @@ -823,12 +897,29 @@ void PandaGen::EmitThrow(const ir::AstNode *node) void PandaGen::EmitRethrow(const ir::AstNode *node) { - sa_.Emit(node); + auto *skipThrow = AllocLabel(); + auto *doThrow = AllocLabel(); + + VReg exception = AllocReg(); + StoreAccumulator(node, exception); + + VReg hole = AllocReg(); + StoreConst(node, hole, Constant::JS_HOLE); + + LoadAccumulator(node, exception); + ra_.Emit(node, hole); + sa_.Emit(node, skipThrow); + + SetLabel(node, doThrow); + LoadAccumulator(node, exception); + sa_.Emit(node); + + SetLabel(node, skipThrow); } void PandaGen::EmitReturn(const ir::AstNode *node) { - sa_.Emit(node); + sa_.Emit(node); } void PandaGen::EmitReturnUndefined(const ir::AstNode *node) @@ -861,7 +952,7 @@ void PandaGen::ValidateClassDirectReturn(const ir::AstNode *node) auto *notUndefined = AllocLabel(); auto *condEnd = AllocLabel(); - BranchIfNotUndefined(node, notUndefined); + BranchIfStrictNotUndefined(node, notUndefined); GetThis(func); ThrowIfSuperNotCorrectCall(func, 0); Branch(node, condEnd); @@ -877,40 +968,36 @@ void PandaGen::EmitAwait(const ir::AstNode *node) builder_->Await(node); } -void PandaGen::CallThis(const ir::AstNode *node, VReg startReg, size_t argCount) +void PandaGen::CallThis(const ir::AstNode *node, std::vector ®s) { - rra_.Emit(node, startReg, argCount + 2, static_cast(argCount), startReg); + ASSERT(regs.size() >= 2); + rra_.Emit(node, regs, static_cast(regs.size() - 1), regs[0]); } -void PandaGen::Call(const ir::AstNode *node, VReg startReg, size_t argCount) +void PandaGen::Call(const ir::AstNode *node, std::vector ®s) { - VReg callee = startReg; + VReg callee = regs[0]; + auto argCount = regs.size() - 1; switch (argCount) { case 0: { // 0 args - ra_.Emit(node, callee); + ra_.Emit(node, callee); break; } case 1: { // 1 arg - VReg arg0 = callee + 1; - ra_.Emit(node, callee, arg0); + ra_.Emit(node, callee, regs[1]); break; } case 2: { // 2 args - VReg arg0 = callee + 1; - VReg arg1 = arg0 + 1; - ra_.Emit(node, callee, arg0, arg1); + ra_.Emit(node, callee, regs[1], regs[2]); break; } case 3: { // 3 args - VReg arg0 = callee + 1; - VReg arg1 = arg0 + 1; - VReg arg2 = arg1 + 1; - ra_.Emit(node, callee, arg0, arg1, arg2); + ra_.Emit(node, callee, regs[1], regs[2], regs[3]); break; } default: { - rra_.Emit(node, startReg, argCount + 1, static_cast(argCount), startReg); + rra_.Emit(node, regs, static_cast(regs.size() - 1), callee); break; } } @@ -926,9 +1013,9 @@ void PandaGen::SuperCallSpread(const ir::AstNode *node, VReg vs) ra_.Emit(node, vs); } -void PandaGen::NewObject(const ir::AstNode *node, VReg startReg, size_t argCount) +void PandaGen::NewObject(const ir::AstNode *node, std::vector ®s) { - rra_.Emit(node, startReg, argCount, static_cast(argCount), startReg); + rra_.Emit(node, regs, static_cast(regs.size()), regs[0]); } void PandaGen::LoadHomeObject(const ir::AstNode *node) @@ -938,21 +1025,22 @@ void PandaGen::LoadHomeObject(const ir::AstNode *node) void PandaGen::DefineFunction(const ir::AstNode *node, const ir::ScriptFunction *realNode, const util::StringView &name) { - if (realNode->IsAsync()) { + auto formal_param_cnt = realNode->FormalParamsLength(); + if (realNode->IsMethod()) { + ra_.Emit(node, name, static_cast(formal_param_cnt), LexEnv()); + } else if (realNode->IsAsync()) { if (realNode->IsGenerator()) { - ra_.Emit(node, name, LexEnv()); + // TODO(): async generator } else { - ra_.Emit(node, name, LexEnv()); + ra_.Emit(node, name, static_cast(formal_param_cnt), LexEnv()); } } else if (realNode->IsGenerator()) { - ra_.Emit(node, name, LexEnv()); + ra_.Emit(node, name, static_cast(formal_param_cnt), LexEnv()); } else if (realNode->IsArrow()) { LoadHomeObject(node); - ra_.Emit(node, name, LexEnv()); - } else if (realNode->IsMethod()) { - ra_.Emit(node, name, LexEnv()); + ra_.Emit(node, name, static_cast(formal_param_cnt), LexEnv()); } else { - ra_.Emit(node, name, LexEnv()); + ra_.Emit(node, name, static_cast(formal_param_cnt), LexEnv()); } strings_.insert(name); @@ -980,12 +1068,14 @@ void PandaGen::GetUnmappedArgs(const ir::AstNode *node) void PandaGen::Negate(const ir::AstNode *node) { - sa_.Emit(node); -} - -void PandaGen::ToBoolean(const ir::AstNode *node) -{ - sa_.Emit(node); + auto *falseLabel = AllocLabel(); + auto *endLabel = AllocLabel(); + BranchIfTrue(node, falseLabel); + LoadConst(node, Constant::JS_TRUE); + Branch(node, endLabel); + SetLabel(node, falseLabel); + LoadConst(node, Constant::JS_FALSE); + SetLabel(node, endLabel); } void PandaGen::ToNumber(const ir::AstNode *node, VReg arg) @@ -995,8 +1085,9 @@ void PandaGen::ToNumber(const ir::AstNode *node, VReg arg) void PandaGen::GetMethod(const ir::AstNode *node, VReg obj, const util::StringView &name) { - ra_.Emit(node, name, obj); - strings_.insert(name); + // commented for compile workaround + // ra_.Emit(node, name, obj); + // strings_.insert(name); } void PandaGen::CreateGeneratorObj(const ir::AstNode *node, VReg funcObj) @@ -1006,32 +1097,36 @@ void PandaGen::CreateGeneratorObj(const ir::AstNode *node, VReg funcObj) void PandaGen::CreateAsyncGeneratorObj(const ir::AstNode *node, VReg funcObj) { - ra_.Emit(node, funcObj); + // commented for compile workaround + // ra_.Emit(node, funcObj); } -void PandaGen::CreateIterResultObject(const ir::AstNode *node, bool done) +void PandaGen::CreateIterResultObject(const ir::AstNode *node, VReg value, VReg done) { - ra_.Emit(node, static_cast(done)); + ra_.Emit(node, value, done); } -void PandaGen::SuspendGenerator(const ir::AstNode *node, VReg genObj) +void PandaGen::SuspendGenerator(const ir::AstNode *node, VReg genObj, VReg iterResult) { - ra_.Emit(node, genObj); + ra_.Emit(node, genObj, iterResult); } void PandaGen::SuspendAsyncGenerator(const ir::AstNode *node, VReg asyncGenObj) { - ra_.Emit(node, asyncGenObj); + // commented for compile workaround + // ra_.Emit(node, asyncGenObj); } void PandaGen::GeneratorYield(const ir::AstNode *node, VReg genObj) { - ra_.Emit(node, genObj, static_cast(GeneratorState::SUSPENDED_YIELD)); + // commented for compile workaround + // ra_.Emit(node, genObj, static_cast(GeneratorState::SUSPENDED_YIELD)); } void PandaGen::GeneratorComplete(const ir::AstNode *node, VReg genObj) { - ra_.Emit(node, genObj, static_cast(GeneratorState::COMPLETED)); + // commented for compile workaround + // ra_.Emit(node, genObj, static_cast(GeneratorState::COMPLETED)); } void PandaGen::ResumeGenerator(const ir::AstNode *node, VReg genObj) @@ -1049,29 +1144,32 @@ void PandaGen::AsyncFunctionEnter(const ir::AstNode *node) sa_.Emit(node); } -void PandaGen::AsyncFunctionAwait(const ir::AstNode *node, VReg asyncFuncObj) +void PandaGen::AsyncFunctionAwait(const ir::AstNode *node, VReg asyncFuncObj, VReg retVal) { - ra_.Emit(node, asyncFuncObj); + ra_.Emit(node, asyncFuncObj, retVal); } -void PandaGen::AsyncFunctionResolve(const ir::AstNode *node, VReg asyncFuncObj) +void PandaGen::AsyncFunctionResolve(const ir::AstNode *node, VReg asyncFuncObj, VReg canSuspend, VReg value) { - ra_.Emit(node, asyncFuncObj); + ra_.Emit(node, asyncFuncObj, canSuspend, value); } void PandaGen::AsyncFunctionReject(const ir::AstNode *node, VReg asyncFuncObj) { - ra_.Emit(node, asyncFuncObj); + // commented for compile workaround + // ra_.Emit(node, asyncFuncObj); } void PandaGen::AsyncGeneratorResolve(const ir::AstNode *node, VReg asyncGenObj) { - ra_.Emit(node, asyncGenObj); + // commented for compile workaround + // ra_.Emit(node, asyncGenObj); } void PandaGen::AsyncGeneratorReject(const ir::AstNode *node, VReg asyncGenObj) { - ra_.Emit(node, asyncGenObj); + // commented for compile workaround + // ra_.Emit(node, asyncGenObj); } void PandaGen::GetTemplateObject(const ir::AstNode *node, VReg value) @@ -1216,7 +1314,7 @@ void PandaGen::CreateArray(const ir::AstNode *node, const ArenaVectorIsOmittedExpression()) { elem->Compile(this); - StOwnByValue(elem, obj, idxReg); + StOwnByValue(elem, obj, idxReg, false); } Unary(elem, lexer::TokenType::PUNCTUATOR_PLUS_PLUS, idxReg); @@ -1230,7 +1328,7 @@ void PandaGen::CreateArray(const ir::AstNode *node, const ArenaVector(node, array, index); } -void PandaGen::ThrowIfNotObject(const ir::AstNode *node) +void PandaGen::ThrowIfNotObject(const ir::AstNode *node, VReg obj) { - ra_.Emit(node); + ra_.Emit(node, obj); } void PandaGen::ThrowThrowNotExist(const ir::AstNode *node) @@ -1258,17 +1356,20 @@ void PandaGen::GetIterator(const ir::AstNode *node) void PandaGen::GetAsyncIterator(const ir::AstNode *node) { - sa_.Emit(node); + // commented for compile workaround + // sa_.Emit(node); } void PandaGen::CreateObjectWithExcludedKeys(const ir::AstNode *node, VReg obj, VReg argStart, size_t argCount) { ASSERT(argStart == obj + 1); if (argCount == 0) { // Do not emit undefined register - argStart = obj; + LoadConst(node, Constant::JS_UNDEFINED); + StoreAccumulator(node, argStart); } - rra_.Emit(node, argStart, argCount, static_cast(argCount), obj, + size_t argRegCnt = (argCount == 0 ? argCount : argCount - 1); + rra_.Emit(node, argStart, argCount, static_cast(argRegCnt), obj, argStart); } @@ -1282,34 +1383,29 @@ void PandaGen::CloseIterator(const ir::AstNode *node, VReg iter) ra_.Emit(node, iter); } -void PandaGen::ImportModule(const ir::AstNode *node, const util::StringView &name) -{ - sa_.Emit(node, name); - strings_.insert(name); -} - void PandaGen::DefineClassWithBuffer(const ir::AstNode *node, const util::StringView &ctorId, int32_t litIdx, - VReg lexenv, VReg base) + VReg lexenv, VReg base, int64_t formalParamCnt) { - ra_.Emit(node, ctorId, litIdx, lexenv, base); + ra_.Emit(node, ctorId, litIdx, formalParamCnt, lexenv, base); strings_.insert(ctorId); } -void PandaGen::LoadModuleVariable(const ir::AstNode *node, VReg module, const util::StringView &name) +void PandaGen::LoadModuleVariable(const ir::AstNode *node, const util::StringView &name, bool isLocalExport) { - ra_.Emit(node, name, module); + ra_.Emit(node, name, isLocalExport ? static_cast(1) : static_cast(0)); strings_.insert(name); } -void PandaGen::StoreModuleVar(const ir::AstNode *node, const util::StringView &name) +void PandaGen::StoreModuleVariable(const ir::AstNode *node, const util::StringView &name) { sa_.Emit(node, name); strings_.insert(name); } -void PandaGen::CopyModule(const ir::AstNode *node, VReg module) +void PandaGen::GetModuleNamespace(const ir::AstNode *node, const util::StringView &name) { - ra_.Emit(node, module); + sa_.Emit(node, name); + strings_.insert(name); } void PandaGen::StSuperByName(const ir::AstNode *node, VReg obj, const util::StringView &key) @@ -1384,9 +1480,14 @@ void PandaGen::LoadLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t sa_.Emit(node, level, slot); } -void PandaGen::StoreLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot) +void PandaGen::StoreLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot, VReg toAllocVreg) { - ra_.Emit(node, level, slot); + VReg value = toAllocVreg; + if (toAllocVreg == 0) { + value = AllocReg(); + } + StoreAccumulator(node, value); + ra_.Emit(node, level, slot, value); } void PandaGen::ThrowIfSuperNotCorrectCall(const ir::AstNode *node, int64_t num) @@ -1396,13 +1497,22 @@ void PandaGen::ThrowIfSuperNotCorrectCall(const ir::AstNode *node, int64_t num) void PandaGen::ThrowUndefinedIfHole(const ir::AstNode *node, const util::StringView &name) { - ra_.Emit(node, name); + VReg holeReg = AllocReg(); + StoreAccumulator(node, holeReg); + LoadAccumulatorString(node, name); + VReg nameReg = AllocReg(); + StoreAccumulator(node, nameReg); + ra_.Emit(node, holeReg, nameReg); + LoadAccumulator(node, holeReg); strings_.insert(name); } void PandaGen::ThrowConstAssignment(const ir::AstNode *node, const util::StringView &name) { - ra_.Emit(node, name); + LoadAccumulatorString(node, name); + VReg nameReg = AllocReg(); + StoreAccumulator(node, nameReg); + ra_.Emit(node, nameReg); strings_.insert(name); } @@ -1411,9 +1521,12 @@ void PandaGen::PopLexEnv(const ir::AstNode *node) sa_.Emit(node); } -void PandaGen::CopyLexEnv(const ir::AstNode *node) +void PandaGen::CopyLexEnv(const ir::AstNode *node, uint32_t num) { - sa_.Emit(node); + // commented for compile workaround + PopLexEnv(node); + NewLexEnv(node, num); + // sa_.Emit(node); } void PandaGen::NewLexEnv(const ir::AstNode *node, uint32_t num) @@ -1459,11 +1572,15 @@ Operand PandaGen::ToNamedPropertyKey(const ir::Expression *prop, bool isComputed { VReg res {0}; - if (!isComputed) { - if (prop->IsIdentifier()) { - return prop->AsIdentifier()->Name(); - } - } else if (prop->IsStringLiteral()) { + if (isComputed) { + return res; + } + + if (prop->IsIdentifier()) { + return prop->AsIdentifier()->Name(); + } + + if (prop->IsStringLiteral()) { const util::StringView &str = prop->AsStringLiteral()->Str(); /* TODO(dbatyai): remove this when runtime handles __proto__ as property name correctly */ @@ -1477,7 +1594,9 @@ Operand PandaGen::ToNamedPropertyKey(const ir::Expression *prop, bool isComputed } return str; - } else if (prop->IsNumberLiteral()) { + } + + if (prop->IsNumberLiteral()) { auto num = prop->AsNumberLiteral()->Number(); if (util::Helpers::IsIndex(num)) { return static_cast(num); @@ -1523,4 +1642,22 @@ VReg PandaGen::LoadPropertyKey(const ir::Expression *prop, bool isComputed) return propReg; } +void PandaGen::StLetToGlobalRecord(const ir::AstNode *node, const util::StringView &name) +{ + sa_.Emit(node, name); + strings_.insert(name); +} + +void PandaGen::StConstToGlobalRecord(const ir::AstNode *node, const util::StringView &name) +{ + sa_.Emit(node, name); + strings_.insert(name); +} + +void PandaGen::StClassToGlobalRecord(const ir::AstNode *node, const util::StringView &name) +{ + sa_.Emit(node, name); + strings_.insert(name); +} + } // namespace panda::es2panda::compiler diff --git a/es2panda/compiler/core/pandagen.h b/es2panda/compiler/core/pandagen.h index eefd2e4b24180c09cf99b988a6a7f24cd2927186..eb061e0b3dd52d8132a89e8efa5007a7d5a03c78 100644 --- a/es2panda/compiler/core/pandagen.h +++ b/es2panda/compiler/core/pandagen.h @@ -174,6 +174,11 @@ public: return buffStorage_; } + int32_t ModuleBuffIndex() const + { + return moduleBuffIndex_; + } + uint32_t IcSize() const { return ic_.Size(); @@ -198,6 +203,7 @@ public: LiteralBuffer *NewLiteralBuffer(); int32_t AddLiteralBuffer(LiteralBuffer *buf); + void SetModuleRecordBufferIndex(); void InitializeLexEnv(const ir::AstNode *node, VReg lexEnv); void CopyFunctionArguments(const ir::AstNode *node); @@ -206,7 +212,12 @@ public: 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 StoreVar(const ir::AstNode *node, const binder::ScopeFindResult &result, + bool isDeclaration, bool isInSetClassProto = false); + + void StLetToGlobalRecord(const ir::AstNode *node, const util::StringView &name); + void StConstToGlobalRecord(const ir::AstNode *node, const util::StringView &name); + void StClassToGlobalRecord(const ir::AstNode *node, const util::StringView &name); void StoreAccumulator(const ir::AstNode *node, VReg vreg); void LoadAccFromArgs(const ir::AstNode *node); @@ -215,7 +226,7 @@ public: 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 StoreOwnProperty(const ir::AstNode *node, VReg obj, const Operand &prop, const bool nameSetting = false); 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); @@ -234,6 +245,7 @@ public: 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 LoadAccumulatorBigInt(const ir::AstNode *node, const util::StringView &num); void LoadConst(const ir::AstNode *node, Constant id); void StoreConst(const ir::AstNode *node, VReg reg, Constant id); @@ -250,12 +262,13 @@ public: void Binary(const ir::AstNode *node, lexer::TokenType op, VReg lhs); void BranchIfUndefined(const ir::AstNode *node, class Label *target); + void BranchIfStrictNotUndefined(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 BranchIfNotFalse(const ir::AstNode *node, class Label *target); void EmitThrow(const ir::AstNode *node); void EmitRethrow(const ir::AstNode *node); @@ -266,14 +279,14 @@ public: 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 CallThis(const ir::AstNode *node, std::vector ®s); + void Call(const ir::AstNode *node, std::vector ®s); 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 NewObject(const ir::AstNode *node, std::vector ®s); void DefineFunction(const ir::AstNode *node, const ir::ScriptFunction *realNode, const util::StringView &name); void TypeOf(const ir::AstNode *node); @@ -281,7 +294,6 @@ public: 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); @@ -289,16 +301,16 @@ public: 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 AsyncFunctionAwait(const ir::AstNode *node, VReg asyncFuncObj, VReg retVal); + void AsyncFunctionResolve(const ir::AstNode *node, VReg asyncFuncObj, VReg canSuspend, VReg value); 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 CreateIterResultObject(const ir::AstNode *node, VReg value, VReg done); + void SuspendGenerator(const ir::AstNode *node, VReg genObj, VReg iterResult); void SuspendAsyncGenerator(const ir::AstNode *node, VReg asyncGenObj); void AsyncGeneratorResolve(const ir::AstNode *node, VReg asyncGenObj); @@ -321,7 +333,7 @@ public: 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 ThrowIfNotObject(const ir::AstNode *node, VReg obj); void ThrowThrowNotExist(const ir::AstNode *node); void GetIterator(const ir::AstNode *node); void GetAsyncIterator(const ir::AstNode *node); @@ -329,13 +341,12 @@ public: 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 DefineClassWithBuffer(const ir::AstNode *node, const util::StringView &ctorId, int32_t litIdx, + VReg lexenv, VReg base, int64_t formalParamCnt); - 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 LoadModuleVariable(const ir::AstNode *node, const util::StringView &name, bool isLocalExport); + void StoreModuleVariable(const ir::AstNode *node, const util::StringView &name); + void GetModuleNamespace(const ir::AstNode *node, const util::StringView &name); void StSuperByName(const ir::AstNode *node, VReg obj, const util::StringView &key); void LdSuperByName(const ir::AstNode *node, VReg obj, const util::StringView &key); @@ -346,10 +357,10 @@ public: void LdLexEnv(const ir::AstNode *node); void PopLexEnv(const ir::AstNode *node); - void CopyLexEnv(const ir::AstNode *node); + void CopyLexEnv(const ir::AstNode *node, uint32_t num); 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 StoreLexicalVar(const ir::AstNode *node, uint32_t level, uint32_t slot, VReg toAllocVreg = 0); void ThrowIfSuperNotCorrectCall(const ir::AstNode *node, int64_t num); void ThrowUndefinedIfHole(const ir::AstNode *node, const util::StringView &name); @@ -366,8 +377,8 @@ public: 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 StOwnByName(const ir::AstNode *node, VReg obj, const util::StringView &prop, const bool nameSetting); + void StOwnByValue(const ir::AstNode *node, VReg obj, VReg prop, const bool nameSetting); void StOwnByIndex(const ir::AstNode *node, VReg obj, int64_t index); static Operand ToNamedPropertyKey(const ir::Expression *prop, bool isComputed); @@ -403,6 +414,7 @@ private: RegAllocator ra_; RangeRegAllocator rra_; + int32_t moduleBuffIndex_ {-1}; uint32_t usedRegs_ {0}; uint32_t totalRegs_ {0}; friend class ScopeContext; diff --git a/es2panda/compiler/core/regAllocator.cpp b/es2panda/compiler/core/regAllocator.cpp index 7ed5763f5499b520da2aff1128a28b73cacc06a7..42113993e41b02adb7b232fdb5632a5c2df1dd5d 100644 --- a/es2panda/compiler/core/regAllocator.cpp +++ b/es2panda/compiler/core/regAllocator.cpp @@ -72,7 +72,7 @@ void RegAllocatorBase::Restore(IRNode *ins) VReg spillReg = spillIndex_; VReg origin = regEnd_ + spillIndex_; - Add(ins->Node(), origin, spillReg); + Add(ins->Node(), spillReg, origin); } // RegAllocator @@ -110,6 +110,56 @@ void RegAllocator::Run(IRNode *ins) } // RangeRegAllocator +bool RangeRegAllocator::CheckRegContinuous(std::vector &inputRegs) +{ + VReg startReg = inputRegs[0]; + for (size_t i = 0; i < inputRegs.size(); i++) { + if (inputRegs[i] != startReg++) { + return false; + } + } + return true; +} + +void RangeRegAllocator::Run(IRNode *ins, std::vector &inputRegs) +{ + ASSERT(spillIndex_ == 0); + std::array regs {}; + auto regCnt = ins->Registers(®s); + auto registers = Span(regs.data(), regs.data() + regCnt); + + if (CheckRegIndices(ins, registers) && CheckRegContinuous(inputRegs)) { + PushBack(ins); + return; + } + + RegScope regScope(pg_); + + regEnd_ = pg_->NextReg(); + + auto *iter = registers.begin(); + auto *iter_end = iter + registers.size() - 1; + + while (iter != iter_end) { + VReg *reg = *iter; + + const auto actual_reg = *reg; + *reg = Spill(ins, actual_reg); + iter++; + } + + VReg *regStartReg = *iter; + *regStartReg = Spill(ins, inputRegs[0]); + for (size_t i = 1; i < inputRegs.size(); ++i) { + Spill(ins, inputRegs[i]); + } + + PushBack(ins); + + while (spillIndex_ != 0) { + Restore(ins); + } +} void RangeRegAllocator::Run(IRNode *ins, VReg rangeStart, size_t argCount) { diff --git a/es2panda/compiler/core/regAllocator.h b/es2panda/compiler/core/regAllocator.h index ec7bfefc6382d6886e243e69f430db24178f97a5..a5502d3003c4f3145e51b78c57616be4fcb6d23a 100644 --- a/es2panda/compiler/core/regAllocator.h +++ b/es2panda/compiler/core/regAllocator.h @@ -158,8 +158,17 @@ public: Run(ins, rangeStart, argCount); } + template + void Emit(const ir::AstNode *node, std::vector ®s, Args &&... args) + { + auto *ins = Alloc(node, std::forward(args)...); + Run(ins, regs); + } + private: void Run(IRNode *ins, VReg rangeStart, size_t argCount); + void Run(IRNode *ins, std::vector &inputRegs); + bool CheckRegContinuous(std::vector &inputRegs); }; } // namespace panda::es2panda::compiler diff --git a/es2panda/compiler/core/regScope.cpp b/es2panda/compiler/core/regScope.cpp index 588340ed6b4b47818e86663c4e2567f64498c294..5ab2003699e0f336b3cb997d5236dbe7d1b78dcc 100644 --- a/es2panda/compiler/core/regScope.cpp +++ b/es2panda/compiler/core/regScope.cpp @@ -16,12 +16,12 @@ #include "regScope.h" #include +#include #include #include #include #include #include -#include namespace panda::es2panda::compiler { @@ -114,11 +114,19 @@ FunctionRegScope::FunctionRegScope(PandaGen *pg) : RegScope(pg), envScope_(pg->A pg_->LoadAccFromArgs(pg_->rootNode_); - if (funcScope->IsModuleScope()) { - ModuleContext::Compile(pg_, pg_->scope_->AsModuleScope()); - } - Hoisting::Hoist(pg); + + if (pg_->TopScope()->IsModuleScope()) { + binder::SourceTextModuleRecord *moduleRecord = pg_->TopScope()->AsModuleScope()->GetModuleRecord(); + for (auto nameSpaceEntry : moduleRecord->GetNamespaceImportEntries()) { + pg_->GetModuleNamespace(nameSpaceEntry->moduleNode, nameSpaceEntry->localName); + auto *var = pg_->TopScope()->FindLocal(nameSpaceEntry->localName); + ASSERT(var != nullptr); + pg_->StoreVar(nameSpaceEntry->moduleNode, + {nameSpaceEntry->localName, pg_->TopScope(), 0, var}, + true); + } + } } FunctionRegScope::~FunctionRegScope() diff --git a/es2panda/compiler/function/asyncFunctionBuilder.cpp b/es2panda/compiler/function/asyncFunctionBuilder.cpp index acbbc790ab449ea78e45f907ad6cc3d527c0c3d5..15cfe91fd62e16c0e8df68a3049350327c3777ef 100644 --- a/es2panda/compiler/function/asyncFunctionBuilder.cpp +++ b/es2panda/compiler/function/asyncFunctionBuilder.cpp @@ -23,17 +23,34 @@ namespace panda::es2panda::compiler { void AsyncFunctionBuilder::DirectReturn(const ir::AstNode *node) const { - pg_->AsyncFunctionResolve(node, funcObj_); + RegScope rs(pg_); + VReg retVal = pg_->AllocReg(); + VReg canSuspend = pg_->AllocReg(); + + pg_->StoreAccumulator(node, retVal); + pg_->LoadConst(node, Constant::JS_TRUE); + pg_->StoreAccumulator(node, canSuspend); + pg_->AsyncFunctionResolve(node, funcObj_, canSuspend, retVal); + // pg_->LoadAccumulator(node, retVal); + // pg_->AsyncFunctionResolve(node, funcObj_); pg_->EmitReturn(node); } void AsyncFunctionBuilder::ImplicitReturn(const ir::AstNode *node) const { + RegScope rs(pg_); + VReg retVal = pg_->AllocReg(); + VReg canSuspend = pg_->AllocReg(); + + pg_->LoadConst(node, Constant::JS_TRUE); + pg_->StoreAccumulator(node, canSuspend); pg_->LoadConst(node, Constant::JS_UNDEFINED); - DirectReturn(node); + pg_->StoreAccumulator(node, retVal); + pg_->AsyncFunctionResolve(node, funcObj_, canSuspend, retVal); + pg_->EmitReturn(node); } -void AsyncFunctionBuilder::Prepare(const ir::ScriptFunction *node) const +void AsyncFunctionBuilder::Prepare(const ir::ScriptFunction *node) { pg_->AsyncFunctionEnter(node); pg_->StoreAccumulator(node, funcObj_); diff --git a/es2panda/compiler/function/asyncFunctionBuilder.h b/es2panda/compiler/function/asyncFunctionBuilder.h index bd7f38a81456a69877e83c58318ab9670dec20ba..68bdd99433f8cf94781f210ba5ca6842d8af09cb 100644 --- a/es2panda/compiler/function/asyncFunctionBuilder.h +++ b/es2panda/compiler/function/asyncFunctionBuilder.h @@ -30,7 +30,7 @@ public: NO_COPY_SEMANTIC(AsyncFunctionBuilder); NO_MOVE_SEMANTIC(AsyncFunctionBuilder); - void Prepare(const ir::ScriptFunction *node) const override; + void Prepare(const ir::ScriptFunction *node) override; void CleanUp(const ir::ScriptFunction *node) const override; void DirectReturn(const ir::AstNode *node) const override; diff --git a/es2panda/compiler/function/asyncGeneratorFunctionBuilder.cpp b/es2panda/compiler/function/asyncGeneratorFunctionBuilder.cpp index c4360cd87af39409aa8692c5872f7498320848e7..18396ce3766862e08606d10819b69af899ff93e1 100644 --- a/es2panda/compiler/function/asyncGeneratorFunctionBuilder.cpp +++ b/es2panda/compiler/function/asyncGeneratorFunctionBuilder.cpp @@ -20,13 +20,13 @@ #include namespace panda::es2panda::compiler { -void AsyncGeneratorFunctionBuilder::Prepare(const ir::ScriptFunction *node) const +void AsyncGeneratorFunctionBuilder::Prepare(const ir::ScriptFunction *node) { VReg callee = FunctionReg(node); pg_->CreateAsyncGeneratorObj(node, callee); pg_->StoreAccumulator(node, funcObj_); - pg_->SuspendGenerator(node, funcObj_); + // pg_->SuspendGenerator(node, funcObj_); pg_->SetLabel(node, catchTable_->LabelSet().TryBegin()); } @@ -72,7 +72,7 @@ void AsyncGeneratorFunctionBuilder::Yield(const ir::AstNode *node) 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_); + pg_->AsyncFunctionAwait(node, funcObj_, completionValue); SuspendResumeExecution(node, completionType, completionValue); // 27.6.3.8.8.c. If awaited.[[Type]] is throw, return Completion(awaited). diff --git a/es2panda/compiler/function/asyncGeneratorFunctionBuilder.h b/es2panda/compiler/function/asyncGeneratorFunctionBuilder.h index f492da49d1f4428945821d5f1a4fae51c75c7b91..8ae591a79c41b90324fb45d62f41ed5284df1f29 100644 --- a/es2panda/compiler/function/asyncGeneratorFunctionBuilder.h +++ b/es2panda/compiler/function/asyncGeneratorFunctionBuilder.h @@ -30,7 +30,7 @@ public: NO_COPY_SEMANTIC(AsyncGeneratorFunctionBuilder); NO_MOVE_SEMANTIC(AsyncGeneratorFunctionBuilder); - void Prepare(const ir::ScriptFunction *node) const override; + void Prepare(const ir::ScriptFunction *node) override; void CleanUp(const ir::ScriptFunction *node) const override; void DirectReturn(const ir::AstNode *node) const override; diff --git a/es2panda/compiler/function/functionBuilder.cpp b/es2panda/compiler/function/functionBuilder.cpp index eaba22a71aaada4722e54db98adba4d474341bc6..53993e51ade8e2512dd812c43ffe05306c4fe16e 100644 --- a/es2panda/compiler/function/functionBuilder.cpp +++ b/es2panda/compiler/function/functionBuilder.cpp @@ -67,8 +67,10 @@ void FunctionBuilder::SuspendResumeExecution(const ir::AstNode *node, VReg compl { ASSERT(BuilderKind() == BuilderType::ASYNC || BuilderKind() == BuilderType::ASYNC_GENERATOR || BuilderKind() == BuilderType::GENERATOR); - - pg_->SuspendGenerator(node, funcObj_); + RegScope rs(pg_); + VReg iterResult = pg_->AllocReg(); + pg_->StoreAccumulator(node, iterResult); + pg_->SuspendGenerator(node, funcObj_, iterResult); resumeGenerator(node, completionType, completionValue); } @@ -103,11 +105,27 @@ void FunctionBuilder::Await(const ir::AstNode *node) RegScope rs(pg_); VReg completionType = pg_->AllocReg(); VReg completionValue = pg_->AllocReg(); + VReg retVal = pg_->AllocReg(); - pg_->AsyncFunctionAwait(node, funcObj_); + pg_->StoreAccumulator(node, retVal); + pg_->AsyncFunctionAwait(node, funcObj_, retVal); SuspendResumeExecution(node, completionType, completionValue); - HandleCompletion(node, completionType, completionValue); + HandleAsyncCompletion(node, completionType, completionValue); +} + +void FunctionBuilder::HandleAsyncCompletion(const ir::AstNode *node, VReg completionType, VReg completionValue) +{ + // .reject + auto *notThrowLabel = pg_->AllocLabel(); + pg_->LoadAccumulatorInt(node, static_cast(ResumeMode::THROW)); + pg_->Condition(node, lexer::TokenType::PUNCTUATOR_EQUAL, completionType, notThrowLabel); + pg_->LoadAccumulator(node, completionValue); + pg_->EmitThrow(node); + + //.resolve + pg_->SetLabel(node, notThrowLabel); + pg_->LoadAccumulator(node, completionValue); } void FunctionBuilder::HandleCompletion(const ir::AstNode *node, VReg completionType, VReg completionValue) @@ -225,7 +243,7 @@ void FunctionBuilder::YieldStar(const ir::AstNode *node) // 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(); + iterator.CallMethodWithValue(receivedValue); // ii. ii. If generatorKind is async, set innerResult to ? Await(innerResult). // 2. If generatorKind is async, set innerResult to ? Await(innerResult). @@ -239,7 +257,7 @@ void FunctionBuilder::YieldStar(const ir::AstNode *node) // 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); + pg_->ThrowIfNotObject(node, receivedValue); // iv. Let done be ? IteratorComplete(innerResult). // v. Let done be ? IteratorComplete(innerResult). @@ -265,7 +283,7 @@ void FunctionBuilder::YieldStar(const ir::AstNode *node) // b. Let awaited be Await(resumptionValue.[[Value]]). pg_->LoadAccumulator(node, receivedValue); - pg_->AsyncFunctionAwait(node, funcObj_); + pg_->AsyncFunctionAwait(node, funcObj_, receivedValue); SuspendResumeExecution(node, receivedType, receivedValue); // c. If awaited.[[Type]] is throw, return Completion(awaited). diff --git a/es2panda/compiler/function/functionBuilder.h b/es2panda/compiler/function/functionBuilder.h index 4147c49577a673a71ea7f8ee198bc1e2158443ce..ca01fe94b9bc64c6257d37135427712422ded36f 100644 --- a/es2panda/compiler/function/functionBuilder.h +++ b/es2panda/compiler/function/functionBuilder.h @@ -49,7 +49,7 @@ public: NO_COPY_SEMANTIC(FunctionBuilder); NO_MOVE_SEMANTIC(FunctionBuilder); - virtual void Prepare([[maybe_unused]] const ir::ScriptFunction *node) const {}; + virtual void Prepare([[maybe_unused]] const ir::ScriptFunction *node) {}; virtual void CleanUp([[maybe_unused]] const ir::ScriptFunction *node) const {}; virtual void DirectReturn(const ir::AstNode *node) const; @@ -76,6 +76,7 @@ protected: VReg FunctionReg(const ir::ScriptFunction *node) const; void HandleCompletion(const ir::AstNode *node, VReg completionType, VReg completionValue); + void HandleAsyncCompletion(const ir::AstNode *node, VReg completionType, VReg completionValue); PandaGen *pg_; CatchTable *catchTable_; diff --git a/es2panda/compiler/function/generatorFunctionBuilder.cpp b/es2panda/compiler/function/generatorFunctionBuilder.cpp index a4d71b3fd2dac50aded1c33cabc31d89dac78a15..2ea213b1a6b3e066971363a3b9cdd939e9719de1 100644 --- a/es2panda/compiler/function/generatorFunctionBuilder.cpp +++ b/es2panda/compiler/function/generatorFunctionBuilder.cpp @@ -21,14 +21,16 @@ namespace panda::es2panda::compiler { -void GeneratorFunctionBuilder::Prepare(const ir::ScriptFunction *node) const +void GeneratorFunctionBuilder::Prepare(const ir::ScriptFunction *node) { VReg callee = FunctionReg(node); - + VReg completionType = pg_->AllocReg(); + VReg completionValue = pg_->AllocReg(); pg_->CreateGeneratorObj(node, callee); pg_->StoreAccumulator(node, funcObj_); - pg_->SuspendGenerator(node, funcObj_); - pg_->SetLabel(node, catchTable_->LabelSet().TryBegin()); + pg_->LoadConst(node, Constant::JS_UNDEFINED); + SuspendResumeExecution(node, completionType, completionValue); + HandleCompletion(node, completionType, completionValue); } void GeneratorFunctionBuilder::CleanUp(const ir::ScriptFunction *node) const @@ -44,8 +46,6 @@ void GeneratorFunctionBuilder::CleanUp(const ir::ScriptFunction *node) const void GeneratorFunctionBuilder::DirectReturn(const ir::AstNode *node) const { - pg_->GeneratorComplete(node, funcObj_); - pg_->CreateIterResultObject(node, true); pg_->EmitReturn(node); } @@ -58,13 +58,16 @@ void GeneratorFunctionBuilder::ImplicitReturn(const ir::AstNode *node) const void GeneratorFunctionBuilder::Yield(const ir::AstNode *node) { RegScope rs(pg_); + VReg value = pg_->AllocReg(); + VReg done = pg_->AllocReg(); VReg completionType = pg_->AllocReg(); VReg completionValue = pg_->AllocReg(); - pg_->CreateIterResultObject(node, false); - pg_->GeneratorYield(node, funcObj_); + pg_->StoreAccumulator(node, value); + pg_->LoadConst(node, Constant::JS_FALSE); + pg_->StoreAccumulator(node, done); + pg_->CreateIterResultObject(node, value, done); SuspendResumeExecution(node, completionType, completionValue); - HandleCompletion(node, completionType, completionValue); } diff --git a/es2panda/compiler/function/generatorFunctionBuilder.h b/es2panda/compiler/function/generatorFunctionBuilder.h index a1a12295654cff025fcd0754b8d1cd116074ecff..6b3b96acb38608325ffc00b5426909e807f617db 100644 --- a/es2panda/compiler/function/generatorFunctionBuilder.h +++ b/es2panda/compiler/function/generatorFunctionBuilder.h @@ -44,7 +44,7 @@ public: NO_COPY_SEMANTIC(GeneratorFunctionBuilder); NO_MOVE_SEMANTIC(GeneratorFunctionBuilder); - void Prepare(const ir::ScriptFunction *node) const override; + void Prepare(const ir::ScriptFunction *node) override; void CleanUp(const ir::ScriptFunction *node) const override; void DirectReturn(const ir::AstNode *node) const override; diff --git a/es2panda/es2abc_config.gni b/es2panda/es2abc_config.gni new file mode 100644 index 0000000000000000000000000000000000000000..b785818b306b4dfbeff3a10008c071950205efea --- /dev/null +++ b/es2panda/es2abc_config.gni @@ -0,0 +1,102 @@ +# 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. + +if (defined(ark_independent_build)) { + import("$build_root/ark.gni") + es2abc_root = "//ts2abc/es2panda" +} else { + import("//build/ohos.gni") + build_root = "//build" + es2abc_root = "//ark/ts2abc/es2panda" +} + + +toolchain_linux = "$build_root/toolchain/linux:clang_x64" +if (host_cpu == "arm64") { + toolchain_mac = "$build_root/toolchain/mac:clang_arm64" +} else { + toolchain_mac = "$build_root/toolchain/mac:clang_x64" +} +toolchain_win = "$build_root/toolchain/mingw:mingw_x86_64" + +es2abc_build_path = "" +es2abc_build_deps = "" +es2abc_out_root = "" + +if (host_toolchain == toolchain_mac) { + es2abc_out_root = get_label_info("$es2abc_root:es2panda($toolchain_mac)", + "root_out_dir") + es2abc_build_deps = [ "$es2abc_root:es2panda($toolchain_mac)" ] +} else if (host_toolchain == toolchain_win) { + es2abc_out_root = get_label_info("$es2abc_root:es2panda($toolchain_win)", + "root_out_dir") + es2abc_build_deps = [ "$es2abc_root:es2panda($toolchain_win)" ] +} else { + es2abc_out_root = get_label_info("$es2abc_root:es2panda($toolchain_linux)", + "root_out_dir") + es2abc_build_deps = [ "$es2abc_root:es2panda($toolchain_linux)" ] +} +es2abc_build_path = es2abc_out_root + "/ark/ark" + +# Generate abc. +# +# Mandatory arguments: +# plugin_path -- plugin js file path +# plugin_name -- name of js file, ex: BatteryPlugin.js +# generat_file -- name of generated file +# package_name -- name of generated file's package +# extra_dependencies -- a list of files that should be considered as dependencies, must be label +# out_puts +template("es2abc_gen_abc") { + assert(defined(invoker.src_js), "src_js is required!") + assert(defined(invoker.dst_file), "dst_file is required!") + assert(defined(invoker.out_puts), "out_puts is required!") + + print("${es2abc_build_path}") + extra_dependencies = [] + if (defined(invoker.extra_dependencies)) { + extra_dependencies += invoker.extra_dependencies + } + + action("$target_name") { + if (defined(invoker.extra_visibility)) { + visibility = invoker.extra_visibility + } + + print() + + script = "${es2abc_root}/scripts/generate_js_bytecode.py" # need to write a new python script + + deps = extra_dependencies + deps += es2abc_build_deps + + args = [ + "--src-js", + invoker.src_js, + "--dst-file", + invoker.dst_file, + "--frontend-tool-path", + rebase_path("${es2abc_build_path}"), + ] + + if (defined(invoker.extra_args)) { + args += invoker.extra_args + } + + if (defined(invoker.in_puts)) { + inputs = invoker.in_puts + } + + outputs = invoker.out_puts + } +} \ No newline at end of file diff --git a/es2panda/ir/base/classDefinition.cpp b/es2panda/ir/base/classDefinition.cpp index bd18a40d3425b32ea918bd40b81e76f83b0d36a3..5797d2036577589572174d9d2c9a8caf03f4bc6a 100644 --- a/es2panda/ir/base/classDefinition.cpp +++ b/es2panda/ir/base/classDefinition.cpp @@ -120,6 +120,7 @@ int32_t ClassDefinition::CreateClassStaticProperties(compiler::PandaGen *pg, uti auto *buf = pg->NewLiteralBuffer(); compiler::LiteralBuffer staticBuf(pg->Allocator()); bool seenComputed = false; + uint32_t unstaticNum = 0; std::unordered_map propNameMap; std::unordered_map staticPropNameMap; @@ -131,12 +132,20 @@ int32_t ClassDefinition::CreateClassStaticProperties(compiler::PandaGen *pg, uti } const ir::MethodDefinition *prop = properties[i]->AsMethodDefinition(); - if (!util::Helpers::IsConstantPropertyKey(prop->Key(), prop->Computed()) || - (prop->Computed() && util::Helpers::IsSpecialPropertyKey(prop->Key()))) { + // if (!util::Helpers::IsConstantPropertyKey(prop->Key(), prop->Computed()) || + // (prop->Computed() && util::Helpers::IsSpecialPropertyKey(prop->Key()))) { + // seenComputed = true; + // continue; + // } + if (prop->Computed()) { seenComputed = true; continue; } + if (prop->IsAccessor()) { + break; + } + util::StringView name = util::Helpers::LiteralToPropName(prop->Key()); compiler::LiteralBuffer *literalBuf = prop->IsStatic() ? &staticBuf : buf; auto &nameMap = prop->IsStatic() ? staticPropNameMap : propNameMap; @@ -150,6 +159,7 @@ int32_t ClassDefinition::CreateClassStaticProperties(compiler::PandaGen *pg, uti literalBuf->Add(pg->Allocator()->New(name)); literalBuf->Add(nullptr); + literalBuf->Add(nullptr); } else { bufferPos = res.first->second; } @@ -163,11 +173,15 @@ int32_t ClassDefinition::CreateClassStaticProperties(compiler::PandaGen *pg, uti value = pg->Allocator()->New(LiteralTag::METHOD, internalName); compiled.Set(i); + literalBuf->ResetLiteral(bufferPos + 1, value); + Literal *methodAffiliate = pg->Allocator()->New(LiteralTag::METHODAFFILIATE, func->Function()->FormalParamsLength()); + literalBuf->ResetLiteral(bufferPos + 2, methodAffiliate); break; } case ir::MethodDefinitionKind::GET: case ir::MethodDefinitionKind::SET: { value = pg->Allocator()->New(); + literalBuf->ResetLiteral(bufferPos + 1, value); break; } default: { @@ -175,17 +189,17 @@ int32_t ClassDefinition::CreateClassStaticProperties(compiler::PandaGen *pg, uti } } - literalBuf->ResetLiteral(bufferPos + 1, value); + if (!prop->IsStatic()) { + unstaticNum++; + } } - 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(litPairs)); + buf->Add(pg->Allocator()->New(unstaticNum)); return pg->AddLiteralBuffer(buf); } @@ -212,12 +226,18 @@ void ClassDefinition::CompileMissingProperties(compiler::PandaGen *pg, const uti switch (prop->Kind()) { case ir::MethodDefinitionKind::METHOD: { compiler::Operand key = pg->ToPropertyKey(prop->Key(), prop->Computed()); - + compiler::VReg keyReg = pg->AllocReg(); + if (prop->Key()->IsIdentifier() && !prop->Computed()) { + pg->LoadAccumulatorString(this, std::get(key)); + } else { + prop->Key()->Compile(pg); + } + pg->StoreAccumulator(this, keyReg); pg->LoadAccumulator(this, dest); const ir::FunctionExpression *func = prop->Value()->AsFunctionExpression(); func->Compile(pg); - pg->StoreOwnProperty(prop->Value()->Parent(), dest, key); + pg->StoreOwnProperty(prop->Value()->Parent(), dest, keyReg, prop->Computed()); break; } case ir::MethodDefinitionKind::GET: @@ -268,9 +288,10 @@ void ClassDefinition::Compile(compiler::PandaGen *pg) const 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()); + auto formalParamCnt = Ctor()->Function()->FormalParamsLength(); + pg->DefineClassWithBuffer(this, ctorId, bufIdx, lexenv, baseReg, formalParamCnt); + if (scope_->Parent()->IsGlobalScope() && ident_ && IsStmt()) { + pg->StClassToGlobalRecord(this, ident_->Name()); } pg->StoreAccumulator(this, classReg); InitializeClassName(pg); diff --git a/es2panda/ir/base/classDefinition.h b/es2panda/ir/base/classDefinition.h index 32a1e3096cc8a835adcdb871b94d4f438f8d17a3..aa2b10a002157da90b3688f4c0dc0c9f558a47ce 100644 --- a/es2panda/ir/base/classDefinition.h +++ b/es2panda/ir/base/classDefinition.h @@ -49,7 +49,7 @@ public: TSTypeParameterInstantiation *superTypeParams, ArenaVector &&implements, MethodDefinition *ctor, Expression *superClass, ArenaVector &&body, - ArenaVector &&indexSignatures, bool declare, bool abstract) + ArenaVector &&indexSignatures, bool declare, bool abstract, bool isStmt) : AstNode(AstNodeType::CLASS_DEFINITION), scope_(scope), ident_(ident), @@ -61,7 +61,8 @@ public: body_(std::move(body)), indexSignatures_(std::move(indexSignatures)), declare_(declare), - abstract_(abstract) + abstract_(abstract), + isStmt_(isStmt) { } @@ -95,6 +96,11 @@ public: return abstract_; } + bool IsStmt() const + { + return isStmt_; + } + ArenaVector &Body() { return body_; @@ -135,6 +141,7 @@ private: ArenaVector indexSignatures_; bool declare_; bool abstract_; + bool isStmt_; }; } // namespace panda::es2panda::ir diff --git a/es2panda/ir/base/methodDefinition.h b/es2panda/ir/base/methodDefinition.h index e304cd084e23e350d8457da1bb9b7e676f6fc26b..1170e01693b500da39d45e68134bcc105aed9a82 100644 --- a/es2panda/ir/base/methodDefinition.h +++ b/es2panda/ir/base/methodDefinition.h @@ -80,6 +80,11 @@ public: return (modifiers_ & ModifierFlags::STATIC) != 0; } + bool IsAccessor() const + { + return (kind_ == MethodDefinitionKind::GET) || (kind_ == MethodDefinitionKind::SET); + } + bool IsOptional() const { return (modifiers_ & ModifierFlags::OPTIONAL) != 0; diff --git a/es2panda/ir/expressions/binaryExpression.cpp b/es2panda/ir/expressions/binaryExpression.cpp index 7423a2dfb2b77762dd586c92af91a76d97420630..5621dfe8e527df72cfb90a74986ce8464631a8d4 100644 --- a/es2panda/ir/expressions/binaryExpression.cpp +++ b/es2panda/ir/expressions/binaryExpression.cpp @@ -56,7 +56,6 @@ void BinaryExpression::CompileLogical(compiler::PandaGen *pg) const // left -> acc -> lhs -> toboolean -> acc -> bool_lhs left_->Compile(pg); pg->StoreAccumulator(this, lhs); - pg->ToBoolean(this); if (operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) { pg->BranchIfFalse(this, skipRight); diff --git a/es2panda/ir/expressions/callExpression.cpp b/es2panda/ir/expressions/callExpression.cpp index bebd28a6792c0b2889299d8e1c05299841f3b55c..c2a16ce7432a42f9d32b68a906b2e3a69a3ba7f1 100644 --- a/es2panda/ir/expressions/callExpression.cpp +++ b/es2panda/ir/expressions/callExpression.cpp @@ -106,6 +106,8 @@ void CallExpression::Compile(compiler::PandaGen *pg) const compiler::VReg callee = pg->AllocReg(); bool hasThis = false; compiler::VReg thisReg {}; + std::vector regs; + regs.push_back(callee); if (callee_->IsMemberExpression()) { hasThis = true; @@ -113,6 +115,7 @@ void CallExpression::Compile(compiler::PandaGen *pg) const compiler::RegScope mrs(pg); callee_->AsMemberExpression()->Compile(pg, thisReg); + regs.push_back(thisReg); } else { callee_->Compile(pg); } @@ -135,14 +138,15 @@ void CallExpression::Compile(compiler::PandaGen *pg) const it->Compile(pg); compiler::VReg arg = pg->AllocReg(); pg->StoreAccumulator(it, arg); + regs.push_back(arg); } if (hasThis) { - pg->CallThis(this, callee, static_cast(arguments_.size() + 1)); + pg->CallThis(this, regs); return; } - pg->Call(this, callee, arguments_.size()); + pg->Call(this, regs); } using ArgRange = std::pair; diff --git a/es2panda/ir/expressions/chainExpression.cpp b/es2panda/ir/expressions/chainExpression.cpp index 0869146030a2790ec4ab1515f6a239faffe2a89e..27e2906bfc4bbe450321a45a3de703512eda4a69 100644 --- a/es2panda/ir/expressions/chainExpression.cpp +++ b/es2panda/ir/expressions/chainExpression.cpp @@ -1,4 +1,4 @@ -/** +/* * 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. @@ -14,8 +14,11 @@ */ #include "chainExpression.h" +#include #include +#include +#include namespace panda::es2panda::ir { @@ -29,7 +32,88 @@ void ChainExpression::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "ChainExpression"}, {"expression", expression_}}); } -void ChainExpression::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void ChainExpression::Compile([[maybe_unused]] compiler::PandaGen *pg) const +{ + const MemberExpression *memberExpr = nullptr; + if (this->GetExpression()->IsMemberExpression()) { + memberExpr = this->GetExpression()->AsMemberExpression(); + } else { + auto callExpr = this->GetExpression()->AsCallExpression(); + memberExpr = callExpr->Callee()->AsMemberExpression(); + } + compiler::Label *resultLabel = nullptr; + CompileLogical(pg, memberExpr, resultLabel); + this->GetExpression()->Compile(pg); + pg->SetLabel(this, resultLabel); +} + +void ChainExpression::CompileLogical(compiler::PandaGen *pg, const MemberExpression *memberExpr, + compiler::Label *&resultLabel) const +{ + compiler::VReg falseReg = pg->AllocReg(); + compiler::VReg trueReg = pg->AllocReg(); + compiler::VReg nullReg = pg->AllocReg(); + compiler::VReg undefinedReg = pg->AllocReg(); + compiler::VReg objReg = pg->AllocReg(); + + pg->LoadConst(this, compiler::Constant::JS_FALSE); + pg->StoreAccumulator(this, falseReg); + pg->LoadConst(this, compiler::Constant::JS_TRUE); + pg->StoreAccumulator(this, trueReg); + pg->LoadConst(this, compiler::Constant::JS_NULL); + pg->StoreAccumulator(this, nullReg); + pg->LoadConst(this, compiler::Constant::JS_UNDEFINED); + pg->StoreAccumulator(this, undefinedReg); + + CheckMemberExpressionObjIfNull(pg, memberExpr, std::vector{objReg, trueReg, falseReg, nullReg}); + auto *isNullRes = pg->AllocLabel(); + pg->BranchIfNotFalse(this, isNullRes); + + CheckMemberExpressionObjIfUndefined(pg, memberExpr, + std::vector{objReg, trueReg, falseReg, undefinedReg}); + auto *isUndefinedRes = pg->AllocLabel(); + pg->BranchIfNotTrue(this, isUndefinedRes); + + pg->SetLabel(this, isNullRes); + pg->LoadAccumulatorInt(this, 0); + pg->LoadAccumulator(this, undefinedReg); + resultLabel = pg->AllocLabel(); + pg->Branch(this, resultLabel); + pg->SetLabel(this, isUndefinedRes); +} + +void ChainExpression::CheckMemberExpressionObjIfNull(compiler::PandaGen *pg, const MemberExpression *memberExpr, + std::vector regs) const +{ + auto *notNullLabel = pg->AllocLabel(); + auto *isNullLabel = pg->AllocLabel(); + + memberExpr->CompileObject(pg, regs[0]); + pg->LoadAccumulator(this, regs[3]); + pg->Condition(this, lexer::TokenType::PUNCTUATOR_STRICT_EQUAL, regs[0], notNullLabel); + pg->LoadAccumulator(this, regs[1]); + pg->Branch(this, isNullLabel); + pg->SetLabel(this, notNullLabel); + pg->LoadAccumulator(this, regs[2]); + pg->SetLabel(this, isNullLabel); +} + +void ChainExpression::CheckMemberExpressionObjIfUndefined(compiler::PandaGen *pg, const MemberExpression *memberExpr, + std::vector regs) const +{ + auto *notUndefinedLabel = pg->AllocLabel(); + auto *isUndefinedLabel = pg->AllocLabel(); + + memberExpr->CompileObject(pg, regs[0]); + pg->LoadAccumulatorInt(this, 0); + pg->LoadAccumulator(this, regs[3]); + pg->Condition(this, lexer::TokenType::PUNCTUATOR_STRICT_EQUAL, regs[0], notUndefinedLabel); + pg->LoadAccumulator(this, regs[1]); + pg->Branch(this, isUndefinedLabel); + pg->SetLabel(this, notUndefinedLabel); + pg->LoadAccumulator(this, regs[2]); + pg->SetLabel(this, isUndefinedLabel); +} checker::Type *ChainExpression::Check([[maybe_unused]] checker::Checker *checker) const { diff --git a/es2panda/ir/expressions/chainExpression.h b/es2panda/ir/expressions/chainExpression.h index 571d10c89b262f2047ce8d2b69ffc94cea95987b..3e8735bc6ae501a096f3468b256668f9727bc4ae 100644 --- a/es2panda/ir/expressions/chainExpression.h +++ b/es2panda/ir/expressions/chainExpression.h @@ -17,6 +17,7 @@ #define ES2PANDA_IR_EXPRESSION_CHAIN_EXPRESSION_H #include +#include namespace panda::es2panda::compiler { class PandaGen; @@ -44,6 +45,12 @@ public: void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; + void CompileLogical(compiler::PandaGen *pg, const MemberExpression *memberExpr, + compiler::Label *&resultLabel) const; + void CheckMemberExpressionObjIfNull(compiler::PandaGen *pg, const MemberExpression *memberExpr, + std::vector regs) const; + void CheckMemberExpressionObjIfUndefined(compiler::PandaGen *pg, const MemberExpression *memberExpr, + std::vector regs) const; checker::Type *Check([[maybe_unused]] checker::Checker *checker) const override; private: diff --git a/es2panda/ir/expressions/literal.cpp b/es2panda/ir/expressions/literal.cpp index 48cb9a94d4317a7940cc7c06ae92c416f03258de..4a021f470ff5a8323d89922856ed064cf09c6ec9 100644 --- a/es2panda/ir/expressions/literal.cpp +++ b/es2panda/ir/expressions/literal.cpp @@ -52,4 +52,10 @@ const util::StringView &Literal::GetMethod() const return AsTaggedLiteral()->Method(); } +uint16_t Literal::GetMethodAffiliate() const +{ + ASSERT(IsTaggedLiteral()); + return AsTaggedLiteral()->MethodAffiliate(); +} + } // namespace panda::es2panda::ir diff --git a/es2panda/ir/expressions/literal.h b/es2panda/ir/expressions/literal.h index ee6bc7af23e6d239b26b2b8275c6cb6428c67bb2..60912e74c3e003083eb60f17ccf87011a6f8361e 100644 --- a/es2panda/ir/expressions/literal.h +++ b/es2panda/ir/expressions/literal.h @@ -31,17 +31,18 @@ namespace panda::es2panda::ir { // must be kept in sync with panda::panda_file::LiteralTag enum class LiteralTag { - TAGVALUE, - BOOLEAN, - INTEGER, + TAGVALUE = 0, + BOOLEAN = 1, + INTEGER = 2, FLOAT, - DOUBLE, - STRING, - ACCESSOR, - METHOD, + DOUBLE = 4, + STRING = 5, + METHOD = 6, GENERATOR_METHOD, + ACCESSOR = 8, + METHODAFFILIATE = 9, ASYNC_GENERATOR_METHOD, - NULL_VALUE, + NULL_VALUE = 255, }; class Literal : public Expression { @@ -58,6 +59,7 @@ public: double GetDouble() const; const util::StringView &GetString() const; const util::StringView &GetMethod() const; + uint16_t GetMethodAffiliate() const; protected: explicit Literal(AstNodeType type) : Expression(type) {} diff --git a/es2panda/ir/expressions/literals/bigIntLiteral.cpp b/es2panda/ir/expressions/literals/bigIntLiteral.cpp index 7d3a149f8fad46f96cb87d6e174d1f78383d3cab..3cc1dfab190a26862b701ad4225b5ea844a64fc7 100644 --- a/es2panda/ir/expressions/literals/bigIntLiteral.cpp +++ b/es2panda/ir/expressions/literals/bigIntLiteral.cpp @@ -30,8 +30,7 @@ void BigIntLiteral::Dump(ir::AstDumper *dumper) const void BigIntLiteral::Compile(compiler::PandaGen *pg) const { - // TODO() - pg->Unimplemented(); + pg->LoadAccumulatorBigInt(this, src_); } checker::Type *BigIntLiteral::Check(checker::Checker *checker) const diff --git a/es2panda/ir/expressions/literals/regExpLiteral.cpp b/es2panda/ir/expressions/literals/regExpLiteral.cpp index 6fb9c4e3c9406e5597cd8e6d4c32e0f01f96e8c7..881a630a3f81df48150de34008e12fcb1df10cd6 100644 --- a/es2panda/ir/expressions/literals/regExpLiteral.cpp +++ b/es2panda/ir/expressions/literals/regExpLiteral.cpp @@ -38,22 +38,27 @@ void RegExpLiteral::Compile(compiler::PandaGen *pg) const compiler::VReg newTarget = pg->AllocReg(); compiler::VReg pattern = pg->AllocReg(); size_t argCount = 3; + std::vector regs = {}; pg->TryLoadGlobalByName(this, "RegExp"); pg->StoreAccumulator(this, ctor); pg->StoreAccumulator(this, newTarget); + regs.push_back(ctor); + regs.push_back(newTarget); pg->LoadAccumulatorString(this, pattern_); pg->StoreAccumulator(this, pattern); + regs.push_back(pattern); if (!flags_.Empty()) { compiler::VReg flag = pg->AllocReg(); pg->LoadAccumulatorString(this, flags_); pg->StoreAccumulator(this, flag); + regs.push_back(flag); argCount++; } - pg->NewObject(this, ctor, argCount); + pg->NewObject(this, regs); } checker::Type *RegExpLiteral::Check(checker::Checker *checker) const diff --git a/es2panda/ir/expressions/literals/taggedLiteral.h b/es2panda/ir/expressions/literals/taggedLiteral.h index 69a4b6486a38bd9e10ad389b8551b24fcf30fcea..c8ecd27e70eb55ca5392b6ff75ddfeb348adee47 100644 --- a/es2panda/ir/expressions/literals/taggedLiteral.h +++ b/es2panda/ir/expressions/literals/taggedLiteral.h @@ -37,6 +37,11 @@ public: { } + explicit TaggedLiteral(LiteralTag tag, uint16_t num) + : Literal(AstNodeType::TAGGED_LITERAL), num_(num), tag_(tag) + { + } + const util::StringView &Str() const { return str_; @@ -59,12 +64,19 @@ public: return str_; } + uint16_t MethodAffiliate() const + { + ASSERT(tag_ == LiteralTag::METHODAFFILIATE); + return num_; + } + 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: + uint16_t num_ {}; util::StringView str_ {}; LiteralTag tag_ {LiteralTag::NULL_VALUE}; }; diff --git a/es2panda/ir/expressions/newExpression.cpp b/es2panda/ir/expressions/newExpression.cpp index f0836eafe9adc2ee6599202e1b6d7fa13e1e9c68..3126337e48e89c1bfd26578815e0a53ca75177fd 100644 --- a/es2panda/ir/expressions/newExpression.cpp +++ b/es2panda/ir/expressions/newExpression.cpp @@ -40,23 +40,27 @@ void NewExpression::Dump(ir::AstDumper *dumper) const void NewExpression::Compile(compiler::PandaGen *pg) const { compiler::RegScope rs(pg); - compiler::VReg ctor = pg->AllocReg(); - compiler::VReg newTarget = pg->AllocReg(); callee_->Compile(pg); + compiler::VReg ctor = pg->AllocReg(); + compiler::VReg newTarget = pg->AllocReg(); + std::vector regs; pg->StoreAccumulator(this, ctor); + regs.push_back(ctor); // new.Target will be the same as ctor pg->StoreAccumulator(this, newTarget); + regs.push_back(newTarget); if (!util::Helpers::ContainSpreadElement(arguments_)) { for (const auto *it : arguments_) { compiler::VReg arg = pg->AllocReg(); it->Compile(pg); pg->StoreAccumulator(this, arg); + regs.push_back(arg); } - pg->NewObject(this, ctor, arguments_.size() + 2); + pg->NewObject(this, regs); } else { compiler::VReg argsObj = pg->AllocReg(); diff --git a/es2panda/ir/expressions/objectExpression.cpp b/es2panda/ir/expressions/objectExpression.cpp index bb4e2f62db4a15691492513944b6183cf728bd17..1aa76b2a48698d1a4f8eb055e972883efaa742d5 100644 --- a/es2panda/ir/expressions/objectExpression.cpp +++ b/es2panda/ir/expressions/objectExpression.cpp @@ -20,14 +20,19 @@ #include #include #include +#include #include #include #include #include +#include #include +#include +#include #include #include #include +#include #include #include #include @@ -35,6 +40,45 @@ namespace panda::es2panda::ir { +static bool NeedSettingName(const ir::Expression *expr) +{ + const ir::Identifier *identifier; + switch (expr->Type()) { + case ir::AstNodeType::FUNCTION_EXPRESSION: { + identifier = expr->AsFunctionExpression()->Function()->Id(); + break; + } + case ir::AstNodeType::ARROW_FUNCTION_EXPRESSION: { + identifier = expr->AsArrowFunctionExpression()->Function()->Id(); + break; + } + case ir::AstNodeType::CLASS_EXPRESSION: { + identifier = expr->AsClassExpression()->Definition()->Ident(); + break; + } + default: { + return false; + } + } + return identifier == nullptr ? true : std::string(identifier->Name()) == ""; +} + +static bool IsTargetNameFormat(const ir::Expression *expr) +{ + util::StringView name; + if (expr->IsIdentifier()) { + name = expr->AsIdentifier()->Name(); + } else if (expr->IsStringLiteral()) { + name = expr->AsStringLiteral()->Str(); + } else if (expr->IsNumberLiteral()) { + name = expr->AsNumberLiteral()->Str(); + } else { + UNREACHABLE(); + } + return std::string(name).find('.') != std::string::npos; +} + + ValidationInfo ObjectExpression::ValidateExpression() { ValidationInfo info; @@ -250,11 +294,14 @@ void ObjectExpression::CompileStaticProperties(compiler::PandaGen *pg, util::Bit bufferPos = res.first->second; } + buf->ResetLiteral(bufferPos + 1, CreateLiteral(pg, prop, compiled, i)); + if (prop->IsMethod()) { hasMethod = true; + const ir::FunctionExpression *func = prop->Value()->AsFunctionExpression(); + Literal *methodAffiliate = pg->Allocator()->New(LiteralTag::METHODAFFILIATE, func->Function()->FormalParamsLength()); + buf->Add(methodAffiliate); } - - buf->ResetLiteral(bufferPos + 1, CreateLiteral(pg, prop, compiled, i)); } EmitCreateObjectWithBuffer(pg, buf, hasMethod); @@ -312,12 +359,20 @@ void ObjectExpression::CompileRemainingProperties(compiler::PandaGen *pg, const case ir::PropertyKind::INIT: { compiler::Operand key = pg->ToPropertyKey(prop->Key(), prop->IsComputed()); + bool nameSetting = false; if (prop->IsMethod()) { pg->LoadAccumulator(prop->Value(), objReg); + nameSetting = true; + } else { + if (prop->IsComputed()) { + nameSetting = NeedSettingName(prop->Value()); + } else { + nameSetting = NeedSettingName(prop->Value()) && IsTargetNameFormat(prop->Key()); + } } prop->Value()->Compile(pg); - pg->StoreOwnProperty(this, objReg, key); + pg->StoreOwnProperty(this, objReg, key, nameSetting); break; } case ir::PropertyKind::PROTO: { diff --git a/es2panda/ir/expressions/taggedTemplateExpression.cpp b/es2panda/ir/expressions/taggedTemplateExpression.cpp index 156483238128f3c08159be578dea97e270952b6e..b833aeb33d4c0b676d0fd79d15982e7ed6811f6e 100644 --- a/es2panda/ir/expressions/taggedTemplateExpression.cpp +++ b/es2panda/ir/expressions/taggedTemplateExpression.cpp @@ -50,10 +50,13 @@ void TaggedTemplateExpression::Compile(compiler::PandaGen *pg) const compiler::RegScope rs(pg); compiler::VReg callee = pg->AllocReg(); bool hasThis = false; + std::vector regs; + regs.push_back(callee); if (tag_->IsMemberExpression()) { hasThis = true; compiler::VReg thisReg = pg->AllocReg(); + regs.push_back(thisReg); compiler::RegScope mrs(pg); tag_->AsMemberExpression()->Compile(pg, thisReg); @@ -66,21 +69,21 @@ void TaggedTemplateExpression::Compile(compiler::PandaGen *pg) const compiler::Literals::GetTemplateObject(pg, this); compiler::VReg arg0 = pg->AllocReg(); pg->StoreAccumulator(this, arg0); + regs.push_back(arg0); for (const auto *element : quasi_->Expressions()) { element->Compile(pg); compiler::VReg arg = pg->AllocReg(); pg->StoreAccumulator(element, arg); + regs.push_back(arg); } if (hasThis) { - constexpr auto extraParams = 2; - pg->CallThis(this, callee, static_cast(quasi_->Expressions().size() + extraParams)); + pg->CallThis(this, regs); return; } - constexpr auto extraParams = 1; - pg->Call(this, callee, quasi_->Expressions().size() + extraParams); + pg->Call(this, regs); } checker::Type *TaggedTemplateExpression::Check(checker::Checker *checker) const diff --git a/es2panda/ir/module/exportDefaultDeclaration.cpp b/es2panda/ir/module/exportDefaultDeclaration.cpp index 92dc53cd961585dca5f8dbf66d08b485ca81155f..977f900dec75e0504eb3904c587de555c9918364 100644 --- a/es2panda/ir/module/exportDefaultDeclaration.cpp +++ b/es2panda/ir/module/exportDefaultDeclaration.cpp @@ -34,7 +34,9 @@ void ExportDefaultDeclaration::Dump(ir::AstDumper *dumper) const void ExportDefaultDeclaration::Compile([[maybe_unused]] compiler::PandaGen *pg) const { decl_->Compile(pg); - pg->StoreModuleVar(this, "default"); + if (!decl_->IsFunctionDeclaration()) { + pg->StoreModuleVariable(this, "*default*"); + } } checker::Type *ExportDefaultDeclaration::Check([[maybe_unused]] checker::Checker *checker) const diff --git a/es2panda/ir/statements/classDeclaration.cpp b/es2panda/ir/statements/classDeclaration.cpp index 0964fcf99a882561282f3682c1a5e4a390d6cd70..c9b00b6f44d90698f6d57518944c49a7c0a08194 100644 --- a/es2panda/ir/statements/classDeclaration.cpp +++ b/es2panda/ir/statements/classDeclaration.cpp @@ -16,10 +16,12 @@ #include "classDeclaration.h" #include +#include #include #include #include #include +#include namespace panda::es2panda::ir { @@ -39,9 +41,15 @@ void ClassDeclaration::Dump(ir::AstDumper *dumper) const void ClassDeclaration::Compile([[maybe_unused]] compiler::PandaGen *pg) const { - auto lref = compiler::LReference::CreateLRef(pg, def_->Ident(), true); - def_->Compile(pg); - lref.SetValue(); + if (def_->Ident()) { + auto lref = compiler::LReference::CreateLRef(pg, def_->Ident(), true); + def_->Compile(pg); + lref.SetValue(true); + } else { + ASSERT(this->Parent()->IsExportDefaultDeclaration() && pg->Scope()->IsModuleScope()); + def_->Compile(pg); + pg->StoreModuleVariable(def_, util::StringView("*default*")); + } } checker::Type *ClassDeclaration::Check([[maybe_unused]] checker::Checker *checker) const diff --git a/es2panda/parser/expressionParser.cpp b/es2panda/parser/expressionParser.cpp index 34bb768e9109427fc6fb839cb68b806ecf515744..d63a53776a86a2de119dd4be92dbde137b5b5765 100644 --- a/es2panda/parser/expressionParser.cpp +++ b/es2panda/parser/expressionParser.cpp @@ -957,6 +957,9 @@ ir::Expression *ParserImpl::ParsePrimaryExpression(ExpressionParseFlags flags) return ParseImportExpression(); } case lexer::TokenType::LITERAL_IDENT: { + if (lexer_->GetToken().Ident().Is("yield")) { + ThrowSyntaxError("Identifier expected. 'yield' is a reserved word in strict mode."); + } auto *identNode = AllocNode(lexer_->GetToken().Ident(), Allocator()); identNode->SetReference(); identNode->SetRange(lexer_->GetToken().Loc()); diff --git a/es2panda/parser/parserImpl.cpp b/es2panda/parser/parserImpl.cpp index 6ecfc77b84dcbe26126be64ed45012ace09a8a34..fbe7bb0d7afc67799980d00a2c99054f09bfe203 100644 --- a/es2panda/parser/parserImpl.cpp +++ b/es2panda/parser/parserImpl.cpp @@ -123,8 +123,11 @@ Program ParserImpl::ParseModule(const std::string &fileName, const std::string & context_.Status() |= (ParserStatus::MODULE); ParseProgram(ScriptKind::MODULE); - if (!Binder()->TopScope()->AsModuleScope()->ExportAnalysis()) { - ThrowSyntaxError("Invalid exported binding"); + std::string errorMessage = ""; + lexer::SourcePosition errorPos; + if (!GetSourceTextModuleRecord()->ValidateModuleRecordEntries(Binder()->TopScope()->AsModuleScope(), + errorMessage, errorPos)) { + ThrowSyntaxError(errorMessage.c_str(), errorPos); } return std::move(program_); @@ -2400,7 +2403,7 @@ ir::Identifier *ParserImpl::SetIdentNodeInClassDefinition() } ir::ClassDefinition *ParserImpl::ParseClassDefinition(bool isDeclaration, bool idRequired, bool isDeclare, - bool isAbstract) + bool isAbstract, bool isStmt) { lexer::SourcePosition startLoc = lexer_->GetToken().Start(); lexer_->NextToken(); @@ -2537,7 +2540,7 @@ ir::ClassDefinition *ParserImpl::ParseClassDefinition(bool isDeclaration, bool i auto *classDefinition = AllocNode( classCtx.GetScope(), identNode, typeParamDecl, superTypeParams, std::move(implements), ctor, superClass, - std::move(properties), std::move(indexSignatures), isDeclare, isAbstract); + std::move(properties), std::move(indexSignatures), isDeclare, isAbstract, isStmt); classDefinition->SetRange({classBodyStartLoc, classBodyEndLoc}); @@ -3250,58 +3253,4 @@ ScriptExtension ParserImpl::Extension() const return program_.Extension(); } -void ExportDeclarationContext::BindExportDecl(const ir::AstNode *exportDecl) -{ - if (!binder_) { - return; - } - - binder::ModuleScope::ExportDeclList declList(Allocator()->Adapter()); - - if (exportDecl->IsExportDefaultDeclaration()) { - const auto *decl = exportDecl->AsExportDefaultDeclaration(); - const auto *rhs = decl->Decl(); - - if (binder_->GetScope()->Bindings().size() == savedBindings_.size()) { - if (rhs->IsFunctionDeclaration()) { - binder_->AddDecl(rhs->Start(), binder_->Allocator(), - util::StringView(DEFAULT_EXPORT), - rhs->AsFunctionDeclaration()->Function()); - } else { - binder_->AddDecl(rhs->Start(), util::StringView(DEFAULT_EXPORT)); - } - } - } - - for (const auto &[name, variable] : binder_->GetScope()->Bindings()) { - if (savedBindings_.find(name) != savedBindings_.end()) { - continue; - } - - util::StringView exportName(exportDecl->IsExportDefaultDeclaration() ? "default" : name); - - variable->AddFlag(binder::VariableFlags::LOCAL_EXPORT); - auto *decl = binder_->AddDecl(variable->Declaration()->Node()->Start(), exportName, name); - declList.push_back(decl); - } - - auto *moduleScope = binder_->GetScope()->AsModuleScope(); - moduleScope->AddExportDecl(exportDecl, std::move(declList)); -} - -void ImportDeclarationContext::BindImportDecl(const ir::ImportDeclaration *importDecl) -{ - binder::ModuleScope::ImportDeclList declList(Allocator()->Adapter()); - - for (const auto &[name, variable] : binder_->GetScope()->Bindings()) { - if (savedBindings_.find(name) != savedBindings_.end()) { - continue; - } - - declList.push_back(variable->Declaration()->AsImportDecl()); - } - - binder_->GetScope()->AsModuleScope()->AddImportDecl(importDecl, std::move(declList)); -} - } // namespace panda::es2panda::parser diff --git a/es2panda/parser/parserImpl.h b/es2panda/parser/parserImpl.h index e73468a66427f1e910a1fc4261bc6cc2c7e85ebe..de1e80b047a53eaca9f09f97b8d8acf4190d5f59 100644 --- a/es2panda/parser/parserImpl.h +++ b/es2panda/parser/parserImpl.h @@ -117,6 +117,10 @@ enum class MethodDefinitionKind; enum class ModifierFlags; } // namespace panda::es2panda::ir +namespace panda::es2panda::binder { +class SourceTextModuleRecord; +} // namespace panda::es2panda::binder + namespace panda::es2panda::parser { class Program; @@ -280,7 +284,7 @@ private: bool implExists, bool isAbstract = false); ir::Identifier *SetIdentNodeInClassDefinition(); ir::ClassDefinition *ParseClassDefinition(bool isDeclaration, bool idRequired = true, bool isDeclare = false, - bool isAbstract = false); + bool isAbstract = false, bool isStmt = false); void ValidateAccessor(ExpressionParseFlags flags, lexer::TokenFlags currentTokenFlags); void CheckPropertyKeyAsycModifier(ParserStatus *methodStatus); @@ -390,8 +394,19 @@ private: void CheckFunctionDeclaration(StatementParsingFlags flags); void CheckLabelledFunction(const ir::Statement *node); + void CheckFunctionLocation(const ir::Statement *node); + void CheckLexerTokenType(); void CheckDeclare(); + void AddImportEntryItem(const ir::StringLiteral *source, const ArenaVector *specifiers); + void AddExportNamedEntryItem(const ArenaVector &specifiers, const ir::StringLiteral *source); + void AddExportStarEntryItem(const lexer::SourcePosition &startLoc, + const ir::StringLiteral *source, + const ir::Identifier *exported); + void AddExportDefaultEntryItem(const ir::AstNode *declNode); + void AddExportLocalEntryItem(const ir::Statement *declNode); + binder::SourceTextModuleRecord *GetSourceTextModuleRecord(); + bool ParseDirective(ArenaVector *statements); void ParseDirectivePrologue(ArenaVector *statements); ArenaVector ParseStatementList(StatementParsingFlags flags = StatementParsingFlags::ALLOW_LEXICAL); @@ -420,7 +435,7 @@ private: ir::Statement *ParseFunctionStatement(StatementParsingFlags flags, bool isDeclare); ir::FunctionDeclaration *ParseFunctionDeclaration(bool canBeAnonymous = false, ParserStatus newStatus = ParserStatus::NO_OPTS, - bool isDeclare = false); + bool isDeclare = false, bool isExported = false); ir::Statement *ParseExportDeclaration(StatementParsingFlags flags, ArenaVector &&decorators); std::tuple ParseForInOf( ir::Expression *leftNode, ExpressionParseFlags exprFlags, bool isAwait); @@ -436,8 +451,11 @@ private: ir::ReturnStatement *ParseReturnStatement(); ir::ClassDeclaration *ParseClassStatement(StatementParsingFlags flags, bool isDeclare, ArenaVector &&decorators, bool isAbstract = false); - ir::ClassDeclaration *ParseClassDeclaration(bool idRequired, ArenaVector &&decorators, - bool isDeclare = false, bool isAbstract = false); + ir::ClassDeclaration *ParseClassDeclaration(bool idRequired, + ArenaVector &&decorators, + bool isDeclare = false, + bool isAbstract = false, + bool isExported = false); ir::TSTypeAliasDeclaration *ParseTsTypeAliasDeclaration(bool isDeclare); ir::TSEnumDeclaration *ParseEnumMembers(ir::Identifier *key, const lexer::SourcePosition &enumStart, bool isConst); ir::TSEnumDeclaration *ParseEnumDeclaration(bool isConst = false); @@ -451,9 +469,10 @@ private: void ValidateDeclaratorId(); ir::VariableDeclarator *ParseVariableDeclaratorInitializer(ir::Expression *init, VariableParsingFlags flags, const lexer::SourcePosition &startLoc, bool isDeclare); - ir::VariableDeclarator *ParseVariableDeclarator(VariableParsingFlags flags, bool isDeclare); + ir::VariableDeclarator *ParseVariableDeclarator(VariableParsingFlags flags, + bool isDeclare, bool isExported = false); ir::Statement *ParseVariableDeclaration(VariableParsingFlags flags = VariableParsingFlags::NO_OPTS, - bool isDeclare = false); + bool isDeclare = false, bool isExported = false); ir::WhileStatement *ParseWhileStatement(); ir::VariableDeclaration *ParseContextualLet(VariableParsingFlags flags, StatementParsingFlags stmFlags = StatementParsingFlags::ALLOW_LEXICAL, @@ -637,53 +656,6 @@ private: } }; -class SavedBindingsContext { -public: - explicit SavedBindingsContext(binder::Binder *binder) - : binder_(binder), savedBindings_(binder_->GetScope()->Bindings()) - { - } - NO_COPY_SEMANTIC(SavedBindingsContext); - NO_MOVE_SEMANTIC(SavedBindingsContext); - ~SavedBindingsContext() = default; - -protected: - ArenaAllocator *Allocator() const - { - return binder_->Allocator(); - } - - binder::Binder *binder_; - binder::VariableMap savedBindings_; -}; - -class ExportDeclarationContext : public SavedBindingsContext { -public: - explicit ExportDeclarationContext(binder::Binder *binder) : SavedBindingsContext(binder) {} - NO_COPY_SEMANTIC(ExportDeclarationContext); - NO_MOVE_SEMANTIC(ExportDeclarationContext); - ~ExportDeclarationContext() = default; - - void BindExportDecl(const ir::AstNode *exportDecl); - -protected: - static constexpr std::string_view DEFAULT_EXPORT = "*default*"; -}; - -class ImportDeclarationContext : public SavedBindingsContext { -public: - explicit ImportDeclarationContext(binder::Binder *binder) : SavedBindingsContext(binder) {} - - NO_COPY_SEMANTIC(ImportDeclarationContext); - NO_MOVE_SEMANTIC(ImportDeclarationContext); - - ~ImportDeclarationContext() = default; - - void BindImportDecl(const ir::ImportDeclaration *importDecl); - -private: -}; - } // namespace panda::es2panda::parser #endif diff --git a/es2panda/parser/statementParser.cpp b/es2panda/parser/statementParser.cpp index 2a06a84efb4e124c1b1a3521b5c7cc7e675ef83a..c4dd69de049493d2a640e50f810649ae64300fa4 100644 --- a/es2panda/parser/statementParser.cpp +++ b/es2panda/parser/statementParser.cpp @@ -495,13 +495,17 @@ ir::ClassDeclaration *ParserImpl::ParseClassStatement(StatementParsingFlags flag } ir::ClassDeclaration *ParserImpl::ParseClassDeclaration(bool idRequired, ArenaVector &&decorators, - bool isDeclare, bool isAbstract) + bool isDeclare, bool isAbstract, bool isExported) { lexer::SourcePosition startLoc = lexer_->GetToken().Start(); - ir::ClassDefinition *classDefinition = ParseClassDefinition(true, idRequired, isDeclare, isAbstract); - - auto *decl = - Binder()->AddDecl(classDefinition->Ident()->Start(), classDefinition->Ident()->Name()); + ir::ClassDefinition *classDefinition = ParseClassDefinition(true, idRequired, isDeclare, isAbstract, true); + + auto *decl = Binder()->AddDecl(classDefinition->Ident() == nullptr ? + startLoc : classDefinition->Ident()->Start(), + classDefinition->Ident() == nullptr ? + util::StringView("*default*") : classDefinition->Ident()->Name(), + isExported ? + binder::ModuleDeclKind::EXPORT : binder::ModuleDeclKind::NONE); decl->BindNode(classDefinition); lexer::SourcePosition endLoc = classDefinition->End(); @@ -690,6 +694,31 @@ void ParserImpl::CheckFunctionDeclaration(StatementParsingFlags flags) } } +void ParserImpl::CheckFunctionLocation(const ir::Statement *node) +{ + if (node->IsFunctionDeclaration()) { + ThrowSyntaxError("In strict mode code, functions can only be declared at top level or inside a block."); + } +} + +void ParserImpl::CheckLexerTokenType() +{ + switch (lexer_->GetToken().Type()) { + case lexer::TokenType::KEYW_CONST: { + ThrowSyntaxError("The 'const' declarations can only be declared inside a block."); + } + case lexer::TokenType::KEYW_CLASS: { + ThrowSyntaxError("Class declaration not allowed in statement position."); + } + case lexer::TokenType::KEYW_LET: { + ThrowSyntaxError("The 'let' declarations can only be declared inside a block."); + } + default: { + return; + } + } +} + void ParserImpl::ConsumeSemicolon(ir::Statement *statement) { if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) { @@ -790,11 +819,11 @@ ir::BreakStatement *ParserImpl::ParseBreakStatement() } lexer::SourcePosition startLoc = lexer_->GetToken().Start(); - lexer::SourcePosition endLoc = lexer_->GetToken().End(); lexer_->NextToken(); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON || - lexer_->GetToken().Type() == lexer::TokenType::EOS || lexer_->GetToken().NewLine()) { + lexer_->GetToken().Type() == lexer::TokenType::EOS || lexer_->GetToken().NewLine() || + lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { if (!allowBreak) { if (Extension() == ScriptExtension::JS) { ThrowSyntaxError("Illegal break statement"); @@ -808,24 +837,9 @@ ir::BreakStatement *ParserImpl::ParseBreakStatement() auto *breakStatement = AllocNode(); breakStatement->SetRange({startLoc, lexer_->GetToken().End()}); - lexer_->NextToken(); - return breakStatement; - } - - if (lexer_->GetToken().NewLine() || lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { - if (!allowBreak) { - if (Extension() == ScriptExtension::JS) { - ThrowSyntaxError("Illegal break statement"); - } - if (Extension() == ScriptExtension::TS) { - ThrowSyntaxError( - "A 'break' statement can only be used within an " - "enclosing iteration or switch statement"); - } + if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) { + lexer_->NextToken(); } - - auto *breakStatement = AllocNode(); - breakStatement->SetRange({startLoc, endLoc}); return breakStatement; } @@ -917,8 +931,9 @@ ir::DoWhileStatement *ParserImpl::ParseDoWhileStatement() lexer::SourcePosition startLoc = lexer_->GetToken().Start(); lexer_->NextToken(); + CheckLexerTokenType(); ir::Statement *body = ParseStatement(); - + CheckFunctionLocation(body); if (lexer_->GetToken().Type() != lexer::TokenType::KEYW_WHILE) { ThrowSyntaxError("Missing 'while' keyword in a 'DoWhileStatement'"); } @@ -951,7 +966,7 @@ ir::DoWhileStatement *ParserImpl::ParseDoWhileStatement() } ir::FunctionDeclaration *ParserImpl::ParseFunctionDeclaration(bool canBeAnonymous, ParserStatus newStatus, - bool isDeclare) + bool isDeclare, bool isExported) { lexer::SourcePosition startLoc = lexer_->GetToken().Start(); @@ -967,6 +982,7 @@ ir::FunctionDeclaration *ParserImpl::ParseFunctionDeclaration(bool canBeAnonymou context_.Status() = savedStatus; + // e.g. export default function () {} if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT && lexer_->GetToken().Type() != lexer::TokenType::KEYW_AWAIT) { if (canBeAnonymous) { @@ -975,6 +991,12 @@ ir::FunctionDeclaration *ParserImpl::ParseFunctionDeclaration(bool canBeAnonymou auto *funcDecl = AllocNode(func); funcDecl->SetRange(func->Range()); + Binder()->AddDecl(startLoc, + Allocator(), + util::StringView("*default*"), + func, + isExported ? + binder::ModuleDeclKind::EXPORT : binder::ModuleDeclKind::NONE); return funcDecl; } @@ -1000,7 +1022,12 @@ ir::FunctionDeclaration *ParserImpl::ParseFunctionDeclaration(bool canBeAnonymou funcDecl->SetRange(func->Range()); if (!func->IsOverload()) { - Binder()->AddDecl(identNode->Start(), Allocator(), ident, func); + Binder()->AddDecl(identNode->Start(), + Allocator(), + ident, + func, + isExported ? + binder::ModuleDeclKind::EXPORT : binder::ModuleDeclKind::NONE); } else if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) { lexer_->NextToken(); } @@ -1302,7 +1329,9 @@ ir::Statement *ParserImpl::ParseForStatement() } lexer_->NextToken(); + CheckLexerTokenType(); ir::Statement *bodyNode = ParseStatement(); + CheckFunctionLocation(bodyNode); lexer::SourcePosition endLoc = bodyNode->End(); ir::Statement *forStatement = nullptr; @@ -1341,18 +1370,22 @@ ir::IfStatement *ParserImpl::ParseIfStatement() } lexer_->NextToken(); + CheckLexerTokenType(); ir::Statement *consequent = ParseStatement(StatementParsingFlags::IF_ELSE | StatementParsingFlags::ALLOW_LEXICAL); if (Extension() == ScriptExtension::TS && consequent->IsEmptyStatement()) { ThrowSyntaxError("The body of an if statement cannot be the empty statement"); } + CheckFunctionLocation(consequent); endLoc = consequent->End(); ir::Statement *alternate = nullptr; if (lexer_->GetToken().Type() == lexer::TokenType::KEYW_ELSE) { lexer_->NextToken(); // eat ELSE keyword + CheckLexerTokenType(); alternate = ParseStatement(StatementParsingFlags::IF_ELSE | StatementParsingFlags::ALLOW_LEXICAL); + CheckFunctionLocation(alternate); endLoc = alternate->End(); } @@ -1370,6 +1403,10 @@ ir::LabelledStatement *ParserImpl::ParseLabelledStatement(const lexer::LexerPosi ThrowSyntaxError("'await' is a reserved identifier in module code", pos.token.Start()); } + if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_YIELD) { + ThrowSyntaxError("Identifier expected. 'yield' is a reserved word in strict mode.", pos.token.Start()); + } + if (context_.FindLabel(actualLabel)) { ThrowSyntaxError("Label already declared", pos.token.Start()); } @@ -1732,7 +1769,8 @@ ir::VariableDeclarator *ParserImpl::ParseVariableDeclaratorInitializer(ir::Expre return declarator; } -ir::VariableDeclarator *ParserImpl::ParseVariableDeclarator(VariableParsingFlags flags, bool isDeclare) +ir::VariableDeclarator *ParserImpl::ParseVariableDeclarator(VariableParsingFlags flags, + bool isDeclare, bool isExported) { ir::Expression *init = nullptr; lexer::SourcePosition startLoc = lexer_->GetToken().Start(); @@ -1794,12 +1832,15 @@ ir::VariableDeclarator *ParserImpl::ParseVariableDeclarator(VariableParsingFlags for (const auto *binding : bindings) { binder::Decl *decl = nullptr; + binder::ModuleDeclKind moduleDeclkind + = isExported ? binder::ModuleDeclKind::EXPORT : binder::ModuleDeclKind::NONE; + if (flags & VariableParsingFlags::VAR) { - decl = Binder()->AddDecl(startLoc, binding->Name()); + decl = Binder()->AddDecl(startLoc, binding->Name(), moduleDeclkind); } else if (flags & VariableParsingFlags::LET) { - decl = Binder()->AddDecl(startLoc, binding->Name()); + decl = Binder()->AddDecl(startLoc, binding->Name(), moduleDeclkind); } else { - decl = Binder()->AddDecl(startLoc, binding->Name()); + decl = Binder()->AddDecl(startLoc, binding->Name(), moduleDeclkind); } decl->BindNode(init); @@ -1808,7 +1849,7 @@ ir::VariableDeclarator *ParserImpl::ParseVariableDeclarator(VariableParsingFlags return declarator; } -ir::Statement *ParserImpl::ParseVariableDeclaration(VariableParsingFlags flags, bool isDeclare) +ir::Statement *ParserImpl::ParseVariableDeclaration(VariableParsingFlags flags, bool isDeclare, bool isExported) { lexer::SourcePosition startLoc = lexer_->GetToken().Start(); @@ -1816,6 +1857,13 @@ ir::Statement *ParserImpl::ParseVariableDeclaration(VariableParsingFlags flags, lexer_->NextToken(); } + if (lexer_->GetToken().Ident().Is("yield")) { + ThrowSyntaxError("Invalid use of 'yield' in strict mode."); + } + if ((flags & VariableParsingFlags::LET) && (lexer_->GetToken().Ident().Is("undefined"))) { + ThrowSyntaxError("Declaration name conflicts with built-in global identifier 'undefined'."); + } + if (Extension() == ScriptExtension::TS && lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_ENUM) { if (!(flags & VariableParsingFlags::CONST)) { ThrowSyntaxError("Variable declaration expected."); @@ -1826,7 +1874,7 @@ ir::Statement *ParserImpl::ParseVariableDeclaration(VariableParsingFlags flags, ArenaVector declarators(Allocator()->Adapter()); while (true) { - ir::VariableDeclarator *declarator = ParseVariableDeclarator(flags, isDeclare); + ir::VariableDeclarator *declarator = ParseVariableDeclarator(flags, isDeclare, isExported); declarators.push_back(declarator); @@ -1867,8 +1915,10 @@ ir::WhileStatement *ParserImpl::ParseWhileStatement() } lexer_->NextToken(); + CheckLexerTokenType(); IterationContext iterCtx(&context_, Binder()); ir::Statement *body = ParseStatement(); + CheckFunctionLocation(body); lexer::SourcePosition endLoc = body->End(); auto *whileStatement = AllocNode(iterCtx.LexicalScope().GetScope(), test, body); @@ -1878,6 +1928,153 @@ ir::WhileStatement *ParserImpl::ParseWhileStatement() return whileStatement; } +binder::SourceTextModuleRecord *ParserImpl::GetSourceTextModuleRecord() +{ + return Binder()->TopScope()->AsModuleScope()->GetModuleRecord(); +} + +void ParserImpl::AddImportEntryItem(const ir::StringLiteral *source, const ArenaVector *specifiers) +{ + ASSERT(source != nullptr); + auto moduleRecord = GetSourceTextModuleRecord(); + + if (specifiers == nullptr || specifiers->empty()) { + moduleRecord->AddEmptyImportEntry(source->Str(), source->Start()); + return; + } + + for (auto *it : *specifiers) { + switch(it->Type()) { + case ir::AstNodeType::IMPORT_DEFAULT_SPECIFIER: { + auto importDefault = it->AsImportDefaultSpecifier(); + auto defaultString = util::StringView("default"); + moduleRecord->AddImportEntry(defaultString, + importDefault->Local()->Name(), + source->Str(), + importDefault->Start(), + source->Start()); + break; + } + case ir::AstNodeType::IMPORT_NAMESPACE_SPECIFIER: { + auto namespaceSpecifier = it->AsImportNamespaceSpecifier(); + moduleRecord->AddStarImportEntry(it, + namespaceSpecifier->Local()->Name(), + source->Str(), + namespaceSpecifier->Start(), + source->Start()); + break; + } + case ir::AstNodeType::IMPORT_SPECIFIER: { + auto importSpecifier = it->AsImportSpecifier(); + moduleRecord->AddImportEntry(importSpecifier->Imported()->Name(), + importSpecifier->Local()->Name(), + source->Str(), + importSpecifier->Start(), + source->Start()); + break; + } + default: { + ThrowSyntaxError("Unexpected astNode type", it->Start()); + } + } + } +} + +void ParserImpl::AddExportNamedEntryItem(const ArenaVector &specifiers, + const ir::StringLiteral *source) +{ + auto moduleRecord = GetSourceTextModuleRecord(); + ASSERT(moduleRecord != nullptr); + if (source) { + if (specifiers.empty()) { + moduleRecord->AddEmptyImportEntry(source->Str(), source->Start()); + } + + for (auto *it : specifiers) { + auto exportSpecifier = it->AsExportSpecifier(); + moduleRecord->AddIndirectExportEntry(exportSpecifier->Local()->Name(), + exportSpecifier->Exported()->Name(), + source->Str(), + exportSpecifier->Start(), + source->Start()); + } + } else { + for (auto *it : specifiers) { + auto exportSpecifier = it->AsExportSpecifier(); + moduleRecord->AddLocalExportEntry(exportSpecifier->Exported()->Name(), + exportSpecifier->Local()->Name(), + exportSpecifier->Start()); + } + } +} + +void ParserImpl::AddExportStarEntryItem(const lexer::SourcePosition &startLoc, + const ir::StringLiteral *source, + const ir::Identifier *exported) +{ + ASSERT(source != nullptr); + auto moduleRecord = GetSourceTextModuleRecord(); + + if (exported != nullptr) { + ThrowSyntaxError("Not support 'export * as'[ecma2020] yet."); + } + + moduleRecord->AddStarExportEntry(source->Str(), startLoc, source->Start()); +} + +void ParserImpl::AddExportDefaultEntryItem(const ir::AstNode *declNode) +{ + ASSERT(declNode != nullptr); + if (declNode->IsTSInterfaceDeclaration()) { + return; + } + auto moduleRecord = GetSourceTextModuleRecord(); + auto exportName = util::StringView("default"); + util::StringView localName; + if (declNode->IsFunctionDeclaration() || declNode->IsClassDeclaration()) { + const ir::Identifier *name = declNode->IsFunctionDeclaration() ? + declNode->AsFunctionDeclaration()->Function()->Id() : + declNode->AsClassDeclaration()->Definition()->Ident(); + localName = name == nullptr ? util::StringView("*default*") : name->Name(); + } + if (declNode->IsExpression()) { + localName = util::StringView("*default*"); + } + ASSERT(!localName.Empty()); + moduleRecord->AddLocalExportEntry(exportName, + localName, + declNode->Start()); +} + +void ParserImpl::AddExportLocalEntryItem(const ir::Statement *declNode) +{ + ASSERT(declNode != nullptr); + auto moduleRecord = GetSourceTextModuleRecord(); + if (declNode->IsVariableDeclaration()) { + auto declarators = declNode->AsVariableDeclaration()->Declarators(); + for (auto *decl : declarators) { + std::vector bindings = util::Helpers::CollectBindingNames(decl->Id()); + for (const auto *binding : bindings) { + moduleRecord->AddLocalExportEntry(binding->Name(), + binding->Name(), + binding->Start()); + } + } + } + if (declNode->IsFunctionDeclaration() || declNode->IsClassDeclaration()) { + auto name = declNode->IsFunctionDeclaration() ? + declNode->AsFunctionDeclaration()->Function()->Id() : + declNode->AsClassDeclaration()->Definition()->Ident(); + if (name == nullptr) { + ThrowSyntaxError("A class or function declaration without the default modifier mush have a name.", + declNode->Start()); + } + moduleRecord->AddLocalExportEntry(name->Name(), + name->Name(), + name->Start()); + } +} + ir::ExportDefaultDeclaration *ParserImpl::ParseExportDefaultDeclaration(const lexer::SourcePosition &startLoc, ArenaVector decorators, bool isExportEquals) @@ -1892,27 +2089,32 @@ ir::ExportDefaultDeclaration *ParserImpl::ParseExportDefaultDeclaration(const le ThrowSyntaxError("Decorators are not valid here.", decorators.front()->Start()); } - ExportDeclarationContext exportDeclCtx(Binder()); - if (lexer_->GetToken().Type() == lexer::TokenType::KEYW_FUNCTION) { - declNode = ParseFunctionDeclaration(true); + declNode = ParseFunctionDeclaration(true, ParserStatus::NO_OPTS, false, true); } else if (lexer_->GetToken().Type() == lexer::TokenType::KEYW_CLASS) { - declNode = ParseClassDeclaration(false, std::move(decorators)); + declNode = ParseClassDeclaration(false, std::move(decorators), false, false, true); } else if (lexer_->GetToken().IsAsyncModifier()) { lexer_->NextToken(); // eat `async` keyword - declNode = ParseFunctionDeclaration(false, ParserStatus::ASYNC_FUNCTION); + declNode = ParseFunctionDeclaration(false, ParserStatus::ASYNC_FUNCTION, false, true); } else if (Extension() == ScriptExtension::TS && lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_INTERFACE) { declNode = ParseTsInterfaceDeclaration(); } else { declNode = ParseExpression(); + Binder()->AddDecl(declNode->Start(), + util::StringView("*default*"), + binder::ModuleDeclKind::EXPORT); eatSemicolon = true; } + // record default export entry + if (!isExportEquals) { + AddExportDefaultEntryItem(declNode); + } + lexer::SourcePosition endLoc = declNode->End(); auto *exportDeclaration = AllocNode(declNode, isExportEquals); exportDeclaration->SetRange({startLoc, endLoc}); - exportDeclCtx.BindExportDecl(exportDeclaration); if (eatSemicolon) { ConsumeSemicolon(exportDeclaration); @@ -1950,10 +2152,11 @@ ir::ExportAllDeclaration *ParserImpl::ParseExportAllDeclaration(const lexer::Sou ir::StringLiteral *source = ParseFromClause(); lexer::SourcePosition endLoc = source->End(); + // record export star entry + AddExportStarEntryItem(startLoc, source, exported); + auto *exportDeclaration = AllocNode(source, exported); exportDeclaration->SetRange({startLoc, endLoc}); - auto *decl = Binder()->AddDecl(startLoc, exported ? exported->Name() : "*", "*"); - Binder()->GetScope()->AsModuleScope()->AddExportDecl(exportDeclaration, decl); ConsumeSemicolon(exportDeclaration); @@ -1965,7 +2168,6 @@ ir::ExportNamedDeclaration *ParserImpl::ParseExportNamedSpecifiers(const lexer:: lexer_->NextToken(lexer::LexerNextTokenFlags::KEYWORD_TO_IDENT); // eat `{` character ArenaVector specifiers(Allocator()->Adapter()); - binder::ModuleScope::ExportDeclList exportDecls(Allocator()->Adapter()); while (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { @@ -1992,8 +2194,6 @@ ir::ExportNamedDeclaration *ParserImpl::ParseExportNamedSpecifiers(const lexer:: specifier->SetRange({local->Start(), exported->End()}); specifiers.push_back(specifier); - auto *decl = Binder()->AddDecl(startLoc, exported->Name(), local->Name(), specifier); - exportDecls.push_back(decl); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) { lexer_->NextToken(lexer::LexerNextTokenFlags::KEYWORD_TO_IDENT); // eat comma @@ -2009,9 +2209,11 @@ ir::ExportNamedDeclaration *ParserImpl::ParseExportNamedSpecifiers(const lexer:: source = ParseFromClause(); } + // record ExportEntry + AddExportNamedEntryItem(specifiers, source); + auto *exportDeclaration = AllocNode(source, std::move(specifiers)); exportDeclaration->SetRange({startLoc, endPos}); - Binder()->GetScope()->AsModuleScope()->AddExportDecl(exportDeclaration, std::move(exportDecls)); ConsumeSemicolon(exportDeclaration); return exportDeclaration; @@ -2034,27 +2236,25 @@ ir::ExportNamedDeclaration *ParserImpl::ParseNamedExportDeclaration(const lexer: ThrowSyntaxError("Decorators are not valid here.", decorators.front()->Start()); } - ExportDeclarationContext exportDeclCtx(Binder()); - switch (lexer_->GetToken().Type()) { case lexer::TokenType::KEYW_VAR: { - decl = ParseVariableDeclaration(VariableParsingFlags::VAR, isDeclare); + decl = ParseVariableDeclaration(VariableParsingFlags::VAR, isDeclare, true); break; } case lexer::TokenType::KEYW_CONST: { - decl = ParseVariableDeclaration(VariableParsingFlags::CONST, isDeclare); + decl = ParseVariableDeclaration(VariableParsingFlags::CONST, isDeclare, true); break; } case lexer::TokenType::KEYW_LET: { - decl = ParseVariableDeclaration(VariableParsingFlags::LET, isDeclare); + decl = ParseVariableDeclaration(VariableParsingFlags::LET, isDeclare, true); break; } case lexer::TokenType::KEYW_FUNCTION: { - decl = ParseFunctionDeclaration(false, ParserStatus::NO_OPTS, isDeclare); + decl = ParseFunctionDeclaration(false, ParserStatus::NO_OPTS, isDeclare, true); break; } case lexer::TokenType::KEYW_CLASS: { - decl = ParseClassDeclaration(true, std::move(decorators), isDeclare); + decl = ParseClassDeclaration(true, std::move(decorators), isDeclare, false, true); break; } case lexer::TokenType::LITERAL_IDENT: { @@ -2105,7 +2305,7 @@ ir::ExportNamedDeclaration *ParserImpl::ParseNamedExportDeclaration(const lexer: } lexer_->NextToken(); // eat `async` keyword - decl = ParseFunctionDeclaration(false, ParserStatus::ASYNC_FUNCTION); + decl = ParseFunctionDeclaration(false, ParserStatus::ASYNC_FUNCTION, false, true); } } @@ -2113,13 +2313,13 @@ ir::ExportNamedDeclaration *ParserImpl::ParseNamedExportDeclaration(const lexer: ConsumeSemicolon(decl); } + AddExportLocalEntryItem(decl); + lexer::SourcePosition endLoc = decl->End(); ArenaVector specifiers(Allocator()->Adapter()); auto *exportDeclaration = AllocNode(decl, std::move(specifiers)); exportDeclaration->SetRange({startLoc, endLoc}); - exportDeclCtx.BindExportDecl(exportDeclaration); - return exportDeclaration; } @@ -2140,13 +2340,13 @@ ir::Statement *ParserImpl::ParseExportDeclaration(StatementParsingFlags flags, lexer_->NextToken(); // eat `export` keyword switch (lexer_->GetToken().Type()) { - case lexer::TokenType::KEYW_DEFAULT: { + case lexer::TokenType::KEYW_DEFAULT: { // export default Id return ParseExportDefaultDeclaration(startLoc, std::move(decorators)); } - case lexer::TokenType::PUNCTUATOR_MULTIPLY: { + case lexer::TokenType::PUNCTUATOR_MULTIPLY: { // export * ... return ParseExportAllDeclaration(startLoc); } - case lexer::TokenType::PUNCTUATOR_LEFT_BRACE: { + case lexer::TokenType::PUNCTUATOR_LEFT_BRACE: { // export { ... } ... return ParseExportNamedSpecifiers(startLoc); } case lexer::TokenType::KEYW_IMPORT: { @@ -2159,7 +2359,7 @@ ir::Statement *ParserImpl::ParseExportDeclaration(StatementParsingFlags flags, [[fallthrough]]; } - default: { + default: { // export [var] id ir::ExportNamedDeclaration *exportDecl = ParseNamedExportDeclaration(startLoc, std::move(decorators)); if (Extension() == ScriptExtension::TS && exportDecl->Decl()->IsVariableDeclaration() && @@ -2190,7 +2390,7 @@ void ParserImpl::ParseNameSpaceImport(ArenaVector *specifiers) specifier->SetRange({namespaceStart, lexer_->GetToken().End()}); specifiers->push_back(specifier); - Binder()->AddDecl(namespaceStart, "*", local->Name(), specifier); + Binder()->AddDecl(namespaceStart, local->Name(), binder::ModuleDeclKind::NONE); lexer_->NextToken(); // eat local name } @@ -2247,7 +2447,7 @@ void ParserImpl::ParseNamedImportSpecifiers(ArenaVector *specifie specifier->SetRange({imported->Start(), local->End()}); specifiers->push_back(specifier); - Binder()->AddDecl(imported->Start(), imported->Name(), local->Name(), specifier); + Binder()->AddDecl(local->Start(), local->Name(), binder::ModuleDeclKind::IMPORT); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) { lexer_->NextToken(lexer::LexerNextTokenFlags::KEYWORD_TO_IDENT); // eat comma @@ -2316,9 +2516,9 @@ ir::AstNode *ParserImpl::ParseImportDefaultSpecifier(ArenaVector specifier->SetRange(specifier->Local()->Range()); specifiers->push_back(specifier); - Binder()->AddDecl(local->Start(), "default", local->Name(), specifier); + Binder()->AddDecl(local->Start(), local->Name(), binder::ModuleDeclKind::IMPORT); - lexer_->NextToken(); // eat specifier name + // lexer_->NextToken(); // eat specifier name if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) { lexer_->NextToken(); // eat comma @@ -2355,6 +2555,7 @@ ir::AstNode *ParserImpl::ParseImportSpecifiers(ArenaVector *speci { ASSERT(specifiers->empty()); + // import [default] from 'source' if (lexer_->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) { ir::AstNode *astNode = ParseImportDefaultSpecifier(specifiers); if (astNode != nullptr) { @@ -2372,8 +2573,6 @@ ir::AstNode *ParserImpl::ParseImportSpecifiers(ArenaVector *speci ir::Statement *ParserImpl::ParseImportDeclaration(StatementParsingFlags flags) { - ImportDeclarationContext importCtx(Binder()); - if (Extension() == ScriptExtension::JS) { if (!(flags & StatementParsingFlags::GLOBAL)) { ThrowSyntaxError("'import' and 'export' may only appear at the top level"); @@ -2385,6 +2584,7 @@ ir::Statement *ParserImpl::ParseImportDeclaration(StatementParsingFlags flags) } char32_t nextChar = lexer_->Lookahead(); + // dynamic import || import.meta if (nextChar == LEX_CHAR_LEFT_PAREN || nextChar == LEX_CHAR_DOT) { return ParseExpressionStatement(); } @@ -2405,14 +2605,16 @@ ir::Statement *ParserImpl::ParseImportDeclaration(StatementParsingFlags flags) return astNode->AsTSImportEqualsDeclaration(); } source = ParseFromClause(true); + AddImportEntryItem(source, &specifiers); } else { + // import 'source' source = ParseFromClause(false); + AddImportEntryItem(source, nullptr); } lexer::SourcePosition endLoc = source->End(); auto *importDeclaration = AllocNode(source, std::move(specifiers)); importDeclaration->SetRange({startLoc, endLoc}); - importCtx.BindImportDecl(importDeclaration); ConsumeSemicolon(importDeclaration); diff --git a/es2panda/scripts/gen_isa.sh b/es2panda/scripts/gen_isa.sh new file mode 100755 index 0000000000000000000000000000000000000000..28ab703f1b0856e7efe47de9712beceff7e0d30c --- /dev/null +++ b/es2panda/scripts/gen_isa.sh @@ -0,0 +1,52 @@ +#!/bin/bash +# 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. + +set -e + +while getopts "g:t:a:o:d:r:h" arg +do + case "${arg}" in + "g") + GENERATOR=${OPTARG} + ;; + "t") + TEMPLATE=${OPTARG} + ;; + "a") + DATA=${OPTARG} + ;; + "o") + OUTPUT=${OPTARG} + ;; + "d") + OUTDIR=${OPTARG} + ;; + "r") + REQUIRE=${OPTARG} + ;; + "h") + echo "help" + ;; + ?) + echo "unkonw argument" + exit 1 + ;; + esac +done + +if [ ! -d ${OUTDIR} ]; then + mkdir -p ${OUTDIR} +fi +echo "${GENERATOR} --template ${TEMPLATE} --data ${DATA} --output ${OUTDIR}/${OUTPUT} --require ${REQUIRE}" +${GENERATOR} --template ${TEMPLATE} --data ${DATA} --output ${OUTDIR}/${OUTPUT} --require ${REQUIRE} diff --git a/es2panda/scripts/gen_keywords.sh b/es2panda/scripts/gen_keywords.sh new file mode 100755 index 0000000000000000000000000000000000000000..43f4069f464845de95f1f72ed85e44f8e22c908f --- /dev/null +++ b/es2panda/scripts/gen_keywords.sh @@ -0,0 +1,46 @@ +#!/bin/bash +# 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. + +set -e + +while getopts "g:t:o:d:h" arg +do + case "${arg}" in + "g") + GENERATOR=${OPTARG} + ;; + "t") + TEMPLATE=${OPTARG} + ;; + "o") + OUTPUT=${OPTARG} + ;; + "d") + OUTDIR=${OPTARG} + ;; + "h") + echo "help" + ;; + ?) + echo "unkonw argument" + exit 1 + ;; + esac +done + +if [ ! -d ${OUTDIR} ]; then + mkdir -p ${OUTDIR} +fi + +ruby ${GENERATOR} ${TEMPLATE} ${OUTDIR}/${OUTPUT} diff --git a/es2panda/scripts/generate_js_bytecode.py b/es2panda/scripts/generate_js_bytecode.py new file mode 100755 index 0000000000000000000000000000000000000000..78cebf940d51aade411644d34ce03872d8cdfc15 --- /dev/null +++ b/es2panda/scripts/generate_js_bytecode.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 +# coding: utf-8 + +""" +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. + +Description: Generate javascript byte code using es2abc +""" + +import os +import subprocess +import platform +import argparse + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument('--src-js', + help = 'js source file') + parser.add_argument('--dst-file', + help = 'the converted target file') + parser.add_argument('--frontend-tool-path', + help = 'path of the frontend conversion tool') + parser.add_argument("--debug", action='store_true', + help='whether add debuginfo') + parser.add_argument("--module", action='store_true', + help='whether is module') + parser.add_argument("--commonjs", action='store_true', + help='whether is commonjs') + arguments = parser.parse_args() + return arguments + +def run_command(cmd, execution_path): + print(" ".join(cmd) + " | execution_path: " + execution_path) + proc = subprocess.Popen(cmd, cwd=execution_path) + proc.wait() + + +def gen_abc_info(input_arguments): + frontend_tool_path = input_arguments.frontend_tool_path + + (path, name) = os.path.split(frontend_tool_path) + + cmd = [os.path.join("./", name, "es2abc"), + '--output', input_arguments.dst_file, + input_arguments.src_js] + + if input_arguments.debug: + src_index = cmd.index(input_arguments.src_js) + cmd.insert(src_index, '--debug-info') + if input_arguments.module: + src_index = cmd.index(input_arguments.src_js) + cmd.insert(src_index, '--module') + if input_arguments.commonjs: + src_index = cmd.index(input_arguments.src_js) + # insert commonjs option to cmd later + run_command(cmd, path) + + +if __name__ == '__main__': + gen_abc_info(parse_args()) \ No newline at end of file diff --git a/test262/config.py b/test262/config.py index bd87d40b4b3a0e1107c4728fb3952a6681d7ae5f..4ae761e555a0657c5f8ec016c3075efe42d68ce3 100755 --- a/test262/config.py +++ b/test262/config.py @@ -43,7 +43,6 @@ TEST_ES2021_DIR = os.path.join(DATA_DIR, "test_es2021") TEST_INTL_DIR = os.path.join(DATA_DIR, "test_intl") TEST_CI_DIR = os.path.join(DATA_DIR, "test_CI") -DEFAULT_ARK_FRONTEND_TOOL = os.path.join(ARK_DIR, "build", "src", "index.js") DEFAULT_ARK_TOOL = os.path.join(ARK_JS_RUNTIME_DIR, "ark_js_vm") DEFAULT_LIBS_DIR = f"{ARK_DIR}:{ICUI_DIR}:{LLVM_DIR}:{ARK_JS_RUNTIME_DIR}" @@ -80,7 +79,14 @@ ARK_FRONTEND_LIST = [ "ts2panda", "es2panda" ] -DEFAULT_ARK_FRONTEND = ARK_FRONTEND_LIST[0] + +DEFAULT_ARK_FRONTEND_TOOL_LIST = [ + os.path.join(ARK_DIR, "build", "src", "index.js"), + os.path.join(ARK_DIR, "es2abc") +] + +DEFAULT_ARK_FRONTEND = ARK_FRONTEND_LIST[1] +DEFAULT_ARK_FRONTEND_TOOL = DEFAULT_ARK_FRONTEND_TOOL_LIST[1] ARK_ARCH_LIST = [ "x64", @@ -89,3 +95,5 @@ ARK_ARCH_LIST = [ ] DEFAULT_ARK_ARCH = ARK_ARCH_LIST[0] + +DEFAULT_OPT_LEVEL = 0 diff --git a/test262/run_sunspider.py b/test262/run_sunspider.py index 4a2e0d26c2beaff809be19f605fed7dd07a6316f..3a8d11469da7dc3e736c332e50990c3cb88023ab 100755 --- a/test262/run_sunspider.py +++ b/test262/run_sunspider.py @@ -62,6 +62,10 @@ def parse_args(): default=DEFAULT_ARK_ARCH, required=False, help="the root path for qemu-aarch64 or qemu-arm") + parser.add_argument('--opt-level', + default=DEFAULT_OPT_LEVEL, + required=False, + help="the opt level for es2abc") arguments = parser.parse_args() return arguments @@ -143,6 +147,7 @@ class ArkProgram(): self.js_file = "" self.arch = ARK_ARCH self.arch_root = "" + self.opt_level = DEFAULT_OPT_LEVEL def proce_parameters(self): if self.args.ark_tool: @@ -157,6 +162,9 @@ class ArkProgram(): if self.args.ark_frontend: self.ark_frontend = self.args.ark_frontend + if self.args.opt_level: + self.opt_level = self.args.opt_level + self.module_list = self.args.module_list.splitlines() self.js_file = self.args.js_file @@ -177,13 +185,15 @@ class ArkProgram(): mod_opt_index = 3 cmd_args = ['node', '--expose-gc', frontend_tool, js_file, '-o', out_file] + if file_name in self.module_list: + cmd_args.insert(mod_opt_index, "-m") elif self.ark_frontend == ARK_FRONTEND_LIST[1]: mod_opt_index = 1 - cmd_args = [frontend_tool, '-c', - '-e', 'js', '-o', out_file, '-i', js_file] + cmd_args = [frontend_tool, '--opt-level=' + str(self.opt_level), + '--thread=0', '--output', out_file, js_file] + if file_name in self.module_list: + cmd_args.insert(mod_opt_index, "--module") - if file_name in self.module_list: - cmd_args.insert(mod_opt_index, "-m") retcode = exec_command(cmd_args) return retcode @@ -196,7 +206,7 @@ class ArkProgram(): elif platform.system() == "Linux" : os.environ["LD_LIBRARY_PATH"] = self.libs_dir else : - sys.exit(f" test262 on {platform.system()} not supported"); + sys.exit(f" test262 on {platform.system()} not supported"); file_name_pre = os.path.splitext(self.js_file)[0] cmd_args = [] if self.arch == ARK_ARCH_LIST[1]: diff --git a/test262/run_test262.py b/test262/run_test262.py index 4c51f40d7187587998fb4fc57f82a4e68a67c363..02f02675183595c2a1ab62d7a773c7ba0e620412 100755 --- a/test262/run_test262.py +++ b/test262/run_test262.py @@ -27,7 +27,7 @@ import sys import subprocess from multiprocessing import Pool import platform -from utils import * +from utils import * from config import * @@ -88,6 +88,9 @@ def parse_args(): parser.add_argument('--ark-arch-root', default=DEFAULT_ARK_ARCH, help="the root path for qemu-aarch64 or qemu-arm") + parser.add_argument('--opt-level', + default=DEFAULT_OPT_LEVEL, + help="the opt level for es2abc") return parser.parse_args() @@ -333,7 +336,7 @@ class TestPrepare(): if self.args.intl: files = self.get_tests_from_file(INTL_LIST_FILE) return files - + def prepare_es2015_tests(self): files = [] files = self.collect_tests() @@ -473,6 +476,7 @@ def get_host_args(args, host_type): ark_frontend = DEFAULT_ARK_FRONTEND ark_arch = DEFAULT_ARK_ARCH module_list = '' + opt_level = DEFAULT_OPT_LEVEL with open(MODULE_FILES_LIST) as fopen: module_list = fopen.read() @@ -491,13 +495,17 @@ def get_host_args(args, host_type): if args.ark_frontend: ark_frontend = args.ark_frontend + if args.opt_level: + opt_level = args.opt_level + if host_type == DEFAULT_HOST_TYPE: host_args = f"-B test262/run_sunspider.py " host_args += f"--ark-tool={ark_tool} " host_args += f"--ark-frontend-tool={ark_frontend_tool} " host_args += f"--libs-dir={libs_dir} " host_args += f"--ark-frontend={ark_frontend} " - host_args += f"--module-list={module_list}" + host_args += f"--module-list={module_list} " + host_args += f"--opt-level={opt_level} " if args.ark_arch != ark_arch: host_args += f"--ark-arch={args.ark_arch} "