From cf8d5be1793b2c5011ef0297b0cd6ae6fbb76f03 Mon Sep 17 00:00:00 2001 From: Aleksandr Semenov Date: Sat, 11 Nov 2023 11:02:49 +0300 Subject: [PATCH 1/2] es2panda: Parse jit-compiler and bco options Signed-off-by: Aleksandr Semenov --- ets2panda/test/CMakeLists.txt | 2 + ets2panda/test/options/CMakeLists.txt | 36 +++++++++++ ets2panda/util/options.cpp | 88 ++++++++++++++++++++++++++- 3 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 ets2panda/test/options/CMakeLists.txt diff --git a/ets2panda/test/CMakeLists.txt b/ets2panda/test/CMakeLists.txt index a602e480e5..ba88fb843f 100644 --- a/ets2panda/test/CMakeLists.txt +++ b/ets2panda/test/CMakeLists.txt @@ -118,3 +118,5 @@ if(PANDA_WITH_ETS) add_subdirectory(tsconfig) endif() + +add_subdirectory(options) diff --git a/ets2panda/test/options/CMakeLists.txt b/ets2panda/test/options/CMakeLists.txt new file mode 100644 index 0000000000..dd46aabd24 --- /dev/null +++ b/ets2panda/test/options/CMakeLists.txt @@ -0,0 +1,36 @@ +# Copyright (c) 2021-2023 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(CMAKE_CROSSCOMPILING) + return() +endif() + +add_custom_target(es2panda_tests_options) +add_dependencies(es2panda_tests es2panda_tests_options) + +function(check_option_help_otput target_name INPUT_ARGS OUTPUT_HELP_LINE) + separate_arguments(INPUT_ARGS) + add_custom_target(es2panda_check_opts_${target_name} + COMMENT "es2panda: checking option ${INPUT_ARGS}" + COMMAND es2panda ${INPUT_ARGS} 2> ${CMAKE_BINARY_DIR}/es2panda_check_opts_${target_name}.out || true + COMMAND grep -q ${OUTPUT_HELP_LINE} ${CMAKE_BINARY_DIR}/es2panda_check_opts_${target_name}.out + DEPENDS es2panda + ) + + add_dependencies(es2panda_tests_options es2panda_check_opts_${target_name}) +endfunction() + +check_option_help_otput(bco_opt "--help" "bco-optimizer:") +check_option_help_otput(bco_opt_help "--bco-optimizer --help" "bytecode-opt-peepholes:") +check_option_help_otput(comp_opt "--help" "bco-compiler:") +check_option_help_otput(comp_opt_help "--bco-compiler --help" "compiler-disasm-dump:") diff --git a/ets2panda/util/options.cpp b/ets2panda/util/options.cpp index c7f2350ca8..60e35b3075 100644 --- a/ets2panda/util/options.cpp +++ b/ets2panda/util/options.cpp @@ -19,6 +19,11 @@ #include +#ifdef PANDA_WITH_BYTECODE_OPTIMIZER +#include "bytecode_optimizer/bytecodeopt_options.h" +#include "compiler/compiler_options.h" +#endif + namespace panda::es2panda::util { template T RemoveExtension(T const &filename) @@ -55,9 +60,84 @@ static std::unordered_set StringToStringSet(const std::string &str) return res; } +// NOLINTNEXTLINE(modernize-avoid-c-arrays, hicpp-avoid-c-arrays) +static void SplitArgs(int argc, const char *argv[], std::vector &es2panda_args, + std::vector &bco_compiler_args, std::vector &bytecodeopt_args) +{ + constexpr std::string_view COMPILER_PREFIX = "--bco-compiler"; + constexpr std::string_view OPTIMIZER_PREFIX = "--bco-optimizer"; + + enum class OptState { ES2PANDA, JIT_COMPILER, OPTIMIZER }; + OptState opt_state = OptState::ES2PANDA; + + std::unordered_map *> args_map = {{OptState::ES2PANDA, &es2panda_args}, + {OptState::JIT_COMPILER, &bco_compiler_args}, + {OptState::OPTIMIZER, &bytecodeopt_args}}; + + for (int i = 1; i < argc; i++) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + const char *arg_i = argv[i]; + if (COMPILER_PREFIX == arg_i) { + opt_state = OptState::JIT_COMPILER; + continue; + } + + if (OPTIMIZER_PREFIX == arg_i) { + opt_state = OptState::OPTIMIZER; + continue; + } + + args_map[opt_state]->emplace_back(arg_i); + opt_state = OptState::ES2PANDA; + } +} + +template +static bool ParseComponentArgs(const std::vector &args, T &options) +{ + panda::PandArgParser parser; + options.AddOptions(&parser); + if (!parser.Parse(args)) { + std::cerr << parser.GetErrorString(); + std::cerr << parser.GetHelpString(); + return false; + } + + if (auto options_err = options.Validate(); options_err) { + std::cerr << "Error: " << options_err.value().GetMessage() << std::endl; + return false; + } + + return true; +} + +static bool ParseBCOCompilerOptions([[maybe_unused]] const std::vector &compiler_args, + [[maybe_unused]] const std::vector &bytecodeopt_args) +{ +#ifdef PANDA_WITH_BYTECODE_OPTIMIZER + if (!ParseComponentArgs(compiler_args, panda::compiler::OPTIONS)) { + return false; + } + if (!ParseComponentArgs(bytecodeopt_args, panda::bytecodeopt::OPTIONS)) { + return false; + } +#endif + + return true; +} + // NOLINTNEXTLINE(readability-function-size) bool Options::Parse(int argc, const char **argv) { + std::vector es2panda_args; + std::vector bco_compiler_args; + std::vector bytecodeopt_args; + + SplitArgs(argc, argv, es2panda_args, bco_compiler_args, bytecodeopt_args); + if (!ParseBCOCompilerOptions(bco_compiler_args, bytecodeopt_args)) { + return false; + } + panda::PandArg op_help("help", false, "Print this message and exit"); // parser @@ -128,7 +208,7 @@ bool Options::Parse(int argc, const char **argv) argparser_->EnableTail(); argparser_->EnableRemainder(); - if (!argparser_->Parse(argc, argv) || op_help.GetValue()) { + if (!argparser_->Parse(es2panda_args) || op_help.GetValue()) { std::stringstream ss; ss << argparser_->GetErrorString() << std::endl; @@ -139,6 +219,12 @@ bool Options::Parse(int argc, const char **argv) ss << "optional arguments:" << std::endl; ss << argparser_->GetHelpString() << std::endl; + ss << std::endl; + ss << "--bco-optimizer: Argument directly to bytecode optimizer can be passed after this prefix" << std::endl; + ss << "--bco-compiler: Argument directly to jit-compiler inside bytecode optimizer can be passed after this " + "prefix" + << std::endl; + error_msg_ = ss.str(); return false; } -- Gitee From 0cdcd2a2d47e1937109bb09d54dcecbcf3185910 Mon Sep 17 00:00:00 2001 From: Zelentsov Dmitry Date: Thu, 9 Nov 2023 14:46:23 +0300 Subject: [PATCH 2/2] Implement constructors with default parameters. Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/I8FJLJ?from=project-issue Test: build Signed-off-by: Zelentsov Dmitry --- ets2panda/checker/ets/function.cpp | 30 ++-- .../ir/ets/etsNewClassInstanceExpression.cpp | 2 + ets2panda/ir/ets/etsParameterExpression.cpp | 4 + ets2panda/ir/ets/etsParameterExpression.h | 15 ++ ets2panda/parser/ETSparser.cpp | 159 +++++++++++++----- ets2panda/parser/ETSparser.h | 24 ++- .../ets/optionalLambdaParameter-expected.txt | 4 +- .../ets/default_parameter1-expected.txt | 4 +- .../ets/default_parameter2-expected.txt | 4 +- .../ets/default_parameter4-expected.txt | 10 +- .../ets/default_parameter5-expected.txt | 4 +- ..._implicitly_typed_return_void-expected.txt | 6 +- .../parser/ets/rest_parameter_02-expected.txt | 4 +- .../test/runtime/ets/default_parameters.ets | 49 ++++++ 14 files changed, 240 insertions(+), 79 deletions(-) create mode 100644 ets2panda/test/runtime/ets/default_parameters.ets diff --git a/ets2panda/checker/ets/function.cpp b/ets2panda/checker/ets/function.cpp index ed412dc646..9594d01036 100644 --- a/ets2panda/checker/ets/function.cpp +++ b/ets2panda/checker/ets/function.cpp @@ -290,10 +290,12 @@ bool ETSChecker::ValidateProxySignature(Signature *const signature, return false; } - const auto num_non_default_params = - signature->Params().size() - signature->Function()->Body()->AsBlockStatement()->Statements().size(); + auto const *const proxy_param = signature->Function()->Params().back()->AsETSParameterExpression(); + if (!proxy_param->Ident()->Name().Is(ir::PROXY_PARAMETER_NAME)) { + return false; + } - if (arguments.size() < num_non_default_params) { + if (arguments.size() < proxy_param->GetRequiredParams()) { return false; } @@ -366,17 +368,25 @@ Signature *ETSChecker::ValidateSignatures(ArenaVector &signatures, return nullptr; } + // Just to avoid extra nesting level + auto const check_ambiguous = [this, most_specific_signature, + &pos](Signature const *const proxy_signature) -> void { + auto const *const proxy_param = proxy_signature->Function()->Params().back()->AsETSParameterExpression(); + if (!proxy_param->Ident()->Name().Is(ir::PROXY_PARAMETER_NAME)) { + ThrowTypeError({"Proxy parameter '", proxy_param->Ident()->Name(), "' has invalid name."}, pos); + } + + if (most_specific_signature->Params().size() == proxy_param->GetRequiredParams()) { + ThrowTypeError({"Reference to ", most_specific_signature->Function()->Id()->Name(), " is ambiguous"}, + pos); + } + }; + if (!proxy_signatures.empty()) { auto *const proxy_signature = ChooseMostSpecificProxySignature( proxy_signatures, arguments, arg_type_inference_required, pos, arguments.size()); if (proxy_signature != nullptr) { - const size_t num_non_default_params = - proxy_signature->Params().size() - - proxy_signature->Function()->Body()->AsBlockStatement()->Statements().size(); - if (most_specific_signature->Params().size() == num_non_default_params) { - ThrowTypeError( - {"Reference to ", most_specific_signature->Function()->Id()->Name(), " is ambiguous"}, pos); - } + check_ambiguous(proxy_signature); } } diff --git a/ets2panda/ir/ets/etsNewClassInstanceExpression.cpp b/ets2panda/ir/ets/etsNewClassInstanceExpression.cpp index e0a0ce1b2d..f39597c1c6 100644 --- a/ets2panda/ir/ets/etsNewClassInstanceExpression.cpp +++ b/ets2panda/ir/ets/etsNewClassInstanceExpression.cpp @@ -164,6 +164,8 @@ checker::Type *ETSNewClassInstanceExpression::Check([[maybe_unused]] checker::ET auto *signature = checker->ResolveConstructExpression(callee_obj, arguments_, Start()); checker->CheckObjectLiteralArguments(signature, arguments_); + checker->AddUndefinedParamsForDefaultParams(signature, arguments_, checker); + checker->ValidateSignatureAccessibility(callee_obj, signature, Start()); ASSERT(signature->Function() != nullptr); diff --git a/ets2panda/ir/ets/etsParameterExpression.cpp b/ets2panda/ir/ets/etsParameterExpression.cpp index 3d00268107..0445df4d22 100644 --- a/ets2panda/ir/ets/etsParameterExpression.cpp +++ b/ets2panda/ir/ets/etsParameterExpression.cpp @@ -171,12 +171,16 @@ ETSParameterExpression *ETSParameterExpression::Clone(ArenaAllocator *const allo if (auto *const clone = allocator->New(ident_or_spread, initializer); clone != nullptr) { ident_or_spread->SetParent(clone); + if (initializer != nullptr) { initializer->SetParent(clone); } + if (parent != nullptr) { clone->SetParent(parent); } + + clone->SetRequiredParams(extra_value_); return clone; } diff --git a/ets2panda/ir/ets/etsParameterExpression.h b/ets2panda/ir/ets/etsParameterExpression.h index 7786d77fc3..64af2b1778 100644 --- a/ets2panda/ir/ets/etsParameterExpression.h +++ b/ets2panda/ir/ets/etsParameterExpression.h @@ -23,6 +23,10 @@ class ETSAnalyzer; } // namespace panda::es2panda::checker namespace panda::es2panda::ir { +// NOLINTBEGIN(modernize-avoid-c-arrays) +inline constexpr char const PROXY_PARAMETER_NAME[] = "$proxy_mask$"; +// NOLINTEND(modernize-avoid-c-arrays) + class ETSParameterExpression final : public Expression { public: ETSParameterExpression() = delete; @@ -64,6 +68,16 @@ public: return spread_ != nullptr; } + [[nodiscard]] std::size_t GetRequiredParams() const noexcept + { + return extra_value_; + } + + void SetRequiredParams(std::size_t const value) noexcept + { + extra_value_ = value; + } + // NOLINTNEXTLINE(google-default-arguments) [[nodiscard]] ETSParameterExpression *Clone(ArenaAllocator *allocator, AstNode *parent = nullptr) override; @@ -80,6 +94,7 @@ private: Expression *initializer_; SpreadElement *spread_ = nullptr; util::StringView saved_lexer_ = ""; + std::size_t extra_value_ = 0U; }; } // namespace panda::es2panda::ir diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index 1100af3be5..b4e80fc32e 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -2168,13 +2168,15 @@ void ETSParser::CreateClassFunctionDeclaration(ir::MethodDefinition *method) method->Function()->AddFlag(ir::ScriptFunctionFlags::OVERLOAD); } -bool ETSParser::HasDefaultParam(const ir::ScriptFunction *const function) +std::pair ETSParser::CheckDefaultParameters(const ir::ScriptFunction *const function) const { bool has_default_parameter = false; bool has_rest_parameter = false; + std::size_t required_parameters_number = 0U; for (auto *const it : function->Params()) { auto const *const param = it->AsETSParameterExpression(); + if (param->IsRestParameter()) { has_rest_parameter = true; continue; @@ -2192,23 +2194,58 @@ bool ETSParser::HasDefaultParam(const ir::ScriptFunction *const function) if (has_default_parameter) { ThrowSyntaxError("Required parameter follows default parameter(s).", param->Start()); } - } - if (!has_default_parameter) { - return false; + ++required_parameters_number; } - if (has_rest_parameter) { + if (has_default_parameter && has_rest_parameter) { ThrowSyntaxError("Both optional and rest parameters are not allowed in function's parameter list.", function->Start()); } - return true; + return std::make_pair(has_default_parameter, required_parameters_number); } -std::string ETSParser::CreateProxyMethodName(const ir::ScriptFunction *const function, ir::MethodDefinition *method, - ir::Identifier *ident_node, varbinder::ClassScope *const cls_scope) +ir::MethodDefinition *ETSParser::CreateProxyConstructorDefinition(ir::MethodDefinition const *const method) { + ASSERT(method->IsConstructor()); + + const auto *const function = method->Function(); + std::string proxy_method = function->Id()->Name().Mutf8() + '('; + + for (const auto *const it : function->Params()) { + auto const *const param = it->AsETSParameterExpression(); + proxy_method += param->Ident()->Name().Mutf8() + ": " + GetNameForTypeNode(param->TypeAnnotation()) + ", "; + } + + proxy_method += ir::PROXY_PARAMETER_NAME; + proxy_method += ": int) { this("; + + auto const parameters_number = function->Params().size(); + for (size_t i = 0U; i < parameters_number; ++i) { + if (auto const *const param = function->Params()[i]->AsETSParameterExpression(); param->IsDefault()) { + std::string proxy_if = "(((" + std::string {ir::PROXY_PARAMETER_NAME} + " >> " + std::to_string(i) + + ") & 0x1) == 0) ? " + param->Ident()->Name().Mutf8() + " : (" + + param->LexerSaved().Mutf8() + "), "; + proxy_method += proxy_if; + } else { + proxy_method += function->Params()[i]->AsETSParameterExpression()->Ident()->Name().Mutf8() + ", "; + } + } + + proxy_method.pop_back(); // Note: at least one parameter always should present! + proxy_method.pop_back(); + proxy_method += ") }"; + + return CreateConstructorDefinition(method->Modifiers(), proxy_method, DEFAULT_PROXY_FILE); +} + +ir::MethodDefinition *ETSParser::CreateProxyMethodDefinition(ir::MethodDefinition const *const method, + ir::Identifier const *const ident_node) +{ + ASSERT(!method->IsConstructor()); + + const auto *const function = method->Function(); std::string proxy_method = function->Id()->Name().Mutf8() + "_proxy("; for (const auto *const it : function->Params()) { @@ -2216,32 +2253,42 @@ std::string ETSParser::CreateProxyMethodName(const ir::ScriptFunction *const fun proxy_method += param->Ident()->Name().Mutf8() + ": " + GetNameForTypeNode(param->TypeAnnotation()) + ", "; } - const bool has_function_return_type = method->Function()->ReturnTypeAnnotation() != nullptr; + const bool has_function_return_type = function->ReturnTypeAnnotation() != nullptr; const std::string return_type = - has_function_return_type ? GetNameForTypeNode(method->Function()->ReturnTypeAnnotation()) : ""; + has_function_return_type ? GetNameForTypeNode(function->ReturnTypeAnnotation()) : ""; - proxy_method += has_function_return_type ? "proxy_int:int):" + return_type + "{" : "proxy_int:int) {"; + proxy_method += ir::PROXY_PARAMETER_NAME; + proxy_method += ": int)"; + if (has_function_return_type) { + proxy_method += ": " + return_type; + } + proxy_method += " { "; auto const parameters_number = function->Params().size(); - for (size_t i = 0U; i < parameters_number; i++) { + for (size_t i = 0U; i < parameters_number; ++i) { if (auto const *const param = function->Params()[i]->AsETSParameterExpression(); param->IsDefault()) { - std::string proxy_if = "if (((proxy_int >> " + std::to_string(i) + ") & 0x1) == 1) { " + - param->Ident()->Name().Mutf8() + " = " + param->LexerSaved().Mutf8() + " }"; + std::string proxy_if = "if (((" + std::string {ir::PROXY_PARAMETER_NAME} + " >> " + std::to_string(i) + + ") & 0x1) == 1) { " + param->Ident()->Name().Mutf8() + " = " + + param->LexerSaved().Mutf8() + " } "; proxy_method += proxy_if; } } + proxy_method += ' '; if (return_type != "void") { - if (cls_scope->Parent()->IsGlobalScope()) { + if (auto *const cls_scope = VarBinder()->GetScope()->AsClassScope(); cls_scope->Parent()->IsGlobalScope()) { proxy_method += "return "; } else if (method->IsStatic()) { + ASSERT(ident_node != nullptr); proxy_method += "return " + ident_node->Name().Mutf8() + "."; } else { proxy_method += "return this."; } } - proxy_method += function->Id()->Name().Mutf8() + "("; + proxy_method += function->Id()->Name().Mutf8(); + proxy_method += '('; + for (const auto *const it : function->Params()) { proxy_method += it->AsETSParameterExpression()->Ident()->Name().Mutf8() + ", "; } @@ -2249,39 +2296,34 @@ std::string ETSParser::CreateProxyMethodName(const ir::ScriptFunction *const fun proxy_method.pop_back(); proxy_method += ") }"; - return proxy_method; + return CreateMethodDefinition(method->Modifiers(), proxy_method, DEFAULT_PROXY_FILE); } void ETSParser::AddProxyOverloadToMethodWithDefaultParams(ir::MethodDefinition *method, ir::Identifier *ident_node) { - if (method->IsConstructor()) { - return; // NOTE(szd): Fix constructors not working with default params - } - - const auto *const function = method->Function(); + if (auto const [has_default_parameters, required_parameters] = CheckDefaultParameters(method->Function()); + has_default_parameters) { + if (ir::MethodDefinition *proxy_method_def = !method->IsConstructor() + ? CreateProxyMethodDefinition(method, ident_node) + : CreateProxyConstructorDefinition(method); + proxy_method_def != nullptr) { + auto *const proxy_param = proxy_method_def->Function()->Params().back()->AsETSParameterExpression(); + proxy_param->SetRequiredParams(required_parameters); - if (!HasDefaultParam(function)) { - return; - } + proxy_method_def->Function()->SetDefaultParamProxy(); + proxy_method_def->Function()->AddFlag(ir::ScriptFunctionFlags::OVERLOAD); - auto *const cls_scope = VarBinder()->GetScope()->AsClassScope(); - varbinder::LocalScope *target_scope = - method->IsStatic() ? cls_scope->StaticMethodScope() : cls_scope->InstanceMethodScope(); - auto *const found = target_scope->FindLocal(method->Id()->Name(), varbinder::ResolveBindingOptions::BINDINGS); + auto *const var = method->Id()->Variable(); + auto *const current_node = var->Declaration()->Node(); - std::string proxy_method = CreateProxyMethodName(function, method, ident_node, cls_scope); + proxy_method_def->Id()->SetVariable(var); + proxy_method_def->SetParent(current_node); - auto class_ctx = - varbinder::LexicalScope::Enter(VarBinder(), GetProgram()->GlobalClassScope()); - - auto *const proxy_method_def = CreateMethodDefinition(method->Modifiers(), proxy_method, ".ets"); - proxy_method_def->Function()->SetDefaultParamProxy(); - - auto *const current_node = found->Declaration()->Node(); - current_node->AsMethodDefinition()->AddOverload(proxy_method_def); - proxy_method_def->Id()->SetVariable(found); - proxy_method_def->SetParent(current_node); - proxy_method_def->Function()->AddFlag(ir::ScriptFunctionFlags::OVERLOAD); + if (!method->IsConstructor()) { + current_node->AsMethodDefinition()->AddOverload(proxy_method_def); + } + } + } } std::string ETSParser::PrimitiveTypeToName(ir::PrimitiveType type) @@ -2310,7 +2352,7 @@ std::string ETSParser::PrimitiveTypeToName(ir::PrimitiveType type) } } -std::string ETSParser::GetNameForTypeNode(const ir::TypeNode *type_annotation) +std::string ETSParser::GetNameForTypeNode(const ir::TypeNode *type_annotation) const { if ((type_annotation->IsNullAssignable() || type_annotation->IsUndefinedAssignable()) && type_annotation->IsETSUnionType()) { @@ -4727,6 +4769,39 @@ ir::MethodDefinition *ETSParser::CreateMethodDefinition(ir::ModifierFlags modifi return method_definition; } +ir::MethodDefinition *ETSParser::CreateConstructorDefinition(ir::ModifierFlags modifiers, + std::string_view const source_code, + std::string_view const file_name) +{ + util::UString source {source_code, Allocator()}; + auto const isp = InnerSourceParser(this); + auto const lexer = InitLexer({file_name, source.View().Utf8()}); + + auto const start_loc = Lexer()->GetToken().Start(); + Lexer()->NextToken(); + + if (IsClassMethodModifier(Lexer()->GetToken().Type())) { + modifiers |= ParseClassMethodModifiers(false); + } + + if (Lexer()->GetToken().Type() != lexer::TokenType::KEYW_CONSTRUCTOR) { + ThrowSyntaxError({"Unexpected token. 'Constructor' keyword is expected."}); + } + + if ((modifiers & ir::ModifierFlags::ASYNC) != 0) { + ThrowSyntaxError({"Constructor should not be async."}); + } + + auto *member_name = AllocNode(Lexer()->GetToken().Ident(), Allocator()); + modifiers |= ir::ModifierFlags::CONSTRUCTOR; + Lexer()->NextToken(); + + auto *const method_definition = ParseClassMethodDefinition(member_name, modifiers); + method_definition->SetStart(start_loc); + + return method_definition; +} + ir::Expression *ETSParser::CreateExpression(std::string_view const source_code, ExpressionParseFlags const flags, std::string_view const file_name) { diff --git a/ets2panda/parser/ETSparser.h b/ets2panda/parser/ETSparser.h index d1eb419aa8..d84e8c0ac2 100644 --- a/ets2panda/parser/ETSparser.h +++ b/ets2panda/parser/ETSparser.h @@ -165,12 +165,13 @@ private: ir::TypeNode *ParseWildcardType(TypeAnnotationParsingOptions *options); ir::TypeNode *ParseFunctionType(); void CreateClassFunctionDeclaration(ir::MethodDefinition *method); - bool HasDefaultParam(const ir::ScriptFunction *function); - std::string CreateProxyMethodName(const ir::ScriptFunction *function, ir::MethodDefinition *method, - ir::Identifier *ident_node, varbinder::ClassScope *cls_scope); + std::pair CheckDefaultParameters(const ir::ScriptFunction *function) const; + ir::MethodDefinition *CreateProxyMethodDefinition(ir::MethodDefinition const *method, + ir::Identifier const *ident_node); + ir::MethodDefinition *CreateProxyConstructorDefinition(ir::MethodDefinition const *method); void AddProxyOverloadToMethodWithDefaultParams(ir::MethodDefinition *method, ir::Identifier *ident_node = nullptr); static std::string PrimitiveTypeToName(ir::PrimitiveType type); - std::string GetNameForTypeNode(const ir::TypeNode *type_annotation); + std::string GetNameForTypeNode(const ir::TypeNode *type_annotation) const; ir::TSInterfaceDeclaration *ParseInterfaceBody(ir::Identifier *name, bool is_static); bool IsArrowFunctionExpressionStart(); ir::ArrowFunctionExpression *ParseArrowFunctionExpression(); @@ -302,10 +303,14 @@ private: void CheckDeclare(); - // Methods to create AST node(s) from the specified string (part of valid ETS-code!) - // NOTE: the correct initial scope should be entered BEFORE calling any of these methods, - // and correct parent and, probably, variable set to the node(s) after obtaining - + // Methods to create AST node(s) from the specified string (part of valid ETS-code!) + // NOTE: the correct initial scope should be entered BEFORE calling any of these methods, + // and correct parent and, probably, variable set to the node(s) after obtaining + // NOLINTBEGIN(modernize-avoid-c-arrays) + inline static constexpr char const DEFAULT_SOURCE_FILE[] = ".ets"; + inline static constexpr char const DEFAULT_PROXY_FILE[] = ".ets"; + // NOLINTEND(modernize-avoid-c-arrays) + // NOLINTBEGIN(google-default-arguments) ir::Statement *CreateStatement(std::string_view source_code, std::string_view file_name = DEFAULT_SOURCE_FILE); ir::Statement *CreateFormattedStatement(std::string_view source_code, std::vector &inserting_nodes, std::string_view file_name = DEFAULT_SOURCE_FILE); @@ -321,7 +326,8 @@ private: ir::MethodDefinition *CreateMethodDefinition(ir::ModifierFlags modifiers, std::string_view source_code, std::string_view file_name = DEFAULT_SOURCE_FILE); - + ir::MethodDefinition *CreateConstructorDefinition(ir::ModifierFlags modifiers, std::string_view source_code, + std::string_view file_name = DEFAULT_SOURCE_FILE); ir::TypeNode *CreateTypeAnnotation(TypeAnnotationParsingOptions *options, std::string_view source_code, std::string_view file_name = DEFAULT_SOURCE_FILE); diff --git a/ets2panda/test/compiler/ets/optionalLambdaParameter-expected.txt b/ets2panda/test/compiler/ets/optionalLambdaParameter-expected.txt index ca7577b0c3..9924e957d6 100644 --- a/ets2panda/test/compiler/ets/optionalLambdaParameter-expected.txt +++ b/ets2panda/test/compiler/ets/optionalLambdaParameter-expected.txt @@ -513,7 +513,7 @@ "type": "ETSParameterExpression", "name": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "typeAnnotation": { "type": "ETSPrimitiveType", "loc": { @@ -608,7 +608,7 @@ "operator": ">>", "left": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "decorators": [], "loc": { "start": { diff --git a/ets2panda/test/parser/ets/default_parameter1-expected.txt b/ets2panda/test/parser/ets/default_parameter1-expected.txt index 70a65a1979..edf5d5438e 100644 --- a/ets2panda/test/parser/ets/default_parameter1-expected.txt +++ b/ets2panda/test/parser/ets/default_parameter1-expected.txt @@ -691,7 +691,7 @@ "type": "ETSParameterExpression", "name": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "typeAnnotation": { "type": "ETSPrimitiveType", "loc": { @@ -758,7 +758,7 @@ "operator": ">>", "left": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "decorators": [], "loc": { "start": { diff --git a/ets2panda/test/parser/ets/default_parameter2-expected.txt b/ets2panda/test/parser/ets/default_parameter2-expected.txt index 0267fc1b3f..96e2d6dcdf 100644 --- a/ets2panda/test/parser/ets/default_parameter2-expected.txt +++ b/ets2panda/test/parser/ets/default_parameter2-expected.txt @@ -676,7 +676,7 @@ "type": "ETSParameterExpression", "name": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "typeAnnotation": { "type": "ETSPrimitiveType", "loc": { @@ -743,7 +743,7 @@ "operator": ">>", "left": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "decorators": [], "loc": { "start": { diff --git a/ets2panda/test/parser/ets/default_parameter4-expected.txt b/ets2panda/test/parser/ets/default_parameter4-expected.txt index 35457f1bc8..5c072e7bcd 100644 --- a/ets2panda/test/parser/ets/default_parameter4-expected.txt +++ b/ets2panda/test/parser/ets/default_parameter4-expected.txt @@ -816,7 +816,7 @@ "type": "ETSParameterExpression", "name": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "typeAnnotation": { "type": "ETSPrimitiveType", "loc": { @@ -883,7 +883,7 @@ "operator": ">>", "left": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "decorators": [], "loc": { "start": { @@ -1067,7 +1067,7 @@ "operator": ">>", "left": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "decorators": [], "loc": { "start": { @@ -1656,7 +1656,7 @@ "type": "ETSParameterExpression", "name": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "typeAnnotation": { "type": "ETSPrimitiveType", "loc": { @@ -1723,7 +1723,7 @@ "operator": ">>", "left": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "decorators": [], "loc": { "start": { diff --git a/ets2panda/test/parser/ets/default_parameter5-expected.txt b/ets2panda/test/parser/ets/default_parameter5-expected.txt index c7eec11850..ab0a5a6760 100644 --- a/ets2panda/test/parser/ets/default_parameter5-expected.txt +++ b/ets2panda/test/parser/ets/default_parameter5-expected.txt @@ -861,7 +861,7 @@ "type": "ETSParameterExpression", "name": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "typeAnnotation": { "type": "ETSPrimitiveType", "loc": { @@ -928,7 +928,7 @@ "operator": ">>", "left": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "decorators": [], "loc": { "start": { diff --git a/ets2panda/test/parser/ets/default_parameter_implicitly_typed_return_void-expected.txt b/ets2panda/test/parser/ets/default_parameter_implicitly_typed_return_void-expected.txt index fcf3644024..1e35125767 100644 --- a/ets2panda/test/parser/ets/default_parameter_implicitly_typed_return_void-expected.txt +++ b/ets2panda/test/parser/ets/default_parameter_implicitly_typed_return_void-expected.txt @@ -690,7 +690,7 @@ "type": "ETSParameterExpression", "name": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "typeAnnotation": { "type": "ETSPrimitiveType", "loc": { @@ -744,7 +744,7 @@ "operator": ">>", "left": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "decorators": [], "loc": { "start": { @@ -928,7 +928,7 @@ "operator": ">>", "left": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "decorators": [], "loc": { "start": { diff --git a/ets2panda/test/parser/ets/rest_parameter_02-expected.txt b/ets2panda/test/parser/ets/rest_parameter_02-expected.txt index 9dcbe17e90..87a53b8d5a 100644 --- a/ets2panda/test/parser/ets/rest_parameter_02-expected.txt +++ b/ets2panda/test/parser/ets/rest_parameter_02-expected.txt @@ -793,7 +793,7 @@ "type": "ETSParameterExpression", "name": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "typeAnnotation": { "type": "ETSPrimitiveType", "loc": { @@ -860,7 +860,7 @@ "operator": ">>", "left": { "type": "Identifier", - "name": "proxy_int", + "name": "$proxy_mask$", "decorators": [], "loc": { "start": { diff --git a/ets2panda/test/runtime/ets/default_parameters.ets b/ets2panda/test/runtime/ets/default_parameters.ets new file mode 100644 index 0000000000..a660a80c04 --- /dev/null +++ b/ets2panda/test/runtime/ets/default_parameters.ets @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021-2023 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. + */ + +function foo(a: int = 3, b: int = 5): int { + return a * 10 + b; +} + +class C { + x: int; + y: int; + + constructor (a: int = 3, b: int = 5) { + this.x = a; + this.y = b; + } +} + +function main(): void { + + let res = foo(5, 7); + assert (res == 57); + + res = foo(7); + assert (res == 75); + + res = foo(); + assert (res == 35); + + let c0 = new C(); + assert (c0.x == 3 && c0.y == 5); + + let c1 = new C(7); + assert (c1.x == 7 && c1.y == 5); + + let c2 = new C(5, 7); + assert (c2.x == 5 && c2.y == 7); +} -- Gitee