diff --git a/BUILD.gn b/BUILD.gn index 99b4a26efe5d858895b44d50fc60166ab698188e..8663df87208714a800ee7d95c44ad9ca0cf1726b 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -138,6 +138,7 @@ libes2panda_sources = [ "compiler/core/JSCompiler.cpp", "compiler/core/JSemitter.cpp", "compiler/core/codeGen.cpp", + "compiler/core/ASTVerifier.cpp", "compiler/core/compileJob.cpp", "compiler/core/compileQueue.cpp", "compiler/core/compilerContext.cpp", diff --git a/CMakeLists.txt b/CMakeLists.txt index e49880048b39a7862c1959de208a79d92c2719a7..b34882d04858cdb74b422b54727fbbe973c8c977 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -102,6 +102,7 @@ set(ES2PANDA_LIB_SRC compiler/base/literals.cpp compiler/base/lreference.cpp compiler/base/optionalChain.cpp + compiler/core/ASTVerifier.cpp compiler/core/codeGen.cpp compiler/core/compileJob.cpp compiler/core/compileQueue.cpp diff --git a/checker/ETSAnalyzer.cpp b/checker/ETSAnalyzer.cpp index 2e05e528f30d1b428c49aef664379507c47a488b..d4423b285ea207d27ee9eb468f0169015eda8919 100644 --- a/checker/ETSAnalyzer.cpp +++ b/checker/ETSAnalyzer.cpp @@ -16,15 +16,9 @@ #include "binder/binder.h" #include "binder/ETSBinder.h" +#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 { @@ -233,37 +227,55 @@ checker::Type *ETSAnalyzer::Check(ir::ETSPackageDeclaration *st) const checker::Type *ETSAnalyzer::Check(ir::ETSParameterExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + if (expr->TsType() == nullptr) { + checker::Type *param_type; + + if (expr->Ident()->TsType() != nullptr) { + param_type = expr->Ident()->TsType(); + } else { + param_type = !expr->IsRestParameter() ? expr->Ident()->Check(checker) : expr->spread_->Check(checker); + if (expr->IsDefault()) { + [[maybe_unused]] auto *const init_type = expr->Initializer()->Check(checker); + // TODO(ttamas) : fix this aftet nullable fix + // const checker::AssignmentContext ctx(checker->Relation(), initializer_, init_type, name_type, + // initializer_->Start(), + // {"Initializers type is not assignable to the target type"}); + } + } + + expr->SetTsType(param_type); + } + + return expr->TsType(); } -checker::Type *ETSAnalyzer::Check(ir::ETSPrimitiveType *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ETSPrimitiveType *node) const { - (void)node; - UNREACHABLE(); + return nullptr; } checker::Type *ETSAnalyzer::Check(ir::ETSStructDeclaration *node) const { - (void)node; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + node->Definition()->Check(checker); + return nullptr; } checker::Type *ETSAnalyzer::Check(ir::ETSTypeReference *node) const { - (void)node; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + return node->GetType(checker); } checker::Type *ETSAnalyzer::Check(ir::ETSTypeReferencePart *node) const { - (void)node; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + return node->GetType(checker); } -checker::Type *ETSAnalyzer::Check(ir::ETSWildcardType *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ETSWildcardType *node) const { - (void)node; UNREACHABLE(); } // compile methods for EXPRESSIONS in alphabetical order @@ -275,8 +287,70 @@ checker::Type *ETSAnalyzer::Check(ir::ArrayExpression *expr) const checker::Type *ETSAnalyzer::Check(ir::ArrowFunctionExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + if (expr->TsType() != nullptr) { + return expr->TsType(); + } + + auto *func_type = checker->BuildFunctionSignature(expr->Function(), false); + + if (expr->Function()->IsAsyncFunc()) { + auto *ret_type = static_cast(expr->Function()->Signature()->ReturnType()); + if (ret_type->AssemblerName() != checker->GlobalBuiltinPromiseType()->AssemblerName()) { + checker->ThrowTypeError("Return type of async lambda must be 'Promise'", expr->Function()->Start()); + } + } + + checker::ScopeContext scope_ctx(checker, expr->Function()->Scope()); + + if (checker->HasStatus(checker::CheckerStatus::IN_INSTANCE_EXTENSION_METHOD)) { + /* + example code: + ``` + class A { + prop:number + } + function A.method() { + let a = () => { + console.println(this.prop) + } + } + ``` + here the enclosing class of arrow function should be Class A + */ + checker->Context().SetContainingClass( + checker->Scope()->Find(binder::Binder::MANDATORY_PARAM_THIS).variable->TsType()->AsETSObjectType()); + } + + checker::SavedCheckerContext saved_context(checker, checker->Context().Status(), + checker->Context().ContainingClass()); + checker->AddStatus(checker::CheckerStatus::IN_LAMBDA); + checker->Context().SetContainingSignature(func_type->CallSignatures()[0]); + + auto *body_type = expr->Function()->Body()->Check(checker); + + if (expr->Function()->Body()->IsExpression()) { + if (expr->Function()->ReturnTypeAnnotation() == nullptr) { + func_type->CallSignatures()[0]->SetReturnType(body_type); + } + + checker::AssignmentContext( + checker->Relation(), expr->Function()->Body()->AsExpression(), body_type, + func_type->CallSignatures()[0]->ReturnType(), expr->Function()->Start(), + {"Return statements return type is not compatible with the containing functions return type"}, + checker::TypeRelationFlag::DIRECT_RETURN); + } + + checker->Context().SetContainingSignature(nullptr); + checker->CheckCapturedVariables(); + + for (auto [var, _] : checker->Context().CapturedVars()) { + (void)_; + expr->CapturedVars().push_back(var); + } + + expr->SetTsType(func_type); + return expr->TsType(); } checker::Type *ETSAnalyzer::Check(ir::AssignmentExpression *expr) const @@ -491,25 +565,96 @@ checker::Type *ETSAnalyzer::Check(ir::ExportSpecifier *st) const checker::Type *ETSAnalyzer::Check(ir::ImportDeclaration *st) const { - (void)st; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + checker::Type *type = nullptr; + for (auto *spec : st->Specifiers()) { + if (spec->IsImportNamespaceSpecifier()) { + type = spec->AsImportNamespaceSpecifier()->Check(checker); + } + } + + return type; } -checker::Type *ETSAnalyzer::Check(ir::ImportDefaultSpecifier *st) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ImportDefaultSpecifier *st) const { - (void)st; UNREACHABLE(); } checker::Type *ETSAnalyzer::Check(ir::ImportNamespaceSpecifier *st) const { - (void)st; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + if (st->Local()->Name().Empty()) { + return nullptr; + } + + if (st->Local()->AsIdentifier()->TsType() != nullptr) { + return st->Local()->TsType(); + } + + auto *import_decl = st->Parent()->AsETSImportDeclaration(); + auto import_path = import_decl->Source()->Str(); + + if (import_decl->IsPureDynamic()) { + auto *type = checker->GlobalBuiltinDynamicType(import_decl->Language()); + checker->SetrModuleObjectTsType(st->Local(), type); + return type; + } + + std::string package_name = + (import_decl->Module() == nullptr) ? import_path.Mutf8() : import_decl->Module()->Str().Mutf8(); + + std::replace(package_name.begin(), package_name.end(), '/', '.'); + util::UString package_path(package_name, checker->Allocator()); + std::vector synthetic_names = checker->GetNameForSynteticObjectType(package_path.View()); + + ASSERT(!synthetic_names.empty()); + + auto assembler_name = synthetic_names[0]; + if (import_decl->Module() != nullptr) { + assembler_name = util::UString(assembler_name.Mutf8().append(".").append(compiler::Signatures::ETS_GLOBAL), + checker->Allocator()) + .View(); + } + + auto *module_object_type = + checker->Allocator()->New(checker->Allocator(), synthetic_names[0], assembler_name, + st->Local()->AsIdentifier(), checker::ETSObjectFlags::CLASS); + + auto *root_decl = checker->Allocator()->New(synthetic_names[0]); + binder::LocalVariable *root_var = + checker->Allocator()->New(root_decl, binder::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); + binder::LocalVariable *var = + checker->Allocator()->New(class_decl, binder::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 @@ -533,26 +678,32 @@ checker::Type *ETSAnalyzer::Check(ir::BreakStatement *st) const checker::Type *ETSAnalyzer::Check(ir::ClassDeclaration *st) const { - (void)st; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + st->Definition()->Check(checker); + return nullptr; } checker::Type *ETSAnalyzer::Check(ir::ContinueStatement *st) const { - (void)st; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + st->target_ = checker->FindJumpTarget(st->Type(), st, st->Ident()); + return nullptr; } -checker::Type *ETSAnalyzer::Check(ir::DebuggerStatement *st) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::DebuggerStatement *st) const { - (void)st; UNREACHABLE(); } checker::Type *ETSAnalyzer::Check(ir::DoWhileStatement *st) const { - (void)st; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + checker::ScopeContext scope_ctx(checker, st->Scope()); + + checker->CheckTruthinessOfType(st->Test()); + st->Body()->Check(checker); + + return nullptr; } checker::Type *ETSAnalyzer::Check(ir::EmptyStatement *st) const diff --git a/checker/SemanticAnalyzer.h b/checker/SemanticAnalyzer.h index 72cfe3735de6e7438ae231ba39f65cf98146e39e..8cc27451f53332c643d0c2cbf5c7139e84b51f76 100644 --- a/checker/SemanticAnalyzer.h +++ b/checker/SemanticAnalyzer.h @@ -17,6 +17,152 @@ #define ES2PANDA_CHECKER_SEMANTICANALYZER_H #include "compiler/core/dynamicContext.h" +#include "ir/opaqueTypeNode.h" +#include "ir/as/namedType.h" +#include "ir/as/prefixAssertionExpression.h" +#include "ir/base/catchClause.h" +#include "ir/base/classDefinition.h" +#include "ir/base/classProperty.h" +#include "ir/base/classStaticBlock.h" +#include "ir/base/decorator.h" +#include "ir/base/metaProperty.h" +#include "ir/base/methodDefinition.h" +#include "ir/base/property.h" +#include "ir/base/scriptFunction.h" +#include "ir/base/spreadElement.h" +#include "ir/base/templateElement.h" +#include "ir/base/tsIndexSignature.h" +#include "ir/base/tsMethodSignature.h" +#include "ir/base/tsPropertySignature.h" +#include "ir/base/tsSignatureDeclaration.h" +#include "ir/ets/etsClassLiteral.h" +#include "ir/ets/etsFunctionType.h" +#include "ir/ets/etsImportDeclaration.h" +#include "ir/ets/etsLaunchExpression.h" +#include "ir/ets/etsNewArrayInstanceExpression.h" +#include "ir/ets/etsNewClassInstanceExpression.h" +#include "ir/ets/etsNewMultiDimArrayInstanceExpression.h" +#include "ir/ets/etsPackageDeclaration.h" +#include "ir/ets/etsParameterExpression.h" +#include "ir/ets/etsPrimitiveType.h" +#include "ir/ets/etsScript.h" +#include "ir/ets/etsStructDeclaration.h" +#include "ir/ets/etsTypeReference.h" +#include "ir/ets/etsTypeReferencePart.h" +#include "ir/ets/etsWildcardType.h" +#include "ir/expressions/arrayExpression.h" +#include "ir/expressions/arrowFunctionExpression.h" +#include "ir/expressions/assignmentExpression.h" +#include "ir/expressions/awaitExpression.h" +#include "ir/expressions/binaryExpression.h" +#include "ir/expressions/callExpression.h" +#include "ir/expressions/chainExpression.h" +#include "ir/expressions/classExpression.h" +#include "ir/expressions/conditionalExpression.h" +#include "ir/expressions/directEvalExpression.h" +#include "ir/expressions/functionExpression.h" +#include "ir/expressions/identifier.h" +#include "ir/expressions/importExpression.h" +#include "ir/expressions/memberExpression.h" +#include "ir/expressions/newExpression.h" +#include "ir/expressions/objectExpression.h" +#include "ir/expressions/omittedExpression.h" +#include "ir/expressions/sequenceExpression.h" +#include "ir/expressions/superExpression.h" +#include "ir/expressions/taggedTemplateExpression.h" +#include "ir/expressions/templateLiteral.h" +#include "ir/expressions/thisExpression.h" +#include "ir/expressions/unaryExpression.h" +#include "ir/expressions/updateExpression.h" +#include "ir/expressions/yieldExpression.h" +#include "ir/expressions/literals/bigIntLiteral.h" +#include "ir/expressions/literals/booleanLiteral.h" +#include "ir/expressions/literals/charLiteral.h" +#include "ir/expressions/literals/nullLiteral.h" +#include "ir/expressions/literals/numberLiteral.h" +#include "ir/expressions/literals/regExpLiteral.h" +#include "ir/expressions/literals/stringLiteral.h" +#include "ir/module/exportAllDeclaration.h" +#include "ir/module/exportDefaultDeclaration.h" +#include "ir/module/exportNamedDeclaration.h" +#include "ir/module/exportSpecifier.h" +#include "ir/module/importDeclaration.h" +#include "ir/module/importDefaultSpecifier.h" +#include "ir/module/importNamespaceSpecifier.h" +#include "ir/module/importSpecifier.h" +#include "ir/statements/assertStatement.h" +#include "ir/statements/blockStatement.h" +#include "ir/statements/breakStatement.h" +#include "ir/statements/classDeclaration.h" +#include "ir/statements/continueStatement.h" +#include "ir/statements/debuggerStatement.h" +#include "ir/statements/doWhileStatement.h" +#include "ir/statements/emptyStatement.h" +#include "ir/statements/expressionStatement.h" +#include "ir/statements/forInStatement.h" +#include "ir/statements/forOfStatement.h" +#include "ir/statements/forUpdateStatement.h" +#include "ir/statements/functionDeclaration.h" +#include "ir/statements/ifStatement.h" +#include "ir/statements/labelledStatement.h" +#include "ir/statements/returnStatement.h" +#include "ir/statements/switchCaseStatement.h" +#include "ir/statements/switchStatement.h" +#include "ir/statements/throwStatement.h" +#include "ir/statements/tryStatement.h" +#include "ir/statements/variableDeclaration.h" +#include "ir/statements/variableDeclarator.h" +#include "ir/statements/whileStatement.h" +#include "ir/ts/tsAnyKeyword.h" +#include "ir/ts/tsArrayType.h" +#include "ir/ts/tsAsExpression.h" +#include "ir/ts/tsBigintKeyword.h" +#include "ir/ts/tsBooleanKeyword.h" +#include "ir/ts/tsClassImplements.h" +#include "ir/ts/tsConditionalType.h" +#include "ir/ts/tsConstructorType.h" +#include "ir/ts/tsEnumDeclaration.h" +#include "ir/ts/tsEnumMember.h" +#include "ir/ts/tsExternalModuleReference.h" +#include "ir/ts/tsFunctionType.h" +#include "ir/ts/tsImportEqualsDeclaration.h" +#include "ir/ts/tsImportType.h" +#include "ir/ts/tsIndexedAccessType.h" +#include "ir/ts/tsInferType.h" +#include "ir/ts/tsInterfaceBody.h" +#include "ir/ts/tsInterfaceDeclaration.h" +#include "ir/ts/tsInterfaceHeritage.h" +#include "ir/ts/tsIntersectionType.h" +#include "ir/ts/tsLiteralType.h" +#include "ir/ts/tsMappedType.h" +#include "ir/ts/tsModuleBlock.h" +#include "ir/ts/tsModuleDeclaration.h" +#include "ir/ts/tsNamedTupleMember.h" +#include "ir/ts/tsNeverKeyword.h" +#include "ir/ts/tsNonNullExpression.h" +#include "ir/ts/tsNullKeyword.h" +#include "ir/ts/tsNumberKeyword.h" +#include "ir/ts/tsObjectKeyword.h" +#include "ir/ts/tsParameterProperty.h" +#include "ir/ts/tsParenthesizedType.h" +#include "ir/ts/tsQualifiedName.h" +#include "ir/ts/tsStringKeyword.h" +#include "ir/ts/tsThisType.h" +#include "ir/ts/tsTupleType.h" +#include "ir/ts/tsTypeAliasDeclaration.h" +#include "ir/ts/tsTypeAssertion.h" +#include "ir/ts/tsTypeLiteral.h" +#include "ir/ts/tsTypeOperator.h" +#include "ir/ts/tsTypeParameterDeclaration.h" +#include "ir/ts/tsTypeParameter.h" +#include "ir/ts/tsTypeParameterInstantiation.h" +#include "ir/ts/tsTypePredicate.h" +#include "ir/ts/tsTypeQuery.h" +#include "ir/ts/tsTypeReference.h" +#include "ir/ts/tsUndefinedKeyword.h" +#include "ir/ts/tsUnionType.h" +#include "ir/ts/tsUnknownKeyword.h" +#include "ir/ts/tsVoidKeyword.h" namespace panda::es2panda::checker { class Checker; diff --git a/checker/TSAnalyzer.cpp b/checker/TSAnalyzer.cpp index f5bfa79b2f493c500b2a5eb57e720362351182ea..b7b55e561e5536db04a29ed9a77e136ce4ea4592 100644 --- a/checker/TSAnalyzer.cpp +++ b/checker/TSAnalyzer.cpp @@ -16,12 +16,7 @@ #include "TSAnalyzer.h" #include "checker/TSchecker.h" -#include "ir/base/catchClause.h" -#include "ir/base/methodDefinition.h" -#include "ir/base/scriptFunction.h" -#include "ir/statements/blockStatement.h" -#include "ir/statements/returnStatement.h" -#include "ir/typeNode.h" +#include "checker/ts/destructuringContext.h" #include "util/helpers.h" namespace panda::es2panda::checker { @@ -191,39 +186,33 @@ checker::Type *TSAnalyzer::Check(ir::ETSPackageDeclaration *st) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::ETSParameterExpression *expr) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ETSParameterExpression *expr) const { - (void)expr; UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::ETSPrimitiveType *node) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ETSPrimitiveType *node) const { - (void)node; UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::ETSStructDeclaration *node) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ETSStructDeclaration *node) const { - (void)node; UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::ETSTypeReference *node) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ETSTypeReference *node) const { - (void)node; UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::ETSTypeReferencePart *node) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ETSTypeReferencePart *node) const { - (void)node; UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::ETSWildcardType *node) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ETSWildcardType *node) const { - (void)node; UNREACHABLE(); } // compile methods for EXPRESSIONS in alphabetical order @@ -235,8 +224,35 @@ checker::Type *TSAnalyzer::Check(ir::ArrayExpression *expr) const checker::Type *TSAnalyzer::Check(ir::ArrowFunctionExpression *expr) const { - (void)expr; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + binder::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())); + + if (!expr->Function()->Body()->IsExpression()) { + expr->Function()->Body()->Check(checker); + } + + return func_type; } checker::Type *TSAnalyzer::Check(ir::AssignmentExpression *expr) const @@ -449,27 +465,23 @@ checker::Type *TSAnalyzer::Check(ir::ExportSpecifier *st) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::ImportDeclaration *st) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ImportDeclaration *st) const { - (void)st; UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::ImportDefaultSpecifier *st) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ImportDefaultSpecifier *st) const { - (void)st; UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::ImportNamespaceSpecifier *st) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ImportNamespaceSpecifier *st) const { - (void)st; UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::ImportSpecifier *st) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ImportSpecifier *st) const { - (void)st; UNREACHABLE(); } // compile methods for STATEMENTS in alphabetical order @@ -491,9 +503,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(); } @@ -503,16 +514,21 @@ checker::Type *TSAnalyzer::Check(ir::ContinueStatement *st) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::DebuggerStatement *st) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::DebuggerStatement *st) const { - (void)st; UNREACHABLE(); } checker::Type *TSAnalyzer::Check(ir::DoWhileStatement *st) const { - (void)st; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + checker::ScopeContext scope_ctx(checker, st->Scope()); + + checker::Type *test_type = st->Test()->Check(checker); + checker->CheckTruthinessOfType(test_type, st->Test()->Start()); + st->Body()->Check(checker); + + return nullptr; } checker::Type *TSAnalyzer::Check(ir::EmptyStatement *st) const diff --git a/compiler/core/ASTCompiler.h b/compiler/core/ASTCompiler.h index b5bd6661794f22acfc3e000542ef9b1282941eda..03fdde033adf00ef433610758d7e7dbcbdccb6c0 100644 --- a/compiler/core/ASTCompiler.h +++ b/compiler/core/ASTCompiler.h @@ -17,6 +17,152 @@ #define ES2PANDA_COMPILER_CORE_ASTCOMPILER_H #include "compiler/core/dynamicContext.h" +#include "ir/opaqueTypeNode.h" +#include "ir/as/namedType.h" +#include "ir/as/prefixAssertionExpression.h" +#include "ir/base/catchClause.h" +#include "ir/base/classDefinition.h" +#include "ir/base/classProperty.h" +#include "ir/base/classStaticBlock.h" +#include "ir/base/decorator.h" +#include "ir/base/metaProperty.h" +#include "ir/base/methodDefinition.h" +#include "ir/base/property.h" +#include "ir/base/scriptFunction.h" +#include "ir/base/spreadElement.h" +#include "ir/base/templateElement.h" +#include "ir/base/tsIndexSignature.h" +#include "ir/base/tsMethodSignature.h" +#include "ir/base/tsPropertySignature.h" +#include "ir/base/tsSignatureDeclaration.h" +#include "ir/ets/etsClassLiteral.h" +#include "ir/ets/etsFunctionType.h" +#include "ir/ets/etsImportDeclaration.h" +#include "ir/ets/etsLaunchExpression.h" +#include "ir/ets/etsNewArrayInstanceExpression.h" +#include "ir/ets/etsNewClassInstanceExpression.h" +#include "ir/ets/etsNewMultiDimArrayInstanceExpression.h" +#include "ir/ets/etsPackageDeclaration.h" +#include "ir/ets/etsParameterExpression.h" +#include "ir/ets/etsPrimitiveType.h" +#include "ir/ets/etsScript.h" +#include "ir/ets/etsStructDeclaration.h" +#include "ir/ets/etsTypeReference.h" +#include "ir/ets/etsTypeReferencePart.h" +#include "ir/ets/etsWildcardType.h" +#include "ir/expressions/arrayExpression.h" +#include "ir/expressions/arrowFunctionExpression.h" +#include "ir/expressions/assignmentExpression.h" +#include "ir/expressions/awaitExpression.h" +#include "ir/expressions/binaryExpression.h" +#include "ir/expressions/callExpression.h" +#include "ir/expressions/chainExpression.h" +#include "ir/expressions/classExpression.h" +#include "ir/expressions/conditionalExpression.h" +#include "ir/expressions/directEvalExpression.h" +#include "ir/expressions/functionExpression.h" +#include "ir/expressions/identifier.h" +#include "ir/expressions/importExpression.h" +#include "ir/expressions/memberExpression.h" +#include "ir/expressions/newExpression.h" +#include "ir/expressions/objectExpression.h" +#include "ir/expressions/omittedExpression.h" +#include "ir/expressions/sequenceExpression.h" +#include "ir/expressions/superExpression.h" +#include "ir/expressions/taggedTemplateExpression.h" +#include "ir/expressions/templateLiteral.h" +#include "ir/expressions/thisExpression.h" +#include "ir/expressions/unaryExpression.h" +#include "ir/expressions/updateExpression.h" +#include "ir/expressions/yieldExpression.h" +#include "ir/expressions/literals/bigIntLiteral.h" +#include "ir/expressions/literals/booleanLiteral.h" +#include "ir/expressions/literals/charLiteral.h" +#include "ir/expressions/literals/nullLiteral.h" +#include "ir/expressions/literals/numberLiteral.h" +#include "ir/expressions/literals/regExpLiteral.h" +#include "ir/expressions/literals/stringLiteral.h" +#include "ir/module/exportAllDeclaration.h" +#include "ir/module/exportDefaultDeclaration.h" +#include "ir/module/exportNamedDeclaration.h" +#include "ir/module/exportSpecifier.h" +#include "ir/module/importDeclaration.h" +#include "ir/module/importDefaultSpecifier.h" +#include "ir/module/importNamespaceSpecifier.h" +#include "ir/module/importSpecifier.h" +#include "ir/statements/assertStatement.h" +#include "ir/statements/blockStatement.h" +#include "ir/statements/breakStatement.h" +#include "ir/statements/classDeclaration.h" +#include "ir/statements/continueStatement.h" +#include "ir/statements/debuggerStatement.h" +#include "ir/statements/doWhileStatement.h" +#include "ir/statements/emptyStatement.h" +#include "ir/statements/expressionStatement.h" +#include "ir/statements/forInStatement.h" +#include "ir/statements/forOfStatement.h" +#include "ir/statements/forUpdateStatement.h" +#include "ir/statements/functionDeclaration.h" +#include "ir/statements/ifStatement.h" +#include "ir/statements/labelledStatement.h" +#include "ir/statements/returnStatement.h" +#include "ir/statements/switchCaseStatement.h" +#include "ir/statements/switchStatement.h" +#include "ir/statements/throwStatement.h" +#include "ir/statements/tryStatement.h" +#include "ir/statements/variableDeclaration.h" +#include "ir/statements/variableDeclarator.h" +#include "ir/statements/whileStatement.h" +#include "ir/ts/tsAnyKeyword.h" +#include "ir/ts/tsArrayType.h" +#include "ir/ts/tsAsExpression.h" +#include "ir/ts/tsBigintKeyword.h" +#include "ir/ts/tsBooleanKeyword.h" +#include "ir/ts/tsClassImplements.h" +#include "ir/ts/tsConditionalType.h" +#include "ir/ts/tsConstructorType.h" +#include "ir/ts/tsEnumDeclaration.h" +#include "ir/ts/tsEnumMember.h" +#include "ir/ts/tsExternalModuleReference.h" +#include "ir/ts/tsFunctionType.h" +#include "ir/ts/tsImportEqualsDeclaration.h" +#include "ir/ts/tsImportType.h" +#include "ir/ts/tsIndexedAccessType.h" +#include "ir/ts/tsInferType.h" +#include "ir/ts/tsInterfaceBody.h" +#include "ir/ts/tsInterfaceDeclaration.h" +#include "ir/ts/tsInterfaceHeritage.h" +#include "ir/ts/tsIntersectionType.h" +#include "ir/ts/tsLiteralType.h" +#include "ir/ts/tsMappedType.h" +#include "ir/ts/tsModuleBlock.h" +#include "ir/ts/tsModuleDeclaration.h" +#include "ir/ts/tsNamedTupleMember.h" +#include "ir/ts/tsNeverKeyword.h" +#include "ir/ts/tsNonNullExpression.h" +#include "ir/ts/tsNullKeyword.h" +#include "ir/ts/tsNumberKeyword.h" +#include "ir/ts/tsObjectKeyword.h" +#include "ir/ts/tsParameterProperty.h" +#include "ir/ts/tsParenthesizedType.h" +#include "ir/ts/tsQualifiedName.h" +#include "ir/ts/tsStringKeyword.h" +#include "ir/ts/tsThisType.h" +#include "ir/ts/tsTupleType.h" +#include "ir/ts/tsTypeAliasDeclaration.h" +#include "ir/ts/tsTypeAssertion.h" +#include "ir/ts/tsTypeLiteral.h" +#include "ir/ts/tsTypeOperator.h" +#include "ir/ts/tsTypeParameterDeclaration.h" +#include "ir/ts/tsTypeParameter.h" +#include "ir/ts/tsTypeParameterInstantiation.h" +#include "ir/ts/tsTypePredicate.h" +#include "ir/ts/tsTypeQuery.h" +#include "ir/ts/tsTypeReference.h" +#include "ir/ts/tsUndefinedKeyword.h" +#include "ir/ts/tsUnionType.h" +#include "ir/ts/tsUnknownKeyword.h" +#include "ir/ts/tsVoidKeyword.h" namespace panda::es2panda::compiler { class CodeGen; diff --git a/compiler/core/ASTVerifier.cpp b/compiler/core/ASTVerifier.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f59438c301e16963727eee4a563f37305bd0c933 --- /dev/null +++ b/compiler/core/ASTVerifier.cpp @@ -0,0 +1,409 @@ +/** + * Copyright (c) 2021-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ASTVerifier.h" + +#include "es2panda.h" +#include "binder/variableFlags.h" +#include "binder/scope.h" +#include "ir/astNode.h" +#include "ir/base/catchClause.h" +#include "ir/base/classDefinition.h" +#include "ir/base/classStaticBlock.h" +#include "ir/base/methodDefinition.h" +#include "ir/base/scriptFunction.h" +#include "ir/ets/etsFunctionType.h" +#include "ir/ets/etsNewClassInstanceExpression.h" +#include "ir/ets/etsPackageDeclaration.h" +#include "ir/ets/etsParameterExpression.h" +#include "ir/ets/etsTypeReference.h" +#include "ir/ets/etsTypeReferencePart.h" +#include "ir/expressions/callExpression.h" +#include "ir/expressions/functionExpression.h" +#include "ir/expressions/identifier.h" +#include "ir/expressions/memberExpression.h" +#include "ir/expressions/literals/numberLiteral.h" +#include "ir/expressions/literals/stringLiteral.h" +#include "ir/statements/blockStatement.h" +#include "ir/statements/classDeclaration.h" +#include "ir/statements/expressionStatement.h" +#include "ir/statements/throwStatement.h" +#include "ir/statements/tryStatement.h" +#include "ir/statements/variableDeclaration.h" +#include "ir/statements/variableDeclarator.h" +#include "ir/ts/tsClassImplements.h" +#include "ir/ts/tsTypeParameter.h" +#include "ir/ts/tsTypeParameterDeclaration.h" +#include "ir/ts/tsTypeParameterInstantiation.h" + +namespace panda::es2panda::compiler { + +bool ASTVerifier::IsCorrectProgram(const parser::Program *program) +{ + bool is_correct = true; + error_messages_.clear(); + + for (auto *statement : program->Ast()->Statements()) { + is_correct &= HaveParents(statement); + } + is_correct &= HaveParents(program->GlobalClass()); + + for (auto *statement : program->Ast()->Statements()) { + is_correct &= HaveTypes(statement); + } + is_correct &= HaveTypes(program->GlobalClass()); + + for (auto *statement : program->Ast()->Statements()) { + is_correct &= HaveVariables(statement); + } + is_correct &= HaveVariables(program->GlobalClass()); + + for (auto *statement : program->Ast()->Statements()) { + is_correct &= HaveScopes(statement); + } + is_correct &= HaveScopes(program->GlobalClass()); + +#ifndef NDEBUG + std::for_each(error_messages_.begin(), error_messages_.end(), [](auto const msg) { LOG(INFO, COMMON) << msg; }); +#endif // NDEBUG + return is_correct; +} + +std::string ToStringHelper(const binder::ScopeType type) +{ + switch (type) { + case binder::ScopeType::CATCH: { + return "CATCH"; + } + case binder::ScopeType::CATCH_PARAM: { + return "CATCH_PARAM"; + } + case binder::ScopeType::CLASS: { + return "CLASS"; + } + case binder::ScopeType::FUNCTION: { + return "FUNCTION"; + } + case binder::ScopeType::FUNCTION_PARAM: { + return "FUNCTION_PARAM"; + } + case binder::ScopeType::GLOBAL: { + return "GLOBAL"; + } + case binder::ScopeType::LOCAL: { + return "LOCAL"; + } + case binder::ScopeType::LOOP: { + return "LOOP"; + } + case binder::ScopeType::LOOP_DECL: { + return "LOOP_DECL"; + } + case binder::ScopeType::MODULE: { + return "MODULE"; + } + case binder::ScopeType::PARAM: { + return "PARAM"; + } + default: { + return "MUST BE UNREACHABLE"; + } + } +} + +std::string ToStringHelper(const util::StringView &name) +{ + return name == nullptr ? "" : name.Mutf8(); +} + +std::string ToStringHelper(const binder::Scope *scope) +{ + if (scope == nullptr) { + return ""; + } + + switch (scope->Type()) { + case binder::ScopeType::FUNCTION: { + return "FUNC_SCOPE " + ToStringHelper(scope->AsFunctionScope()->Name()); + } + case binder::ScopeType::LOCAL: { + return "LOCAL_SCOPE "; + } + case binder::ScopeType::CATCH: { + return "CATCH_SCOPE "; + } + default: { + return "MUST BE UNREACHABLE"; + } + } +} + +std::string ToStringHelper(const binder::Variable *var) +{ + if (var == nullptr) { + return ""; + } + + switch (var->Type()) { + case binder::VariableType::LOCAL: { + return "LOCAL_VAR " + ToStringHelper(var->Name()); + } + case binder::VariableType::MODULE: { + return "MODULE_VAR " + ToStringHelper(var->Name()); + } + case binder::VariableType::GLOBAL: { + return "GLOBAL_VAR " + ToStringHelper(var->Name()); + } + case binder::VariableType::ENUM: { + return "ENUM_VAR " + ToStringHelper(var->Name()); + } + default: { + return "MUST BE UNREACHABLE"; + } + } +} + +template +std::string ToStringParamsHelper(const ir::AstNode *parent, const ArenaVector ¶ms) +{ + std::string name; + if (parent != nullptr) { + name = ToStringHelper(parent) + " "; + } + + name += "("; + for (auto const *param : params) { + name += ToStringHelper(param); + } + + return name + ")"; +} + +std::string ToStringHelper(const ir::AstNode *ast) +{ + if (ast == nullptr) { + return ""; + } + + switch (ast->Type()) { + case ir::AstNodeType::IDENTIFIER: { + return "ID " + ToStringHelper(ast->AsIdentifier()->Name()); + } + case ir::AstNodeType::CLASS_DEFINITION: { + return "CLS_DEF " + ToStringHelper(ast->AsClassDefinition()->Ident()); + } + case ir::AstNodeType::CLASS_DECLARATION: { + return "CLS_DECL " + ToStringHelper(ast->AsClassDeclaration()->Definition()); + } + case ir::AstNodeType::BLOCK_STATEMENT: { + return "BLOCK " + ToStringHelper(ast->AsBlockStatement()->Scope()); + } + case ir::AstNodeType::SCRIPT_FUNCTION: { + auto const *sf = ast->AsScriptFunction(); + return "SCRIPT_FUN " + ToStringHelper(sf->Scope()) + "::" + ToStringHelper(sf->Id()); + } + case ir::AstNodeType::FUNCTION_EXPRESSION: { + return "FUN_EXPR " + ToStringHelper(ast->AsFunctionExpression()->Function()); + } + case ir::AstNodeType::METHOD_DEFINITION: { + return "METHOD_DEF " + ToStringHelper(ast->AsMethodDefinition()->Value()); + } + case ir::AstNodeType::ETS_TYPE_REFERENCE_PART: { + return "TYPE_REF_PART " + ToStringHelper(ast->AsETSTypeReferencePart()->Name()); + } + case ir::AstNodeType::ETS_TYPE_REFERENCE: { + return "TYPE_REF " + ToStringHelper(ast->AsETSTypeReference()->Part()); + } + case ir::AstNodeType::VARIABLE_DECLARATOR: { + return "VAR_DECLARATOR " + ToStringHelper(ast->AsVariableDeclarator()->Id()); + } + case ir::AstNodeType::VARIABLE_DECLARATION: { + if (ast->AsVariableDeclaration()->Declarators().empty()) { + return "VAR_DECLARATION "; + } + return "VAR_DECLARATION " + ToStringHelper(ast->AsVariableDeclaration()->Declarators().at(0)); + } + case ir::AstNodeType::CALL_EXPRESSION: { + return "CALL_EXPR " + ToStringHelper(ast->AsCallExpression()->Callee()) + "(...)"; + } + case ir::AstNodeType::EXPRESSION_STATEMENT: { + return "EXPR_STMT " + ToStringHelper(ast->AsExpressionStatement()->GetExpression()); + } + case ir::AstNodeType::MEMBER_EXPRESSION: { + auto const *me = ast->AsMemberExpression(); + return "MEMBER_EXPR " + ToStringHelper(me->Object()) + "." + ToStringHelper(me->Property()); + } + case ir::AstNodeType::CLASS_STATIC_BLOCK: { + return "CLS_STATIC_BLOCK " + ToStringHelper(ast->AsClassStaticBlock()->Function()); + } + case ir::AstNodeType::ETS_PACKAGE_DECLARATION: { + return "PKG_DECL "; + } + case ir::AstNodeType::TS_TYPE_PARAMETER_DECLARATION: { + return "PARAM_DECL " + ToStringParamsHelper( + ast->Parent(), ast->AsTSTypeParameterDeclaration()->Params()); + } + case ir::AstNodeType::TS_TYPE_PARAMETER: { + return "TYPE_PARAM " + ToStringHelper(ast->AsTSTypeParameter()->Name()); + } + case ir::AstNodeType::TS_TYPE_PARAMETER_INSTANTIATION: { + return "PARAM_INSTANTIATION " + + ToStringParamsHelper(ast->Parent(), ast->AsTSTypeParameterInstantiation()->Params()); + } + case ir::AstNodeType::THROW_STATEMENT: { + return "THROW_STMT " + ToStringHelper(ast->AsThrowStatement()->Argument()); + } + case ir::AstNodeType::ETS_NEW_CLASS_INSTANCE_EXPRESSION: { + return "NEW_CLS_INSTANCE " + ToStringHelper(ast->AsETSNewClassInstanceExpression()->GetTypeRef()); + } + case ir::AstNodeType::STRING_LITERAL: { + return "STR_LITERAL " + ToStringHelper(ast->AsStringLiteral()->Str()); + } + case ir::AstNodeType::TRY_STATEMENT: { + return "TRY_STMT " + ToStringHelper(ast->AsTryStatement()->Block()); + } + case ir::AstNodeType::CATCH_CLAUSE: { + return "CATCH_CLAUSE "; + } + case ir::AstNodeType::NUMBER_LITERAL: { + return "NUMBER_LITERAL " + ToStringHelper(ast->AsNumberLiteral()->Str()); + } + case ir::AstNodeType::ETS_PARAMETER_EXPRESSION: { + return "ETS_PARAM_EXPR " + ToStringHelper(ast->AsETSParameterExpression()->Ident()); + } + case ir::AstNodeType::TS_INTERFACE_DECLARATION: { + return "TS_INTERFACE_DECL " + ToStringHelper(ast->AsTSInterfaceDeclaration()->Id()); + } + case ir::AstNodeType::TS_INTERFACE_BODY: { + return "TS_INTERFACE_BODY "; + } + case ir::AstNodeType::ETS_FUNCTION_TYPE: { + return "ETS_FUNC_TYPE " + + ToStringParamsHelper(ast->Parent(), ast->AsETSFunctionType()->Params()); + } + case ir::AstNodeType::TS_CLASS_IMPLEMENTS: { + return "TS_CLASS_IMPL " + ToStringHelper(ast->AsTSClassImplements()->Expr()); + } + default: { + return "MUST BE UNREACHABLE"; + } + } +} + +bool ASTVerifier::HasParent(const ir::AstNode *ast) +{ + if (ast == nullptr) { + return false; + } + + if (ast->Parent() == nullptr) { + error_messages_.push_back("NULL_PARENT: " + ToStringHelper(ast)); + return false; + } + + return true; +} + +bool ASTVerifier::HaveParents(const ir::AstNode *ast) +{ + if (ast == nullptr) { + return false; + } + + bool has_parent = HasParent(ast); + ast->IterateRecursively([this, &has_parent](ir::AstNode *child) { has_parent &= HasParent(child); }); + return has_parent; +} + +bool ASTVerifier::HasType(const ir::AstNode *ast) +{ + if (ast == nullptr) { + return false; + } + + if (ast->IsTyped() && static_cast(ast)->TsType() == nullptr) { + error_messages_.push_back("NULL_TS_TYPE: " + ToStringHelper(ast)); + return false; + } + return true; +} + +bool ASTVerifier::HaveTypes(const ir::AstNode *ast) +{ + if (ast == nullptr) { + return false; + } + + bool has_type = HasType(ast); + ast->IterateRecursively([this, &has_type](ir::AstNode *child) { has_type &= HasType(child); }); + return has_type; +} + +bool ASTVerifier::HasVariable(const ir::AstNode *ast) +{ + if (ast == nullptr) { + return false; + } + + if (!ast->IsIdentifier() || ast->AsIdentifier()->Variable() != nullptr) { + return true; + } + + error_messages_.push_back("NULL_VARIABLE: " + ToStringHelper(ast->AsIdentifier())); + return false; +} + +bool ASTVerifier::HaveVariables(const ir::AstNode *ast) +{ + if (ast == nullptr) { + return false; + } + + bool has_variable = HasVariable(ast); + ast->IterateRecursively([this, &has_variable](ir::AstNode *child) { has_variable &= HasVariable(child); }); + return has_variable; +} + +bool ASTVerifier::HasScope(const ir::AstNode *ast) +{ + if (ast == nullptr) { + return false; + } + + if (!ast->IsIdentifier()) { + return true; // we will check only Identifier + } + // we will check only local variables of identifiers + if (HasVariable(ast) && ast->AsIdentifier()->Variable()->IsLocalVariable() && + ast->AsIdentifier()->Variable()->AsLocalVariable()->GetScope() == nullptr) { + error_messages_.push_back("NULL_SCOPE_LOCAL_VAR: " + ToStringHelper(ast)); + return false; + } + // TODO(tatiana): Add check that the scope enclose this identifier + return true; +} + +bool ASTVerifier::HaveScopes(const ir::AstNode *ast) +{ + if (ast == nullptr) { + return false; + } + + bool has_scope = HasScope(ast); + ast->IterateRecursively([this, &has_scope](ir::AstNode *child) { has_scope &= HasScope(child); }); + return has_scope; +} + +} // namespace panda::es2panda::compiler diff --git a/compiler/core/ASTVerifier.h b/compiler/core/ASTVerifier.h new file mode 100644 index 0000000000000000000000000000000000000000..d9bdba1180982ab20a5050b1b263dfe8f9db2cda --- /dev/null +++ b/compiler/core/ASTVerifier.h @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ES2PANDA_COMPILER_CORE_ASTVERIFIER_H +#define ES2PANDA_COMPILER_CORE_ASTVERIFIER_H + +#include "parser/program/program.h" + +namespace panda::es2panda::compiler { + +class ASTVerifier { +public: + using ErrorMessages = std::vector; + NO_COPY_SEMANTIC(ASTVerifier); + NO_MOVE_SEMANTIC(ASTVerifier); + + ASTVerifier() = default; + ~ASTVerifier() = default; + + bool IsCorrectProgram(const parser::Program *program); + bool HaveParents(const ir::AstNode *ast); + bool HasParent(const ir::AstNode *ast); + bool HaveTypes(const ir::AstNode *ast); + bool HasType(const ir::AstNode *ast); + bool HaveVariables(const ir::AstNode *ast); + bool HasVariable(const ir::AstNode *ast); + bool HasScope(const ir::AstNode *ast); + bool HaveScopes(const ir::AstNode *ast); + + ErrorMessages GetErrorMessages() + { + return error_messages_; + } + +private: + ErrorMessages error_messages_; +}; + +std::string ToStringHelper(const ir::AstNode *ast); + +} // namespace panda::es2panda::compiler + +#endif // ES2PANDA_COMPILER_CORE_ASTVERIFIER_H diff --git a/compiler/core/ETSCompiler.cpp b/compiler/core/ETSCompiler.cpp index c7f91c0d7962a2e2b8797f073f71b64e0e9c642f..104ff2b4b58da2b40d703c6dcd6d881a80343b92 100644 --- a/compiler/core/ETSCompiler.cpp +++ b/compiler/core/ETSCompiler.cpp @@ -15,13 +15,11 @@ #include "ETSCompiler.h" +#include "checker/types/ets/etsDynamicFunctionType.h" +#include "compiler/base/condition.h" #include "compiler/base/lreference.h" #include "compiler/core/ETSGen.h" -#include "ir/base/catchClause.h" -#include "ir/base/classProperty.h" -#include "ir/expressions/identifier.h" -#include "ir/statements/blockStatement.h" -#include "ir/statements/returnStatement.h" +#include "compiler/function/functionBuilder.h" namespace panda::es2panda::compiler { @@ -198,38 +196,36 @@ void ETSCompiler::Compile(const ir::ETSPackageDeclaration *st) const void ETSCompiler::Compile(const ir::ETSParameterExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + expr->Ident()->Identifier::Compile(etsg); } -void ETSCompiler::Compile(const ir::ETSPrimitiveType *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::ETSPrimitiveType *node) const { - (void)node; UNREACHABLE(); } -void ETSCompiler::Compile(const ir::ETSStructDeclaration *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::ETSStructDeclaration *node) const { - (void)node; UNREACHABLE(); } void ETSCompiler::Compile(const ir::ETSTypeReference *node) const { - (void)node; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + node->Part()->Compile(etsg); } void ETSCompiler::Compile(const ir::ETSTypeReferencePart *node) const { - (void)node; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + node->Name()->Compile(etsg); } -void ETSCompiler::Compile(const ir::ETSWildcardType *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::ETSWildcardType *node) const { - (void)node; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + etsg->Unimplemented(); } // compile methods for EXPRESSIONS in alphabetical order void ETSCompiler::Compile(const ir::ArrayExpression *expr) const @@ -240,8 +236,23 @@ void ETSCompiler::Compile(const ir::ArrayExpression *expr) const void ETSCompiler::Compile(const ir::ArrowFunctionExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + ASSERT(expr->ResolvedLambda() != nullptr); + auto *ctor = expr->ResolvedLambda()->TsType()->AsETSObjectType()->ConstructSignatures()[0]; + std::vector arguments; + + for (auto *it : expr->CapturedVars()) { + if (it->HasFlag(binder::VariableFlags::LOCAL)) { + arguments.push_back(it->AsLocalVariable()->Vreg()); + } + } + + if (expr->propagate_this_) { + arguments.push_back(etsg->GetThisReg()); + } + + etsg->InitLambdaObject(expr, ctor, arguments); + etsg->SetAccumulatorType(expr->resolved_lambda_->TsType()); } void ETSCompiler::Compile(const ir::AssignmentExpression *expr) const @@ -454,27 +465,23 @@ void ETSCompiler::Compile(const ir::ExportSpecifier *st) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::ImportDeclaration *st) const +void ETSCompiler::Compile([[maybe_unused]] const ir::ImportDeclaration *st) const { - (void)st; UNREACHABLE(); } -void ETSCompiler::Compile(const ir::ImportDefaultSpecifier *st) const +void ETSCompiler::Compile([[maybe_unused]] const ir::ImportDefaultSpecifier *st) const { - (void)st; UNREACHABLE(); } -void ETSCompiler::Compile(const ir::ImportNamespaceSpecifier *st) const +void ETSCompiler::Compile([[maybe_unused]] const ir::ImportNamespaceSpecifier *st) const { - (void)st; UNREACHABLE(); } -void ETSCompiler::Compile(const ir::ImportSpecifier *st) const +void ETSCompiler::Compile([[maybe_unused]] const ir::ImportSpecifier *st) const { - (void)st; UNREACHABLE(); } // compile methods for STATEMENTS in alphabetical order @@ -496,28 +503,55 @@ void ETSCompiler::Compile(const ir::BreakStatement *st) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::ClassDeclaration *st) const +void ETSCompiler::Compile([[maybe_unused]] const ir::ClassDeclaration *st) const { - (void)st; UNREACHABLE(); } +static void CompileImpl(const ir::ContinueStatement *self, ETSGen *etsg) +{ + compiler::Label *target = etsg->ControlFlowChangeContinue(self->Ident()); + etsg->Branch(self, target); +} + void ETSCompiler::Compile(const ir::ContinueStatement *st) const { - (void)st; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + if (etsg->ExtendWithFinalizer(st->parent_, st)) { + return; + } + CompileImpl(st, etsg); } -void ETSCompiler::Compile(const ir::DebuggerStatement *st) const +void ETSCompiler::Compile([[maybe_unused]] const ir::DebuggerStatement *st) const { - (void)st; UNREACHABLE(); } +void CompileImpl(const ir::DoWhileStatement *self, ETSGen *etsg) +{ + auto *start_label = etsg->AllocLabel(); + compiler::LabelTarget label_target(etsg); + + etsg->SetLabel(self, start_label); + + { + compiler::LocalRegScope reg_scope(etsg, self->Scope()); + compiler::LabelContext label_ctx(etsg, label_target); + self->Body()->Compile(etsg); + } + + etsg->SetLabel(self, label_target.ContinueTarget()); + compiler::Condition::Compile(etsg, self->Test(), label_target.BreakTarget()); + + etsg->Branch(self, start_label); + etsg->SetLabel(self, label_target.BreakTarget()); +} + void ETSCompiler::Compile(const ir::DoWhileStatement *st) const { - (void)st; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + CompileImpl(st, etsg); } void ETSCompiler::Compile(const ir::EmptyStatement *st) const diff --git a/compiler/core/JSCompiler.cpp b/compiler/core/JSCompiler.cpp index a0b4815892d893a6432ee139e5fcea744c7a4b0c..732540bd41d7d381d5f3d661b0e9f19f9be5c9f4 100644 --- a/compiler/core/JSCompiler.cpp +++ b/compiler/core/JSCompiler.cpp @@ -15,18 +15,10 @@ #include "JSCompiler.h" +#include "compiler/base/condition.h" #include "compiler/base/lreference.h" #include "compiler/core/pandagen.h" -#include "ir/base/catchClause.h" -#include "ir/base/classDefinition.h" -#include "ir/base/classProperty.h" -#include "ir/base/classStaticBlock.h" -#include "ir/base/methodDefinition.h" -#include "ir/base/scriptFunction.h" -#include "ir/expressions/functionExpression.h" -#include "ir/expressions/identifier.h" -#include "ir/statements/blockStatement.h" -#include "ir/statements/returnStatement.h" +#include "compiler/function/functionBuilder.h" #include "util/helpers.h" namespace panda::es2panda::compiler { @@ -523,39 +515,33 @@ void JSCompiler::Compile(const ir::ETSPackageDeclaration *expr) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::ETSParameterExpression *expr) const +void JSCompiler::Compile([[maybe_unused]] const ir::ETSParameterExpression *expr) const { - (void)expr; UNREACHABLE(); } -void JSCompiler::Compile(const ir::ETSPrimitiveType *expr) const +void JSCompiler::Compile([[maybe_unused]] const ir::ETSPrimitiveType *expr) const { - (void)expr; UNREACHABLE(); } -void JSCompiler::Compile(const ir::ETSStructDeclaration *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::ETSStructDeclaration *node) const { - (void)node; UNREACHABLE(); } -void JSCompiler::Compile(const ir::ETSTypeReference *expr) const +void JSCompiler::Compile([[maybe_unused]] const ir::ETSTypeReference *expr) const { - (void)expr; UNREACHABLE(); } -void JSCompiler::Compile(const ir::ETSTypeReferencePart *expr) const +void JSCompiler::Compile([[maybe_unused]] const ir::ETSTypeReferencePart *expr) const { - (void)expr; UNREACHABLE(); } -void JSCompiler::Compile(const ir::ETSWildcardType *expr) const +void JSCompiler::Compile([[maybe_unused]] const ir::ETSWildcardType *expr) const { - (void)expr; UNREACHABLE(); } @@ -568,8 +554,8 @@ void JSCompiler::Compile(const ir::ArrayExpression *expr) const void JSCompiler::Compile(const ir::ArrowFunctionExpression *expr) const { - (void)expr; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + pg->DefineFunction(expr->Function(), expr->Function(), expr->Function()->Scope()->InternalName()); } void JSCompiler::Compile(const ir::AssignmentExpression *expr) const @@ -782,27 +768,20 @@ void JSCompiler::Compile(const ir::ExportSpecifier *st) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::ImportDeclaration *st) const -{ - (void)st; - UNREACHABLE(); -} +void JSCompiler::Compile([[maybe_unused]] const ir::ImportDeclaration *st) const {} -void JSCompiler::Compile(const ir::ImportDefaultSpecifier *st) const +void JSCompiler::Compile([[maybe_unused]] const ir::ImportDefaultSpecifier *st) const { - (void)st; UNREACHABLE(); } -void JSCompiler::Compile(const ir::ImportNamespaceSpecifier *st) const +void JSCompiler::Compile([[maybe_unused]] const ir::ImportNamespaceSpecifier *st) const { - (void)st; UNREACHABLE(); } -void JSCompiler::Compile(const ir::ImportSpecifier *st) const +void JSCompiler::Compile([[maybe_unused]] const ir::ImportSpecifier *st) const { - (void)st; UNREACHABLE(); } // Compile methods for STATEMENTS in alphabetical order @@ -826,26 +805,50 @@ void JSCompiler::Compile(const ir::BreakStatement *st) const void JSCompiler::Compile(const ir::ClassDeclaration *st) const { - (void)st; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + auto lref = compiler::JSLReference::Create(pg, st->Definition()->Ident(), true); + st->Definition()->Compile(pg); + lref.SetValue(); +} + +static void CompileImpl(const ir::ContinueStatement *self, PandaGen *cg) +{ + compiler::Label *target = cg->ControlFlowChangeContinue(self->Ident()); + cg->Branch(self, target); } void JSCompiler::Compile(const ir::ContinueStatement *st) const { - (void)st; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + CompileImpl(st, pg); } -void JSCompiler::Compile(const ir::DebuggerStatement *st) const +void JSCompiler::Compile([[maybe_unused]] const ir::DebuggerStatement *st) const {} + +static void CompileImpl(const ir::DoWhileStatement *self, PandaGen *cg) { - (void)st; - UNREACHABLE(); + auto *start_label = cg->AllocLabel(); + compiler::LabelTarget label_target(cg); + + cg->SetLabel(self, start_label); + + { + compiler::LocalRegScope reg_scope(cg, self->Scope()); + compiler::LabelContext label_ctx(cg, label_target); + self->Body()->Compile(cg); + } + + cg->SetLabel(self, label_target.ContinueTarget()); + compiler::Condition::Compile(cg, self->Test(), label_target.BreakTarget()); + + cg->Branch(self, start_label); + cg->SetLabel(self, label_target.BreakTarget()); } void JSCompiler::Compile(const ir::DoWhileStatement *st) const { - (void)st; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + CompileImpl(st, pg); } void JSCompiler::Compile(const ir::EmptyStatement *st) const diff --git a/compiler/lowering/phase.cpp b/compiler/lowering/phase.cpp index 5877c6e4907ef23c263a0290514724a6c3c3becb..0b7c300573d1bcf2bf72fea9e6ec70e3d668a095 100644 --- a/compiler/lowering/phase.cpp +++ b/compiler/lowering/phase.cpp @@ -15,6 +15,7 @@ #include "phase.h" #include "checker/checker.h" +#include "compiler/core/ASTVerifier.h" #include "compiler/core/compilerContext.h" #include "lexer/token/sourceLocation.h" #include "compiler/lowering/checkerPhase.h" @@ -57,6 +58,10 @@ bool Phase::Apply(CompilerContext *ctx, parser::Program *program) } #ifndef NDEBUG + ASTVerifier ast_before; + if (!ast_before.IsCorrectProgram(program)) { + // TODO(tatiana): Add some error processing + } if (!Precondition(ctx, program)) { ctx->Checker()->ThrowTypeError({"Precondition check failed for ", Name()}, lexer::SourcePosition {}); } @@ -72,6 +77,10 @@ bool Phase::Apply(CompilerContext *ctx, parser::Program *program) } #ifndef NDEBUG + ASTVerifier ast_after; + if (!ast_after.IsCorrectProgram(program)) { + // TODO(tatiana): Add some error processing + } if (!Postcondition(ctx, program)) { ctx->Checker()->ThrowTypeError({"Postcondition check failed for ", Name()}, lexer::SourcePosition {}); } diff --git a/ir/astNode.h b/ir/astNode.h index b9558663a3a25fd3e987cc93a64866b1fa0e4b12..5accd1e728953732abeb88275b0252004feebff8 100644 --- a/ir/astNode.h +++ b/ir/astNode.h @@ -227,6 +227,11 @@ public: return false; } + virtual bool IsTyped() const + { + return false; + } + // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define DECLARE_AS_CASTS(nodeType, className) \ className *As##className() \ @@ -587,6 +592,11 @@ public: ts_type_ = ts_type; } + bool IsTyped() const override + { + return true; + } + protected: explicit Typed(AstNodeType const type) : T(type) {} explicit Typed(AstNodeType const type, ModifierFlags const flags) : T(type, flags) {} diff --git a/ir/ets/etsParameterExpression.cpp b/ir/ets/etsParameterExpression.cpp index c862ffe69700f0e0eb8df259431497a42cf888d3..30fee78aa4f556aff9461fd5fa689f1cc5183758 100644 --- a/ir/ets/etsParameterExpression.cpp +++ b/ir/ets/etsParameterExpression.cpp @@ -15,9 +15,11 @@ #include "etsParameterExpression.h" -#include "compiler/core/pandagen.h" #include "checker/ETSchecker.h" #include "checker/ets/typeRelationContext.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "ir/astDump.h" #include "ir/typeNode.h" #include "ir/expressions/identifier.h" @@ -140,43 +142,24 @@ void ETSParameterExpression::Dump(ir::AstDumper *const dumper) const } } -void ETSParameterExpression::Compile([[maybe_unused]] compiler::PandaGen *const pg) const +void ETSParameterExpression::Compile(compiler::PandaGen *const pg) const { - UNREACHABLE(); + pg->GetAstCompiler()->Compile(this); } -void ETSParameterExpression::Compile([[maybe_unused]] compiler::ETSGen *const etsg) const +void ETSParameterExpression::Compile(compiler::ETSGen *const etsg) const { - ident_->Identifier::Compile(etsg); + etsg->GetAstCompiler()->Compile(this); } -checker::Type *ETSParameterExpression::Check([[maybe_unused]] checker::TSChecker *const checker) +checker::Type *ETSParameterExpression::Check(checker::TSChecker *const checker) { - UNREACHABLE(); + return checker->GetAnalyzer()->Check(this); } checker::Type *ETSParameterExpression::Check(checker::ETSChecker *const checker) { - if (TsType() == nullptr) { - checker::Type *param_type; - - if (ident_->TsType() != nullptr) { - param_type = ident_->TsType(); - } else { - param_type = !IsRestParameter() ? ident_->Check(checker) : spread_->Check(checker); - if (IsDefault()) { - [[maybe_unused]] auto *const init_type = initializer_->Check(checker); - // TODO(ttamas) : fix this aftet nullable fix - // const checker::AssignmentContext ctx(checker->Relation(), initializer_, init_type, name_type, - // initializer_->Start(), - // {"Initializers type is not assignable to the target type"}); - } - } - - SetTsType(param_type); - } - - return TsType(); + return checker->GetAnalyzer()->Check(this); } // NOLINTNEXTLINE(google-default-arguments) diff --git a/ir/ets/etsParameterExpression.h b/ir/ets/etsParameterExpression.h index d63a3dd887cd921d18cacf3f9e98f1a327a0fdb3..1160289e8857c7061ed70be9d20f93637d05f9b3 100644 --- a/ir/ets/etsParameterExpression.h +++ b/ir/ets/etsParameterExpression.h @@ -18,6 +18,10 @@ #include "ir/expression.h" +namespace panda::es2panda::checker { +class ETSAnalyzer; +} // namespace panda::es2panda::checker + namespace panda::es2panda::ir { class ETSParameterExpression final : public Expression { public: @@ -29,6 +33,9 @@ public: explicit ETSParameterExpression(AnnotatedExpression *ident_or_spread, Expression *initializer); + // TODO (csabahurton): friend relationship can be removed once there are getters for private fields + friend class checker::ETSAnalyzer; + [[nodiscard]] const Identifier *Ident() const noexcept; [[nodiscard]] Identifier *Ident() noexcept; diff --git a/ir/ets/etsPrimitiveType.cpp b/ir/ets/etsPrimitiveType.cpp index 820b6fb5448dc8d09b2a45b200d35fd229f549cb..7e722d78c6c25cb8134f8a32d09d8adbfe49b296 100644 --- a/ir/ets/etsPrimitiveType.cpp +++ b/ir/ets/etsPrimitiveType.cpp @@ -15,10 +15,11 @@ #include "etsPrimitiveType.h" -#include "ir/astDump.h" #include "checker/TSchecker.h" #include "checker/ETSchecker.h" #include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" +#include "ir/astDump.h" namespace panda::es2panda::ir { void ETSPrimitiveType::TransformChildren([[maybe_unused]] const NodeTransformer &cb) {} @@ -29,16 +30,19 @@ void ETSPrimitiveType::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "ETSPrimitiveType"}}); } -void ETSPrimitiveType::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void ETSPrimitiveType::Compile(compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} -void ETSPrimitiveType::Compile([[maybe_unused]] compiler::ETSGen *etsg) const +void ETSPrimitiveType::Compile(compiler::ETSGen *etsg) const { - UNREACHABLE(); + etsg->GetAstCompiler()->Compile(this); } -checker::Type *ETSPrimitiveType::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *ETSPrimitiveType::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *ETSPrimitiveType::GetType([[maybe_unused]] checker::TSChecker *checker) @@ -46,9 +50,9 @@ checker::Type *ETSPrimitiveType::GetType([[maybe_unused]] checker::TSChecker *ch return checker->GlobalAnyType(); } -checker::Type *ETSPrimitiveType::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *ETSPrimitiveType::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *ETSPrimitiveType::GetType([[maybe_unused]] checker::ETSChecker *checker) diff --git a/ir/ets/etsPrimitiveType.h b/ir/ets/etsPrimitiveType.h index c8ae085f4585c41133ece704a672f1730826cc76..c394b0019617a7cee0117fe9a666514feda59b01 100644 --- a/ir/ets/etsPrimitiveType.h +++ b/ir/ets/etsPrimitiveType.h @@ -33,11 +33,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; - 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; checker::Type *GetType([[maybe_unused]] checker::ETSChecker *checker) override; private: diff --git a/ir/ets/etsStructDeclaration.cpp b/ir/ets/etsStructDeclaration.cpp index 62f8b74cdf5b9d4c5b577779dc33efa932f0d523..3b05f2717a58e9f06fd49b95e29ce09bdb8838d4 100644 --- a/ir/ets/etsStructDeclaration.cpp +++ b/ir/ets/etsStructDeclaration.cpp @@ -15,6 +15,7 @@ #include "etsStructDeclaration.h" +#include "checker/TSchecker.h" #include "compiler/base/lreference.h" #include "compiler/core/pandagen.h" #include "compiler/core/ETSGen.h" @@ -48,24 +49,23 @@ void ETSStructDeclaration::Dump(ir::AstDumper *dumper) const {{"type", "ETSStructDeclaration"}, {"definition", def_}, {"decorators", AstDumper::Optional(decorators_)}}); } -void ETSStructDeclaration::Compile([[maybe_unused]] compiler::PandaGen *pg) const +void ETSStructDeclaration::Compile(compiler::PandaGen *pg) const { - UNREACHABLE(); + pg->GetAstCompiler()->Compile(this); } -void ETSStructDeclaration::Compile([[maybe_unused]] compiler::ETSGen *etsg) const +void ETSStructDeclaration::Compile(compiler::ETSGen *etsg) const { - UNREACHABLE(); + etsg->GetAstCompiler()->Compile(this); } -checker::Type *ETSStructDeclaration::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *ETSStructDeclaration::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *ETSStructDeclaration::Check(checker::ETSChecker *checker) { - def_->Check(checker); - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ir/ets/etsStructDeclaration.h b/ir/ets/etsStructDeclaration.h index 7a52e9b804388b7722ac9993ddced626184610ec..10a2201ab66054c5439654f7c01363b52520d218 100644 --- a/ir/ets/etsStructDeclaration.h +++ b/ir/ets/etsStructDeclaration.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/ir/ets/etsTypeReference.cpp b/ir/ets/etsTypeReference.cpp index 849f5234630df198d5d699fb7da1081ed8f802a4..7ac21bd519609eefdad4dd3b0d8ad0d0a1438b1f 100644 --- a/ir/ets/etsTypeReference.cpp +++ b/ir/ets/etsTypeReference.cpp @@ -15,11 +15,13 @@ #include "etsTypeReference.h" +#include "checker/ETSchecker.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "ir/astDump.h" #include "ir/ts/tsQualifiedName.h" #include "ir/ets/etsTypeReferencePart.h" -#include "checker/ETSchecker.h" -#include "compiler/core/ETSGen.h" namespace panda::es2panda::ir { void ETSTypeReference::TransformChildren(const NodeTransformer &cb) @@ -60,20 +62,23 @@ void ETSTypeReference::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "ETSTypeReference"}, {"part", part_}}); } -void ETSTypeReference::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} -void ETSTypeReference::Compile([[maybe_unused]] compiler::ETSGen *etsg) const +void ETSTypeReference::Compile(compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} +void ETSTypeReference::Compile(compiler::ETSGen *etsg) const { - part_->Compile(etsg); + etsg->GetAstCompiler()->Compile(this); } -checker::Type *ETSTypeReference::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *ETSTypeReference::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *ETSTypeReference::Check(checker::ETSChecker *checker) { - return GetType(checker); + return checker->GetAnalyzer()->Check(this); } checker::Type *ETSTypeReference::GetType(checker::ETSChecker *checker) diff --git a/ir/ets/etsTypeReference.h b/ir/ets/etsTypeReference.h index 17b8ef6ce1c30595a325a66579d06005fa28314c..d771dcceb0b8cdfb80668aa6d9861e7ec4d51f04 100644 --- a/ir/ets/etsTypeReference.h +++ b/ir/ets/etsTypeReference.h @@ -41,10 +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; - 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; checker::Type *GetType([[maybe_unused]] checker::ETSChecker *checker) override; private: diff --git a/ir/ets/etsTypeReferencePart.cpp b/ir/ets/etsTypeReferencePart.cpp index 4d86e09056694abe5f068f41ab938457160d3c9e..79a2b4e97a74dcaa63f37e1151bd8c658e2331cd 100644 --- a/ir/ets/etsTypeReferencePart.cpp +++ b/ir/ets/etsTypeReferencePart.cpp @@ -15,13 +15,12 @@ #include "etsTypeReferencePart.h" -#include "ir/astDump.h" -#include "ir/expressions/identifier.h" -#include "ir/ts/tsTypeParameterInstantiation.h" -#include "checker/TSchecker.h" #include "checker/ETSchecker.h" #include "checker/ets/typeRelationContext.h" +#include "checker/TSchecker.h" #include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" +#include "ir/astDump.h" namespace panda::es2panda::ir { void ETSTypeReferencePart::TransformChildren(const NodeTransformer &cb) @@ -58,20 +57,23 @@ void ETSTypeReferencePart::Dump(ir::AstDumper *dumper) const {"previous", AstDumper::Optional(prev_)}}); } -void ETSTypeReferencePart::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} -void ETSTypeReferencePart::Compile([[maybe_unused]] compiler::ETSGen *etsg) const +void ETSTypeReferencePart::Compile(compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} +void ETSTypeReferencePart::Compile(compiler::ETSGen *etsg) const { - name_->Compile(etsg); + etsg->GetAstCompiler()->Compile(this); } -checker::Type *ETSTypeReferencePart::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *ETSTypeReferencePart::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *ETSTypeReferencePart::Check(checker::ETSChecker *checker) { - return GetType(checker); + return checker->GetAnalyzer()->Check(this); } checker::Type *ETSTypeReferencePart::GetType(checker::ETSChecker *checker) diff --git a/ir/ets/etsTypeReferencePart.h b/ir/ets/etsTypeReferencePart.h index f8d82bcf2934f5df7b119ff7dd3952b6b5eca2a2..f3e4b8aafa150d7615ff64c1cbaf4c5b84146efd 100644 --- a/ir/ets/etsTypeReferencePart.h +++ b/ir/ets/etsTypeReferencePart.h @@ -58,10 +58,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; checker::Type *GetType([[maybe_unused]] checker::ETSChecker *checker) override; private: diff --git a/ir/ets/etsWildcardType.cpp b/ir/ets/etsWildcardType.cpp index 07db87b9c6c5e99b1846269df3f178c6b0c3ee33..76c5ea1cc3fa4cc74d2e5b7de0644e290332dc51 100644 --- a/ir/ets/etsWildcardType.cpp +++ b/ir/ets/etsWildcardType.cpp @@ -15,11 +15,12 @@ #include "etsWildcardType.h" -#include "ir/astDump.h" -#include "ir/ets/etsTypeReference.h" -#include "checker/TSchecker.h" #include "checker/ETSchecker.h" +#include "checker/TSchecker.h" #include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" +#include "ir/astDump.h" +#include "ir/ets/etsTypeReference.h" namespace panda::es2panda::ir { void ETSWildcardType::TransformChildren(const NodeTransformer &cb) @@ -44,16 +45,19 @@ void ETSWildcardType::Dump(ir::AstDumper *dumper) const {"out", AstDumper::Optional(IsOut())}}); } -void ETSWildcardType::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void ETSWildcardType::Compile(compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} -void ETSWildcardType::Compile([[maybe_unused]] compiler::ETSGen *etsg) const +void ETSWildcardType::Compile(compiler::ETSGen *etsg) const { - etsg->Unimplemented(); + etsg->GetAstCompiler()->Compile(this); } -checker::Type *ETSWildcardType::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *ETSWildcardType::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *ETSWildcardType::GetType([[maybe_unused]] checker::TSChecker *checker) @@ -61,9 +65,9 @@ checker::Type *ETSWildcardType::GetType([[maybe_unused]] checker::TSChecker *che return nullptr; } -checker::Type *ETSWildcardType::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *ETSWildcardType::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *ETSWildcardType::GetType([[maybe_unused]] checker::ETSChecker *checker) diff --git a/ir/ets/etsWildcardType.h b/ir/ets/etsWildcardType.h index 4ce8ce2adbed61728aa477c22a1d7fdec22f3a5c..ca14342e0d1e44b64cab6164cb81721b8ba5bfbf 100644 --- a/ir/ets/etsWildcardType.h +++ b/ir/ets/etsWildcardType.h @@ -36,11 +36,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; - 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; checker::Type *GetType([[maybe_unused]] checker::ETSChecker *checker) override; private: diff --git a/ir/expressions/arrowFunctionExpression.cpp b/ir/expressions/arrowFunctionExpression.cpp index a7ceaf07c98cedf1e0434fd224eafc22f089b02c..0cb1b3b65fda36d2382bd984c471d1ff3110e718 100644 --- a/ir/expressions/arrowFunctionExpression.cpp +++ b/ir/expressions/arrowFunctionExpression.cpp @@ -44,124 +44,21 @@ void ArrowFunctionExpression::Dump(ir::AstDumper *dumper) const void ArrowFunctionExpression::Compile(compiler::PandaGen *pg) const { - pg->DefineFunction(func_, func_, func_->Scope()->InternalName()); + pg->GetAstCompiler()->Compile(this); } void ArrowFunctionExpression::Compile(compiler::ETSGen *etsg) const { - ASSERT(resolved_lambda_ != nullptr); - auto *ctor = resolved_lambda_->TsType()->AsETSObjectType()->ConstructSignatures()[0]; - std::vector arguments; - - for (auto *it : captured_vars_) { - if (it->HasFlag(binder::VariableFlags::LOCAL)) { - arguments.push_back(it->AsLocalVariable()->Vreg()); - } - } - - if (propagate_this_) { - arguments.push_back(etsg->GetThisReg()); - } - - etsg->InitLambdaObject(this, ctor, arguments); - etsg->SetAccumulatorType(resolved_lambda_->TsType()); + etsg->GetAstCompiler()->Compile(this); } checker::Type *ArrowFunctionExpression::Check(checker::TSChecker *checker) { - binder::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_)); - - if (!func_->Body()->IsExpression()) { - func_->Body()->Check(checker); - } - - return func_type; + return checker->GetAnalyzer()->Check(this); } checker::Type *ArrowFunctionExpression::Check(checker::ETSChecker *checker) { - if (TsType() != nullptr) { - return TsType(); - } - - auto *func_type = checker->BuildFunctionSignature(func_, false); - - if (Function()->IsAsyncFunc()) { - auto *ret_type = static_cast(Function()->Signature()->ReturnType()); - if (ret_type->AssemblerName() != checker->GlobalBuiltinPromiseType()->AssemblerName()) { - checker->ThrowTypeError("Return type of async lambda must be 'Promise'", Function()->Start()); - } - } - - checker::ScopeContext scope_ctx(checker, func_->Scope()); - - if (checker->HasStatus(checker::CheckerStatus::IN_INSTANCE_EXTENSION_METHOD)) { - /* - example code: - ``` - class A { - prop:number - } - function A.method() { - let a = () => { - console.println(this.prop) - } - } - ``` - here the enclosing class of arrow function should be Class A - */ - checker->Context().SetContainingClass( - checker->Scope()->Find(binder::Binder::MANDATORY_PARAM_THIS).variable->TsType()->AsETSObjectType()); - } - - checker::SavedCheckerContext saved_context(checker, checker->Context().Status(), - checker->Context().ContainingClass()); - checker->AddStatus(checker::CheckerStatus::IN_LAMBDA); - checker->Context().SetContainingSignature(func_type->CallSignatures()[0]); - - auto *body_type = func_->Body()->Check(checker); - - if (func_->Body()->IsExpression()) { - if (func_->ReturnTypeAnnotation() == nullptr) { - func_type->CallSignatures()[0]->SetReturnType(body_type); - } - - checker::AssignmentContext( - checker->Relation(), func_->Body()->AsExpression(), body_type, func_type->CallSignatures()[0]->ReturnType(), - func_->Start(), - {"Return statements return type is not compatible with the containing functions return type"}, - checker::TypeRelationFlag::DIRECT_RETURN); - } - - checker->Context().SetContainingSignature(nullptr); - checker->CheckCapturedVariables(); - - for (auto [var, _] : checker->Context().CapturedVars()) { - (void)_; - captured_vars_.push_back(var); - } - - SetTsType(func_type); - return TsType(); + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ir/expressions/arrowFunctionExpression.h b/ir/expressions/arrowFunctionExpression.h index 5bcefdb81bafc68f1657f7ef856caeb730c6276c..204ce84ac5bb4e47207b3e8e6ed0344e793d852b 100644 --- a/ir/expressions/arrowFunctionExpression.h +++ b/ir/expressions/arrowFunctionExpression.h @@ -18,6 +18,10 @@ #include "ir/expression.h" +namespace panda::es2panda::compiler { +class ETSCompiler; +} // namespace panda::es2panda::compiler + namespace panda::es2panda::ir { class ScriptFunction; @@ -27,6 +31,8 @@ public: : Expression(AstNodeType::ARROW_FUNCTION_EXPRESSION), func_(func), captured_vars_(allocator->Adapter()) { } + // TODO (csabahurton): friend relationship can be removed once there are getters for private fields + friend class compiler::ETSCompiler; const ScriptFunction *Function() const { @@ -71,10 +77,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/ir/module/importDeclaration.cpp b/ir/module/importDeclaration.cpp index b946fbd1b679d90f467435cc458cbd68d79a3dbe..e1208b0d02a56bb3b2eb6ba72753ec14817a2ede 100644 --- a/ir/module/importDeclaration.cpp +++ b/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/ir/module/importDeclaration.h b/ir/module/importDeclaration.h index 18594b35e398f98c9fe13b2b31e26f42c2272922..fc8e923882bad9d6d0b209670f82e88cf8a5f284 100644 --- a/ir/module/importDeclaration.h +++ b/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/ir/module/importDefaultSpecifier.cpp b/ir/module/importDefaultSpecifier.cpp index 2413efb897afcfa10a9ee7636f5f788fa027f7a9..ea4a43b93e199df6aa0178d0fbca81eb82e89459 100644 --- a/ir/module/importDefaultSpecifier.cpp +++ b/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/ir/module/importDefaultSpecifier.h b/ir/module/importDefaultSpecifier.h index 7d39425a088c59f202e41c07c2acbc619f0478d3..0ad73508467408f9477946cf9ec2a776aac1a244 100644 --- a/ir/module/importDefaultSpecifier.h +++ b/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/ir/module/importNamespaceSpecifier.cpp b/ir/module/importNamespaceSpecifier.cpp index 466ed4e40798d89c5a66411c09fbe4384d442ec5..dc138e16357baebfba56bfdcacdb2433ca675cc1 100644 --- a/ir/module/importNamespaceSpecifier.cpp +++ b/ir/module/importNamespaceSpecifier.cpp @@ -15,12 +15,9 @@ #include "importNamespaceSpecifier.h" -#include "checker/ETSchecker.h" -#include "binder/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 +35,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]); - binder::LocalVariable *root_var = - checker->Allocator()->New(root_decl, binder::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); - binder::LocalVariable *var = - checker->Allocator()->New(class_decl, binder::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/ir/module/importNamespaceSpecifier.h b/ir/module/importNamespaceSpecifier.h index 0af20262ba57e28274a7974262ef5ca60a22978a..e725cce1aef38761c90498c64939d19eeabf2c45 100644 --- a/ir/module/importNamespaceSpecifier.h +++ b/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/ir/module/importSpecifier.cpp b/ir/module/importSpecifier.cpp index 343614347e2e30cb5af932d939965a43cac4ba45..984e4137d5861c8b746bb2fc0bbe2a63f02e5559 100644 --- a/ir/module/importSpecifier.cpp +++ b/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/ir/module/importSpecifier.h b/ir/module/importSpecifier.h index 9a0c1311abb9eee8973fb19ac1479b050cfabe99..c59fba3bed65f9dadc3658fc27678a920357a5c9 100644 --- a/ir/module/importSpecifier.h +++ b/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/ir/statements/classDeclaration.cpp b/ir/statements/classDeclaration.cpp index 6c0822d5f27188bd9be8fa96bf140895ef367ece..627e9bece0a42037e8d65b33e331a28d9073671d 100644 --- a/ir/statements/classDeclaration.cpp +++ b/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/ir/statements/classDeclaration.h b/ir/statements/classDeclaration.h index c2e535c0740205f0be808f6d4e772d51b8f8e7b1..8984cf0651ff6dcaf30a39b62ea9db4a58f2fb9f 100644 --- a/ir/statements/classDeclaration.h +++ b/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/ir/statements/continueStatement.cpp b/ir/statements/continueStatement.cpp index 47cc3d6e75fe40a27693b0b06e5a141ed8b99bcb..0dbdedb732b3813bc3b9d189e3769dae06a6c8fa 100644 --- a/ir/statements/continueStatement.cpp +++ b/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::Nullable(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/ir/statements/continueStatement.h b/ir/statements/continueStatement.h index 2eead3db014edee313f4d7df437480dc734736f2..804670d2a6c6a1186d1430dabb86549ef8c058d5 100644 --- a/ir/statements/continueStatement.h +++ b/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/ir/statements/debuggerStatement.cpp b/ir/statements/debuggerStatement.cpp index 506daf50ae480818324ae2a6532fa1dc2cd1ba5b..b0bb23faadd70a585650ec54cd7d21c5988d5c0f 100644 --- a/ir/statements/debuggerStatement.cpp +++ b/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/ir/statements/debuggerStatement.h b/ir/statements/debuggerStatement.h index d9858dbfd48308a8c4f381539a0c05f9936ab209..792af73b967f1e99bf3c29aa1a3b22ffe6e35131 100644 --- a/ir/statements/debuggerStatement.h +++ b/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/ir/statements/doWhileStatement.cpp b/ir/statements/doWhileStatement.cpp index d7a875423f3d52aeeab38069de7e109e159e9b53..4e39a23ba05f3884766f3e36bb9b0642e7a98f16 100644 --- a/ir/statements/doWhileStatement.cpp +++ b/ir/statements/doWhileStatement.cpp @@ -15,14 +15,9 @@ #include "doWhileStatement.h" -#include "binder/scope.h" -#include "compiler/base/condition.h" -#include "compiler/core/labelTarget.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 DoWhileStatement::TransformChildren(const NodeTransformer &cb) @@ -42,55 +37,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/ir/statements/doWhileStatement.h b/ir/statements/doWhileStatement.h index 58cf43cfca1af649dd59b60d67b4e6d3ef12fe2c..ee5fef663d88bb0c0e443a29c0c197c729840eb7 100644 --- a/ir/statements/doWhileStatement.h +++ b/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/ir/statements/tryStatement.h b/ir/statements/tryStatement.h index 74b955c87aca3f798585faf0c83457db28d74159..af69c1eb9d91f8f33a9ee79f4244c548b90e706b 100644 --- a/ir/statements/tryStatement.h +++ b/ir/statements/tryStatement.h @@ -16,7 +16,7 @@ #ifndef ES2PANDA_IR_STATEMENT_TRY_STATEMENT_H #define ES2PANDA_IR_STATEMENT_TRY_STATEMENT_H -#include "compiler/core/ETSGen.h" +#include "compiler/core/labelPair.h" #include "ir/statement.h" namespace panda::es2panda::compiler { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f40aed24be528f99fc880954a9bb04380f30fce6..ff14df7c4ae66ff22c3618052179032ef05d69e4 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -92,5 +92,17 @@ if(PANDA_WITH_ETS) add_dependencies(ets_tests es2panda_tests) endif() + panda_add_gtest( + NAME es2panda_astverifier_tests + SOURCES + public/ast_verifier_test.cpp + LIBRARIES + es2panda-lib + INCLUDE_DIRS + ${ES2PANDA_PATH} + SANITIZERS + ${PANDA_SANITIZERS_LIST} + ) + add_subdirectory(tsconfig) endif() diff --git a/test/public/ast_verifier_test.cpp b/test/public/ast_verifier_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dd36a1937988cfe8ea1ae3622f6bfae857a57f81 --- /dev/null +++ b/test/public/ast_verifier_test.cpp @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2021-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "macros.h" + +#include "compiler/core/ASTVerifier.h" +#include "ir/astDump.h" +#include "ir/expressions/literals/stringLiteral.h" + +class ASTVerifierTest : public testing::Test { +public: + ASTVerifierTest() = default; + ~ASTVerifierTest() override = default; + + NO_COPY_SEMANTIC(ASTVerifierTest); + NO_MOVE_SEMANTIC(ASTVerifierTest); + +private: +}; + +TEST_F(ASTVerifierTest, NullParent) +{ + panda::es2panda::compiler::ASTVerifier verifier {}; + panda::es2panda::ir::StringLiteral empty_node; + + bool has_parent = verifier.HasParent(&empty_node); + auto messages = verifier.GetErrorMessages(); + + ASSERT_EQ(has_parent, false); + ASSERT_NE(messages.size(), 0); + ASSERT_EQ(messages[0], "NULL_PARENT: STR_LITERAL "); +} + +TEST_F(ASTVerifierTest, NullType) +{ + panda::es2panda::compiler::ASTVerifier verifier {}; + panda::es2panda::ir::StringLiteral empty_node; + + bool has_type = verifier.HasType(&empty_node); + auto messages = verifier.GetErrorMessages(); + + ASSERT_EQ(has_type, false); + ASSERT_NE(messages.size(), 0); + ASSERT_EQ(messages[0], "NULL_TS_TYPE: STR_LITERAL "); +} + +TEST_F(ASTVerifierTest, WithoutScope) +{ + panda::es2panda::compiler::ASTVerifier verifier {}; + panda::es2panda::ir::StringLiteral empty_node; + + bool has_scope = verifier.HasScope(&empty_node); + auto messages = verifier.GetErrorMessages(); + + ASSERT_EQ(has_scope, true); + ASSERT_EQ(messages.size(), 0); +}