diff --git a/include/bolt/CST.hpp b/include/bolt/CST.hpp index 6106b86f6..57e3283f7 100644 --- a/include/bolt/CST.hpp +++ b/include/bolt/CST.hpp @@ -1,6 +1,7 @@ #ifndef BOLT_CST_HPP #define BOLT_CST_HPP +#include #include #include #include @@ -28,8 +29,8 @@ class Statement; class TextLoc { public: - size_t Line = 1; - size_t Column = 1; + std::size_t Line = 1; + std::size_t Column = 1; inline bool isEmpty() const noexcept { return Line == 0 && Column == 0; @@ -68,18 +69,18 @@ class TextFile { ByteString Path; ByteString Text; - std::vector LineOffsets; + std::vector LineOffsets; public: TextFile(ByteString Path, ByteString Text); - size_t getLine(size_t Offset) const; - size_t getColumn(size_t Offset) const; - size_t getStartOffsetOfLine(size_t Line) const; - size_t getEndOffsetOfLine(size_t Line) const; + std::size_t getLine(std::size_t Offset) const; + std::size_t getColumn(std::size_t Offset) const; + std::size_t getStartOffsetOfLine(std::size_t Line) const; + std::size_t getEndOffsetOfLine(std::size_t Line) const; - size_t getLineCount() const; + std::size_t getLineCount() const; ByteString getPath() const; @@ -96,6 +97,7 @@ enum class NodeKind { DotDot, Tilde, At, + DoKeyword, LParen, RParen, LBracket, @@ -156,6 +158,7 @@ enum class NodeKind { ReferenceExpression, MatchCase, MatchExpression, + BlockExpression, MemberExpression, TupleExpression, NestedExpression, @@ -347,19 +350,19 @@ public: TextLoc getEndLoc() const; - inline size_t getStartLine() const override { + inline std::size_t getStartLine() const override { return StartLoc.Line; } - inline size_t getStartColumn() const override { + inline std::size_t getStartColumn() const override { return StartLoc.Column; } - inline size_t getEndLine() const override { + inline std::size_t getEndLine() const override { return getEndLoc().Line; } - inline size_t getEndColumn() const override { + inline std::size_t getEndColumn() const override { return getEndLoc().Column; } @@ -481,6 +484,20 @@ public: }; +class DoKeyword : public Token { +public: + + inline DoKeyword(TextLoc StartLoc): + Token(NodeKind::DoKeyword, StartLoc) {} + + std::string getText() const override; + + static bool classof(const Node* N) { + return N->getKind() == NodeKind::DoKeyword; + } + +}; + class LParen : public Token { public: @@ -1193,7 +1210,15 @@ public: class AnnotationContainer { public: + std::vector Annotations; + + inline AnnotationContainer(): + Annotations({}) {} + + inline AnnotationContainer(std::vector Annotations): + Annotations(Annotations) {} + }; class ExpressionAnnotation : public Annotation { @@ -1764,6 +1789,7 @@ public: || N->getKind() == NodeKind::InfixExpression || N->getKind() == NodeKind::RecordExpression || N->getKind() == NodeKind::MatchExpression + || N->getKind() == NodeKind::BlockExpression || N->getKind() == NodeKind::MemberExpression || N->getKind() == NodeKind::LiteralExpression || N->getKind() == NodeKind::PrefixExpression; @@ -1871,6 +1897,37 @@ public: }; +class BlockExpression : public Expression { +public: + + class DoKeyword* DoKeyword; + class BlockStart* BlockStart; + std::vector Elements; + + inline BlockExpression( + class DoKeyword* DoKeyword, + class BlockStart* BlockStart, + std::vector Elements + ): Expression(NodeKind::BlockExpression), + DoKeyword(DoKeyword), + BlockStart(BlockStart), + Elements(Elements) {} + + inline BlockExpression( + std::vector Annotations, + class DoKeyword* DoKeyword, + class BlockStart* BlockStart, + std::vector Elements + ): Expression(NodeKind::BlockExpression, Annotations), + DoKeyword(DoKeyword), + BlockStart(BlockStart), + Elements(Elements) {} + + Token* getFirstToken() const override; + Token* getLastToken() const override; + +}; + class MemberExpression : public Expression { public: diff --git a/include/bolt/CSTVisitor.hpp b/include/bolt/CSTVisitor.hpp index a359a6786..f7c16bbea 100644 --- a/include/bolt/CSTVisitor.hpp +++ b/include/bolt/CSTVisitor.hpp @@ -28,6 +28,7 @@ public: BOLT_GEN_CASE(DotDot) BOLT_GEN_CASE(Tilde) BOLT_GEN_CASE(At) + BOLT_GEN_CASE(DoKeyword) BOLT_GEN_CASE(LParen) BOLT_GEN_CASE(RParen) BOLT_GEN_CASE(LBracket) @@ -88,6 +89,7 @@ public: BOLT_GEN_CASE(ReferenceExpression) BOLT_GEN_CASE(MatchCase) BOLT_GEN_CASE(MatchExpression) + BOLT_GEN_CASE(BlockExpression) BOLT_GEN_CASE(MemberExpression) BOLT_GEN_CASE(TupleExpression) BOLT_GEN_CASE(NestedExpression) @@ -192,6 +194,10 @@ protected: static_cast(this)->visitToken(N); } + void visitDoKeyword(DoKeyword* N) { + static_cast(this)->visitToken(N); + } + void visitLParen(LParen* N) { static_cast(this)->visitToken(N); } @@ -452,6 +458,10 @@ protected: static_cast(this)->visitExpression(N); } + void visitBlockExpression(BlockExpression* N) { + static_cast(this)->visitExpression(N); + } + void visitMemberExpression(MemberExpression* N) { static_cast(this)->visitExpression(N); } @@ -606,6 +616,7 @@ public: BOLT_GEN_CHILD_CASE(DotDot) BOLT_GEN_CHILD_CASE(Tilde) BOLT_GEN_CHILD_CASE(At) + BOLT_GEN_CHILD_CASE(DoKeyword) BOLT_GEN_CHILD_CASE(LParen) BOLT_GEN_CHILD_CASE(RParen) BOLT_GEN_CHILD_CASE(LBracket) @@ -666,6 +677,7 @@ public: BOLT_GEN_CHILD_CASE(ReferenceExpression) BOLT_GEN_CHILD_CASE(MatchCase) BOLT_GEN_CHILD_CASE(MatchExpression) + BOLT_GEN_CHILD_CASE(BlockExpression) BOLT_GEN_CHILD_CASE(MemberExpression) BOLT_GEN_CHILD_CASE(TupleExpression) BOLT_GEN_CHILD_CASE(NestedExpression) @@ -723,6 +735,9 @@ public: void visitEachChild(At* N) { } + void visitEachChild(DoKeyword* N) { + } + void visitEachChild(LParen* N) { } @@ -1051,6 +1066,17 @@ public: } } + void visitEachChild(BlockExpression* N) { + for (auto A: N->Annotations) { + BOLT_VISIT(A); + } + BOLT_VISIT(N->DoKeyword); + BOLT_VISIT(N->BlockStart); + for (auto Element: N->Elements) { + BOLT_VISIT(Element); + } + } + void visitEachChild(MemberExpression* N) { for (auto A: N->Annotations) { BOLT_VISIT(A); diff --git a/include/bolt/Common.hpp b/include/bolt/Common.hpp index e6ee8c33a..bee22a018 100644 --- a/include/bolt/Common.hpp +++ b/include/bolt/Common.hpp @@ -50,6 +50,7 @@ const D* cast(const B* base) { template bool isa(const T* value) { + ZEN_ASSERT(value != nullptr); return D::classof(value); } diff --git a/include/bolt/Scanner.hpp b/include/bolt/Scanner.hpp index abaaf9902..46b0f73cf 100644 --- a/include/bolt/Scanner.hpp +++ b/include/bolt/Scanner.hpp @@ -68,6 +68,8 @@ class Punctuator : public BufferedStream { Stream& Tokens; + bool ShouldStartBlock = false; + std::stack Frames; std::stack Locations; diff --git a/src/CST.cc b/src/CST.cc index b4b2d5f43..15df7b619 100644 --- a/src/CST.cc +++ b/src/CST.cc @@ -422,6 +422,17 @@ Token* MatchExpression::getLastToken() const { return BlockStart; } +Token* BlockExpression::getFirstToken() const { + return DoKeyword; +} + +Token* BlockExpression::getLastToken() const { + if (!Elements.empty()) { + return Elements.back()->getLastToken(); + } + return BlockStart; +} + Token* RecordExpressionField::getFirstToken() const { return Name; } @@ -935,6 +946,10 @@ std::string At::getText() const { return "@"; } +std::string DoKeyword::getText() const { + return "@"; +} + std::string ClassKeyword::getText() const { return "class"; } diff --git a/src/Parser.cc b/src/Parser.cc index 48a748020..776075aa2 100644 --- a/src/Parser.cc +++ b/src/Parser.cc @@ -1,6 +1,7 @@ // TODO check for memory leaks everywhere a nullptr is returned +#include #include #include @@ -61,6 +62,11 @@ void OperatorTable::add(std::string Name, unsigned Flags, int Precedence) { Mapping.emplace(Name, OperatorInfo { Precedence, Flags }); } +#define BOLT_EACH_UNREF(nodes) \ + for (auto N: nodes) { \ + N->unref(); \ + } + Parser::Parser(TextFile& File, Stream& S, DiagnosticEngine& DE): File(File), Tokens(S), DE(DE) { ExprOperators.add("**", OperatorFlags_InfixR, 10); @@ -879,6 +885,38 @@ after_tuple_elements: } case NodeKind::MatchKeyword: return parseMatchExpression(); + case NodeKind::DoKeyword: + { + Tokens.get(); + auto T1 = expectToken(NodeKind::BlockStart); + if (!T1) { + BOLT_EACH_UNREF(Annotations); + T0->unref(); + return nullptr; + } + std::vector Elements; + for (;;) { + auto T2 = Tokens.peek(); + if (T2->getKind() == NodeKind::BlockEnd) { + Tokens.get()->unref(); + break; + } + auto Element = parseLetBodyElement(); + if (Element == nullptr) { + BOLT_EACH_UNREF(Annotations); + T0->unref(); + T1->unref(); + BOLT_EACH_UNREF(Elements); + return nullptr; + } + Elements.push_back(Element); + } + return new BlockExpression { + static_cast(T0), + static_cast(T1), + Elements + }; + } case NodeKind::IntegerLiteral: case NodeKind::StringLiteral: Tokens.get(); @@ -1044,6 +1082,7 @@ ReturnStatement* Parser::parseReturnStatement() { auto Annotations = parseAnnotations(); auto ReturnKeyword = expectToken(); if (!ReturnKeyword) { + BOLT_EACH_UNREF(Annotations); return nullptr; } Expression* Expression; @@ -1067,6 +1106,10 @@ IfStatement* Parser::parseIfStatement() { std::vector Parts; auto Annotations = parseAnnotations(); auto IfKeyword = expectToken(); + if (!IfKeyword) { + BOLT_EACH_UNREF(Annotations); + return nullptr; + } auto Test = parseExpression(); if (!Test) { IfKeyword->unref(); diff --git a/src/Scanner.cc b/src/Scanner.cc index d6c790fda..3407f29fc 100644 --- a/src/Scanner.cc +++ b/src/Scanner.cc @@ -64,21 +64,22 @@ static int toDigit(Char Chr) { } std::unordered_map Keywords = { - { "pub", NodeKind::PubKeyword }, - { "let", NodeKind::LetKeyword }, - { "foreign", NodeKind::ForeignKeyword }, - { "mut", NodeKind::MutKeyword }, - { "return", NodeKind::ReturnKeyword }, - { "type", NodeKind::TypeKeyword }, - { "mod", NodeKind::ModKeyword }, - { "if", NodeKind::IfKeyword }, - { "else", NodeKind::ElseKeyword }, - { "elif", NodeKind::ElifKeyword }, - { "match", NodeKind::MatchKeyword }, { "class", NodeKind::ClassKeyword }, - { "instance", NodeKind::InstanceKeyword }, - { "struct", NodeKind::StructKeyword }, + { "do", NodeKind::DoKeyword }, + { "elif", NodeKind::ElifKeyword }, + { "else", NodeKind::ElseKeyword }, { "enum", NodeKind::EnumKeyword }, + { "foreign", NodeKind::ForeignKeyword }, + { "if", NodeKind::IfKeyword }, + { "instance", NodeKind::InstanceKeyword }, + { "let", NodeKind::LetKeyword }, + { "match", NodeKind::MatchKeyword }, + { "mod", NodeKind::ModKeyword }, + { "mut", NodeKind::MutKeyword }, + { "pub", NodeKind::PubKeyword }, + { "return", NodeKind::ReturnKeyword }, + { "struct", NodeKind::StructKeyword }, + { "type", NodeKind::TypeKeyword }, }; Scanner::Scanner(DiagnosticEngine& DE, TextFile& File, Stream& Chars): @@ -290,6 +291,8 @@ digit_finish: return new StructKeyword(StartLoc); case NodeKind::EnumKeyword: return new EnumKeyword(StartLoc); + case NodeKind::DoKeyword: + return new DoKeyword(StartLoc); default: ZEN_UNREACHABLE } @@ -432,6 +435,12 @@ Token* Punctuator::read() { auto T0 = Tokens.peek(); + if (ShouldStartBlock) { + ShouldStartBlock = false; + Frames.push(FrameType::Block); + return new BlockStart { T0->getStartLoc() }; + } + switch (T0->getKind()) { case NodeKind::LBrace: Frames.push(FrameType::Fallthrough); @@ -482,6 +491,9 @@ Token* Punctuator::read() { return new BlockStart(T0->getStartLoc()); } } + if (isa(T0)) { + ShouldStartBlock = true; + } return Tokens.get(); } case FrameType::Block: