From ec07e2d2f1f3a0b7aec5ef74152e47c46347be64 Mon Sep 17 00:00:00 2001 From: Csaba Hurton Date: Mon, 30 Oct 2023 09:49:39 +0100 Subject: [PATCH 1/6] (10) Move Compile and Check Logic from ASTNode classes Compile logic is moved to JSCompiler and ETSCompiler classes. Check logic with their helper functions is moved to TSAnalyzer and ETSAnalyzer classes. AstNodes that are being moved: - nodes inside ir/ts: - TSAnyKeyword - TSBooleanKeyword - TSEnumDeclaration - TSEnumMember - TSExternalModuleReference - TSNumberKeyword - TSObjectKeyword - TSStringKeyword - TSUndefinedKeyword - TSUnknownKeyword - TSVoidKeyword Linked Internal Issue 13840 Change-Id: Id30ca860aa91bd751fafde8530eab5b83304ca85 Signed-off-by: Csaba Hurton --- ets2panda/checker/ETSAnalyzer.cpp | 61 +-- ets2panda/checker/TSAnalyzer.cpp | 375 ++++++++++++++++-- ets2panda/checker/TSAnalyzer.h | 11 + ets2panda/compiler/core/ETSCompiler.cpp | 35 +- ets2panda/compiler/core/JSCompiler.cpp | 36 +- ets2panda/ir/statements/returnStatement.h | 8 +- ets2panda/ir/ts/tsAnyKeyword.cpp | 21 +- ets2panda/ir/ts/tsAnyKeyword.h | 7 +- ets2panda/ir/ts/tsBooleanKeyword.cpp | 21 +- ets2panda/ir/ts/tsBooleanKeyword.h | 7 +- ets2panda/ir/ts/tsEnumDeclaration.cpp | 85 +--- ets2panda/ir/ts/tsEnumDeclaration.h | 9 +- ets2panda/ir/ts/tsEnumMember.cpp | 24 +- ets2panda/ir/ts/tsEnumMember.h | 7 +- ets2panda/ir/ts/tsExternalModuleReference.cpp | 22 +- ets2panda/ir/ts/tsExternalModuleReference.h | 7 +- ets2panda/ir/ts/tsNumberKeyword.cpp | 21 +- ets2panda/ir/ts/tsNumberKeyword.h | 7 +- ets2panda/ir/ts/tsObjectKeyword.cpp | 17 +- ets2panda/ir/ts/tsObjectKeyword.h | 7 +- ets2panda/ir/ts/tsStringKeyword.cpp | 21 +- ets2panda/ir/ts/tsStringKeyword.h | 7 +- ets2panda/ir/ts/tsUndefinedKeyword.cpp | 21 +- ets2panda/ir/ts/tsUndefinedKeyword.h | 7 +- ets2panda/ir/ts/tsUnknownKeyword.cpp | 21 +- ets2panda/ir/ts/tsUnknownKeyword.h | 7 +- ets2panda/ir/ts/tsVoidKeyword.cpp | 21 +- ets2panda/ir/ts/tsVoidKeyword.h | 7 +- 28 files changed, 622 insertions(+), 278 deletions(-) diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index ec729cf229..38bc58d0bd 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -20,14 +20,6 @@ #include "checker/ETSchecker.h" #include "checker/ets/castingContext.h" #include "checker/ets/typeRelationContext.h" -#include "ir/base/catchClause.h" -#include "ir/base/classProperty.h" -#include "ir/base/classStaticBlock.h" -#include "ir/expressions/identifier.h" -#include "ir/expressions/objectExpression.h" -#include "ir/expressions/arrayExpression.h" -#include "ir/statements/blockStatement.h" -#include "ir/statements/returnStatement.h" #include "util/helpers.h" namespace panda::es2panda::checker { @@ -949,9 +941,8 @@ checker::Type *ETSAnalyzer::Check(ir::WhileStatement *st) const UNREACHABLE(); } // from ts folder -checker::Type *ETSAnalyzer::Check(ir::TSAnyKeyword *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSAnyKeyword *node) const { - (void)node; UNREACHABLE(); } @@ -973,9 +964,8 @@ checker::Type *ETSAnalyzer::Check(ir::TSBigintKeyword *node) const UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSBooleanKeyword *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSBooleanKeyword *node) const { - (void)node; UNREACHABLE(); } @@ -999,19 +989,36 @@ checker::Type *ETSAnalyzer::Check(ir::TSConstructorType *node) const checker::Type *ETSAnalyzer::Check(ir::TSEnumDeclaration *st) const { - (void)st; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + varbinder::Variable *enum_var = st->Key()->Variable(); + ASSERT(enum_var != nullptr); + + if (enum_var->TsType() == nullptr) { + checker::Type *ets_enum_type; + if (auto *const item_init = st->Members().front()->AsTSEnumMember()->Init(); item_init->IsNumberLiteral()) { + ets_enum_type = checker->CreateETSEnumType(st); + } else if (item_init->IsStringLiteral()) { + ets_enum_type = checker->CreateETSStringEnumType(st); + } else { + checker->ThrowTypeError("Invalid enumeration value type.", st->Start()); + } + st->SetTsType(ets_enum_type); + ets_enum_type->SetVariable(enum_var); + enum_var->SetTsType(ets_enum_type); + } else if (st->TsType() == nullptr) { + st->SetTsType(enum_var->TsType()); + } + + return st->TsType(); } -checker::Type *ETSAnalyzer::Check(ir::TSEnumMember *st) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSEnumMember *st) const { - (void)st; UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSExternalModuleReference *expr) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSExternalModuleReference *expr) const { - (void)expr; UNREACHABLE(); } @@ -1117,15 +1124,13 @@ checker::Type *ETSAnalyzer::Check(ir::TSNullKeyword *node) const UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSNumberKeyword *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSNumberKeyword *node) const { - (void)node; UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSObjectKeyword *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSObjectKeyword *node) const { - (void)node; UNREACHABLE(); } @@ -1147,9 +1152,8 @@ checker::Type *ETSAnalyzer::Check(ir::TSQualifiedName *expr) const UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSStringKeyword *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSStringKeyword *node) const { - (void)node; UNREACHABLE(); } @@ -1225,9 +1229,8 @@ checker::Type *ETSAnalyzer::Check(ir::TSTypeReference *node) const UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSUndefinedKeyword *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSUndefinedKeyword *node) const { - (void)node; UNREACHABLE(); } @@ -1237,15 +1240,13 @@ checker::Type *ETSAnalyzer::Check(ir::TSUnionType *node) const UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSUnknownKeyword *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSUnknownKeyword *node) const { - (void)node; UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSVoidKeyword *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSVoidKeyword *node) const { - (void)node; UNREACHABLE(); } diff --git a/ets2panda/checker/TSAnalyzer.cpp b/ets2panda/checker/TSAnalyzer.cpp index d3e96e821f..a08d475c11 100644 --- a/ets2panda/checker/TSAnalyzer.cpp +++ b/ets2panda/checker/TSAnalyzer.cpp @@ -665,10 +665,9 @@ checker::Type *TSAnalyzer::Check(ir::WhileStatement *st) const UNREACHABLE(); } // from ts folder -checker::Type *TSAnalyzer::Check(ir::TSAnyKeyword *node) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSAnyKeyword *node) const { - (void)node; - UNREACHABLE(); + return nullptr; } checker::Type *TSAnalyzer::Check(ir::TSArrayType *node) const @@ -689,10 +688,9 @@ checker::Type *TSAnalyzer::Check(ir::TSBigintKeyword *node) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::TSBooleanKeyword *node) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSBooleanKeyword *node) const { - (void)node; - UNREACHABLE(); + return nullptr; } checker::Type *TSAnalyzer::Check(ir::TSClassImplements *expr) const @@ -713,21 +711,346 @@ checker::Type *TSAnalyzer::Check(ir::TSConstructorType *node) const UNREACHABLE(); } +static binder::EnumMemberResult EvaluateIdentifier(checker::TSChecker *checker, binder::EnumVariable *enum_var, + const ir::Identifier *expr) +{ + if (expr->Name() == "NaN") { + return std::nan(""); + } + if (expr->Name() == "Infinity") { + return std::numeric_limits::infinity(); + } + + binder::Variable *enum_member = expr->AsIdentifier()->Variable(); + + if (enum_member == nullptr) { + checker->ThrowTypeError({"Cannot find name ", expr->AsIdentifier()->Name()}, + enum_var->Declaration()->Node()->Start()); + } + + if (enum_member->IsEnumVariable()) { + binder::EnumVariable *expr_enum_var = enum_member->AsEnumVariable(); + if (std::holds_alternative(expr_enum_var->Value())) { + checker->ThrowTypeError( + "A member initializer in a enum declaration cannot reference members declared after it, " + "including " + "members defined in other enums.", + enum_var->Declaration()->Node()->Start()); + } + + return expr_enum_var->Value(); + } + + return false; +} + +static int32_t ToInt(double num) +{ + if (num >= std::numeric_limits::min() && num <= std::numeric_limits::max()) { + return static_cast(num); + } + + // TODO(aszilagyi): Perform ECMA defined toInt conversion + + return 0; +} + +static uint32_t ToUInt(double num) +{ + if (num >= std::numeric_limits::min() && num <= std::numeric_limits::max()) { + return static_cast(num); + } + + // TODO(aszilagyi): Perform ECMA defined toInt conversion + + return 0; +} + +binder::EnumMemberResult TSAnalyzer::EvaluateBinaryExpression(checker::TSChecker *checker, + binder::EnumVariable *enum_var, + const ir::BinaryExpression *expr) const +{ + binder::EnumMemberResult left = EvaluateEnumMember(checker, enum_var, expr->AsBinaryExpression()->Left()); + binder::EnumMemberResult right = EvaluateEnumMember(checker, enum_var, expr->AsBinaryExpression()->Right()); + if (std::holds_alternative(left) && std::holds_alternative(right)) { + switch (expr->AsBinaryExpression()->OperatorType()) { + case lexer::TokenType::PUNCTUATOR_BITWISE_OR: { + return static_cast(ToUInt(std::get(left)) | ToUInt(std::get(right))); + } + case lexer::TokenType::PUNCTUATOR_BITWISE_AND: { + return static_cast(ToUInt(std::get(left)) & ToUInt(std::get(right))); + } + case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: { + return static_cast(ToUInt(std::get(left)) ^ ToUInt(std::get(right))); + } + case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: { // NOLINTNEXTLINE(hicpp-signed-bitwise) + return static_cast(ToInt(std::get(left)) << ToUInt(std::get(right))); + } + case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: { // NOLINTNEXTLINE(hicpp-signed-bitwise) + return static_cast(ToInt(std::get(left)) >> ToUInt(std::get(right))); + } + case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: { + return static_cast(ToUInt(std::get(left)) >> ToUInt(std::get(right))); + } + case lexer::TokenType::PUNCTUATOR_PLUS: { + return std::get(left) + std::get(right); + } + case lexer::TokenType::PUNCTUATOR_MINUS: { + return std::get(left) - std::get(right); + } + case lexer::TokenType::PUNCTUATOR_MULTIPLY: { + return std::get(left) * std::get(right); + } + case lexer::TokenType::PUNCTUATOR_DIVIDE: { + return std::get(left) / std::get(right); + } + case lexer::TokenType::PUNCTUATOR_MOD: { + return std::fmod(std::get(left), std::get(right)); + } + case lexer::TokenType::PUNCTUATOR_EXPONENTIATION: { + return std::pow(std::get(left), std::get(right)); + } + default: { + break; + } + } + + return false; + } + + if (std::holds_alternative(left) && std::holds_alternative(right) && + expr->AsBinaryExpression()->OperatorType() == lexer::TokenType::PUNCTUATOR_PLUS) { + std::stringstream ss; + ss << std::get(left) << std::get(right); + + util::UString res(ss.str(), checker->Allocator()); + return res.View(); + } + + return false; +} + +binder::EnumMemberResult TSAnalyzer::EvaluateUnaryExpression(checker::TSChecker *checker, + binder::EnumVariable *enum_var, + const ir::UnaryExpression *expr) const +{ + binder::EnumMemberResult value = EvaluateEnumMember(checker, enum_var, expr->Argument()); + if (!std::holds_alternative(value)) { + return false; + } + + switch (expr->OperatorType()) { + case lexer::TokenType::PUNCTUATOR_PLUS: { + return std::get(value); + } + case lexer::TokenType::PUNCTUATOR_MINUS: { + return -std::get(value); + } + case lexer::TokenType::PUNCTUATOR_TILDE: { + return static_cast(~ToInt(std::get(value))); // NOLINT(hicpp-signed-bitwise) + } + default: { + break; + } + } + + return false; +} + +binder::EnumMemberResult TSAnalyzer::EvaluateEnumMember(checker::TSChecker *checker, binder::EnumVariable *enum_var, + const ir::AstNode *expr) const +{ + switch (expr->Type()) { + case ir::AstNodeType::UNARY_EXPRESSION: { + return EvaluateUnaryExpression(checker, enum_var, expr->AsUnaryExpression()); + } + case ir::AstNodeType::BINARY_EXPRESSION: { + return EvaluateBinaryExpression(checker, enum_var, expr->AsBinaryExpression()); + } + case ir::AstNodeType::NUMBER_LITERAL: { + return expr->AsNumberLiteral()->Number().GetDouble(); + } + case ir::AstNodeType::STRING_LITERAL: { + return expr->AsStringLiteral()->Str(); + } + case ir::AstNodeType::IDENTIFIER: { + return EvaluateIdentifier(checker, enum_var, expr->AsIdentifier()); + } + case ir::AstNodeType::MEMBER_EXPRESSION: { + return EvaluateEnumMember(checker, enum_var, expr->AsMemberExpression()); + } + default: + break; + } + + return false; +} + +static bool IsComputedEnumMember(const ir::Expression *init) +{ + if (init->IsLiteral()) { + return !init->AsLiteral()->IsStringLiteral() && !init->AsLiteral()->IsNumberLiteral(); + } + + if (init->IsTemplateLiteral()) { + return !init->AsTemplateLiteral()->Quasis().empty(); + } + + return true; +} + +static void AddEnumValueDeclaration(checker::TSChecker *checker, double number, binder::EnumVariable *variable) +{ + variable->SetTsType(checker->GlobalNumberType()); + + util::StringView member_str = util::Helpers::ToStringView(checker->Allocator(), number); + + binder::LocalScope *enum_scope = checker->Scope()->AsLocalScope(); + binder::Variable *res = enum_scope->FindLocal(member_str); + binder::EnumVariable *enum_var = nullptr; + + if (res == nullptr) { + auto *decl = checker->Allocator()->New(member_str); + decl->BindNode(variable->Declaration()->Node()); + enum_scope->AddDecl(checker->Allocator(), decl, ScriptExtension::TS); + res = enum_scope->FindLocal(member_str); + ASSERT(res && res->IsEnumVariable()); + enum_var = res->AsEnumVariable(); + enum_var->AsEnumVariable()->SetBackReference(); + enum_var->SetTsType(checker->GlobalStringType()); + } else { + ASSERT(res->IsEnumVariable()); + enum_var = res->AsEnumVariable(); + auto *decl = checker->Allocator()->New(member_str); + decl->BindNode(variable->Declaration()->Node()); + enum_var->ResetDecl(decl); + } + + enum_var->SetValue(variable->Declaration()->Name()); +} + +void TSAnalyzer::InferEnumVariableType(checker::TSChecker *checker, binder::EnumVariable *variable, double *value, + bool *init_next, bool *is_literal_enum, bool is_const_enum, + const ir::Expression *computed_expr) const +{ + const ir::Expression *init = variable->Declaration()->Node()->AsTSEnumMember()->Init(); + + if (init == nullptr && *init_next) { + checker->ThrowTypeError("Enum member must have initializer.", variable->Declaration()->Node()->Start()); + } + + if (init == nullptr && !*init_next) { + variable->SetValue(++(*value)); + AddEnumValueDeclaration(checker, *value, variable); + return; + } + + ASSERT(init); + + if (IsComputedEnumMember(init)) { + if (*is_literal_enum) { + checker->ThrowTypeError("Computed values are not permitted in an enum with string valued members.", + init->Start()); + } + + computed_expr = init; + } + + binder::EnumMemberResult res = EvaluateEnumMember(checker, variable, init); + if (std::holds_alternative(res)) { + if (computed_expr != nullptr) { + checker->ThrowTypeError("Computed values are not permitted in an enum with string valued members.", + computed_expr->Start()); + } + + *is_literal_enum = true; + variable->SetTsType(checker->GlobalStringType()); + *init_next = true; + return; + } + + if (std::holds_alternative(res)) { + if (is_const_enum) { + checker->ThrowTypeError( + "const enum member initializers can only contain literal values and other computed enum " + "values.", + init->Start()); + } + + *init_next = true; + return; + } + + ASSERT(std::holds_alternative(res)); + variable->SetValue(res); + + *value = std::get(res); + if (is_const_enum) { + if (std::isnan(*value)) { + checker->ThrowTypeError("'const' enum member initializer was evaluated to disallowed value 'NaN'.", + init->Start()); + } + + if (std::isinf(*value)) { + checker->ThrowTypeError("'const' enum member initializer was evaluated to a non-finite value.", + init->Start()); + } + } + + *init_next = false; + AddEnumValueDeclaration(checker, *value, variable); +} + +checker::Type *TSAnalyzer::InferType(checker::TSChecker *checker, bool is_const, ir::TSEnumDeclaration *st) const +{ + double value = -1.0; + + varbinder::LocalScope *enum_scope = checker->Scope()->AsLocalScope(); + + bool init_next = false; + bool is_literal_enum = false; + const ir::Expression *computed_expr = nullptr; + size_t locals_size = enum_scope->Decls().size(); + + for (size_t i = 0; i < locals_size; i++) { + const util::StringView ¤t_name = enum_scope->Decls()[i]->Name(); + varbinder::Variable *current_var = enum_scope->FindLocal(current_name, varbinder::ResolveBindingOptions::BINDINGS); + ASSERT(current_var && current_var->IsEnumVariable()); + InferEnumVariableType(checker, current_var->AsEnumVariable(), &value, &init_next, &is_literal_enum, is_const, + computed_expr); + } + + checker::Type *enum_type = checker->Allocator()->New( + st->Key()->Name(), checker->Scope(), + is_literal_enum ? checker::EnumLiteralType::EnumLiteralTypeKind::LITERAL + : checker::EnumLiteralType::EnumLiteralTypeKind::NUMERIC); + + return enum_type; +} + checker::Type *TSAnalyzer::Check(ir::TSEnumDeclaration *st) const { - (void)st; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + varbinder::Variable *enum_var = st->Key()->Variable(); + ASSERT(enum_var); + + if (enum_var->TsType() == nullptr) { + checker::ScopeContext scope_ctx(checker, st->Scope()); + checker::Type *enum_type = InferType(checker, st->IsConst(), st); + enum_type->SetVariable(enum_var); + enum_var->SetTsType(enum_type); + } + + return nullptr; } -checker::Type *TSAnalyzer::Check(ir::TSEnumMember *st) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSEnumMember *st) const { - (void)st; UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::TSExternalModuleReference *expr) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSExternalModuleReference *expr) const { - (void)expr; UNREACHABLE(); } @@ -833,15 +1156,13 @@ checker::Type *TSAnalyzer::Check(ir::TSNullKeyword *node) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::TSNumberKeyword *node) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSNumberKeyword *node) const { - (void)node; - UNREACHABLE(); + return nullptr; } -checker::Type *TSAnalyzer::Check(ir::TSObjectKeyword *node) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSObjectKeyword *node) const { - (void)node; UNREACHABLE(); } @@ -863,10 +1184,9 @@ checker::Type *TSAnalyzer::Check(ir::TSQualifiedName *expr) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::TSStringKeyword *node) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSStringKeyword *node) const { - (void)node; - UNREACHABLE(); + return nullptr; } checker::Type *TSAnalyzer::Check(ir::TSThisType *node) const @@ -941,10 +1261,9 @@ checker::Type *TSAnalyzer::Check(ir::TSTypeReference *node) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::TSUndefinedKeyword *node) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSUndefinedKeyword *node) const { - (void)node; - UNREACHABLE(); + return nullptr; } checker::Type *TSAnalyzer::Check(ir::TSUnionType *node) const @@ -953,16 +1272,14 @@ checker::Type *TSAnalyzer::Check(ir::TSUnionType *node) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::TSUnknownKeyword *node) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSUnknownKeyword *node) const { - (void)node; - UNREACHABLE(); + return nullptr; } -checker::Type *TSAnalyzer::Check(ir::TSVoidKeyword *node) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSVoidKeyword *node) const { - (void)node; - UNREACHABLE(); + return nullptr; } } // namespace panda::es2panda::checker diff --git a/ets2panda/checker/TSAnalyzer.h b/ets2panda/checker/TSAnalyzer.h index eb23fa2fc5..127c48de1b 100644 --- a/ets2panda/checker/TSAnalyzer.h +++ b/ets2panda/checker/TSAnalyzer.h @@ -36,6 +36,17 @@ public: private: TSChecker *GetTSChecker() const; + + binder::EnumMemberResult EvaluateBinaryExpression(checker::TSChecker *checker, binder::EnumVariable *enum_var, + const ir::BinaryExpression *expr) const; + binder::EnumMemberResult EvaluateEnumMember(checker::TSChecker *checker, binder::EnumVariable *enum_var, + const ir::AstNode *expr) const; + binder::EnumMemberResult EvaluateUnaryExpression(checker::TSChecker *checker, binder::EnumVariable *enum_var, + const ir::UnaryExpression *expr) const; + void InferEnumVariableType(checker::TSChecker *checker, binder::EnumVariable *variable, double *value, + bool *init_next, bool *is_literal_enum, bool is_const_enum, + const ir::Expression *computed_expr) const; + checker::Type *InferType(checker::TSChecker *checker, bool is_const, ir::TSEnumDeclaration *st) const; }; } // namespace panda::es2panda::checker diff --git a/ets2panda/compiler/core/ETSCompiler.cpp b/ets2panda/compiler/core/ETSCompiler.cpp index 46dd096ae8..e4d0feed2e 100644 --- a/ets2panda/compiler/core/ETSCompiler.cpp +++ b/ets2panda/compiler/core/ETSCompiler.cpp @@ -678,9 +678,8 @@ void ETSCompiler::Compile(const ir::WhileStatement *st) const UNREACHABLE(); } // from ts folder -void ETSCompiler::Compile(const ir::TSAnyKeyword *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSAnyKeyword *node) const { - (void)node; UNREACHABLE(); } @@ -702,9 +701,8 @@ void ETSCompiler::Compile(const ir::TSBigintKeyword *node) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSBooleanKeyword *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSBooleanKeyword *node) const { - (void)node; UNREACHABLE(); } @@ -726,21 +724,18 @@ void ETSCompiler::Compile(const ir::TSConstructorType *node) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSEnumDeclaration *st) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSEnumDeclaration *st) const { - (void)st; UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSEnumMember *st) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSEnumMember *st) const { - (void)st; UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSExternalModuleReference *expr) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSExternalModuleReference *expr) const { - (void)expr; UNREACHABLE(); } @@ -846,15 +841,13 @@ void ETSCompiler::Compile(const ir::TSNullKeyword *node) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSNumberKeyword *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSNumberKeyword *node) const { - (void)node; UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSObjectKeyword *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSObjectKeyword *node) const { - (void)node; UNREACHABLE(); } @@ -876,9 +869,8 @@ void ETSCompiler::Compile(const ir::TSQualifiedName *expr) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSStringKeyword *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSStringKeyword *node) const { - (void)node; UNREACHABLE(); } @@ -954,9 +946,8 @@ void ETSCompiler::Compile(const ir::TSTypeReference *node) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSUndefinedKeyword *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSUndefinedKeyword *node) const { - (void)node; UNREACHABLE(); } @@ -966,16 +957,14 @@ void ETSCompiler::Compile(const ir::TSUnionType *node) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSUnknownKeyword *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSUnknownKeyword *node) const { - (void)node; UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSVoidKeyword *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSVoidKeyword *node) const { - (void)node; UNREACHABLE(); } -} // namespace panda::es2panda::compiler \ No newline at end of file +} // namespace panda::es2panda::compiler diff --git a/ets2panda/compiler/core/JSCompiler.cpp b/ets2panda/compiler/core/JSCompiler.cpp index 10a894d364..0dc612a2bc 100644 --- a/ets2panda/compiler/core/JSCompiler.cpp +++ b/ets2panda/compiler/core/JSCompiler.cpp @@ -963,9 +963,8 @@ void JSCompiler::Compile(const ir::WhileStatement *st) const UNREACHABLE(); } // from ts folder -void JSCompiler::Compile(const ir::TSAnyKeyword *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSAnyKeyword *node) const { - (void)node; UNREACHABLE(); } @@ -987,9 +986,8 @@ void JSCompiler::Compile(const ir::TSBigintKeyword *node) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSBooleanKeyword *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSBooleanKeyword *node) const { - (void)node; UNREACHABLE(); } @@ -1011,21 +1009,18 @@ void JSCompiler::Compile(const ir::TSConstructorType *node) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSEnumDeclaration *st) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSEnumDeclaration *st) const { - (void)st; UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSEnumMember *st) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSEnumMember *st) const { - (void)st; UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSExternalModuleReference *expr) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSExternalModuleReference *expr) const { - (void)expr; UNREACHABLE(); } @@ -1131,15 +1126,13 @@ void JSCompiler::Compile(const ir::TSNullKeyword *node) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSNumberKeyword *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSNumberKeyword *node) const { - (void)node; UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSObjectKeyword *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSObjectKeyword *node) const { - (void)node; UNREACHABLE(); } @@ -1161,9 +1154,8 @@ void JSCompiler::Compile(const ir::TSQualifiedName *expr) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSStringKeyword *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSStringKeyword *node) const { - (void)node; UNREACHABLE(); } @@ -1239,9 +1231,8 @@ void JSCompiler::Compile(const ir::TSTypeReference *node) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSUndefinedKeyword *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSUndefinedKeyword *node) const { - (void)node; UNREACHABLE(); } @@ -1251,16 +1242,13 @@ void JSCompiler::Compile(const ir::TSUnionType *node) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSUnknownKeyword *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSUnknownKeyword *node) const { - (void)node; UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSVoidKeyword *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSVoidKeyword *node) const { - (void)node; UNREACHABLE(); } - -} // namespace panda::es2panda::compiler \ No newline at end of file +} // namespace panda::es2panda::compiler diff --git a/ets2panda/ir/statements/returnStatement.h b/ets2panda/ir/statements/returnStatement.h index cacaf713a7..2e2efaf8da 100644 --- a/ets2panda/ir/statements/returnStatement.h +++ b/ets2panda/ir/statements/returnStatement.h @@ -61,10 +61,10 @@ 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 Compile([[maybe_unused]] compiler::ETSGen *etsg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: Expression *argument_ {}; diff --git a/ets2panda/ir/ts/tsAnyKeyword.cpp b/ets2panda/ir/ts/tsAnyKeyword.cpp index 170d086c83..c82f027415 100644 --- a/ets2panda/ir/ts/tsAnyKeyword.cpp +++ b/ets2panda/ir/ts/tsAnyKeyword.cpp @@ -15,8 +15,9 @@ #include "tsAnyKeyword.h" -#include "ir/astDump.h" #include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void TSAnyKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb) {} @@ -27,11 +28,19 @@ void TSAnyKeyword::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "TSAnyKeyword"}}); } -void TSAnyKeyword::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSAnyKeyword::Compile(compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} + +void TSAnyKeyword::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} -checker::Type *TSAnyKeyword::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *TSAnyKeyword::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSAnyKeyword::GetType([[maybe_unused]] checker::TSChecker *checker) @@ -39,8 +48,8 @@ checker::Type *TSAnyKeyword::GetType([[maybe_unused]] checker::TSChecker *checke return checker->GlobalAnyType(); } -checker::Type *TSAnyKeyword::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *TSAnyKeyword::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsAnyKeyword.h b/ets2panda/ir/ts/tsAnyKeyword.h index 5719a54c0a..e6f2d21e62 100644 --- a/ets2panda/ir/ts/tsAnyKeyword.h +++ b/ets2panda/ir/ts/tsAnyKeyword.h @@ -26,10 +26,11 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; checker::Type *GetType([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; }; } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsBooleanKeyword.cpp b/ets2panda/ir/ts/tsBooleanKeyword.cpp index f5759ccf7f..7cc031e8a9 100644 --- a/ets2panda/ir/ts/tsBooleanKeyword.cpp +++ b/ets2panda/ir/ts/tsBooleanKeyword.cpp @@ -15,8 +15,9 @@ #include "tsBooleanKeyword.h" -#include "ir/astDump.h" #include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void TSBooleanKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb) {} @@ -27,11 +28,19 @@ void TSBooleanKeyword::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "TSBooleanKeyword"}}); } -void TSBooleanKeyword::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSBooleanKeyword::Compile(compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} + +void TSBooleanKeyword::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} -checker::Type *TSBooleanKeyword::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *TSBooleanKeyword::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSBooleanKeyword::GetType([[maybe_unused]] checker::TSChecker *checker) @@ -39,8 +48,8 @@ checker::Type *TSBooleanKeyword::GetType([[maybe_unused]] checker::TSChecker *ch return checker->GlobalBooleanType(); } -checker::Type *TSBooleanKeyword::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *TSBooleanKeyword::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsBooleanKeyword.h b/ets2panda/ir/ts/tsBooleanKeyword.h index a4936f1cec..c796b0e41c 100644 --- a/ets2panda/ir/ts/tsBooleanKeyword.h +++ b/ets2panda/ir/ts/tsBooleanKeyword.h @@ -26,10 +26,11 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; checker::Type *GetType([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; }; } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsEnumDeclaration.cpp b/ets2panda/ir/ts/tsEnumDeclaration.cpp index c1bb84f23b..be7bca44b3 100644 --- a/ets2panda/ir/ts/tsEnumDeclaration.cpp +++ b/ets2panda/ir/ts/tsEnumDeclaration.cpp @@ -15,22 +15,11 @@ #include "tsEnumDeclaration.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "varbinder/scope.h" #include "util/helpers.h" -#include "ir/astDump.h" -#include "ir/base/decorator.h" -#include "ir/base/scriptFunction.h" -#include "ir/expressions/identifier.h" -#include "ir/base/methodDefinition.h" -#include "ir/expressions/memberExpression.h" -#include "ir/expressions/unaryExpression.h" -#include "ir/expressions/binaryExpression.h" -#include "ir/expressions/templateLiteral.h" -#include "ir/expressions/literals/stringLiteral.h" -#include "ir/expressions/literals/numberLiteral.h" -#include "ir/ts/tsEnumMember.h" -#include "checker/TSchecker.h" -#include "checker/ETSchecker.h" namespace panda::es2panda::ir { void TSEnumDeclaration::TransformChildren(const NodeTransformer &cb) @@ -68,8 +57,6 @@ void TSEnumDeclaration::Dump(ir::AstDumper *dumper) const {"const", is_const_}}); } -void TSEnumDeclaration::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} - int32_t ToInt(double num) { if (num >= std::numeric_limits::min() && num <= std::numeric_limits::max()) { @@ -382,70 +369,22 @@ void InferEnumVariableType(checker::TSChecker *checker, varbinder::EnumVariable AddEnumValueDeclaration(checker, *value, variable); } -checker::Type *TSEnumDeclaration::InferType(checker::TSChecker *checker, bool is_const) const -{ - double value = -1.0; - - varbinder::LocalScope *enum_scope = checker->Scope()->AsLocalScope(); - - bool init_next = false; - bool is_literal_enum = false; - const ir::Expression *computed_expr = nullptr; - size_t locals_size = enum_scope->Decls().size(); - - for (size_t i = 0; i < locals_size; i++) { - const util::StringView ¤t_name = enum_scope->Decls()[i]->Name(); - varbinder::Variable *current_var = - enum_scope->FindLocal(current_name, varbinder::ResolveBindingOptions::BINDINGS); - ASSERT(current_var && current_var->IsEnumVariable()); - InferEnumVariableType(checker, current_var->AsEnumVariable(), &value, &init_next, &is_literal_enum, is_const, - computed_expr); - } - - checker::Type *enum_type = checker->Allocator()->New( - key_->Name(), checker->Scope(), - is_literal_enum ? checker::EnumLiteralType::EnumLiteralTypeKind::LITERAL - : checker::EnumLiteralType::EnumLiteralTypeKind::NUMERIC); - - return enum_type; +void TSEnumDeclaration::Compile(compiler::PandaGen *pg) const { + pg->GetAstCompiler()->Compile(this); } -checker::Type *TSEnumDeclaration::Check([[maybe_unused]] checker::TSChecker *checker) +void TSEnumDeclaration::Compile(compiler::ETSGen *etsg) const { - varbinder::Variable *enum_var = key_->Variable(); - ASSERT(enum_var); - - if (enum_var->TsType() == nullptr) { - checker::ScopeContext scope_ctx(checker, scope_); - checker::Type *enum_type = InferType(checker, is_const_); - enum_type->SetVariable(enum_var); - enum_var->SetTsType(enum_type); - } + etsg->GetAstCompiler()->Compile(this); +} - return nullptr; +checker::Type *TSEnumDeclaration::Check(checker::TSChecker *checker) +{ + return checker->GetAnalyzer()->Check(this); } checker::Type *TSEnumDeclaration::Check(checker::ETSChecker *const checker) { - varbinder::Variable *enum_var = key_->Variable(); - ASSERT(enum_var != nullptr); - - if (enum_var->TsType() == nullptr) { - checker::Type *ets_enum_type; - if (auto *const item_init = members_.front()->AsTSEnumMember()->Init(); item_init->IsNumberLiteral()) { - ets_enum_type = checker->CreateETSEnumType(this); - } else if (item_init->IsStringLiteral()) { - ets_enum_type = checker->CreateETSStringEnumType(this); - } else { - checker->ThrowTypeError("Invalid enumeration value type.", Start()); - } - SetTsType(ets_enum_type); - ets_enum_type->SetVariable(enum_var); - enum_var->SetTsType(ets_enum_type); - } else if (TsType() == nullptr) { - SetTsType(enum_var->TsType()); - } - - return TsType(); + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsEnumDeclaration.h b/ets2panda/ir/ts/tsEnumDeclaration.h index 72a6d0870e..d6d318a62b 100644 --- a/ets2panda/ir/ts/tsEnumDeclaration.h +++ b/ets2panda/ir/ts/tsEnumDeclaration.h @@ -101,14 +101,13 @@ public: static varbinder::EnumMemberResult EvaluateEnumMember(checker::TSChecker *checker, varbinder::EnumVariable *enum_var, const ir::AstNode *expr); - checker::Type *InferType(checker::TSChecker *checker, bool is_const) const; - void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: varbinder::LocalScope *scope_; diff --git a/ets2panda/ir/ts/tsEnumMember.cpp b/ets2panda/ir/ts/tsEnumMember.cpp index d0cb459a00..adb6873dd8 100644 --- a/ets2panda/ir/ts/tsEnumMember.cpp +++ b/ets2panda/ir/ts/tsEnumMember.cpp @@ -15,9 +15,9 @@ #include "tsEnumMember.h" -#include "ir/astDump.h" -#include "ir/expression.h" -#include "ir/expressions/identifier.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void TSEnumMember::TransformChildren(const NodeTransformer &cb) @@ -49,15 +49,23 @@ util::StringView TSEnumMember::Name() const return key_->AsIdentifier()->Name(); } -void TSEnumMember::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSEnumMember::Compile(compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} + +void TSEnumMember::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} -checker::Type *TSEnumMember::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *TSEnumMember::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } -checker::Type *TSEnumMember::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *TSEnumMember::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsEnumMember.h b/ets2panda/ir/ts/tsEnumMember.h index 52918aee60..c169a782db 100644 --- a/ets2panda/ir/ts/tsEnumMember.h +++ b/ets2panda/ir/ts/tsEnumMember.h @@ -43,9 +43,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: Expression *key_; diff --git a/ets2panda/ir/ts/tsExternalModuleReference.cpp b/ets2panda/ir/ts/tsExternalModuleReference.cpp index 5e9aa155d8..601c235a02 100644 --- a/ets2panda/ir/ts/tsExternalModuleReference.cpp +++ b/ets2panda/ir/ts/tsExternalModuleReference.cpp @@ -15,7 +15,9 @@ #include "tsExternalModuleReference.h" -#include "ir/astDump.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void TSExternalModuleReference::TransformChildren(const NodeTransformer &cb) @@ -33,15 +35,23 @@ void TSExternalModuleReference::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "TSExternalModuleReference"}, {"expression", expr_}}); } -void TSExternalModuleReference::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSExternalModuleReference::Compile(compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} + +void TSExternalModuleReference::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} -checker::Type *TSExternalModuleReference::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *TSExternalModuleReference::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } -checker::Type *TSExternalModuleReference::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *TSExternalModuleReference::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsExternalModuleReference.h b/ets2panda/ir/ts/tsExternalModuleReference.h index 2ab4685a25..00ec35da54 100644 --- a/ets2panda/ir/ts/tsExternalModuleReference.h +++ b/ets2panda/ir/ts/tsExternalModuleReference.h @@ -34,9 +34,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: Expression *expr_; diff --git a/ets2panda/ir/ts/tsNumberKeyword.cpp b/ets2panda/ir/ts/tsNumberKeyword.cpp index 294e15b549..13aca3172f 100644 --- a/ets2panda/ir/ts/tsNumberKeyword.cpp +++ b/ets2panda/ir/ts/tsNumberKeyword.cpp @@ -15,8 +15,9 @@ #include "tsNumberKeyword.h" -#include "ir/astDump.h" #include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void TSNumberKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb) {} @@ -27,11 +28,19 @@ void TSNumberKeyword::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "TSNumberKeyword"}}); } -void TSNumberKeyword::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSNumberKeyword::Compile(compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} + +void TSNumberKeyword::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} -checker::Type *TSNumberKeyword::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *TSNumberKeyword::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSNumberKeyword::GetType([[maybe_unused]] checker::TSChecker *checker) @@ -39,8 +48,8 @@ checker::Type *TSNumberKeyword::GetType([[maybe_unused]] checker::TSChecker *che return checker->GlobalNumberType(); } -checker::Type *TSNumberKeyword::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *TSNumberKeyword::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsNumberKeyword.h b/ets2panda/ir/ts/tsNumberKeyword.h index f901274168..5debdb8a4a 100644 --- a/ets2panda/ir/ts/tsNumberKeyword.h +++ b/ets2panda/ir/ts/tsNumberKeyword.h @@ -26,10 +26,11 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; checker::Type *GetType([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; }; } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsObjectKeyword.cpp b/ets2panda/ir/ts/tsObjectKeyword.cpp index eb471e9d7b..da0fea0061 100644 --- a/ets2panda/ir/ts/tsObjectKeyword.cpp +++ b/ets2panda/ir/ts/tsObjectKeyword.cpp @@ -15,8 +15,9 @@ #include "tsObjectKeyword.h" -#include "ir/astDump.h" #include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void TSObjectKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb) {} @@ -27,11 +28,19 @@ void TSObjectKeyword::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "TSObjectKeyword"}}); } -void TSObjectKeyword::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSObjectKeyword::Compile([[maybe_unused]] compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} + +void TSObjectKeyword::Compile([[maybe_unused]] compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} checker::Type *TSObjectKeyword::Check([[maybe_unused]] checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSObjectKeyword::GetType([[maybe_unused]] checker::TSChecker *checker) @@ -41,6 +50,6 @@ checker::Type *TSObjectKeyword::GetType([[maybe_unused]] checker::TSChecker *che checker::Type *TSObjectKeyword::Check([[maybe_unused]] checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsObjectKeyword.h b/ets2panda/ir/ts/tsObjectKeyword.h index d06a36dde2..ecbb83c451 100644 --- a/ets2panda/ir/ts/tsObjectKeyword.h +++ b/ets2panda/ir/ts/tsObjectKeyword.h @@ -26,10 +26,11 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; checker::Type *GetType([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; }; } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsStringKeyword.cpp b/ets2panda/ir/ts/tsStringKeyword.cpp index 3374b8bb51..11caf9ca5a 100644 --- a/ets2panda/ir/ts/tsStringKeyword.cpp +++ b/ets2panda/ir/ts/tsStringKeyword.cpp @@ -15,8 +15,9 @@ #include "tsStringKeyword.h" -#include "ir/astDump.h" #include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void TSStringKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb) {} @@ -27,11 +28,19 @@ void TSStringKeyword::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "TSStringKeyword"}}); } -void TSStringKeyword::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSStringKeyword::Compile(compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} + +void TSStringKeyword::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} -checker::Type *TSStringKeyword::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *TSStringKeyword::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSStringKeyword::GetType([[maybe_unused]] checker::TSChecker *checker) @@ -39,8 +48,8 @@ checker::Type *TSStringKeyword::GetType([[maybe_unused]] checker::TSChecker *che return checker->GlobalStringType(); } -checker::Type *TSStringKeyword::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *TSStringKeyword::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsStringKeyword.h b/ets2panda/ir/ts/tsStringKeyword.h index 14b8cf390d..611c2a70f9 100644 --- a/ets2panda/ir/ts/tsStringKeyword.h +++ b/ets2panda/ir/ts/tsStringKeyword.h @@ -26,10 +26,11 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; checker::Type *GetType([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; }; } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsUndefinedKeyword.cpp b/ets2panda/ir/ts/tsUndefinedKeyword.cpp index 6d889996c8..ba59f6f222 100644 --- a/ets2panda/ir/ts/tsUndefinedKeyword.cpp +++ b/ets2panda/ir/ts/tsUndefinedKeyword.cpp @@ -15,8 +15,9 @@ #include "tsUndefinedKeyword.h" -#include "ir/astDump.h" #include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void TSUndefinedKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb) {} @@ -27,11 +28,19 @@ void TSUndefinedKeyword::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "TSUndefinedKeyword"}}); } -void TSUndefinedKeyword::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSUndefinedKeyword::Compile(compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} + +void TSUndefinedKeyword::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} -checker::Type *TSUndefinedKeyword::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *TSUndefinedKeyword::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSUndefinedKeyword::GetType([[maybe_unused]] checker::TSChecker *checker) @@ -39,8 +48,8 @@ checker::Type *TSUndefinedKeyword::GetType([[maybe_unused]] checker::TSChecker * return checker->GlobalUndefinedType(); } -checker::Type *TSUndefinedKeyword::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *TSUndefinedKeyword::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsUndefinedKeyword.h b/ets2panda/ir/ts/tsUndefinedKeyword.h index 1dcc42d743..1bbf96fcfd 100644 --- a/ets2panda/ir/ts/tsUndefinedKeyword.h +++ b/ets2panda/ir/ts/tsUndefinedKeyword.h @@ -26,10 +26,11 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; checker::Type *GetType([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; }; } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsUnknownKeyword.cpp b/ets2panda/ir/ts/tsUnknownKeyword.cpp index 3799e4b62b..d8e35bf46a 100644 --- a/ets2panda/ir/ts/tsUnknownKeyword.cpp +++ b/ets2panda/ir/ts/tsUnknownKeyword.cpp @@ -15,8 +15,9 @@ #include "tsUnknownKeyword.h" -#include "ir/astDump.h" #include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void TSUnknownKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb) {} @@ -27,11 +28,19 @@ void TSUnknownKeyword::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "TSUnknownKeyword"}}); } -void TSUnknownKeyword::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSUnknownKeyword::Compile(compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} + +void TSUnknownKeyword::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} -checker::Type *TSUnknownKeyword::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *TSUnknownKeyword::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSUnknownKeyword::GetType([[maybe_unused]] checker::TSChecker *checker) @@ -39,8 +48,8 @@ checker::Type *TSUnknownKeyword::GetType([[maybe_unused]] checker::TSChecker *ch return checker->GlobalUnknownType(); } -checker::Type *TSUnknownKeyword::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *TSUnknownKeyword::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsUnknownKeyword.h b/ets2panda/ir/ts/tsUnknownKeyword.h index 0e912ca124..642f239a53 100644 --- a/ets2panda/ir/ts/tsUnknownKeyword.h +++ b/ets2panda/ir/ts/tsUnknownKeyword.h @@ -26,10 +26,11 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; checker::Type *GetType([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; }; } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsVoidKeyword.cpp b/ets2panda/ir/ts/tsVoidKeyword.cpp index 43417ff96a..47502deb37 100644 --- a/ets2panda/ir/ts/tsVoidKeyword.cpp +++ b/ets2panda/ir/ts/tsVoidKeyword.cpp @@ -15,8 +15,9 @@ #include "tsVoidKeyword.h" -#include "ir/astDump.h" #include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void TSVoidKeyword::TransformChildren([[maybe_unused]] const NodeTransformer &cb) {} @@ -27,11 +28,19 @@ void TSVoidKeyword::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "TSVoidKeyword"}}); } -void TSVoidKeyword::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSVoidKeyword::Compile(compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} + +void TSVoidKeyword::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} -checker::Type *TSVoidKeyword::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *TSVoidKeyword::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSVoidKeyword::GetType([[maybe_unused]] checker::TSChecker *checker) @@ -39,8 +48,8 @@ checker::Type *TSVoidKeyword::GetType([[maybe_unused]] checker::TSChecker *check return checker->GlobalVoidType(); } -checker::Type *TSVoidKeyword::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *TSVoidKeyword::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsVoidKeyword.h b/ets2panda/ir/ts/tsVoidKeyword.h index 6a1d20d35d..d1869ab617 100644 --- a/ets2panda/ir/ts/tsVoidKeyword.h +++ b/ets2panda/ir/ts/tsVoidKeyword.h @@ -26,10 +26,11 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; checker::Type *GetType([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; }; } // namespace panda::es2panda::ir -- Gitee From cb23c1b28c97dc1f57bff7a0579aad2c9af41909 Mon Sep 17 00:00:00 2001 From: Csaba Hurton Date: Fri, 27 Oct 2023 09:44:39 +0200 Subject: [PATCH 2/6] (9) Move Compile and Check Logic from ASTNode classes Compile logic is moved to JSCompiler and ETSCompiler classes. Check logic with their helper functions is moved to TSAnalyzer and ETSAnalyzer classes. AstNodes that are being moved: - nodes inside ir/statements: - EmptyStatement - ExpressionStatement - ForInStatement - ForOfStatement - ForUpdateStatement - FunctionDeclaration - IfStatement - LabelledStatement - SwitchCaseStatement - SwitchStatement Linked Internal Issue 13840 Change-Id: I90b588b90a01751f3c72860482edc021f4f4f218 Signed-off-by: Csaba Hurton --- ets2panda/checker/ETSAnalyzer.cpp | 188 +++++++++-- ets2panda/checker/TSAnalyzer.cpp | 148 ++++++--- ets2panda/checker/TSAnalyzer.h | 8 +- ets2panda/compiler/core/ETSCompiler.cpp | 182 +++++++++-- ets2panda/compiler/core/JSCompiler.cpp | 186 +++++++++-- ets2panda/ir/statements/emptyStatement.cpp | 22 +- ets2panda/ir/statements/emptyStatement.h | 7 +- .../ir/statements/expressionStatement.cpp | 21 +- ets2panda/ir/statements/expressionStatement.h | 8 +- ets2panda/ir/statements/forInStatement.cpp | 50 +-- ets2panda/ir/statements/forInStatement.h | 7 +- ets2panda/ir/statements/forOfStatement.cpp | 172 +--------- ets2panda/ir/statements/forOfStatement.h | 8 +- .../ir/statements/forUpdateStatement.cpp | 110 +------ ets2panda/ir/statements/forUpdateStatement.h | 8 +- .../ir/statements/functionDeclaration.cpp | 43 +-- ets2panda/ir/statements/functionDeclaration.h | 8 +- ets2panda/ir/statements/ifStatement.cpp | 80 +---- ets2panda/ir/statements/ifStatement.h | 17 +- ets2panda/ir/statements/labelledStatement.cpp | 30 +- ets2panda/ir/statements/labelledStatement.h | 15 +- .../ir/statements/switchCaseStatement.cpp | 23 +- ets2panda/ir/statements/switchCaseStatement.h | 7 +- ets2panda/ir/statements/switchStatement.cpp | 128 +------- ets2panda/ir/statements/switchStatement.h | 17 +- ets2panda/ir/ts/tsEnumDeclaration.cpp | 293 +----------------- 26 files changed, 770 insertions(+), 1016 deletions(-) diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 38bc58d0bd..ef4fd5a722 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -639,52 +639,150 @@ checker::Type *ETSAnalyzer::Check(ir::DoWhileStatement *st) const UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::EmptyStatement *st) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::EmptyStatement *st) const { - (void)st; - UNREACHABLE(); + return nullptr; } checker::Type *ETSAnalyzer::Check(ir::ExpressionStatement *st) const { - (void)st; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + return st->GetExpression()->Check(checker); } -checker::Type *ETSAnalyzer::Check(ir::ForInStatement *st) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ForInStatement *st) const { - (void)st; UNREACHABLE(); } +// NOLINTBEGIN(modernize-avoid-c-arrays) +static constexpr char const INVALID_SOURCE_EXPR_TYPE[] = + "'For-of' statement source expression should be either a string or an array."; +static constexpr char const INVALID_CONST_ASSIGNMENT[] = "Cannot assign a value to a constant variable "; +static constexpr char const ITERATOR_TYPE_ABSENT[] = "Cannot obtain iterator type in 'for-of' statement."; +// NOLINTEND(modernize-avoid-c-arrays) + checker::Type *ETSAnalyzer::Check(ir::ForOfStatement *st) const { - (void)st; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + checker::ScopeContext scope_ctx(checker, st->Scope()); + + checker::Type *const expr_type = st->Right()->Check(checker); + checker::Type *elem_type; + + if (expr_type == nullptr || (!expr_type->IsETSArrayType() && !expr_type->IsETSStringType())) { + checker->ThrowTypeError(INVALID_SOURCE_EXPR_TYPE, st->Right()->Start()); + } else if (expr_type->IsETSStringType()) { + elem_type = checker->GetGlobalTypesHolder()->GlobalCharType(); + } else { + elem_type = expr_type->AsETSArrayType()->ElementType()->Instantiate(checker->Allocator(), checker->Relation(), + checker->GetGlobalTypesHolder()); + elem_type->RemoveTypeFlag(checker::TypeFlag::CONSTANT); + } + + st->Left()->Check(checker); + checker::Type *iter_type = nullptr; + + // Just to avoid extra nested level(s) + auto const get_iter_type = [checker, elem_type](ir::VariableDeclarator *const declarator) -> checker::Type * { + if (declarator->TsType() == nullptr) { + if (auto *resolved = checker->FindVariableInFunctionScope(declarator->Id()->AsIdentifier()->Name()); + resolved != nullptr) { + resolved->SetTsType(elem_type); + return elem_type; + } + } else { + return declarator->TsType(); + } + return nullptr; + }; + + if (st->Left()->IsIdentifier()) { + if (auto *const variable = st->Left()->AsIdentifier()->Variable(); variable != nullptr) { + if (variable->Declaration()->IsConstDecl()) { + checker->ThrowTypeError({INVALID_CONST_ASSIGNMENT, variable->Name()}, + variable->Declaration()->Node()->Start()); + } + } + iter_type = st->Left()->AsIdentifier()->TsType(); + } else if (st->Left()->IsVariableDeclaration()) { + if (auto const &declarators = st->Left()->AsVariableDeclaration()->Declarators(); !declarators.empty()) { + iter_type = get_iter_type(declarators.front()); + } + } + + if (iter_type == nullptr) { + checker->ThrowTypeError(ITERATOR_TYPE_ABSENT, st->Left()->Start()); + } + + auto *const relation = checker->Relation(); + relation->SetFlags(checker::TypeRelationFlag::ASSIGNMENT_CONTEXT); + relation->SetNode(checker->AllocNode()); // Dummy node to avoid assertion! + + if (!relation->IsAssignableTo(elem_type, iter_type)) { + std::stringstream ss {}; + ss << "Source element type '"; + elem_type->ToString(ss); + ss << "' is not assignable to the loop iterator type '"; + iter_type->ToString(ss); + ss << "'."; + checker->ThrowTypeError(ss.str(), st->Start()); + } + + relation->SetNode(nullptr); + relation->SetFlags(checker::TypeRelationFlag::NONE); + + st->Body()->Check(checker); + + return nullptr; } checker::Type *ETSAnalyzer::Check(ir::ForUpdateStatement *st) const { - (void)st; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + checker::ScopeContext scope_ctx(checker, st->Scope()); + + if (st->Init() != nullptr) { + st->Init()->Check(checker); + } + + if (st->Test() != nullptr) { + checker->CheckTruthinessOfType(st->Test()); + } + + if (st->Update() != nullptr) { + st->Update()->Check(checker); + } + + st->Body()->Check(checker); + + return nullptr; } -checker::Type *ETSAnalyzer::Check(ir::FunctionDeclaration *st) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::FunctionDeclaration *st) const { - (void)st; UNREACHABLE(); } checker::Type *ETSAnalyzer::Check(ir::IfStatement *st) const { - (void)st; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + checker->CheckTruthinessOfType(st->test_); + + st->consequent_->Check(checker); + + if (st->Alternate() != nullptr) { + st->alternate_->Check(checker); + } + + return nullptr; } checker::Type *ETSAnalyzer::Check(ir::LabelledStatement *st) const { - (void)st; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + st->body_->Check(checker); + return nullptr; } void CheckArgumentVoidType(checker::Type *&func_return_type, ETSChecker *checker, const std::string &name, @@ -899,16 +997,64 @@ checker::Type *ETSAnalyzer::Check(ir::ReturnStatement *st) const return nullptr; } -checker::Type *ETSAnalyzer::Check(ir::SwitchCaseStatement *st) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::SwitchCaseStatement *st) const { - (void)st; UNREACHABLE(); } checker::Type *ETSAnalyzer::Check(ir::SwitchStatement *st) const { - (void)st; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + checker::ScopeContext scope_ctx(checker, st->scope_); + st->discriminant_->Check(checker); + checker::SavedTypeRelationFlagsContext saved_type_relation_flag_ctx(checker->Relation(), + checker::TypeRelationFlag::NONE); + // TODO(user): check exhaustive Switch + checker->CheckSwitchDiscriminant(st->discriminant_); + auto *compared_expr_type = st->discriminant_->TsType(); + auto unboxed_disc_type = + (st->Discriminant()->GetBoxingUnboxingFlags() & ir::BoxingUnboxingFlags::UNBOXING_FLAG) != 0U + ? checker->ETSBuiltinTypeAsPrimitiveType(compared_expr_type) + : compared_expr_type; + + bool valid_case_type; + + for (auto *it : st->Cases()) { + if (it->Test() != nullptr) { + auto *case_type = it->Test()->Check(checker); + valid_case_type = true; + if (case_type->HasTypeFlag(checker::TypeFlag::CHAR)) { + valid_case_type = compared_expr_type->HasTypeFlag(checker::TypeFlag::ETS_INTEGRAL); + } else if (case_type->IsETSEnumType() && st->Discriminant()->TsType()->IsETSEnumType()) { + valid_case_type = + st->Discriminant()->TsType()->AsETSEnumType()->IsSameEnumType(case_type->AsETSEnumType()); + } else if (case_type->IsETSStringEnumType() && st->Discriminant()->TsType()->IsETSStringEnumType()) { + valid_case_type = st->Discriminant()->TsType()->AsETSStringEnumType()->IsSameEnumType( + case_type->AsETSStringEnumType()); + } else { + checker::AssignmentContext( + checker->Relation(), st->discriminant_, case_type, unboxed_disc_type, it->Test()->Start(), + {"Switch case type ", case_type, " is not comparable to discriminant type ", compared_expr_type}, + (compared_expr_type->IsETSObjectType() ? checker::TypeRelationFlag::NO_WIDENING + : checker::TypeRelationFlag::NO_UNBOXING) | + checker::TypeRelationFlag::NO_BOXING); + } + + if (!valid_case_type) { + checker->ThrowTypeError( + {"Switch case type ", case_type, " is not comparable to discriminant type ", compared_expr_type}, + it->Test()->Start()); + } + } + + for (auto *case_stmt : it->Consequent()) { + case_stmt->Check(checker); + } + } + + checker->CheckForSameSwitchCases(&st->cases_); + + return nullptr; } checker::Type *ETSAnalyzer::Check(ir::ThrowStatement *st) const diff --git a/ets2panda/checker/TSAnalyzer.cpp b/ets2panda/checker/TSAnalyzer.cpp index a08d475c11..0662819e40 100644 --- a/ets2panda/checker/TSAnalyzer.cpp +++ b/ets2panda/checker/TSAnalyzer.cpp @@ -544,51 +544,90 @@ checker::Type *TSAnalyzer::Check(ir::DoWhileStatement *st) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::EmptyStatement *st) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::EmptyStatement *st) const { - (void)st; - UNREACHABLE(); + return nullptr; } checker::Type *TSAnalyzer::Check(ir::ExpressionStatement *st) const { - (void)st; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + return st->GetExpression()->Check(checker); } -checker::Type *TSAnalyzer::Check(ir::ForInStatement *st) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ForInStatement *st) const { - (void)st; UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::ForOfStatement *st) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ForOfStatement *st) const { - (void)st; UNREACHABLE(); } checker::Type *TSAnalyzer::Check(ir::ForUpdateStatement *st) const { - (void)st; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + checker::ScopeContext scope_ctx(checker, st->Scope()); + + if (st->Init() != nullptr) { + st->Init()->Check(checker); + } + + if (st->Test() != nullptr) { + checker::Type *test_type = st->Test()->Check(checker); + checker->CheckTruthinessOfType(test_type, st->Start()); + } + + if (st->Update() != nullptr) { + st->Update()->Check(checker); + } + + st->Body()->Check(checker); + + return nullptr; } checker::Type *TSAnalyzer::Check(ir::FunctionDeclaration *st) const { - (void)st; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + if (st->Function()->IsOverload()) { + return nullptr; + } + + const util::StringView &func_name = st->Function()->Id()->Name(); + auto result = checker->Scope()->Find(func_name); + ASSERT(result.variable); + + checker::ScopeContext scope_ctx(checker, st->Function()->Scope()); + + if (result.variable->TsType() == nullptr) { + checker->InferFunctionDeclarationType(result.variable->Declaration()->AsFunctionDecl(), result.variable); + } + + st->Function()->Body()->Check(checker); + + return nullptr; } checker::Type *TSAnalyzer::Check(ir::IfStatement *st) const { - (void)st; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + checker::Type *test_type = st->test_->Check(checker); + checker->CheckTruthinessOfType(test_type, st->Start()); + checker->CheckTestingKnownTruthyCallableOrAwaitableType(st->test_, test_type, st->consequent_); + + st->consequent_->Check(checker); + + if (st->Alternate() != nullptr) { + st->alternate_->Check(checker); + } + + return nullptr; } -checker::Type *TSAnalyzer::Check(ir::LabelledStatement *st) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::LabelledStatement *st) const { - (void)st; UNREACHABLE(); } @@ -623,16 +662,43 @@ checker::Type *TSAnalyzer::Check(ir::ReturnStatement *st) const return nullptr; } -checker::Type *TSAnalyzer::Check(ir::SwitchCaseStatement *st) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::SwitchCaseStatement *st) const { - (void)st; UNREACHABLE(); } checker::Type *TSAnalyzer::Check(ir::SwitchStatement *st) const { - (void)st; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + checker::ScopeContext scope_ctx(checker, st->Scope()); + + checker::Type *expr_type = st->discriminant_->Check(checker); + bool expr_is_literal = checker::TSChecker::IsLiteralType(expr_type); + + for (auto *it : st->Cases()) { + if (it->Test() != nullptr) { + checker::Type *case_type = it->Test()->Check(checker); + bool case_is_literal = checker::TSChecker::IsLiteralType(case_type); + checker::Type *compared_expr_type = expr_type; + + if (!case_is_literal || !expr_is_literal) { + case_type = case_is_literal ? checker->GetBaseTypeOfLiteralType(case_type) : case_type; + compared_expr_type = checker->GetBaseTypeOfLiteralType(expr_type); + } + + if (!checker->IsTypeEqualityComparableTo(compared_expr_type, case_type) && + !checker->IsTypeComparableTo(case_type, compared_expr_type)) { + checker->ThrowTypeError({"Type ", case_type, " is not comparable to type ", compared_expr_type}, + it->Test()->Start()); + } + } + + for (auto *case_stmt : it->Consequent()) { + case_stmt->Check(checker); + } + } + + return nullptr; } checker::Type *TSAnalyzer::Check(ir::ThrowStatement *st) const @@ -711,7 +777,7 @@ checker::Type *TSAnalyzer::Check(ir::TSConstructorType *node) const UNREACHABLE(); } -static binder::EnumMemberResult EvaluateIdentifier(checker::TSChecker *checker, binder::EnumVariable *enum_var, +static varbinder::EnumMemberResult EvaluateIdentifier(checker::TSChecker *checker, varbinder::EnumVariable *enum_var, const ir::Identifier *expr) { if (expr->Name() == "NaN") { @@ -721,7 +787,7 @@ static binder::EnumMemberResult EvaluateIdentifier(checker::TSChecker *checker, return std::numeric_limits::infinity(); } - binder::Variable *enum_member = expr->AsIdentifier()->Variable(); + varbinder::Variable *enum_member = expr->AsIdentifier()->Variable(); if (enum_member == nullptr) { checker->ThrowTypeError({"Cannot find name ", expr->AsIdentifier()->Name()}, @@ -729,7 +795,7 @@ static binder::EnumMemberResult EvaluateIdentifier(checker::TSChecker *checker, } if (enum_member->IsEnumVariable()) { - binder::EnumVariable *expr_enum_var = enum_member->AsEnumVariable(); + varbinder::EnumVariable *expr_enum_var = enum_member->AsEnumVariable(); if (std::holds_alternative(expr_enum_var->Value())) { checker->ThrowTypeError( "A member initializer in a enum declaration cannot reference members declared after it, " @@ -766,12 +832,12 @@ static uint32_t ToUInt(double num) return 0; } -binder::EnumMemberResult TSAnalyzer::EvaluateBinaryExpression(checker::TSChecker *checker, - binder::EnumVariable *enum_var, +varbinder::EnumMemberResult TSAnalyzer::EvaluateBinaryExpression(checker::TSChecker *checker, + varbinder::EnumVariable *enum_var, const ir::BinaryExpression *expr) const { - binder::EnumMemberResult left = EvaluateEnumMember(checker, enum_var, expr->AsBinaryExpression()->Left()); - binder::EnumMemberResult right = EvaluateEnumMember(checker, enum_var, expr->AsBinaryExpression()->Right()); + varbinder::EnumMemberResult left = EvaluateEnumMember(checker, enum_var, expr->AsBinaryExpression()->Left()); + varbinder::EnumMemberResult right = EvaluateEnumMember(checker, enum_var, expr->AsBinaryExpression()->Right()); if (std::holds_alternative(left) && std::holds_alternative(right)) { switch (expr->AsBinaryExpression()->OperatorType()) { case lexer::TokenType::PUNCTUATOR_BITWISE_OR: { @@ -830,11 +896,11 @@ binder::EnumMemberResult TSAnalyzer::EvaluateBinaryExpression(checker::TSChecker return false; } -binder::EnumMemberResult TSAnalyzer::EvaluateUnaryExpression(checker::TSChecker *checker, - binder::EnumVariable *enum_var, +varbinder::EnumMemberResult TSAnalyzer::EvaluateUnaryExpression(checker::TSChecker *checker, + varbinder::EnumVariable *enum_var, const ir::UnaryExpression *expr) const { - binder::EnumMemberResult value = EvaluateEnumMember(checker, enum_var, expr->Argument()); + varbinder::EnumMemberResult value = EvaluateEnumMember(checker, enum_var, expr->Argument()); if (!std::holds_alternative(value)) { return false; } @@ -857,7 +923,7 @@ binder::EnumMemberResult TSAnalyzer::EvaluateUnaryExpression(checker::TSChecker return false; } -binder::EnumMemberResult TSAnalyzer::EvaluateEnumMember(checker::TSChecker *checker, binder::EnumVariable *enum_var, +varbinder::EnumMemberResult TSAnalyzer::EvaluateEnumMember(checker::TSChecker *checker, varbinder::EnumVariable *enum_var, const ir::AstNode *expr) const { switch (expr->Type()) { @@ -899,21 +965,21 @@ static bool IsComputedEnumMember(const ir::Expression *init) return true; } -static void AddEnumValueDeclaration(checker::TSChecker *checker, double number, binder::EnumVariable *variable) +static void AddEnumValueDeclaration(checker::TSChecker *checker, double number, varbinder::EnumVariable *variable) { variable->SetTsType(checker->GlobalNumberType()); util::StringView member_str = util::Helpers::ToStringView(checker->Allocator(), number); - binder::LocalScope *enum_scope = checker->Scope()->AsLocalScope(); - binder::Variable *res = enum_scope->FindLocal(member_str); - binder::EnumVariable *enum_var = nullptr; + varbinder::LocalScope *enum_scope = checker->Scope()->AsLocalScope(); + varbinder::Variable *res = enum_scope->FindLocal(member_str, varbinder::ResolveBindingOptions::BINDINGS); + varbinder::EnumVariable *enum_var = nullptr; if (res == nullptr) { - auto *decl = checker->Allocator()->New(member_str); + auto *decl = checker->Allocator()->New(member_str); decl->BindNode(variable->Declaration()->Node()); enum_scope->AddDecl(checker->Allocator(), decl, ScriptExtension::TS); - res = enum_scope->FindLocal(member_str); + res = enum_scope->FindLocal(member_str, varbinder::ResolveBindingOptions::BINDINGS); ASSERT(res && res->IsEnumVariable()); enum_var = res->AsEnumVariable(); enum_var->AsEnumVariable()->SetBackReference(); @@ -921,7 +987,7 @@ static void AddEnumValueDeclaration(checker::TSChecker *checker, double number, } else { ASSERT(res->IsEnumVariable()); enum_var = res->AsEnumVariable(); - auto *decl = checker->Allocator()->New(member_str); + auto *decl = checker->Allocator()->New(member_str); decl->BindNode(variable->Declaration()->Node()); enum_var->ResetDecl(decl); } @@ -929,7 +995,7 @@ static void AddEnumValueDeclaration(checker::TSChecker *checker, double number, enum_var->SetValue(variable->Declaration()->Name()); } -void TSAnalyzer::InferEnumVariableType(checker::TSChecker *checker, binder::EnumVariable *variable, double *value, +void TSAnalyzer::InferEnumVariableType(checker::TSChecker *checker, varbinder::EnumVariable *variable, double *value, bool *init_next, bool *is_literal_enum, bool is_const_enum, const ir::Expression *computed_expr) const { @@ -956,7 +1022,7 @@ void TSAnalyzer::InferEnumVariableType(checker::TSChecker *checker, binder::Enum computed_expr = init; } - binder::EnumMemberResult res = EvaluateEnumMember(checker, variable, init); + varbinder::EnumMemberResult res = EvaluateEnumMember(checker, variable, init); if (std::holds_alternative(res)) { if (computed_expr != nullptr) { checker->ThrowTypeError("Computed values are not permitted in an enum with string valued members.", diff --git a/ets2panda/checker/TSAnalyzer.h b/ets2panda/checker/TSAnalyzer.h index 127c48de1b..9696cc5156 100644 --- a/ets2panda/checker/TSAnalyzer.h +++ b/ets2panda/checker/TSAnalyzer.h @@ -37,13 +37,13 @@ public: private: TSChecker *GetTSChecker() const; - binder::EnumMemberResult EvaluateBinaryExpression(checker::TSChecker *checker, binder::EnumVariable *enum_var, + varbinder::EnumMemberResult EvaluateBinaryExpression(checker::TSChecker *checker, varbinder::EnumVariable *enum_var, const ir::BinaryExpression *expr) const; - binder::EnumMemberResult EvaluateEnumMember(checker::TSChecker *checker, binder::EnumVariable *enum_var, + varbinder::EnumMemberResult EvaluateEnumMember(checker::TSChecker *checker, varbinder::EnumVariable *enum_var, const ir::AstNode *expr) const; - binder::EnumMemberResult EvaluateUnaryExpression(checker::TSChecker *checker, binder::EnumVariable *enum_var, + varbinder::EnumMemberResult EvaluateUnaryExpression(checker::TSChecker *checker, varbinder::EnumVariable *enum_var, const ir::UnaryExpression *expr) const; - void InferEnumVariableType(checker::TSChecker *checker, binder::EnumVariable *variable, double *value, + void InferEnumVariableType(checker::TSChecker *checker, varbinder::EnumVariable *variable, double *value, bool *init_next, bool *is_literal_enum, bool is_const_enum, const ir::Expression *computed_expr) const; checker::Type *InferType(checker::TSChecker *checker, bool is_const, ir::TSEnumDeclaration *st) const; diff --git a/ets2panda/compiler/core/ETSCompiler.cpp b/ets2panda/compiler/core/ETSCompiler.cpp index e4d0feed2e..a3cb169f36 100644 --- a/ets2panda/compiler/core/ETSCompiler.cpp +++ b/ets2panda/compiler/core/ETSCompiler.cpp @@ -19,6 +19,7 @@ #include "compiler/base/condition.h" #include "compiler/base/lreference.h" #include "compiler/core/ETSGen.h" +#include "compiler/core/switchBuilder.h" #include "compiler/function/functionBuilder.h" namespace panda::es2panda::compiler { @@ -545,52 +546,156 @@ void ETSCompiler::Compile(const ir::DoWhileStatement *st) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::EmptyStatement *st) const -{ - (void)st; - UNREACHABLE(); -} +void ETSCompiler::Compile([[maybe_unused]] const ir::EmptyStatement *st) const {} void ETSCompiler::Compile(const ir::ExpressionStatement *st) const { - (void)st; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + st->GetExpression()->Compile(etsg); } -void ETSCompiler::Compile(const ir::ForInStatement *st) const +void ETSCompiler::Compile([[maybe_unused]] const ir::ForInStatement *st) const { - (void)st; UNREACHABLE(); } void ETSCompiler::Compile(const ir::ForOfStatement *st) const { - (void)st; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + compiler::LocalRegScope decl_reg_scope(etsg, st->Scope()->DeclScope()->InitScope()); + + checker::Type const *const expr_type = st->Right()->TsType(); + ASSERT(expr_type->IsETSArrayType() || expr_type->IsETSStringType()); + + st->Right()->Compile(etsg); + compiler::VReg obj_reg = etsg->AllocReg(); + etsg->StoreAccumulator(st, obj_reg); + + if (expr_type->IsETSArrayType()) { + etsg->LoadArrayLength(st, obj_reg); + } else { + etsg->LoadStringLength(st); + } + + compiler::VReg size_reg = etsg->AllocReg(); + etsg->StoreAccumulator(st, size_reg); + + compiler::LabelTarget label_target(etsg); + auto label_ctx = compiler::LabelContext(etsg, label_target); + + etsg->BranchIfFalse(st, label_target.BreakTarget()); + + compiler::VReg count_reg = etsg->AllocReg(); + etsg->MoveImmediateToRegister(st, count_reg, checker::TypeFlag::INT, static_cast(0)); + etsg->LoadAccumulatorInt(st, static_cast(0)); + + auto *const start_label = etsg->AllocLabel(); + etsg->SetLabel(st, start_label); + + auto lref = compiler::ETSLReference::Create(etsg, st->Left(), false); + + if (st->Right()->TsType()->IsETSArrayType()) { + etsg->LoadArrayElement(st, obj_reg); + } else { + etsg->LoadStringChar(st, obj_reg, count_reg); + } + + lref.SetValue(); + st->Body()->Compile(etsg); + + etsg->SetLabel(st, label_target.ContinueTarget()); + + etsg->IncrementImmediateRegister(st, count_reg, checker::TypeFlag::INT, static_cast(1)); + etsg->LoadAccumulator(st, count_reg); + + etsg->JumpCompareRegister(st, size_reg, start_label); + etsg->SetLabel(st, label_target.BreakTarget()); } void ETSCompiler::Compile(const ir::ForUpdateStatement *st) const { - (void)st; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + compiler::LocalRegScope decl_reg_scope(etsg, st->Scope()->DeclScope()->InitScope()); + + if (st->Init() != nullptr) { + ASSERT(st->Init()->IsVariableDeclaration() || st->Init()->IsExpression()); + st->Init()->Compile(etsg); + } + + auto *start_label = etsg->AllocLabel(); + compiler::LabelTarget label_target(etsg); + auto label_ctx = compiler::LabelContext(etsg, label_target); + etsg->SetLabel(st, start_label); + + { + compiler::LocalRegScope reg_scope(etsg, st->Scope()); + + if (st->Test() != nullptr) { + compiler::Condition::Compile(etsg, st->Test(), label_target.BreakTarget()); + } + + st->Body()->Compile(etsg); + etsg->SetLabel(st, label_target.ContinueTarget()); + } + + if (st->Update() != nullptr) { + st->Update()->Compile(etsg); + } + + etsg->Branch(st, start_label); + etsg->SetLabel(st, label_target.BreakTarget()); } -void ETSCompiler::Compile(const ir::FunctionDeclaration *st) const +void ETSCompiler::Compile([[maybe_unused]] const ir::FunctionDeclaration *st) const { - (void)st; UNREACHABLE(); } void ETSCompiler::Compile(const ir::IfStatement *st) const { - (void)st; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + auto res = compiler::Condition::CheckConstantExpr(etsg, st->Test()); + + if (res == compiler::Condition::Result::CONST_TRUE) { + st->Consequent()->Compile(etsg); + return; + } + + if (res == compiler::Condition::Result::CONST_FALSE) { + if (st->Alternate() != nullptr) { + st->Alternate()->Compile(etsg); + } + return; + } + + auto *consequent_end = etsg->AllocLabel(); + compiler::Label *statement_end = consequent_end; + + compiler::Condition::Compile(etsg, st->Test(), consequent_end); + + st->Consequent()->Compile(etsg); + + if (st->Alternate() != nullptr) { + statement_end = etsg->AllocLabel(); + etsg->Branch(etsg->Insns().back()->Node(), statement_end); + + etsg->SetLabel(st, consequent_end); + st->Alternate()->Compile(etsg); + } + + etsg->SetLabel(st, statement_end); +} + +void CompileImpl(const ir::LabelledStatement *self, ETSGen *cg) +{ + compiler::LabelContext label_ctx(cg, self); + self->Body()->Compile(cg); } void ETSCompiler::Compile(const ir::LabelledStatement *st) const { - (void)st; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + CompileImpl(st, etsg); } void ETSCompiler::Compile(const ir::ReturnStatement *st) const @@ -636,16 +741,47 @@ void ETSCompiler::Compile(const ir::ReturnStatement *st) const etsg->ReturnAcc(st); } -void ETSCompiler::Compile(const ir::SwitchCaseStatement *st) const +void ETSCompiler::Compile([[maybe_unused]] const ir::SwitchCaseStatement *st) const { - (void)st; UNREACHABLE(); } +static void CompileImpl(const ir::SwitchStatement *self, ETSGen *etsg) +{ + compiler::LocalRegScope lrs(etsg, self->Scope()); + compiler::SwitchBuilder builder(etsg, self); + compiler::VReg tag = etsg->AllocReg(); + + builder.CompileTagOfSwitch(tag); + uint32_t default_index = 0; + + for (size_t i = 0; i < self->Cases().size(); i++) { + const auto *clause = self->Cases()[i]; + + if (clause->Test() == nullptr) { + default_index = i; + continue; + } + + builder.JumpIfCase(tag, i); + } + + if (default_index > 0) { + builder.JumpToDefault(default_index); + } else { + builder.Break(); + } + + for (size_t i = 0; i < self->Cases().size(); i++) { + builder.SetCaseTarget(i); + builder.CompileCaseStatements(i); + } +} + void ETSCompiler::Compile(const ir::SwitchStatement *st) const { - (void)st; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + CompileImpl(st, etsg); } void ETSCompiler::Compile(const ir::ThrowStatement *st) const diff --git a/ets2panda/compiler/core/JSCompiler.cpp b/ets2panda/compiler/core/JSCompiler.cpp index 0dc612a2bc..2921b4384f 100644 --- a/ets2panda/compiler/core/JSCompiler.cpp +++ b/ets2panda/compiler/core/JSCompiler.cpp @@ -18,6 +18,7 @@ #include "compiler/base/condition.h" #include "compiler/base/lreference.h" #include "compiler/core/pandagen.h" +#include "compiler/core/switchBuilder.h" #include "compiler/function/functionBuilder.h" #include "util/helpers.h" @@ -847,52 +848,156 @@ void JSCompiler::Compile(const ir::DoWhileStatement *st) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::EmptyStatement *st) const -{ - (void)st; - UNREACHABLE(); -} +void JSCompiler::Compile([[maybe_unused]] const ir::EmptyStatement *st) const {} void JSCompiler::Compile(const ir::ExpressionStatement *st) const { - (void)st; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + st->GetExpression()->Compile(pg); } void JSCompiler::Compile(const ir::ForInStatement *st) const { - (void)st; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + compiler::LabelTarget label_target(pg); + + compiler::RegScope rs(pg); + compiler::VReg iter = pg->AllocReg(); + compiler::VReg prop_name = pg->AllocReg(); + + // create enumerator + st->Right()->Compile(pg); + pg->GetPropIterator(st); + pg->StoreAccumulator(st, iter); + + pg->SetLabel(st, label_target.ContinueTarget()); + + // get next prop of enumerator + pg->GetNextPropName(st, iter); + pg->StoreAccumulator(st, prop_name); + pg->BranchIfUndefined(st, label_target.BreakTarget()); + + compiler::LocalRegScope decl_reg_scope(pg, st->Scope()->DeclScope()->InitScope()); + auto lref = compiler::JSLReference::Create(pg, st->Left(), false); + pg->LoadAccumulator(st, prop_name); + lref.SetValue(); + + compiler::LoopEnvScope decl_env_scope(pg, st->Scope()->DeclScope()); + + { + compiler::LoopEnvScope env_scope(pg, st->Scope(), label_target); + st->Body()->Compile(pg); + } + + pg->Branch(st, label_target.ContinueTarget()); + pg->SetLabel(st, label_target.BreakTarget()); } void JSCompiler::Compile(const ir::ForOfStatement *st) const { - (void)st; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + compiler::LocalRegScope decl_reg_scope(pg, st->Scope()->DeclScope()->InitScope()); + + st->Right()->Compile(pg); + + compiler::LabelTarget label_target(pg); + auto iterator_type = st->IsAwait() ? compiler::IteratorType::ASYNC : compiler::IteratorType::SYNC; + compiler::Iterator iterator(pg, st, iterator_type); + + pg->SetLabel(st, label_target.ContinueTarget()); + + iterator.Next(); + iterator.Complete(); + pg->BranchIfTrue(st, label_target.BreakTarget()); + + iterator.Value(); + pg->StoreAccumulator(st, iterator.NextResult()); + + auto lref = compiler::JSLReference::Create(pg, st->Left(), false); + + { + compiler::IteratorContext for_of_ctx(pg, iterator, label_target); + pg->LoadAccumulator(st, iterator.NextResult()); + lref.SetValue(); + + compiler::LoopEnvScope decl_env_scope(pg, st->Scope()->DeclScope()); + compiler::LoopEnvScope env_scope(pg, st->Scope(), {}); + st->Body()->Compile(pg); + } + + pg->Branch(st, label_target.ContinueTarget()); + pg->SetLabel(st, label_target.BreakTarget()); } void JSCompiler::Compile(const ir::ForUpdateStatement *st) const { - (void)st; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + compiler::LocalRegScope decl_reg_scope(pg, st->Scope()->DeclScope()->InitScope()); + + if (st->Init() != nullptr) { + ASSERT(st->Init()->IsVariableDeclaration() || st->Init()->IsExpression()); + st->Init()->Compile(pg); + } + + auto *start_label = pg->AllocLabel(); + compiler::LabelTarget label_target(pg); + + compiler::LoopEnvScope decl_env_scope(pg, st->Scope()->DeclScope()); + compiler::LoopEnvScope env_scope(pg, label_target, st->Scope()); + pg->SetLabel(st, start_label); + + { + compiler::LocalRegScope reg_scope(pg, st->Scope()); + + if (st->Test() != nullptr) { + compiler::Condition::Compile(pg, st->Test(), label_target.BreakTarget()); + } + + st->Body()->Compile(pg); + pg->SetLabel(st, label_target.ContinueTarget()); + env_scope.CopyPetIterationCtx(); + } + + if (st->Update() != nullptr) { + st->Update()->Compile(pg); + } + + pg->Branch(st, start_label); + pg->SetLabel(st, label_target.BreakTarget()); } -void JSCompiler::Compile(const ir::FunctionDeclaration *st) const +void JSCompiler::Compile([[maybe_unused]] const ir::FunctionDeclaration *st) const {} + +void JSCompiler::Compile(const ir::IfStatement *st) const { - (void)st; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + auto *consequent_end = pg->AllocLabel(); + compiler::Label *statement_end = consequent_end; + + compiler::Condition::Compile(pg, st->Test(), consequent_end); + st->Consequent()->Compile(pg); + + if (st->Alternate() != nullptr) { + statement_end = pg->AllocLabel(); + pg->Branch(pg->Insns().back()->Node(), statement_end); + + pg->SetLabel(st, consequent_end); + st->Alternate()->Compile(pg); + } + + pg->SetLabel(st, statement_end); } -void JSCompiler::Compile(const ir::IfStatement *st) const +void CompileImpl(const ir::LabelledStatement *self, PandaGen *cg) { - (void)st; - UNREACHABLE(); + compiler::LabelContext label_ctx(cg, self); + self->Body()->Compile(cg); } void JSCompiler::Compile(const ir::LabelledStatement *st) const { - (void)st; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + CompileImpl(st, pg); } void JSCompiler::Compile(const ir::ReturnStatement *st) const @@ -921,16 +1026,47 @@ void JSCompiler::Compile(const ir::ReturnStatement *st) const } } -void JSCompiler::Compile(const ir::SwitchCaseStatement *st) const +void JSCompiler::Compile([[maybe_unused]] const ir::SwitchCaseStatement *st) const { - (void)st; UNREACHABLE(); } +static void CompileImpl(const ir::SwitchStatement *self, PandaGen *cg) +{ + compiler::LocalRegScope lrs(cg, self->Scope()); + compiler::SwitchBuilder builder(cg, self); + compiler::VReg tag = cg->AllocReg(); + + builder.CompileTagOfSwitch(tag); + uint32_t default_index = 0; + + for (size_t i = 0; i < self->Cases().size(); i++) { + const auto *clause = self->Cases()[i]; + + if (clause->Test() == nullptr) { + default_index = i; + continue; + } + + builder.JumpIfCase(tag, i); + } + + if (default_index > 0) { + builder.JumpToDefault(default_index); + } else { + builder.Break(); + } + + for (size_t i = 0; i < self->Cases().size(); i++) { + builder.SetCaseTarget(i); + builder.CompileCaseStatements(i); + } +} + void JSCompiler::Compile(const ir::SwitchStatement *st) const { - (void)st; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + CompileImpl(st, pg); } void JSCompiler::Compile(const ir::ThrowStatement *st) const diff --git a/ets2panda/ir/statements/emptyStatement.cpp b/ets2panda/ir/statements/emptyStatement.cpp index 5da09fdd22..4c00f2a89e 100644 --- a/ets2panda/ir/statements/emptyStatement.cpp +++ b/ets2panda/ir/statements/emptyStatement.cpp @@ -15,7 +15,9 @@ #include "emptyStatement.h" -#include "ir/astDump.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void EmptyStatement::TransformChildren([[maybe_unused]] const NodeTransformer &cb) {} @@ -26,15 +28,23 @@ void EmptyStatement::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "EmptyStatement"}}); } -void EmptyStatement::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void EmptyStatement::Compile(compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} + +void EmptyStatement::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} -checker::Type *EmptyStatement::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *EmptyStatement::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } -checker::Type *EmptyStatement::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *EmptyStatement::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/statements/emptyStatement.h b/ets2panda/ir/statements/emptyStatement.h index 44c82b2fba..a815449fba 100644 --- a/ets2panda/ir/statements/emptyStatement.h +++ b/ets2panda/ir/statements/emptyStatement.h @@ -26,9 +26,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: }; diff --git a/ets2panda/ir/statements/expressionStatement.cpp b/ets2panda/ir/statements/expressionStatement.cpp index 61ebaca008..d4750832be 100644 --- a/ets2panda/ir/statements/expressionStatement.cpp +++ b/ets2panda/ir/statements/expressionStatement.cpp @@ -15,8 +15,9 @@ #include "expressionStatement.h" -#include "ir/astDump.h" -#include "ir/expression.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void ExpressionStatement::TransformChildren(const NodeTransformer &cb) @@ -34,23 +35,23 @@ void ExpressionStatement::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "ExpressionStatement"}, {"expression", expression_}}); } -void ExpressionStatement::Compile([[maybe_unused]] compiler::PandaGen *pg) const +void ExpressionStatement::Compile(compiler::PandaGen *pg) const { - expression_->Compile(pg); + pg->GetAstCompiler()->Compile(this); } -void ExpressionStatement::Compile([[maybe_unused]] compiler::ETSGen *etsg) const +void ExpressionStatement::Compile(compiler::ETSGen *etsg) const { - expression_->Compile(etsg); + etsg->GetAstCompiler()->Compile(this); } -checker::Type *ExpressionStatement::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *ExpressionStatement::Check(checker::TSChecker *checker) { - return expression_->Check(checker); + return checker->GetAnalyzer()->Check(this); } -checker::Type *ExpressionStatement::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *ExpressionStatement::Check(checker::ETSChecker *checker) { - return expression_->Check(checker); + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/statements/expressionStatement.h b/ets2panda/ir/statements/expressionStatement.h index 2f80d87221..56ea203632 100644 --- a/ets2panda/ir/statements/expressionStatement.h +++ b/ets2panda/ir/statements/expressionStatement.h @@ -38,10 +38,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - void Compile([[maybe_unused]] compiler::ETSGen *etsg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: Expression *expression_; diff --git a/ets2panda/ir/statements/forInStatement.cpp b/ets2panda/ir/statements/forInStatement.cpp index b21b387e5d..331be2f2ff 100644 --- a/ets2panda/ir/statements/forInStatement.cpp +++ b/ets2panda/ir/statements/forInStatement.cpp @@ -20,9 +20,7 @@ #include "compiler/core/labelTarget.h" #include "compiler/core/pandagen.h" #include "checker/TSchecker.h" - -#include "ir/astDump.h" -#include "ir/expression.h" +#include "compiler/core/ETSGen.h" namespace panda::es2panda::ir { void ForInStatement::TransformChildren(const NodeTransformer &cb) @@ -44,49 +42,23 @@ void ForInStatement::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "ForInStatement"}, {"left", left_}, {"right", right_}, {"body", body_}}); } -void ForInStatement::Compile([[maybe_unused]] compiler::PandaGen *pg) const +void ForInStatement::Compile(compiler::PandaGen *pg) const { - compiler::LabelTarget label_target(pg); - - compiler::RegScope rs(pg); - compiler::VReg iter = pg->AllocReg(); - compiler::VReg prop_name = pg->AllocReg(); - - // create enumerator - right_->Compile(pg); - pg->GetPropIterator(this); - pg->StoreAccumulator(this, iter); - - pg->SetLabel(this, label_target.ContinueTarget()); - - // get next prop of enumerator - pg->GetNextPropName(this, iter); - pg->StoreAccumulator(this, prop_name); - pg->BranchIfUndefined(this, label_target.BreakTarget()); - - compiler::LocalRegScope decl_reg_scope(pg, Scope()->DeclScope()->InitScope()); - auto lref = compiler::JSLReference::Create(pg, left_, false); - pg->LoadAccumulator(this, prop_name); - lref.SetValue(); - - compiler::LoopEnvScope decl_env_scope(pg, Scope()->DeclScope()); - - { - compiler::LoopEnvScope env_scope(pg, Scope(), label_target); - body_->Compile(pg); - } + pg->GetAstCompiler()->Compile(this); +} - pg->Branch(this, label_target.ContinueTarget()); - pg->SetLabel(this, label_target.BreakTarget()); +void ForInStatement::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); } -checker::Type *ForInStatement::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *ForInStatement::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } -checker::Type *ForInStatement::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *ForInStatement::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/statements/forInStatement.h b/ets2panda/ir/statements/forInStatement.h index 1089e3ffa4..78d482e827 100644 --- a/ets2panda/ir/statements/forInStatement.h +++ b/ets2panda/ir/statements/forInStatement.h @@ -72,9 +72,10 @@ public: 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::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: AstNode *left_; diff --git a/ets2panda/ir/statements/forOfStatement.cpp b/ets2panda/ir/statements/forOfStatement.cpp index 1b7ae5a7cc..50cb1e9d1c 100644 --- a/ets2panda/ir/statements/forOfStatement.cpp +++ b/ets2panda/ir/statements/forOfStatement.cpp @@ -19,14 +19,9 @@ #include "compiler/base/iterators.h" #include "compiler/base/lreference.h" #include "compiler/core/labelTarget.h" +#include "checker/TSchecker.h" #include "compiler/core/pandagen.h" #include "compiler/core/ETSGen.h" -#include "ir/astDump.h" -#include "ir/expression.h" -#include "ir/expressions/identifier.h" -#include "ir/expressions/superExpression.h" -#include "ir/statements/variableDeclarator.h" -#include "ir/statements/variableDeclaration.h" namespace panda::es2panda::ir { void ForOfStatement::TransformChildren(const NodeTransformer &cb) @@ -49,176 +44,23 @@ void ForOfStatement::Dump(ir::AstDumper *dumper) const {{"type", "ForOfStatement"}, {"await", is_await_}, {"left", left_}, {"right", right_}, {"body", body_}}); } -void ForOfStatement::Compile([[maybe_unused]] compiler::PandaGen *pg) const +void ForOfStatement::Compile(compiler::PandaGen *pg) const { - compiler::LocalRegScope decl_reg_scope(pg, Scope()->DeclScope()->InitScope()); - - right_->Compile(pg); - - compiler::LabelTarget label_target(pg); - auto iterator_type = is_await_ ? compiler::IteratorType::ASYNC : compiler::IteratorType::SYNC; - compiler::Iterator iterator(pg, this, iterator_type); - - pg->SetLabel(this, label_target.ContinueTarget()); - - iterator.Next(); - iterator.Complete(); - pg->BranchIfTrue(this, label_target.BreakTarget()); - - iterator.Value(); - pg->StoreAccumulator(this, iterator.NextResult()); - - auto lref = compiler::JSLReference::Create(pg, left_, false); - - { - compiler::IteratorContext for_of_ctx(pg, iterator, label_target); - pg->LoadAccumulator(this, iterator.NextResult()); - lref.SetValue(); - - compiler::LoopEnvScope decl_env_scope(pg, Scope()->DeclScope()); - compiler::LoopEnvScope env_scope(pg, Scope(), {}); - body_->Compile(pg); - } - - pg->Branch(this, label_target.ContinueTarget()); - pg->SetLabel(this, label_target.BreakTarget()); + pg->GetAstCompiler()->Compile(this); } void ForOfStatement::Compile(compiler::ETSGen *etsg) const { - compiler::LocalRegScope decl_reg_scope(etsg, Scope()->DeclScope()->InitScope()); - - checker::Type const *const expr_type = right_->TsType(); - ASSERT(expr_type->IsETSArrayType() || expr_type->IsETSStringType()); - - right_->Compile(etsg); - compiler::VReg obj_reg = etsg->AllocReg(); - etsg->StoreAccumulator(this, obj_reg); - - if (expr_type->IsETSArrayType()) { - etsg->LoadArrayLength(this, obj_reg); - } else { - etsg->LoadStringLength(this); - } - - compiler::VReg size_reg = etsg->AllocReg(); - etsg->StoreAccumulator(this, size_reg); - - compiler::LabelTarget label_target(etsg); - auto label_ctx = compiler::LabelContext(etsg, label_target); - - etsg->BranchIfFalse(this, label_target.BreakTarget()); - - compiler::VReg count_reg = etsg->AllocReg(); - etsg->MoveImmediateToRegister(this, count_reg, checker::TypeFlag::INT, static_cast(0)); - etsg->LoadAccumulatorInt(this, static_cast(0)); - - auto *const start_label = etsg->AllocLabel(); - etsg->SetLabel(this, start_label); - - auto lref = compiler::ETSLReference::Create(etsg, left_, false); - - if (right_->TsType()->IsETSArrayType()) { - etsg->LoadArrayElement(this, obj_reg); - } else { - etsg->LoadStringChar(this, obj_reg, count_reg); - } - - lref.SetValue(); - body_->Compile(etsg); - - etsg->SetLabel(this, label_target.ContinueTarget()); - - etsg->IncrementImmediateRegister(this, count_reg, checker::TypeFlag::INT, static_cast(1)); - etsg->LoadAccumulator(this, count_reg); - - etsg->JumpCompareRegister(this, size_reg, start_label); - etsg->SetLabel(this, label_target.BreakTarget()); + etsg->GetAstCompiler()->Compile(this); } -checker::Type *ForOfStatement::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *ForOfStatement::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } -// NOLINTBEGIN(modernize-avoid-c-arrays) -static constexpr char const INVALID_SOURCE_EXPR_TYPE[] = - "'For-of' statement source expression should be either a string or an array."; -static constexpr char const INVALID_CONST_ASSIGNMENT[] = "Cannot assign a value to a constant variable "; -static constexpr char const ITERATOR_TYPE_ABSENT[] = "Cannot obtain iterator type in 'for-of' statement."; -// NOLINTEND(modernize-avoid-c-arrays) - checker::Type *ForOfStatement::Check(checker::ETSChecker *checker) { - checker::ScopeContext scope_ctx(checker, Scope()); - - checker::Type *const expr_type = right_->Check(checker); - checker::Type *elem_type; - - if (expr_type == nullptr || (!expr_type->IsETSArrayType() && !expr_type->IsETSStringType())) { - checker->ThrowTypeError(INVALID_SOURCE_EXPR_TYPE, right_->Start()); - } else if (expr_type->IsETSStringType()) { - elem_type = checker->GetGlobalTypesHolder()->GlobalCharType(); - } else { - elem_type = expr_type->AsETSArrayType()->ElementType()->Instantiate(checker->Allocator(), checker->Relation(), - checker->GetGlobalTypesHolder()); - elem_type->RemoveTypeFlag(checker::TypeFlag::CONSTANT); - } - - left_->Check(checker); - checker::Type *iter_type = nullptr; - - // Just to avoid extra nested level(s) - auto const get_iter_type = [checker, elem_type](ir::VariableDeclarator *const declarator) -> checker::Type * { - if (declarator->TsType() == nullptr) { - if (auto *resolved = checker->FindVariableInFunctionScope(declarator->Id()->AsIdentifier()->Name()); - resolved != nullptr) { - resolved->SetTsType(elem_type); - return elem_type; - } - } else { - return declarator->TsType(); - } - return nullptr; - }; - - if (left_->IsIdentifier()) { - if (auto *const variable = left_->AsIdentifier()->Variable(); variable != nullptr) { - if (variable->Declaration()->IsConstDecl()) { - checker->ThrowTypeError({INVALID_CONST_ASSIGNMENT, variable->Name()}, - variable->Declaration()->Node()->Start()); - } - } - iter_type = left_->AsIdentifier()->TsType(); - } else if (left_->IsVariableDeclaration()) { - if (auto const &declarators = left_->AsVariableDeclaration()->Declarators(); !declarators.empty()) { - iter_type = get_iter_type(declarators.front()); - } - } - - if (iter_type == nullptr) { - checker->ThrowTypeError(ITERATOR_TYPE_ABSENT, left_->Start()); - } - - auto *const relation = checker->Relation(); - relation->SetFlags(checker::TypeRelationFlag::ASSIGNMENT_CONTEXT); - relation->SetNode(checker->AllocNode()); // Dummy node to avoid assertion! - - if (!relation->IsAssignableTo(elem_type, iter_type)) { - std::stringstream ss {}; - ss << "Source element type '"; - elem_type->ToString(ss); - ss << "' is not assignable to the loop iterator type '"; - iter_type->ToString(ss); - ss << "'."; - checker->ThrowTypeError(ss.str(), Start()); - } - - relation->SetNode(nullptr); - relation->SetFlags(checker::TypeRelationFlag::NONE); - - body_->Check(checker); - - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/statements/forOfStatement.h b/ets2panda/ir/statements/forOfStatement.h index 51a99573c8..0043c78a7c 100644 --- a/ets2panda/ir/statements/forOfStatement.h +++ b/ets2panda/ir/statements/forOfStatement.h @@ -82,10 +82,10 @@ 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 Compile([[maybe_unused]] compiler::ETSGen *etsg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: AstNode *left_; diff --git a/ets2panda/ir/statements/forUpdateStatement.cpp b/ets2panda/ir/statements/forUpdateStatement.cpp index 378dbcf36d..09ccc20602 100644 --- a/ets2panda/ir/statements/forUpdateStatement.cpp +++ b/ets2panda/ir/statements/forUpdateStatement.cpp @@ -23,8 +23,6 @@ #include "compiler/core/ETSGen.h" #include "compiler/core/dynamicContext.h" #include "checker/TSchecker.h" -#include "ir/astDump.h" -#include "ir/expression.h" namespace panda::es2panda::ir { void ForUpdateStatement::TransformChildren(const NodeTransformer &cb) @@ -68,115 +66,23 @@ void ForUpdateStatement::Dump(ir::AstDumper *dumper) const {"body", body_}}); } -void ForUpdateStatement::Compile([[maybe_unused]] compiler::PandaGen *pg) const +void ForUpdateStatement::Compile(compiler::PandaGen *pg) const { - compiler::LocalRegScope decl_reg_scope(pg, Scope()->DeclScope()->InitScope()); - - if (init_ != nullptr) { - ASSERT(init_->IsVariableDeclaration() || init_->IsExpression()); - init_->Compile(pg); - } - - auto *start_label = pg->AllocLabel(); - compiler::LabelTarget label_target(pg); - - compiler::LoopEnvScope decl_env_scope(pg, Scope()->DeclScope()); - compiler::LoopEnvScope env_scope(pg, label_target, Scope()); - pg->SetLabel(this, start_label); - - { - compiler::LocalRegScope reg_scope(pg, Scope()); - - if (test_ != nullptr) { - compiler::Condition::Compile(pg, test_, label_target.BreakTarget()); - } - - body_->Compile(pg); - pg->SetLabel(this, label_target.ContinueTarget()); - env_scope.CopyPetIterationCtx(); - } - - if (update_ != nullptr) { - update_->Compile(pg); - } - - pg->Branch(this, start_label); - pg->SetLabel(this, label_target.BreakTarget()); + pg->GetAstCompiler()->Compile(this); } -void ForUpdateStatement::Compile([[maybe_unused]] compiler::ETSGen *etsg) const +void ForUpdateStatement::Compile(compiler::ETSGen *etsg) const { - compiler::LocalRegScope decl_reg_scope(etsg, Scope()->DeclScope()->InitScope()); - - if (init_ != nullptr) { - ASSERT(init_->IsVariableDeclaration() || init_->IsExpression()); - init_->Compile(etsg); - } - - auto *start_label = etsg->AllocLabel(); - compiler::LabelTarget label_target(etsg); - auto label_ctx = compiler::LabelContext(etsg, label_target); - etsg->SetLabel(this, start_label); - - { - compiler::LocalRegScope reg_scope(etsg, Scope()); - - if (test_ != nullptr) { - compiler::Condition::Compile(etsg, test_, label_target.BreakTarget()); - } - - body_->Compile(etsg); - etsg->SetLabel(this, label_target.ContinueTarget()); - } - - if (update_ != nullptr) { - update_->Compile(etsg); - } - - etsg->Branch(this, start_label); - etsg->SetLabel(this, label_target.BreakTarget()); + etsg->GetAstCompiler()->Compile(this); } -checker::Type *ForUpdateStatement::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *ForUpdateStatement::Check(checker::TSChecker *checker) { - checker::ScopeContext scope_ctx(checker, Scope()); - - if (init_ != nullptr) { - init_->Check(checker); - } - - if (test_ != nullptr) { - checker::Type *test_type = test_->Check(checker); - checker->CheckTruthinessOfType(test_type, Start()); - } - - if (update_ != nullptr) { - update_->Check(checker); - } - - body_->Check(checker); - - return nullptr; + return checker->GetAnalyzer()->Check(this); } -checker::Type *ForUpdateStatement::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *ForUpdateStatement::Check(checker::ETSChecker *checker) { - checker::ScopeContext scope_ctx(checker, Scope()); - - if (init_ != nullptr) { - init_->Check(checker); - } - - if (test_ != nullptr) { - checker->CheckTruthinessOfType(test_); - } - - if (update_ != nullptr) { - update_->Check(checker); - } - - body_->Check(checker); - - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/statements/forUpdateStatement.h b/ets2panda/ir/statements/forUpdateStatement.h index f79166695e..9e39b8b0d4 100644 --- a/ets2panda/ir/statements/forUpdateStatement.h +++ b/ets2panda/ir/statements/forUpdateStatement.h @@ -87,10 +87,10 @@ 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 Compile([[maybe_unused]] compiler::ETSGen *etsg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: AstNode *init_; diff --git a/ets2panda/ir/statements/functionDeclaration.cpp b/ets2panda/ir/statements/functionDeclaration.cpp index 578a8b1e78..a5c9e3a614 100644 --- a/ets2panda/ir/statements/functionDeclaration.cpp +++ b/ets2panda/ir/statements/functionDeclaration.cpp @@ -19,14 +19,7 @@ #include "varbinder/scope.h" #include "compiler/core/ETSGen.h" #include "checker/TSchecker.h" -#include "checker/ETSchecker.h" -#include "checker/types/ets/etsFunctionType.h" -#include "ir/astDump.h" -#include "ir/typeNode.h" -#include "ir/base/spreadElement.h" -#include "ir/base/decorator.h" -#include "ir/base/scriptFunction.h" -#include "ir/expressions/identifier.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void FunctionDeclaration::TransformChildren(const NodeTransformer &cb) @@ -54,37 +47,23 @@ void FunctionDeclaration::Dump(ir::AstDumper *dumper) const {"function", func_}}); } -void FunctionDeclaration::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} - -void FunctionDeclaration::Compile([[maybe_unused]] compiler::ETSGen *etsg) const +void FunctionDeclaration::Compile(compiler::PandaGen *pg) const { - UNREACHABLE(); + pg->GetAstCompiler()->Compile(this); } -checker::Type *FunctionDeclaration::Check([[maybe_unused]] checker::TSChecker *checker) +void FunctionDeclaration::Compile(compiler::ETSGen *etsg) const { - if (func_->IsOverload()) { - return nullptr; - } - - const util::StringView &func_name = func_->Id()->Name(); - auto result = checker->Scope()->Find(func_name); - ASSERT(result.variable); - - checker::ScopeContext scope_ctx(checker, func_->Scope()); - - if (result.variable->TsType() == nullptr) { - checker->InferFunctionDeclarationType(result.variable->Declaration()->AsFunctionDecl(), result.variable); - } - - func_->Body()->Check(checker); + etsg->GetAstCompiler()->Compile(this); +} - return nullptr; +checker::Type *FunctionDeclaration::Check(checker::TSChecker *checker) +{ + return checker->GetAnalyzer()->Check(this); } -checker::Type *FunctionDeclaration::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *FunctionDeclaration::Check(checker::ETSChecker *checker) { - UNREACHABLE(); - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/statements/functionDeclaration.h b/ets2panda/ir/statements/functionDeclaration.h index 0c00928b77..26bed64a5d 100644 --- a/ets2panda/ir/statements/functionDeclaration.h +++ b/ets2panda/ir/statements/functionDeclaration.h @@ -51,10 +51,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - void Compile([[maybe_unused]] compiler::ETSGen *etsg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: ArenaVector decorators_; diff --git a/ets2panda/ir/statements/ifStatement.cpp b/ets2panda/ir/statements/ifStatement.cpp index 02d9091d06..05b30ac411 100644 --- a/ets2panda/ir/statements/ifStatement.cpp +++ b/ets2panda/ir/statements/ifStatement.cpp @@ -15,12 +15,9 @@ #include "ifStatement.h" -#include "compiler/base/condition.h" -#include "compiler/core/pandagen.h" -#include "compiler/core/ETSGen.h" #include "checker/TSchecker.h" -#include "ir/astDump.h" -#include "ir/expression.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void IfStatement::TransformChildren(const NodeTransformer &cb) @@ -51,84 +48,23 @@ void IfStatement::Dump(ir::AstDumper *dumper) const {"alternate", AstDumper::Nullish(alternate_)}}); } -void IfStatement::Compile([[maybe_unused]] compiler::PandaGen *pg) const +void IfStatement::Compile(compiler::PandaGen *pg) const { - auto *consequent_end = pg->AllocLabel(); - compiler::Label *statement_end = consequent_end; - - compiler::Condition::Compile(pg, test_, consequent_end); - consequent_->Compile(pg); - - if (alternate_ != nullptr) { - statement_end = pg->AllocLabel(); - pg->Branch(pg->Insns().back()->Node(), statement_end); - - pg->SetLabel(this, consequent_end); - alternate_->Compile(pg); - } - - pg->SetLabel(this, statement_end); + pg->GetAstCompiler()->Compile(this); } -void IfStatement::Compile([[maybe_unused]] compiler::ETSGen *etsg) const +void IfStatement::Compile(compiler::ETSGen *etsg) const { - auto res = compiler::Condition::CheckConstantExpr(etsg, test_); - - if (res == compiler::Condition::Result::CONST_TRUE) { - consequent_->Compile(etsg); - return; - } - - if (res == compiler::Condition::Result::CONST_FALSE) { - if (alternate_ != nullptr) { - alternate_->Compile(etsg); - } - return; - } - - auto *consequent_end = etsg->AllocLabel(); - compiler::Label *statement_end = consequent_end; - - compiler::Condition::Compile(etsg, test_, consequent_end); - - consequent_->Compile(etsg); - - if (alternate_ != nullptr) { - statement_end = etsg->AllocLabel(); - etsg->Branch(etsg->Insns().back()->Node(), statement_end); - - etsg->SetLabel(this, consequent_end); - alternate_->Compile(etsg); - } - - etsg->SetLabel(this, statement_end); + etsg->GetAstCompiler()->Compile(this); } checker::Type *IfStatement::Check([[maybe_unused]] checker::TSChecker *checker) { - checker::Type *test_type = test_->Check(checker); - checker->CheckTruthinessOfType(test_type, Start()); - checker->CheckTestingKnownTruthyCallableOrAwaitableType(test_, test_type, consequent_); - - consequent_->Check(checker); - - if (alternate_ != nullptr) { - alternate_->Check(checker); - } - - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *IfStatement::Check([[maybe_unused]] checker::ETSChecker *checker) { - checker->CheckTruthinessOfType(test_); - - consequent_->Check(checker); - - if (alternate_ != nullptr) { - alternate_->Check(checker); - } - - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/statements/ifStatement.h b/ets2panda/ir/statements/ifStatement.h index b2596d77bc..b0fa50be83 100644 --- a/ets2panda/ir/statements/ifStatement.h +++ b/ets2panda/ir/statements/ifStatement.h @@ -18,6 +18,11 @@ #include "ir/statement.h" +namespace panda::es2panda::checker { +class TSAnalyzer; +class ETSAnalyzer; +} // namespace panda::es2panda::checker + namespace panda::es2panda::ir { class Expression; @@ -28,6 +33,10 @@ public: { } + // TODO (csabahurton): these friend relationships can be removed once there are getters for private fields + friend class checker::ETSAnalyzer; + friend class checker::TSAnalyzer; + const Expression *Test() const { return test_; @@ -56,10 +65,10 @@ 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 Compile([[maybe_unused]] compiler::ETSGen *etsg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: Expression *test_; diff --git a/ets2panda/ir/statements/labelledStatement.cpp b/ets2panda/ir/statements/labelledStatement.cpp index be77a04fdc..c43d30ebf8 100644 --- a/ets2panda/ir/statements/labelledStatement.cpp +++ b/ets2panda/ir/statements/labelledStatement.cpp @@ -15,11 +15,9 @@ #include "labelledStatement.h" -#include "compiler/core/pandagen.h" +#include "checker/TSchecker.h" #include "compiler/core/ETSGen.h" -#include "compiler/core/labelTarget.h" -#include "ir/astDump.h" -#include "ir/expressions/identifier.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void LabelledStatement::TransformChildren(const NodeTransformer &cb) @@ -39,13 +37,6 @@ void LabelledStatement::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "LabelledStatement"}, {"label", ident_}, {"body", body_}}); } -template -void CompileImpl(const LabelledStatement *self, CodeGen *cg) -{ - compiler::LabelContext label_ctx(cg, self); - self->Body()->Compile(cg); -} - const ir::AstNode *LabelledStatement::GetReferencedStatement() const { const auto *iter = body_; @@ -67,24 +58,23 @@ const ir::AstNode *LabelledStatement::GetReferencedStatement() const } } -void LabelledStatement::Compile([[maybe_unused]] compiler::PandaGen *pg) const +void LabelledStatement::Compile(compiler::PandaGen *pg) const { - CompileImpl(this, pg); + pg->GetAstCompiler()->Compile(this); } -void LabelledStatement::Compile([[maybe_unused]] compiler::ETSGen *etsg) const +void LabelledStatement::Compile(compiler::ETSGen *etsg) const { - CompileImpl(this, etsg); + etsg->GetAstCompiler()->Compile(this); } -checker::Type *LabelledStatement::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *LabelledStatement::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } -checker::Type *LabelledStatement::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *LabelledStatement::Check(checker::ETSChecker *checker) { - body_->Check(checker); - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/statements/labelledStatement.h b/ets2panda/ir/statements/labelledStatement.h index 7a5779bd3f..a0a2b52e11 100644 --- a/ets2panda/ir/statements/labelledStatement.h +++ b/ets2panda/ir/statements/labelledStatement.h @@ -19,6 +19,10 @@ #include "ir/statement.h" #include "util/ustring.h" +namespace panda::es2panda::checker { +class ETSAnalyzer; +} // namespace panda::es2panda::checker + namespace panda::es2panda::ir { class Identifier; @@ -29,6 +33,9 @@ public: { } + // TODO (csabahurton): these friend relationships can be removed once there are getters for private fields + friend class checker::ETSAnalyzer; + const Statement *Body() const { return body_; @@ -51,10 +58,10 @@ 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 Compile([[maybe_unused]] compiler::ETSGen *etsg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: Identifier *ident_; diff --git a/ets2panda/ir/statements/switchCaseStatement.cpp b/ets2panda/ir/statements/switchCaseStatement.cpp index d3b4ab31ea..3830c777c6 100644 --- a/ets2panda/ir/statements/switchCaseStatement.cpp +++ b/ets2panda/ir/statements/switchCaseStatement.cpp @@ -15,8 +15,9 @@ #include "switchCaseStatement.h" -#include "ir/astDump.h" -#include "ir/expression.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void SwitchCaseStatement::TransformChildren(const NodeTransformer &cb) @@ -46,15 +47,23 @@ void SwitchCaseStatement::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "SwitchCase"}, {"test", AstDumper::Nullish(test_)}, {"consequent", consequent_}}); } -void SwitchCaseStatement::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void SwitchCaseStatement::Compile(compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} + +void SwitchCaseStatement::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} -checker::Type *SwitchCaseStatement::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *SwitchCaseStatement::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } -checker::Type *SwitchCaseStatement::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *SwitchCaseStatement::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/statements/switchCaseStatement.h b/ets2panda/ir/statements/switchCaseStatement.h index 0ed32b85fa..886520a6f7 100644 --- a/ets2panda/ir/statements/switchCaseStatement.h +++ b/ets2panda/ir/statements/switchCaseStatement.h @@ -55,9 +55,10 @@ public: 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::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: Expression *test_; diff --git a/ets2panda/ir/statements/switchStatement.cpp b/ets2panda/ir/statements/switchStatement.cpp index 4bc685e3b2..c7d908bd2d 100644 --- a/ets2panda/ir/statements/switchStatement.cpp +++ b/ets2panda/ir/statements/switchStatement.cpp @@ -21,12 +21,6 @@ #include "compiler/core/pandagen.h" #include "compiler/core/ETSGen.h" #include "checker/TSchecker.h" -#include "checker/ets/typeRelationContext.h" -#include "ir/astDump.h" -#include "ir/expression.h" -#include "ir/expressions/identifier.h" -#include "ir/expressions/memberExpression.h" -#include "ir/statements/switchCaseStatement.h" namespace panda::es2panda::ir { void SwitchStatement::TransformChildren(const NodeTransformer &cb) @@ -52,132 +46,24 @@ void SwitchStatement::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "SwitchStatement"}, {"discriminant", discriminant_}, {"cases", cases_}}); } -template -void CompileImpl(const SwitchStatement *self, CodeGen *cg) +void SwitchStatement::Compile(compiler::PandaGen *pg) const { - compiler::LocalRegScope lrs(cg, self->Scope()); - compiler::SwitchBuilder builder(cg, self); - compiler::VReg tag = cg->AllocReg(); - - builder.CompileTagOfSwitch(tag); - uint32_t default_index = 0; - - for (size_t i = 0; i < self->Cases().size(); i++) { - const auto *clause = self->Cases()[i]; - - if (clause->Test() == nullptr) { - default_index = i; - continue; - } - - builder.JumpIfCase(tag, i); - } - - if (default_index > 0) { - builder.JumpToDefault(default_index); - } else { - builder.Break(); - } - - for (size_t i = 0; i < self->Cases().size(); i++) { - builder.SetCaseTarget(i); - builder.CompileCaseStatements(i); - } + pg->GetAstCompiler()->Compile(this); } -void SwitchStatement::Compile([[maybe_unused]] compiler::PandaGen *pg) const +void SwitchStatement::Compile(compiler::ETSGen *etsg) const { - CompileImpl(this, pg); + etsg->GetAstCompiler()->Compile(this); } -void SwitchStatement::Compile([[maybe_unused]] compiler::ETSGen *etsg) const +checker::Type *SwitchStatement::Check(checker::TSChecker *checker) { - CompileImpl(this, etsg); -} - -checker::Type *SwitchStatement::Check([[maybe_unused]] checker::TSChecker *checker) -{ - checker::ScopeContext scope_ctx(checker, scope_); - - checker::Type *expr_type = discriminant_->Check(checker); - bool expr_is_literal = checker::TSChecker::IsLiteralType(expr_type); - - for (auto *it : cases_) { - if (it->Test() != nullptr) { - checker::Type *case_type = it->Test()->Check(checker); - bool case_is_literal = checker::TSChecker::IsLiteralType(case_type); - checker::Type *compared_expr_type = expr_type; - - if (!case_is_literal || !expr_is_literal) { - case_type = case_is_literal ? checker->GetBaseTypeOfLiteralType(case_type) : case_type; - compared_expr_type = checker->GetBaseTypeOfLiteralType(expr_type); - } - - if (!checker->IsTypeEqualityComparableTo(compared_expr_type, case_type) && - !checker->IsTypeComparableTo(case_type, compared_expr_type)) { - checker->ThrowTypeError({"Type ", case_type, " is not comparable to type ", compared_expr_type}, - it->Test()->Start()); - } - } - - for (auto *case_stmt : it->Consequent()) { - case_stmt->Check(checker); - } - } - - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *SwitchStatement::Check(checker::ETSChecker *const checker) { - checker::ScopeContext scope_ctx(checker, scope_); - discriminant_->Check(checker); - checker::SavedTypeRelationFlagsContext saved_type_relation_flag_ctx(checker->Relation(), - checker::TypeRelationFlag::NONE); - // NOTE: check exhaustive Switch - checker->CheckSwitchDiscriminant(discriminant_); - auto *compared_expr_type = discriminant_->TsType(); - auto unboxed_disc_type = (Discriminant()->GetBoxingUnboxingFlags() & ir::BoxingUnboxingFlags::UNBOXING_FLAG) != 0U - ? checker->ETSBuiltinTypeAsPrimitiveType(compared_expr_type) - : compared_expr_type; - - bool valid_case_type; - - for (auto *it : cases_) { - if (it->Test() != nullptr) { - auto *case_type = it->Test()->Check(checker); - valid_case_type = true; - if (case_type->HasTypeFlag(checker::TypeFlag::CHAR)) { - valid_case_type = compared_expr_type->HasTypeFlag(checker::TypeFlag::ETS_INTEGRAL); - } else if (case_type->IsETSEnumType() && discriminant_->TsType()->IsETSEnumType()) { - valid_case_type = discriminant_->TsType()->AsETSEnumType()->IsSameEnumType(case_type->AsETSEnumType()); - } else if (case_type->IsETSStringEnumType() && discriminant_->TsType()->IsETSStringEnumType()) { - valid_case_type = - discriminant_->TsType()->AsETSStringEnumType()->IsSameEnumType(case_type->AsETSStringEnumType()); - } else { - checker::AssignmentContext( - checker->Relation(), discriminant_, case_type, unboxed_disc_type, it->Test()->Start(), - {"Switch case type ", case_type, " is not comparable to discriminant type ", compared_expr_type}, - (compared_expr_type->IsETSObjectType() ? checker::TypeRelationFlag::NO_WIDENING - : checker::TypeRelationFlag::NO_UNBOXING) | - checker::TypeRelationFlag::NO_BOXING); - } - - if (!valid_case_type) { - checker->ThrowTypeError( - {"Switch case type ", case_type, " is not comparable to discriminant type ", compared_expr_type}, - it->Test()->Start()); - } - } - - for (auto *case_stmt : it->Consequent()) { - case_stmt->Check(checker); - } - } - - checker->CheckForSameSwitchCases(&cases_); - - return nullptr; + return checker->GetAnalyzer()->Check(this); } void SwitchStatement::SetReturnType(checker::ETSChecker *checker, checker::Type *type) diff --git a/ets2panda/ir/statements/switchStatement.h b/ets2panda/ir/statements/switchStatement.h index 70a0fab746..015d12a91b 100644 --- a/ets2panda/ir/statements/switchStatement.h +++ b/ets2panda/ir/statements/switchStatement.h @@ -19,6 +19,11 @@ #include "varbinder/scope.h" #include "ir/statement.h" +namespace panda::es2panda::checker { +class TSAnalyzer; +class ETSAnalyzer; +} // namespace panda::es2panda::checker + namespace panda::es2panda::ir { class Expression; class SwitchCaseStatement; @@ -31,6 +36,10 @@ public: { } + // TODO (csabahurton): these friend relationships can be removed once there are getters for private fields + friend class checker::ETSAnalyzer; + friend class checker::TSAnalyzer; + const Expression *Discriminant() const { return discriminant_; @@ -56,10 +65,10 @@ 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 Compile([[maybe_unused]] compiler::ETSGen *etsg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: varbinder::LocalScope *scope_; diff --git a/ets2panda/ir/ts/tsEnumDeclaration.cpp b/ets2panda/ir/ts/tsEnumDeclaration.cpp index be7bca44b3..d1b0248875 100644 --- a/ets2panda/ir/ts/tsEnumDeclaration.cpp +++ b/ets2panda/ir/ts/tsEnumDeclaration.cpp @@ -57,91 +57,12 @@ void TSEnumDeclaration::Dump(ir::AstDumper *dumper) const {"const", is_const_}}); } -int32_t ToInt(double num) -{ - if (num >= std::numeric_limits::min() && num <= std::numeric_limits::max()) { - return static_cast(num); - } - - // NOTE: aszilagyi. Perform ECMA defined toInt conversion - - return 0; -} - -uint32_t ToUInt(double num) -{ - if (num >= std::numeric_limits::min() && num <= std::numeric_limits::max()) { - return static_cast(num); - } - - // NOTE: aszilagyi. Perform ECMA defined toInt conversion - - return 0; -} - -varbinder::EnumMemberResult EvaluateIdentifier(checker::TSChecker *checker, varbinder::EnumVariable *enum_var, - const ir::Identifier *expr) -{ - if (expr->Name() == "NaN") { - return std::nan(""); - } - if (expr->Name() == "Infinity") { - return std::numeric_limits::infinity(); - } - - varbinder::Variable *enum_member = expr->AsIdentifier()->Variable(); - - if (enum_member == nullptr) { - checker->ThrowTypeError({"Cannot find name ", expr->AsIdentifier()->Name()}, - enum_var->Declaration()->Node()->Start()); - } - - if (enum_member->IsEnumVariable()) { - varbinder::EnumVariable *expr_enum_var = enum_member->AsEnumVariable(); - if (std::holds_alternative(expr_enum_var->Value())) { - checker->ThrowTypeError( - "A member initializer in a enum declaration cannot reference members declared after it, " - "including " - "members defined in other enums.", - enum_var->Declaration()->Node()->Start()); - } - - return expr_enum_var->Value(); - } - - return false; -} - -varbinder::EnumMemberResult EvaluateUnaryExpression(checker::TSChecker *checker, varbinder::EnumVariable *enum_var, - const ir::UnaryExpression *expr) -{ - varbinder::EnumMemberResult value = TSEnumDeclaration::EvaluateEnumMember(checker, enum_var, expr->Argument()); - if (!std::holds_alternative(value)) { - return false; - } - - switch (expr->OperatorType()) { - case lexer::TokenType::PUNCTUATOR_PLUS: { - return std::get(value); - } - case lexer::TokenType::PUNCTUATOR_MINUS: { - return -std::get(value); - } - case lexer::TokenType::PUNCTUATOR_TILDE: { - return static_cast(~ToInt(std::get(value))); // NOLINT(hicpp-signed-bitwise) - } - default: { - break; - } - } - - return false; -} - +// NOTE (csabahurton): this method has not been moved to TSAnalyizer.cpp, because it is not used. varbinder::EnumMemberResult EvaluateMemberExpression(checker::TSChecker *checker, [[maybe_unused]] varbinder::EnumVariable *enum_var, ir::MemberExpression *expr) { + if (checker::TSChecker::IsConstantMemberAccess(expr->AsExpression())) { if (expr->Check(checker)->TypeFlags() == checker::TypeFlag::ENUM) { util::StringView name; @@ -159,216 +80,6 @@ varbinder::EnumMemberResult EvaluateMemberExpression(checker::TSChecker *checker return false; } -varbinder::EnumMemberResult EvaluateBinaryExpression(checker::TSChecker *checker, varbinder::EnumVariable *enum_var, - const ir::BinaryExpression *expr) -{ - varbinder::EnumMemberResult left = - TSEnumDeclaration::EvaluateEnumMember(checker, enum_var, expr->AsBinaryExpression()->Left()); - varbinder::EnumMemberResult right = - TSEnumDeclaration::EvaluateEnumMember(checker, enum_var, expr->AsBinaryExpression()->Right()); - if (std::holds_alternative(left) && std::holds_alternative(right)) { - switch (expr->AsBinaryExpression()->OperatorType()) { - case lexer::TokenType::PUNCTUATOR_BITWISE_OR: { - return static_cast(ToUInt(std::get(left)) | ToUInt(std::get(right))); - } - case lexer::TokenType::PUNCTUATOR_BITWISE_AND: { - return static_cast(ToUInt(std::get(left)) & ToUInt(std::get(right))); - } - case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: { - return static_cast(ToUInt(std::get(left)) ^ ToUInt(std::get(right))); - } - case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: { // NOLINTNEXTLINE(hicpp-signed-bitwise) - return static_cast(ToInt(std::get(left)) << ToUInt(std::get(right))); - } - case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: { // NOLINTNEXTLINE(hicpp-signed-bitwise) - return static_cast(ToInt(std::get(left)) >> ToUInt(std::get(right))); - } - case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: { - return static_cast(ToUInt(std::get(left)) >> ToUInt(std::get(right))); - } - case lexer::TokenType::PUNCTUATOR_PLUS: { - return std::get(left) + std::get(right); - } - case lexer::TokenType::PUNCTUATOR_MINUS: { - return std::get(left) - std::get(right); - } - case lexer::TokenType::PUNCTUATOR_MULTIPLY: { - return std::get(left) * std::get(right); - } - case lexer::TokenType::PUNCTUATOR_DIVIDE: { - return std::get(left) / std::get(right); - } - case lexer::TokenType::PUNCTUATOR_MOD: { - return std::fmod(std::get(left), std::get(right)); - } - case lexer::TokenType::PUNCTUATOR_EXPONENTIATION: { - return std::pow(std::get(left), std::get(right)); - } - default: { - break; - } - } - - return false; - } - - if (std::holds_alternative(left) && std::holds_alternative(right) && - expr->AsBinaryExpression()->OperatorType() == lexer::TokenType::PUNCTUATOR_PLUS) { - std::stringstream ss; - ss << std::get(left) << std::get(right); - - util::UString res(ss.str(), checker->Allocator()); - return res.View(); - } - - return false; -} - -varbinder::EnumMemberResult TSEnumDeclaration::EvaluateEnumMember(checker::TSChecker *checker, - varbinder::EnumVariable *enum_var, - const ir::AstNode *expr) -{ - switch (expr->Type()) { - case ir::AstNodeType::UNARY_EXPRESSION: { - return EvaluateUnaryExpression(checker, enum_var, expr->AsUnaryExpression()); - } - case ir::AstNodeType::BINARY_EXPRESSION: { - return EvaluateBinaryExpression(checker, enum_var, expr->AsBinaryExpression()); - } - case ir::AstNodeType::NUMBER_LITERAL: { - return expr->AsNumberLiteral()->Number().GetDouble(); - } - case ir::AstNodeType::STRING_LITERAL: { - return expr->AsStringLiteral()->Str(); - } - case ir::AstNodeType::IDENTIFIER: { - return EvaluateIdentifier(checker, enum_var, expr->AsIdentifier()); - } - case ir::AstNodeType::MEMBER_EXPRESSION: { - return EvaluateEnumMember(checker, enum_var, expr->AsMemberExpression()); - } - default: - break; - } - - return false; -} - -bool IsComputedEnumMember(const ir::Expression *init) -{ - if (init->IsLiteral()) { - return !init->AsLiteral()->IsStringLiteral() && !init->AsLiteral()->IsNumberLiteral(); - } - - if (init->IsTemplateLiteral()) { - return !init->AsTemplateLiteral()->Quasis().empty(); - } - - return true; -} - -void AddEnumValueDeclaration(checker::TSChecker *checker, double number, varbinder::EnumVariable *variable) -{ - variable->SetTsType(checker->GlobalNumberType()); - - util::StringView member_str = util::Helpers::ToStringView(checker->Allocator(), number); - - varbinder::LocalScope *enum_scope = checker->Scope()->AsLocalScope(); - varbinder::Variable *res = enum_scope->FindLocal(member_str, varbinder::ResolveBindingOptions::BINDINGS); - varbinder::EnumVariable *enum_var = nullptr; - - if (res == nullptr) { - auto *decl = checker->Allocator()->New(member_str); - decl->BindNode(variable->Declaration()->Node()); - enum_scope->AddDecl(checker->Allocator(), decl, ScriptExtension::TS); - res = enum_scope->FindLocal(member_str, varbinder::ResolveBindingOptions::BINDINGS); - ASSERT(res && res->IsEnumVariable()); - enum_var = res->AsEnumVariable(); - enum_var->AsEnumVariable()->SetBackReference(); - enum_var->SetTsType(checker->GlobalStringType()); - } else { - ASSERT(res->IsEnumVariable()); - enum_var = res->AsEnumVariable(); - auto *decl = checker->Allocator()->New(member_str); - decl->BindNode(variable->Declaration()->Node()); - enum_var->ResetDecl(decl); - } - - enum_var->SetValue(variable->Declaration()->Name()); -} - -void InferEnumVariableType(checker::TSChecker *checker, varbinder::EnumVariable *variable, double *value, - bool *init_next, bool *is_literal_enum, bool is_const_enum, - const ir::Expression *computed_expr) -{ - const ir::Expression *init = variable->Declaration()->Node()->AsTSEnumMember()->Init(); - - if (init == nullptr && *init_next) { - checker->ThrowTypeError("Enum member must have initializer.", variable->Declaration()->Node()->Start()); - } - - if (init == nullptr && !*init_next) { - variable->SetValue(++(*value)); - AddEnumValueDeclaration(checker, *value, variable); - return; - } - - ASSERT(init); - - if (IsComputedEnumMember(init)) { - if (*is_literal_enum) { - checker->ThrowTypeError("Computed values are not permitted in an enum with string valued members.", - init->Start()); - } - - computed_expr = init; - } - - varbinder::EnumMemberResult res = TSEnumDeclaration::EvaluateEnumMember(checker, variable, init); - if (std::holds_alternative(res)) { - if (computed_expr != nullptr) { - checker->ThrowTypeError("Computed values are not permitted in an enum with string valued members.", - computed_expr->Start()); - } - - *is_literal_enum = true; - variable->SetTsType(checker->GlobalStringType()); - *init_next = true; - return; - } - - if (std::holds_alternative(res)) { - if (is_const_enum) { - checker->ThrowTypeError( - "const enum member initializers can only contain literal values and other computed enum " - "values.", - init->Start()); - } - - *init_next = true; - return; - } - - ASSERT(std::holds_alternative(res)); - variable->SetValue(res); - - *value = std::get(res); - if (is_const_enum) { - if (std::isnan(*value)) { - checker->ThrowTypeError("'const' enum member initializer was evaluated to disallowed value 'NaN'.", - init->Start()); - } - - if (std::isinf(*value)) { - checker->ThrowTypeError("'const' enum member initializer was evaluated to a non-finite value.", - init->Start()); - } - } - - *init_next = false; - AddEnumValueDeclaration(checker, *value, variable); -} - void TSEnumDeclaration::Compile(compiler::PandaGen *pg) const { pg->GetAstCompiler()->Compile(this); } -- Gitee From 37ac28de088d711f54d99016e175c836fa406363 Mon Sep 17 00:00:00 2001 From: Csaba Hurton Date: Thu, 26 Oct 2023 11:44:01 +0200 Subject: [PATCH 3/6] (8) Move Compile and Check Logic from ASTNode classes Compile logic is moved to JSCompiler and ETSCompiler classes. Check logic with their helper functions is moved to TSAnalyzer and ETSAnalyzer classes. AstNodes that are being moved: - nodes inside ir/module: - ImportDeclaration - ImportDefaultSpecifier - ImportNamespaceSpecifier - ImportNamespaceSpecifier - nodes inside ir/statements: - ClassDeclaration - ContinueStatement - DebuggerStatement - DoWhileStatement Linked Internal Issue 13840 Change-Id: I343bc42db9d7b04be52db1dfd5a61fababdc4ffa Signed-off-by: Csaba Hurton --- ets2panda/checker/ETSAnalyzer.cpp | 109 +++++++++++++++--- ets2panda/checker/TSAnalyzer.cpp | 28 ++--- ets2panda/compiler/core/ETSCompiler.cpp | 55 ++++++--- ets2panda/compiler/core/JSCompiler.cpp | 57 +++++---- ets2panda/ir/module/importDeclaration.cpp | 30 ++--- ets2panda/ir/module/importDeclaration.h | 8 +- .../ir/module/importDefaultSpecifier.cpp | 26 +++-- ets2panda/ir/module/importDefaultSpecifier.h | 7 +- .../ir/module/importNamespaceSpecifier.cpp | 90 +++------------ .../ir/module/importNamespaceSpecifier.h | 7 +- ets2panda/ir/module/importSpecifier.cpp | 23 ++-- ets2panda/ir/module/importSpecifier.h | 8 +- ets2panda/ir/statements/classDeclaration.cpp | 25 ++-- ets2panda/ir/statements/classDeclaration.h | 8 +- ets2panda/ir/statements/continueStatement.cpp | 30 ++--- ets2panda/ir/statements/continueStatement.h | 20 +++- ets2panda/ir/statements/debuggerStatement.cpp | 22 +++- ets2panda/ir/statements/debuggerStatement.h | 7 +- ets2panda/ir/statements/doWhileStatement.cpp | 50 ++------ ets2panda/ir/statements/doWhileStatement.h | 8 +- 20 files changed, 324 insertions(+), 294 deletions(-) diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index ef4fd5a722..5aee8f8366 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -575,25 +575,96 @@ checker::Type *ETSAnalyzer::Check(ir::ExportSpecifier *st) const checker::Type *ETSAnalyzer::Check(ir::ImportDeclaration *st) const { - (void)st; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + checker::Type *type = nullptr; + for (auto *spec : st->Specifiers()) { + if (spec->IsImportNamespaceSpecifier()) { + type = spec->AsImportNamespaceSpecifier()->Check(checker); + } + } + + return type; } -checker::Type *ETSAnalyzer::Check(ir::ImportDefaultSpecifier *st) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ImportDefaultSpecifier *st) const { - (void)st; UNREACHABLE(); } checker::Type *ETSAnalyzer::Check(ir::ImportNamespaceSpecifier *st) const { - (void)st; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + if (st->Local()->Name().Empty()) { + return nullptr; + } + + if (st->Local()->AsIdentifier()->TsType() != nullptr) { + return st->Local()->TsType(); + } + + auto *import_decl = st->Parent()->AsETSImportDeclaration(); + auto import_path = import_decl->Source()->Str(); + + if (import_decl->IsPureDynamic()) { + auto *type = checker->GlobalBuiltinDynamicType(import_decl->Language()); + checker->SetrModuleObjectTsType(st->Local(), type); + return type; + } + + std::string package_name = + (import_decl->Module() == nullptr) ? import_path.Mutf8() : import_decl->Module()->Str().Mutf8(); + + std::replace(package_name.begin(), package_name.end(), '/', '.'); + util::UString package_path(package_name, checker->Allocator()); + std::vector synthetic_names = checker->GetNameForSynteticObjectType(package_path.View()); + + ASSERT(!synthetic_names.empty()); + + auto assembler_name = synthetic_names[0]; + if (import_decl->Module() != nullptr) { + assembler_name = util::UString(assembler_name.Mutf8().append(".").append(compiler::Signatures::ETS_GLOBAL), + checker->Allocator()) + .View(); + } + + auto *module_object_type = + checker->Allocator()->New(checker->Allocator(), synthetic_names[0], assembler_name, + st->Local()->AsIdentifier(), checker::ETSObjectFlags::CLASS); + + auto *root_decl = checker->Allocator()->New(synthetic_names[0]); + varbinder::LocalVariable *root_var = + checker->Allocator()->New(root_decl, varbinder::VariableFlags::NONE); + root_var->SetTsType(module_object_type); + + synthetic_names.erase(synthetic_names.begin()); + checker::ETSObjectType *last_object_type(module_object_type); + + for (const auto &synthetic_name : synthetic_names) { + auto *synthetic_obj_type = checker->Allocator()->New( + checker->Allocator(), synthetic_name, synthetic_name, st->Local()->AsIdentifier(), + checker::ETSObjectFlags::NO_OPTS); + + auto *class_decl = checker->Allocator()->New(synthetic_name); + varbinder::LocalVariable *var = + checker->Allocator()->New(class_decl, varbinder::VariableFlags::CLASS); + var->SetTsType(synthetic_obj_type); + last_object_type->AddProperty(var); + synthetic_obj_type->SetEnclosingType(last_object_type); + last_object_type = synthetic_obj_type; + } + + checker->SetPropertiesForModuleObject( + last_object_type, + (import_decl->Module() != nullptr) + ? util::UString(import_path.Mutf8() + import_decl->Module()->Str().Mutf8(), checker->Allocator()).View() + : import_path); + checker->SetrModuleObjectTsType(st->Local(), last_object_type); + + return module_object_type; } -checker::Type *ETSAnalyzer::Check(ir::ImportSpecifier *st) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ImportSpecifier *st) const { - (void)st; UNREACHABLE(); } // compile methods for STATEMENTS in alphabetical order @@ -617,26 +688,32 @@ checker::Type *ETSAnalyzer::Check(ir::BreakStatement *st) const checker::Type *ETSAnalyzer::Check(ir::ClassDeclaration *st) const { - (void)st; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + st->Definition()->Check(checker); + return nullptr; } checker::Type *ETSAnalyzer::Check(ir::ContinueStatement *st) const { - (void)st; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + st->target_ = checker->FindJumpTarget(st->Type(), st, st->Ident()); + return nullptr; } -checker::Type *ETSAnalyzer::Check(ir::DebuggerStatement *st) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::DebuggerStatement *st) const { - (void)st; UNREACHABLE(); } checker::Type *ETSAnalyzer::Check(ir::DoWhileStatement *st) const { - (void)st; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + checker::ScopeContext scope_ctx(checker, st->Scope()); + + checker->CheckTruthinessOfType(st->Test()); + st->Body()->Check(checker); + + return nullptr; } checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::EmptyStatement *st) const diff --git a/ets2panda/checker/TSAnalyzer.cpp b/ets2panda/checker/TSAnalyzer.cpp index 0662819e40..cd0b565532 100644 --- a/ets2panda/checker/TSAnalyzer.cpp +++ b/ets2panda/checker/TSAnalyzer.cpp @@ -478,27 +478,23 @@ checker::Type *TSAnalyzer::Check(ir::ExportSpecifier *st) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::ImportDeclaration *st) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ImportDeclaration *st) const { - (void)st; UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::ImportDefaultSpecifier *st) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ImportDefaultSpecifier *st) const { - (void)st; UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::ImportNamespaceSpecifier *st) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ImportNamespaceSpecifier *st) const { - (void)st; UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::ImportSpecifier *st) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ImportSpecifier *st) const { - (void)st; UNREACHABLE(); } // compile methods for STATEMENTS in alphabetical order @@ -520,9 +516,8 @@ checker::Type *TSAnalyzer::Check(ir::BreakStatement *st) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::ClassDeclaration *st) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ClassDeclaration *st) const { - (void)st; UNREACHABLE(); } @@ -532,16 +527,21 @@ checker::Type *TSAnalyzer::Check(ir::ContinueStatement *st) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::DebuggerStatement *st) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::DebuggerStatement *st) const { - (void)st; UNREACHABLE(); } checker::Type *TSAnalyzer::Check(ir::DoWhileStatement *st) const { - (void)st; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + checker::ScopeContext scope_ctx(checker, st->Scope()); + + checker::Type *test_type = st->Test()->Check(checker); + checker->CheckTruthinessOfType(test_type, st->Test()->Start()); + st->Body()->Check(checker); + + return nullptr; } checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::EmptyStatement *st) const diff --git a/ets2panda/compiler/core/ETSCompiler.cpp b/ets2panda/compiler/core/ETSCompiler.cpp index a3cb169f36..c890722e38 100644 --- a/ets2panda/compiler/core/ETSCompiler.cpp +++ b/ets2panda/compiler/core/ETSCompiler.cpp @@ -480,27 +480,23 @@ void ETSCompiler::Compile(const ir::ExportSpecifier *st) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::ImportDeclaration *st) const +void ETSCompiler::Compile([[maybe_unused]] const ir::ImportDeclaration *st) const { - (void)st; UNREACHABLE(); } -void ETSCompiler::Compile(const ir::ImportDefaultSpecifier *st) const +void ETSCompiler::Compile([[maybe_unused]] const ir::ImportDefaultSpecifier *st) const { - (void)st; UNREACHABLE(); } -void ETSCompiler::Compile(const ir::ImportNamespaceSpecifier *st) const +void ETSCompiler::Compile([[maybe_unused]] const ir::ImportNamespaceSpecifier *st) const { - (void)st; UNREACHABLE(); } -void ETSCompiler::Compile(const ir::ImportSpecifier *st) const +void ETSCompiler::Compile([[maybe_unused]] const ir::ImportSpecifier *st) const { - (void)st; UNREACHABLE(); } // compile methods for STATEMENTS in alphabetical order @@ -522,28 +518,55 @@ void ETSCompiler::Compile(const ir::BreakStatement *st) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::ClassDeclaration *st) const +void ETSCompiler::Compile([[maybe_unused]] const ir::ClassDeclaration *st) const { - (void)st; UNREACHABLE(); } +static void CompileImpl(const ir::ContinueStatement *self, ETSGen *etsg) +{ + compiler::Label *target = etsg->ControlFlowChangeContinue(self->Ident()); + etsg->Branch(self, target); +} + void ETSCompiler::Compile(const ir::ContinueStatement *st) const { - (void)st; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + if (etsg->ExtendWithFinalizer(st->parent_, st)) { + return; + } + CompileImpl(st, etsg); } -void ETSCompiler::Compile(const ir::DebuggerStatement *st) const +void ETSCompiler::Compile([[maybe_unused]] const ir::DebuggerStatement *st) const { - (void)st; UNREACHABLE(); } +void CompileImpl(const ir::DoWhileStatement *self, ETSGen *etsg) +{ + auto *start_label = etsg->AllocLabel(); + compiler::LabelTarget label_target(etsg); + + etsg->SetLabel(self, start_label); + + { + compiler::LocalRegScope reg_scope(etsg, self->Scope()); + compiler::LabelContext label_ctx(etsg, label_target); + self->Body()->Compile(etsg); + } + + etsg->SetLabel(self, label_target.ContinueTarget()); + compiler::Condition::Compile(etsg, self->Test(), label_target.BreakTarget()); + + etsg->Branch(self, start_label); + etsg->SetLabel(self, label_target.BreakTarget()); +} + void ETSCompiler::Compile(const ir::DoWhileStatement *st) const { - (void)st; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + CompileImpl(st, etsg); } void ETSCompiler::Compile([[maybe_unused]] const ir::EmptyStatement *st) const {} diff --git a/ets2panda/compiler/core/JSCompiler.cpp b/ets2panda/compiler/core/JSCompiler.cpp index 2921b4384f..83c36cae08 100644 --- a/ets2panda/compiler/core/JSCompiler.cpp +++ b/ets2panda/compiler/core/JSCompiler.cpp @@ -782,27 +782,20 @@ void JSCompiler::Compile(const ir::ExportSpecifier *st) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::ImportDeclaration *st) const -{ - (void)st; - UNREACHABLE(); -} +void JSCompiler::Compile([[maybe_unused]] const ir::ImportDeclaration *st) const {} -void JSCompiler::Compile(const ir::ImportDefaultSpecifier *st) const +void JSCompiler::Compile([[maybe_unused]] const ir::ImportDefaultSpecifier *st) const { - (void)st; UNREACHABLE(); } -void JSCompiler::Compile(const ir::ImportNamespaceSpecifier *st) const +void JSCompiler::Compile([[maybe_unused]] const ir::ImportNamespaceSpecifier *st) const { - (void)st; UNREACHABLE(); } -void JSCompiler::Compile(const ir::ImportSpecifier *st) const +void JSCompiler::Compile([[maybe_unused]] const ir::ImportSpecifier *st) const { - (void)st; UNREACHABLE(); } // Compile methods for STATEMENTS in alphabetical order @@ -826,26 +819,50 @@ void JSCompiler::Compile(const ir::BreakStatement *st) const void JSCompiler::Compile(const ir::ClassDeclaration *st) const { - (void)st; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + auto lref = compiler::JSLReference::Create(pg, st->Definition()->Ident(), true); + st->Definition()->Compile(pg); + lref.SetValue(); +} + +static void CompileImpl(const ir::ContinueStatement *self, PandaGen *cg) +{ + compiler::Label *target = cg->ControlFlowChangeContinue(self->Ident()); + cg->Branch(self, target); } void JSCompiler::Compile(const ir::ContinueStatement *st) const { - (void)st; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + CompileImpl(st, pg); } -void JSCompiler::Compile(const ir::DebuggerStatement *st) const +void JSCompiler::Compile([[maybe_unused]] const ir::DebuggerStatement *st) const {} + +static void CompileImpl(const ir::DoWhileStatement *self, PandaGen *cg) { - (void)st; - UNREACHABLE(); + auto *start_label = cg->AllocLabel(); + compiler::LabelTarget label_target(cg); + + cg->SetLabel(self, start_label); + + { + compiler::LocalRegScope reg_scope(cg, self->Scope()); + compiler::LabelContext label_ctx(cg, label_target); + self->Body()->Compile(cg); + } + + cg->SetLabel(self, label_target.ContinueTarget()); + compiler::Condition::Compile(cg, self->Test(), label_target.BreakTarget()); + + cg->Branch(self, start_label); + cg->SetLabel(self, label_target.BreakTarget()); } void JSCompiler::Compile(const ir::DoWhileStatement *st) const { - (void)st; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + CompileImpl(st, pg); } void JSCompiler::Compile([[maybe_unused]] const ir::EmptyStatement *st) const {} diff --git a/ets2panda/ir/module/importDeclaration.cpp b/ets2panda/ir/module/importDeclaration.cpp index b946fbd1b6..e1208b0d02 100644 --- a/ets2panda/ir/module/importDeclaration.cpp +++ b/ets2panda/ir/module/importDeclaration.cpp @@ -15,11 +15,9 @@ #include "importDeclaration.h" +#include "checker/TSchecker.h" #include "compiler/core/ETSGen.h" -#include "ir/astDump.h" -#include "ir/expressions/literals/stringLiteral.h" -#include "ir/module/importNamespaceSpecifier.h" -#include "ir/module/importSpecifier.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void ImportDeclaration::TransformChildren(const NodeTransformer &cb) @@ -45,27 +43,23 @@ void ImportDeclaration::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "ImportDeclaration"}, {"source", source_}, {"specifiers", specifiers_}}); } -void ImportDeclaration::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} - -void ImportDeclaration::Compile([[maybe_unused]] compiler::ETSGen *etsg) const +void ImportDeclaration::Compile(compiler::PandaGen *pg) const { - UNREACHABLE(); + pg->GetAstCompiler()->Compile(this); } -checker::Type *ImportDeclaration::Check([[maybe_unused]] checker::TSChecker *checker) +void ImportDeclaration::Compile(compiler::ETSGen *etsg) const { - return nullptr; + etsg->GetAstCompiler()->Compile(this); } -checker::Type *ImportDeclaration::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *ImportDeclaration::Check(checker::TSChecker *checker) { - checker::Type *type = nullptr; - for (auto *spec : specifiers_) { - if (spec->IsImportNamespaceSpecifier()) { - type = spec->AsImportNamespaceSpecifier()->Check(checker); - } - } + return checker->GetAnalyzer()->Check(this); +} - return type; +checker::Type *ImportDeclaration::Check(checker::ETSChecker *checker) +{ + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/module/importDeclaration.h b/ets2panda/ir/module/importDeclaration.h index 18594b35e3..fc8e923882 100644 --- a/ets2panda/ir/module/importDeclaration.h +++ b/ets2panda/ir/module/importDeclaration.h @@ -47,10 +47,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - void Compile([[maybe_unused]] compiler::ETSGen *etsg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: StringLiteral *source_; diff --git a/ets2panda/ir/module/importDefaultSpecifier.cpp b/ets2panda/ir/module/importDefaultSpecifier.cpp index 2413efb897..ea4a43b93e 100644 --- a/ets2panda/ir/module/importDefaultSpecifier.cpp +++ b/ets2panda/ir/module/importDefaultSpecifier.cpp @@ -15,11 +15,9 @@ #include "importDefaultSpecifier.h" -#include "checker/ETSchecker.h" -#include "ir/astDump.h" -#include "ir/expressions/identifier.h" -#include "ir/module/importDeclaration.h" -#include "ir/expressions/literals/stringLiteral.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void ImportDefaultSpecifier::TransformChildren(const NodeTransformer &cb) @@ -37,15 +35,23 @@ void ImportDefaultSpecifier::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "ImportDefaultSpecifier"}, {"local", local_}}); } -void ImportDefaultSpecifier::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void ImportDefaultSpecifier::Compile(compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} + +void ImportDefaultSpecifier::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} -checker::Type *ImportDefaultSpecifier::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *ImportDefaultSpecifier::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } -checker::Type *ImportDefaultSpecifier::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *ImportDefaultSpecifier::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/module/importDefaultSpecifier.h b/ets2panda/ir/module/importDefaultSpecifier.h index 7d39425a08..0ad7350846 100644 --- a/ets2panda/ir/module/importDefaultSpecifier.h +++ b/ets2panda/ir/module/importDefaultSpecifier.h @@ -35,9 +35,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: Identifier *local_; diff --git a/ets2panda/ir/module/importNamespaceSpecifier.cpp b/ets2panda/ir/module/importNamespaceSpecifier.cpp index 9607da9ba6..44660316c6 100644 --- a/ets2panda/ir/module/importNamespaceSpecifier.cpp +++ b/ets2panda/ir/module/importNamespaceSpecifier.cpp @@ -15,12 +15,10 @@ #include "importNamespaceSpecifier.h" -#include "checker/ETSchecker.h" #include "varbinder/ETSBinder.h" -#include "ir/astDump.h" -#include "ir/expressions/identifier.h" -#include "ir/module/importDeclaration.h" -#include "ir/expressions/literals/stringLiteral.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void ImportNamespaceSpecifier::TransformChildren(const NodeTransformer &cb) @@ -38,81 +36,23 @@ void ImportNamespaceSpecifier::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "ImportNamespaceSpecifier"}, {"local", local_}}); } -void ImportNamespaceSpecifier::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} - -checker::Type *ImportNamespaceSpecifier::Check([[maybe_unused]] checker::TSChecker *checker) +void ImportNamespaceSpecifier::Compile(compiler::PandaGen *pg) const { - return nullptr; + pg->GetAstCompiler()->Compile(this); } -checker::Type *ImportNamespaceSpecifier::Check([[maybe_unused]] checker::ETSChecker *checker) +void ImportNamespaceSpecifier::Compile(compiler::ETSGen *etsg) const { - if (Local()->Name().Empty()) { - return nullptr; - } - - if (Local()->AsIdentifier()->TsType() != nullptr) { - return local_->TsType(); - } - - auto *import_decl = Parent()->AsETSImportDeclaration(); - auto import_path = import_decl->Source()->Str(); - - if (import_decl->IsPureDynamic()) { - auto *type = checker->GlobalBuiltinDynamicType(import_decl->Language()); - checker->SetrModuleObjectTsType(local_, type); - return type; - } - - std::string package_name = - (import_decl->Module() == nullptr) ? import_path.Mutf8() : import_decl->Module()->Str().Mutf8(); - - std::replace(package_name.begin(), package_name.end(), '/', '.'); - util::UString package_path(package_name, checker->Allocator()); - std::vector synthetic_names = checker->GetNameForSynteticObjectType(package_path.View()); - - ASSERT(!synthetic_names.empty()); - - auto assembler_name = synthetic_names[0]; - if (import_decl->Module() != nullptr) { - assembler_name = util::UString(assembler_name.Mutf8().append(".").append(compiler::Signatures::ETS_GLOBAL), - checker->Allocator()) - .View(); - } - - auto *module_object_type = - checker->Allocator()->New(checker->Allocator(), synthetic_names[0], assembler_name, - local_->AsIdentifier(), checker::ETSObjectFlags::CLASS); - - auto *root_decl = checker->Allocator()->New(synthetic_names[0]); - varbinder::LocalVariable *root_var = - checker->Allocator()->New(root_decl, varbinder::VariableFlags::NONE); - root_var->SetTsType(module_object_type); - - synthetic_names.erase(synthetic_names.begin()); - checker::ETSObjectType *last_object_type(module_object_type); - - for (const auto &synthetic_name : synthetic_names) { - auto *synthetic_obj_type = - checker->Allocator()->New(checker->Allocator(), synthetic_name, synthetic_name, - local_->AsIdentifier(), checker::ETSObjectFlags::NO_OPTS); - - auto *class_decl = checker->Allocator()->New(synthetic_name); - varbinder::LocalVariable *var = - checker->Allocator()->New(class_decl, varbinder::VariableFlags::CLASS); - var->SetTsType(synthetic_obj_type); - last_object_type->AddProperty(var); - synthetic_obj_type->SetEnclosingType(last_object_type); - last_object_type = synthetic_obj_type; - } + etsg->GetAstCompiler()->Compile(this); +} - checker->SetPropertiesForModuleObject( - last_object_type, - (import_decl->Module() != nullptr) - ? util::UString(import_path.Mutf8() + import_decl->Module()->Str().Mutf8(), checker->Allocator()).View() - : import_path); - checker->SetrModuleObjectTsType(local_, last_object_type); +checker::Type *ImportNamespaceSpecifier::Check(checker::TSChecker *checker) +{ + return checker->GetAnalyzer()->Check(this); +} - return module_object_type; +checker::Type *ImportNamespaceSpecifier::Check(checker::ETSChecker *checker) +{ + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/module/importNamespaceSpecifier.h b/ets2panda/ir/module/importNamespaceSpecifier.h index 0af20262ba..e725cce1ae 100644 --- a/ets2panda/ir/module/importNamespaceSpecifier.h +++ b/ets2panda/ir/module/importNamespaceSpecifier.h @@ -41,9 +41,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: Identifier *local_; diff --git a/ets2panda/ir/module/importSpecifier.cpp b/ets2panda/ir/module/importSpecifier.cpp index 343614347e..984e4137d5 100644 --- a/ets2panda/ir/module/importSpecifier.cpp +++ b/ets2panda/ir/module/importSpecifier.cpp @@ -15,11 +15,9 @@ #include "importSpecifier.h" +#include "checker/TSchecker.h" #include "compiler/core/ETSGen.h" -#include "ir/astDump.h" -#include "ir/expressions/identifier.h" -#include "ir/expressions/literals/stringLiteral.h" -#include "ir/module/importDeclaration.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void ImportSpecifier::TransformChildren(const NodeTransformer &cb) @@ -43,19 +41,22 @@ void ImportSpecifier::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "ImportSpecifier"}, {"local", ir::AstDumper::Optional(local_)}, {"imported", imported_}}); } -void ImportSpecifier::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} -void ImportSpecifier::Compile([[maybe_unused]] compiler::ETSGen *etsg) const +void ImportSpecifier::Compile(compiler::PandaGen *pg) const { - UNREACHABLE(); + pg->GetAstCompiler()->Compile(this); +} +void ImportSpecifier::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); } -checker::Type *ImportSpecifier::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *ImportSpecifier::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } -checker::Type *ImportSpecifier::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *ImportSpecifier::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/module/importSpecifier.h b/ets2panda/ir/module/importSpecifier.h index 9a0c1311ab..c59fba3bed 100644 --- a/ets2panda/ir/module/importSpecifier.h +++ b/ets2panda/ir/module/importSpecifier.h @@ -51,10 +51,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - void Compile([[maybe_unused]] compiler::ETSGen *etsg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: Identifier *imported_; diff --git a/ets2panda/ir/statements/classDeclaration.cpp b/ets2panda/ir/statements/classDeclaration.cpp index 6c0822d5f2..627e9bece0 100644 --- a/ets2panda/ir/statements/classDeclaration.cpp +++ b/ets2panda/ir/statements/classDeclaration.cpp @@ -15,13 +15,9 @@ #include "classDeclaration.h" -#include "compiler/base/lreference.h" -#include "compiler/core/pandagen.h" +#include "checker/TSchecker.h" #include "compiler/core/ETSGen.h" -#include "ir/astDump.h" -#include "ir/base/classDefinition.h" -#include "ir/base/decorator.h" -#include "ir/expressions/identifier.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void ClassDeclaration::TransformChildren(const NodeTransformer &cb) @@ -47,26 +43,23 @@ void ClassDeclaration::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "ClassDeclaration"}, {"definition", def_}, {"decorators", AstDumper::Optional(decorators_)}}); } -void ClassDeclaration::Compile([[maybe_unused]] compiler::PandaGen *pg) const +void ClassDeclaration::Compile(compiler::PandaGen *pg) const { - auto lref = compiler::JSLReference::Create(pg, def_->Ident(), true); - def_->Compile(pg); - lref.SetValue(); + pg->GetAstCompiler()->Compile(this); } -void ClassDeclaration::Compile([[maybe_unused]] compiler::ETSGen *etsg) const +void ClassDeclaration::Compile(compiler::ETSGen *etsg) const { - UNREACHABLE(); + etsg->GetAstCompiler()->Compile(this); } -checker::Type *ClassDeclaration::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *ClassDeclaration::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *ClassDeclaration::Check(checker::ETSChecker *checker) { - def_->Check(checker); - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/statements/classDeclaration.h b/ets2panda/ir/statements/classDeclaration.h index c2e535c074..8984cf0651 100644 --- a/ets2panda/ir/statements/classDeclaration.h +++ b/ets2panda/ir/statements/classDeclaration.h @@ -54,11 +54,11 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - void Compile([[maybe_unused]] compiler::ETSGen *etsg) const override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: ClassDefinition *def_; diff --git a/ets2panda/ir/statements/continueStatement.cpp b/ets2panda/ir/statements/continueStatement.cpp index 74536dc361..da58f870ae 100644 --- a/ets2panda/ir/statements/continueStatement.cpp +++ b/ets2panda/ir/statements/continueStatement.cpp @@ -15,10 +15,9 @@ #include "continueStatement.h" -#include "compiler/core/pandagen.h" +#include "checker/TSchecker.h" #include "compiler/core/ETSGen.h" -#include "ir/astDump.h" -#include "checker/ETSchecker.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void ContinueStatement::TransformChildren(const NodeTransformer &cb) @@ -40,34 +39,23 @@ void ContinueStatement::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "ContinueStatement"}, {"label", AstDumper::Nullish(ident_)}}); } -template -void CompileImpl(const ContinueStatement *self, [[maybe_unused]] CodeGen *cg) -{ - compiler::Label *target = cg->ControlFlowChangeContinue(self->Ident()); - cg->Branch(self, target); -} - -void ContinueStatement::Compile([[maybe_unused]] compiler::PandaGen *pg) const +void ContinueStatement::Compile(compiler::PandaGen *pg) const { - CompileImpl(this, pg); + pg->GetAstCompiler()->Compile(this); } -void ContinueStatement::Compile([[maybe_unused]] compiler::ETSGen *etsg) const +void ContinueStatement::Compile(compiler::ETSGen *etsg) const { - if (etsg->ExtendWithFinalizer(parent_, this)) { - return; - } - CompileImpl(this, etsg); + etsg->GetAstCompiler()->Compile(this); } -checker::Type *ContinueStatement::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *ContinueStatement::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *ContinueStatement::Check(checker::ETSChecker *checker) { - target_ = checker->FindJumpTarget(Type(), this, ident_); - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/statements/continueStatement.h b/ets2panda/ir/statements/continueStatement.h index 2eead3db01..804670d2a6 100644 --- a/ets2panda/ir/statements/continueStatement.h +++ b/ets2panda/ir/statements/continueStatement.h @@ -19,12 +19,24 @@ #include "ir/statement.h" #include "ir/expressions/identifier.h" +namespace panda::es2panda::checker { +class ETSAnalyzer; +} // namespace panda::es2panda::checker + +namespace panda::es2panda::compiler { +class ETSCompiler; +} // namespace panda::es2panda::compiler + namespace panda::es2panda::ir { class ContinueStatement : public Statement { public: explicit ContinueStatement() : Statement(AstNodeType::CONTINUE_STATEMENT) {} explicit ContinueStatement(Identifier *ident) : Statement(AstNodeType::CONTINUE_STATEMENT), ident_(ident) {} + // TODO (csabahurton): these friend relationships can be removed once there are getters for private fields + friend class checker::ETSAnalyzer; + friend class compiler::ETSCompiler; + const Identifier *Ident() const { return ident_; @@ -38,10 +50,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - void Compile([[maybe_unused]] compiler::ETSGen *etsg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: Identifier *ident_ {}; diff --git a/ets2panda/ir/statements/debuggerStatement.cpp b/ets2panda/ir/statements/debuggerStatement.cpp index 506daf50ae..b0bb23faad 100644 --- a/ets2panda/ir/statements/debuggerStatement.cpp +++ b/ets2panda/ir/statements/debuggerStatement.cpp @@ -15,7 +15,9 @@ #include "debuggerStatement.h" -#include "ir/astDump.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void DebuggerStatement::TransformChildren([[maybe_unused]] const NodeTransformer &cb) {} @@ -26,15 +28,23 @@ void DebuggerStatement::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "DebuggerStatement"}}); } -void DebuggerStatement::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void DebuggerStatement::Compile(compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} + +void DebuggerStatement::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} -checker::Type *DebuggerStatement::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *DebuggerStatement::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } -checker::Type *DebuggerStatement::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *DebuggerStatement::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/statements/debuggerStatement.h b/ets2panda/ir/statements/debuggerStatement.h index d9858dbfd4..792af73b96 100644 --- a/ets2panda/ir/statements/debuggerStatement.h +++ b/ets2panda/ir/statements/debuggerStatement.h @@ -26,9 +26,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: }; diff --git a/ets2panda/ir/statements/doWhileStatement.cpp b/ets2panda/ir/statements/doWhileStatement.cpp index e36442c438..93d2a413e6 100644 --- a/ets2panda/ir/statements/doWhileStatement.cpp +++ b/ets2panda/ir/statements/doWhileStatement.cpp @@ -21,8 +21,6 @@ #include "compiler/core/pandagen.h" #include "compiler/core/ETSGen.h" #include "checker/TSchecker.h" -#include "ir/astDump.h" -#include "ir/expression.h" namespace panda::es2panda::ir { void DoWhileStatement::TransformChildren(const NodeTransformer &cb) @@ -42,55 +40,23 @@ void DoWhileStatement::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "DoWhileStatement"}, {"body", body_}, {"test", test_}}); } -template -void CompileImpl(const DoWhileStatement *self, [[maybe_unused]] CodeGen *cg) +void DoWhileStatement::Compile(compiler::PandaGen *pg) const { - auto *start_label = cg->AllocLabel(); - compiler::LabelTarget label_target(cg); - - cg->SetLabel(self, start_label); - - { - compiler::LocalRegScope reg_scope(cg, self->Scope()); - compiler::LabelContext label_ctx(cg, label_target); - self->Body()->Compile(cg); - } - - cg->SetLabel(self, label_target.ContinueTarget()); - compiler::Condition::Compile(cg, self->Test(), label_target.BreakTarget()); - - cg->Branch(self, start_label); - cg->SetLabel(self, label_target.BreakTarget()); + pg->GetAstCompiler()->Compile(this); } -void DoWhileStatement::Compile([[maybe_unused]] compiler::PandaGen *pg) const +void DoWhileStatement::Compile(compiler::ETSGen *etsg) const { - CompileImpl(this, pg); + etsg->GetAstCompiler()->Compile(this); } -void DoWhileStatement::Compile([[maybe_unused]] compiler::ETSGen *etsg) const +checker::Type *DoWhileStatement::Check(checker::TSChecker *checker) { - CompileImpl(this, etsg); + return checker->GetAnalyzer()->Check(this); } -checker::Type *DoWhileStatement::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *DoWhileStatement::Check(checker::ETSChecker *checker) { - checker::ScopeContext scope_ctx(checker, Scope()); - - checker::Type *test_type = Test()->Check(checker); - checker->CheckTruthinessOfType(test_type, Test()->Start()); - Body()->Check(checker); - - return nullptr; -} - -checker::Type *DoWhileStatement::Check([[maybe_unused]] checker::ETSChecker *checker) -{ - checker::ScopeContext scope_ctx(checker, Scope()); - - checker->CheckTruthinessOfType(Test()); - Body()->Check(checker); - - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/statements/doWhileStatement.h b/ets2panda/ir/statements/doWhileStatement.h index 58b970bfdc..bc811edca2 100644 --- a/ets2panda/ir/statements/doWhileStatement.h +++ b/ets2panda/ir/statements/doWhileStatement.h @@ -62,10 +62,10 @@ 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 Compile([[maybe_unused]] compiler::ETSGen *etsg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: Statement *body_; -- Gitee From ac7640d3d353590d1635d9065914e1b77c8c7d54 Mon Sep 17 00:00:00 2001 From: Csaba Hurton Date: Tue, 24 Oct 2023 09:59:03 +0200 Subject: [PATCH 4/6] (7) Move Compile and Check Logic from ASTNode classes AstNodes that are being moved: - nodes inside ir/expressions/literals: - NullLiteral - NumberLiteral - RegExpLiteral - StringLiteral - nodes inside ir/module: - ExportAllDeclaration - ExportDefaultDeclaration - ExportNamedDeclaration - ExportSpecifier Linked Internal Issue 13840 Change-Id: I0efafd502fb3fa6469ca6037e4090f5aa640d772 Signed-off-by: Csaba Hurton --- ets2panda/checker/ETSAnalyzer.cpp | 49 ++++++++---- ets2panda/checker/TSAnalyzer.cpp | 48 +++++++----- ets2panda/compiler/core/ETSCompiler.cpp | 56 ++++++++++---- ets2panda/compiler/core/JSCompiler.cpp | 46 ++++++----- .../ir/expressions/literals/nullLiteral.cpp | 19 ++--- .../ir/expressions/literals/nullLiteral.h | 2 +- .../ir/expressions/literals/numberLiteral.cpp | 76 ++----------------- .../ir/expressions/literals/numberLiteral.h | 2 +- .../ir/expressions/literals/regExpLiteral.cpp | 15 ++-- .../ir/expressions/literals/regExpLiteral.h | 3 +- .../ir/expressions/literals/stringLiteral.cpp | 28 ++----- .../ir/expressions/literals/stringLiteral.h | 2 +- ets2panda/ir/module/exportAllDeclaration.cpp | 24 ++++-- ets2panda/ir/module/exportAllDeclaration.h | 7 +- .../ir/module/exportDefaultDeclaration.cpp | 21 +++-- .../ir/module/exportDefaultDeclaration.h | 7 +- .../ir/module/exportNamedDeclaration.cpp | 27 +++---- ets2panda/ir/module/exportNamedDeclaration.h | 8 +- ets2panda/ir/module/exportSpecifier.cpp | 23 ++++-- ets2panda/ir/module/exportSpecifier.h | 7 +- 20 files changed, 237 insertions(+), 233 deletions(-) diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 5aee8f8366..9e477e1e56 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -520,26 +520,47 @@ checker::Type *ETSAnalyzer::Check(ir::CharLiteral *expr) const checker::Type *ETSAnalyzer::Check(ir::NullLiteral *expr) const { - (void)expr; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + if (expr->TsType() == nullptr) { + expr->SetTsType(checker->GlobalETSNullType()); + } + return expr->TsType(); } checker::Type *ETSAnalyzer::Check(ir::NumberLiteral *expr) const { - (void)expr; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + if (expr->Number().IsInt()) { + expr->SetTsType(checker->CreateIntType(expr->Number().GetInt())); + return expr->TsType(); + } + + if (expr->Number().IsLong()) { + expr->SetTsType(checker->CreateLongType(expr->Number().GetLong())); + return expr->TsType(); + } + + if (expr->Number().IsFloat()) { + expr->SetTsType(checker->CreateFloatType(expr->Number().GetFloat())); + return expr->TsType(); + } + + expr->SetTsType(checker->CreateDoubleType(expr->Number().GetDouble())); + return expr->TsType(); } -checker::Type *ETSAnalyzer::Check(ir::RegExpLiteral *expr) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::RegExpLiteral *expr) const { - (void)expr; UNREACHABLE(); } checker::Type *ETSAnalyzer::Check(ir::StringLiteral *expr) const { - (void)expr; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + if (expr->TsType() == nullptr) { + expr->SetTsType(checker->CreateETSStringLiteralType(expr->Str())); + } + return expr->TsType(); } checker::Type *ETSAnalyzer::Check(ir::UndefinedLiteral *expr) const @@ -549,27 +570,23 @@ checker::Type *ETSAnalyzer::Check(ir::UndefinedLiteral *expr) const } // compile methods for MODULE-related nodes in alphabetical order -checker::Type *ETSAnalyzer::Check(ir::ExportAllDeclaration *st) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ExportAllDeclaration *st) const { - (void)st; UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::ExportDefaultDeclaration *st) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ExportDefaultDeclaration *st) const { - (void)st; UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::ExportNamedDeclaration *st) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ExportNamedDeclaration *st) const { - (void)st; UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::ExportSpecifier *st) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ExportSpecifier *st) const { - (void)st; UNREACHABLE(); } diff --git a/ets2panda/checker/TSAnalyzer.cpp b/ets2panda/checker/TSAnalyzer.cpp index cd0b565532..0992afe494 100644 --- a/ets2panda/checker/TSAnalyzer.cpp +++ b/ets2panda/checker/TSAnalyzer.cpp @@ -423,28 +423,44 @@ checker::Type *TSAnalyzer::Check(ir::CharLiteral *expr) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::NullLiteral *expr) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::NullLiteral *expr) const { - (void)expr; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + return checker->GlobalNullType(); } checker::Type *TSAnalyzer::Check(ir::NumberLiteral *expr) const { - (void)expr; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + auto search = checker->NumberLiteralMap().find(expr->Number().GetDouble()); + if (search != checker->NumberLiteralMap().end()) { + return search->second; + } + + auto *new_num_literal_type = checker->Allocator()->New(expr->Number().GetDouble()); + checker->NumberLiteralMap().insert({expr->Number().GetDouble(), new_num_literal_type}); + return new_num_literal_type; } -checker::Type *TSAnalyzer::Check(ir::RegExpLiteral *expr) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::RegExpLiteral *expr) const { - (void)expr; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + // TODO(aszilagyi); + return checker->GlobalAnyType(); } checker::Type *TSAnalyzer::Check(ir::StringLiteral *expr) const { - (void)expr; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + auto search = checker->StringLiteralMap().find(expr->Str()); + if (search != checker->StringLiteralMap().end()) { + return search->second; + } + + auto *new_str_literal_type = checker->Allocator()->New(expr->Str()); + checker->StringLiteralMap().insert({expr->Str(), new_str_literal_type}); + + return new_str_literal_type; } checker::Type *TSAnalyzer::Check(ir::UndefinedLiteral *expr) const @@ -454,27 +470,23 @@ checker::Type *TSAnalyzer::Check(ir::UndefinedLiteral *expr) const } // compile methods for MODULE-related nodes in alphabetical order -checker::Type *TSAnalyzer::Check(ir::ExportAllDeclaration *st) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ExportAllDeclaration *st) const { - (void)st; UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::ExportDefaultDeclaration *st) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ExportDefaultDeclaration *st) const { - (void)st; UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::ExportNamedDeclaration *st) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ExportNamedDeclaration *st) const { - (void)st; UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::ExportSpecifier *st) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ExportSpecifier *st) const { - (void)st; UNREACHABLE(); } diff --git a/ets2panda/compiler/core/ETSCompiler.cpp b/ets2panda/compiler/core/ETSCompiler.cpp index c890722e38..ac99acae33 100644 --- a/ets2panda/compiler/core/ETSCompiler.cpp +++ b/ets2panda/compiler/core/ETSCompiler.cpp @@ -427,26 +427,54 @@ void ETSCompiler::Compile(const ir::CharLiteral *expr) const void ETSCompiler::Compile(const ir::NullLiteral *expr) const { - (void)expr; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + etsg->LoadAccumulatorNull(expr, expr->TsType()); } void ETSCompiler::Compile(const ir::NumberLiteral *expr) const { - (void)expr; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + auto ttctx = compiler::TargetTypeContext(etsg, expr->TsType()); + if (expr->Number().IsInt()) { + if (util::Helpers::IsTargetFitInSourceRange( + expr->Number().GetInt())) { + etsg->LoadAccumulatorByte(expr, static_cast(expr->Number().GetInt())); + return; + } + + if (util::Helpers::IsTargetFitInSourceRange( + expr->Number().GetInt())) { + etsg->LoadAccumulatorShort(expr, static_cast(expr->Number().GetInt())); + return; + } + + etsg->LoadAccumulatorInt(expr, static_cast(expr->Number().GetInt())); + return; + } + + if (expr->Number().IsLong()) { + etsg->LoadAccumulatorWideInt(expr, expr->Number().GetLong()); + return; + } + + if (expr->Number().IsFloat()) { + etsg->LoadAccumulatorFloat(expr, expr->Number().GetFloat()); + return; + } + + etsg->LoadAccumulatorDouble(expr, expr->Number().GetDouble()); } -void ETSCompiler::Compile(const ir::RegExpLiteral *expr) const +void ETSCompiler::Compile([[maybe_unused]] const ir::RegExpLiteral *expr) const { - (void)expr; UNREACHABLE(); } void ETSCompiler::Compile(const ir::StringLiteral *expr) const { - (void)expr; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + etsg->LoadAccumulatorString(expr, expr->Str()); + etsg->SetAccumulatorType(expr->TsType()); } void ETSCompiler::Compile(const ir::UndefinedLiteral *expr) const @@ -456,27 +484,23 @@ void ETSCompiler::Compile(const ir::UndefinedLiteral *expr) const } // compile methods for MODULE-related nodes in alphabetical order -void ETSCompiler::Compile(const ir::ExportAllDeclaration *st) const +void ETSCompiler::Compile([[maybe_unused]] const ir::ExportAllDeclaration *st) const { - (void)st; UNREACHABLE(); } -void ETSCompiler::Compile(const ir::ExportDefaultDeclaration *st) const +void ETSCompiler::Compile([[maybe_unused]] const ir::ExportDefaultDeclaration *st) const { - (void)st; UNREACHABLE(); } -void ETSCompiler::Compile(const ir::ExportNamedDeclaration *st) const +void ETSCompiler::Compile([[maybe_unused]] const ir::ExportNamedDeclaration *st) const { - (void)st; UNREACHABLE(); } -void ETSCompiler::Compile(const ir::ExportSpecifier *st) const +void ETSCompiler::Compile([[maybe_unused]] const ir::ExportSpecifier *st) const { - (void)st; UNREACHABLE(); } diff --git a/ets2panda/compiler/core/JSCompiler.cpp b/ets2panda/compiler/core/JSCompiler.cpp index 83c36cae08..3b26df543f 100644 --- a/ets2panda/compiler/core/JSCompiler.cpp +++ b/ets2panda/compiler/core/JSCompiler.cpp @@ -729,26 +729,34 @@ void JSCompiler::Compile(const ir::CharLiteral *expr) const void JSCompiler::Compile(const ir::NullLiteral *expr) const { - (void)expr; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + pg->LoadConst(expr, compiler::Constant::JS_NULL); } void JSCompiler::Compile(const ir::NumberLiteral *expr) const { - (void)expr; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + if (std::isnan(expr->Number().GetDouble())) { + pg->LoadConst(expr, compiler::Constant::JS_NAN); + } else if (!std::isfinite(expr->Number().GetDouble())) { + pg->LoadConst(expr, compiler::Constant::JS_INFINITY); + } else if (util::Helpers::IsInteger(expr->Number().GetDouble())) { + pg->LoadAccumulatorInt(expr, static_cast(expr->Number().GetDouble())); + } else { + pg->LoadAccumulatorDouble(expr, expr->Number().GetDouble()); + } } void JSCompiler::Compile(const ir::RegExpLiteral *expr) const { - (void)expr; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + pg->CreateRegExpWithLiteral(expr, expr->Pattern(), static_cast(expr->Flags())); } void JSCompiler::Compile(const ir::StringLiteral *expr) const { - (void)expr; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + pg->LoadAccumulatorString(expr, expr->Str()); } void JSCompiler::Compile(const ir::UndefinedLiteral *expr) const @@ -758,27 +766,27 @@ void JSCompiler::Compile(const ir::UndefinedLiteral *expr) const } // Compile methods for MODULE-related nodes in alphabetical order -void JSCompiler::Compile(const ir::ExportAllDeclaration *st) const -{ - (void)st; - UNREACHABLE(); -} +void JSCompiler::Compile([[maybe_unused]] const ir::ExportAllDeclaration *st) const {} void JSCompiler::Compile(const ir::ExportDefaultDeclaration *st) const { - (void)st; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + st->Decl()->Compile(pg); + pg->StoreModuleVar(st, "default"); } void JSCompiler::Compile(const ir::ExportNamedDeclaration *st) const { - (void)st; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + if (st->Decl() == nullptr) { + return; + } + + st->Decl()->Compile(pg); } -void JSCompiler::Compile(const ir::ExportSpecifier *st) const +void JSCompiler::Compile([[maybe_unused]] const ir::ExportSpecifier *st) const { - (void)st; UNREACHABLE(); } diff --git a/ets2panda/ir/expressions/literals/nullLiteral.cpp b/ets2panda/ir/expressions/literals/nullLiteral.cpp index 10868ce832..06ab4c14f3 100644 --- a/ets2panda/ir/expressions/literals/nullLiteral.cpp +++ b/ets2panda/ir/expressions/literals/nullLiteral.cpp @@ -15,11 +15,9 @@ #include "nullLiteral.h" -#include "compiler/core/pandagen.h" -#include "compiler/core/ETSGen.h" #include "checker/TSchecker.h" -#include "checker/ETSchecker.h" -#include "ir/astDump.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void NullLiteral::TransformChildren([[maybe_unused]] const NodeTransformer &cb) {} @@ -32,25 +30,22 @@ void NullLiteral::Dump(ir::AstDumper *dumper) const void NullLiteral::Compile(compiler::PandaGen *pg) const { - pg->LoadConst(this, compiler::Constant::JS_NULL); + pg->GetAstCompiler()->Compile(this); } void NullLiteral::Compile(compiler::ETSGen *etsg) const { - etsg->LoadAccumulatorNull(this, TsType()); + etsg->GetAstCompiler()->Compile(this); } checker::Type *NullLiteral::Check(checker::TSChecker *checker) { - return checker->GlobalNullType(); + return checker->GetAnalyzer()->Check(this); } -checker::Type *NullLiteral::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *NullLiteral::Check(checker::ETSChecker *checker) { - if (TsType() == nullptr) { - SetTsType(checker->GlobalETSNullType()); - } - return TsType(); + return checker->GetAnalyzer()->Check(this); } // NOLINTNEXTLINE(google-default-arguments) diff --git a/ets2panda/ir/expressions/literals/nullLiteral.h b/ets2panda/ir/expressions/literals/nullLiteral.h index 1fa60a74f0..6554e5c0f3 100644 --- a/ets2panda/ir/expressions/literals/nullLiteral.h +++ b/ets2panda/ir/expressions/literals/nullLiteral.h @@ -37,7 +37,7 @@ public: void Compile(compiler::PandaGen *pg) const override; void Compile(compiler::ETSGen *etsg) const override; checker::Type *Check(checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; }; } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/expressions/literals/numberLiteral.cpp b/ets2panda/ir/expressions/literals/numberLiteral.cpp index d411de9238..4891bb85d2 100644 --- a/ets2panda/ir/expressions/literals/numberLiteral.cpp +++ b/ets2panda/ir/expressions/literals/numberLiteral.cpp @@ -15,12 +15,9 @@ #include "numberLiteral.h" -#include "util/helpers.h" -#include "compiler/core/pandagen.h" -#include "compiler/core/ETSGen.h" #include "checker/TSchecker.h" -#include "checker/ETSchecker.h" -#include "ir/astDump.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void NumberLiteral::TransformChildren([[maybe_unused]] const NodeTransformer &cb) {} @@ -33,81 +30,22 @@ void NumberLiteral::Dump(ir::AstDumper *dumper) const void NumberLiteral::Compile(compiler::PandaGen *pg) const { - if (std::isnan(number_.GetDouble())) { - pg->LoadConst(this, compiler::Constant::JS_NAN); - } else if (!std::isfinite(number_.GetDouble())) { - pg->LoadConst(this, compiler::Constant::JS_INFINITY); - } else if (util::Helpers::IsInteger(number_.GetDouble())) { - pg->LoadAccumulatorInt(this, static_cast(number_.GetDouble())); - } else { - pg->LoadAccumulatorDouble(this, number_.GetDouble()); - } + pg->GetAstCompiler()->Compile(this); } void NumberLiteral::Compile(compiler::ETSGen *etsg) const { - auto ttctx = compiler::TargetTypeContext(etsg, TsType()); - if (number_.IsInt()) { - if (util::Helpers::IsTargetFitInSourceRange( - number_.GetInt())) { - etsg->LoadAccumulatorByte(this, static_cast(number_.GetInt())); - return; - } - - if (util::Helpers::IsTargetFitInSourceRange( - number_.GetInt())) { - etsg->LoadAccumulatorShort(this, static_cast(number_.GetInt())); - return; - } - - etsg->LoadAccumulatorInt(this, static_cast(number_.GetInt())); - return; - } - - if (number_.IsLong()) { - etsg->LoadAccumulatorWideInt(this, number_.GetLong()); - return; - } - - if (number_.IsFloat()) { - etsg->LoadAccumulatorFloat(this, number_.GetFloat()); - return; - } - - etsg->LoadAccumulatorDouble(this, number_.GetDouble()); + etsg->GetAstCompiler()->Compile(this); } checker::Type *NumberLiteral::Check(checker::TSChecker *checker) { - auto search = checker->NumberLiteralMap().find(number_.GetDouble()); - if (search != checker->NumberLiteralMap().end()) { - return search->second; - } - - auto *new_num_literal_type = checker->Allocator()->New(number_.GetDouble()); - checker->NumberLiteralMap().insert({number_.GetDouble(), new_num_literal_type}); - return new_num_literal_type; + return checker->GetAnalyzer()->Check(this); } -checker::Type *NumberLiteral::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *NumberLiteral::Check(checker::ETSChecker *checker) { - if (number_.IsInt()) { - SetTsType(checker->CreateIntType(number_.GetInt())); - return TsType(); - } - - if (number_.IsLong()) { - SetTsType(checker->CreateLongType(number_.GetLong())); - return TsType(); - } - - if (number_.IsFloat()) { - SetTsType(checker->CreateFloatType(number_.GetFloat())); - return TsType(); - } - - SetTsType(checker->CreateDoubleType(number_.GetDouble())); - return TsType(); + return checker->GetAnalyzer()->Check(this); } // NOLINTNEXTLINE(google-default-arguments) diff --git a/ets2panda/ir/expressions/literals/numberLiteral.h b/ets2panda/ir/expressions/literals/numberLiteral.h index e7391b8e40..9fb2893c77 100644 --- a/ets2panda/ir/expressions/literals/numberLiteral.h +++ b/ets2panda/ir/expressions/literals/numberLiteral.h @@ -58,7 +58,7 @@ public: void Compile(compiler::PandaGen *pg) const override; void Compile(compiler::ETSGen *etsg) const override; checker::Type *Check(checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: lexer::Number number_; diff --git a/ets2panda/ir/expressions/literals/regExpLiteral.cpp b/ets2panda/ir/expressions/literals/regExpLiteral.cpp index d278513f9f..3e747af6bc 100644 --- a/ets2panda/ir/expressions/literals/regExpLiteral.cpp +++ b/ets2panda/ir/expressions/literals/regExpLiteral.cpp @@ -19,7 +19,7 @@ #include "compiler/core/pandagen.h" #include "compiler/core/regScope.h" #include "checker/TSchecker.h" -#include "ir/astDump.h" +#include "compiler/core/ETSGen.h" namespace panda::es2panda::ir { void RegExpLiteral::TransformChildren([[maybe_unused]] const NodeTransformer &cb) {} @@ -32,17 +32,22 @@ void RegExpLiteral::Dump(ir::AstDumper *dumper) const void RegExpLiteral::Compile(compiler::PandaGen *pg) const { - pg->CreateRegExpWithLiteral(this, pattern_, static_cast(flags_)); + pg->GetAstCompiler()->Compile(this); +} + +void RegExpLiteral::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); } checker::Type *RegExpLiteral::Check(checker::TSChecker *checker) { - return checker->GlobalAnyType(); + return checker->GetAnalyzer()->Check(this); } -checker::Type *RegExpLiteral::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *RegExpLiteral::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } // NOLINTNEXTLINE(google-default-arguments) diff --git a/ets2panda/ir/expressions/literals/regExpLiteral.h b/ets2panda/ir/expressions/literals/regExpLiteral.h index 8ee1c453e5..bdb265f7d6 100644 --- a/ets2panda/ir/expressions/literals/regExpLiteral.h +++ b/ets2panda/ir/expressions/literals/regExpLiteral.h @@ -51,8 +51,9 @@ public: void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; checker::Type *Check(checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: util::StringView pattern_; diff --git a/ets2panda/ir/expressions/literals/stringLiteral.cpp b/ets2panda/ir/expressions/literals/stringLiteral.cpp index 2c45cb252e..d3a2fa4a74 100644 --- a/ets2panda/ir/expressions/literals/stringLiteral.cpp +++ b/ets2panda/ir/expressions/literals/stringLiteral.cpp @@ -15,11 +15,9 @@ #include "stringLiteral.h" -#include "compiler/core/pandagen.h" -#include "compiler/core/ETSGen.h" #include "checker/TSchecker.h" -#include "checker/ETSchecker.h" -#include "ir/astDump.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void StringLiteral::TransformChildren([[maybe_unused]] const NodeTransformer &cb) {} @@ -32,34 +30,22 @@ void StringLiteral::Dump(ir::AstDumper *dumper) const void StringLiteral::Compile(compiler::PandaGen *pg) const { - pg->LoadAccumulatorString(this, str_); + pg->GetAstCompiler()->Compile(this); } void StringLiteral::Compile(compiler::ETSGen *etsg) const { - etsg->LoadAccumulatorString(this, str_); - etsg->SetAccumulatorType(TsType()); + etsg->GetAstCompiler()->Compile(this); } checker::Type *StringLiteral::Check(checker::TSChecker *checker) { - auto search = checker->StringLiteralMap().find(str_); - if (search != checker->StringLiteralMap().end()) { - return search->second; - } - - auto *new_str_literal_type = checker->Allocator()->New(str_); - checker->StringLiteralMap().insert({str_, new_str_literal_type}); - - return new_str_literal_type; + return checker->GetAnalyzer()->Check(this); } -checker::Type *StringLiteral::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *StringLiteral::Check(checker::ETSChecker *checker) { - if (TsType() == nullptr) { - SetTsType(checker->CreateETSStringLiteralType(str_)); - } - return TsType(); + return checker->GetAnalyzer()->Check(this); } // NOLINTNEXTLINE(google-default-arguments) diff --git a/ets2panda/ir/expressions/literals/stringLiteral.h b/ets2panda/ir/expressions/literals/stringLiteral.h index da7f22fdad..8daed2c98e 100644 --- a/ets2panda/ir/expressions/literals/stringLiteral.h +++ b/ets2panda/ir/expressions/literals/stringLiteral.h @@ -50,7 +50,7 @@ public: void Compile(compiler::PandaGen *pg) const override; void Compile(compiler::ETSGen *etsg) const override; checker::Type *Check(checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: util::StringView str_; diff --git a/ets2panda/ir/module/exportAllDeclaration.cpp b/ets2panda/ir/module/exportAllDeclaration.cpp index 9867f99848..c34cb356e4 100644 --- a/ets2panda/ir/module/exportAllDeclaration.cpp +++ b/ets2panda/ir/module/exportAllDeclaration.cpp @@ -15,9 +15,9 @@ #include "exportAllDeclaration.h" -#include "ir/astDump.h" -#include "ir/expressions/identifier.h" -#include "ir/expressions/literals/stringLiteral.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void ExportAllDeclaration::TransformChildren(const NodeTransformer &cb) @@ -43,15 +43,23 @@ void ExportAllDeclaration::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "ExportAllDeclaration"}, {"source", source_}, {"exported", AstDumper::Nullish(exported_)}}); } -void ExportAllDeclaration::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void ExportAllDeclaration::Compile(compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} + +void ExportAllDeclaration::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} -checker::Type *ExportAllDeclaration::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *ExportAllDeclaration::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } -checker::Type *ExportAllDeclaration::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *ExportAllDeclaration::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/module/exportAllDeclaration.h b/ets2panda/ir/module/exportAllDeclaration.h index afcdea02dc..89926b4ec8 100644 --- a/ets2panda/ir/module/exportAllDeclaration.h +++ b/ets2panda/ir/module/exportAllDeclaration.h @@ -42,9 +42,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: StringLiteral *source_; diff --git a/ets2panda/ir/module/exportDefaultDeclaration.cpp b/ets2panda/ir/module/exportDefaultDeclaration.cpp index 657179005a..82e090025b 100644 --- a/ets2panda/ir/module/exportDefaultDeclaration.cpp +++ b/ets2panda/ir/module/exportDefaultDeclaration.cpp @@ -15,8 +15,9 @@ #include "exportDefaultDeclaration.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" #include "compiler/core/pandagen.h" -#include "ir/astDump.h" namespace panda::es2panda::ir { void ExportDefaultDeclaration::TransformChildren(const NodeTransformer &cb) @@ -35,19 +36,23 @@ void ExportDefaultDeclaration::Dump(ir::AstDumper *dumper) const {{"type", IsExportEquals() ? "TSExportAssignment" : "ExportDefaultDeclaration"}, {"declaration", decl_}}); } -void ExportDefaultDeclaration::Compile([[maybe_unused]] compiler::PandaGen *pg) const +void ExportDefaultDeclaration::Compile(compiler::PandaGen *pg) const { - decl_->Compile(pg); - pg->StoreModuleVar(this, "default"); + pg->GetAstCompiler()->Compile(this); } -checker::Type *ExportDefaultDeclaration::Check([[maybe_unused]] checker::TSChecker *checker) +void ExportDefaultDeclaration::Compile(compiler::ETSGen *etsg) const { - return nullptr; + etsg->GetAstCompiler()->Compile(this); } -checker::Type *ExportDefaultDeclaration::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *ExportDefaultDeclaration::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); +} + +checker::Type *ExportDefaultDeclaration::Check(checker::ETSChecker *checker) +{ + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/module/exportDefaultDeclaration.h b/ets2panda/ir/module/exportDefaultDeclaration.h index 38af658d5f..6d32882db5 100644 --- a/ets2panda/ir/module/exportDefaultDeclaration.h +++ b/ets2panda/ir/module/exportDefaultDeclaration.h @@ -44,9 +44,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: AstNode *decl_; diff --git a/ets2panda/ir/module/exportNamedDeclaration.cpp b/ets2panda/ir/module/exportNamedDeclaration.cpp index 5bbd501593..ff886326fd 100644 --- a/ets2panda/ir/module/exportNamedDeclaration.cpp +++ b/ets2panda/ir/module/exportNamedDeclaration.cpp @@ -15,12 +15,9 @@ #include "exportNamedDeclaration.h" -#include "compiler/core/pandagen.h" +#include "checker/TSchecker.h" #include "compiler/core/ETSGen.h" -#include "ir/astDump.h" -#include "ir/base/decorator.h" -#include "ir/expressions/literals/stringLiteral.h" -#include "ir/module/exportSpecifier.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void ExportNamedDeclaration::TransformChildren(const NodeTransformer &cb) @@ -70,27 +67,23 @@ void ExportNamedDeclaration::Dump(ir::AstDumper *dumper) const {"specifiers", specifiers_}}); } -void ExportNamedDeclaration::Compile([[maybe_unused]] compiler::PandaGen *pg) const +void ExportNamedDeclaration::Compile(compiler::PandaGen *pg) const { - if (decl_ == nullptr) { - return; - } - - decl_->Compile(pg); + pg->GetAstCompiler()->Compile(this); } -void ExportNamedDeclaration::Compile([[maybe_unused]] compiler::ETSGen *etsg) const +void ExportNamedDeclaration::Compile(compiler::ETSGen *etsg) const { - UNREACHABLE(); + etsg->GetAstCompiler()->Compile(this); } -checker::Type *ExportNamedDeclaration::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *ExportNamedDeclaration::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } -checker::Type *ExportNamedDeclaration::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *ExportNamedDeclaration::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/module/exportNamedDeclaration.h b/ets2panda/ir/module/exportNamedDeclaration.h index e794931975..f455b8985e 100644 --- a/ets2panda/ir/module/exportNamedDeclaration.h +++ b/ets2panda/ir/module/exportNamedDeclaration.h @@ -78,10 +78,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - void Compile([[maybe_unused]] compiler::ETSGen *etsg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: ArenaVector decorators_; diff --git a/ets2panda/ir/module/exportSpecifier.cpp b/ets2panda/ir/module/exportSpecifier.cpp index e308dd2b06..2aa19dee82 100644 --- a/ets2panda/ir/module/exportSpecifier.cpp +++ b/ets2panda/ir/module/exportSpecifier.cpp @@ -15,8 +15,9 @@ #include "exportSpecifier.h" -#include "ir/astDump.h" -#include "ir/expressions/identifier.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void ExportSpecifier::TransformChildren(const NodeTransformer &cb) @@ -36,15 +37,23 @@ void ExportSpecifier::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "ExportSpecifier"}, {"local", local_}, {"exported", exported_}}); } -void ExportSpecifier::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void ExportSpecifier::Compile(compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} + +void ExportSpecifier::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} -checker::Type *ExportSpecifier::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *ExportSpecifier::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } -checker::Type *ExportSpecifier::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *ExportSpecifier::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/module/exportSpecifier.h b/ets2panda/ir/module/exportSpecifier.h index f6bfefbd9f..d50d2bee59 100644 --- a/ets2panda/ir/module/exportSpecifier.h +++ b/ets2panda/ir/module/exportSpecifier.h @@ -41,9 +41,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: Identifier *local_; -- Gitee From 60cfecc09f2455620609ffb25af02eb80ab5c415 Mon Sep 17 00:00:00 2001 From: Csaba Hurton Date: Tue, 17 Oct 2023 17:10:58 +0200 Subject: [PATCH 5/6] Move Check and Compile methods to Compiler and Analyzer classes Round #5 Moves these ASTNodes: - AwaitExpression - BinaryExpression - CallExpression - ChainExpression - ClassExpression - ConditionalExpression - DirectEvalExpression - FunctionExpression Linked Internal Issue 13840 Change-Id: I295033b85c28d4fd41c5049bd13ca4d3ab2fac2f Signed-off-by: Csaba Hurton --- ets2panda/checker/ETSAnalyzer.cpp | 266 +++++++++- ets2panda/checker/TSAnalyzer.cpp | 141 +++++- ets2panda/compiler/core/ETSCompiler.cpp | 334 ++++++++++++- ets2panda/compiler/core/JSCompiler.cpp | 219 ++++++++- ets2panda/ir/expressions/awaitExpression.cpp | 45 +- ets2panda/ir/expressions/awaitExpression.h | 9 +- ets2panda/ir/expressions/binaryExpression.cpp | 249 +--------- ets2panda/ir/expressions/binaryExpression.h | 11 +- ets2panda/ir/expressions/callExpression.cpp | 462 +----------------- ets2panda/ir/expressions/callExpression.h | 28 +- ets2panda/ir/expressions/chainExpression.cpp | 25 +- ets2panda/ir/expressions/chainExpression.h | 14 +- ets2panda/ir/expressions/classExpression.cpp | 21 +- ets2panda/ir/expressions/classExpression.h | 7 +- .../ir/expressions/conditionalExpression.cpp | 99 +--- .../ir/expressions/conditionalExpression.h | 9 + .../ir/expressions/directEvalExpression.cpp | 45 +- .../ir/expressions/directEvalExpression.h | 12 +- .../ir/expressions/functionExpression.cpp | 41 +- ets2panda/ir/expressions/functionExpression.h | 6 +- ets2panda/ir/expressions/memberExpression.cpp | 15 - 21 files changed, 1042 insertions(+), 1016 deletions(-) diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 9e477e1e56..25d05c22a8 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -364,49 +364,283 @@ checker::Type *ETSAnalyzer::Check(ir::AssignmentExpression *expr) const checker::Type *ETSAnalyzer::Check(ir::AwaitExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + if (expr->TsType() != nullptr) { + return expr->TsType(); + } + + checker::Type *arg_type = expr->argument_->Check(checker); + // Check the argument type of await expression + if (!arg_type->IsETSObjectType() || + (arg_type->AsETSObjectType()->AssemblerName() != compiler::Signatures::BUILTIN_PROMISE)) { + checker->ThrowTypeError("'await' expressions require Promise object as argument.", expr->Argument()->Start()); + } + + expr->SetTsType(arg_type->AsETSObjectType()->TypeArguments().at(0)); + return expr->TsType(); } checker::Type *ETSAnalyzer::Check(ir::BinaryExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + if (expr->TsType() != nullptr) { + return expr->TsType(); + } + checker::Type *new_ts_type {nullptr}; + std::tie(new_ts_type, expr->operation_type_) = + checker->CheckBinaryOperator(expr->Left(), expr->Right(), expr, expr->OperatorType(), expr->Start()); + expr->SetTsType(new_ts_type); + return expr->TsType(); +} + +static checker::Type *InitAnonymousLambdaCallee(checker::ETSChecker *checker, ir::Expression *callee, + checker::Type *callee_type) +{ + auto *const arrow_func = callee->AsArrowFunctionExpression()->Function(); + auto orig_params = arrow_func->Params(); + auto *func_type = checker->Allocator()->New( + arrow_func->Scope()->AsFunctionScope()->ParamScope(), std::move(orig_params), nullptr, + arrow_func->ReturnTypeAnnotation(), ir::ScriptFunctionFlags::NONE); + auto *const func_iface = func_type->Check(checker); + checker->Relation()->SetNode(callee); + checker->Relation()->IsAssignableTo(callee_type, func_iface); + return func_iface; +} + +static checker::Signature *ResolveCallExtensionFunction(checker::ETSFunctionType *function_type, + checker::ETSChecker *checker, ir::CallExpression *expr) +{ + auto *member_expr = expr->Callee()->AsMemberExpression(); + expr->Arguments().insert(expr->Arguments().begin(), member_expr->Object()); + auto *signature = + checker->ResolveCallExpressionAndTrailingLambda(function_type->CallSignatures(), expr, expr->Start()); + if (!signature->Function()->IsExtensionMethod()) { + checker->ThrowTypeError({"Property '", member_expr->Property()->AsIdentifier()->Name(), + "' does not exist on type '", member_expr->ObjType()->Name(), "'"}, + member_expr->Property()->Start()); + } + expr->SetSignature(signature); + expr->SetCallee(member_expr->Property()); + member_expr->Property()->AsIdentifier()->SetParent(expr); + expr->Arguments()[0]->SetParent(expr); + checker->HandleUpdatedCallExpressionNode(expr); + // Set TsType for new Callee(original member expression's Object) + expr->Callee()->Check(checker); + return signature; +} + +static checker::Signature *ResolveCallForETSExtensionFuncHelperType(checker::ETSExtensionFuncHelperType *type, + checker::ETSChecker *checker, + ir::CallExpression *expr) +{ + checker::Signature *signature = checker->ResolveCallExpressionAndTrailingLambda( + type->ClassMethodType()->CallSignatures(), expr, expr->Start(), checker::TypeRelationFlag::NO_THROW); + + if (signature != nullptr) { + return signature; + } + + return ResolveCallExtensionFunction(type->ExtensionMethodType(), checker, expr); } checker::Type *ETSAnalyzer::Check(ir::CallExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + if (expr->TsType() != nullptr) { + return expr->TsType(); + } + auto *old_callee = expr->Callee(); + checker::Type *callee_type = expr->Callee()->Check(checker); + if (expr->Callee() != old_callee) { + // If it is a static invoke, the callee will be transformed from an identifier to a member expression + // Type check the callee again for member expression + callee_type = expr->Callee()->Check(checker); + } + if (!expr->IsOptional()) { + checker->CheckNonNullishType(callee_type, expr->Callee()->Start()); + } + checker::Type *return_type; + if (callee_type->IsETSDynamicType() && !callee_type->AsETSDynamicType()->HasDecl()) { + // Trailing lambda for js function call is not supported, check the correctness of `foo() {}` + checker->EnsureValidCurlyBrace(expr); + auto lang = callee_type->AsETSDynamicType()->Language(); + expr->SetSignature(checker->ResolveDynamicCallExpression(expr->Callee(), expr->Arguments(), lang, false)); + return_type = expr->Signature()->ReturnType(); + } else { + bool constructor_call = expr->IsETSConstructorCall(); + bool functional_interface = + callee_type->IsETSObjectType() && + callee_type->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::FUNCTIONAL_INTERFACE); + bool ets_extension_func_helper_type = callee_type->IsETSExtensionFuncHelperType(); + bool extension_function_type = + expr->Callee()->IsMemberExpression() && checker->ExtensionETSFunctionType(callee_type); + + if (expr->Callee()->IsArrowFunctionExpression()) { + callee_type = InitAnonymousLambdaCallee(checker, expr->Callee(), callee_type); + functional_interface = true; + } + + if (!functional_interface && !callee_type->IsETSFunctionType() && !constructor_call && + !ets_extension_func_helper_type) { + checker->ThrowTypeError("This expression is not callable.", expr->Start()); + } + + checker::Signature *signature = nullptr; + + if (ets_extension_func_helper_type) { + signature = + ResolveCallForETSExtensionFuncHelperType(callee_type->AsETSExtensionFuncHelperType(), checker, expr); + } else { + if (extension_function_type) { + signature = ResolveCallExtensionFunction(callee_type->AsETSFunctionType(), checker, expr); + } else { + auto &signatures = constructor_call ? callee_type->AsETSObjectType()->ConstructSignatures() + : functional_interface + ? callee_type->AsETSObjectType() + ->GetOwnProperty("invoke") + ->TsType() + ->AsETSFunctionType() + ->CallSignatures() + : callee_type->AsETSFunctionType()->CallSignatures(); + signature = checker->ResolveCallExpressionAndTrailingLambda(signatures, expr, expr->Start()); + if (signature->Function()->IsExtensionMethod()) { + checker->ThrowTypeError({"No matching call signature"}, expr->Start()); + } + } + } + + checker->CheckObjectLiteralArguments(signature, expr->Arguments()); + + checker->AddUndefinedParamsForDefaultParams(signature, expr->Arguments(), checker); + + if (!functional_interface) { + checker::ETSObjectType *callee_obj {}; + if (constructor_call) { + callee_obj = callee_type->AsETSObjectType(); + } else if (expr->Callee()->IsIdentifier()) { + callee_obj = checker->Context().ContainingClass(); + } else { + ASSERT(expr->Callee()->IsMemberExpression()); + callee_obj = expr->Callee()->AsMemberExpression()->ObjType(); + } + + checker->ValidateSignatureAccessibility(callee_obj, signature, expr->Start()); + } + + ASSERT(signature->Function() != nullptr); + + if (signature->Function()->IsThrowing() || signature->Function()->IsRethrowing()) { + checker->CheckThrowingStatements(expr); + } + + if (signature->Function()->IsDynamic()) { + ASSERT(signature->Function()->IsDynamic()); + auto lang = signature->Function()->Language(); + expr->SetSignature(checker->ResolveDynamicCallExpression(expr->Callee(), signature->Params(), lang, false)); + } else { + ASSERT(!signature->Function()->IsDynamic()); + expr->SetSignature(signature); + } + + return_type = signature->ReturnType(); + } + + if (expr->Signature()->RestVar() != nullptr) { + auto *const element_type = expr->Signature()->RestVar()->TsType()->AsETSArrayType()->ElementType(); + auto *const array_type = checker->CreateETSArrayType(element_type)->AsETSArrayType(); + checker->CreateBuiltinArraySignature(array_type, array_type->Rank()); + } + + if (expr->Signature()->HasSignatureFlag(checker::SignatureFlags::NEED_RETURN_TYPE)) { + expr->Signature()->OwnerVar()->Declaration()->Node()->Check(checker); + return_type = expr->Signature()->ReturnType(); + } + expr->SetOptionalType(return_type); + if (expr->IsOptional() && callee_type->IsNullishOrNullLike()) { + checker->Relation()->SetNode(expr); + return_type = checker->CreateOptionalResultType(return_type); + checker->Relation()->SetNode(nullptr); + } + expr->SetTsType(return_type); + return expr->TsType(); } -checker::Type *ETSAnalyzer::Check(ir::ChainExpression *expr) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ChainExpression *expr) const { - (void)expr; UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::ClassExpression *expr) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ClassExpression *expr) const { - (void)expr; UNREACHABLE(); } checker::Type *ETSAnalyzer::Check(ir::ConditionalExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + if (expr->TsType() != nullptr) { + return expr->TsType(); + } + + checker->CheckTruthinessOfType(expr->Test()); + + checker::Type *consequent_type = expr->consequent_->Check(checker); + checker::Type *alternate_type = expr->alternate_->Check(checker); + + auto *primitive_consequent_type = checker->ETSBuiltinTypeAsPrimitiveType(consequent_type); + auto *primitive_alter_type = checker->ETSBuiltinTypeAsPrimitiveType(alternate_type); + + if (primitive_consequent_type != nullptr && primitive_alter_type != nullptr) { + if (checker->IsTypeIdenticalTo(consequent_type, alternate_type)) { + expr->SetTsType(checker->GetNonConstantTypeFromPrimitiveType(consequent_type)); + } else if (checker->IsTypeIdenticalTo(primitive_consequent_type, primitive_alter_type)) { + checker->FlagExpressionWithUnboxing(expr->consequent_->TsType(), primitive_consequent_type, + expr->consequent_); + checker->FlagExpressionWithUnboxing(expr->alternate_->TsType(), primitive_alter_type, expr->alternate_); + + expr->SetTsType(primitive_consequent_type); + } else if (primitive_consequent_type->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC) && + primitive_alter_type->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC)) { + checker->FlagExpressionWithUnboxing(expr->consequent_->TsType(), primitive_consequent_type, + expr->consequent_); + checker->FlagExpressionWithUnboxing(expr->alternate_->TsType(), primitive_alter_type, expr->alternate_); + + expr->SetTsType( + checker->ApplyConditionalOperatorPromotion(checker, primitive_consequent_type, primitive_alter_type)); + } else { + checker->ThrowTypeError("Type error", expr->Range().start); + } + } else { + if (!(consequent_type->IsETSArrayType() || alternate_type->IsETSArrayType()) && + !(consequent_type->IsETSObjectType() && alternate_type->IsETSObjectType())) { + checker->ThrowTypeError("Type error", expr->Range().start); + } else { + checker->Relation()->SetNode(expr->consequent_); + auto builtin_conseq_type = checker->PrimitiveTypeAsETSBuiltinType(consequent_type); + auto builtin_alternate_type = checker->PrimitiveTypeAsETSBuiltinType(alternate_type); + + if (builtin_conseq_type == nullptr) { + builtin_conseq_type = consequent_type; + } + + if (builtin_alternate_type == nullptr) { + builtin_alternate_type = alternate_type; + } + + expr->SetTsType(checker->FindLeastUpperBound(builtin_conseq_type, builtin_alternate_type)); + } + } + + return expr->TsType(); } -checker::Type *ETSAnalyzer::Check(ir::DirectEvalExpression *expr) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::DirectEvalExpression *expr) const { - (void)expr; UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::FunctionExpression *expr) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::FunctionExpression *expr) const { - (void)expr; UNREACHABLE(); } diff --git a/ets2panda/checker/TSAnalyzer.cpp b/ets2panda/checker/TSAnalyzer.cpp index 0992afe494..ddcc6a2db9 100644 --- a/ets2panda/checker/TSAnalyzer.cpp +++ b/ets2panda/checker/TSAnalyzer.cpp @@ -267,52 +267,157 @@ checker::Type *TSAnalyzer::Check(ir::AssignmentExpression *expr) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::AwaitExpression *expr) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::AwaitExpression *expr) const { - (void)expr; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + // NOTE(aszilagyi) + return checker->GlobalAnyType(); } checker::Type *TSAnalyzer::Check(ir::BinaryExpression *expr) const { - (void)expr; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + auto *left_type = expr->Left()->Check(checker); + auto *right_type = expr->Right()->Check(checker); + + switch (expr->OperatorType()) { + case lexer::TokenType::PUNCTUATOR_MULTIPLY: + case lexer::TokenType::PUNCTUATOR_EXPONENTIATION: + case lexer::TokenType::PUNCTUATOR_DIVIDE: + case lexer::TokenType::PUNCTUATOR_MOD: + case lexer::TokenType::PUNCTUATOR_MINUS: + case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: + case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: + case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: + case lexer::TokenType::PUNCTUATOR_BITWISE_AND: + case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: + case lexer::TokenType::PUNCTUATOR_BITWISE_OR: { + return checker->CheckBinaryOperator(left_type, right_type, expr->Left(), expr->Right(), expr, + expr->OperatorType()); + } + case lexer::TokenType::PUNCTUATOR_PLUS: { + return checker->CheckPlusOperator(left_type, right_type, expr->Left(), expr->Right(), expr, + expr->OperatorType()); + } + case lexer::TokenType::PUNCTUATOR_LESS_THAN: + case lexer::TokenType::PUNCTUATOR_GREATER_THAN: { + return checker->CheckCompareOperator(left_type, right_type, expr->Left(), expr->Right(), expr, + expr->OperatorType()); + } + case lexer::TokenType::PUNCTUATOR_EQUAL: + case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: + case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL: + case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: { + if (checker->IsTypeEqualityComparableTo(left_type, right_type) || + checker->IsTypeEqualityComparableTo(right_type, left_type)) { + return checker->GlobalBooleanType(); + } + + checker->ThrowBinaryLikeError(expr->OperatorType(), left_type, right_type, expr->Start()); + } + case lexer::TokenType::KEYW_INSTANCEOF: { + return checker->CheckInstanceofExpression(left_type, right_type, expr->Right(), expr); + } + case lexer::TokenType::KEYW_IN: { + return checker->CheckInExpression(left_type, right_type, expr->Left(), expr->Right(), expr); + } + case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: { + return checker->CheckAndOperator(left_type, right_type, expr->Left()); + } + case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: { + return checker->CheckOrOperator(left_type, right_type, expr->Left()); + } + case lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING: { + // NOTE: Csaba Repasi. Implement checker for nullish coalescing + return checker->GlobalAnyType(); + } + case lexer::TokenType::PUNCTUATOR_SUBSTITUTION: { + checker->CheckAssignmentOperator(expr->OperatorType(), expr->Left(), left_type, right_type); + return right_type; + } + default: { + UNREACHABLE(); + break; + } + } + + return nullptr; } checker::Type *TSAnalyzer::Check(ir::CallExpression *expr) const { - (void)expr; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + checker::Type *callee_type = expr->callee_->Check(checker); + + // NOTE: aszilagyi. handle optional chain + if (callee_type->IsObjectType()) { + checker::ObjectType *callee_obj = callee_type->AsObjectType(); + return checker->ResolveCallOrNewExpression(callee_obj->CallSignatures(), expr->Arguments(), expr->Start()); + } + + checker->ThrowTypeError("This expression is not callable.", expr->Start()); + return nullptr; } checker::Type *TSAnalyzer::Check(ir::ChainExpression *expr) const { - (void)expr; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + return expr->expression_->Check(checker); } -checker::Type *TSAnalyzer::Check(ir::ClassExpression *expr) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ClassExpression *expr) const { - (void)expr; UNREACHABLE(); } checker::Type *TSAnalyzer::Check(ir::ConditionalExpression *expr) const { - (void)expr; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + checker::Type *test_type = expr->Test()->Check(checker); + + checker->CheckTruthinessOfType(test_type, expr->Test()->Start()); + checker->CheckTestingKnownTruthyCallableOrAwaitableType(expr->Test(), test_type, expr->consequent_); + + checker::Type *consequent_type = expr->consequent_->Check(checker); + checker::Type *alternate_type = expr->alternate_->Check(checker); + + return checker->CreateUnionType({consequent_type, alternate_type}); } -checker::Type *TSAnalyzer::Check(ir::DirectEvalExpression *expr) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::DirectEvalExpression *expr) const { - (void)expr; UNREACHABLE(); } checker::Type *TSAnalyzer::Check(ir::FunctionExpression *expr) const { - (void)expr; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + varbinder::Variable *func_var = nullptr; + + if (expr->Function()->Parent()->Parent() != nullptr && + expr->Function()->Parent()->Parent()->IsVariableDeclarator() && + expr->Function()->Parent()->Parent()->AsVariableDeclarator()->Id()->IsIdentifier()) { + func_var = expr->Function()->Parent()->Parent()->AsVariableDeclarator()->Id()->AsIdentifier()->Variable(); + } + + checker::ScopeContext scope_ctx(checker, expr->Function()->Scope()); + + auto *signature_info = checker->Allocator()->New(checker->Allocator()); + checker->CheckFunctionParameterDeclarations(expr->Function()->Params(), signature_info); + + auto *signature = checker->Allocator()->New( + signature_info, checker->GlobalResolvingReturnType(), expr->Function()); + checker::Type *func_type = checker->CreateFunctionTypeWithSignature(signature); + + if (func_var != nullptr && func_var->TsType() == nullptr) { + func_var->SetTsType(func_type); + } + + signature->SetReturnType(checker->HandleFunctionReturn(expr->Function())); + + expr->Function()->Body()->Check(checker); + + return func_type; } checker::Type *TSAnalyzer::Check(ir::Identifier *expr) const @@ -445,7 +550,7 @@ checker::Type *TSAnalyzer::Check(ir::NumberLiteral *expr) const checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::RegExpLiteral *expr) const { TSChecker *checker = GetTSChecker(); - // TODO(aszilagyi); + // NOTE(aszilagyi); return checker->GlobalAnyType(); } diff --git a/ets2panda/compiler/core/ETSCompiler.cpp b/ets2panda/compiler/core/ETSCompiler.cpp index ac99acae33..2f7a58772e 100644 --- a/ets2panda/compiler/core/ETSCompiler.cpp +++ b/ets2panda/compiler/core/ETSCompiler.cpp @@ -271,49 +271,351 @@ void ETSCompiler::Compile(const ir::AssignmentExpression *expr) const void ETSCompiler::Compile(const ir::AwaitExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + static constexpr bool IS_UNCHECKED_CAST = false; + compiler::RegScope rs(etsg); + compiler::VReg argument_reg = etsg->AllocReg(); + expr->Argument()->Compile(etsg); + etsg->StoreAccumulator(expr, argument_reg); + etsg->CallThisVirtual0(expr->Argument(), argument_reg, compiler::Signatures::BUILTIN_PROMISE_AWAIT_RESOLUTION); + etsg->CastToArrayOrObject(expr->Argument(), expr->TsType(), IS_UNCHECKED_CAST); + etsg->SetAccumulatorType(expr->TsType()); +} + +static void CompileNullishCoalescing(compiler::ETSGen *etsg, ir::BinaryExpression const *const node) +{ + auto const compile_operand = [etsg, optype = node->OperationType()](ir::Expression const *expr) { + etsg->CompileAndCheck(expr); + etsg->ApplyConversion(expr, optype); + }; + + compile_operand(node->Left()); + + if (!node->Left()->TsType()->IsNullishOrNullLike()) { + // fallthrough + } else if (node->Left()->TsType()->IsETSNullLike()) { + compile_operand(node->Right()); + } else { + auto *if_left_nullish = etsg->AllocLabel(); + auto *end_label = etsg->AllocLabel(); + + etsg->BranchIfNullish(node, if_left_nullish); + + etsg->ConvertToNonNullish(node); + etsg->ApplyConversion(node->Left(), node->OperationType()); + etsg->JumpTo(node, end_label); + + etsg->SetLabel(node, if_left_nullish); + compile_operand(node->Right()); + + etsg->SetLabel(node, end_label); + } + etsg->SetAccumulatorType(node->TsType()); +} + +static void CompileLogical(compiler::ETSGen *etsg, const ir::BinaryExpression *expr) +{ + if (expr->OperatorType() == lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING) { + CompileNullishCoalescing(etsg, expr); + return; + } + + ASSERT(expr->IsLogicalExtended()); + auto ttctx = compiler::TargetTypeContext(etsg, expr->OperationType()); + compiler::RegScope rs(etsg); + auto lhs = etsg->AllocReg(); + auto rhs = etsg->AllocReg(); + expr->Left()->Compile(etsg); + etsg->ApplyConversionAndStoreAccumulator(expr->Left(), lhs, expr->OperationType()); + + auto *end_label = etsg->AllocLabel(); + + auto left_false_label = etsg->AllocLabel(); + if (expr->OperatorType() == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) { + etsg->ResolveConditionalResultIfFalse(expr->Left(), left_false_label); + etsg->BranchIfFalse(expr, left_false_label); + + expr->Right()->Compile(etsg); + etsg->ApplyConversionAndStoreAccumulator(expr->Right(), rhs, expr->OperationType()); + etsg->Branch(expr, end_label); + + etsg->SetLabel(expr, left_false_label); + etsg->LoadAccumulator(expr, lhs); + } else { + etsg->ResolveConditionalResultIfFalse(expr->Left(), left_false_label); + etsg->BranchIfFalse(expr, left_false_label); + + etsg->LoadAccumulator(expr, lhs); + etsg->Branch(expr, end_label); + + etsg->SetLabel(expr, left_false_label); + expr->Right()->Compile(etsg); + etsg->ApplyConversionAndStoreAccumulator(expr->Right(), rhs, expr->OperationType()); + } + + etsg->SetLabel(expr, end_label); + etsg->SetAccumulatorType(expr->TsType()); } void ETSCompiler::Compile(const ir::BinaryExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + if (etsg->TryLoadConstantExpression(expr)) { + return; + } + + auto ttctx = compiler::TargetTypeContext(etsg, expr->OperationType()); + + if (expr->IsLogical()) { + CompileLogical(etsg, expr); + etsg->ApplyConversion(expr, expr->OperationType()); + return; + } + + compiler::RegScope rs(etsg); + compiler::VReg lhs = etsg->AllocReg(); + + if (expr->OperatorType() == lexer::TokenType::PUNCTUATOR_PLUS && + (expr->Left()->TsType()->IsETSStringType() || expr->Right()->TsType()->IsETSStringType())) { + etsg->BuildString(expr); + return; + } + + expr->Left()->Compile(etsg); + etsg->ApplyConversionAndStoreAccumulator(expr->Left(), lhs, expr->OperationType()); + expr->Right()->Compile(etsg); + etsg->ApplyConversion(expr->Right(), expr->OperationType()); + if (expr->OperatorType() >= lexer::TokenType::PUNCTUATOR_LEFT_SHIFT && + expr->OperatorType() <= lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT) { + etsg->ApplyCast(expr->Right(), expr->OperationType()); + } + + etsg->Binary(expr, expr->OperatorType(), lhs); +} + +static void ConvertRestArguments(checker::ETSChecker *const checker, const ir::CallExpression *expr) +{ + if (expr->Signature()->RestVar() != nullptr) { + std::size_t const argument_count = expr->Arguments().size(); + std::size_t const parameter_count = expr->Signature()->MinArgCount(); + ASSERT(argument_count >= parameter_count); + + auto &arguments = const_cast &>(expr->Arguments()); + std::size_t i = parameter_count; + + if (i < argument_count && expr->Arguments()[i]->IsSpreadElement()) { + arguments[i] = expr->Arguments()[i]->AsSpreadElement()->Argument(); + } else { + ArenaVector elements(checker->Allocator()->Adapter()); + for (; i < argument_count; ++i) { + elements.emplace_back(expr->Arguments()[i]); + } + auto *array_expression = checker->AllocNode(std::move(elements), checker->Allocator()); + array_expression->SetParent(const_cast(expr)); + array_expression->SetTsType(expr->Signature()->RestVar()->TsType()); + arguments.erase(expr->Arguments().begin() + parameter_count, expr->Arguments().end()); + arguments.emplace_back(array_expression); + } + } } void ETSCompiler::Compile(const ir::CallExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + compiler::RegScope rs(etsg); + compiler::VReg callee_reg = etsg->AllocReg(); + + const auto is_proxy = expr->Signature()->HasSignatureFlag(checker::SignatureFlags::PROXY); + + if (is_proxy && expr->Callee()->IsMemberExpression()) { + auto *const callee_object = expr->callee_->AsMemberExpression()->Object(); + + auto const *const enum_interface = [callee_type = + callee_object->TsType()]() -> checker::ETSEnumInterface const * { + if (callee_type->IsETSEnumType()) { + return callee_type->AsETSEnumType(); + } + if (callee_type->IsETSStringEnumType()) { + return callee_type->AsETSStringEnumType(); + } + return nullptr; + }(); + + if (enum_interface != nullptr) { + ArenaVector arguments(etsg->Allocator()->Adapter()); + + checker::Signature *const signature = [expr, callee_object, enum_interface, &arguments]() { + const auto &member_proxy_method_name = expr->Signature()->InternalName(); + + if (member_proxy_method_name == checker::ETSEnumType::TO_STRING_METHOD_NAME) { + arguments.push_back(callee_object); + return enum_interface->ToStringMethod().global_signature; + } + if (member_proxy_method_name == checker::ETSEnumType::GET_VALUE_METHOD_NAME) { + arguments.push_back(callee_object); + return enum_interface->GetValueMethod().global_signature; + } + if (member_proxy_method_name == checker::ETSEnumType::GET_NAME_METHOD_NAME) { + arguments.push_back(callee_object); + return enum_interface->GetNameMethod().global_signature; + } + if (member_proxy_method_name == checker::ETSEnumType::VALUES_METHOD_NAME) { + return enum_interface->ValuesMethod().global_signature; + } + if (member_proxy_method_name == checker::ETSEnumType::VALUE_OF_METHOD_NAME) { + arguments.push_back(expr->Arguments().front()); + return enum_interface->ValueOfMethod().global_signature; + } + UNREACHABLE(); + }(); + + ASSERT(signature->ReturnType() == expr->Signature()->ReturnType()); + etsg->CallStatic(expr, signature, arguments); + etsg->SetAccumulatorType(expr->TsType()); + return; + } + } + + bool is_static = expr->Signature()->HasSignatureFlag(checker::SignatureFlags::STATIC); + bool is_reference = expr->Signature()->HasSignatureFlag(checker::SignatureFlags::TYPE); + bool is_dynamic = expr->Callee()->TsType()->HasTypeFlag(checker::TypeFlag::ETS_DYNAMIC_FLAG); + + ConvertRestArguments(const_cast(etsg->Checker()->AsETSChecker()), expr); + + compiler::VReg dyn_param2; + + // Helper function to avoid branching in non optional cases + auto emit_call = [expr, etsg, is_static, is_dynamic, &callee_reg, &dyn_param2]() { + if (is_dynamic) { + etsg->CallDynamic(expr, callee_reg, dyn_param2, expr->Signature(), expr->Arguments()); + } else if (is_static) { + etsg->CallStatic(expr, expr->Signature(), expr->Arguments()); + } else if (expr->Signature()->HasSignatureFlag(checker::SignatureFlags::PRIVATE) || + expr->IsETSConstructorCall() || + (expr->Callee()->IsMemberExpression() && + expr->Callee()->AsMemberExpression()->Object()->IsSuperExpression())) { + etsg->CallThisStatic(expr, callee_reg, expr->Signature(), expr->Arguments()); + } else { + etsg->CallThisVirtual(expr, callee_reg, expr->Signature(), expr->Arguments()); + } + etsg->SetAccumulatorType(expr->TsType()); + }; + + if (is_dynamic) { + dyn_param2 = etsg->AllocReg(); + + ir::Expression *obj = expr->callee_; + std::vector parts; + + while (obj->IsMemberExpression() && obj->AsMemberExpression()->ObjType()->IsETSDynamicType()) { + auto *mem_expr = obj->AsMemberExpression(); + obj = mem_expr->Object(); + parts.push_back(mem_expr->Property()->AsIdentifier()->Name()); + } + + if (!obj->IsMemberExpression() && obj->IsIdentifier()) { + auto *var = obj->AsIdentifier()->Variable(); + auto *data = etsg->VarBinder()->DynamicImportDataForVar(var); + if (data != nullptr) { + auto *import = data->import; + auto *specifier = data->specifier; + ASSERT(import->Language().IsDynamic()); + etsg->LoadAccumulatorDynamicModule(expr, import); + if (specifier->IsImportSpecifier()) { + parts.push_back(specifier->AsImportSpecifier()->Imported()->Name()); + } + } else { + obj->Compile(etsg); + } + } else { + obj->Compile(etsg); + } + + etsg->StoreAccumulator(expr, callee_reg); + + if (!parts.empty()) { + std::stringstream ss; + for_each(parts.rbegin(), parts.rend(), [&ss](util::StringView sv) { ss << "." << sv; }); + + etsg->LoadAccumulatorString(expr, util::UString(ss.str(), etsg->Allocator()).View()); + } else { + auto lang = expr->Callee()->TsType()->IsETSDynamicFunctionType() + ? expr->Callee()->TsType()->AsETSDynamicFunctionType()->Language() + : expr->Callee()->TsType()->AsETSDynamicType()->Language(); + + etsg->LoadUndefinedDynamic(expr, lang); + } + + etsg->StoreAccumulator(expr, dyn_param2); + + emit_call(); + + if (expr->Signature()->ReturnType() != expr->TsType()) { + etsg->ApplyConversion(expr, expr->TsType()); + } + } else if (!is_reference && expr->Callee()->IsIdentifier()) { + if (!is_static) { + etsg->LoadThis(expr); + etsg->StoreAccumulator(expr, callee_reg); + } + emit_call(); + } else if (!is_reference && expr->Callee()->IsMemberExpression()) { + if (!is_static) { + expr->Callee()->AsMemberExpression()->Object()->Compile(etsg); + etsg->StoreAccumulator(expr, callee_reg); + } + emit_call(); + } else if (expr->Callee()->IsSuperExpression() || expr->Callee()->IsThisExpression()) { + ASSERT(!is_reference && expr->IsETSConstructorCall()); + expr->Callee()->Compile(etsg); // ctor is not a value! + etsg->SetVRegType(callee_reg, etsg->GetAccumulatorType()); + emit_call(); + } else { + ASSERT(is_reference); + etsg->CompileAndCheck(expr->Callee()); + etsg->StoreAccumulator(expr, callee_reg); + etsg->EmitMaybeOptional(expr, emit_call, expr->IsOptional()); + } } -void ETSCompiler::Compile(const ir::ChainExpression *expr) const +void ETSCompiler::Compile([[maybe_unused]] const ir::ChainExpression *expr) const { - (void)expr; UNREACHABLE(); } -void ETSCompiler::Compile(const ir::ClassExpression *expr) const +void ETSCompiler::Compile([[maybe_unused]] const ir::ClassExpression *expr) const { - (void)expr; UNREACHABLE(); } void ETSCompiler::Compile(const ir::ConditionalExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + + auto *false_label = etsg->AllocLabel(); + auto *end_label = etsg->AllocLabel(); + + compiler::Condition::Compile(etsg, expr->Test(), false_label); + + auto ttctx = compiler::TargetTypeContext(etsg, expr->TsType()); + + expr->Consequent()->Compile(etsg); + etsg->ApplyConversion(expr->Consequent()); + etsg->Branch(expr, end_label); + etsg->SetLabel(expr, false_label); + expr->Alternate()->Compile(etsg); + etsg->ApplyConversion(expr->Alternate()); + etsg->SetLabel(expr, end_label); + etsg->SetAccumulatorType(expr->TsType()); } -void ETSCompiler::Compile(const ir::DirectEvalExpression *expr) const +void ETSCompiler::Compile([[maybe_unused]] const ir::DirectEvalExpression *expr) const { - (void)expr; UNREACHABLE(); } -void ETSCompiler::Compile(const ir::FunctionExpression *expr) const +void ETSCompiler::Compile([[maybe_unused]] const ir::FunctionExpression *expr) const { - (void)expr; UNREACHABLE(); } diff --git a/ets2panda/compiler/core/JSCompiler.cpp b/ets2panda/compiler/core/JSCompiler.cpp index 3b26df543f..c3c3666045 100644 --- a/ets2panda/compiler/core/JSCompiler.cpp +++ b/ets2panda/compiler/core/JSCompiler.cpp @@ -573,50 +573,237 @@ void JSCompiler::Compile(const ir::AssignmentExpression *expr) const void JSCompiler::Compile(const ir::AwaitExpression *expr) const { - (void)expr; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + compiler::RegScope rs(pg); + + if (expr->Argument() != nullptr) { + expr->Argument()->Compile(pg); + } else { + pg->LoadConst(expr, compiler::Constant::JS_UNDEFINED); + } + + pg->EmitAwait(expr); +} + +static void CompileLogical(compiler::PandaGen *pg, const ir::BinaryExpression *expr) +{ + compiler::RegScope rs(pg); + compiler::VReg lhs = pg->AllocReg(); + + ASSERT(expr->OperatorType() == lexer::TokenType::PUNCTUATOR_LOGICAL_AND || + expr->OperatorType() == lexer::TokenType::PUNCTUATOR_LOGICAL_OR || + expr->OperatorType() == lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING); + + auto *skip_right = pg->AllocLabel(); + auto *end_label = pg->AllocLabel(); + + // left -> acc -> lhs -> toboolean -> acc -> bool_lhs + expr->Left()->Compile(pg); + pg->StoreAccumulator(expr, lhs); + + if (expr->OperatorType() == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) { + pg->ToBoolean(expr); + pg->BranchIfFalse(expr, skip_right); + } else if (expr->OperatorType() == lexer::TokenType::PUNCTUATOR_LOGICAL_OR) { + pg->ToBoolean(expr); + pg->BranchIfTrue(expr, skip_right); + } else if (expr->OperatorType() == lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING) { + pg->BranchIfCoercible(expr, skip_right); + } + + // left is true/false(and/or) then right -> acc + expr->Right()->Compile(pg); + pg->Branch(expr, end_label); + + // left is false/true(and/or) then lhs -> acc + pg->SetLabel(expr, skip_right); + pg->LoadAccumulator(expr, lhs); + pg->SetLabel(expr, end_label); } void JSCompiler::Compile(const ir::BinaryExpression *expr) const { - (void)expr; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + if (expr->IsLogical()) { + CompileLogical(pg, expr); + return; + } + + if (expr->OperatorType() == lexer::TokenType::KEYW_IN && expr->Left()->IsIdentifier() && + expr->Left()->AsIdentifier()->IsPrivateIdent()) { + compiler::RegScope rs(pg); + compiler::VReg ctor = pg->AllocReg(); + const auto &name = expr->Left()->AsIdentifier()->Name(); + compiler::Function::LoadClassContexts(expr, pg, ctor, name); + expr->Right()->Compile(pg); + pg->ClassPrivateFieldIn(expr, ctor, name); + return; + } + + compiler::RegScope rs(pg); + compiler::VReg lhs = pg->AllocReg(); + + expr->Left()->Compile(pg); + pg->StoreAccumulator(expr, lhs); + expr->Right()->Compile(pg); + + pg->Binary(expr, expr->OperatorType(), lhs); +} + +static compiler::VReg CreateSpreadArguments(compiler::PandaGen *pg, const ir::CallExpression *expr) +{ + compiler::VReg args_obj = pg->AllocReg(); + pg->CreateArray(expr, expr->Arguments(), args_obj); + + return args_obj; } void JSCompiler::Compile(const ir::CallExpression *expr) const { - (void)expr; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + compiler::RegScope rs(pg); + bool contains_spread = util::Helpers::ContainSpreadElement(expr->Arguments()); + + if (expr->Callee()->IsSuperExpression()) { + if (contains_spread) { + compiler::RegScope param_scope(pg); + compiler::VReg args_obj = CreateSpreadArguments(pg, expr); + + pg->GetFunctionObject(expr); + pg->SuperCallSpread(expr, args_obj); + } else { + compiler::RegScope param_scope(pg); + compiler::VReg arg_start {}; + + if (expr->Arguments().empty()) { + arg_start = pg->AllocReg(); + pg->StoreConst(expr, arg_start, compiler::Constant::JS_UNDEFINED); + } else { + arg_start = pg->NextReg(); + } + + for (const auto *it : expr->Arguments()) { + compiler::VReg arg = pg->AllocReg(); + it->Compile(pg); + pg->StoreAccumulator(it, arg); + } + + pg->GetFunctionObject(expr); + pg->SuperCall(expr, arg_start, expr->Arguments().size()); + } + + compiler::VReg new_this = pg->AllocReg(); + pg->StoreAccumulator(expr, new_this); + + pg->GetThis(expr); + pg->ThrowIfSuperNotCorrectCall(expr, 1); + + pg->LoadAccumulator(expr, new_this); + pg->SetThis(expr); + + compiler::Function::CompileInstanceFields(pg, pg->RootNode()->AsScriptFunction()); + return; + } + + compiler::VReg callee = pg->AllocReg(); + compiler::VReg this_reg = compiler::VReg::Invalid(); + + if (expr->Callee()->IsMemberExpression()) { + this_reg = pg->AllocReg(); + + compiler::RegScope mrs(pg); + expr->Callee()->AsMemberExpression()->CompileToReg(pg, this_reg); + } else if (expr->Callee()->IsChainExpression()) { + this_reg = pg->AllocReg(); + + compiler::RegScope mrs(pg); + expr->Callee()->AsChainExpression()->CompileToReg(pg, this_reg); + } else { + expr->Callee()->Compile(pg); + } + + pg->StoreAccumulator(expr, callee); + pg->OptionalChainCheck(expr->IsOptional(), callee); + + if (contains_spread || expr->Arguments().size() >= compiler::PandaGen::MAX_RANGE_CALL_ARG) { + if (this_reg.IsInvalid()) { + this_reg = pg->AllocReg(); + pg->StoreConst(expr, this_reg, compiler::Constant::JS_UNDEFINED); + } + + compiler::VReg args_obj = CreateSpreadArguments(pg, expr); + pg->CallSpread(expr, callee, this_reg, args_obj); + } else { + pg->Call(expr, callee, this_reg, expr->Arguments()); + } } void JSCompiler::Compile(const ir::ChainExpression *expr) const { - (void)expr; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + compiler::OptionalChain chain(pg, expr); + expr->GetExpression()->Compile(pg); } void JSCompiler::Compile(const ir::ClassExpression *expr) const { - (void)expr; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + expr->Definition()->Compile(pg); +} + +template +static void CompileImpl(const ir::ConditionalExpression *self, CodeGen *cg) +{ + auto *false_label = cg->AllocLabel(); + auto *end_label = cg->AllocLabel(); + + compiler::Condition::Compile(cg, self->Test(), false_label); + self->Consequent()->Compile(cg); + cg->Branch(self, end_label); + cg->SetLabel(self, false_label); + self->Alternate()->Compile(cg); + cg->SetLabel(self, end_label); } void JSCompiler::Compile(const ir::ConditionalExpression *expr) const { - (void)expr; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + CompileImpl(expr, pg); } void JSCompiler::Compile(const ir::DirectEvalExpression *expr) const { - (void)expr; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + if (expr->Arguments().empty()) { + pg->LoadConst(expr, compiler::Constant::JS_UNDEFINED); + return; + } + + compiler::RegScope rs(pg); + bool contains_spread = util::Helpers::ContainSpreadElement(expr->Arguments()); + if (contains_spread) { + [[maybe_unused]] compiler::VReg args_obj = CreateSpreadArguments(pg, expr); + pg->LoadObjByIndex(expr, 0); + } else { + compiler::VReg arg0 = pg->AllocReg(); + auto iter = expr->Arguments().cbegin(); + (*iter++)->Compile(pg); + pg->StoreAccumulator(expr, arg0); + + while (iter != expr->Arguments().cend()) { + (*iter++)->Compile(pg); + } + + pg->LoadAccumulator(expr, arg0); + } + + pg->DirectEval(expr, expr->parser_status_); } void JSCompiler::Compile(const ir::FunctionExpression *expr) const { - (void)expr; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + pg->DefineFunction(expr->Function(), expr->Function(), expr->Function()->Scope()->InternalName()); } void JSCompiler::Compile(const ir::Identifier *expr) const diff --git a/ets2panda/ir/expressions/awaitExpression.cpp b/ets2panda/ir/expressions/awaitExpression.cpp index 636a7e5bc2..0dc54fafb3 100644 --- a/ets2panda/ir/expressions/awaitExpression.cpp +++ b/ets2panda/ir/expressions/awaitExpression.cpp @@ -15,15 +15,10 @@ #include "awaitExpression.h" +#include "checker/TSchecker.h" #include "compiler/core/pandagen.h" #include "compiler/core/ETSGen.h" -#include "compiler/core/regScope.h" -#include "checker/TSchecker.h" -#include "checker/ETSchecker.h" #include "ir/astDump.h" -#include "ir/base/methodDefinition.h" -#include "ir/base/scriptFunction.h" -#include "ir/expressions/arrowFunctionExpression.h" namespace panda::es2panda::ir { void AwaitExpression::TransformChildren(const NodeTransformer &cb) @@ -47,50 +42,22 @@ void AwaitExpression::Dump(ir::AstDumper *dumper) const void AwaitExpression::Compile(compiler::PandaGen *pg) const { - compiler::RegScope rs(pg); - - if (argument_ != nullptr) { - argument_->Compile(pg); - } else { - pg->LoadConst(this, compiler::Constant::JS_UNDEFINED); - } - - pg->EmitAwait(this); + pg->GetAstCompiler()->Compile(this); } void AwaitExpression::Compile(compiler::ETSGen *etsg) const { - static constexpr bool IS_UNCHECKED_CAST = false; - compiler::RegScope rs(etsg); - compiler::VReg argument_reg = etsg->AllocReg(); - argument_->Compile(etsg); - etsg->StoreAccumulator(this, argument_reg); - etsg->CallThisVirtual0(argument_, argument_reg, compiler::Signatures::BUILTIN_PROMISE_AWAIT_RESOLUTION); - etsg->CastToArrayOrObject(argument_, TsType(), IS_UNCHECKED_CAST); - etsg->SetAccumulatorType(TsType()); + etsg->GetAstCompiler()->Compile(this); } -checker::Type *AwaitExpression::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *AwaitExpression::Check(checker::TSChecker *checker) { - // NOTE: aszilagyi - return checker->GlobalAnyType(); + return checker->GetAnalyzer()->Check(this); } checker::Type *AwaitExpression::Check(checker::ETSChecker *checker) { - if (TsType() != nullptr) { - return TsType(); - } - - checker::Type *arg_type = argument_->Check(checker); - // Check the argument type of await expression - if (!arg_type->IsETSObjectType() || - (arg_type->AsETSObjectType()->AssemblerName() != compiler::Signatures::BUILTIN_PROMISE)) { - checker->ThrowTypeError("'await' expressions require Promise object as argument.", argument_->Start()); - } - - SetTsType(arg_type->AsETSObjectType()->TypeArguments().at(0)); - return TsType(); + return checker->GetAnalyzer()->Check(this); } // NOLINTNEXTLINE(google-default-arguments) diff --git a/ets2panda/ir/expressions/awaitExpression.h b/ets2panda/ir/expressions/awaitExpression.h index 17240df98c..0a84c6e7bf 100644 --- a/ets2panda/ir/expressions/awaitExpression.h +++ b/ets2panda/ir/expressions/awaitExpression.h @@ -18,6 +18,10 @@ #include "ir/expression.h" +namespace panda::es2panda::checker { +class ETSAnalyzer; +} // namespace panda::es2panda::checker + namespace panda::es2panda::ir { class AwaitExpression : public Expression { public: @@ -29,6 +33,9 @@ public: explicit AwaitExpression(Expression *argument) : Expression(AstNodeType::AWAIT_EXPRESSION), argument_(argument) {} + // TODO (csabahurton): friend relationship can be removed once there are getters for private fields + friend class checker::ETSAnalyzer; + [[nodiscard]] const Expression *Argument() const noexcept { return argument_; @@ -43,7 +50,7 @@ public: void Compile(compiler::PandaGen *pg) const override; void Compile(compiler::ETSGen *etsg) const override; checker::Type *Check(checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: Expression *argument_; diff --git a/ets2panda/ir/expressions/binaryExpression.cpp b/ets2panda/ir/expressions/binaryExpression.cpp index 440afa17f2..77707c82be 100644 --- a/ets2panda/ir/expressions/binaryExpression.cpp +++ b/ets2panda/ir/expressions/binaryExpression.cpp @@ -15,14 +15,9 @@ #include "binaryExpression.h" -#include "varbinder/variable.h" -#include "compiler/core/function.h" #include "compiler/core/pandagen.h" #include "compiler/core/ETSGen.h" -#include "compiler/core/regScope.h" #include "checker/TSchecker.h" -#include "ir/astDump.h" -#include "ir/expressions/identifier.h" namespace panda::es2panda::ir { void BinaryExpression::TransformChildren(const NodeTransformer &cb) @@ -45,254 +40,22 @@ void BinaryExpression::Dump(ir::AstDumper *dumper) const {"right", right_}}); } -void BinaryExpression::CompileLogical(compiler::PandaGen *pg) const -{ - compiler::RegScope rs(pg); - compiler::VReg lhs = pg->AllocReg(); - - ASSERT(operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_AND || - operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_OR || - operator_ == lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING); - - auto *skip_right = pg->AllocLabel(); - auto *end_label = pg->AllocLabel(); - - // left -> acc -> lhs -> toboolean -> acc -> bool_lhs - left_->Compile(pg); - pg->StoreAccumulator(this, lhs); - - if (operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) { - pg->ToBoolean(this); - pg->BranchIfFalse(this, skip_right); - } else if (operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_OR) { - pg->ToBoolean(this); - pg->BranchIfTrue(this, skip_right); - } else if (operator_ == lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING) { - pg->BranchIfCoercible(this, skip_right); - } - - // left is true/false(and/or) then right -> acc - right_->Compile(pg); - pg->Branch(this, end_label); - - // left is false/true(and/or) then lhs -> acc - pg->SetLabel(this, skip_right); - pg->LoadAccumulator(this, lhs); - pg->SetLabel(this, end_label); -} - -void BinaryExpression::Compile(compiler::PandaGen *pg) const -{ - if (IsLogical()) { - CompileLogical(pg); - return; - } - - if (operator_ == lexer::TokenType::KEYW_IN && left_->IsIdentifier() && left_->AsIdentifier()->IsPrivateIdent()) { - compiler::RegScope rs(pg); - compiler::VReg ctor = pg->AllocReg(); - const auto &name = left_->AsIdentifier()->Name(); - compiler::Function::LoadClassContexts(this, pg, ctor, name); - right_->Compile(pg); - pg->ClassPrivateFieldIn(this, ctor, name); - return; - } - - compiler::RegScope rs(pg); - compiler::VReg lhs = pg->AllocReg(); - - left_->Compile(pg); - pg->StoreAccumulator(this, lhs); - right_->Compile(pg); - - pg->Binary(this, operator_, lhs); +void BinaryExpression::Compile(compiler::PandaGen *pg) const { + pg->GetAstCompiler()->Compile(this); } -void BinaryExpression::Compile(compiler::ETSGen *etsg) const -{ - if (etsg->TryLoadConstantExpression(this)) { - return; - } - - auto ttctx = compiler::TargetTypeContext(etsg, operation_type_); - - if (IsLogical()) { - CompileLogical(etsg); - etsg->ApplyConversion(this, operation_type_); - return; - } - - compiler::RegScope rs(etsg); - compiler::VReg lhs = etsg->AllocReg(); - - if (operator_ == lexer::TokenType::PUNCTUATOR_PLUS && - (left_->TsType()->IsETSStringType() || right_->TsType()->IsETSStringType())) { - etsg->BuildString(this); - return; - } - - left_->Compile(etsg); - etsg->ApplyConversionAndStoreAccumulator(left_, lhs, operation_type_); - right_->Compile(etsg); - etsg->ApplyConversion(right_, operation_type_); - if (operator_ >= lexer::TokenType::PUNCTUATOR_LEFT_SHIFT && - operator_ <= lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT) { - etsg->ApplyCast(right_, operation_type_); - } - - etsg->Binary(this, operator_, lhs); -} - -static void CompileNullishCoalescing(BinaryExpression const *const node, compiler::ETSGen *etsg) -{ - auto const compile_operand = [etsg, optype = node->OperationType()](ir::Expression const *expr) { - etsg->CompileAndCheck(expr); - etsg->ApplyConversion(expr, optype); - }; - - compile_operand(node->Left()); - - if (!node->Left()->TsType()->IsNullishOrNullLike()) { - // fallthrough - } else if (node->Left()->TsType()->IsETSNullLike()) { - compile_operand(node->Right()); - } else { - auto *if_left_nullish = etsg->AllocLabel(); - auto *end_label = etsg->AllocLabel(); - - etsg->BranchIfNullish(node, if_left_nullish); - - etsg->ConvertToNonNullish(node); - etsg->ApplyConversion(node->Left(), node->OperationType()); - etsg->JumpTo(node, end_label); - - etsg->SetLabel(node, if_left_nullish); - compile_operand(node->Right()); - - etsg->SetLabel(node, end_label); - } - etsg->SetAccumulatorType(node->TsType()); -} - -void BinaryExpression::CompileLogical(compiler::ETSGen *etsg) const -{ - if (operator_ == lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING) { - CompileNullishCoalescing(this, etsg); - return; - } - - ASSERT(IsLogicalExtended()); - auto ttctx = compiler::TargetTypeContext(etsg, OperationType()); - compiler::RegScope rs(etsg); - auto lhs = etsg->AllocReg(); - auto rhs = etsg->AllocReg(); - left_->Compile(etsg); - etsg->ApplyConversionAndStoreAccumulator(left_, lhs, OperationType()); - - auto *end_label = etsg->AllocLabel(); - - auto left_false_label = etsg->AllocLabel(); - if (operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) { - etsg->ResolveConditionalResultIfFalse(left_, left_false_label); - etsg->BranchIfFalse(this, left_false_label); - - right_->Compile(etsg); - etsg->ApplyConversionAndStoreAccumulator(right_, rhs, OperationType()); - etsg->Branch(this, end_label); - - etsg->SetLabel(this, left_false_label); - etsg->LoadAccumulator(this, lhs); - } else { - etsg->ResolveConditionalResultIfFalse(left_, left_false_label); - etsg->BranchIfFalse(this, left_false_label); - - etsg->LoadAccumulator(this, lhs); - etsg->Branch(this, end_label); - - etsg->SetLabel(this, left_false_label); - right_->Compile(etsg); - etsg->ApplyConversionAndStoreAccumulator(right_, rhs, OperationType()); - } - - etsg->SetLabel(this, end_label); - etsg->SetAccumulatorType(TsType()); +void BinaryExpression::Compile(compiler::ETSGen *etsg) const { + etsg->GetAstCompiler()->Compile(this); } checker::Type *BinaryExpression::Check(checker::TSChecker *checker) { - auto *left_type = left_->Check(checker); - auto *right_type = right_->Check(checker); - - switch (operator_) { - case lexer::TokenType::PUNCTUATOR_MULTIPLY: - case lexer::TokenType::PUNCTUATOR_EXPONENTIATION: - case lexer::TokenType::PUNCTUATOR_DIVIDE: - case lexer::TokenType::PUNCTUATOR_MOD: - case lexer::TokenType::PUNCTUATOR_MINUS: - case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: - case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: - case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: - case lexer::TokenType::PUNCTUATOR_BITWISE_AND: - case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: - case lexer::TokenType::PUNCTUATOR_BITWISE_OR: { - return checker->CheckBinaryOperator(left_type, right_type, left_, right_, this, operator_); - } - case lexer::TokenType::PUNCTUATOR_PLUS: { - return checker->CheckPlusOperator(left_type, right_type, left_, right_, this, operator_); - } - case lexer::TokenType::PUNCTUATOR_LESS_THAN: - case lexer::TokenType::PUNCTUATOR_GREATER_THAN: { - return checker->CheckCompareOperator(left_type, right_type, left_, right_, this, operator_); - } - case lexer::TokenType::PUNCTUATOR_EQUAL: - case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: - case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL: - case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: { - if (checker->IsTypeEqualityComparableTo(left_type, right_type) || - checker->IsTypeEqualityComparableTo(right_type, left_type)) { - return checker->GlobalBooleanType(); - } - - checker->ThrowBinaryLikeError(operator_, left_type, right_type, Start()); - } - case lexer::TokenType::KEYW_INSTANCEOF: { - return checker->CheckInstanceofExpression(left_type, right_type, right_, this); - } - case lexer::TokenType::KEYW_IN: { - return checker->CheckInExpression(left_type, right_type, left_, right_, this); - } - case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: { - return checker->CheckAndOperator(left_type, right_type, left_); - } - case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: { - return checker->CheckOrOperator(left_type, right_type, left_); - } - case lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING: { - // NOTE: Csaba Repasi. Implement checker for nullish coalescing - return checker->GlobalAnyType(); - } - case lexer::TokenType::PUNCTUATOR_SUBSTITUTION: { - checker->CheckAssignmentOperator(operator_, left_, left_type, right_type); - return right_type; - } - default: { - UNREACHABLE(); - break; - } - } - - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *BinaryExpression::Check(checker::ETSChecker *checker) { - if (TsType() != nullptr) { - return TsType(); - } - checker::Type *new_ts_type {nullptr}; - std::tie(new_ts_type, operation_type_) = checker->CheckBinaryOperator(left_, right_, this, operator_, Start()); - SetTsType(new_ts_type); - return TsType(); + return checker->GetAnalyzer()->Check(this); } // NOLINTNEXTLINE(google-default-arguments) diff --git a/ets2panda/ir/expressions/binaryExpression.h b/ets2panda/ir/expressions/binaryExpression.h index c2a1a47bbb..0ab4ba0e25 100644 --- a/ets2panda/ir/expressions/binaryExpression.h +++ b/ets2panda/ir/expressions/binaryExpression.h @@ -19,6 +19,10 @@ #include "ir/expression.h" #include "lexer/token/tokenType.h" +namespace panda::es2panda::checker { +class ETSAnalyzer; +} // namespace panda::es2panda::checker + namespace panda::es2panda::ir { class BinaryExpression : public Expression { public: @@ -33,6 +37,9 @@ public: { } + // TODO (csabahurton): friend relationship can be removed once there are getters for private fields + friend class checker::ETSAnalyzer; + [[nodiscard]] const Expression *Left() const noexcept { return left_; @@ -120,10 +127,8 @@ public: void Dump(ir::AstDumper *dumper) const override; void Compile(compiler::PandaGen *pg) const override; void Compile(compiler::ETSGen *etsg) const override; - void CompileLogical(compiler::PandaGen *pg) const; - void CompileLogical(compiler::ETSGen *etsg) const; checker::Type *Check(checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: Expression *left_ = nullptr; diff --git a/ets2panda/ir/expressions/callExpression.cpp b/ets2panda/ir/expressions/callExpression.cpp index b74f16794d..311fc21349 100644 --- a/ets2panda/ir/expressions/callExpression.cpp +++ b/ets2panda/ir/expressions/callExpression.cpp @@ -15,29 +15,9 @@ #include "callExpression.h" -#include "util/helpers.h" -#include "compiler/core/function.h" -#include "compiler/core/pandagen.h" -#include "compiler/core/ETSGen.h" -#include "compiler/core/regScope.h" #include "checker/TSchecker.h" -#include "checker/ETSchecker.h" -#include "checker/types/ets/etsDynamicFunctionType.h" -#include "checker/types/ts/objectType.h" -#include "checker/types/signature.h" -#include "ir/astDump.h" -#include "ir/base/scriptFunction.h" -#include "ir/base/spreadElement.h" -#include "ir/ets/etsFunctionType.h" -#include "ir/expressions/arrayExpression.h" -#include "ir/expressions/chainExpression.h" -#include "ir/expressions/identifier.h" -#include "ir/expressions/memberExpression.h" -#include "ir/expressions/arrowFunctionExpression.h" -#include "ir/expressions/literals/numberLiteral.h" -#include "ir/statements/blockStatement.h" -#include "ir/ts/tsTypeParameterInstantiation.h" -#include "ir/ts/tsEnumMember.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void CallExpression::TransformChildren(const NodeTransformer &cb) @@ -79,287 +59,19 @@ void CallExpression::Dump(ir::AstDumper *dumper) const {"typeParameters", AstDumper::Optional(type_params_)}}); } -compiler::VReg CallExpression::CreateSpreadArguments(compiler::PandaGen *pg) const -{ - compiler::VReg args_obj = pg->AllocReg(); - pg->CreateArray(this, arguments_, args_obj); - - return args_obj; -} - -void CallExpression::ConvertRestArguments(checker::ETSChecker *const checker) const -{ - if (signature_->RestVar() != nullptr) { - std::size_t const argument_count = arguments_.size(); - std::size_t const parameter_count = signature_->MinArgCount(); - ASSERT(argument_count >= parameter_count); - - auto &arguments = const_cast &>(arguments_); - std::size_t i = parameter_count; - - if (i < argument_count && arguments_[i]->IsSpreadElement()) { - arguments[i] = arguments_[i]->AsSpreadElement()->Argument(); - } else { - ArenaVector elements(checker->Allocator()->Adapter()); - for (; i < argument_count; ++i) { - elements.emplace_back(arguments_[i]); - } - auto *array_expression = checker->AllocNode(std::move(elements), checker->Allocator()); - array_expression->SetParent(const_cast(this)); - array_expression->SetTsType(signature_->RestVar()->TsType()); - arguments.erase(arguments_.begin() + parameter_count, arguments_.end()); - arguments.emplace_back(array_expression); - } - } -} - void CallExpression::Compile(compiler::PandaGen *pg) const { - compiler::RegScope rs(pg); - bool contains_spread = util::Helpers::ContainSpreadElement(arguments_); - - if (callee_->IsSuperExpression()) { - if (contains_spread) { - compiler::RegScope param_scope(pg); - compiler::VReg args_obj = CreateSpreadArguments(pg); - - pg->GetFunctionObject(this); - pg->SuperCallSpread(this, args_obj); - } else { - compiler::RegScope param_scope(pg); - compiler::VReg arg_start {}; - - if (arguments_.empty()) { - arg_start = pg->AllocReg(); - pg->StoreConst(this, arg_start, compiler::Constant::JS_UNDEFINED); - } else { - arg_start = pg->NextReg(); - } - - for (const auto *it : arguments_) { - compiler::VReg arg = pg->AllocReg(); - it->Compile(pg); - pg->StoreAccumulator(it, arg); - } - - pg->GetFunctionObject(this); - pg->SuperCall(this, arg_start, arguments_.size()); - } - - compiler::VReg new_this = pg->AllocReg(); - pg->StoreAccumulator(this, new_this); - - pg->GetThis(this); - pg->ThrowIfSuperNotCorrectCall(this, 1); - - pg->LoadAccumulator(this, new_this); - pg->SetThis(this); - - compiler::Function::CompileInstanceFields(pg, pg->RootNode()->AsScriptFunction()); - return; - } - - compiler::VReg callee = pg->AllocReg(); - compiler::VReg this_reg = compiler::VReg::Invalid(); - - if (callee_->IsMemberExpression()) { - this_reg = pg->AllocReg(); - - compiler::RegScope mrs(pg); - callee_->AsMemberExpression()->CompileToReg(pg, this_reg); - } else if (callee_->IsChainExpression()) { - this_reg = pg->AllocReg(); - - compiler::RegScope mrs(pg); - callee_->AsChainExpression()->CompileToReg(pg, this_reg); - } else { - callee_->Compile(pg); - } - - pg->StoreAccumulator(this, callee); - pg->OptionalChainCheck(IsOptional(), callee); - - if (contains_spread || arguments_.size() >= compiler::PandaGen::MAX_RANGE_CALL_ARG) { - if (this_reg.IsInvalid()) { - this_reg = pg->AllocReg(); - pg->StoreConst(this, this_reg, compiler::Constant::JS_UNDEFINED); - } - - compiler::VReg args_obj = CreateSpreadArguments(pg); - pg->CallSpread(this, callee, this_reg, args_obj); - } else { - pg->Call(this, callee, this_reg, arguments_); - } + pg->GetAstCompiler()->Compile(this); } void CallExpression::Compile(compiler::ETSGen *etsg) const { - compiler::RegScope rs(etsg); - compiler::VReg callee_reg = etsg->AllocReg(); - - const auto is_proxy = signature_->HasSignatureFlag(checker::SignatureFlags::PROXY); - - if (is_proxy && callee_->IsMemberExpression()) { - auto *const callee_object = callee_->AsMemberExpression()->Object(); - - auto const *const enum_interface = [callee_type = - callee_object->TsType()]() -> checker::ETSEnumInterface const * { - if (callee_type->IsETSEnumType()) { - return callee_type->AsETSEnumType(); - } - if (callee_type->IsETSStringEnumType()) { - return callee_type->AsETSStringEnumType(); - } - return nullptr; - }(); - - if (enum_interface != nullptr) { - ArenaVector arguments(etsg->Allocator()->Adapter()); - - checker::Signature *const signature = [this, callee_object, enum_interface, &arguments]() { - const auto &member_proxy_method_name = signature_->InternalName(); - - if (member_proxy_method_name == checker::ETSEnumType::TO_STRING_METHOD_NAME) { - arguments.push_back(callee_object); - return enum_interface->ToStringMethod().global_signature; - } - if (member_proxy_method_name == checker::ETSEnumType::GET_VALUE_METHOD_NAME) { - arguments.push_back(callee_object); - return enum_interface->GetValueMethod().global_signature; - } - if (member_proxy_method_name == checker::ETSEnumType::GET_NAME_METHOD_NAME) { - arguments.push_back(callee_object); - return enum_interface->GetNameMethod().global_signature; - } - if (member_proxy_method_name == checker::ETSEnumType::VALUES_METHOD_NAME) { - return enum_interface->ValuesMethod().global_signature; - } - if (member_proxy_method_name == checker::ETSEnumType::VALUE_OF_METHOD_NAME) { - arguments.push_back(arguments_.front()); - return enum_interface->ValueOfMethod().global_signature; - } - UNREACHABLE(); - }(); - - ASSERT(signature->ReturnType() == signature_->ReturnType()); - etsg->CallStatic(this, signature, arguments); - etsg->SetAccumulatorType(TsType()); - return; - } - } - - bool is_static = signature_->HasSignatureFlag(checker::SignatureFlags::STATIC); - bool is_reference = signature_->HasSignatureFlag(checker::SignatureFlags::TYPE); - bool is_dynamic = callee_->TsType()->HasTypeFlag(checker::TypeFlag::ETS_DYNAMIC_FLAG); - - ConvertRestArguments(const_cast(etsg->Checker()->AsETSChecker())); - - compiler::VReg dyn_param2; - - // Helper function to avoid branching in non optional cases - auto emit_call = [this, etsg, is_static, is_dynamic, &callee_reg, &dyn_param2]() { - if (is_dynamic) { - etsg->CallDynamic(this, callee_reg, dyn_param2, signature_, arguments_); - } else if (is_static) { - etsg->CallStatic(this, signature_, arguments_); - } else if (signature_->HasSignatureFlag(checker::SignatureFlags::PRIVATE) || IsETSConstructorCall() || - (callee_->IsMemberExpression() && callee_->AsMemberExpression()->Object()->IsSuperExpression())) { - etsg->CallThisStatic(this, callee_reg, signature_, arguments_); - } else { - etsg->CallThisVirtual(this, callee_reg, signature_, arguments_); - } - etsg->SetAccumulatorType(TsType()); - }; - - if (is_dynamic) { - dyn_param2 = etsg->AllocReg(); - - ir::Expression *obj = callee_; - std::vector parts; - - while (obj->IsMemberExpression() && obj->AsMemberExpression()->ObjType()->IsETSDynamicType()) { - auto *mem_expr = obj->AsMemberExpression(); - obj = mem_expr->Object(); - parts.push_back(mem_expr->Property()->AsIdentifier()->Name()); - } - - if (!obj->IsMemberExpression() && obj->IsIdentifier()) { - auto *var = obj->AsIdentifier()->Variable(); - auto *data = etsg->VarBinder()->DynamicImportDataForVar(var); - if (data != nullptr) { - auto *import = data->import; - auto *specifier = data->specifier; - ASSERT(import->Language().IsDynamic()); - etsg->LoadAccumulatorDynamicModule(this, import); - if (specifier->IsImportSpecifier()) { - parts.push_back(specifier->AsImportSpecifier()->Imported()->Name()); - } - } else { - obj->Compile(etsg); - } - } else { - obj->Compile(etsg); - } - - etsg->StoreAccumulator(this, callee_reg); - - if (!parts.empty()) { - std::stringstream ss; - for_each(parts.rbegin(), parts.rend(), [&ss](util::StringView sv) { ss << "." << sv; }); - - etsg->LoadAccumulatorString(this, util::UString(ss.str(), etsg->Allocator()).View()); - } else { - auto lang = callee_->TsType()->IsETSDynamicFunctionType() - ? callee_->TsType()->AsETSDynamicFunctionType()->Language() - : callee_->TsType()->AsETSDynamicType()->Language(); - - etsg->LoadUndefinedDynamic(this, lang); - } - - etsg->StoreAccumulator(this, dyn_param2); - - emit_call(); - - if (signature_->ReturnType() != TsType()) { - etsg->ApplyConversion(this, TsType()); - } - } else if (!is_reference && callee_->IsIdentifier()) { - if (!is_static) { - etsg->LoadThis(this); - etsg->StoreAccumulator(this, callee_reg); - } - emit_call(); - } else if (!is_reference && callee_->IsMemberExpression()) { - if (!is_static) { - callee_->AsMemberExpression()->Object()->Compile(etsg); - etsg->StoreAccumulator(this, callee_reg); - } - emit_call(); - } else if (callee_->IsSuperExpression() || callee_->IsThisExpression()) { - ASSERT(!is_reference && IsETSConstructorCall()); - callee_->Compile(etsg); // ctor is not a value! - etsg->SetVRegType(callee_reg, etsg->GetAccumulatorType()); - emit_call(); - } else { - ASSERT(is_reference); - etsg->CompileAndCheck(callee_); - etsg->StoreAccumulator(this, callee_reg); - etsg->EmitMaybeOptional(this, emit_call, IsOptional()); - } + etsg->GetAstCompiler()->Compile(this); } checker::Type *CallExpression::Check(checker::TSChecker *checker) { - checker::Type *callee_type = callee_->Check(checker); - - // NOTE: aszilagyi. handle optional chain - if (callee_type->IsObjectType()) { - checker::ObjectType *callee_obj = callee_type->AsObjectType(); - return checker->ResolveCallOrNewExpression(callee_obj->CallSignatures(), arguments_, Start()); - } - - checker->ThrowTypeError("This expression is not callable.", Start()); - return nullptr; + return checker->GetAnalyzer()->Check(this); } bool CallExpression::IsETSConstructorCall() const @@ -367,170 +79,8 @@ bool CallExpression::IsETSConstructorCall() const return callee_->IsThisExpression() || callee_->IsSuperExpression(); } -checker::Signature *CallExpression::ResolveCallExtensionFunction(checker::ETSFunctionType *function_type, - checker::ETSChecker *checker) -{ - auto *member_expr = callee_->AsMemberExpression(); - arguments_.insert(arguments_.begin(), member_expr->Object()); - auto *signature = checker->ResolveCallExpressionAndTrailingLambda(function_type->CallSignatures(), this, Start()); - if (!signature->Function()->IsExtensionMethod()) { - checker->ThrowTypeError({"Property '", member_expr->Property()->AsIdentifier()->Name(), - "' does not exist on type '", member_expr->ObjType()->Name(), "'"}, - member_expr->Property()->Start()); - } - this->SetSignature(signature); - this->SetCallee(member_expr->Property()); - member_expr->Property()->AsIdentifier()->SetParent(this); - this->Arguments()[0]->SetParent(this); - checker->HandleUpdatedCallExpressionNode(this); - // Set TsType for new Callee(original member expression's Object) - this->Callee()->Check(checker); - return signature; -} - -checker::Signature *CallExpression::ResolveCallForETSExtensionFuncHelperType(checker::ETSExtensionFuncHelperType *type, - checker::ETSChecker *checker) -{ - checker::Signature *signature = checker->ResolveCallExpressionAndTrailingLambda( - type->ClassMethodType()->CallSignatures(), this, Start(), checker::TypeRelationFlag::NO_THROW); - - if (signature != nullptr) { - return signature; - } - - return ResolveCallExtensionFunction(type->ExtensionMethodType(), checker); -} - checker::Type *CallExpression::Check(checker::ETSChecker *checker) { - if (TsType() != nullptr) { - return TsType(); - } - auto *old_callee = callee_; - checker::Type *callee_type = callee_->Check(checker); - if (callee_ != old_callee) { - // If it is a static invoke, the callee will be transformed from an identifier to a member expression - // Type check the callee again for member expression - callee_type = callee_->Check(checker); - } - if (!IsOptional()) { - checker->CheckNonNullishType(callee_type, callee_->Start()); - } - checker::Type *return_type; - if (callee_type->IsETSDynamicType() && !callee_type->AsETSDynamicType()->HasDecl()) { - // Trailing lambda for js function call is not supported, check the correctness of `foo() {}` - checker->EnsureValidCurlyBrace(this); - auto lang = callee_type->AsETSDynamicType()->Language(); - signature_ = checker->ResolveDynamicCallExpression(callee_, arguments_, lang, false); - return_type = signature_->ReturnType(); - } else { - bool constructor_call = IsETSConstructorCall(); - bool functional_interface = - callee_type->IsETSObjectType() && - callee_type->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::FUNCTIONAL_INTERFACE); - bool ets_extension_func_helper_type = callee_type->IsETSExtensionFuncHelperType(); - bool extension_function_type = callee_->IsMemberExpression() && checker->ExtensionETSFunctionType(callee_type); - - if (callee_->IsArrowFunctionExpression()) { - callee_type = InitAnonymousLambdaCallee(checker, callee_, callee_type); - functional_interface = true; - } - - if (!functional_interface && !callee_type->IsETSFunctionType() && !constructor_call && - !ets_extension_func_helper_type) { - checker->ThrowTypeError("This expression is not callable.", Start()); - } - - checker::Signature *signature = nullptr; - - if (ets_extension_func_helper_type) { - signature = ResolveCallForETSExtensionFuncHelperType(callee_type->AsETSExtensionFuncHelperType(), checker); - } else { - if (extension_function_type) { - signature = ResolveCallExtensionFunction(callee_type->AsETSFunctionType(), checker); - } else { - auto &signatures = constructor_call ? callee_type->AsETSObjectType()->ConstructSignatures() - : functional_interface - ? callee_type->AsETSObjectType() - ->GetOwnProperty("invoke") - ->TsType() - ->AsETSFunctionType() - ->CallSignatures() - : callee_type->AsETSFunctionType()->CallSignatures(); - signature = checker->ResolveCallExpressionAndTrailingLambda(signatures, this, Start()); - if (signature->Function()->IsExtensionMethod()) { - checker->ThrowTypeError({"No matching call signature"}, Start()); - } - } - } - - checker->CheckObjectLiteralArguments(signature, arguments_); - - checker->AddUndefinedParamsForDefaultParams(signature, arguments_, checker); - - if (!functional_interface) { - checker::ETSObjectType *callee_obj {}; - if (constructor_call) { - callee_obj = callee_type->AsETSObjectType(); - } else if (callee_->IsIdentifier()) { - callee_obj = checker->Context().ContainingClass(); - } else { - ASSERT(callee_->IsMemberExpression()); - callee_obj = callee_->AsMemberExpression()->ObjType(); - } - - checker->ValidateSignatureAccessibility(callee_obj, signature, Start()); - } - - ASSERT(signature->Function() != nullptr); - - if (signature->Function()->IsThrowing() || signature->Function()->IsRethrowing()) { - checker->CheckThrowingStatements(this); - } - - if (signature->Function()->IsDynamic()) { - ASSERT(signature->Function()->IsDynamic()); - auto lang = signature->Function()->Language(); - signature_ = checker->ResolveDynamicCallExpression(callee_, signature->Params(), lang, false); - } else { - ASSERT(!signature->Function()->IsDynamic()); - signature_ = signature; - } - - return_type = signature->ReturnType(); - } - - if (signature_->RestVar() != nullptr) { - auto *const element_type = signature_->RestVar()->TsType()->AsETSArrayType()->ElementType(); - auto *const array_type = checker->CreateETSArrayType(element_type)->AsETSArrayType(); - checker->CreateBuiltinArraySignature(array_type, array_type->Rank()); - } - - if (signature_->HasSignatureFlag(checker::SignatureFlags::NEED_RETURN_TYPE)) { - signature_->OwnerVar()->Declaration()->Node()->Check(checker); - return_type = signature_->ReturnType(); - } - SetOptionalType(return_type); - if (IsOptional() && callee_type->IsNullishOrNullLike()) { - checker->Relation()->SetNode(this); - return_type = checker->CreateOptionalResultType(return_type); - checker->Relation()->SetNode(nullptr); - } - SetTsType(return_type); - return TsType(); -} - -checker::Type *CallExpression::InitAnonymousLambdaCallee(checker::ETSChecker *checker, Expression *callee, - checker::Type *callee_type) -{ - auto *const arrow_func = callee->AsArrowFunctionExpression()->Function(); - auto orig_params = arrow_func->Params(); - auto *func_type = checker->Allocator()->New( - arrow_func->Scope()->AsFunctionScope()->ParamScope(), std::move(orig_params), nullptr, - arrow_func->ReturnTypeAnnotation(), ir::ScriptFunctionFlags::NONE); - auto *const func_iface = func_type->Check(checker); - checker->Relation()->SetNode(callee); - checker->Relation()->IsAssignableTo(callee_type, func_iface); - return func_iface; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/expressions/callExpression.h b/ets2panda/ir/expressions/callExpression.h index d68ca9daca..a7ed295afc 100644 --- a/ets2panda/ir/expressions/callExpression.h +++ b/ets2panda/ir/expressions/callExpression.h @@ -21,9 +21,16 @@ #include "ir/expression.h" namespace panda::es2panda::checker { +class ETSAnalyzer; +class TSAnalyzer; class Signature; } // namespace panda::es2panda::checker +namespace panda::es2panda::compiler { +class JSCompiler; +class ETSCompiler; +} // namespace panda::es2panda::compiler + namespace panda::es2panda::ir { class TSTypeParameterInstantiation; @@ -39,6 +46,12 @@ public: { } + // TODO (csabahurton): these friend relationships can be removed once there are getters for private fields + friend class checker::TSAnalyzer; + friend class checker::ETSAnalyzer; + friend class compiler::JSCompiler; + friend class compiler::ETSCompiler; + const Expression *Callee() const { return callee_; @@ -122,18 +135,12 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - void Compile([[maybe_unused]] compiler::ETSGen *etsg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; - checker::Signature *ResolveCallExtensionFunction(checker::ETSFunctionType *function_type, - checker::ETSChecker *checker); - checker::Signature *ResolveCallForETSExtensionFuncHelperType(checker::ETSExtensionFuncHelperType *type, - checker::ETSChecker *checker); + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; protected: - compiler::VReg CreateSpreadArguments(compiler::PandaGen *pg) const; - // NOLINTBEGIN(misc-non-private-member-variables-in-classes) Expression *callee_; ArenaVector arguments_; @@ -149,7 +156,6 @@ private: bool IsETSConstructorCall() const; checker::Type *InitAnonymousLambdaCallee(checker::ETSChecker *checker, Expression *callee, checker::Type *callee_type); - void ConvertRestArguments(checker::ETSChecker *checker) const; }; } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/expressions/chainExpression.cpp b/ets2panda/ir/expressions/chainExpression.cpp index ce71eac838..c2987762ee 100644 --- a/ets2panda/ir/expressions/chainExpression.cpp +++ b/ets2panda/ir/expressions/chainExpression.cpp @@ -15,12 +15,11 @@ #include "chainExpression.h" -#include "ir/expressions/callExpression.h" -#include "ir/expressions/memberExpression.h" -#include "compiler/base/optionalChain.h" -#include "compiler/core/regScope.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" #include "compiler/core/pandagen.h" #include "ir/astDump.h" +#include "ir/expressions/memberExpression.h" namespace panda::es2panda::ir { void ChainExpression::TransformChildren(const NodeTransformer &cb) @@ -38,10 +37,9 @@ 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(compiler::PandaGen *pg) const { - compiler::OptionalChain chain(pg, this); - expression_->Compile(pg); + pg->GetAstCompiler()->Compile(this); } void ChainExpression::CompileToReg(compiler::PandaGen *pg, compiler::VReg &obj_reg) const @@ -57,14 +55,19 @@ void ChainExpression::CompileToReg(compiler::PandaGen *pg, compiler::VReg &obj_r } } -checker::Type *ChainExpression::Check([[maybe_unused]] checker::TSChecker *checker) +void ChainExpression::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} + +checker::Type *ChainExpression::Check(checker::TSChecker *checker) { - return expression_->Check(checker); + return checker->GetAnalyzer()->Check(this); } -checker::Type *ChainExpression::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *ChainExpression::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } // NOLINTNEXTLINE(google-default-arguments) diff --git a/ets2panda/ir/expressions/chainExpression.h b/ets2panda/ir/expressions/chainExpression.h index 252ece9500..a54d632b09 100644 --- a/ets2panda/ir/expressions/chainExpression.h +++ b/ets2panda/ir/expressions/chainExpression.h @@ -19,6 +19,10 @@ #include "ir/expression.h" #include "ir/irnode.h" +namespace panda::es2panda::checker { +class TSAnalyzer; +} // namespace panda::es2panda::checker + namespace panda::es2panda::ir { class ChainExpression : public Expression { public: @@ -33,6 +37,9 @@ public: { } + // TODO (csabahurton): friend relationship can be removed once there are getters for private fields + friend class checker::TSAnalyzer; + const Expression *GetExpression() const noexcept { return expression_; @@ -44,10 +51,11 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; void CompileToReg(compiler::PandaGen *pg, compiler::VReg &obj_reg) const; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: Expression *expression_; diff --git a/ets2panda/ir/expressions/classExpression.cpp b/ets2panda/ir/expressions/classExpression.cpp index ecefc3a8fa..394625e52d 100644 --- a/ets2panda/ir/expressions/classExpression.cpp +++ b/ets2panda/ir/expressions/classExpression.cpp @@ -15,8 +15,10 @@ #include "classExpression.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "ir/astDump.h" -#include "ir/base/classDefinition.h" namespace panda::es2panda::ir { void ClassExpression::TransformChildren(const NodeTransformer &cb) @@ -34,18 +36,23 @@ void ClassExpression::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "ClassExpression"}, {"definition", def_}}); } -void ClassExpression::Compile([[maybe_unused]] compiler::PandaGen *pg) const +void ClassExpression::Compile(compiler::PandaGen *pg) const { - def_->Compile(pg); + pg->GetAstCompiler()->Compile(this); } -checker::Type *ClassExpression::Check([[maybe_unused]] checker::TSChecker *checker) +void ClassExpression::Compile(compiler::ETSGen *etsg) const { - return nullptr; + etsg->GetAstCompiler()->Compile(this); } -checker::Type *ClassExpression::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *ClassExpression::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); +} + +checker::Type *ClassExpression::Check(checker::ETSChecker *checker) +{ + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/expressions/classExpression.h b/ets2panda/ir/expressions/classExpression.h index 1ab8e4a09c..168b3fac74 100644 --- a/ets2panda/ir/expressions/classExpression.h +++ b/ets2panda/ir/expressions/classExpression.h @@ -33,9 +33,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: ClassDefinition *def_; diff --git a/ets2panda/ir/expressions/conditionalExpression.cpp b/ets2panda/ir/expressions/conditionalExpression.cpp index b60d48679a..aab68ac2b8 100644 --- a/ets2panda/ir/expressions/conditionalExpression.cpp +++ b/ets2panda/ir/expressions/conditionalExpression.cpp @@ -15,11 +15,9 @@ #include "conditionalExpression.h" -#include "compiler/base/condition.h" +#include "checker/TSchecker.h" #include "compiler/core/pandagen.h" #include "compiler/core/ETSGen.h" -#include "checker/TSchecker.h" -#include "ir/astDump.h" namespace panda::es2panda::ir { void ConditionalExpression::TransformChildren(const NodeTransformer &cb) @@ -42,111 +40,24 @@ void ConditionalExpression::Dump(ir::AstDumper *dumper) const {{"type", "ConditionalExpression"}, {"test", test_}, {"consequent", consequent_}, {"alternate", alternate_}}); } -template -void CompileImpl(const ConditionalExpression *self, CodeGen *cg) -{ - auto *false_label = cg->AllocLabel(); - auto *end_label = cg->AllocLabel(); - - compiler::Condition::Compile(cg, self->Test(), false_label); - self->Consequent()->Compile(cg); - cg->Branch(self, end_label); - cg->SetLabel(self, false_label); - self->Alternate()->Compile(cg); - cg->SetLabel(self, end_label); -} - void ConditionalExpression::Compile(compiler::PandaGen *pg) const { - CompileImpl(this, pg); + pg->GetAstCompiler()->Compile(this); } void ConditionalExpression::Compile(compiler::ETSGen *etsg) const { - auto *false_label = etsg->AllocLabel(); - auto *end_label = etsg->AllocLabel(); - - compiler::Condition::Compile(etsg, Test(), false_label); - - auto ttctx = compiler::TargetTypeContext(etsg, TsType()); - - Consequent()->Compile(etsg); - etsg->ApplyConversion(Consequent()); - etsg->Branch(this, end_label); - etsg->SetLabel(this, false_label); - Alternate()->Compile(etsg); - etsg->ApplyConversion(Alternate()); - etsg->SetLabel(this, end_label); - etsg->SetAccumulatorType(TsType()); + etsg->GetAstCompiler()->Compile(this); } checker::Type *ConditionalExpression::Check(checker::TSChecker *checker) { - checker::Type *test_type = test_->Check(checker); - - checker->CheckTruthinessOfType(test_type, test_->Start()); - checker->CheckTestingKnownTruthyCallableOrAwaitableType(test_, test_type, consequent_); - - checker::Type *consequent_type = consequent_->Check(checker); - checker::Type *alternate_type = alternate_->Check(checker); - - return checker->CreateUnionType({consequent_type, alternate_type}); + return checker->GetAnalyzer()->Check(this); } checker::Type *ConditionalExpression::Check(checker::ETSChecker *checker) { - if (TsType() != nullptr) { - return TsType(); - } - - checker->CheckTruthinessOfType(test_); - - checker::Type *consequent_type = consequent_->Check(checker); - checker::Type *alternate_type = alternate_->Check(checker); - - auto *primitive_consequent_type = checker->ETSBuiltinTypeAsPrimitiveType(consequent_type); - auto *primitive_alter_type = checker->ETSBuiltinTypeAsPrimitiveType(alternate_type); - - if (primitive_consequent_type != nullptr && primitive_alter_type != nullptr) { - if (checker->IsTypeIdenticalTo(consequent_type, alternate_type)) { - SetTsType(checker->GetNonConstantTypeFromPrimitiveType(consequent_type)); - } else if (checker->IsTypeIdenticalTo(primitive_consequent_type, primitive_alter_type)) { - checker->FlagExpressionWithUnboxing(consequent_->TsType(), primitive_consequent_type, consequent_); - checker->FlagExpressionWithUnboxing(alternate_->TsType(), primitive_alter_type, alternate_); - - SetTsType(primitive_consequent_type); - } else if (primitive_consequent_type->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC) && - primitive_alter_type->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC)) { - checker->FlagExpressionWithUnboxing(consequent_->TsType(), primitive_consequent_type, consequent_); - checker->FlagExpressionWithUnboxing(alternate_->TsType(), primitive_alter_type, alternate_); - - SetTsType( - checker->ApplyConditionalOperatorPromotion(checker, primitive_consequent_type, primitive_alter_type)); - } else { - checker->ThrowTypeError("Type error", this->range_.start); - } - } else { - if (!(consequent_type->IsETSArrayType() || alternate_type->IsETSArrayType()) && - !(consequent_type->IsETSObjectType() && alternate_type->IsETSObjectType())) { - checker->ThrowTypeError("Type error", this->range_.start); - } else { - checker->Relation()->SetNode(consequent_); - auto builtin_conseq_type = checker->PrimitiveTypeAsETSBuiltinType(consequent_type); - auto builtin_alternate_type = checker->PrimitiveTypeAsETSBuiltinType(alternate_type); - - if (builtin_conseq_type == nullptr) { - builtin_conseq_type = consequent_type; - } - - if (builtin_alternate_type == nullptr) { - builtin_alternate_type = alternate_type; - } - - SetTsType(checker->FindLeastUpperBound(builtin_conseq_type, builtin_alternate_type)); - } - } - - return TsType(); + return checker->GetAnalyzer()->Check(this); } // NOLINTNEXTLINE(google-default-arguments) diff --git a/ets2panda/ir/expressions/conditionalExpression.h b/ets2panda/ir/expressions/conditionalExpression.h index 8e0e7a10d8..77ca2e883e 100644 --- a/ets2panda/ir/expressions/conditionalExpression.h +++ b/ets2panda/ir/expressions/conditionalExpression.h @@ -18,6 +18,11 @@ #include "ir/expression.h" +namespace panda::es2panda::checker { +class TSAnalyzer; +class ETSAnalyzer; +} // namespace panda::es2panda::checker + namespace panda::es2panda::ir { class ConditionalExpression : public Expression { public: @@ -32,6 +37,10 @@ public: { } + // TODO (csabahurton): these friend relationships can be removed once there are getters for private fields + friend class checker::TSAnalyzer; + friend class checker::ETSAnalyzer; + [[nodiscard]] const Expression *Test() const noexcept { return test_; diff --git a/ets2panda/ir/expressions/directEvalExpression.cpp b/ets2panda/ir/expressions/directEvalExpression.cpp index 356301fb15..95cb09e367 100644 --- a/ets2panda/ir/expressions/directEvalExpression.cpp +++ b/ets2panda/ir/expressions/directEvalExpression.cpp @@ -17,36 +17,29 @@ #include "directEvalExpression.h" -#include "util/helpers.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" #include "compiler/core/pandagen.h" -#include "compiler/core/regScope.h" namespace panda::es2panda::ir { void DirectEvalExpression::Compile(compiler::PandaGen *pg) const { - if (arguments_.empty()) { - pg->LoadConst(this, compiler::Constant::JS_UNDEFINED); - return; - } - - compiler::RegScope rs(pg); - bool contains_spread = util::Helpers::ContainSpreadElement(arguments_); - if (contains_spread) { - [[maybe_unused]] compiler::VReg args_obj = CreateSpreadArguments(pg); - pg->LoadObjByIndex(this, 0); - } else { - compiler::VReg arg0 = pg->AllocReg(); - auto iter = arguments_.cbegin(); - (*iter++)->Compile(pg); - pg->StoreAccumulator(this, arg0); - - while (iter != arguments_.cend()) { - (*iter++)->Compile(pg); - } - - pg->LoadAccumulator(this, arg0); - } - - pg->DirectEval(this, parser_status_); + pg->GetAstCompiler()->Compile(this); } + +void DirectEvalExpression::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} + +checker::Type *DirectEvalExpression::Check(checker::TSChecker *checker) +{ + return checker->GetAnalyzer()->Check(this); +} + +checker::Type *DirectEvalExpression::Check(checker::ETSChecker *checker) +{ + return checker->GetAnalyzer()->Check(this); +} + } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/expressions/directEvalExpression.h b/ets2panda/ir/expressions/directEvalExpression.h index eca1913339..33c9d6ec03 100644 --- a/ets2panda/ir/expressions/directEvalExpression.h +++ b/ets2panda/ir/expressions/directEvalExpression.h @@ -16,6 +16,10 @@ #ifndef ES2PANDA_IR_EXPRESSION_DIRECT_EVAL_H #define ES2PANDA_IR_EXPRESSION_DIRECT_EVAL_H +namespace panda::es2panda::compiler { +class JSCompiler; +} // namespace panda::es2panda::compiler + #include "ir/expressions/callExpression.h" namespace panda::es2panda::ir { @@ -28,7 +32,13 @@ public: type_ = AstNodeType::DIRECT_EVAL; } - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; + // TODO (csabahurton): friend relationship can be removed once there are getters for private fields + friend class compiler::JSCompiler; + + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: uint32_t parser_status_ {}; diff --git a/ets2panda/ir/expressions/functionExpression.cpp b/ets2panda/ir/expressions/functionExpression.cpp index 7f9c194231..01f1f4b68c 100644 --- a/ets2panda/ir/expressions/functionExpression.cpp +++ b/ets2panda/ir/expressions/functionExpression.cpp @@ -15,13 +15,10 @@ #include "functionExpression.h" -#include "compiler/core/pandagen.h" -#include "compiler/core/ETSGen.h" #include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "ir/astDump.h" -#include "ir/base/scriptFunction.h" -#include "ir/expressions/identifier.h" -#include "ir/statements/variableDeclarator.h" namespace panda::es2panda::ir { void FunctionExpression::TransformChildren(const NodeTransformer &cb) @@ -41,45 +38,21 @@ void FunctionExpression::Dump(ir::AstDumper *dumper) const void FunctionExpression::Compile(compiler::PandaGen *pg) const { - pg->DefineFunction(func_, func_, func_->Scope()->InternalName()); + pg->GetAstCompiler()->Compile(this); } -void FunctionExpression::Compile([[maybe_unused]] compiler::ETSGen *etsg) const +void FunctionExpression::Compile(compiler::ETSGen *etsg) const { - UNREACHABLE(); + etsg->GetAstCompiler()->Compile(this); } checker::Type *FunctionExpression::Check(checker::TSChecker *checker) { - varbinder::Variable *func_var = nullptr; - - if (func_->Parent()->Parent() != nullptr && func_->Parent()->Parent()->IsVariableDeclarator() && - func_->Parent()->Parent()->AsVariableDeclarator()->Id()->IsIdentifier()) { - func_var = func_->Parent()->Parent()->AsVariableDeclarator()->Id()->AsIdentifier()->Variable(); - } - - checker::ScopeContext scope_ctx(checker, func_->Scope()); - - auto *signature_info = checker->Allocator()->New(checker->Allocator()); - checker->CheckFunctionParameterDeclarations(func_->Params(), signature_info); - - auto *signature = - checker->Allocator()->New(signature_info, checker->GlobalResolvingReturnType(), func_); - checker::Type *func_type = checker->CreateFunctionTypeWithSignature(signature); - - if (func_var != nullptr && func_var->TsType() == nullptr) { - func_var->SetTsType(func_type); - } - - signature->SetReturnType(checker->HandleFunctionReturn(func_)); - - func_->Body()->Check(checker); - - return func_type; + return checker->GetAnalyzer()->Check(this); } checker::Type *FunctionExpression::Check([[maybe_unused]] checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/expressions/functionExpression.h b/ets2panda/ir/expressions/functionExpression.h index 4b21918578..1e858ac12a 100644 --- a/ets2panda/ir/expressions/functionExpression.h +++ b/ets2panda/ir/expressions/functionExpression.h @@ -38,10 +38,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; + void Compile(compiler::PandaGen *pg) const override; void Compile(compiler::ETSGen *etsg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: ScriptFunction *func_; diff --git a/ets2panda/ir/expressions/memberExpression.cpp b/ets2panda/ir/expressions/memberExpression.cpp index 44936411de..2387690888 100644 --- a/ets2panda/ir/expressions/memberExpression.cpp +++ b/ets2panda/ir/expressions/memberExpression.cpp @@ -15,24 +15,9 @@ #include "memberExpression.h" -#include "checker/types/typeRelation.h" #include "compiler/core/pandagen.h" #include "compiler/core/ETSGen.h" -#include "compiler/core/function.h" #include "checker/TSchecker.h" -#include "checker/ETSchecker.h" -#include "checker/types/ets/etsExtensionFuncHelperType.h" -#include "checker/types/ets/etsFunctionType.h" -#include "checker/types/signature.h" -#include "ir/astDump.h" -#include "ir/base/methodDefinition.h" -#include "ir/base/scriptFunction.h" -#include "ir/expressions/callExpression.h" -#include "ir/expressions/identifier.h" -#include "ir/expressions/literals/numberLiteral.h" -#include "ir/expressions/literals/stringLiteral.h" -#include "ir/ts/tsEnumMember.h" -#include "util/helpers.h" namespace panda::es2panda::ir { MemberExpression::MemberExpression([[maybe_unused]] Tag const tag, Expression *const object, Expression *const property) -- Gitee From a094910dd17aaf86e4f9c7acbb699c8016acb605 Mon Sep 17 00:00:00 2001 From: Csaba Hurton Date: Mon, 30 Oct 2023 11:31:25 +0100 Subject: [PATCH 6/6] Move Check and Compile methods to Compiler and Analyzer classes Round #2 Linked Internal Issue 13840 Change-Id: Iaec45fa3bc146455534e9682f40901465345254a Signed-off-by: Csaba Hurton --- ets2panda/checker/ETSAnalyzer.cpp | 219 ++++++++++++++++-- ets2panda/checker/ETSAnalyzer.h | 1 + ets2panda/checker/TSAnalyzer.cpp | 103 ++++++-- ets2panda/checker/TSAnalyzer.h | 6 +- ets2panda/compiler/core/ETSCompiler.cpp | 25 +- ets2panda/compiler/core/JSCompiler.cpp | 33 +-- ets2panda/ir/base/metaProperty.cpp | 29 +-- ets2panda/ir/base/metaProperty.h | 7 +- ets2panda/ir/base/methodDefinition.cpp | 214 +---------------- ets2panda/ir/base/methodDefinition.h | 23 +- ets2panda/ir/base/property.cpp | 29 +-- ets2panda/ir/base/property.h | 7 +- ets2panda/ir/base/scriptFunction.cpp | 26 +-- ets2panda/ir/base/scriptFunction.h | 8 +- ets2panda/ir/base/templateElement.cpp | 25 +- ets2panda/ir/base/templateElement.h | 8 +- ets2panda/ir/base/tsIndexSignature.cpp | 41 ++-- ets2panda/ir/base/tsIndexSignature.h | 13 +- ets2panda/ir/base/tsMethodSignature.cpp | 43 ++-- ets2panda/ir/base/tsMethodSignature.h | 15 +- ets2panda/ir/base/tsPropertySignature.cpp | 35 ++- ets2panda/ir/base/tsPropertySignature.h | 7 +- ets2panda/ir/expressions/binaryExpression.cpp | 6 +- ets2panda/ir/ts/tsEnumDeclaration.cpp | 6 +- 24 files changed, 478 insertions(+), 451 deletions(-) diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 25d05c22a8..bda5e9b47f 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -118,27 +118,216 @@ checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::Decorator *st) const UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::MetaProperty *expr) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::MetaProperty *expr) const { - (void)expr; UNREACHABLE(); } +static void CheckExtensionIsShadowedInCurrentClassOrInterface(checker::ETSChecker *checker, + checker::ETSObjectType *obj_type, + ir::ScriptFunction *extension_func, + checker::Signature *signature) +{ + const auto method_name = extension_func->Id()->Name(); + // Only check if there are class and interfaces' instance methods which would shadow instance extension method + auto *const variable = obj_type->GetOwnProperty(method_name); + if (variable == nullptr) { + return; + } + + const auto *const func_type = variable->TsType()->AsETSFunctionType(); + for (auto *func_signature : func_type->CallSignatures()) { + signature->SetReturnType(func_signature->ReturnType()); + if (!checker->Relation()->IsIdenticalTo(signature, func_signature)) { + continue; + } + + checker->ReportWarning({"extension is shadowed by a instance member function '", func_type->Name(), + func_signature, "' in class ", obj_type->Name()}, + extension_func->Body()->Start()); + return; + } +} + +static void CheckExtensionIsShadowedByMethod(checker::ETSChecker *checker, checker::ETSObjectType *obj_type, + ir::ScriptFunction *extension_func, checker::Signature *signature) +{ + if (obj_type == nullptr) { + return; + } + + CheckExtensionIsShadowedInCurrentClassOrInterface(checker, obj_type, extension_func, signature); + + for (auto *interface : obj_type->Interfaces()) { + CheckExtensionIsShadowedByMethod(checker, interface, extension_func, signature); + } + + CheckExtensionIsShadowedByMethod(checker, obj_type->SuperType(), extension_func, signature); +} + +static void CheckExtensionMethod(checker::ETSChecker *checker, ir::ScriptFunction *extension_func, + ir::MethodDefinition *node) +{ + auto *const class_type = extension_func->Signature()->Params()[0]->TsType(); + if (!class_type->IsETSObjectType() || + (!class_type->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::CLASS) && + !class_type->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::INTERFACE))) { + checker->ThrowTypeError("Extension function can only defined for class and interface type.", node->Start()); + } + + checker->AddStatus(checker::CheckerStatus::IN_INSTANCE_EXTENSION_METHOD); + + checker::SignatureInfo *original_extension_sig_info = checker->Allocator()->New( + extension_func->Signature()->GetSignatureInfo(), checker->Allocator()); + original_extension_sig_info->min_arg_count -= 1; + original_extension_sig_info->params.erase(original_extension_sig_info->params.begin()); + checker::Signature *original_extension_sigature = checker->CreateSignature( + original_extension_sig_info, extension_func->Signature()->ReturnType(), extension_func); + + CheckExtensionIsShadowedByMethod(checker, class_type->AsETSObjectType(), extension_func, + original_extension_sigature); +} + checker::Type *ETSAnalyzer::Check(ir::MethodDefinition *node) const { - (void)node; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + auto *script_func = node->Function(); + + if (script_func->IsProxy()) { + return nullptr; + } + + // NOTE: aszilagyi. make it correctly check for open function not have body + if (!script_func->HasBody() && !(node->IsAbstract() || node->IsNative() || node->IsDeclare() || + checker->HasStatus(checker::CheckerStatus::IN_INTERFACE))) { + checker->ThrowTypeError("Only abstract or native methods can't have body.", script_func->Start()); + } + + if (script_func->ReturnTypeAnnotation() == nullptr && + (node->IsNative() || (node->IsDeclare() && !node->IsConstructor()))) { + checker->ThrowTypeError("Native and Declare methods should have explicit return type.", script_func->Start()); + } + + if (node->TsType() == nullptr) { + node->SetTsType(checker->BuildMethodSignature(node)); + } + + this->CheckMethodModifiers(node); + + if (node->IsNative() && script_func->ReturnTypeAnnotation() == nullptr) { + checker->ThrowTypeError("'Native' method should have explicit return type", script_func->Start()); + } + + if (node->IsNative() && (script_func->IsGetter() || script_func->IsSetter())) { + checker->ThrowTypeError("'Native' modifier is invalid for Accessors", script_func->Start()); + } + + if (script_func->HasBody() && (node->IsNative() || node->IsAbstract() || node->IsDeclare())) { + checker->ThrowTypeError("Native, Abstract and Declare methods cannot have body.", script_func->Body()->Start()); + } + + if (script_func->IsAsyncFunc()) { + auto *ret_type = static_cast(script_func->Signature()->ReturnType()); + if (ret_type->AssemblerName() != checker->GlobalBuiltinPromiseType()->AssemblerName()) { + checker->ThrowTypeError("Return type of async function must be 'Promise'.", script_func->Start()); + } + } else if (script_func->HasBody() && !script_func->IsExternal()) { + checker::ScopeContext scope_ctx(checker, script_func->Scope()); + checker::SavedCheckerContext saved_context(checker, checker->Context().Status(), + checker->Context().ContainingClass()); + checker->Context().SetContainingSignature(checker->GetSignatureFromMethodDefinition(node)); + + if (node->IsStatic() && !node->IsConstructor() && + !checker->Context().ContainingClass()->HasObjectFlag(checker::ETSObjectFlags::GLOBAL)) { + checker->AddStatus(checker::CheckerStatus::IN_STATIC_CONTEXT); + } + + if (node->IsConstructor()) { + checker->AddStatus(checker::CheckerStatus::IN_CONSTRUCTOR); + } + + if (node->IsExtensionMethod()) { + CheckExtensionMethod(checker, script_func, node); + } + + script_func->Body()->Check(checker); + + // In case of inferred function's return type set it forcedly to all return statements; + if (script_func->Signature()->HasSignatureFlag(checker::SignatureFlags::INFERRED_RETURN_TYPE) && + script_func->ReturnTypeAnnotation() == nullptr && script_func->Body() != nullptr && + script_func->Body()->IsStatement()) { + script_func->Body()->AsStatement()->SetReturnType(checker, script_func->Signature()->ReturnType()); + } + + checker->Context().SetContainingSignature(nullptr); + } + + if (script_func->IsSetter() && (script_func->Signature()->ReturnType() != checker->GlobalBuiltinVoidType())) { + checker->ThrowTypeError("Setter must have void return type", script_func->Start()); + } + + if (script_func->IsGetter() && (script_func->Signature()->ReturnType() == checker->GlobalBuiltinVoidType())) { + checker->ThrowTypeError("Getter must return a value", script_func->Start()); + } + + checker->CheckOverride(node->TsType()->AsETSFunctionType()->FindSignature(node->Function())); + + for (auto *it : node->Overloads()) { + it->Check(checker); + } + + if (script_func->IsRethrowing()) { + checker->CheckRethrowingFunction(script_func); + } + + return node->TsType(); } -checker::Type *ETSAnalyzer::Check(ir::Property *expr) const +void ETSAnalyzer::CheckMethodModifiers(ir::MethodDefinition *node) const +{ + ETSChecker *checker = GetETSChecker(); + auto const not_valid_in_abstract = ir::ModifierFlags::NATIVE | ir::ModifierFlags::PRIVATE | + ir::ModifierFlags::OVERRIDE | ir::ModifierFlags::FINAL | + ir::ModifierFlags::STATIC; + + if (node->IsAbstract() && (node->flags_ & not_valid_in_abstract) != 0U) { + checker->ThrowTypeError( + "Invalid method modifier(s): an abstract method can't have private, override, static, final or native " + "modifier.", + node->Start()); + } + + if ((node->IsAbstract() || (!node->Function()->HasBody() && !node->IsNative() && !node->IsDeclare())) && + !(checker->HasStatus(checker::CheckerStatus::IN_ABSTRACT) || + checker->HasStatus(checker::CheckerStatus::IN_INTERFACE))) { + checker->ThrowTypeError("Non abstract class has abstract method.", node->Start()); + } + + auto const not_valid_in_final = ir::ModifierFlags::ABSTRACT | ir::ModifierFlags::STATIC | ir::ModifierFlags::NATIVE; + + if (node->IsFinal() && (node->flags_ & not_valid_in_final) != 0U) { + checker->ThrowTypeError( + "Invalid method modifier(s): a final method can't have abstract, static or native modifier.", + node->Start()); + } + + auto const not_valid_in_static = + ir::ModifierFlags::ABSTRACT | ir::ModifierFlags::FINAL | ir::ModifierFlags::OVERRIDE; + + if (node->IsStatic() && (node->flags_ & not_valid_in_static) != 0U) { + checker->ThrowTypeError( + "Invalid method modifier(s): a static method can't have abstract, final or override modifier.", + node->Start()); + } +} + +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::Property *expr) const { - (void)expr; UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::ScriptFunction *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ScriptFunction *node) const { - (void)node; UNREACHABLE(); } @@ -150,25 +339,23 @@ checker::Type *ETSAnalyzer::Check(ir::SpreadElement *expr) const checker::Type *ETSAnalyzer::Check(ir::TemplateElement *expr) const { - (void)expr; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + expr->SetTsType(checker->CreateETSStringLiteralType(expr->Raw())); + return expr->TsType(); } -checker::Type *ETSAnalyzer::Check(ir::TSIndexSignature *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSIndexSignature *node) const { - (void)node; UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSMethodSignature *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSMethodSignature *node) const { - (void)node; UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSPropertySignature *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSPropertySignature *node) const { - (void)node; UNREACHABLE(); } diff --git a/ets2panda/checker/ETSAnalyzer.h b/ets2panda/checker/ETSAnalyzer.h index de2b57cc58..0fcf2540f4 100644 --- a/ets2panda/checker/ETSAnalyzer.h +++ b/ets2panda/checker/ETSAnalyzer.h @@ -37,6 +37,7 @@ public: private: ETSChecker *GetETSChecker() const; + void CheckMethodModifiers(ir::MethodDefinition *node) const; }; } // namespace panda::es2panda::checker diff --git a/ets2panda/checker/TSAnalyzer.cpp b/ets2panda/checker/TSAnalyzer.cpp index ddcc6a2db9..d8ab78500e 100644 --- a/ets2panda/checker/TSAnalyzer.cpp +++ b/ets2panda/checker/TSAnalyzer.cpp @@ -78,27 +78,25 @@ checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::Decorator *st) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::MetaProperty *expr) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::MetaProperty *expr) const { - (void)expr; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + // NOTE: aszilagyi. + return checker->GlobalAnyType(); } -checker::Type *TSAnalyzer::Check(ir::MethodDefinition *node) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::MethodDefinition *node) const { - (void)node; UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::Property *expr) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::Property *expr) const { - (void)expr; UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::ScriptFunction *node) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ScriptFunction *node) const { - (void)node; UNREACHABLE(); } @@ -108,28 +106,81 @@ checker::Type *TSAnalyzer::Check(ir::SpreadElement *expr) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::TemplateElement *expr) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TemplateElement *expr) const { - (void)expr; UNREACHABLE(); } checker::Type *TSAnalyzer::Check(ir::TSIndexSignature *node) const { - (void)node; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + if (node->TsType() != nullptr) { + return node->TsType(); + } + + const util::StringView ¶m_name = node->Param()->AsIdentifier()->Name(); + node->type_annotation_->Check(checker); + checker::Type *index_type = node->type_annotation_->GetType(checker); + checker::IndexInfo *info = + checker->Allocator()->New(index_type, param_name, node->Readonly(), node->Start()); + checker::ObjectDescriptor *desc = checker->Allocator()->New(checker->Allocator()); + checker::ObjectType *placeholder = checker->Allocator()->New(desc); + + if (node->Kind() == ir::TSIndexSignature::TSIndexSignatureKind::NUMBER) { + placeholder->Desc()->number_index_info = info; + } else { + placeholder->Desc()->string_index_info = info; + } + + node->SetTsType(placeholder); + return placeholder; } checker::Type *TSAnalyzer::Check(ir::TSMethodSignature *node) const { - (void)node; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + if (node->Computed()) { + checker->CheckComputedPropertyName(node->Key()); + } + + checker::ScopeContext scope_ctx(checker, node->Scope()); + + auto *signature_info = checker->Allocator()->New(checker->Allocator()); + checker->CheckFunctionParameterDeclarations(node->Params(), signature_info); + + auto *call_signature = checker->Allocator()->New(signature_info, checker->GlobalAnyType()); + node->Variable()->SetTsType(checker->CreateFunctionTypeWithSignature(call_signature)); + + if (node->ReturnTypeAnnotation() == nullptr) { + checker->ThrowTypeError( + "Method signature, which lacks return-type annotation, implicitly has an 'any' return type.", + node->Start()); + } + + node->return_type_annotation_->Check(checker); + call_signature->SetReturnType(node->return_type_annotation_->GetType(checker)); + + return nullptr; } checker::Type *TSAnalyzer::Check(ir::TSPropertySignature *node) const { - (void)node; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + if (node->TypeAnnotation() != nullptr) { + node->TypeAnnotation()->Check(checker); + } + + if (node->Computed()) { + checker->CheckComputedPropertyName(node->Key()); + } + + if (node->TypeAnnotation() != nullptr) { + node->Variable()->SetTsType(node->TypeAnnotation()->GetType(checker)); + return nullptr; + } + + checker->ThrowTypeError("Property implicitly has an 'any' type.", node->Start()); + return nullptr; } checker::Type *TSAnalyzer::Check(ir::TSSignatureDeclaration *node) const @@ -895,7 +946,7 @@ checker::Type *TSAnalyzer::Check(ir::TSConstructorType *node) const } static varbinder::EnumMemberResult EvaluateIdentifier(checker::TSChecker *checker, varbinder::EnumVariable *enum_var, - const ir::Identifier *expr) + const ir::Identifier *expr) { if (expr->Name() == "NaN") { return std::nan(""); @@ -950,8 +1001,8 @@ static uint32_t ToUInt(double num) } varbinder::EnumMemberResult TSAnalyzer::EvaluateBinaryExpression(checker::TSChecker *checker, - varbinder::EnumVariable *enum_var, - const ir::BinaryExpression *expr) const + varbinder::EnumVariable *enum_var, + const ir::BinaryExpression *expr) const { varbinder::EnumMemberResult left = EvaluateEnumMember(checker, enum_var, expr->AsBinaryExpression()->Left()); varbinder::EnumMemberResult right = EvaluateEnumMember(checker, enum_var, expr->AsBinaryExpression()->Right()); @@ -1014,8 +1065,8 @@ varbinder::EnumMemberResult TSAnalyzer::EvaluateBinaryExpression(checker::TSChec } varbinder::EnumMemberResult TSAnalyzer::EvaluateUnaryExpression(checker::TSChecker *checker, - varbinder::EnumVariable *enum_var, - const ir::UnaryExpression *expr) const + varbinder::EnumVariable *enum_var, + const ir::UnaryExpression *expr) const { varbinder::EnumMemberResult value = EvaluateEnumMember(checker, enum_var, expr->Argument()); if (!std::holds_alternative(value)) { @@ -1040,8 +1091,9 @@ varbinder::EnumMemberResult TSAnalyzer::EvaluateUnaryExpression(checker::TSCheck return false; } -varbinder::EnumMemberResult TSAnalyzer::EvaluateEnumMember(checker::TSChecker *checker, varbinder::EnumVariable *enum_var, - const ir::AstNode *expr) const +varbinder::EnumMemberResult TSAnalyzer::EvaluateEnumMember(checker::TSChecker *checker, + varbinder::EnumVariable *enum_var, + const ir::AstNode *expr) const { switch (expr->Type()) { case ir::AstNodeType::UNARY_EXPRESSION: { @@ -1197,7 +1249,8 @@ checker::Type *TSAnalyzer::InferType(checker::TSChecker *checker, bool is_const, for (size_t i = 0; i < locals_size; i++) { const util::StringView ¤t_name = enum_scope->Decls()[i]->Name(); - varbinder::Variable *current_var = enum_scope->FindLocal(current_name, varbinder::ResolveBindingOptions::BINDINGS); + varbinder::Variable *current_var = + enum_scope->FindLocal(current_name, varbinder::ResolveBindingOptions::BINDINGS); ASSERT(current_var && current_var->IsEnumVariable()); InferEnumVariableType(checker, current_var->AsEnumVariable(), &value, &init_next, &is_literal_enum, is_const, computed_expr); diff --git a/ets2panda/checker/TSAnalyzer.h b/ets2panda/checker/TSAnalyzer.h index 9696cc5156..b99a5d18aa 100644 --- a/ets2panda/checker/TSAnalyzer.h +++ b/ets2panda/checker/TSAnalyzer.h @@ -38,11 +38,11 @@ private: TSChecker *GetTSChecker() const; varbinder::EnumMemberResult EvaluateBinaryExpression(checker::TSChecker *checker, varbinder::EnumVariable *enum_var, - const ir::BinaryExpression *expr) const; + const ir::BinaryExpression *expr) const; varbinder::EnumMemberResult EvaluateEnumMember(checker::TSChecker *checker, varbinder::EnumVariable *enum_var, - const ir::AstNode *expr) const; + const ir::AstNode *expr) const; varbinder::EnumMemberResult EvaluateUnaryExpression(checker::TSChecker *checker, varbinder::EnumVariable *enum_var, - const ir::UnaryExpression *expr) const; + const ir::UnaryExpression *expr) const; void InferEnumVariableType(checker::TSChecker *checker, varbinder::EnumVariable *variable, double *value, bool *init_next, bool *is_literal_enum, bool is_const_enum, const ir::Expression *computed_expr) const; diff --git a/ets2panda/compiler/core/ETSCompiler.cpp b/ets2panda/compiler/core/ETSCompiler.cpp index 2f7a58772e..63a13ac862 100644 --- a/ets2panda/compiler/core/ETSCompiler.cpp +++ b/ets2panda/compiler/core/ETSCompiler.cpp @@ -87,27 +87,23 @@ void ETSCompiler::Compile([[maybe_unused]] const ir::Decorator *st) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::MetaProperty *expr) const +void ETSCompiler::Compile([[maybe_unused]] const ir::MetaProperty *expr) const { - (void)expr; UNREACHABLE(); } -void ETSCompiler::Compile(const ir::MethodDefinition *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::MethodDefinition *node) const { - (void)node; UNREACHABLE(); } -void ETSCompiler::Compile(const ir::Property *expr) const +void ETSCompiler::Compile([[maybe_unused]] const ir::Property *expr) const { - (void)expr; UNREACHABLE(); } -void ETSCompiler::Compile(const ir::ScriptFunction *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::ScriptFunction *node) const { - (void)node; UNREACHABLE(); } @@ -119,25 +115,22 @@ void ETSCompiler::Compile(const ir::SpreadElement *expr) const void ETSCompiler::Compile(const ir::TemplateElement *expr) const { - (void)expr; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + etsg->LoadAccumulatorString(expr, expr->Raw()); } -void ETSCompiler::Compile(const ir::TSIndexSignature *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSIndexSignature *node) const { - (void)node; UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSMethodSignature *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSMethodSignature *node) const { - (void)node; UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSPropertySignature *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSPropertySignature *node) const { - (void)node; UNREACHABLE(); } diff --git a/ets2panda/compiler/core/JSCompiler.cpp b/ets2panda/compiler/core/JSCompiler.cpp index c3c3666045..0a73227327 100644 --- a/ets2panda/compiler/core/JSCompiler.cpp +++ b/ets2panda/compiler/core/JSCompiler.cpp @@ -410,25 +410,30 @@ void JSCompiler::Compile([[maybe_unused]] const ir::Decorator *st) const void JSCompiler::Compile(const ir::MetaProperty *expr) const { - (void)expr; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + if (expr->Kind() == ir::MetaProperty::MetaPropertyKind::NEW_TARGET) { + pg->GetNewTarget(expr); + return; + } + + if (expr->Kind() == ir::MetaProperty::MetaPropertyKind::IMPORT_META) { + // NOTE + pg->Unimplemented(); + } } -void JSCompiler::Compile(const ir::MethodDefinition *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::MethodDefinition *node) const { - (void)node; UNREACHABLE(); } -void JSCompiler::Compile(const ir::Property *expr) const +void JSCompiler::Compile([[maybe_unused]] const ir::Property *expr) const { - (void)expr; UNREACHABLE(); } -void JSCompiler::Compile(const ir::ScriptFunction *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::ScriptFunction *node) const { - (void)node; UNREACHABLE(); } @@ -438,27 +443,23 @@ void JSCompiler::Compile(const ir::SpreadElement *expr) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TemplateElement *expr) const +void JSCompiler::Compile([[maybe_unused]] const ir::TemplateElement *expr) const { - (void)expr; UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSIndexSignature *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSIndexSignature *node) const { - (void)node; UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSMethodSignature *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSMethodSignature *node) const { - (void)node; UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSPropertySignature *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSPropertySignature *node) const { - (void)node; UNREACHABLE(); } diff --git a/ets2panda/ir/base/metaProperty.cpp b/ets2panda/ir/base/metaProperty.cpp index f88b13cc03..24c5f5c0d6 100644 --- a/ets2panda/ir/base/metaProperty.cpp +++ b/ets2panda/ir/base/metaProperty.cpp @@ -15,10 +15,9 @@ #include "metaProperty.h" -#include "es2panda.h" -#include "compiler/core/pandagen.h" #include "checker/TSchecker.h" -#include "ir/astDump.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void MetaProperty::TransformChildren([[maybe_unused]] const NodeTransformer &cb) {} @@ -45,28 +44,24 @@ void MetaProperty::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "MetaProperty"}, {"kind", kind}}); } -void MetaProperty::Compile([[maybe_unused]] compiler::PandaGen *pg) const +void MetaProperty::Compile(compiler::PandaGen *pg) const { - if (kind_ == ir::MetaProperty::MetaPropertyKind::NEW_TARGET) { - pg->GetNewTarget(this); - return; - } + pg->GetAstCompiler()->Compile(this); +} - if (kind_ == ir::MetaProperty::MetaPropertyKind::IMPORT_META) { - // NOTE - pg->Unimplemented(); - } +void MetaProperty::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); } -checker::Type *MetaProperty::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *MetaProperty::Check(checker::TSChecker *checker) { - // NOTE: aszilagyi. - return checker->GlobalAnyType(); + return checker->GetAnalyzer()->Check(this); } -checker::Type *MetaProperty::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *MetaProperty::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } // NOLINTNEXTLINE(google-default-arguments) diff --git a/ets2panda/ir/base/metaProperty.h b/ets2panda/ir/base/metaProperty.h index 7a3d4e7f17..bca6a88b69 100644 --- a/ets2panda/ir/base/metaProperty.h +++ b/ets2panda/ir/base/metaProperty.h @@ -48,9 +48,10 @@ public: 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::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: MetaPropertyKind kind_; diff --git a/ets2panda/ir/base/methodDefinition.cpp b/ets2panda/ir/base/methodDefinition.cpp index cff3cf3c6b..30433c0391 100644 --- a/ets2panda/ir/base/methodDefinition.cpp +++ b/ets2panda/ir/base/methodDefinition.cpp @@ -16,20 +16,9 @@ #include "methodDefinition.h" #include "varbinder/scope.h" -#include "ir/astDump.h" -#include "ir/base/decorator.h" -#include "ir/base/classDefinition.h" -#include "ir/base/scriptFunction.h" -#include "ir/expression.h" -#include "ir/expressions/functionExpression.h" -#include "ir/expressions/identifier.h" -#include "ir/statements/blockStatement.h" -#include "ir/statements/returnStatement.h" -#include "ir/ts/tsTypeParameter.h" -#include "ir/typeNode.h" -#include "checker/ETSchecker.h" - -#include +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { @@ -131,204 +120,23 @@ void MethodDefinition::Dump(ir::AstDumper *dumper) const {"decorators", decorators_}}); } -void MethodDefinition::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} - -void MethodDefinition::Compile([[maybe_unused]] compiler::ETSGen *etsg) const {} - -checker::Type *MethodDefinition::Check([[maybe_unused]] checker::TSChecker *checker) -{ - return nullptr; -} - -checker::Type *MethodDefinition::Check(checker::ETSChecker *checker) -{ - auto *script_func = Function(); - - if (script_func->IsProxy()) { - return nullptr; - } - - // NOTE: aszilagyi. make it correctly check for open function not have body - if (!script_func->HasBody() && - !(IsAbstract() || IsNative() || IsDeclare() || checker->HasStatus(checker::CheckerStatus::IN_INTERFACE))) { - checker->ThrowTypeError("Only abstract or native methods can't have body.", script_func->Start()); - } - - if (script_func->ReturnTypeAnnotation() == nullptr && (IsNative() || (IsDeclare() && !IsConstructor()))) { - checker->ThrowTypeError("Native and Declare methods should have explicit return type.", script_func->Start()); - } - - if (TsType() == nullptr) { - SetTsType(checker->BuildMethodSignature(this)); - } - - CheckMethodModifiers(checker); - - if (IsNative() && script_func->ReturnTypeAnnotation() == nullptr) { - checker->ThrowTypeError("'Native' method should have explicit return type", script_func->Start()); - } - - if (IsNative() && (script_func->IsGetter() || script_func->IsSetter())) { - checker->ThrowTypeError("'Native' modifier is invalid for Accessors", script_func->Start()); - } - - if (script_func->HasBody() && (IsNative() || IsAbstract() || IsDeclare())) { - checker->ThrowTypeError("Native, Abstract and Declare methods cannot have body.", script_func->Body()->Start()); - } - - if (script_func->IsAsyncFunc()) { - auto *ret_type = static_cast(script_func->Signature()->ReturnType()); - if (ret_type->AssemblerName() != checker->GlobalBuiltinPromiseType()->AssemblerName()) { - checker->ThrowTypeError("Return type of async function must be 'Promise'.", script_func->Start()); - } - } else if (script_func->HasBody() && !script_func->IsExternal()) { - checker::ScopeContext scope_ctx(checker, script_func->Scope()); - checker::SavedCheckerContext saved_context(checker, checker->Context().Status(), - checker->Context().ContainingClass()); - checker->Context().SetContainingSignature(checker->GetSignatureFromMethodDefinition(this)); - - if (IsStatic() && !IsConstructor() && - !checker->Context().ContainingClass()->HasObjectFlag(checker::ETSObjectFlags::GLOBAL)) { - checker->AddStatus(checker::CheckerStatus::IN_STATIC_CONTEXT); - } - - if (IsConstructor()) { - checker->AddStatus(checker::CheckerStatus::IN_CONSTRUCTOR); - } - - if (IsExtensionMethod()) { - CheckExtensionMethod(checker, script_func); - } - - script_func->Body()->Check(checker); - - // In case of inferred function's return type set it forcedly to all return statements; - if (script_func->Signature()->HasSignatureFlag(checker::SignatureFlags::INFERRED_RETURN_TYPE) && - script_func->ReturnTypeAnnotation() == nullptr && script_func->Body() != nullptr && - script_func->Body()->IsStatement()) { - script_func->Body()->AsStatement()->SetReturnType(checker, script_func->Signature()->ReturnType()); - } - - checker->Context().SetContainingSignature(nullptr); - } - - if (script_func->IsSetter() && (script_func->Signature()->ReturnType() != checker->GlobalBuiltinVoidType())) { - checker->ThrowTypeError("Setter must have void return type", script_func->Start()); - } - - if (script_func->IsGetter() && (script_func->Signature()->ReturnType() == checker->GlobalBuiltinVoidType())) { - checker->ThrowTypeError("Getter must return a value", script_func->Start()); - } - - checker->CheckOverride(TsType()->AsETSFunctionType()->FindSignature(Function())); - - for (auto *it : overloads_) { - it->Check(checker); - } - - if (script_func->IsRethrowing()) { - checker->CheckRethrowingFunction(script_func); - } - - return TsType(); -} - -void MethodDefinition::CheckExtensionMethod(checker::ETSChecker *checker, ScriptFunction *extension_func) +void MethodDefinition::Compile(compiler::PandaGen *pg) const { - auto *const class_type = extension_func->Signature()->Params()[0]->TsType(); - if (!class_type->IsETSObjectType() || - (!class_type->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::CLASS) && - !class_type->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::INTERFACE))) { - checker->ThrowTypeError("Extension function can only defined for class and interface type.", Start()); - } - - checker->AddStatus(checker::CheckerStatus::IN_INSTANCE_EXTENSION_METHOD); - - checker::SignatureInfo *original_extension_sig_info = checker->Allocator()->New( - extension_func->Signature()->GetSignatureInfo(), checker->Allocator()); - original_extension_sig_info->min_arg_count -= 1; - original_extension_sig_info->params.erase(original_extension_sig_info->params.begin()); - checker::Signature *original_extension_sigature = checker->CreateSignature( - original_extension_sig_info, extension_func->Signature()->ReturnType(), extension_func); - - CheckExtensionIsShadowedByMethod(checker, class_type->AsETSObjectType(), extension_func, - original_extension_sigature); + pg->GetAstCompiler()->Compile(this); } -void MethodDefinition::CheckExtensionIsShadowedByMethod(checker::ETSChecker *checker, checker::ETSObjectType *obj_type, - ScriptFunction *extension_func, checker::Signature *sigature) +void MethodDefinition::Compile(compiler::ETSGen *etsg) const { - if (obj_type == nullptr) { - return; - } - - CheckExtensionIsShadowedInCurrentClassOrInterface(checker, obj_type, extension_func, sigature); - - for (auto *interface : obj_type->Interfaces()) { - CheckExtensionIsShadowedByMethod(checker, interface, extension_func, sigature); - } - - CheckExtensionIsShadowedByMethod(checker, obj_type->SuperType(), extension_func, sigature); + etsg->GetAstCompiler()->Compile(this); } -void MethodDefinition::CheckExtensionIsShadowedInCurrentClassOrInterface(checker::ETSChecker *checker, - checker::ETSObjectType *obj_type, - ScriptFunction *extension_func, - checker::Signature *sigature) +checker::Type *MethodDefinition::Check(checker::TSChecker *checker) { - const auto method_name = extension_func->Id()->Name(); - // Only check if there are class and interfaces' instance methods which would shadow instance extension method - auto *const variable = obj_type->GetOwnProperty(method_name); - if (variable == nullptr) { - return; - } - - const auto *const func_type = variable->TsType()->AsETSFunctionType(); - for (auto *func_signature : func_type->CallSignatures()) { - sigature->SetReturnType(func_signature->ReturnType()); - if (!checker->Relation()->IsIdenticalTo(sigature, func_signature)) { - continue; - } - - checker->ReportWarning({"extension is shadowed by a instance member function '", func_type->Name(), - func_signature, "' in class ", obj_type->Name()}, - extension_func->Body()->Start()); - return; - } + return checker->GetAnalyzer()->Check(this); } -void MethodDefinition::CheckMethodModifiers(checker::ETSChecker *checker) +checker::Type *MethodDefinition::Check(checker::ETSChecker *checker) { - auto const not_valid_in_abstract = ir::ModifierFlags::NATIVE | ir::ModifierFlags::PRIVATE | - ir::ModifierFlags::OVERRIDE | ir::ModifierFlags::FINAL | - ir::ModifierFlags::STATIC; - - if (IsAbstract() && (flags_ & not_valid_in_abstract) != 0U) { - checker->ThrowTypeError( - "Invalid method modifier(s): an abstract method can't have private, override, static, final or native " - "modifier.", - Start()); - } - - if ((IsAbstract() || (!Function()->HasBody() && !IsNative() && !IsDeclare())) && - !(checker->HasStatus(checker::CheckerStatus::IN_ABSTRACT) || - checker->HasStatus(checker::CheckerStatus::IN_INTERFACE))) { - checker->ThrowTypeError("Non abstract class has abstract method.", Start()); - } - - auto const not_valid_in_final = ir::ModifierFlags::ABSTRACT | ir::ModifierFlags::STATIC | ir::ModifierFlags::NATIVE; - - if (IsFinal() && (flags_ & not_valid_in_final) != 0U) { - checker->ThrowTypeError( - "Invalid method modifier(s): a final method can't have abstract, static or native modifier.", Start()); - } - - auto const not_valid_in_static = - ir::ModifierFlags::ABSTRACT | ir::ModifierFlags::FINAL | ir::ModifierFlags::OVERRIDE; - - if (IsStatic() && (flags_ & not_valid_in_static) != 0U) { - checker->ThrowTypeError( - "Invalid method modifier(s): a static method can't have abstract, final or override modifier.", Start()); - } + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/base/methodDefinition.h b/ets2panda/ir/base/methodDefinition.h index 079bddf66c..ac2119f346 100644 --- a/ets2panda/ir/base/methodDefinition.h +++ b/ets2panda/ir/base/methodDefinition.h @@ -20,6 +20,10 @@ #include "checker/types/signature.h" #include "ir/base/classElement.h" +namespace panda::es2panda::checker { +class ETSAnalyzer; +} // namespace panda::es2panda::checker + namespace panda::es2panda::ir { class Expression; @@ -35,6 +39,9 @@ public: { } + // TODO (csabahurton): these friend relationships can be removed once there are getters for private fields + friend class checker::ETSAnalyzer; + MethodDefinitionKind Kind() const { return kind_; @@ -73,22 +80,14 @@ public: ScriptFunction *Function(); const ScriptFunction *Function() const; PrivateFieldKind ToPrivateFieldKind(bool is_static) const override; - void CheckMethodModifiers(checker::ETSChecker *checker); - void CheckExtensionMethod(checker::ETSChecker *checker, ScriptFunction *extension_func); - void CheckExtensionIsShadowedByMethod(checker::ETSChecker *checker, checker::ETSObjectType *obj_type, - ScriptFunction *extension_func, checker::Signature *sigature); - void CheckExtensionIsShadowedInCurrentClassOrInterface(checker::ETSChecker *checker, - checker::ETSObjectType *obj_type, - ScriptFunction *extension_func, - checker::Signature *sigature); void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - void Compile([[maybe_unused]] compiler::ETSGen *etsg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: MethodDefinitionKind kind_; diff --git a/ets2panda/ir/base/property.cpp b/ets2panda/ir/base/property.cpp index f607be57b1..80dfea74ac 100644 --- a/ets2panda/ir/base/property.cpp +++ b/ets2panda/ir/base/property.cpp @@ -16,14 +16,9 @@ #include "property.h" #include "es2panda.h" -#include "ir/astDump.h" -#include "ir/expression.h" -#include "ir/expressions/arrayExpression.h" -#include "ir/expressions/assignmentExpression.h" -#include "ir/expressions/objectExpression.h" -#include "ir/expressions/identifier.h" -#include "ir/expressions/literals/stringLiteral.h" -#include "ir/validationInfo.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { Property::Property([[maybe_unused]] Tag const tag, Expression *const key, Expression *const value) : Property(*this) @@ -170,15 +165,23 @@ void Property::Dump(ir::AstDumper *dumper) const {"kind", kind}}); } -void Property::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void Property::Compile(compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} + +void Property::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} -checker::Type *Property::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *Property::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } -checker::Type *Property::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *Property::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/base/property.h b/ets2panda/ir/base/property.h index 91d91512c4..3d42ba60ae 100644 --- a/ets2panda/ir/base/property.h +++ b/ets2panda/ir/base/property.h @@ -111,9 +111,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; protected: Property(Property const &other) : Expression(static_cast(other)) diff --git a/ets2panda/ir/base/scriptFunction.cpp b/ets2panda/ir/base/scriptFunction.cpp index d7477e92b5..72e1b6034e 100644 --- a/ets2panda/ir/base/scriptFunction.cpp +++ b/ets2panda/ir/base/scriptFunction.cpp @@ -16,14 +16,9 @@ #include "scriptFunction.h" #include "varbinder/scope.h" +#include "checker/TSchecker.h" #include "compiler/core/ETSGen.h" -#include "ir/astDump.h" -#include "ir/expression.h" -#include "ir/typeNode.h" -#include "ir/expressions/identifier.h" -#include "ir/statements/blockStatement.h" -#include "ir/ts/tsTypeParameter.h" -#include "ir/ts/tsTypeParameterDeclaration.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { bool ScriptFunction::HasBody() const @@ -117,19 +112,22 @@ void ScriptFunction::Dump(ir::AstDumper *dumper) const } } -void ScriptFunction::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} -void ScriptFunction::Compile([[maybe_unused]] compiler::ETSGen *etsg) const +void ScriptFunction::Compile(compiler::PandaGen *pg) const { - UNREACHABLE(); + pg->GetAstCompiler()->Compile(this); +} +void ScriptFunction::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); } -checker::Type *ScriptFunction::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *ScriptFunction::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } -checker::Type *ScriptFunction::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *ScriptFunction::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/base/scriptFunction.h b/ets2panda/ir/base/scriptFunction.h index 93e1344227..ebb4d045f6 100644 --- a/ets2panda/ir/base/scriptFunction.h +++ b/ets2panda/ir/base/scriptFunction.h @@ -286,10 +286,10 @@ 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 Compile([[maybe_unused]] compiler::ETSGen *etsg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: varbinder::FunctionScope *scope_; diff --git a/ets2panda/ir/base/templateElement.cpp b/ets2panda/ir/base/templateElement.cpp index 8a0e7d317e..b623500211 100644 --- a/ets2panda/ir/base/templateElement.cpp +++ b/ets2panda/ir/base/templateElement.cpp @@ -15,10 +15,11 @@ #include "templateElement.h" -#include "es2panda.h" +#include "checker/TSchecker.h" #include "compiler/core/ETSGen.h" -#include "ir/astDump.h" -#include "util/ustring.h" +#include "compiler/core/pandagen.h" +// #include "es2panda.h" +// #include "ir/astDump.h" namespace panda::es2panda::ir { void TemplateElement::TransformChildren([[maybe_unused]] const NodeTransformer &cb) {} @@ -32,22 +33,24 @@ void TemplateElement::Dump(ir::AstDumper *dumper) const }); } -void TemplateElement::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TemplateElement::Compile(compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} -void TemplateElement::Compile([[maybe_unused]] compiler::ETSGen *etsg) const +void TemplateElement::Compile(compiler::ETSGen *etsg) const { - etsg->LoadAccumulatorString(this, raw_); + etsg->GetAstCompiler()->Compile(this); } -checker::Type *TemplateElement::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *TemplateElement::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } -checker::Type *TemplateElement::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *TemplateElement::Check(checker::ETSChecker *checker) { - SetTsType(checker->CreateETSStringLiteralType(raw_)); - return TsType(); + return checker->GetAnalyzer()->Check(this); } // NOLINTNEXTLINE(google-default-arguments) diff --git a/ets2panda/ir/base/templateElement.h b/ets2panda/ir/base/templateElement.h index b373d7aff8..ec8f4b05c5 100644 --- a/ets2panda/ir/base/templateElement.h +++ b/ets2panda/ir/base/templateElement.h @@ -50,10 +50,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - void Compile([[maybe_unused]] compiler::ETSGen *etsg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: util::StringView raw_ {}; diff --git a/ets2panda/ir/base/tsIndexSignature.cpp b/ets2panda/ir/base/tsIndexSignature.cpp index 09598d5b24..3794a31ecf 100644 --- a/ets2panda/ir/base/tsIndexSignature.cpp +++ b/ets2panda/ir/base/tsIndexSignature.cpp @@ -15,11 +15,9 @@ #include "tsIndexSignature.h" -#include "ir/astDump.h" -#include "ir/typeNode.h" -#include "ir/expressions/identifier.h" - #include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { TSIndexSignature::TSIndexSignatureKind TSIndexSignature::Kind() const @@ -48,34 +46,23 @@ void TSIndexSignature::Dump(ir::AstDumper *dumper) const {"readonly", readonly_}}); } -void TSIndexSignature::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} - -checker::Type *TSIndexSignature::Check([[maybe_unused]] checker::TSChecker *checker) +void TSIndexSignature::Compile(compiler::PandaGen *pg) const { - if (TsType() != nullptr) { - return TsType(); - } - - const util::StringView ¶m_name = param_->AsIdentifier()->Name(); - type_annotation_->Check(checker); - checker::Type *index_type = type_annotation_->GetType(checker); - checker::IndexInfo *info = - checker->Allocator()->New(index_type, param_name, readonly_, this->Start()); - checker::ObjectDescriptor *desc = checker->Allocator()->New(checker->Allocator()); - checker::ObjectType *placeholder = checker->Allocator()->New(desc); + pg->GetAstCompiler()->Compile(this); +} - if (Kind() == ir::TSIndexSignature::TSIndexSignatureKind::NUMBER) { - placeholder->Desc()->number_index_info = info; - } else { - placeholder->Desc()->string_index_info = info; - } +void TSIndexSignature::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} - SetTsType(placeholder); - return placeholder; +checker::Type *TSIndexSignature::Check(checker::TSChecker *checker) +{ + return checker->GetAnalyzer()->Check(this); } -checker::Type *TSIndexSignature::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *TSIndexSignature::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/base/tsIndexSignature.h b/ets2panda/ir/base/tsIndexSignature.h index db29746c91..a3b6b80dd4 100644 --- a/ets2panda/ir/base/tsIndexSignature.h +++ b/ets2panda/ir/base/tsIndexSignature.h @@ -18,6 +18,10 @@ #include "ir/statement.h" +namespace panda::es2panda::checker { +class TSAnalyzer; +} // namespace panda::es2panda::checker + namespace panda::es2panda::ir { class TSIndexSignature : public TypedAstNode { public: @@ -30,6 +34,8 @@ public: readonly_(readonly) { } + // TODO (csabahurton): friend relationship can be removed once there are getters for private fields + friend class checker::TSAnalyzer; const Expression *Param() const { @@ -51,9 +57,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: Expression *param_; diff --git a/ets2panda/ir/base/tsMethodSignature.cpp b/ets2panda/ir/base/tsMethodSignature.cpp index c6f203b24b..a0a356cda1 100644 --- a/ets2panda/ir/base/tsMethodSignature.cpp +++ b/ets2panda/ir/base/tsMethodSignature.cpp @@ -16,12 +16,9 @@ #include "tsMethodSignature.h" #include "varbinder/scope.h" -#include "ir/astDump.h" -#include "ir/typeNode.h" -#include "ir/ts/tsTypeParameter.h" -#include "ir/ts/tsTypeParameterDeclaration.h" - #include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void TSMethodSignature::TransformChildren(const NodeTransformer &cb) @@ -69,35 +66,23 @@ void TSMethodSignature::Dump(ir::AstDumper *dumper) const {"typeAnnotation", AstDumper::Optional(return_type_annotation_)}}); } -void TSMethodSignature::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} - -checker::Type *TSMethodSignature::Check([[maybe_unused]] checker::TSChecker *checker) +void TSMethodSignature::Compile(compiler::PandaGen *pg) const { - if (computed_) { - checker->CheckComputedPropertyName(key_); - } - - checker::ScopeContext scope_ctx(checker, scope_); - - auto *signature_info = checker->Allocator()->New(checker->Allocator()); - checker->CheckFunctionParameterDeclarations(params_, signature_info); - - auto *call_signature = checker->Allocator()->New(signature_info, checker->GlobalAnyType()); - Variable()->SetTsType(checker->CreateFunctionTypeWithSignature(call_signature)); - - if (return_type_annotation_ == nullptr) { - checker->ThrowTypeError( - "Method signature, which lacks return-type annotation, implicitly has an 'any' return type.", Start()); - } + pg->GetAstCompiler()->Compile(this); +} - return_type_annotation_->Check(checker); - call_signature->SetReturnType(return_type_annotation_->GetType(checker)); +void TSMethodSignature::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} - return nullptr; +checker::Type *TSMethodSignature::Check(checker::TSChecker *checker) +{ + return checker->GetAnalyzer()->Check(this); } -checker::Type *TSMethodSignature::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *TSMethodSignature::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/base/tsMethodSignature.h b/ets2panda/ir/base/tsMethodSignature.h index ffa4dca387..80ec369139 100644 --- a/ets2panda/ir/base/tsMethodSignature.h +++ b/ets2panda/ir/base/tsMethodSignature.h @@ -18,6 +18,11 @@ #include "ir/statement.h" +namespace panda::es2panda::checker { +class TSAnalyzer; +class ETSAnalyzer; +} // namespace panda::es2panda::checker + namespace panda::es2panda::ir { class TSTypeParameterDeclaration; @@ -37,6 +42,9 @@ public: { } + // TODO (csabahurton): friend relationship can be removed once there are getters for private fields + friend class checker::TSAnalyzer; + bool IsScopeBearer() const override { return true; @@ -85,9 +93,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: varbinder::Scope *scope_; diff --git a/ets2panda/ir/base/tsPropertySignature.cpp b/ets2panda/ir/base/tsPropertySignature.cpp index 3cfddf1f7f..822061f30e 100644 --- a/ets2panda/ir/base/tsPropertySignature.cpp +++ b/ets2panda/ir/base/tsPropertySignature.cpp @@ -15,10 +15,9 @@ #include "tsPropertySignature.h" -#include "ir/astDump.h" -#include "ir/typeNode.h" - #include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void TSPropertySignature::TransformChildren(const NodeTransformer &cb) @@ -49,29 +48,23 @@ void TSPropertySignature::Dump(ir::AstDumper *dumper) const {"typeAnnotation", AstDumper::Optional(TypeAnnotation())}}); } -void TSPropertySignature::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} - -checker::Type *TSPropertySignature::Check([[maybe_unused]] checker::TSChecker *checker) +void TSPropertySignature::Compile(compiler::PandaGen *pg) const { - if (TypeAnnotation() != nullptr) { - TypeAnnotation()->Check(checker); - } - - if (computed_) { - checker->CheckComputedPropertyName(key_); - } + pg->GetAstCompiler()->Compile(this); +} - if (TypeAnnotation() != nullptr) { - Variable()->SetTsType(TypeAnnotation()->GetType(checker)); - return nullptr; - } +void TSPropertySignature::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} - checker->ThrowTypeError("Property implicitly has an 'any' type.", Start()); - return nullptr; +checker::Type *TSPropertySignature::Check(checker::TSChecker *checker) +{ + return checker->GetAnalyzer()->Check(this); } -checker::Type *TSPropertySignature::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *TSPropertySignature::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/base/tsPropertySignature.h b/ets2panda/ir/base/tsPropertySignature.h index b39ebfdd0d..571ce78f8b 100644 --- a/ets2panda/ir/base/tsPropertySignature.h +++ b/ets2panda/ir/base/tsPropertySignature.h @@ -61,9 +61,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: Expression *key_; diff --git a/ets2panda/ir/expressions/binaryExpression.cpp b/ets2panda/ir/expressions/binaryExpression.cpp index 77707c82be..1537a4bd5d 100644 --- a/ets2panda/ir/expressions/binaryExpression.cpp +++ b/ets2panda/ir/expressions/binaryExpression.cpp @@ -40,11 +40,13 @@ void BinaryExpression::Dump(ir::AstDumper *dumper) const {"right", right_}}); } -void BinaryExpression::Compile(compiler::PandaGen *pg) const { +void BinaryExpression::Compile(compiler::PandaGen *pg) const +{ pg->GetAstCompiler()->Compile(this); } -void BinaryExpression::Compile(compiler::ETSGen *etsg) const { +void BinaryExpression::Compile(compiler::ETSGen *etsg) const +{ etsg->GetAstCompiler()->Compile(this); } diff --git a/ets2panda/ir/ts/tsEnumDeclaration.cpp b/ets2panda/ir/ts/tsEnumDeclaration.cpp index d1b0248875..b0f73788e5 100644 --- a/ets2panda/ir/ts/tsEnumDeclaration.cpp +++ b/ets2panda/ir/ts/tsEnumDeclaration.cpp @@ -57,12 +57,11 @@ void TSEnumDeclaration::Dump(ir::AstDumper *dumper) const {"const", is_const_}}); } -// NOTE (csabahurton): this method has not been moved to TSAnalyizer.cpp, because it is not used. +// NOTE (csabahurton): this method has not been moved to TSAnalyizer.cpp, because it is not used. varbinder::EnumMemberResult EvaluateMemberExpression(checker::TSChecker *checker, [[maybe_unused]] varbinder::EnumVariable *enum_var, ir::MemberExpression *expr) { - if (checker::TSChecker::IsConstantMemberAccess(expr->AsExpression())) { if (expr->Check(checker)->TypeFlags() == checker::TypeFlag::ENUM) { util::StringView name; @@ -80,7 +79,8 @@ varbinder::EnumMemberResult EvaluateMemberExpression(checker::TSChecker *checker return false; } -void TSEnumDeclaration::Compile(compiler::PandaGen *pg) const { +void TSEnumDeclaration::Compile(compiler::PandaGen *pg) const +{ pg->GetAstCompiler()->Compile(this); } -- Gitee