Parse if-expressions

This commit is contained in:
Brandon Dyck 2023-06-28 16:26:08 -06:00
parent 1264aca7f3
commit ba5283694e
5 changed files with 42 additions and 1 deletions

View File

@ -43,4 +43,9 @@ class ASTPrinter : IVisitor<string>
{ {
return parenthesize(expr.Op.lexeme, expr.Right); return parenthesize(expr.Op.lexeme, expr.Right);
} }
public string visitIfExpr(If expr)
{
return parenthesize("if", expr.Condition, expr.Then, expr.Else);
}
} }

View File

@ -14,6 +14,7 @@ public interface IVisitor<T> {
T visitGroupingExpr(Grouping expr); T visitGroupingExpr(Grouping expr);
T visitLiteralExpr(Literal expr); T visitLiteralExpr(Literal expr);
T visitUnaryExpr(Unary expr); T visitUnaryExpr(Unary expr);
T visitIfExpr(If expr);
} }
public class Binary : Expr public class Binary : Expr
{ {
@ -50,3 +51,13 @@ public class Unary : Expr
return visitor.visitUnaryExpr(this); return visitor.visitUnaryExpr(this);
} }
} }
public class If : Expr
{
public required Expr Condition { get; init; }
public required Expr Then { get; init; }
public required Expr Else { get; init; }
public override T accept<T>(IVisitor<T> visitor)
{
return visitor.visitIfExpr(this);
}
}

View File

@ -143,6 +143,7 @@ class Parser
private Expr sum() => binaryLeft(product, TokenType.Minus, TokenType.Plus); private Expr sum() => binaryLeft(product, TokenType.Minus, TokenType.Plus);
private Expr product() => binaryLeft(unary, TokenType.Slash, TokenType.Asterisk); private Expr product() => binaryLeft(unary, TokenType.Slash, TokenType.Asterisk);
private Expr unary() private Expr unary()
{ {
if (match(TokenType.Bang, TokenType.Minus)) if (match(TokenType.Bang, TokenType.Minus))
@ -151,6 +152,21 @@ class Parser
Expr right = unary(); Expr right = unary();
return new Unary { Op = op, Right = right }; return new Unary { Op = op, Right = right };
} }
return ifExpr();
}
private Expr ifExpr()
{
if (match(TokenType.If))
{
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 = condition, Then = thenCase, Else = elseCase };
}
return primary(); return primary();
} }

View File

@ -107,6 +107,7 @@ public enum TokenType
PipeLeft, PipeLeft,
ComposeRight, ComposeRight,
ComposeLeft, ComposeLeft,
If, Then, Else,
When, When,
Is, Is,
Let, Let,
@ -136,6 +137,9 @@ class Scanner
private static readonly Dictionary<String, TokenType> keywords = new Dictionary<string, TokenType>() private static readonly Dictionary<String, TokenType> keywords = new Dictionary<string, TokenType>()
{ {
{"def", TokenType.Def}, {"def", TokenType.Def},
{"if", TokenType.If},
{"then", TokenType.Then},
{"else", TokenType.Else},
{"when", TokenType.When}, {"when", TokenType.When},
{"is", TokenType.Is}, {"is", TokenType.Is},
{"let", TokenType.Let}, {"let", TokenType.Let},

View File

@ -14,7 +14,12 @@ let types =
[ { Type = "System.Object" [ { Type = "System.Object"
Name = "Value" } ] } Name = "Value" } ] }
{ Name = "Unary" { Name = "Unary"
Fields = [ { Type = "Token"; Name = "Op" }; { Type = "Expr"; Name = "Right" } ] } ] Fields = [ { Type = "Token"; Name = "Op" }; { Type = "Expr"; Name = "Right" } ] }
{ Name = "If"
Fields =
[ { Type = "Expr"; Name = "Condition" }
{ Type = "Expr"; Name = "Then" }
{ Type = "Expr"; Name = "Else" } ] } ]
let visitorMethod baseName t = $"visit{t.Name}{baseName}" let visitorMethod baseName t = $"visit{t.Name}{baseName}"