Parse let exprs with simple and variant patterns
This commit is contained in:
parent
ef3de7a707
commit
b5bdd95605
23
AST.cs
23
AST.cs
@ -1,4 +1,5 @@
|
||||
using System.CodeDom.Compiler;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Finn.AST;
|
||||
|
||||
@ -38,3 +39,25 @@ public partial record Literal
|
||||
return this.Value.ToString()!;
|
||||
}
|
||||
}
|
||||
|
||||
public record Binding(Pattern Pattern, Expr Value);
|
||||
|
||||
public partial record SimplePattern
|
||||
{
|
||||
public override string ToString()
|
||||
{
|
||||
if (this.Identifier == null)
|
||||
{
|
||||
return "_";
|
||||
}
|
||||
return this.Identifier.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public partial record Let
|
||||
{
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Let {{ Bindings = {string.Join(", ", (IEnumerable<object?>)(this.Bindings))}, Body = {this.Body} }}";
|
||||
}
|
||||
}
|
@ -24,6 +24,7 @@ public interface IExprVisitor<T> {
|
||||
T visitSelectorExpr(Selector expr);
|
||||
T visitIndexerExpr(Indexer expr);
|
||||
T visitCallExpr(Call expr);
|
||||
T visitLetExpr(Let expr);
|
||||
}
|
||||
public partial record Sequence(Expr Left, Expr Right) : Expr()
|
||||
{
|
||||
@ -116,3 +117,10 @@ public partial record Call(Expr Left, Expr?[] Arguments) : Expr()
|
||||
return visitor.visitCallExpr(this);
|
||||
}
|
||||
}
|
||||
public partial record Let(Binding[] Bindings, Expr Body) : Expr()
|
||||
{
|
||||
public override T accept<T>(IExprVisitor<T> visitor)
|
||||
{
|
||||
return visitor.visitLetExpr(this);
|
||||
}
|
||||
}
|
||||
|
78
Parser.cs
78
Parser.cs
@ -158,9 +158,85 @@ class Parser
|
||||
Expr right = unary();
|
||||
return new Unary(op, right);
|
||||
}
|
||||
return let();
|
||||
}
|
||||
|
||||
private RecordPattern? recordPattern()
|
||||
{
|
||||
if (!match(TokenType.LBrace))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
throw new NotImplementedException("TODO record pattern");
|
||||
}
|
||||
|
||||
private VariantPattern? variantPattern()
|
||||
{
|
||||
if (!match(TokenType.Backtick))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
Name? tag = name();
|
||||
if (tag == null)
|
||||
{
|
||||
throw error(peek(), "Expect identifier as tag name.");
|
||||
}
|
||||
if (!match(TokenType.LParen))
|
||||
{
|
||||
return new(tag, null);
|
||||
}
|
||||
Pattern argument = pattern();
|
||||
consume(TokenType.RParen, "Expect ')' after variant argument.");
|
||||
return new(tag, argument);
|
||||
}
|
||||
|
||||
private Pattern pattern()
|
||||
{
|
||||
if (match(TokenType.Blank))
|
||||
{
|
||||
return new SimplePattern(null);
|
||||
}
|
||||
|
||||
var identifier = name();
|
||||
if (identifier != null)
|
||||
{
|
||||
return new SimplePattern(identifier);
|
||||
}
|
||||
|
||||
Pattern? p = recordPattern();
|
||||
if (p != null)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
if ((p = variantPattern()) != null)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
throw error(peek(), "Expect pattern after 'let'.");
|
||||
}
|
||||
|
||||
private Expr let()
|
||||
{
|
||||
if (!match(TokenType.Let))
|
||||
{
|
||||
return control();
|
||||
}
|
||||
|
||||
List<Binding> bindings = new List<Binding>();
|
||||
Pattern p = pattern();
|
||||
consume(TokenType.Equal, "Expect '=' after pattern.");
|
||||
bindings.Add(new(p, expression()));
|
||||
while (match(TokenType.And))
|
||||
{
|
||||
p = pattern();
|
||||
consume(TokenType.Equal, "Expect '=' after pattern.");
|
||||
bindings.Add(new(p, expression()));
|
||||
}
|
||||
consume(TokenType.In, "Expect 'in' after let-bindings.");
|
||||
Expr body = expression();
|
||||
return new Let(bindings.ToArray(), body);
|
||||
}
|
||||
|
||||
private Expr control()
|
||||
{
|
||||
switch (peek().type)
|
||||
@ -322,7 +398,7 @@ class Parser
|
||||
Expr? argument = null;
|
||||
if (tag == null)
|
||||
{
|
||||
throw error(peek(), "Expect identifier after backtick.");
|
||||
throw error(peek(), "Expect identifier as tag name.");
|
||||
}
|
||||
if (match(TokenType.LParen))
|
||||
{
|
||||
|
@ -11,16 +11,16 @@ public abstract record Pattern() {
|
||||
public abstract T accept<T>(IPatternVisitor<T> visitor);
|
||||
}
|
||||
public interface IPatternVisitor<T> {
|
||||
T visitIdentifierPatternPattern(IdentifierPattern pattern);
|
||||
T visitSimplePatternPattern(SimplePattern pattern);
|
||||
T visitVariantPatternPattern(VariantPattern pattern);
|
||||
T visitFieldPatternPattern(FieldPattern pattern);
|
||||
T visitRecordPatternPattern(RecordPattern pattern);
|
||||
}
|
||||
public partial record IdentifierPattern(Name? Identifier) : Pattern()
|
||||
public partial record SimplePattern(Name? Identifier) : Pattern()
|
||||
{
|
||||
public override T accept<T>(IPatternVisitor<T> visitor)
|
||||
{
|
||||
return visitor.visitIdentifierPatternPattern(this);
|
||||
return visitor.visitSimplePatternPattern(this);
|
||||
}
|
||||
}
|
||||
public partial record VariantPattern(Name Tag, Pattern? Argument) : Pattern()
|
||||
@ -37,7 +37,7 @@ public partial record FieldPattern(Name Name, Pattern? Pattern) : Pattern()
|
||||
return visitor.visitFieldPatternPattern(this);
|
||||
}
|
||||
}
|
||||
public partial record RecordPattern(FieldPattern[] Fields, IdentifierPattern Rest) : Pattern()
|
||||
public partial record RecordPattern(FieldPattern[] Fields, SimplePattern? Rest) : Pattern()
|
||||
{
|
||||
public override T accept<T>(IPatternVisitor<T> visitor)
|
||||
{
|
||||
|
@ -38,10 +38,15 @@ let exprTypes =
|
||||
{ Name = "Indexer"
|
||||
Fields = [ { Type = "Expr"; Name = "Left" }; { Type = "Expr"; Name = "Index" } ] }
|
||||
{ Name = "Call"
|
||||
Fields = [ { Type = "Expr"; Name = "Left" }; { Type = "Expr?[]"; Name = "Arguments" } ] } ]
|
||||
Fields = [ { Type = "Expr"; Name = "Left" }; { Type = "Expr?[]"; Name = "Arguments" } ] }
|
||||
{ Name = "Let"
|
||||
Fields =
|
||||
[ { Type = "Binding[]"
|
||||
Name = "Bindings" }
|
||||
{ Type = "Expr"; Name = "Body" } ] } ]
|
||||
|
||||
let patternTypes =
|
||||
[ { Name = "IdentifierPattern"
|
||||
[ { Name = "SimplePattern"
|
||||
Fields = [ { Type = "Name?"; Name = "Identifier" } ] }
|
||||
{ Name = "VariantPattern"
|
||||
Fields = [ { Type = "Name"; Name = "Tag" }; { Type = "Pattern?"; Name = "Argument" } ] }
|
||||
@ -51,7 +56,7 @@ let patternTypes =
|
||||
Fields =
|
||||
[ { Type = "FieldPattern[]"
|
||||
Name = "Fields" }
|
||||
{ Type = "IdentifierPattern"
|
||||
{ Type = "SimplePattern?"
|
||||
Name = "Rest" } ] } ]
|
||||
|
||||
let visitorMethod baseName t = $"visit{t.Name}{baseName}"
|
||||
|
Loading…
Reference in New Issue
Block a user