diff --git a/AST.cs b/AST.cs index 75f47b8..a333cb3 100644 --- a/AST.cs +++ b/AST.cs @@ -40,8 +40,6 @@ public partial record Literal } } -public record Binding(Pattern Pattern, Expr Value); - public partial record SimplePattern { public override string ToString() @@ -54,6 +52,16 @@ public partial record SimplePattern } } +public abstract record Binding(Expr Value); +public record VarBinding(Pattern Pattern, Expr Value) : Binding(Value); +public record FuncBinding(Name Name, SimplePattern[] Params, Expr Value) : Binding(Value) +{ + public override string ToString() + { + return $"FuncBinding {{ Name = {Name}, Params = {string.Join(", ", (IEnumerable)(this.Params))}, Value = {this.Value} }}"; + } +} + public partial record Let { public override string ToString() @@ -68,4 +76,4 @@ public partial record RecordPattern { return $"Let {{ Bindings = {string.Join(", ", (IEnumerable)(this.Fields))}, Rest = {this.Rest} }}"; } -} \ No newline at end of file +} diff --git a/Parser.cs b/Parser.cs index c8ccddb..adefd30 100644 --- a/Parser.cs +++ b/Parser.cs @@ -248,20 +248,53 @@ class Parser return ifExpr(); } - // TODO Add function bindings. List bindings = new List(); - Pattern p = pattern(); - consume(TokenType.Equal, "Expect '=' after pattern."); - bindings.Add(new(p, expression())); + bindings.Add(parseBinding()); while (match(TokenType.And)) { - p = pattern(); - consume(TokenType.Equal, "Expect '=' after pattern."); - bindings.Add(new(p, expression())); + bindings.Add(parseBinding()); } consume(TokenType.In, "Expect 'in' after let-bindings."); Expr body = expression(); return new Let(bindings.ToArray(), body); + + Binding parseBinding() + { + Pattern p = pattern(); + switch (p) + { + case (SimplePattern(var funcName)) when funcName != null && match(TokenType.LParen): + List funcParams = new List(); + while (!check(TokenType.RParen)) + { + Name? paramName; + if (match(TokenType.Blank)) + { + funcParams.Add(new(null)); + } + else if ((paramName = name()) != null) + { + funcParams.Add(new(paramName)); + } + else + { + throw error(peek(), "Expect identifier or '_' as function parameter."); + } + if (!match(TokenType.Comma)) + { + break; + } + } + consume(TokenType.RParen, "Expect ')' at end of parameters."); + consume(TokenType.Equal, "Expect '=' after parameters."); + return new FuncBinding(funcName, funcParams.ToArray(), expression()); + default: + consume(TokenType.Equal, "Expect '=' after pattern."); + return new VarBinding(p, expression()); + } + } + + } private Expr ifExpr() @@ -300,7 +333,7 @@ class Parser Pattern pat = pattern(); consume(TokenType.DoubleArrow, "Expect '=>' after pattern."); Expr value = expression(); - return new(pat, value); + return new VarBinding(pat, value); } } @@ -357,7 +390,7 @@ class Parser break; } } - consume(TokenType.RParen, "Expect '(' after arguments."); + consume(TokenType.RParen, "Expect ')' after arguments."); return new Call(expr, args.ToArray()); }