From 8b8e4091d7acff0a2d6e41e1b01118efcf93aaf4 Mon Sep 17 00:00:00 2001 From: Filip Sajdak Date: Thu, 20 Apr 2023 02:10:03 +0200 Subject: [PATCH 1/6] Add diagnostics for semicolon at the end of function This change introduce diagnostics when there is a semicolon at the end of the function body: ```cpp g: () = {}; ``` Generates: ``` error: a compound function body shall not end with a semicolon (at ';') ``` And ```cpp g: () = 42;; ``` Generates: ``` error: a short function syntax shall end with a single semicolon (at ';') ``` --- source/parse.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/source/parse.h b/source/parse.h index 909677e86e..8705614ef6 100644 --- a/source/parse.h +++ b/source/parse.h @@ -5690,6 +5690,21 @@ class parser return {}; } + if ( + n->is_function() + && n->initializer + && !done() && curr().type() == lexeme::Semicolon + ) + { + if (n->initializer->is_compound() && n->has_name()) { + error("a braced function body may not be followed by a semicolon (empty statements are not allowed)"); + return {}; + } else if (n->initializer->is_expression()) { + error("a single-expression function should end with a single semicolon"); + return {}; + } + } + // If this is an implicit constructor, it must have two parameters if (n->is_constructor()) { From d1e4c6482dcd27948e7470f92f08076dda872c4a Mon Sep 17 00:00:00 2001 From: Filip Sajdak Date: Thu, 20 Apr 2023 02:10:03 +0200 Subject: [PATCH 2/6] Add diagnostics for semicolon at the end of for loop This change introduce diagnostics when there is a semicolon at the end of the for..do loop body: ```cpp for v* | all next log() do :(e) = { foo(); bar*; }; ``` generates: ``` error: for..do loop body shall not end with a semicolon (at ';') ``` --- source/parse.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/parse.h b/source/parse.h index 8705614ef6..1e91cab024 100644 --- a/source/parse.h +++ b/source/parse.h @@ -4485,6 +4485,11 @@ class parser n->for_with_in = true; } + if (!done() && curr().type() == lexeme::Semicolon) { + error("a loop body may not be followed by a semicolon (empty statements are not allowed)"); + return {}; + } + return n; } From 120f87b3aa2a1a1a178db7b9e30d5a05b41d9930 Mon Sep 17 00:00:00 2001 From: Filip Sajdak Date: Thu, 20 Apr 2023 02:10:03 +0200 Subject: [PATCH 3/6] Add diagnostics for semicolon at the end of while body This change introduce diagnostics when there is a semicolon at the end of the while loop body: ```cpp i := 0; while i* < container.size() next i++ { std::cout << container[i] << std::endl; }; ``` generates: ``` error: while loop body shall not end with a semicolon (at ';') ``` --- source/parse.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/parse.h b/source/parse.h index 1e91cab024..d3566ced2d 100644 --- a/source/parse.h +++ b/source/parse.h @@ -4423,6 +4423,10 @@ class parser if (!handle_logical_expression ()) { return {}; } if (!handle_optional_next_clause()) { return {}; } if (!handle_compound_statement ()) { return {}; } + if (!done() && curr().type() == lexeme::Semicolon) { + error("a loop body may not be followed by a semicolon (empty statements are not allowed)"); + return {}; + } return n; } From 03a9baabb57163159afb584693ca9e987d5b531b Mon Sep 17 00:00:00 2001 From: Filip Sajdak Date: Thu, 20 Apr 2023 02:10:03 +0200 Subject: [PATCH 4/6] Add diagnostics for double semicolon at short lambda This change introduce diagnostics when there is a double semicolon at the end of the short function body for unnamed function: ```cpp l2 := :() -> int = 24;; ``` Generates: ``` error: a short function syntax shall end with a single semicolon (at ';') ``` --- source/parse.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/parse.h b/source/parse.h index d3566ced2d..fca2cd6c00 100644 --- a/source/parse.h +++ b/source/parse.h @@ -3225,6 +3225,12 @@ class parser next(); return {}; } + if ( // check if a single-expression function is followed by an extra second semicolon + decl->initializer && decl->initializer->is_expression() + && !done() && curr().type() == lexeme::Semicolon + ) { + error("a single-expression function should end with a single semicolon"); + } if (!(*func)->contracts.empty()) { error("an unnamed function at expression scope currently cannot have contracts"); next(); From 179b953332ab10439f7e68221f551b6b50a5a06f Mon Sep 17 00:00:00 2001 From: Filip Sajdak Date: Thu, 20 Apr 2023 02:10:04 +0200 Subject: [PATCH 5/6] Add diagnostics for empty statements (extra semicolon) This change introduce diagnostics when there is a semicolon without statement ```cpp ; ``` Generates: ``` error: empty statement is not allowed - remove extra semicolon (at ';') ``` That also handles cases when there is double semicolon after a proper statemnt: ```cpp i := 0;; ``` Generates: ``` error: empty statement is not allowed - remove extra semicolon (at ';') ``` --- source/parse.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/parse.h b/source/parse.h index fca2cd6c00..def92c6573 100644 --- a/source/parse.h +++ b/source/parse.h @@ -4722,6 +4722,11 @@ class parser ) -> std::unique_ptr { + if (!done() && curr().type() == lexeme::Semicolon) { + error("empty statement is not allowed - remove extra semicolon"); + return {}; + } + auto n = std::make_unique(); // Now handle the rest of the statement From 6881f5b6e5039fe149a39620290e18ccf850b8f0 Mon Sep 17 00:00:00 2001 From: Filip Sajdak Date: Thu, 20 Apr 2023 02:10:04 +0200 Subject: [PATCH 6/6] Fix error() method that throws when done() is true When done() is true last correct token and its position is printed. --- source/parse.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/source/parse.h b/source/parse.h index def92c6573..e4c94a6963 100644 --- a/source/parse.h +++ b/source/parse.h @@ -3068,15 +3068,15 @@ class parser -> void { auto m = std::string{msg}; + auto i = done() ? -1 : 0; + assert (peek(i)); if (include_curr_token) { - m += std::string(" (at '") + curr().to_string(true) + "')"; + m += std::string(" (at '") + peek(i)->to_string(true) + "')"; } if ( err_pos == source_position{} - && peek(0) - ) - { - err_pos = peek(0)->position(); + ) { + err_pos = peek(i)->position(); } errors.emplace_back( err_pos, m, false, fallback ); } @@ -5093,7 +5093,8 @@ class parser // If there's no [ [ then this isn't a contract if ( - curr().type() != lexeme::LeftBracket + done() + || curr().type() != lexeme::LeftBracket || !peek(1) || peek(1)->type() != lexeme::LeftBracket )