From 01223b7e67bae718f05a21c72d463e27008b557e Mon Sep 17 00:00:00 2001 From: zhangrengao Date: Sun, 24 Jul 2022 21:06:37 +0800 Subject: [PATCH 1/3] Fix syntax error of break&continue statement issue: I5IZ26 Signed-off-by: zhangrengao Change-Id: I485364656ecc9699e4a1c3aa1f204557319c8a93 --- es2panda/compiler/core/dynamicContext.cpp | 2 +- es2panda/parser/context/parserContext.cpp | 4 - es2panda/parser/context/parserContext.h | 4 + es2panda/parser/parserImpl.h | 3 + es2panda/parser/statementParser.cpp | 110 +++++++++++++++------- 5 files changed, 85 insertions(+), 38 deletions(-) diff --git a/es2panda/compiler/core/dynamicContext.cpp b/es2panda/compiler/core/dynamicContext.cpp index 73e9e9ddcb..f4402d572d 100644 --- a/es2panda/compiler/core/dynamicContext.cpp +++ b/es2panda/compiler/core/dynamicContext.cpp @@ -36,7 +36,7 @@ DynamicContext::~DynamicContext() LabelContext::LabelContext(PandaGen *pg, const ir::LabelledStatement *labelledStmt) : DynamicContext(pg, LabelTarget(labelledStmt->Ident()->Name())), labelledStmt_(labelledStmt) { - if (!labelledStmt->Body()->IsBlockStatement()) { + if (!labelledStmt->Body()->IsBlockStatement() && !labelledStmt->Body()->IsIfStatement()) { return; } diff --git a/es2panda/parser/context/parserContext.cpp b/es2panda/parser/context/parserContext.cpp index 0d67e93039..b96a540bc8 100644 --- a/es2panda/parser/context/parserContext.cpp +++ b/es2panda/parser/context/parserContext.cpp @@ -22,10 +22,6 @@ const ParserContext *ParserContext::FindLabel(const util::StringView &label) con { const auto *iter = this; do { - if (iter->label_.Empty()) { - return nullptr; - } - if (iter->label_ == label) { return iter; } diff --git a/es2panda/parser/context/parserContext.h b/es2panda/parser/context/parserContext.h index 757a3d5be8..417bff5c27 100644 --- a/es2panda/parser/context/parserContext.h +++ b/es2panda/parser/context/parserContext.h @@ -124,6 +124,10 @@ public: return (status_ & ParserStatus::MODULE) != 0; } + const util::StringView Label() { + return label_; + } + const ParserContext *FindLabel(const util::StringView &label) const; private: diff --git a/es2panda/parser/parserImpl.h b/es2panda/parser/parserImpl.h index e73468a664..1a21988153 100644 --- a/es2panda/parser/parserImpl.h +++ b/es2panda/parser/parserImpl.h @@ -392,6 +392,9 @@ private: void CheckLabelledFunction(const ir::Statement *node); void CheckDeclare(); + void checkBreakStatement(ir::Identifier *label); + void checkContinueStatement(ir::Identifier *label); + bool ParseDirective(ArenaVector *statements); void ParseDirectivePrologue(ArenaVector *statements); ArenaVector ParseStatementList(StatementParsingFlags flags = StatementParsingFlags::ALLOW_LEXICAL); diff --git a/es2panda/parser/statementParser.cpp b/es2panda/parser/statementParser.cpp index c1e63e01d4..d66345d4de 100644 --- a/es2panda/parser/statementParser.cpp +++ b/es2panda/parser/statementParser.cpp @@ -116,6 +116,75 @@ void ParserImpl::CheckDeclare() } } +void ParserImpl::checkBreakStatement(ir::Identifier *label) +{ + auto *iter = &context_; + while (iter) { + if (static_cast(iter->Status() & (ParserStatus::FUNCTION | + ParserStatus::IN_ITERATION | + ParserStatus::IN_SWITCH | + ParserStatus::IN_LABELED)) == ParserStatus::FUNCTION) { + ThrowSyntaxError("Jump target cannot cross function boundary."); + } + if (static_cast(iter->Status() & ParserStatus::IN_LABELED) == ParserStatus::IN_LABELED) { + if (label != nullptr && iter->Label() == label->Name()) { + return; + } + } + if (static_cast(iter->Status() & ParserStatus::IN_SWITCH) == ParserStatus::IN_SWITCH) { + if (label == nullptr) { + return; + } + } + if (static_cast(iter->Status() & ParserStatus::IN_ITERATION) == ParserStatus::IN_ITERATION) { + if (label == nullptr) { + return; + } + } + iter = iter->Prev(); + } + + if (label != nullptr) { + ThrowSyntaxError("A 'break' statement can only jump to a label of an enclosing statement."); + } else { + ThrowSyntaxError("A 'break' statement can only be used within an enclosing iteration or switch statement."); + } +} + + +void ParserImpl::checkContinueStatement(ir::Identifier *label) +{ + auto *iter = &context_; + while (iter) { + if (static_cast(iter->Status() & (ParserStatus::FUNCTION | + ParserStatus::IN_ITERATION | + ParserStatus::IN_SWITCH | + ParserStatus::IN_LABELED)) == ParserStatus::FUNCTION) { + ThrowSyntaxError("Jump target cannot cross function boundary."); + } + if (static_cast(iter->Status() & ParserStatus::IN_LABELED) == ParserStatus::IN_LABELED) { + if (label != nullptr && iter->Label() == label->Name()) { + if (!(static_cast(iter->Status() & ParserStatus::IN_ITERATION) == ParserStatus::IN_ITERATION)) { + ThrowSyntaxError("A 'continue' statement can only jump to a label of an enclosing iteration statement."); + } + return; + } + } + if (static_cast(iter->Status() & ParserStatus::IN_ITERATION) == ParserStatus::IN_ITERATION) { + if (label == nullptr) { + return; + } + } + iter = iter->Prev(); + } + + if (label != nullptr) { + ThrowSyntaxError("A 'continue' statement can only jump to a label of an enclosing statement."); + } else { + ThrowSyntaxError("A 'continue' statement can only be used within an enclosing iteration statement."); + } +} + ir::Statement *ParserImpl::ParseStatement(StatementParsingFlags flags) { bool isDeclare = false; @@ -780,27 +849,13 @@ ir::BlockStatement *ParserImpl::ParseBlockStatement() ir::BreakStatement *ParserImpl::ParseBreakStatement() { - bool allowBreak = (context_.Status() & (ParserStatus::IN_ITERATION | ParserStatus::IN_SWITCH)); - if (Extension() == ScriptExtension::TS && (context_.Status() & ParserStatus::FUNCTION) && !allowBreak) { - ThrowSyntaxError("Jump target cannot cross function boundary"); - } - lexer::SourcePosition startLoc = lexer_->GetToken().Start(); lexer_->NextToken(); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON || lexer_->GetToken().Type() == lexer::TokenType::EOS || lexer_->GetToken().NewLine() || lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { - if (!allowBreak) { - if (Extension() == ScriptExtension::JS) { - ThrowSyntaxError("Illegal break statement"); - } - if (Extension() == ScriptExtension::TS) { - ThrowSyntaxError( - "A 'break' statement can only be used within an " - "enclosing iteration or switch statement"); - } - } + checkBreakStatement(nullptr); auto *breakStatement = AllocNode(); breakStatement->SetRange({startLoc, lexer_->GetToken().End()}); @@ -823,6 +878,7 @@ ir::BreakStatement *ParserImpl::ParseBreakStatement() auto *identNode = AllocNode(label, Allocator()); identNode->SetRange(lexer_->GetToken().Loc()); + checkBreakStatement(identNode); auto *breakStatement = AllocNode(identNode); breakStatement->SetRange({startLoc, lexer_->GetToken().End()}); @@ -835,28 +891,13 @@ ir::BreakStatement *ParserImpl::ParseBreakStatement() ir::ContinueStatement *ParserImpl::ParseContinueStatement() { - if (Extension() == ScriptExtension::TS && - (static_cast(context_.Status() & (ParserStatus::FUNCTION | ParserStatus::IN_ITERATION | - ParserStatus::IN_SWITCH)) == ParserStatus::FUNCTION)) { - ThrowSyntaxError("Jump target cannot cross function boundary"); - } - - if (!(context_.Status() & ParserStatus::IN_ITERATION)) { - if (Extension() == ScriptExtension::JS) { - ThrowSyntaxError("Illegal continue statement"); - } - if (Extension() == ScriptExtension::TS) { - ThrowSyntaxError( - "A 'continue' statement can only be used within an " - "enclosing iteration statement"); - } - } - lexer::SourcePosition startLoc = lexer_->GetToken().Start(); lexer::SourcePosition endLoc = lexer_->GetToken().End(); lexer_->NextToken(); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) { + checkContinueStatement(nullptr); + auto *continueStatement = AllocNode(); continueStatement->SetRange({startLoc, lexer_->GetToken().End()}); lexer_->NextToken(); @@ -865,6 +906,8 @@ ir::ContinueStatement *ParserImpl::ParseContinueStatement() if (lexer_->GetToken().NewLine() || lexer_->GetToken().Type() == lexer::TokenType::EOS || lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { + checkContinueStatement(nullptr); + auto *continueStatement = AllocNode(); continueStatement->SetRange({startLoc, endLoc}); return continueStatement; @@ -877,12 +920,13 @@ ir::ContinueStatement *ParserImpl::ParseContinueStatement() const auto &label = lexer_->GetToken().Ident(); const ParserContext *labelCtx = context_.FindLabel(label); - if (!labelCtx || !(labelCtx->Status() & ParserStatus::IN_ITERATION)) { + if (!labelCtx) { ThrowSyntaxError("Undefined label"); } auto *identNode = AllocNode(label, Allocator()); identNode->SetRange(lexer_->GetToken().Loc()); + checkContinueStatement(identNode); auto *continueStatement = AllocNode(identNode); continueStatement->SetRange({startLoc, lexer_->GetToken().End()}); -- Gitee From 35391a5ba7d09678bb8f76769fdbc1e7ae29f9fd Mon Sep 17 00:00:00 2001 From: zhangrengao Date: Tue, 2 Aug 2022 16:33:35 +0800 Subject: [PATCH 2/3] fix review info Signed-off-by: zhangrengao Change-Id: I416219397b38d3f9c23b784f922de4f5e95cc376 --- es2panda/parser/context/parserContext.cpp | 4 + es2panda/parser/context/parserContext.h | 8 +- es2panda/parser/parserImpl.h | 4 +- es2panda/parser/statementParser.cpp | 98 ++++++++++++++++------- 4 files changed, 80 insertions(+), 34 deletions(-) diff --git a/es2panda/parser/context/parserContext.cpp b/es2panda/parser/context/parserContext.cpp index b96a540bc8..0d67e93039 100644 --- a/es2panda/parser/context/parserContext.cpp +++ b/es2panda/parser/context/parserContext.cpp @@ -22,6 +22,10 @@ const ParserContext *ParserContext::FindLabel(const util::StringView &label) con { const auto *iter = this; do { + if (iter->label_.Empty()) { + return nullptr; + } + if (iter->label_ == label) { return iter; } diff --git a/es2panda/parser/context/parserContext.h b/es2panda/parser/context/parserContext.h index 417bff5c27..e1dc0af28e 100644 --- a/es2panda/parser/context/parserContext.h +++ b/es2panda/parser/context/parserContext.h @@ -124,7 +124,13 @@ public: return (status_ & ParserStatus::MODULE) != 0; } - const util::StringView Label() { + bool IsInStatus(const ParserStatus status) const + { + return static_cast(status_ & status) == status; + } + + const util::StringView &Label() const + { return label_; } diff --git a/es2panda/parser/parserImpl.h b/es2panda/parser/parserImpl.h index 1a21988153..2b3b79b857 100644 --- a/es2panda/parser/parserImpl.h +++ b/es2panda/parser/parserImpl.h @@ -392,8 +392,8 @@ private: void CheckLabelledFunction(const ir::Statement *node); void CheckDeclare(); - void checkBreakStatement(ir::Identifier *label); - void checkContinueStatement(ir::Identifier *label); + void checkBreakStatement(ir::Identifier *label) const; + void checkContinueStatement(ir::Identifier *label) const; bool ParseDirective(ArenaVector *statements); void ParseDirectivePrologue(ArenaVector *statements); diff --git a/es2panda/parser/statementParser.cpp b/es2panda/parser/statementParser.cpp index d66345d4de..f256cf96e1 100644 --- a/es2panda/parser/statementParser.cpp +++ b/es2panda/parser/statementParser.cpp @@ -116,7 +116,7 @@ void ParserImpl::CheckDeclare() } } -void ParserImpl::checkBreakStatement(ir::Identifier *label) +void ParserImpl::checkBreakStatement(ir::Identifier *label) const { auto *iter = &context_; while (iter) { @@ -126,18 +126,12 @@ void ParserImpl::checkBreakStatement(ir::Identifier *label) ParserStatus::IN_LABELED)) == ParserStatus::FUNCTION) { ThrowSyntaxError("Jump target cannot cross function boundary."); } - if (static_cast(iter->Status() & ParserStatus::IN_LABELED) == ParserStatus::IN_LABELED) { - if (label != nullptr && iter->Label() == label->Name()) { + if (label == nullptr) { + if (iter->IsInStatus(ParserStatus::IN_SWITCH) || iter->IsInStatus(ParserStatus::IN_ITERATION)) { return; } - } - if (static_cast(iter->Status() & ParserStatus::IN_SWITCH) == ParserStatus::IN_SWITCH) { - if (label == nullptr) { - return; - } - } - if (static_cast(iter->Status() & ParserStatus::IN_ITERATION) == ParserStatus::IN_ITERATION) { - if (label == nullptr) { + } else { + if (iter->IsInStatus(ParserStatus::IN_LABELED) && iter->Label() == label->Name()) { return; } } @@ -145,14 +139,14 @@ void ParserImpl::checkBreakStatement(ir::Identifier *label) } if (label != nullptr) { - ThrowSyntaxError("A 'break' statement can only jump to a label of an enclosing statement."); + ThrowSyntaxError("Undefined label " + std::string(label->Name())); } else { - ThrowSyntaxError("A 'break' statement can only be used within an enclosing iteration or switch statement."); + ThrowSyntaxError("Illegal break statement"); } } -void ParserImpl::checkContinueStatement(ir::Identifier *label) +void ParserImpl::checkContinueStatement(ir::Identifier *label) const { auto *iter = &context_; while (iter) { @@ -162,16 +156,16 @@ void ParserImpl::checkContinueStatement(ir::Identifier *label) ParserStatus::IN_LABELED)) == ParserStatus::FUNCTION) { ThrowSyntaxError("Jump target cannot cross function boundary."); } - if (static_cast(iter->Status() & ParserStatus::IN_LABELED) == ParserStatus::IN_LABELED) { - if (label != nullptr && iter->Label() == label->Name()) { - if (!(static_cast(iter->Status() & ParserStatus::IN_ITERATION) == ParserStatus::IN_ITERATION)) { - ThrowSyntaxError("A 'continue' statement can only jump to a label of an enclosing iteration statement."); - } + if (label == nullptr) { + if (iter->IsInStatus(ParserStatus::IN_ITERATION)) { return; } - } - if (static_cast(iter->Status() & ParserStatus::IN_ITERATION) == ParserStatus::IN_ITERATION) { - if (label == nullptr) { + } else { + if (iter->IsInStatus(ParserStatus::IN_LABELED) && iter->Label() == label->Name()) { + if (!iter->IsInStatus(ParserStatus::IN_ITERATION)) { + ThrowSyntaxError("Illegal continue statement: " + std::string(label->Name()) + + " does not denote an iteration statement"); + } return; } } @@ -179,9 +173,9 @@ void ParserImpl::checkContinueStatement(ir::Identifier *label) } if (label != nullptr) { - ThrowSyntaxError("A 'continue' statement can only jump to a label of an enclosing statement."); + ThrowSyntaxError("Undefined label " + std::string(label->Name())); } else { - ThrowSyntaxError("A 'continue' statement can only be used within an enclosing iteration statement."); + ThrowSyntaxError("Illegal continue statement: no surrounding iteration statement"); } } @@ -849,13 +843,27 @@ ir::BlockStatement *ParserImpl::ParseBlockStatement() ir::BreakStatement *ParserImpl::ParseBreakStatement() { + bool allowBreak = (context_.Status() & (ParserStatus::IN_ITERATION | ParserStatus::IN_SWITCH)); + if (Extension() == ScriptExtension::TS && (context_.Status() & ParserStatus::FUNCTION) && !allowBreak) { + ThrowSyntaxError("Jump target cannot cross function boundary"); + } + lexer::SourcePosition startLoc = lexer_->GetToken().Start(); lexer_->NextToken(); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON || lexer_->GetToken().Type() == lexer::TokenType::EOS || lexer_->GetToken().NewLine() || lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { - checkBreakStatement(nullptr); + if (!allowBreak) { + if (Extension() == ScriptExtension::TS) { + ThrowSyntaxError( + "A 'break' statement can only be used within an " + "enclosing iteration or switch statement"); + } + } + if (Extension() == ScriptExtension::JS) { + checkBreakStatement(nullptr); + } auto *breakStatement = AllocNode(); breakStatement->SetRange({startLoc, lexer_->GetToken().End()}); @@ -878,7 +886,9 @@ ir::BreakStatement *ParserImpl::ParseBreakStatement() auto *identNode = AllocNode(label, Allocator()); identNode->SetRange(lexer_->GetToken().Loc()); - checkBreakStatement(identNode); + if (Extension() == ScriptExtension::JS) { + checkBreakStatement(identNode); + } auto *breakStatement = AllocNode(identNode); breakStatement->SetRange({startLoc, lexer_->GetToken().End()}); @@ -891,12 +901,28 @@ ir::BreakStatement *ParserImpl::ParseBreakStatement() ir::ContinueStatement *ParserImpl::ParseContinueStatement() { + if (Extension() == ScriptExtension::TS && + (static_cast(context_.Status() & (ParserStatus::FUNCTION | ParserStatus::IN_ITERATION | + ParserStatus::IN_SWITCH)) == ParserStatus::FUNCTION)) { + ThrowSyntaxError("Jump target cannot cross function boundary"); + } + + if (!(context_.Status() & ParserStatus::IN_ITERATION)) { + if (Extension() == ScriptExtension::TS) { + ThrowSyntaxError( + "A 'continue' statement can only be used within an " + "enclosing iteration statement"); + } + } + lexer::SourcePosition startLoc = lexer_->GetToken().Start(); lexer::SourcePosition endLoc = lexer_->GetToken().End(); lexer_->NextToken(); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) { - checkContinueStatement(nullptr); + if (Extension() == ScriptExtension::JS) { + checkContinueStatement(nullptr); + } auto *continueStatement = AllocNode(); continueStatement->SetRange({startLoc, lexer_->GetToken().End()}); @@ -906,7 +932,9 @@ ir::ContinueStatement *ParserImpl::ParseContinueStatement() if (lexer_->GetToken().NewLine() || lexer_->GetToken().Type() == lexer::TokenType::EOS || lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { - checkContinueStatement(nullptr); + if (Extension() == ScriptExtension::JS) { + checkContinueStatement(nullptr); + } auto *continueStatement = AllocNode(); continueStatement->SetRange({startLoc, endLoc}); @@ -920,13 +948,21 @@ ir::ContinueStatement *ParserImpl::ParseContinueStatement() const auto &label = lexer_->GetToken().Ident(); const ParserContext *labelCtx = context_.FindLabel(label); - if (!labelCtx) { - ThrowSyntaxError("Undefined label"); + if (Extension() == ScriptExtension::TS) { + if (!labelCtx || !(labelCtx->Status() & ParserStatus::IN_ITERATION)) { + ThrowSyntaxError("Undefined label"); + } + } else { + if (!labelCtx) { + ThrowSyntaxError("Undefined label"); + } } auto *identNode = AllocNode(label, Allocator()); identNode->SetRange(lexer_->GetToken().Loc()); - checkContinueStatement(identNode); + if (Extension() == ScriptExtension::JS) { + checkContinueStatement(identNode); + } auto *continueStatement = AllocNode(identNode); continueStatement->SetRange({startLoc, lexer_->GetToken().End()}); -- Gitee From 2b0c9723ad789ce2c67cbe7faa8fa4a011a480dd Mon Sep 17 00:00:00 2001 From: zhangrengao Date: Thu, 4 Aug 2022 15:18:37 +0800 Subject: [PATCH 3/3] Add iteratorstatement Signed-off-by: zhangrengao Change-Id: I352ec93e8fafd33fa28e3c5941bf6016dec2273b --- es2panda/parser/parserImpl.h | 1 + es2panda/parser/statementParser.cpp | 32 ++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/es2panda/parser/parserImpl.h b/es2panda/parser/parserImpl.h index 2b3b79b857..a6075544a1 100644 --- a/es2panda/parser/parserImpl.h +++ b/es2panda/parser/parserImpl.h @@ -394,6 +394,7 @@ private: void checkBreakStatement(ir::Identifier *label) const; void checkContinueStatement(ir::Identifier *label) const; + bool isIterationStatement(); bool ParseDirective(ArenaVector *statements); void ParseDirectivePrologue(ArenaVector *statements); diff --git a/es2panda/parser/statementParser.cpp b/es2panda/parser/statementParser.cpp index f256cf96e1..4b383c87a7 100644 --- a/es2panda/parser/statementParser.cpp +++ b/es2panda/parser/statementParser.cpp @@ -1423,8 +1423,34 @@ ir::IfStatement *ParserImpl::ParseIfStatement() return ifStatement; } +bool ParserImpl::isIterationStatement() +{ + lexer_->NextToken(); + + switch (lexer_->GetToken().Type()) { + case lexer::TokenType::KEYW_DO: + case lexer::TokenType::KEYW_FOR: + case lexer::TokenType::KEYW_WHILE: { + return true; + } + case lexer::TokenType::LITERAL_IDENT: { + if (lexer_->Lookahead() == LEX_CHAR_COLON) { + lexer_->NextToken(); + return isIterationStatement(); + } + } + default: + return false; + } + return false; +} + ir::LabelledStatement *ParserImpl::ParseLabelledStatement(const lexer::LexerPosition &pos) { + const auto savedPos = lexer_->Save(); + bool isInIterator = isIterationStatement(); + lexer_->Rewind(savedPos); + const util::StringView &actualLabel = pos.token.Ident(); // TODO(frobert) : check correctness @@ -1436,7 +1462,11 @@ ir::LabelledStatement *ParserImpl::ParseLabelledStatement(const lexer::LexerPosi ThrowSyntaxError("Label already declared", pos.token.Start()); } - SavedParserContext newCtx(this, ParserStatus::IN_LABELED, actualLabel); + ParserStatus newStatus = ParserStatus::IN_LABELED; + if (isInIterator) { + newStatus |= ParserStatus::IN_ITERATION; + } + SavedParserContext newCtx(this, newStatus, actualLabel); auto *identNode = AllocNode(actualLabel, Allocator()); identNode->SetRange(pos.token.Loc()); -- Gitee