Parse when-expressions

This commit is contained in:
Brandon Dyck 2023-07-05 08:52:14 -06:00
parent 86a9241632
commit d498cc627b
4 changed files with 69 additions and 20 deletions

View File

@ -25,6 +25,7 @@ public interface IExprVisitor<T> {
T visitIndexerExpr(Indexer expr); T visitIndexerExpr(Indexer expr);
T visitCallExpr(Call expr); T visitCallExpr(Call expr);
T visitLetExpr(Let expr); T visitLetExpr(Let expr);
T visitWhenExpr(When expr);
} }
public partial record Sequence(Expr Left, Expr Right) : Expr() public partial record Sequence(Expr Left, Expr Right) : Expr()
{ {
@ -124,3 +125,10 @@ public partial record Let(Binding[] Bindings, Expr Body) : Expr()
return visitor.visitLetExpr(this); return visitor.visitLetExpr(this);
} }
} }
public partial record When(Expr Head, Binding[] Cases) : Expr()
{
public override T accept<T>(IExprVisitor<T> visitor)
{
return visitor.visitWhenExpr(this);
}
}

View File

@ -245,9 +245,10 @@ class Parser
{ {
if (!match(TokenType.Let)) if (!match(TokenType.Let))
{ {
return control(); return ifExpr();
} }
// TODO Add function bindings.
List<Binding> bindings = new List<Binding>(); List<Binding> bindings = new List<Binding>();
Pattern p = pattern(); Pattern p = pattern();
consume(TokenType.Equal, "Expect '=' after pattern."); consume(TokenType.Equal, "Expect '=' after pattern.");
@ -263,23 +264,63 @@ class Parser
return new Let(bindings.ToArray(), body); return new Let(bindings.ToArray(), body);
} }
private Expr control() private Expr ifExpr()
{ {
switch (peek().type) if (!match(TokenType.If))
{ {
case TokenType.If: return when();
advance();
Expr condition = expression();
consume(TokenType.Then, "Expect 'then' after condition.");
Expr thenCase = expression();
consume(TokenType.Else, "Expect 'else' after 'then' case.");
Expr elseCase = expression();
return new If(condition, thenCase, elseCase);
case TokenType.When:
throw new NotImplementedException("TODO when");
} }
Expr condition = expression();
consume(TokenType.Then, "Expect 'then' after condition.");
Expr thenCase = expression();
consume(TokenType.Else, "Expect 'else' after 'then' case.");
Expr elseCase = expression();
return new If(condition, thenCase, elseCase);
}
return primary(); // private Expr control()
// {
// switch (peek().type)
// {
// case TokenType.If:
// advance();
// Expr condition = expression();
// consume(TokenType.Then, "Expect 'then' after condition.");
// Expr thenCase = expression();
// consume(TokenType.Else, "Expect 'else' after 'then' case.");
// Expr elseCase = expression();
// return new If(condition, thenCase, elseCase);
// case TokenType.When:
// throw new NotImplementedException("TODO when");
// }
// return primary();
// }
private Expr when()
{
if (!match(TokenType.When))
{
return primary();
}
Expr head = expression();
consume(TokenType.Is, "Expect 'is' after expression.");
List<Binding> cases = new List<Binding>();
cases.Add(parseCase());
while (match(TokenType.Comma))
{
cases.Add(parseCase());
}
return new When(head, cases.ToArray());
Binding parseCase()
{
Pattern pat = pattern();
consume(TokenType.DoubleArrow, "Expect '=>' after pattern.");
Expr value = expression();
return new(pat, value);
}
} }
private Name? name() private Name? name()

View File

@ -43,7 +43,9 @@ let exprTypes =
Fields = Fields =
[ { Type = "Binding[]" [ { Type = "Binding[]"
Name = "Bindings" } Name = "Bindings" }
{ Type = "Expr"; Name = "Body" } ] } ] { Type = "Expr"; Name = "Body" } ] }
{ Name = "When"
Fields = [ { Type = "Expr"; Name = "Head" }; { Type = "Binding[]"; Name = "Cases" } ] } ]
let patternTypes = let patternTypes =
[ { Name = "SimplePattern" [ { Name = "SimplePattern"

View File

@ -4,7 +4,8 @@ expression ->
| unary | unary
| binary | binary
| let | let
| control | if
| when
| primary | primary
grouping -> "(" expression ")" ; grouping -> "(" expression ")" ;
@ -19,11 +20,8 @@ record_pattern -> "{" ( identifier ( "=" pattern )? ( "," identifier ( "=" patte
variant_pattern -> "`" identifier ( "(" ( "_" | compound_pattern | identifier ) ")" )? ; variant_pattern -> "`" identifier ( "(" ( "_" | compound_pattern | identifier ) ")" )? ;
parameters -> "(" ( identifier ( "," identifier )* )?")" parameters -> "(" ( identifier ( "," identifier )* )?")"
let -> "let" ( identifier parameters? | pattern ) "=" expression ( "and" ( identifier parameters? | pattern ) "=" expression )* "in" expression ; let -> "let" ( identifier parameters? | pattern ) "=" expression ( "and" ( identifier parameters? | pattern ) "=" expression )* "in" expression ;
control ->
| if
| when
if -> "if" expression "then" expression "else" expression ; if -> "if" expression "then" expression "else" expression ;
when -> "when" expression "is" ( ( identifier | pattern ) "=>" expression )+ ; when -> "when" expression "is" ( identifier | pattern ) "=>" expression ( "," ( identifier | pattern ) "=>" expression )* ;
variant -> "`" identifier ( "(" expression ")" )? ; variant -> "`" identifier ( "(" expression ")" )? ;
base_record -> expression ( "with" identifier "=" expression ( "," identifier "=" expression )* ","? )? base_record -> expression ( "with" identifier "=" expression ( "," identifier "=" expression )* ","? )?
record -> record ->