diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index ec729cf22942eacc61d2ca5a674062973d981b88..bda5e9b47f73a61c62d1246b564ccfb523d74210 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 { @@ -126,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(); } @@ -158,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(); } @@ -372,49 +551,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(); } @@ -528,26 +941,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 @@ -557,51 +991,118 @@ 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(); } 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 @@ -625,74 +1126,178 @@ 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(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, @@ -907,16 +1512,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 @@ -949,9 +1602,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 +1625,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 +1650,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 +1785,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 +1813,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 +1890,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 +1901,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/ETSAnalyzer.h b/ets2panda/checker/ETSAnalyzer.h index de2b57cc58f1221ba182913a895318b90abe91fd..0fcf2540f4b6cc899c42246c44801615a059bfcd 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 d3e96e821ffd6bb149a2337acaa909ed200d7dca..d8ab78500ee34b1747ce5a574bcb50902be92b82 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 @@ -267,52 +318,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 @@ -423,28 +579,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(); + // NOTE(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,51 +626,43 @@ 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(); } -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 +684,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,63 +695,107 @@ 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(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 +830,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 @@ -665,10 +899,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 +922,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 +945,348 @@ checker::Type *TSAnalyzer::Check(ir::TSConstructorType *node) const UNREACHABLE(); } +static 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; +} + +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; +} + +varbinder::EnumMemberResult TSAnalyzer::EvaluateBinaryExpression(checker::TSChecker *checker, + 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()); + 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 TSAnalyzer::EvaluateUnaryExpression(checker::TSChecker *checker, + varbinder::EnumVariable *enum_var, + const ir::UnaryExpression *expr) const +{ + varbinder::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; +} + +varbinder::EnumMemberResult TSAnalyzer::EvaluateEnumMember(checker::TSChecker *checker, + varbinder::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, 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 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 +{ + 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 = 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 +1392,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 +1420,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 +1497,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 +1508,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 eb23fa2fc5c919df6b4b822e49429c8c3775b349..b99a5d18aaf433a866cba3c337229cca23758aef 100644 --- a/ets2panda/checker/TSAnalyzer.h +++ b/ets2panda/checker/TSAnalyzer.h @@ -36,6 +36,17 @@ public: private: TSChecker *GetTSChecker() const; + + varbinder::EnumMemberResult EvaluateBinaryExpression(checker::TSChecker *checker, varbinder::EnumVariable *enum_var, + const ir::BinaryExpression *expr) const; + varbinder::EnumMemberResult EvaluateEnumMember(checker::TSChecker *checker, varbinder::EnumVariable *enum_var, + const ir::AstNode *expr) const; + varbinder::EnumMemberResult EvaluateUnaryExpression(checker::TSChecker *checker, varbinder::EnumVariable *enum_var, + 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; + 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 46dd096ae82d9c812db8af28704dee330951bdcd..63a13ac8627e6b60a2f3a067d8e6326296279638 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 { @@ -86,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(); } @@ -118,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(); } @@ -270,49 +264,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(); } @@ -426,26 +722,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 @@ -455,51 +779,43 @@ 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(); } -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 @@ -521,76 +837,207 @@ 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 ETSCompiler::Compile(const ir::DoWhileStatement *st) const +void CompileImpl(const ir::DoWhileStatement *self, ETSGen *etsg) { - (void)st; - UNREACHABLE(); + 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::EmptyStatement *st) const +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 {} + 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 +1083,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 @@ -678,9 +1156,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 +1179,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 +1202,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 +1319,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 +1347,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 +1424,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 +1435,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 10a894d364243fe8b74d0bd55d96c5d90df2551c..0a73227327cbee50cddc2433643f603ea07e6142 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" @@ -409,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(); } @@ -437,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(); } @@ -572,50 +574,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 @@ -728,26 +917,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 @@ -757,51 +954,44 @@ 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; + } -void JSCompiler::Compile(const ir::ExportSpecifier *st) const -{ - (void)st; - UNREACHABLE(); + st->Decl()->Compile(pg); } -void JSCompiler::Compile(const ir::ImportDeclaration *st) const +void JSCompiler::Compile([[maybe_unused]] const ir::ExportSpecifier *st) const { - (void)st; UNREACHABLE(); } -void JSCompiler::Compile(const ir::ImportDefaultSpecifier *st) const +void JSCompiler::Compile([[maybe_unused]] const ir::ImportDeclaration *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 @@ -825,74 +1015,202 @@ 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(); } -void JSCompiler::Compile(const ir::ContinueStatement *st) const +static void CompileImpl(const ir::ContinueStatement *self, PandaGen *cg) { - (void)st; - UNREACHABLE(); + compiler::Label *target = cg->ControlFlowChangeContinue(self->Ident()); + cg->Branch(self, target); } -void JSCompiler::Compile(const ir::DebuggerStatement *st) const +void JSCompiler::Compile(const ir::ContinueStatement *st) const { - (void)st; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + CompileImpl(st, pg); } -void JSCompiler::Compile(const ir::DoWhileStatement *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::EmptyStatement *st) const +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 {} + 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 +1239,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 @@ -963,9 +1312,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 +1335,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 +1358,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 +1475,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 +1503,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 +1580,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 +1591,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/base/metaProperty.cpp b/ets2panda/ir/base/metaProperty.cpp index f88b13cc03b88649618baabbb677af035f4dce63..24c5f5c0d6c95032dd774773ef96c95a98a39ba3 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 7a3d4e7f1736685ee21cd162a22f70506a014073..bca6a88b692459700df1b3d79fc4fd73ca185224 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 cff3cf3c6bd661e08997ecfc465c3c3b6208bd3c..30433c039147f1b3f31569a28b3a6969fdd8ec97 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 079bddf66cfa20019c67274a2b4b1579b4c0af61..ac2119f346eeb5d8b31680eb1d1e7a08d8de5166 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 f607be57b12bc097976ea5ea62d080cc8809aac4..80dfea74ac0858d741731d8462eb3a2bad3df146 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 91d91512c44d69921b94b4698ef2043ae9be9982..3d42ba60aed02f2d728a80ca55104c6d09fca972 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 d7477e92b5b7cd519c9d50af95313d86ef5ba972..72e1b6034e428c3e13a732c34324438a9b8e5cb5 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 93e134422716eda3f0635a8ab6982427df2d6bea..ebb4d045f6738bcaf13afe5980d97153d878e6f3 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 8a0e7d317ee2ca4c6cdd02508ea2490ef5eb7ca5..b623500211403ea9585982e28fddf58b2fac0c8e 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 b373d7aff8cc660a598824361c10e65c2e93ef3c..ec8f4b05c57ff278cd2eb3122bcd5b9c54d72aa3 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 09598d5b2488039e1ebf0c31c6900265cb77e31a..3794a31ecfe948231338df38bede51855b55a244 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 db29746c9150d9f768b760e68477280096771d64..a3b6b80dd467ecda26963ebb2d210bc61d93dd5e 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 c6f203b24b91e353de82a43c3fc37a2cd96349f9..a0a356cda192518d78d6ca156e8e190bab5e7d8f 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 ffa4dca38709fca21aa9ff37fc4382ca0e2e69cd..80ec369139cc19faa222b49573553d757e80f27c 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 3cfddf1f7fa1cb06cf888cd07f5a517fa545388e..822061f30ee25636b151b442f9d502ae85ab9de0 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 b39ebfdd0dc38b3e327f4905f11ab52012768d2f..571ce78f8b4406de38782243a1c3cb882268b36a 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/awaitExpression.cpp b/ets2panda/ir/expressions/awaitExpression.cpp index 636a7e5bc25ab705db10bbefabee403e2d0fc139..0dc54fafb386780ec97024f78c9d7cfb437dea4d 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 17240df98c3efcdf6ca7e22e01545aa4a293e8f9..0a84c6e7bf4f44dcf491b3c5ebc765216ced2385 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 440afa17f2d760db3d417e9bc88304214c0a7f85..1537a4bd5d25f55cdb763cec5929505c9b1d3080 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,24 @@ 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); + 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()); + 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 c2a1a47bbbc2943a56b1b2822cfa2227ecd71963..0ab4ba0e258dc9ac03eeb6790ad3215fc218430f 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 b74f16794da9ce5f8877d48db9208e8a2afb4f3b..311fc21349df2ec9a13888f579355c7fd9327061 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 d68ca9daca725252c798de103c0eac2180193eca..a7ed295afcf4cbb7db59edbbd7ca44cfe3d0a2dc 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 ce71eac838816b664bcb6cbfc04018e05cfb1b23..c2987762eee531c3fea3dbb286fea0a153a21aa3 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 252ece9500b899c32839e359942a82ab5d196360..a54d632b09a4af969e1f47beb4339cfc12575226 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 ecefc3a8faa98819a7af97b4a76a6d32be7280c2..394625e52d007dc35002fa03fd2b6bf60bb6784a 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 1ab8e4a09cef41e69b7982dadee50bf1f4d269bb..168b3fac747cc97d0f71c742626e6c80299418d8 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 b60d48679a534d877a6043bcf2a4da23c1f8b8d2..aab68ac2b82f344854e3bdc00032650dfa9f4ddd 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 8e0e7a10d8f05320189fb05223dedd18f2d73dea..77ca2e883e915e9f8854caef60ae4a70f26f47c7 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 356301fb15468c40b02608ae59669c30bd649465..95cb09e36775f8723343bdc0e58c9e2184637a57 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 eca191333919c1ad2372095147cc0326165dbdca..33c9d6ec03b40e013f87e4857aa95f5199629bc6 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 7f9c194231c0aed7c6c2b7a3d46b99df5c074fff..01f1f4b68c92b1eaf2c57e34f6e3e9bce512f835 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 4b2191857876d40e841c41400d5ce63f5f3de283..1e858ac12a74374f74dee572122095b8b04474d1 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/literals/nullLiteral.cpp b/ets2panda/ir/expressions/literals/nullLiteral.cpp index 10868ce8325bb18e32378cdc0cce05e2578a7ede..06ab4c14f3b2343a25239c48c1444e3e1c0f9114 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 1fa60a74f0fa783d1d44d8106f99a51ea01d32c5..6554e5c0f38b4057233057b0283e90e41790c0b6 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 d411de92385590e1760a15ad0e1145ef357cb244..4891bb85d25e4cd03200f0a45eec55a053a25749 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 e7391b8e40398b77f86ecd401c3e64d6517acdfa..9fb2893c776a7724d2ae4fca98f4fdeddbbfedfe 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 d278513f9fe09ca26e43472a2f48dc2ec46a2fbd..3e747af6bc9d8adadfc8dfd76ff921e8b55da92c 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 8ee1c453e535964d0a1c483a91f7f276a99d7e85..bdb265f7d66fac49fc60c7a3bcd9cda76a8a2f65 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 2c45cb252ecda5adb8c4d5b410bef4345cf508af..d3a2fa4a749f552ebe4e555ed0381d33359971d1 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 da7f22fdadbab4187e7988f6e37c7e7fcf8041fb..8daed2c98e3bbbc8cd06e33665d5a1791f1ba91a 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/expressions/memberExpression.cpp b/ets2panda/ir/expressions/memberExpression.cpp index 44936411def8039ca48d27983c70f5b50f85269e..2387690888ed9653e52bd4905c9f0d1c86374a4a 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) diff --git a/ets2panda/ir/module/exportAllDeclaration.cpp b/ets2panda/ir/module/exportAllDeclaration.cpp index 9867f99848a1b6bac1430a33d5f7a758011eb814..c34cb356e49c57204f7920e1862daed02a77ec6d 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 afcdea02dc0642a422c4a88e6935da6cfaafb38e..89926b4ec8ba4af0a07361fcf324be8611a1eedb 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 657179005ad193df5ed6ec2b95386b1f2c72077f..82e090025be581f9ea29b24ed39d83d1c7bc210f 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 38af658d5fd2109cc40f22b083b4cf0526b5b33a..6d32882db58427972a6495ba267d3c04cb356173 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 5bbd501593ea5ebbc42befcf2b5d8808ecb93f0d..ff886326fd879b9e8fe06e74fdf6dde74a11d3d6 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 e794931975cb496b4ff75af645ee64f51e014fb2..f455b8985e6a3c51e15f4bd2832950257da1806c 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 e308dd2b06e10d8ac06045377dea3290fad64075..2aa19dee82c77cf7cb630552fde92cc83c183f9c 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 f6bfefbd9f576fc633d063ff5ac4fa8df07eba16..d50d2bee59f714f3f87dc48258fd4c268bfe6a74 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_; diff --git a/ets2panda/ir/module/importDeclaration.cpp b/ets2panda/ir/module/importDeclaration.cpp index b946fbd1b679d90f467435cc458cbd68d79a3dbe..e1208b0d02a56bb3b2eb6ba72753ec14817a2ede 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 18594b35e398f98c9fe13b2b31e26f42c2272922..fc8e923882bad9d6d0b209670f82e88cf8a5f284 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 2413efb897afcfa10a9ee7636f5f788fa027f7a9..ea4a43b93e199df6aa0178d0fbca81eb82e89459 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 7d39425a088c59f202e41c07c2acbc619f0478d3..0ad73508467408f9477946cf9ec2a776aac1a244 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 9607da9ba6a098627b7b78b4c0d9d03a15096575..44660316c6ed0e0860617c2d976c7e8f2a24316b 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 0af20262ba57e28274a7974262ef5ca60a22978a..e725cce1aef38761c90498c64939d19eeabf2c45 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 343614347e2e30cb5af932d939965a43cac4ba45..984e4137d5861c8b746bb2fc0bbe2a63f02e5559 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 9a0c1311abb9eee8973fb19ac1479b050cfabe99..c59fba3bed65f9dadc3658fc27678a920357a5c9 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 6c0822d5f27188bd9be8fa96bf140895ef367ece..627e9bece0a42037e8d65b33e331a28d9073671d 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 c2e535c0740205f0be808f6d4e772d51b8f8e7b1..8984cf0651ff6dcaf30a39b62ea9db4a58f2fb9f 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 74536dc361990216d18cc453b69cb7bc40b21b77..da58f870ae1043602b4e21bcb8460c06f4742262 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 2eead3db014edee313f4d7df437480dc734736f2..804670d2a6c6a1186d1430dabb86549ef8c058d5 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 506daf50ae480818324ae2a6532fa1dc2cd1ba5b..b0bb23faadd70a585650ec54cd7d21c5988d5c0f 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 d9858dbfd48308a8c4f381539a0c05f9936ab209..792af73b967f1e99bf3c29aa1a3b22ffe6e35131 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 e36442c438d676836f8e153234cd403a5ea8ac23..93d2a413e6a8e2efabe04fa0d386c38083230573 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 58b970bfdcecebd33c19ab6b66e1d7fcb69ce851..bc811edca2c361e570539a30fa61467242c010c3 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_; diff --git a/ets2panda/ir/statements/emptyStatement.cpp b/ets2panda/ir/statements/emptyStatement.cpp index 5da09fdd2284bad2b67f115767bb55cd0e163517..4c00f2a89ee6f42aea577b5c9121229994a54b11 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 44c82b2fba26420907ff6388cb687a08da889b22..a815449fbadf23621f73dfd5ba1ba21070799c57 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 61ebaca008147e8c817413c5420f97726aaa5de2..d4750832be8cdad6688db5c3f34f4f80185336df 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 2f80d87221946a812a42877339724d51be7cad30..56ea20363273428ddb7a53d833ecd72818830d1f 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 b21b387e5d819c361781df5ef246153ef6dd3d6d..331be2f2fff94081c1ae8d4b1b8527e784c91c1a 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 1089e3ffa4875d5b9040c3d74c90e07c7c9dc9f0..78d482e827d98b8884b84ddea5abec50275b01ef 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 1b7ae5a7cc17222bc20fb1a1eda01b3978f74d1f..50cb1e9d1c9e63c719ed6236d68ed35d2f2d12e8 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 51a99573c8ca30a73b4e6e2a4bb42a9a3e27ea36..0043c78a7c6e7e4d3b3244df1bf12b8251bc3a39 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 378dbcf36dc89fad9af9431ff94c135a8e04c791..09ccc206027021f9ecad28e5c682212f9ad238f8 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 f79166695e3efc93d0e6fa272d6def0f8de14a68..9e39b8b0d47c7b71e5201107ac0999ceab72d3ae 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 578a8b1e7883d21a2eeafba08f3a00431f5c3245..a5c9e3a6148b417654cc2360ad5ad0b80fc3934d 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 0c00928b77c77239586cc8f93347ddc1cd002ad2..26bed64a5df7b0c8b4a5d95c192dfe669bbd3c75 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 02d9091d064a664cdc3999ec5e4de66e24c09bef..05b30ac4114a462e1148d45887c8a54fea6758d4 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 b2596d77bc4043995a8fca37e3c52555433dac39..b0fa50be838b3d2a064a0e569cfc2ec63df6f581 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 be77a04fdcb42c826352d2467bebf1c37e54b8bc..c43d30ebf809b61b750156899434574fa474ec94 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 7a5779bd3febc3c7c20a37847e7b76a2f3191d3b..a0a2b52e110d553499b35b3b4237f955866480bd 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/returnStatement.h b/ets2panda/ir/statements/returnStatement.h index cacaf713a77d7b33281721073dea6680f01c6cff..2e2efaf8da232a47c16cb0ef0863994fb0032546 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/statements/switchCaseStatement.cpp b/ets2panda/ir/statements/switchCaseStatement.cpp index d3b4ab31eaa9d4bfcabffbf0afb8081c0d07ad80..3830c777c6445b27e21d45b8b7069cbdda0e9a73 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 0ed32b85facd23ca10301372f9e6c2616dd9e74e..886520a6f719792a1a9835481d2750439f97e1ee 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 4bc685e3b2ba20fc3c0f25c67c3d0a36e1eb8300..c7d908bd2d4ec163e47ee390b1a21ce49cb6b864 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 70a0fab7466e5818c6861ecb5897de991b770dc2..015d12a91bfddf44ceb5721c8e37a57328e9be58 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/tsAnyKeyword.cpp b/ets2panda/ir/ts/tsAnyKeyword.cpp index 170d086c834e06131469232c55c42778705bb7a6..c82f0274154bba1664f4055ba3082a96504a8266 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 5719a54c0a73cc95b06679d6190b869ba21910f6..e6f2d21e62f1ad86135cddb12d10f5ad84a36c92 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 f5759ccf7f82246b477557cff9dcbc2e04714c1b..7cc031e8a91543cfcef2b0a1a680ad182a2c90bc 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 a4936f1cecadf7e928448c41e891ebc3dcfd8eeb..c796b0e41c04d70a67e045d3b3fb3fd359fe1832 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 c1bb84f23b05aace5810caed65fa8ba22a0ed144..b0f73788e5517e4142ff969721f057e92825a6e0 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,89 +57,7 @@ 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()) { - 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) @@ -172,280 +79,23 @@ varbinder::EnumMemberResult EvaluateMemberExpression(checker::TSChecker *checker return false; } -varbinder::EnumMemberResult EvaluateBinaryExpression(checker::TSChecker *checker, varbinder::EnumVariable *enum_var, - const ir::BinaryExpression *expr) +void TSEnumDeclaration::Compile(compiler::PandaGen *pg) const { - 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; + pg->GetAstCompiler()->Compile(this); } -varbinder::EnumMemberResult TSEnumDeclaration::EvaluateEnumMember(checker::TSChecker *checker, - varbinder::EnumVariable *enum_var, - const ir::AstNode *expr) +void TSEnumDeclaration::Compile(compiler::ETSGen *etsg) 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; -} - -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); + etsg->GetAstCompiler()->Compile(this); } -checker::Type *TSEnumDeclaration::InferType(checker::TSChecker *checker, bool is_const) const +checker::Type *TSEnumDeclaration::Check(checker::TSChecker *checker) { - 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; -} - -checker::Type *TSEnumDeclaration::Check([[maybe_unused]] checker::TSChecker *checker) -{ - 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); - } - - return nullptr; + 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 72a6d0870e70927c208743b2179173baf897b3e6..d6d318a62bd846c8181de21aeb724de6def6f45c 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 d0cb459a00ee3e5d787bc70aacf7b6c7f14c48cc..adb6873dd8b5ffb09e1c3451e10afe28b93c95ba 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 52918aee6035283dfd9502090324f2035ba06f66..c169a782db2bbe14f6bcd09d903471fd837df8a1 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 5e9aa155d8e9903772b48181c504ae15de8bb758..601c235a021631515e75a58bcc15a6f566762db8 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 2ab4685a25524fa460de66ddb231c6ffd88a94bd..00ec35da541200445121e4b99bbaf29834a6ec67 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 294e15b549f5c62458c1e8322542441823f881ad..13aca3172f286fb496bf7b9cbaecaacd2f6cdb43 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 f9012741687d4613e41392c7af9b026847ad9e0a..5debdb8a4a114c28859cc24b147b06321b57eeb1 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 eb471e9d7b1502b6ba6895968a7fc19c2d77e7c8..da0fea006153b8aca88c0a39aecb43b9f7db034f 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 d06a36dde29392f550497276e762ee1a3272e4aa..ecbb83c4518d66c430daa21e2884b04c653c30f8 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 3374b8bb51d9eccd2a48ca08990eab939e65a420..11caf9ca5a439ab380ae10e48c43135243033167 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 14b8cf390d545b080368bce3979fa6622077265e..611c2a70f90643775d63d26876d10b9c4cb40998 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 6d889996c82dab60fced9a83fd9230db62ce8c4d..ba59f6f222104216981d9d0947bfec593be26db7 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 1dcc42d743a2803f468a43a8c3b008a09752eca3..1bbf96fcfdea6d51a220218457fc74afa8ab5703 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 3799e4b62b1b288094101bfeda5d8b18558db5b7..d8e35bf46a3b69854a8209cb66f10adb66a48b21 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 0e912ca124800fd68f94ae4bf3a615cfadfdaec2..642f239a53d7f929e544c44b1b2e63a0c4cd5299 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 43417ff96ac18a52f86f0ea68ce7fded722ac217..47502deb375b1b5088bd99d2837c606d2f93b6d4 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 6a1d20d35d712a7631f8c1e483d6ae377c68048d..d1869ab617e16b767aaf296e818456b3d6d91067 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