diff --git a/lib/include/artichoke/Parser/AST/Statements.hpp b/lib/include/artichoke/Parser/AST/Statements.hpp index f0b50a4..adfc6d1 100644 --- a/lib/include/artichoke/Parser/AST/Statements.hpp +++ b/lib/include/artichoke/Parser/AST/Statements.hpp @@ -93,7 +93,8 @@ namespace arti::lang::ast { WhileStmtNode, DoWhileStmtNode, InfLoopStmtNode, - ExpressionStmtNode + ExpressionStmtNode, + CodeBlockStmtNode >; using ElseBranchNode = Variant< diff --git a/lib/src/Parser/AST/toDot.cpp b/lib/src/Parser/AST/toDot.cpp index 811b923..9e5eb19 100644 --- a/lib/src/Parser/AST/toDot.cpp +++ b/lib/src/Parser/AST/toDot.cpp @@ -1002,6 +1002,7 @@ namespace arti::lang::ast { [&g](const DoWhileStmtNode &n) { return emit(n, g); }, [&g](const InfLoopStmtNode &n) { return emit(n, g); }, [&g](const ExpressionStmtNode &n) { return emit(n, g); }, + [&g](const CodeBlockStmtNode &n) { return emit(n, g); }, }; return std::visit(visitor, node); } diff --git a/lib/src/Parser/AST/toString.cpp b/lib/src/Parser/AST/toString.cpp index c86b264..9617e30 100644 --- a/lib/src/Parser/AST/toString.cpp +++ b/lib/src/Parser/AST/toString.cpp @@ -1419,6 +1419,9 @@ namespace arti::lang::ast { [padding](const ExpressionStmtNode &node) -> std::string { return toString(node, padding); }, + [padding](const CodeBlockStmtNode &node) -> std::string { + return toString(node, padding); + } }; return std::visit(visitor, node); diff --git a/lib/src/Parser/Declarations.cpp b/lib/src/Parser/Declarations.cpp index 00b4e79..fa33f69 100644 --- a/lib/src/Parser/Declarations.cpp +++ b/lib/src/Parser/Declarations.cpp @@ -468,6 +468,13 @@ namespace arti::lang { bool keepParsing = true; + if (auto close = match(TokenV::opRSquirly); ! close) { + return Unexpected{ std::move(close).error() }; + } + else if (close.value()) { + keepParsing = false; + } + while (keepParsing) { if (auto member = parseStructMember(); ! member) { return Unexpected{ std::move(member).error() }; @@ -479,13 +486,22 @@ namespace arti::lang { if (auto comma = matchAndConsume(TokenV::opComma); ! comma) { return Unexpected<>{ std::move(comma).error() }; } - - if (auto peekToken = tokenizer.peek(); ! peekToken) { - return Unexpected{ std::move(peekToken).error() }; - } - else { - if (peekToken->value == TokenV::opRSquirly) { - keepParsing = false; + else if (! comma.value()) { + if (auto peekToken = tokenizer.peek(); ! peekToken) { + return Unexpected{ std::move(peekToken).error() }; + } + else { + if (peekToken->value != TokenV::opRSquirly) { + return langException( + peekToken->line, + peekToken->column, + toString(*peekToken), + "',' or '}'" + ); + } + else { + keepParsing = false; + } } } } @@ -533,6 +549,13 @@ namespace arti::lang { bool keepParsing = true; + if (auto close = match(TokenV::opRSquirly); ! close) { + return Unexpected{ std::move(close).error() }; + } + else if (close.value()) { + keepParsing = false; + } + while (keepParsing) { if (auto member = parseEnumMember(); ! member) { return Unexpected{ std::move(member).error() }; @@ -544,13 +567,22 @@ namespace arti::lang { if (auto comma = matchAndConsume(TokenV::opComma); ! comma) { return Unexpected<>{ std::move(comma).error() }; } - - if (auto peekToken = tokenizer.peek(); ! peekToken) { - return Unexpected{ std::move(peekToken).error() }; - } - else { - if (peekToken->value == TokenV::opRSquirly) { - keepParsing = false; + else if (! comma.value()) { + if (auto peekToken = tokenizer.peek(); ! peekToken) { + return Unexpected{ std::move(peekToken).error() }; + } + else { + if (peekToken->value != TokenV::opRSquirly) { + return langException( + peekToken->line, + peekToken->column, + toString(*peekToken), + "',' or '}'" + ); + } + else { + keepParsing = false; + } } } } diff --git a/lib/src/Parser/Statements.cpp b/lib/src/Parser/Statements.cpp index dcaddf4..eab6553 100644 --- a/lib/src/Parser/Statements.cpp +++ b/lib/src/Parser/Statements.cpp @@ -36,6 +36,13 @@ namespace arti::lang { return Unexpected<>{ std::move(lsquirly).error() }; } + if (auto close = match(TokenV::opRSquirly); ! close) { + return Unexpected<>{ std::move(close).error() }; + } + else if (close.value()) { + keepParsing = false; + } + while (keepParsing) { if (auto ok = parseStatement(); ! ok) { return Unexpected<>{ std::move(ok).error() }; @@ -50,6 +57,13 @@ namespace arti::lang { node->statements.push_back(std::move(stmt).value()); } } + + if (auto close = match(TokenV::opRSquirly); ! close) { + return Unexpected<>{ std::move(close).error() }; + } + else if (close.value()) { + keepParsing = false; + } } if (auto rsquirly = consume(TokenV::opRSquirly, "'}'"); ! rsquirly) { @@ -300,6 +314,23 @@ namespace arti::lang { return ast::StatementNode{ std::move(stmt).value() }; } } + else if (peekToken->value == TokenV::opLSquirly) { + if (label.has_value()) { + return langException( + peekToken->line, + peekToken->column, + toString(*peekToken), + "loop keyword, i.e. any of ( for, while, do, loop )" + ); + } + + if (auto stmt = parseCodeBlock(); ! stmt) { + return Unexpected<>{ std::move(stmt).error() }; + } + else { + return ast::StatementNode{ std::move(stmt).value() }; + } + } else { if (label.has_value()) { return langException( @@ -981,7 +1012,7 @@ namespace arti::lang { return Unexpected<>{ std::move(lParen).error() }; } - if (auto skipPre = match(TokenV::opSemicolon); ! skipPre) { + if (auto skipPre = matchAndConsume(TokenV::opSemicolon); ! skipPre) { return Unexpected<>{ std::move(skipPre).error() }; } else if (not skipPre.value()) { @@ -1234,6 +1265,10 @@ namespace arti::lang { return Unexpected<>{ std::move(rParen).error() }; } + if (auto rParen = consume(TokenV::opSemicolon, "';'"); ! rParen) { + return Unexpected<>{ std::move(rParen).error() }; + } + return node; }