From ba5283694e7b0ea41b0eadc4beffa5f3a6f2ffc9 Mon Sep 17 00:00:00 2001 From: Brandon Dyck Date: Wed, 28 Jun 2023 16:26:08 -0600 Subject: [PATCH] Parse if-expressions --- ASTPrinter.cs | 5 +++++ Expr.g.cs | 11 +++++++++++ Parser.cs | 16 ++++++++++++++++ Program.cs | 4 ++++ ast_classes.fsx | 7 ++++++- 5 files changed, 42 insertions(+), 1 deletion(-) diff --git a/ASTPrinter.cs b/ASTPrinter.cs index a29998d..a331171 100644 --- a/ASTPrinter.cs +++ b/ASTPrinter.cs @@ -43,4 +43,9 @@ class ASTPrinter : IVisitor { return parenthesize(expr.Op.lexeme, expr.Right); } + + public string visitIfExpr(If expr) + { + return parenthesize("if", expr.Condition, expr.Then, expr.Else); + } } diff --git a/Expr.g.cs b/Expr.g.cs index 290bbf4..1e0937d 100644 --- a/Expr.g.cs +++ b/Expr.g.cs @@ -14,6 +14,7 @@ public interface IVisitor { T visitGroupingExpr(Grouping expr); T visitLiteralExpr(Literal expr); T visitUnaryExpr(Unary expr); + T visitIfExpr(If expr); } public class Binary : Expr { @@ -50,3 +51,13 @@ public class Unary : Expr 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(IVisitor visitor) + { + return visitor.visitIfExpr(this); + } +} diff --git a/Parser.cs b/Parser.cs index 502e1ed..9db5c7b 100644 --- a/Parser.cs +++ b/Parser.cs @@ -143,6 +143,7 @@ class Parser private Expr sum() => binaryLeft(product, TokenType.Minus, TokenType.Plus); private Expr product() => binaryLeft(unary, TokenType.Slash, TokenType.Asterisk); + private Expr unary() { if (match(TokenType.Bang, TokenType.Minus)) @@ -151,6 +152,21 @@ class Parser Expr right = unary(); 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(); } diff --git a/Program.cs b/Program.cs index e7acf23..efbc2dd 100644 --- a/Program.cs +++ b/Program.cs @@ -107,6 +107,7 @@ public enum TokenType PipeLeft, ComposeRight, ComposeLeft, + If, Then, Else, When, Is, Let, @@ -136,6 +137,9 @@ class Scanner private static readonly Dictionary keywords = new Dictionary() { {"def", TokenType.Def}, + {"if", TokenType.If}, + {"then", TokenType.Then}, + {"else", TokenType.Else}, {"when", TokenType.When}, {"is", TokenType.Is}, {"let", TokenType.Let}, diff --git a/ast_classes.fsx b/ast_classes.fsx index 5b7b09f..35ec3ed 100644 --- a/ast_classes.fsx +++ b/ast_classes.fsx @@ -14,7 +14,12 @@ let types = [ { Type = "System.Object" Name = "Value" } ] } { 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}"