Parse if-expressions
This commit is contained in:
		@@ -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);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										11
									
								
								Expr.g.cs
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								Expr.g.cs
									
									
									
									
									
								
							@@ -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);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										16
									
								
								Parser.cs
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								Parser.cs
									
									
									
									
									
								
							@@ -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();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user