diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 1b18db86c4a0cd71e901844ad228d72eebb6614b..d199ca6805b82eba2ee02f1c29aaeb97020fbeea 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -19,14 +19,6 @@ #include "checker/ETSchecker.h" #include "checker/ets/castingContext.h" #include "checker/ets/typeRelationContext.h" -#include "ir/base/catchClause.h" -#include "ir/base/classProperty.h" -#include "ir/base/classStaticBlock.h" -#include "ir/expressions/identifier.h" -#include "ir/expressions/objectExpression.h" -#include "ir/expressions/arrayExpression.h" -#include "ir/statements/blockStatement.h" -#include "ir/statements/returnStatement.h" #include "util/helpers.h" namespace panda::es2panda::checker { @@ -515,14 +507,20 @@ checker::Type *ETSAnalyzer::Check(ir::BigIntLiteral *expr) const checker::Type *ETSAnalyzer::Check(ir::BooleanLiteral *expr) const { - (void)expr; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + if (expr->TsType() == nullptr) { + expr->SetTsType(checker->CreateETSBooleanType(expr->Value())); + } + return expr->TsType(); } checker::Type *ETSAnalyzer::Check(ir::CharLiteral *expr) const { - (void)expr; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + if (expr->TsType() == nullptr) { + expr->SetTsType(checker->Allocator()->New(expr->Char())); + } + return expr->TsType(); } checker::Type *ETSAnalyzer::Check(ir::NullLiteral *expr) const @@ -599,20 +597,44 @@ checker::Type *ETSAnalyzer::Check(ir::ImportSpecifier *st) const // compile methods for STATEMENTS in alphabetical order checker::Type *ETSAnalyzer::Check(ir::AssertStatement *st) const { - (void)st; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + checker->CheckTruthinessOfType(st->test_); + + if (st->Second() != nullptr) { + auto *msg_type = st->second_->Check(checker); + + if (!msg_type->IsETSStringType()) { + checker->ThrowTypeError("Assert message must be string", st->Second()->Start()); + } + } + + return nullptr; } checker::Type *ETSAnalyzer::Check(ir::BlockStatement *st) const { - (void)st; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + checker::ScopeContext scope_ctx(checker, st->Scope()); + + for (auto *it : st->Statements()) { + it->Check(checker); + } + + for (auto [stmt, trailing_block] : st->trailing_blocks_) { + auto iterator = std::find(st->Statements().begin(), st->Statements().end(), stmt); + ASSERT(iterator != st->Statements().end()); + st->Statements().insert(iterator + 1, trailing_block); + trailing_block->Check(checker); + } + + return nullptr; } checker::Type *ETSAnalyzer::Check(ir::BreakStatement *st) const { - (void)st; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + st->target_ = checker->FindJumpTarget(st->Type(), st, st->Ident()); + return nullptr; } checker::Type *ETSAnalyzer::Check(ir::ClassDeclaration *st) const diff --git a/ets2panda/checker/TSAnalyzer.cpp b/ets2panda/checker/TSAnalyzer.cpp index 6b42c2deb681f0d36cb4402187745b155a66a41c..0d09ae19aa6f755e65a4e8ecc4c6c9f807a79d57 100644 --- a/ets2panda/checker/TSAnalyzer.cpp +++ b/ets2panda/checker/TSAnalyzer.cpp @@ -413,13 +413,12 @@ checker::Type *TSAnalyzer::Check(ir::BigIntLiteral *expr) const checker::Type *TSAnalyzer::Check(ir::BooleanLiteral *expr) const { - (void)expr; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + return expr->Value() ? checker->GlobalTrueType() : checker->GlobalFalseType(); } -checker::Type *TSAnalyzer::Check(ir::CharLiteral *expr) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::CharLiteral *expr) const { - (void)expr; UNREACHABLE(); } @@ -495,22 +494,26 @@ checker::Type *TSAnalyzer::Check(ir::ImportSpecifier *st) const UNREACHABLE(); } // compile methods for STATEMENTS in alphabetical order -checker::Type *TSAnalyzer::Check(ir::AssertStatement *st) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::AssertStatement *st) const { - (void)st; UNREACHABLE(); } checker::Type *TSAnalyzer::Check(ir::BlockStatement *st) const { - (void)st; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + checker::ScopeContext scope_ctx(checker, st->Scope()); + + for (auto *it : st->Statements()) { + it->Check(checker); + } + + return nullptr; } -checker::Type *TSAnalyzer::Check(ir::BreakStatement *st) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::BreakStatement *st) const { - (void)st; - UNREACHABLE(); + return nullptr; } checker::Type *TSAnalyzer::Check(ir::ClassDeclaration *st) const diff --git a/ets2panda/compiler/core/ETSCompiler.cpp b/ets2panda/compiler/core/ETSCompiler.cpp index 4770e12ab3c3b6adab796ada779aa83caaa6a554..e5e78ae10c8907a6c900ad103d77f3a304ace804 100644 --- a/ets2panda/compiler/core/ETSCompiler.cpp +++ b/ets2panda/compiler/core/ETSCompiler.cpp @@ -413,14 +413,14 @@ void ETSCompiler::Compile(const ir::BigIntLiteral *expr) const void ETSCompiler::Compile(const ir::BooleanLiteral *expr) const { - (void)expr; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + etsg->LoadAccumulatorBoolean(expr, expr->Value()); } void ETSCompiler::Compile(const ir::CharLiteral *expr) const { - (void)expr; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + etsg->LoadAccumulatorChar(expr, expr->Char()); } void ETSCompiler::Compile(const ir::NullLiteral *expr) const @@ -494,23 +494,69 @@ void ETSCompiler::Compile(const ir::ImportSpecifier *st) const (void)st; UNREACHABLE(); } + +static void ThrowError(compiler::ETSGen *const etsg, const ir::AssertStatement *st) +{ + const compiler::RegScope rs(etsg); + + if (st->Second() != nullptr) { + st->Second()->Compile(etsg); + } else { + etsg->LoadAccumulatorString(st, "Assertion failed."); + } + + const auto message = etsg->AllocReg(); + etsg->StoreAccumulator(st, message); + + const auto assertion_error = etsg->AllocReg(); + etsg->NewObject(st, assertion_error, compiler::Signatures::BUILTIN_ASSERTION_ERROR); + etsg->CallThisStatic1(st, assertion_error, compiler::Signatures::BUILTIN_ASSERTION_ERROR_CTOR, message); + etsg->EmitThrow(st, assertion_error); +} // compile methods for STATEMENTS in alphabetical order void ETSCompiler::Compile(const ir::AssertStatement *st) const { - (void)st; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + auto res = compiler::Condition::CheckConstantExpr(etsg, st->Test()); + if (res == compiler::Condition::Result::CONST_TRUE) { + return; + } + + if (res == compiler::Condition::Result::CONST_FALSE) { + ThrowError(etsg, st); + return; + } + + compiler::Label *end_label = etsg->AllocLabel(); + + st->Test()->Compile(etsg); + etsg->BranchIfTrue(st, end_label); + ThrowError(etsg, st); + etsg->SetLabel(st, end_label); } void ETSCompiler::Compile(const ir::BlockStatement *st) const { - (void)st; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + compiler::LocalRegScope lrs(etsg, st->Scope()); + + etsg->CompileStatements(st->Statements()); +} + +template +static void CompileImpl(const ir::BreakStatement *self, [[maybe_unused]] CodeGen *cg) +{ + compiler::Label *target = cg->ControlFlowChangeBreak(self->Ident()); + cg->Branch(self, target); } void ETSCompiler::Compile(const ir::BreakStatement *st) const { - (void)st; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + if (etsg->ExtendWithFinalizer(st->parent_, st)) { + return; + } + CompileImpl(st, etsg); } void ETSCompiler::Compile(const ir::ClassDeclaration *st) const diff --git a/ets2panda/compiler/core/JSCompiler.cpp b/ets2panda/compiler/core/JSCompiler.cpp index 23fc28f983e779a35e8f1d8cd8a810190aa0c3b6..0272ccfb822f783994be8a336507960b8a465ba3 100644 --- a/ets2panda/compiler/core/JSCompiler.cpp +++ b/ets2panda/compiler/core/JSCompiler.cpp @@ -20,7 +20,6 @@ #include "compiler/core/pandagen.h" #include "compiler/function/functionBuilder.h" #include "util/helpers.h" - namespace panda::es2panda::compiler { PandaGen *JSCompiler::GetPandaGen() const @@ -716,13 +715,12 @@ void JSCompiler::Compile(const ir::BigIntLiteral *expr) const void JSCompiler::Compile(const ir::BooleanLiteral *expr) const { - (void)expr; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + pg->LoadConst(expr, expr->Value() ? compiler::Constant::JS_TRUE : compiler::Constant::JS_FALSE); } -void JSCompiler::Compile(const ir::CharLiteral *expr) const +void JSCompiler::Compile([[maybe_unused]] const ir::CharLiteral *expr) const { - (void)expr; UNREACHABLE(); } @@ -798,22 +796,31 @@ void JSCompiler::Compile(const ir::ImportSpecifier *st) const UNREACHABLE(); } // Compile methods for STATEMENTS in alphabetical order -void JSCompiler::Compile(const ir::AssertStatement *st) const +void JSCompiler::Compile([[maybe_unused]] const ir::AssertStatement *st) const { - (void)st; UNREACHABLE(); } void JSCompiler::Compile(const ir::BlockStatement *st) const { - (void)st; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + compiler::LocalRegScope lrs(pg, st->Scope()); + + for (const auto *it : st->Statements()) { + it->Compile(pg); + } } +template +static void CompileImpl(const ir::BreakStatement *self, [[maybe_unused]] CodeGen *cg) +{ + compiler::Label *target = cg->ControlFlowChangeBreak(self->Ident()); + cg->Branch(self, target); +} void JSCompiler::Compile(const ir::BreakStatement *st) const { - (void)st; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + CompileImpl(st, pg); } void JSCompiler::Compile(const ir::ClassDeclaration *st) const diff --git a/ets2panda/ir/expressions/literals/booleanLiteral.cpp b/ets2panda/ir/expressions/literals/booleanLiteral.cpp index 81fc1cb14718f2c6e99534c32beca2b02f6e38fb..6e66795cdfd9ebd4fb57b1d5ab543ed6ddbebec1 100644 --- a/ets2panda/ir/expressions/literals/booleanLiteral.cpp +++ b/ets2panda/ir/expressions/literals/booleanLiteral.cpp @@ -32,25 +32,22 @@ void BooleanLiteral::Dump(ir::AstDumper *dumper) const void BooleanLiteral::Compile(compiler::PandaGen *pg) const { - pg->LoadConst(this, boolean_ ? compiler::Constant::JS_TRUE : compiler::Constant::JS_FALSE); + pg->GetAstCompiler()->Compile(this); } void BooleanLiteral::Compile(compiler::ETSGen *etsg) const { - etsg->LoadAccumulatorBoolean(this, boolean_); + etsg->GetAstCompiler()->Compile(this); } checker::Type *BooleanLiteral::Check(checker::TSChecker *checker) { - return boolean_ ? checker->GlobalTrueType() : checker->GlobalFalseType(); + return checker->GetAnalyzer()->Check(this); } checker::Type *BooleanLiteral::Check([[maybe_unused]] checker::ETSChecker *checker) { - if (TsType() == nullptr) { - SetTsType(checker->CreateETSBooleanType(boolean_)); - } - return TsType(); + return checker->GetAnalyzer()->Check(this); } // NOLINTNEXTLINE(google-default-arguments) diff --git a/ets2panda/ir/expressions/literals/charLiteral.cpp b/ets2panda/ir/expressions/literals/charLiteral.cpp index 6596de257711f061e06f4395377b7ac1fea59ac0..c3ce97217d338713dbc635b9c6f97ab3e2045ab3 100644 --- a/ets2panda/ir/expressions/literals/charLiteral.cpp +++ b/ets2panda/ir/expressions/literals/charLiteral.cpp @@ -15,6 +15,7 @@ #include "charLiteral.h" +#include "checker/TSchecker.h" #include "compiler/core/pandagen.h" #include "compiler/core/ETSGen.h" #include "checker/ETSchecker.h" @@ -31,24 +32,24 @@ void CharLiteral::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "CharLiteral"}, {"value", char_}}); } -void CharLiteral::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void CharLiteral::Compile([[maybe_unused]] compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} void CharLiteral::Compile([[maybe_unused]] compiler::ETSGen *etsg) const { - etsg->LoadAccumulatorChar(this, char_); + etsg->GetAstCompiler()->Compile(this); } checker::Type *CharLiteral::Check([[maybe_unused]] checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *CharLiteral::Check([[maybe_unused]] checker::ETSChecker *checker) { - if (TsType() == nullptr) { - SetTsType(checker->Allocator()->New(char_)); - } - return TsType(); + return checker->GetAnalyzer()->Check(this); } // NOLINTNEXTLINE(google-default-arguments) diff --git a/ets2panda/ir/statements/assertStatement.cpp b/ets2panda/ir/statements/assertStatement.cpp index ded0f277170515d97b251becc546cce4d550b822..a79d809f9d942b331549b0fe7eecb7f136898259 100644 --- a/ets2panda/ir/statements/assertStatement.cpp +++ b/ets2panda/ir/statements/assertStatement.cpp @@ -48,64 +48,23 @@ void AssertStatement::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "AssertStatement"}, {"test", test_}, {"second", AstDumper::Nullable(second_)}}); } -void AssertStatement::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} - -void AssertStatement::ThrowError(compiler::ETSGen *const etsg) const +void AssertStatement::Compile([[maybe_unused]] compiler::PandaGen *pg) const { - const compiler::RegScope rs(etsg); - - if (second_ != nullptr) { - second_->Compile(etsg); - } else { - etsg->LoadAccumulatorString(this, "Assertion failed."); - } - - const auto message = etsg->AllocReg(); - etsg->StoreAccumulator(this, message); - - const auto assertion_error = etsg->AllocReg(); - etsg->NewObject(this, assertion_error, compiler::Signatures::BUILTIN_ASSERTION_ERROR); - etsg->CallThisStatic1(this, assertion_error, compiler::Signatures::BUILTIN_ASSERTION_ERROR_CTOR, message); - etsg->EmitThrow(this, assertion_error); + pg->GetAstCompiler()->Compile(this); } void AssertStatement::Compile([[maybe_unused]] compiler::ETSGen *etsg) const { - auto res = compiler::Condition::CheckConstantExpr(etsg, test_); - if (res == compiler::Condition::Result::CONST_TRUE) { - return; - } - - if (res == compiler::Condition::Result::CONST_FALSE) { - ThrowError(etsg); - return; - } - - compiler::Label *end_label = etsg->AllocLabel(); - - test_->Compile(etsg); - etsg->BranchIfTrue(this, end_label); - ThrowError(etsg); - etsg->SetLabel(this, end_label); + etsg->GetAstCompiler()->Compile(this); } checker::Type *AssertStatement::Check([[maybe_unused]] checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *AssertStatement::Check([[maybe_unused]] checker::ETSChecker *checker) { - checker->CheckTruthinessOfType(test_); - - if (second_ != nullptr) { - auto *msg_type = second_->Check(checker); - - if (!msg_type->IsETSStringType()) { - checker->ThrowTypeError("Assert message must be string", second_->Start()); - } - } - - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/statements/assertStatement.h b/ets2panda/ir/statements/assertStatement.h index 749c5c739be791db07da7efdc043137f83d23f2d..1a20e32a625dae06b6db6814aa3c1eb6af4e87e1 100644 --- a/ets2panda/ir/statements/assertStatement.h +++ b/ets2panda/ir/statements/assertStatement.h @@ -18,6 +18,10 @@ #include "ir/statement.h" +namespace panda::es2panda::checker { +class ETSAnalyzer; +} // namespace panda::es2panda::checker + namespace panda::es2panda::ir { class Expression; @@ -27,6 +31,8 @@ public: : Statement(AstNodeType::ASSERT_STATEMENT), test_(test), second_(second) { } + // TODO (somas): this friend relationship can be removed once there are getters for private fields + friend class checker::ETSAnalyzer; const Expression *Test() const { @@ -46,9 +52,6 @@ public: checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; -protected: - void ThrowError(compiler::ETSGen *etsg) const; - private: Expression *test_; Expression *second_; diff --git a/ets2panda/ir/statements/blockStatement.cpp b/ets2panda/ir/statements/blockStatement.cpp index 948c0fc83d9bc093bcf44dea5bbd4936efd2ceb9..4bb8908d3267e607162f9dadd5ee17defdd5a595 100644 --- a/ets2panda/ir/statements/blockStatement.cpp +++ b/ets2panda/ir/statements/blockStatement.cpp @@ -16,6 +16,7 @@ #include "blockStatement.h" #include "varbinder/scope.h" +#include "compiler/core/pandagen.h" #include "compiler/core/regScope.h" #include "compiler/core/ETSGen.h" #include "checker/TSchecker.h" @@ -44,46 +45,21 @@ void BlockStatement::Dump(ir::AstDumper *dumper) const void BlockStatement::Compile([[maybe_unused]] compiler::PandaGen *pg) const { - compiler::LocalRegScope lrs(pg, scope_); - - for (const auto *it : statements_) { - it->Compile(pg); - } + pg->GetAstCompiler()->Compile(this); } void BlockStatement::Compile([[maybe_unused]] compiler::ETSGen *etsg) const { - compiler::LocalRegScope lrs(etsg, scope_); - - etsg->CompileStatements(statements_); + etsg->GetAstCompiler()->Compile(this); } checker::Type *BlockStatement::Check([[maybe_unused]] checker::TSChecker *checker) { - checker::ScopeContext scope_ctx(checker, scope_); - - for (auto *it : statements_) { - it->Check(checker); - } - - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *BlockStatement::Check([[maybe_unused]] checker::ETSChecker *checker) { - checker::ScopeContext scope_ctx(checker, scope_); - - for (auto *it : statements_) { - it->Check(checker); - } - - for (auto [stmt, trailing_block] : trailing_blocks_) { - auto iterator = std::find(statements_.begin(), statements_.end(), stmt); - ASSERT(iterator != statements_.end()); - statements_.insert(iterator + 1, trailing_block); - trailing_block->Check(checker); - } - - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/statements/blockStatement.h b/ets2panda/ir/statements/blockStatement.h index 2716162ef20cc46ff94cf86713ebf9e7c520eabb..86a00ffc80d01086bc4e05833df41a00a6130013 100644 --- a/ets2panda/ir/statements/blockStatement.h +++ b/ets2panda/ir/statements/blockStatement.h @@ -18,6 +18,10 @@ #include "ir/statement.h" +namespace panda::es2panda::checker { +class ETSAnalyzer; +} // namespace panda::es2panda::checker + namespace panda::es2panda::ir { class BlockStatement : public Statement { public: @@ -30,6 +34,9 @@ public: { } + // TODO (somas): this friend relationship can be removed once there are getters for private fields + friend class checker::ETSAnalyzer; + bool IsScopeBearer() const override { return true; diff --git a/ets2panda/ir/statements/breakStatement.cpp b/ets2panda/ir/statements/breakStatement.cpp index 43ab14c95139901fd01f0546fcc2aaac2e7178b2..143129257f3f167b6b382fdac98128f9a0496c76 100644 --- a/ets2panda/ir/statements/breakStatement.cpp +++ b/ets2panda/ir/statements/breakStatement.cpp @@ -15,6 +15,7 @@ #include "breakStatement.h" +#include "checker/TSchecker.h" #include "compiler/core/pandagen.h" #include "compiler/core/ETSGen.h" #include "ir/astDump.h" @@ -41,34 +42,23 @@ void BreakStatement::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "BreakStatement"}, {"label", AstDumper::Nullable(ident_)}}); } -template -void CompileImpl(const BreakStatement *self, [[maybe_unused]] CodeGen *cg) -{ - compiler::Label *target = cg->ControlFlowChangeBreak(self->Ident()); - cg->Branch(self, target); -} - void BreakStatement::Compile([[maybe_unused]] compiler::PandaGen *pg) const { - CompileImpl(this, pg); + pg->GetAstCompiler()->Compile(this); } void BreakStatement::Compile([[maybe_unused]] compiler::ETSGen *etsg) const { - if (etsg->ExtendWithFinalizer(parent_, this)) { - return; - } - CompileImpl(this, etsg); + etsg->GetAstCompiler()->Compile(this); } checker::Type *BreakStatement::Check([[maybe_unused]] checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *BreakStatement::Check(checker::ETSChecker *checker) { - target_ = checker->FindJumpTarget(Type(), this, ident_); - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/statements/breakStatement.h b/ets2panda/ir/statements/breakStatement.h index e9273960969cb2db367eca55bf3d22aa841a017a..e51f71040d11e53d898057087787f37402efba1c 100644 --- a/ets2panda/ir/statements/breakStatement.h +++ b/ets2panda/ir/statements/breakStatement.h @@ -18,6 +18,14 @@ #include "ir/statement.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 Identifier; @@ -26,6 +34,9 @@ public: explicit BreakStatement() : Statement(AstNodeType::BREAK_STATEMENT) {} explicit BreakStatement(Identifier *ident) : Statement(AstNodeType::BREAK_STATEMENT), ident_(ident) {} + friend checker::ETSAnalyzer; + friend compiler::ETSCompiler; + const Identifier *Ident() const { return ident_;