diff --git a/include/bolt/CST.hpp b/include/bolt/CST.hpp index 36897c05a..ae332db1f 100644 --- a/include/bolt/CST.hpp +++ b/include/bolt/CST.hpp @@ -108,6 +108,7 @@ namespace bolt { ReturnKeyword, ModKeyword, StructKeyword, + EnumKeyword, ClassKeyword, InstanceKeyword, ElifKeyword, @@ -130,11 +131,14 @@ namespace bolt { QualifiedTypeExpression, ReferenceTypeExpression, ArrowTypeExpression, + AppTypeExpression, VarTypeExpression, NestedTypeExpression, TupleTypeExpression, BindPattern, LiteralPattern, + NamedPattern, + NestedPattern, ReferenceExpression, MatchCase, MatchExpression, @@ -158,6 +162,9 @@ namespace bolt { LetDeclaration, RecordDeclarationField, RecordDeclaration, + VariantDeclaration, + TupleVariantDeclarationMember, + RecordVariantDeclarationMember, ClassDeclaration, InstanceDeclaration, SourceFile, @@ -252,9 +259,11 @@ namespace bolt { Node* Source; std::unordered_multimap> Mapping; + void addSymbol(ByteString Name, Node* Decl, SymbolKind Kind); + void scan(Node* X); - void addBindings(Pattern* P, Node* ToInsert); + void visitPattern(Pattern* P, Node* ToInsert); public: @@ -622,6 +631,20 @@ namespace bolt { }; + class EnumKeyword : public Token { + public: + + inline EnumKeyword(TextLoc StartLoc): + Token(NodeKind::EnumKeyword, StartLoc) {} + + std::string getText() const override; + + static bool classof(const Node* N) { + return N->getKind() == NodeKind::EnumKeyword; + } + + }; + class ClassKeyword : public Token { public: @@ -1067,6 +1090,24 @@ namespace bolt { }; + class AppTypeExpression : public TypeExpression { + public: + + TypeExpression* Op; + std::vector Args; + + inline AppTypeExpression( + TypeExpression* Op, + std::vector Args + ): TypeExpression(NodeKind::AppTypeExpression), + Op(Op), + Args(Args) {} + + Token* getFirstToken() const override; + Token* getLastToken() const override; + + }; + class VarTypeExpression : public TypeExpression { public: @@ -1167,6 +1208,45 @@ namespace bolt { }; + class NamedPattern : public Pattern { + public: + + IdentifierAlt* Name; + std::vector Patterns; + + inline NamedPattern( + IdentifierAlt* Name, + std::vector Patterns + ): Pattern(NodeKind::NamedPattern), + Name(Name), + Patterns(Patterns) {} + + Token* getFirstToken() const override; + Token* getLastToken() const override; + + }; + + class NestedPattern : public Pattern { + public: + + class LParen* LParen; + Pattern* P; + class RParen* RParen; + + inline NestedPattern( + class LParen* LParen, + Pattern* P, + class RParen* RParen + ): Pattern(NodeKind::NestedPattern), + LParen(LParen), + P(P), + RParen(RParen) {} + + Token* getFirstToken() const override; + Token* getLastToken() const override; + + }; + class Expression : public TypedNode { protected: @@ -1741,6 +1821,83 @@ namespace bolt { }; + class VariantDeclarationMember : public Node { + public: + + inline VariantDeclarationMember(NodeKind Kind): + Node(Kind) {} + + }; + + class TupleVariantDeclarationMember : public VariantDeclarationMember { + public: + + IdentifierAlt* Name; + std::vector Elements; + + inline TupleVariantDeclarationMember( + IdentifierAlt* Name, + std::vector Elements + ): VariantDeclarationMember(NodeKind::TupleVariantDeclarationMember), + Name(Name), + Elements(Elements) {} + + Token* getFirstToken() const override; + Token* getLastToken() const override; + + }; + + class RecordVariantDeclarationMember : public VariantDeclarationMember { + public: + + IdentifierAlt* Name; + BlockStart* BlockStart; + std::vector Fields; + + inline RecordVariantDeclarationMember( + IdentifierAlt* Name, + class BlockStart* BlockStart, + std::vector Fields + ): VariantDeclarationMember(NodeKind::RecordVariantDeclarationMember), + Name(Name), + BlockStart(BlockStart), + Fields(Fields) {} + + Token* getFirstToken() const override; + Token* getLastToken() const override; + + }; + + class VariantDeclaration : public Node { + public: + + class PubKeyword* PubKeyword; + class EnumKeyword* EnumKeyword; + class IdentifierAlt* Name; + std::vector TVs; + class BlockStart* BlockStart; + std::vector Members; + + inline VariantDeclaration( + class PubKeyword* PubKeyword, + class EnumKeyword* EnumKeyword, + class IdentifierAlt* Name, + std::vector TVs, + class BlockStart* BlockStart, + std::vector Members + ): Node(NodeKind::VariantDeclaration), + PubKeyword(PubKeyword), + EnumKeyword(EnumKeyword), + Name(Name), + TVs(TVs), + BlockStart(BlockStart), + Members(Members) {} + + Token* getFirstToken() const override; + Token* getLastToken() const override; + + }; + class SourceFile : public Node { Scope* TheScope = nullptr; @@ -1798,6 +1955,7 @@ namespace bolt { template<> inline NodeKind getNodeType() { return NodeKind::ReturnKeyword; } template<> inline NodeKind getNodeType() { return NodeKind::ModKeyword; } template<> inline NodeKind getNodeType() { return NodeKind::StructKeyword; } + template<> inline NodeKind getNodeType() { return NodeKind::EnumKeyword; } template<> inline NodeKind getNodeType() { return NodeKind::ClassKeyword; } template<> inline NodeKind getNodeType() { return NodeKind::InstanceKeyword; } template<> inline NodeKind getNodeType() { return NodeKind::ElifKeyword; } diff --git a/include/bolt/CSTVisitor.hpp b/include/bolt/CSTVisitor.hpp index 953dd4f35..59e1ed598 100644 --- a/include/bolt/CSTVisitor.hpp +++ b/include/bolt/CSTVisitor.hpp @@ -1,6 +1,8 @@ #pragma once +#include "zen/config.hpp" + #include "bolt/CST.hpp" namespace bolt { @@ -53,6 +55,8 @@ namespace bolt { return static_cast(this)->visitModKeyword(static_cast(N)); case NodeKind::StructKeyword: return static_cast(this)->visitStructKeyword(static_cast(N)); + case NodeKind::EnumKeyword: + return static_cast(this)->visitEnumKeyword(static_cast(N)); case NodeKind::ClassKeyword: return static_cast(this)->visitClassKeyword(static_cast(N)); case NodeKind::InstanceKeyword: @@ -97,6 +101,8 @@ namespace bolt { return static_cast(this)->visitReferenceTypeExpression(static_cast(N)); case NodeKind::ArrowTypeExpression: return static_cast(this)->visitArrowTypeExpression(static_cast(N)); + case NodeKind::AppTypeExpression: + return static_cast(this)->visitAppTypeExpression(static_cast(N)); case NodeKind::VarTypeExpression: return static_cast(this)->visitVarTypeExpression(static_cast(N)); case NodeKind::NestedTypeExpression: @@ -107,6 +113,10 @@ namespace bolt { return static_cast(this)->visitBindPattern(static_cast(N)); case NodeKind::LiteralPattern: return static_cast(this)->visitLiteralPattern(static_cast(N)); + case NodeKind::NamedPattern: + return static_cast(this)->visitNamedPattern(static_cast(N)); + case NodeKind::NestedPattern: + return static_cast(this)->visitNestedPattern(static_cast(N)); case NodeKind::ReferenceExpression: return static_cast(this)->visitReferenceExpression(static_cast(N)); case NodeKind::MatchCase: @@ -153,6 +163,12 @@ namespace bolt { return static_cast(this)->visitStructDeclarationField(static_cast(N)); case NodeKind::RecordDeclaration: return static_cast(this)->visitStructDeclaration(static_cast(N)); + case NodeKind::VariantDeclaration: + return static_cast(this)->visitVariantDeclaration(static_cast(N)); + case NodeKind::TupleVariantDeclarationMember: + return static_cast(this)->visitTupleVariantDeclarationMember(static_cast(N)); + case NodeKind::RecordVariantDeclarationMember: + return static_cast(this)->visitRecordVariantDeclarationMember(static_cast(N)); case NodeKind::ClassDeclaration: return static_cast(this)->visitClassDeclaration(static_cast(N)); case NodeKind::InstanceDeclaration: @@ -256,6 +272,10 @@ namespace bolt { visitToken(N); } + void visitEnumKeyword(EnumKeyword* N) { + visitToken(N); + } + void visitClassKeyword(ClassKeyword* N) { visitToken(N); } @@ -352,6 +372,10 @@ namespace bolt { visitTypeExpression(N); } + void visitAppTypeExpression(AppTypeExpression* N) { + visitTypeExpression(N); + } + void visitVarTypeExpression(VarTypeExpression* N) { visitTypeExpression(N); } @@ -376,6 +400,14 @@ namespace bolt { visitPattern(N); } + void visitNamedPattern(NamedPattern* N) { + visitPattern(N); + } + + void visitNestedPattern(NestedPattern* N) { + visitPattern(N); + } + void visitExpression(Expression* N) { visitNode(N); } @@ -480,6 +512,22 @@ namespace bolt { visitNode(N); } + void visitVariantDeclaration(VariantDeclaration* N) { + visitNode(N); + } + + void visitVariantDeclarationMember(VariantDeclarationMember* N) { + visitNode(N); + } + + void visitTupleVariantDeclarationMember(TupleVariantDeclarationMember* N) { + visitVariantDeclarationMember(N); + } + + void visitRecordVariantDeclarationMember(RecordVariantDeclarationMember* N) { + visitVariantDeclarationMember(N); + } + void visitClassDeclaration(ClassDeclaration* N) { visitNode(N); } @@ -559,6 +607,9 @@ namespace bolt { case NodeKind::StructKeyword: visitEachChild(static_cast(N)); break; + case NodeKind::EnumKeyword: + visitEachChild(static_cast(N)); + break; case NodeKind::ClassKeyword: visitEachChild(static_cast(N)); break; @@ -625,6 +676,9 @@ namespace bolt { case NodeKind::ArrowTypeExpression: visitEachChild(static_cast(N)); break; + case NodeKind::AppTypeExpression: + visitEachChild(static_cast(N)); + break; case NodeKind::VarTypeExpression: visitEachChild(static_cast(N)); break; @@ -640,6 +694,12 @@ namespace bolt { case NodeKind::LiteralPattern: visitEachChild(static_cast(N)); break; + case NodeKind::NamedPattern: + visitEachChild(static_cast(N)); + break; + case NodeKind::NestedPattern: + visitEachChild(static_cast(N)); + break; case NodeKind::ReferenceExpression: visitEachChild(static_cast(N)); break; @@ -709,6 +769,15 @@ namespace bolt { case NodeKind::RecordDeclarationField: visitEachChild(static_cast(N)); break; + case NodeKind::VariantDeclaration: + visitEachChild(static_cast(N)); + break; + case NodeKind::TupleVariantDeclarationMember: + visitEachChild(static_cast(N)); + break; + case NodeKind::RecordVariantDeclarationMember: + visitEachChild(static_cast(N)); + break; case NodeKind::ClassDeclaration: visitEachChild(static_cast(N)); break; @@ -788,6 +857,9 @@ namespace bolt { void visitEachChild(StructKeyword* N) { } + void visitEachChild(EnumKeyword* N) { + } + void visitEachChild(ClassKeyword* N) { } @@ -878,6 +950,13 @@ namespace bolt { BOLT_VISIT(N->ReturnType); } + void visitEachChild(AppTypeExpression* N) { + BOLT_VISIT(N->Op); + for (auto Arg: N->Args) { + BOLT_VISIT(Arg); + } + } + void visitEachChild(VarTypeExpression* N) { BOLT_VISIT(N->Name); } @@ -907,6 +986,19 @@ namespace bolt { BOLT_VISIT(N->Literal); } + void visitEachChild(NamedPattern* N) { + BOLT_VISIT(N->Name); + for (auto P: N->Patterns) { + BOLT_VISIT(P); + } + } + + void visitEachChild(NestedPattern* N) { + BOLT_VISIT(N->LParen); + BOLT_VISIT(N->P); + BOLT_VISIT(N->RParen); + } + void visitEachChild(ReferenceExpression* N) { for (auto [Name, Dot]: N->ModulePath) { BOLT_VISIT(Name); @@ -1082,6 +1174,36 @@ namespace bolt { } } + void visitEachChild(VariantDeclaration* N) { + if (N->PubKeyword) { + BOLT_VISIT(N->PubKeyword); + } + BOLT_VISIT(N->EnumKeyword); + BOLT_VISIT(N->Name); + for (auto TV: N->TVs) { + BOLT_VISIT(TV); + } + BOLT_VISIT(N->BlockStart); + for (auto Member: N->Members) { + BOLT_VISIT(Member); + } + } + + void visitEachChild(TupleVariantDeclarationMember* N) { + BOLT_VISIT(N->Name); + for (auto Element: N->Elements) { + BOLT_VISIT(Element); + } + } + + void visitEachChild(RecordVariantDeclarationMember* N) { + BOLT_VISIT(N->Name); + BOLT_VISIT(N->BlockStart); + for (auto Field: N->Fields) { + BOLT_VISIT(Field); + } + } + void visitEachChild(ClassDeclaration* N) { if (N->PubKeyword) { BOLT_VISIT(N->PubKeyword); diff --git a/include/bolt/Parser.hpp b/include/bolt/Parser.hpp index c578ba446..e82a1b45b 100644 --- a/include/bolt/Parser.hpp +++ b/include/bolt/Parser.hpp @@ -53,9 +53,7 @@ namespace bolt { std::optional getInfix(Token* T); bool isInfix(Token* T); - bool isPrefix(Token* T); - bool isSuffix(Token* T); }; @@ -73,6 +71,8 @@ namespace bolt { Token* expectToken(NodeKind Ty); + std::vector parseRecordFields(); + template T* expectToken() { return static_cast(expectToken(getNodeType())); @@ -86,6 +86,7 @@ namespace bolt { ConstraintExpression* parseConstraintExpression(); + TypeExpression* parseAppTypeExpression(); TypeExpression* parsePrimitiveTypeExpression(); TypeExpression* parseQualifiedTypeExpression(); TypeExpression* parseArrowTypeExpression(); @@ -101,6 +102,7 @@ namespace bolt { TypeExpression* parseTypeExpression(); + Pattern* parsePrimitivePattern(); Pattern* parsePattern(); Parameter* parseParam(); @@ -131,6 +133,8 @@ namespace bolt { RecordDeclaration* parseRecordDeclaration(); + VariantDeclaration* parseVariantDeclaration(); + Node* parseSourceElement(); SourceFile* parseSourceFile(); diff --git a/src/CST.cc b/src/CST.cc index 1ef91ac64..16612f0d2 100644 --- a/src/CST.cc +++ b/src/CST.cc @@ -55,6 +55,10 @@ namespace bolt { scan(Source); } + void Scope::addSymbol(ByteString Name, Node* Decl, SymbolKind Kind) { + Mapping.emplace(Name, std::make_tuple(Decl, Kind)); + } + void Scope::scan(Node* X) { switch (X->getKind()) { case NodeKind::ExpressionStatement: @@ -72,7 +76,7 @@ namespace bolt { case NodeKind::ClassDeclaration: { auto Decl = static_cast(X); - Mapping.emplace(Decl->Name->getCanonicalText(), std::make_tuple(Decl, SymbolKind::Class)); + addSymbol(Decl->Name->getCanonicalText(), Decl, SymbolKind::Class); for (auto Element: Decl->Elements) { scan(Element); } @@ -84,7 +88,19 @@ namespace bolt { case NodeKind::LetDeclaration: { auto Decl = static_cast(X); - addBindings(Decl->Pattern, Decl); + visitPattern(Decl->Pattern, Decl); + break; + } + case NodeKind::RecordDeclaration: + { + auto Decl = static_cast(X); + addSymbol(Decl->Name->getCanonicalText(), Decl, SymbolKind::Type); + break; + } + case NodeKind::VariantDeclaration: + { + auto Decl = static_cast(X); + addSymbol(Decl->Name->getCanonicalText(), Decl, SymbolKind::Type); break; } default: @@ -92,12 +108,26 @@ namespace bolt { } } - void Scope::addBindings(Pattern* X, Node* ToInsert) { + void Scope::visitPattern(Pattern* X, Node* Decl) { switch (X->getKind()) { case NodeKind::BindPattern: { auto Y = static_cast(X); - Mapping.emplace(Y->Name->Text, std::make_tuple(ToInsert, SymbolKind::Var)); + addSymbol(Y->Name->Text, Decl, SymbolKind::Var); + break; + } + case NodeKind::NamedPattern: + { + auto Y = static_cast(X); + for (auto P: Y->Patterns) { + visitPattern(P, Decl); + } + break; + } + case NodeKind::NestedPattern: + { + auto Y = static_cast(X); + visitPattern(Y->P, Decl); break; } case NodeKind::LiteralPattern: @@ -287,6 +317,17 @@ namespace bolt { return ReturnType->getLastToken(); } + Token* AppTypeExpression::getFirstToken() const { + return Op->getFirstToken(); + } + + Token* AppTypeExpression::getLastToken() const { + if (Args.size()) { + return Args.back()->getLastToken(); + } + return Op->getLastToken(); + } + Token* VarTypeExpression::getLastToken() const { return Name; } @@ -327,6 +368,25 @@ namespace bolt { return Literal; } + Token* NamedPattern::getFirstToken() const { + return Name; + } + + Token* NamedPattern::getLastToken() const { + if (Patterns.size()) { + return Patterns.back()->getLastToken(); + } + return Name; + } + + Token* NestedPattern::getFirstToken() const { + return LParen; + } + + Token* NestedPattern::getLastToken() const { + return RParen; + } + Token* ReferenceExpression::getFirstToken() const { if (!ModulePath.empty()) { return std::get<0>(ModulePath.front()); @@ -531,7 +591,43 @@ namespace bolt { Token* RecordDeclaration::getLastToken() const { if (Fields.size()) { - Fields.back()->getLastToken(); + return Fields.back()->getLastToken(); + } + return BlockStart; + } + + Token* VariantDeclaration::getFirstToken() const { + if (PubKeyword) { + return PubKeyword; + } + return EnumKeyword; + } + + Token* VariantDeclaration::getLastToken() const { + if (Members.size()) { + return Members.back()->getLastToken(); + } + return BlockStart; + } + + Token* TupleVariantDeclarationMember::getFirstToken() const { + return Name; + } + + Token* TupleVariantDeclarationMember::getLastToken() const { + if (Elements.size()) { + return Elements.back()->getLastToken(); + } + return Name; + } + + Token* RecordVariantDeclarationMember::getFirstToken() const { + return Name; + } + + Token* RecordVariantDeclarationMember::getLastToken() const { + if (Fields.size()) { + return Fields.back()->getLastToken(); } return BlockStart; } @@ -667,6 +763,10 @@ namespace bolt { return "struct"; } + std::string EnumKeyword::getText() const { + return "enum"; + } + std::string Invalid::getText() const { return ""; } diff --git a/src/Parser.cc b/src/Parser.cc index 45373af05..76645f687 100644 --- a/src/Parser.cc +++ b/src/Parser.cc @@ -26,8 +26,10 @@ // includes tokens. This avoids memory leaks. And yes, they matter when the // compiler is permanently on such as in a language server. // -// 5. Always unref() a LineFoldEnd obtained via Tokens.get(), since it will -// never be stored somewhere +// 5. Always unref() a LineFoldEnd or BlockEnd obtained via Tokens.get(), since +// it will never be stored somewhere +// +// 6. Maintain the invariant that a wrong parse will never advance the input stream. namespace bolt { @@ -100,7 +102,7 @@ namespace bolt { return T; } - Pattern* Parser::parsePattern() { + Pattern* Parser::parsePrimitivePattern() { auto T0 = Tokens.peek(); switch (T0->getKind()) { case NodeKind::StringLiteral: @@ -110,6 +112,52 @@ namespace bolt { case NodeKind::Identifier: Tokens.get(); return new BindPattern(static_cast(T0)); + case NodeKind::IdentifierAlt: + Tokens.get(); + return new NamedPattern(static_cast(T0), {}); + case NodeKind::LParen: + { + Tokens.get(); + auto LParen = static_cast(T0); + auto T1 = Tokens.peek(); + RParen* RParen; + if (T1->getKind() == NodeKind::IdentifierAlt) { + Tokens.get(); + auto Name = static_cast(T1); + std::vector Patterns; + for (;;) { + auto T2 = Tokens.peek(); + if (T2->getKind() == NodeKind::RParen) { + Tokens.get(); + RParen = static_cast(T2); + break; + } + auto P = parsePrimitivePattern(); + if (!P) { + LParen->unref(); + for (auto P: Patterns) { + P->unref(); + } + return nullptr; + } + Patterns.push_back(P); + } + return new NestedPattern { LParen, new NamedPattern { Name, Patterns }, RParen }; + } else { + auto P = parsePattern(); + if (!P) { + LParen->unref(); + return nullptr; + } + auto RParen = expectToken(); + if (!RParen) { + LParen->unref(); + P->unref(); + return nullptr; + } + return new NestedPattern { LParen, P, RParen }; + } + } default: // Tokens.get(); DE.add(File, T0, std::vector { NodeKind::Identifier, NodeKind::StringLiteral, NodeKind::IntegerLiteral }); @@ -117,6 +165,10 @@ namespace bolt { } } + Pattern* Parser::parsePattern() { + return parsePrimitivePattern(); + } + TypeExpression* Parser::parseTypeExpression() { return parseQualifiedTypeExpression(); } @@ -292,8 +344,39 @@ after_tuple_element: return new ReferenceTypeExpression(ModulePath, static_cast(Name)); } + TypeExpression* Parser::parseAppTypeExpression() { + auto OpTy = parsePrimitiveTypeExpression(); + if (!OpTy) { + return nullptr; + } + std::vector ArgTys; + for (;;) { + auto T1 = Tokens.peek(); + auto Kind = T1->getKind(); + if (Kind == NodeKind::RArrow || Kind == NodeKind::Equals || Kind == NodeKind::BlockStart || Kind == NodeKind::LineFoldEnd || Kind == NodeKind::EndOfFile || Kind == NodeKind::RParen) { + break; + } + auto TE = parsePrimitiveTypeExpression(); + if (!TE) { + OpTy->unref(); + for (auto Arg: ArgTys) { + Arg->unref(); + } + return nullptr; + } + ArgTys.push_back(TE); + } + if (ArgTys.empty()) { + return OpTy; + } + return new AppTypeExpression { OpTy, ArgTys }; + } + TypeExpression* Parser::parseArrowTypeExpression() { - auto RetType = parsePrimitiveTypeExpression(); + auto RetType = parseAppTypeExpression(); + if (RetType == nullptr) { + return nullptr; + } std::vector ParamTypes; for (;;) { auto T1 = Tokens.peek(); @@ -302,7 +385,7 @@ after_tuple_element: } Tokens.get(); ParamTypes.push_back(RetType); - RetType = parsePrimitiveTypeExpression(); + RetType = parseAppTypeExpression(); if (!RetType) { for (auto ParamType: ParamTypes) { ParamType->unref(); @@ -321,7 +404,6 @@ after_tuple_element: if (!T0) { return nullptr; } - Tokens.get(); auto T1 = Tokens.peek(); Expression* Value; BlockStart* BlockStart; @@ -346,7 +428,7 @@ after_tuple_element: for (;;) { auto T2 = Tokens.peek(); if (llvm::isa(T2)) { - Tokens.get(); + Tokens.get()->unref(); break; } auto Pattern = parsePattern(); @@ -657,7 +739,7 @@ finish: for (;;) { auto T2 = Tokens.peek(); if (T2->getKind() == NodeKind::BlockEnd) { - Tokens.get(); + Tokens.get()->unref(); break; } auto Element = parseLetBodyElement(); @@ -681,7 +763,7 @@ finish: for (;;) { auto T5 = Tokens.peek(); if (T5->getKind() == NodeKind::BlockEnd) { - Tokens.get(); + Tokens.get()->unref(); break; } auto Element = parseLetBodyElement(); @@ -784,7 +866,7 @@ after_params: Elements.push_back(Element); } } - Tokens.get(); + Tokens.get()->unref(); // Always a BlockEnd Body = new LetBlockBody(static_cast(T2), Elements); break; } @@ -966,7 +1048,7 @@ after_vars: for (;;) { auto T2 = Tokens.peek(); if (T2->is()) { - Tokens.get(); + Tokens.get()->unref(); break; } auto Element = parseClassElement(); @@ -1044,7 +1126,7 @@ after_vars: for (;;) { auto T2 = Tokens.peek(); if (T2->is()) { - Tokens.get(); + Tokens.get()->unref(); break; } auto Element = parseClassElement(); @@ -1063,6 +1145,38 @@ after_vars: ); } + std::vector Parser::parseRecordFields() { + std::vector Fields; + for (;;) { + auto T1 = Tokens.peek(); + if (T1->getKind() == NodeKind::BlockEnd) { + Tokens.get()->unref(); + break; + } + auto Name = expectToken(); + if (!Name) { + skipToLineFoldEnd(); + continue; + } + auto Colon = expectToken(); + if (!Colon) { + Name->unref(); + skipToLineFoldEnd(); + continue; + } + auto TE = parseTypeExpression(); + if (!TE) { + Name->unref(); + Colon->unref(); + skipToLineFoldEnd(); + continue; + } + checkLineFoldEnd(); + Fields.push_back(new RecordDeclarationField { Name, Colon, TE }); + } + return Fields; + } + RecordDeclaration* Parser::parseRecordDeclaration() { auto T0 = Tokens.peek(); PubKeyword* Pub = nullptr; @@ -1087,6 +1201,17 @@ after_vars: skipToLineFoldEnd(); return nullptr; } + std::vector Vars; + for (;;) { + auto T1 = Tokens.peek(); + if (T1->getKind() == NodeKind::BlockStart) { + break; + } + auto Var = parseVarTypeExpression(); + if (Var) { + Vars.push_back(Var); + } + } auto BS = expectToken(); if (!BS) { if (Pub) { @@ -1097,50 +1222,99 @@ after_vars: skipToLineFoldEnd(); return nullptr; } - std::vector Fields; + auto Fields = parseRecordFields(); + Tokens.get()->unref(); // Always a LineFoldEnd + return new RecordDeclaration { Pub, Struct, Name, Vars, BS, Fields }; + } + + VariantDeclaration* Parser::parseVariantDeclaration() { + auto T0 = Tokens.peek(); + PubKeyword* Pub = nullptr; + if (T0->getKind() == NodeKind::MutKeyword) { + Tokens.get(); + Pub = static_cast(T0); + } + auto Enum = expectToken(); + if (!Enum) { + if (Pub) { + Pub->unref(); + } + skipToLineFoldEnd(); + return nullptr; + } + auto Name = expectToken(); + if (!Name) { + if (Pub) { + Pub->unref(); + } + Enum->unref(); + skipToLineFoldEnd(); + return nullptr; + } + std::vector TVs; for (;;) { - auto T1 = Tokens.get(); - if (T1->getKind() == NodeKind::BlockEnd) { + auto T0 = Tokens.peek(); + if (T0->getKind() == NodeKind::BlockStart) { break; } - if (T1->getKind() != NodeKind::Identifier) { - DE.add(File, T1, std::vector { NodeKind::Identifier }); - if (Pub) { - Pub->unref(); - } - Struct->unref(); - Name->unref(); - T1->unref(); - skipToLineFoldEnd(); - return nullptr; + auto Var = parseVarTypeExpression(); + if (Var) { + TVs.push_back(Var); } - auto Colon = expectToken(); - if (!Colon) { - if (Pub) { - Pub->unref(); - } - Struct->unref(); - Name->unref(); - T1->unref(); - skipToLineFoldEnd(); - return nullptr; - } - auto TE = parseTypeExpression(); - if (!TE) { - if (Pub) { - Pub->unref(); - } - Struct->unref(); - Name->unref(); - T1->unref(); - Colon->unref(); - skipToLineFoldEnd(); - return nullptr; - } - checkLineFoldEnd(); } - Tokens.get(); // Always a LineFoldEnd - return new RecordDeclaration { Pub, Struct, Name, BS, Fields }; + auto BS = expectToken(); + if (!BS) { + if (Pub) { + Pub->unref(); + } + Enum->unref(); + Name->unref(); + skipToLineFoldEnd(); + return nullptr; + } + std::vector Members; + for (;;) { +next_member: + auto T0 = Tokens.peek(); + if (T0->getKind() == NodeKind::BlockEnd) { + Tokens.get()->unref(); + break; + } + auto Name = expectToken(); + if (!Name) { + skipToLineFoldEnd(); + continue; + } + auto T1 = Tokens.peek(); + if (T1->getKind() == NodeKind::BlockStart) { + Tokens.get(); + auto BS = static_cast(T1); + auto Fields = parseRecordFields(); + // TODO continue; on error in Fields + Members.push_back(new RecordVariantDeclarationMember { Name, BS, Fields }); + } else { + std::vector Elements; + for (;;) { + auto T2 = Tokens.peek(); + if (T2->getKind() == NodeKind::LineFoldEnd) { + Tokens.get()->unref(); + break; + } + auto TE = parsePrimitiveTypeExpression(); + if (!TE) { + Name->unref(); + for (auto El: Elements) { + El->unref(); + } + goto next_member; + } + Elements.push_back(TE); + } + Members.push_back(new TupleVariantDeclarationMember { Name, Elements }); + } + } + checkLineFoldEnd(); + return new VariantDeclaration { Pub, Enum, Name, TVs, BS, Members }; } Node* Parser::parseClassElement() { @@ -1170,6 +1344,8 @@ after_vars: return parseInstanceDeclaration(); case NodeKind::StructKeyword: return parseRecordDeclaration(); + case NodeKind::EnumKeyword: + return parseVariantDeclaration(); default: return parseExpressionStatement(); } diff --git a/src/Scanner.cc b/src/Scanner.cc index 93a83b52f..a1ea9ef2e 100644 --- a/src/Scanner.cc +++ b/src/Scanner.cc @@ -73,6 +73,7 @@ namespace bolt { { "class", NodeKind::ClassKeyword }, { "instance", NodeKind::InstanceKeyword }, { "struct", NodeKind::StructKeyword }, + { "enum", NodeKind::EnumKeyword }, }; Scanner::Scanner(TextFile& File, Stream& Chars): @@ -245,6 +246,8 @@ digit_finish: return new InstanceKeyword(StartLoc); case NodeKind::StructKeyword: return new StructKeyword(StartLoc); + case NodeKind::EnumKeyword: + return new EnumKeyword(StartLoc); default: ZEN_UNREACHABLE }