Add support for match-expressions in parser

This commit is contained in:
Sam Vervaeck 2023-05-21 11:30:25 +02:00
parent 66d7b90f82
commit 1f94b7f799
Signed by: samvv
SSH key fingerprint: SHA256:dIg0ywU1OP+ZYifrYxy8c5esO72cIKB+4/9wkZj1VaY
5 changed files with 163 additions and 0 deletions

View file

@ -51,6 +51,7 @@ namespace bolt {
ElifKeyword, ElifKeyword,
IfKeyword, IfKeyword,
ElseKeyword, ElseKeyword,
MatchKeyword,
Invalid, Invalid,
EndOfFile, EndOfFile,
BlockStart, BlockStart,
@ -70,6 +71,8 @@ namespace bolt {
VarTypeExpression, VarTypeExpression,
BindPattern, BindPattern,
ReferenceExpression, ReferenceExpression,
MatchCase,
MatchExpression,
NestedExpression, NestedExpression,
ConstantExpression, ConstantExpression,
CallExpression, CallExpression,
@ -588,6 +591,20 @@ namespace bolt {
}; };
class MatchKeyword : public Token {
public:
inline MatchKeyword(TextLoc StartLoc):
Token(NodeKind::MatchKeyword, StartLoc) {}
std::string getText() const override;
static bool classof(const Node* N) {
return N->getKind() == NodeKind::MatchKeyword;
}
};
class Invalid : public Token { class Invalid : public Token {
public: public:
@ -969,6 +986,52 @@ namespace bolt {
}; };
class MatchCase : public Node {
public:
class Pattern* Pattern;
class RArrowAlt* RArrowAlt;
class Expression* Expression;
inline MatchCase(
class Pattern* Pattern,
class RArrowAlt* RArrowAlt,
class Expression* Expression
): Node(NodeKind::MatchCase),
Pattern(Pattern),
RArrowAlt(RArrowAlt),
Expression(Expression) {}
Token* getFirstToken() override;
Token* getLastToken() override;
};
class MatchExpression : public Expression {
public:
class MatchKeyword* MatchKeyword;
Expression* Value;
class BlockStart* BlockStart;
std::vector<MatchCase*> Cases;
inline MatchExpression(
class MatchKeyword* MatchKeyword,
Expression* Value,
class BlockStart* BlockStart,
std::vector<MatchCase*> Cases
): Expression(NodeKind::MatchExpression),
MatchKeyword(MatchKeyword),
Value(Value),
BlockStart(BlockStart),
Cases(Cases) {}
Token* getFirstToken() override;
Token* getLastToken() override;
};
class NestedExpression : public Expression { class NestedExpression : public Expression {
public: public:

View file

@ -63,6 +63,8 @@ namespace bolt {
return static_cast<D*>(this)->visitIfKeyword(static_cast<IfKeyword*>(N)); return static_cast<D*>(this)->visitIfKeyword(static_cast<IfKeyword*>(N));
case NodeKind::ElseKeyword: case NodeKind::ElseKeyword:
return static_cast<D*>(this)->visitElseKeyword(static_cast<ElseKeyword*>(N)); return static_cast<D*>(this)->visitElseKeyword(static_cast<ElseKeyword*>(N));
case NodeKind::MatchKeyword:
return static_cast<D*>(this)->visitMatchKeyword(static_cast<MatchKeyword*>(N));
case NodeKind::Invalid: case NodeKind::Invalid:
return static_cast<D*>(this)->visitInvalid(static_cast<Invalid*>(N)); return static_cast<D*>(this)->visitInvalid(static_cast<Invalid*>(N));
case NodeKind::EndOfFile: case NodeKind::EndOfFile:
@ -101,6 +103,10 @@ namespace bolt {
return static_cast<D*>(this)->visitBindPattern(static_cast<BindPattern*>(N)); return static_cast<D*>(this)->visitBindPattern(static_cast<BindPattern*>(N));
case NodeKind::ReferenceExpression: case NodeKind::ReferenceExpression:
return static_cast<D*>(this)->visitReferenceExpression(static_cast<ReferenceExpression*>(N)); return static_cast<D*>(this)->visitReferenceExpression(static_cast<ReferenceExpression*>(N));
case NodeKind::MatchCase:
return static_cast<D*>(this)->visitMatchCase(static_cast<MatchCase*>(N));
case NodeKind::MatchExpression:
return static_cast<D*>(this)->visitMatchExpression(static_cast<MatchExpression*>(N));
case NodeKind::NestedExpression: case NodeKind::NestedExpression:
return static_cast<D*>(this)->visitNestedExpression(static_cast<NestedExpression*>(N)); return static_cast<D*>(this)->visitNestedExpression(static_cast<NestedExpression*>(N));
case NodeKind::ConstantExpression: case NodeKind::ConstantExpression:
@ -256,6 +262,10 @@ namespace bolt {
visitToken(N); visitToken(N);
} }
void visitMatchKeyword(MatchKeyword* N) {
visitToken(N);
}
void visitInvalid(Invalid* N) { void visitInvalid(Invalid* N) {
visitToken(N); visitToken(N);
} }
@ -348,6 +358,14 @@ namespace bolt {
visitExpression(N); visitExpression(N);
} }
void visitMatchCase(MatchCase* N) {
visitNode(N);
}
void visitMatchExpression(MatchExpression* N) {
visitExpression(N);
}
void visitNestedExpression(NestedExpression* N) { void visitNestedExpression(NestedExpression* N) {
visitExpression(N); visitExpression(N);
} }
@ -514,6 +532,9 @@ namespace bolt {
case NodeKind::ElseKeyword: case NodeKind::ElseKeyword:
visitEachChild(static_cast<ElseKeyword*>(N)); visitEachChild(static_cast<ElseKeyword*>(N));
break; break;
case NodeKind::MatchKeyword:
visitEachChild(static_cast<MatchKeyword*>(N));
break;
case NodeKind::Invalid: case NodeKind::Invalid:
visitEachChild(static_cast<Invalid*>(N)); visitEachChild(static_cast<Invalid*>(N));
break; break;
@ -571,6 +592,12 @@ namespace bolt {
case NodeKind::ReferenceExpression: case NodeKind::ReferenceExpression:
visitEachChild(static_cast<ReferenceExpression*>(N)); visitEachChild(static_cast<ReferenceExpression*>(N));
break; break;
case NodeKind::MatchCase:
visitEachChild(static_cast<MatchCase*>(N));
break;
case NodeKind::MatchExpression:
visitEachChild(static_cast<MatchExpression*>(N));
break;
case NodeKind::NestedExpression: case NodeKind::NestedExpression:
visitEachChild(static_cast<NestedExpression*>(N)); visitEachChild(static_cast<NestedExpression*>(N));
break; break;
@ -713,6 +740,9 @@ namespace bolt {
void visitEachChild(ElseKeyword* N) { void visitEachChild(ElseKeyword* N) {
} }
void visitEachChild(MatchKeyword* N) {
}
void visitEachChild(Invalid* N) { void visitEachChild(Invalid* N) {
} }
@ -801,6 +831,23 @@ namespace bolt {
BOLT_VISIT(N->Name); BOLT_VISIT(N->Name);
} }
void visitEachChild(MatchCase* N) {
BOLT_VISIT(N->Pattern);
BOLT_VISIT(N->RArrowAlt);
BOLT_VISIT(N->Expression);
}
void visitEachChild(MatchExpression* N) {
BOLT_VISIT(N->MatchKeyword);
if (N->Value) {
BOLT_VISIT(N->Value);
}
BOLT_VISIT(N->BlockStart);
for (auto Case: N->Cases) {
BOLT_VISIT(Case);
}
}
void visitEachChild(NestedExpression* N) { void visitEachChild(NestedExpression* N) {
BOLT_VISIT(N->LParen); BOLT_VISIT(N->LParen);
BOLT_VISIT(N->Inner); BOLT_VISIT(N->Inner);

View file

@ -232,6 +232,25 @@ namespace bolt {
return Name; return Name;
} }
Token* MatchCase::getFirstToken() {
return Pattern->getFirstToken();
}
Token* MatchCase::getLastToken() {
return Expression->getLastToken();
}
Token* MatchExpression::getFirstToken() {
return MatchKeyword;
}
Token* MatchExpression::getLastToken() {
if (!Cases.empty()) {
return Cases.back()->getLastToken();
}
return BlockStart;
}
Token* NestedExpression::getFirstToken() { Token* NestedExpression::getFirstToken() {
return LParen; return LParen;
} }
@ -514,6 +533,10 @@ namespace bolt {
return "elif"; return "elif";
} }
std::string MatchKeyword::getText() const {
return "match";
}
std::string ModKeyword::getText() const { std::string ModKeyword::getText() const {
return "mod"; return "mod";
} }

View file

@ -231,6 +231,33 @@ after_constraints:
auto T2 = static_cast<RParen*>(expectToken(NodeKind::RParen)); auto T2 = static_cast<RParen*>(expectToken(NodeKind::RParen));
return new NestedExpression(static_cast<LParen*>(T0), E, T2); return new NestedExpression(static_cast<LParen*>(T0), E, T2);
} }
case NodeKind::MatchKeyword:
{
Tokens.get();
auto T1 = Tokens.peek();
Expression* Value = nullptr;
BlockStart* BlockStart;
if (llvm::isa<class BlockStart>(T1)) {
BlockStart = static_cast<class BlockStart*>(T1);
} else {
Value = parseExpression();
BlockStart = expectToken<class BlockStart>();
}
std::vector<MatchCase*> Cases;
for (;;) {
auto T2 = Tokens.peek();
if (llvm::isa<BlockEnd>(T2)) {
Tokens.get();
break;
}
auto Pattern = parsePattern();
auto RArrowAlt = expectToken<class RArrowAlt>();
auto Expression = parseExpression();
expectToken<LineFoldEnd>();
Cases.push_back(new MatchCase { Pattern, RArrowAlt, Expression });
}
return new MatchExpression(static_cast<MatchKeyword*>(T0), Value, BlockStart, Cases);
}
case NodeKind::IntegerLiteral: case NodeKind::IntegerLiteral:
case NodeKind::StringLiteral: case NodeKind::StringLiteral:
Tokens.get(); Tokens.get();

View file

@ -69,6 +69,7 @@ namespace bolt {
{ "if", NodeKind::IfKeyword }, { "if", NodeKind::IfKeyword },
{ "else", NodeKind::ElseKeyword }, { "else", NodeKind::ElseKeyword },
{ "elif", NodeKind::ElifKeyword }, { "elif", NodeKind::ElifKeyword },
{ "match", NodeKind::MatchKeyword },
{ "class", NodeKind::ClassKeyword }, { "class", NodeKind::ClassKeyword },
{ "instance", NodeKind::InstanceKeyword }, { "instance", NodeKind::InstanceKeyword },
}; };
@ -235,6 +236,8 @@ digit_finish:
return new ElifKeyword(StartLoc); return new ElifKeyword(StartLoc);
case NodeKind::ElseKeyword: case NodeKind::ElseKeyword:
return new ElseKeyword(StartLoc); return new ElseKeyword(StartLoc);
case NodeKind::MatchKeyword:
return new MatchKeyword(StartLoc);
case NodeKind::ClassKeyword: case NodeKind::ClassKeyword:
return new ClassKeyword(StartLoc); return new ClassKeyword(StartLoc);
case NodeKind::InstanceKeyword: case NodeKind::InstanceKeyword: