diff --git a/.vscode/launch.json b/.vscode/launch.json index e81d80199..01d5fa8fb 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,7 +9,7 @@ "request": "launch", "name": "Debug", "program": "${workspaceFolder}/build/bolt", - "args": [ "--direct-diagnostics", "verify", "test/checker/wrong_return_type.bolt" ], + "args": [ "--direct-diagnostics", "check", "test.bolt" ], "cwd": "${workspaceFolder}", "preLaunchTask": "CMake: build" } diff --git a/include/bolt/Parser.hpp b/include/bolt/Parser.hpp index 777b0dbd4..954c53da5 100644 --- a/include/bolt/Parser.hpp +++ b/include/bolt/Parser.hpp @@ -99,6 +99,9 @@ namespace bolt { void checkLineFoldEnd(); void skipToLineFoldEnd(); + void disablePunctuation(); + void enablePunctuation(); + public: Parser(TextFile& File, Stream& S, DiagnosticEngine& DE); diff --git a/include/bolt/Scanner.hpp b/include/bolt/Scanner.hpp index ba16e276c..343a93762 100644 --- a/include/bolt/Scanner.hpp +++ b/include/bolt/Scanner.hpp @@ -61,16 +61,25 @@ namespace bolt { enum class FrameType { Block, LineFold, - Fallthrough, + }; + + struct Frame { + FrameType Type; + int Parens = 0; + int Braces = 0; + int Brackets = 0; }; class Punctuator : public BufferedStream { Stream& Tokens; - std::stack Frames; + std::stack Frames; std::stack Locations; + bool ShouldYieldNextTokenInLineFold = false; + bool isTerminal(NodeKind Kind); + protected: virtual Token* read() override; diff --git a/src/Parser.cc b/src/Parser.cc index 98e6279c2..1dc34e228 100644 --- a/src/Parser.cc +++ b/src/Parser.cc @@ -492,8 +492,8 @@ after_tuple_element: } MatchExpression* Parser::parseMatchExpression() { - auto T0 = expectToken(); - if (!T0) { + auto Match = expectToken(); + if (!Match) { return nullptr; } auto T1 = Tokens.peek(); @@ -506,12 +506,12 @@ after_tuple_element: } else { Value = parseExpression(); if (!Value) { - T0->unref(); + Match->unref(); return nullptr; } BlockStart = expectToken(); if (!BlockStart) { - T0->unref(); + Match->unref(); Value->unref(); return nullptr; } @@ -544,7 +544,7 @@ after_tuple_element: checkLineFoldEnd(); Cases.push_back(new MatchCase { Pattern, RArrowAlt, Expression }); } - return new MatchExpression(static_cast(T0), Value, BlockStart, Cases); + return new MatchExpression(Match, Value, BlockStart, Cases); } RecordExpression* Parser::parseRecordExpression() { @@ -688,10 +688,13 @@ after_tuple_element: case NodeKind::LineFoldEnd: case NodeKind::BlockStart: case NodeKind::EndOfFile: - // Can recover from this one - RParen = nullptr; DE.add(File, T2, std::vector { NodeKind::RParen, NodeKind::Comma }); - goto after_tuple_elements; + LParen->unref(); + for (auto [E, Comma]: Elements) { + E->unref(); + Comma->unref(); + } + return nullptr; } } after_tuple_elements: @@ -764,6 +767,7 @@ finish: if (T1->getKind() == NodeKind::LineFoldEnd || T1->getKind() == NodeKind::RParen || T1->getKind() == NodeKind::RBrace + || T1->getKind() == NodeKind::RBracket || T1->getKind() == NodeKind::BlockStart || T1->getKind() == NodeKind::Comma || ExprOperators.isInfix(T1)) { diff --git a/src/Scanner.cc b/src/Scanner.cc index 61f4e8649..436666893 100644 --- a/src/Scanner.cc +++ b/src/Scanner.cc @@ -426,17 +426,77 @@ after_string_contents: Punctuator::Punctuator(Stream& Tokens): Tokens(Tokens) { - Frames.push(FrameType::Block); + Frames.push({ FrameType::Block }); Locations.push(TextLoc { 0, 0 }); } + static bool isCloseDelim(NodeKind Kind) { + switch (Kind) { + case NodeKind::RParen: + case NodeKind::RBrace: + case NodeKind::RBracket: + return true; + default: + return false; + } + } + + // struct DelimCounter { + // int Parens = 0; + // int Braces = 0; + // int Brackets = 0; + // }; + + bool Punctuator::isTerminal(NodeKind Kind) { + auto& Frame = Frames.top(); + switch (Kind) { + case NodeKind::RParen: + return Frame.Parens == 0; + case NodeKind::RBrace: + return Frame.Braces == 0; + case NodeKind::RBracket: + return Frame.Brackets == 0; + default: + return false; + } + } + Token* Punctuator::read() { auto T0 = Tokens.peek(); + auto& RefLoc = Locations.top(); + auto& Frame = Frames.top(); switch (T0->getKind()) { + case NodeKind::LParen: + ++Frame.Parens; + break; case NodeKind::LBrace: - Frames.push(FrameType::Fallthrough); + ++Frame.Braces; + break; + case NodeKind::LBracket: + ++Frame.Brackets; + break; + case NodeKind::RParen: + if (Frame.Parens == 0) { + // TODO add diagnostic? + break; + } + --Frame.Parens; + break; + case NodeKind::RBrace: + if (Frame.Braces == 0) { + // TODO add diagnostic? + break; + } + --Frame.Braces; + break; + case NodeKind::RBracket: + if (Frame.Brackets == 0) { + // TODO add diagnostic? + break; + } + --Frame.Brackets; break; case NodeKind::EndOfFile: { @@ -445,9 +505,7 @@ after_string_contents: } auto Frame = Frames.top(); Frames.pop(); - switch (Frame) { - case FrameType::Fallthrough: - break; + switch (Frame.Type) { case FrameType::Block: return new BlockEnd(T0->getStartLoc()); case FrameType::LineFold: @@ -458,20 +516,17 @@ after_string_contents: break; } - auto RefLoc = Locations.top(); - switch (Frames.top()) { - case FrameType::Fallthrough: - { - if (T0->getKind() == NodeKind::RBrace) { - Frames.pop(); - } - Tokens.get(); - return T0; - } + switch (Frame.Type) { case FrameType::LineFold: { - if (T0->getStartLine() > RefLoc.Line - && T0->getStartColumn() <= RefLoc.Column) { + if (ShouldYieldNextTokenInLineFold) { + ShouldYieldNextTokenInLineFold = false; + return Tokens.get(); + } + ShouldYieldNextTokenInLineFold = isTerminal(T0->getKind()); + if (ShouldYieldNextTokenInLineFold + || (T0->getStartLine() > RefLoc.Line + && T0->getStartColumn() <= RefLoc.Column)) { Frames.pop(); Locations.pop(); return new LineFoldEnd(T0->getStartLoc()); @@ -480,7 +535,7 @@ after_string_contents: auto T1 = Tokens.peek(1); if (T1->getStartLine() > T0->getEndLine()) { Tokens.get(); - Frames.push(FrameType::Block); + Frames.push({ FrameType::Block }); return new BlockStart(T0->getStartLoc()); } } @@ -488,12 +543,12 @@ after_string_contents: } case FrameType::Block: { - if (T0->getStartColumn() <= RefLoc.Column) { + if (T0->getStartColumn() <= RefLoc.Column || isTerminal(T0->getKind())) { Frames.pop(); return new BlockEnd(T0->getStartLoc()); } - Frames.push(FrameType::LineFold); + Frames.push({ FrameType::LineFold }); Locations.push(T0->getStartLoc()); return Tokens.get();