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.CodeDom.Compiler;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Finn.AST;
|
namespace Finn.AST;
|
||||||
|
|
||||||
@ -38,3 +39,25 @@ public partial record Literal
|
|||||||
return this.Value.ToString()!;
|
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 visitSelectorExpr(Selector expr);
|
||||||
T visitIndexerExpr(Indexer expr);
|
T visitIndexerExpr(Indexer expr);
|
||||||
T visitCallExpr(Call expr);
|
T visitCallExpr(Call expr);
|
||||||
|
T visitLetExpr(Let expr);
|
||||||
}
|
}
|
||||||
public partial record Sequence(Expr Left, Expr Right) : 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);
|
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();
|
Expr right = unary();
|
||||||
return new Unary(op, right);
|
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();
|
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()
|
private Expr control()
|
||||||
{
|
{
|
||||||
switch (peek().type)
|
switch (peek().type)
|
||||||
@ -322,7 +398,7 @@ class Parser
|
|||||||
Expr? argument = null;
|
Expr? argument = null;
|
||||||
if (tag == null)
|
if (tag == null)
|
||||||
{
|
{
|
||||||
throw error(peek(), "Expect identifier after backtick.");
|
throw error(peek(), "Expect identifier as tag name.");
|
||||||
}
|
}
|
||||||
if (match(TokenType.LParen))
|
if (match(TokenType.LParen))
|
||||||
{
|
{
|
||||||
|
@ -11,16 +11,16 @@ public abstract record Pattern() {
|
|||||||
public abstract T accept<T>(IPatternVisitor<T> visitor);
|
public abstract T accept<T>(IPatternVisitor<T> visitor);
|
||||||
}
|
}
|
||||||
public interface IPatternVisitor<T> {
|
public interface IPatternVisitor<T> {
|
||||||
T visitIdentifierPatternPattern(IdentifierPattern pattern);
|
T visitSimplePatternPattern(SimplePattern pattern);
|
||||||
T visitVariantPatternPattern(VariantPattern pattern);
|
T visitVariantPatternPattern(VariantPattern pattern);
|
||||||
T visitFieldPatternPattern(FieldPattern pattern);
|
T visitFieldPatternPattern(FieldPattern pattern);
|
||||||
T visitRecordPatternPattern(RecordPattern 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)
|
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()
|
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);
|
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)
|
public override T accept<T>(IPatternVisitor<T> visitor)
|
||||||
{
|
{
|
||||||
|
@ -38,10 +38,15 @@ let exprTypes =
|
|||||||
{ Name = "Indexer"
|
{ Name = "Indexer"
|
||||||
Fields = [ { Type = "Expr"; Name = "Left" }; { Type = "Expr"; Name = "Index" } ] }
|
Fields = [ { Type = "Expr"; Name = "Left" }; { Type = "Expr"; Name = "Index" } ] }
|
||||||
{ Name = "Call"
|
{ 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 =
|
let patternTypes =
|
||||||
[ { Name = "IdentifierPattern"
|
[ { Name = "SimplePattern"
|
||||||
Fields = [ { Type = "Name?"; Name = "Identifier" } ] }
|
Fields = [ { Type = "Name?"; Name = "Identifier" } ] }
|
||||||
{ Name = "VariantPattern"
|
{ Name = "VariantPattern"
|
||||||
Fields = [ { Type = "Name"; Name = "Tag" }; { Type = "Pattern?"; Name = "Argument" } ] }
|
Fields = [ { Type = "Name"; Name = "Tag" }; { Type = "Pattern?"; Name = "Argument" } ] }
|
||||||
@ -51,7 +56,7 @@ let patternTypes =
|
|||||||
Fields =
|
Fields =
|
||||||
[ { Type = "FieldPattern[]"
|
[ { Type = "FieldPattern[]"
|
||||||
Name = "Fields" }
|
Name = "Fields" }
|
||||||
{ Type = "IdentifierPattern"
|
{ Type = "SimplePattern?"
|
||||||
Name = "Rest" } ] } ]
|
Name = "Rest" } ] } ]
|
||||||
|
|
||||||
let visitorMethod baseName t = $"visit{t.Name}{baseName}"
|
let visitorMethod baseName t = $"visit{t.Name}{baseName}"
|
||||||
|
Loading…
Reference in New Issue
Block a user