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,
IfKeyword,
ElseKeyword,
MatchKeyword,
Invalid,
EndOfFile,
BlockStart,
@ -70,6 +71,8 @@ namespace bolt {
VarTypeExpression,
BindPattern,
ReferenceExpression,
MatchCase,
MatchExpression,
NestedExpression,
ConstantExpression,
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 {
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 {
public:

View file

@ -63,6 +63,8 @@ namespace bolt {
return static_cast<D*>(this)->visitIfKeyword(static_cast<IfKeyword*>(N));
case NodeKind::ElseKeyword:
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:
return static_cast<D*>(this)->visitInvalid(static_cast<Invalid*>(N));
case NodeKind::EndOfFile:
@ -101,6 +103,10 @@ namespace bolt {
return static_cast<D*>(this)->visitBindPattern(static_cast<BindPattern*>(N));
case NodeKind::ReferenceExpression:
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:
return static_cast<D*>(this)->visitNestedExpression(static_cast<NestedExpression*>(N));
case NodeKind::ConstantExpression:
@ -256,6 +262,10 @@ namespace bolt {
visitToken(N);
}
void visitMatchKeyword(MatchKeyword* N) {
visitToken(N);
}
void visitInvalid(Invalid* N) {
visitToken(N);
}
@ -348,6 +358,14 @@ namespace bolt {
visitExpression(N);
}
void visitMatchCase(MatchCase* N) {
visitNode(N);
}
void visitMatchExpression(MatchExpression* N) {
visitExpression(N);
}
void visitNestedExpression(NestedExpression* N) {
visitExpression(N);
}
@ -514,6 +532,9 @@ namespace bolt {
case NodeKind::ElseKeyword:
visitEachChild(static_cast<ElseKeyword*>(N));
break;
case NodeKind::MatchKeyword:
visitEachChild(static_cast<MatchKeyword*>(N));
break;
case NodeKind::Invalid:
visitEachChild(static_cast<Invalid*>(N));
break;
@ -571,6 +592,12 @@ namespace bolt {
case NodeKind::ReferenceExpression:
visitEachChild(static_cast<ReferenceExpression*>(N));
break;
case NodeKind::MatchCase:
visitEachChild(static_cast<MatchCase*>(N));
break;
case NodeKind::MatchExpression:
visitEachChild(static_cast<MatchExpression*>(N));
break;
case NodeKind::NestedExpression:
visitEachChild(static_cast<NestedExpression*>(N));
break;
@ -713,6 +740,9 @@ namespace bolt {
void visitEachChild(ElseKeyword* N) {
}
void visitEachChild(MatchKeyword* N) {
}
void visitEachChild(Invalid* N) {
}
@ -801,6 +831,23 @@ namespace bolt {
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) {
BOLT_VISIT(N->LParen);
BOLT_VISIT(N->Inner);

View file

@ -232,6 +232,25 @@ namespace bolt {
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() {
return LParen;
}
@ -514,6 +533,10 @@ namespace bolt {
return "elif";
}
std::string MatchKeyword::getText() const {
return "match";
}
std::string ModKeyword::getText() const {
return "mod";
}

View file

@ -231,6 +231,33 @@ after_constraints:
auto T2 = static_cast<RParen*>(expectToken(NodeKind::RParen));
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::StringLiteral:
Tokens.get();

View file

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