Evaluate let-exprs with simple bindings
This commit is contained in:
parent
108870c731
commit
ca97c93181
94
Expr.g.cs
94
Expr.g.cs
@ -8,127 +8,127 @@
|
|||||||
namespace Finn.AST;
|
namespace Finn.AST;
|
||||||
|
|
||||||
public abstract record Expr() {
|
public abstract record Expr() {
|
||||||
public abstract T accept<T>(IExprVisitor<T> visitor);
|
public abstract TResult accept<TContext, TResult>(TContext context, IExprVisitor<TContext, TResult> visitor);
|
||||||
}
|
}
|
||||||
public interface IExprVisitor<T> {
|
public interface IExprVisitor<TContext, TResult> {
|
||||||
T visitSequenceExpr(Sequence expr);
|
TResult visitSequenceExpr(TContext context, Sequence expr);
|
||||||
T visitBinaryExpr(Binary expr);
|
TResult visitBinaryExpr(TContext context, Binary expr);
|
||||||
T visitGroupingExpr(Grouping expr);
|
TResult visitGroupingExpr(TContext context, Grouping expr);
|
||||||
T visitLiteralExpr(Literal expr);
|
TResult visitLiteralExpr(TContext context, Literal expr);
|
||||||
T visitUnaryExpr(Unary expr);
|
TResult visitUnaryExpr(TContext context, Unary expr);
|
||||||
T visitIfExpr(If expr);
|
TResult visitIfExpr(TContext context, If expr);
|
||||||
T visitVariableExpr(Variable expr);
|
TResult visitVariableExpr(TContext context, Variable expr);
|
||||||
T visitListExpr(List expr);
|
TResult visitListExpr(TContext context, List expr);
|
||||||
T visitVariantExpr(Variant expr);
|
TResult visitVariantExpr(TContext context, Variant expr);
|
||||||
T visitRecordExpr(Record expr);
|
TResult visitRecordExpr(TContext context, Record expr);
|
||||||
T visitSelectorExpr(Selector expr);
|
TResult visitSelectorExpr(TContext context, Selector expr);
|
||||||
T visitIndexerExpr(Indexer expr);
|
TResult visitIndexerExpr(TContext context, Indexer expr);
|
||||||
T visitCallExpr(Call expr);
|
TResult visitCallExpr(TContext context, Call expr);
|
||||||
T visitLetExpr(Let expr);
|
TResult visitLetExpr(TContext context, Let expr);
|
||||||
T visitWhenExpr(When expr);
|
TResult visitWhenExpr(TContext context, When expr);
|
||||||
}
|
}
|
||||||
public partial record Sequence(Expr Left, Expr Right) : Expr()
|
public partial record Sequence(Expr Left, Expr Right) : Expr()
|
||||||
{
|
{
|
||||||
public override T accept<T>(IExprVisitor<T> visitor)
|
public override TResult accept<TContext, TResult>(TContext context, IExprVisitor<TContext, TResult> visitor)
|
||||||
{
|
{
|
||||||
return visitor.visitSequenceExpr(this);
|
return visitor.visitSequenceExpr(context, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public partial record Binary(Expr Left, Token Op, Expr Right) : Expr()
|
public partial record Binary(Expr Left, Token Op, Expr Right) : Expr()
|
||||||
{
|
{
|
||||||
public override T accept<T>(IExprVisitor<T> visitor)
|
public override TResult accept<TContext, TResult>(TContext context, IExprVisitor<TContext, TResult> visitor)
|
||||||
{
|
{
|
||||||
return visitor.visitBinaryExpr(this);
|
return visitor.visitBinaryExpr(context, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public partial record Grouping(Expr Expression) : Expr()
|
public partial record Grouping(Expr Expression) : Expr()
|
||||||
{
|
{
|
||||||
public override T accept<T>(IExprVisitor<T> visitor)
|
public override TResult accept<TContext, TResult>(TContext context, IExprVisitor<TContext, TResult> visitor)
|
||||||
{
|
{
|
||||||
return visitor.visitGroupingExpr(this);
|
return visitor.visitGroupingExpr(context, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public partial record Literal(System.Object Value) : Expr()
|
public partial record Literal(System.Object Value) : Expr()
|
||||||
{
|
{
|
||||||
public override T accept<T>(IExprVisitor<T> visitor)
|
public override TResult accept<TContext, TResult>(TContext context, IExprVisitor<TContext, TResult> visitor)
|
||||||
{
|
{
|
||||||
return visitor.visitLiteralExpr(this);
|
return visitor.visitLiteralExpr(context, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public partial record Unary(Token Op, Expr Right) : Expr()
|
public partial record Unary(Token Op, Expr Right) : Expr()
|
||||||
{
|
{
|
||||||
public override T accept<T>(IExprVisitor<T> visitor)
|
public override TResult accept<TContext, TResult>(TContext context, IExprVisitor<TContext, TResult> visitor)
|
||||||
{
|
{
|
||||||
return visitor.visitUnaryExpr(this);
|
return visitor.visitUnaryExpr(context, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public partial record If(Expr Condition, Expr Then, Expr Else) : Expr()
|
public partial record If(Expr Condition, Expr Then, Expr Else) : Expr()
|
||||||
{
|
{
|
||||||
public override T accept<T>(IExprVisitor<T> visitor)
|
public override TResult accept<TContext, TResult>(TContext context, IExprVisitor<TContext, TResult> visitor)
|
||||||
{
|
{
|
||||||
return visitor.visitIfExpr(this);
|
return visitor.visitIfExpr(context, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public partial record Variable(Name Value) : Expr()
|
public partial record Variable(Name Value) : Expr()
|
||||||
{
|
{
|
||||||
public override T accept<T>(IExprVisitor<T> visitor)
|
public override TResult accept<TContext, TResult>(TContext context, IExprVisitor<TContext, TResult> visitor)
|
||||||
{
|
{
|
||||||
return visitor.visitVariableExpr(this);
|
return visitor.visitVariableExpr(context, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public partial record List(Expr[] Elements) : Expr()
|
public partial record List(Expr[] Elements) : Expr()
|
||||||
{
|
{
|
||||||
public override T accept<T>(IExprVisitor<T> visitor)
|
public override TResult accept<TContext, TResult>(TContext context, IExprVisitor<TContext, TResult> visitor)
|
||||||
{
|
{
|
||||||
return visitor.visitListExpr(this);
|
return visitor.visitListExpr(context, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public partial record Variant(Name Tag, Expr? Argument) : Expr()
|
public partial record Variant(Name Tag, Expr? Argument) : Expr()
|
||||||
{
|
{
|
||||||
public override T accept<T>(IExprVisitor<T> visitor)
|
public override TResult accept<TContext, TResult>(TContext context, IExprVisitor<TContext, TResult> visitor)
|
||||||
{
|
{
|
||||||
return visitor.visitVariantExpr(this);
|
return visitor.visitVariantExpr(context, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public partial record Record(Field[] Extensions, BaseRecord? Base) : Expr()
|
public partial record Record(Field[] Extensions, BaseRecord? Base) : Expr()
|
||||||
{
|
{
|
||||||
public override T accept<T>(IExprVisitor<T> visitor)
|
public override TResult accept<TContext, TResult>(TContext context, IExprVisitor<TContext, TResult> visitor)
|
||||||
{
|
{
|
||||||
return visitor.visitRecordExpr(this);
|
return visitor.visitRecordExpr(context, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public partial record Selector(Expr Left, Name FieldName) : Expr()
|
public partial record Selector(Expr Left, Name FieldName) : Expr()
|
||||||
{
|
{
|
||||||
public override T accept<T>(IExprVisitor<T> visitor)
|
public override TResult accept<TContext, TResult>(TContext context, IExprVisitor<TContext, TResult> visitor)
|
||||||
{
|
{
|
||||||
return visitor.visitSelectorExpr(this);
|
return visitor.visitSelectorExpr(context, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public partial record Indexer(Expr Left, Expr Index) : Expr()
|
public partial record Indexer(Expr Left, Expr Index) : Expr()
|
||||||
{
|
{
|
||||||
public override T accept<T>(IExprVisitor<T> visitor)
|
public override TResult accept<TContext, TResult>(TContext context, IExprVisitor<TContext, TResult> visitor)
|
||||||
{
|
{
|
||||||
return visitor.visitIndexerExpr(this);
|
return visitor.visitIndexerExpr(context, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public partial record Call(Expr Left, Expr?[] Arguments) : Expr()
|
public partial record Call(Expr Left, Expr?[] Arguments) : Expr()
|
||||||
{
|
{
|
||||||
public override T accept<T>(IExprVisitor<T> visitor)
|
public override TResult accept<TContext, TResult>(TContext context, IExprVisitor<TContext, TResult> visitor)
|
||||||
{
|
{
|
||||||
return visitor.visitCallExpr(this);
|
return visitor.visitCallExpr(context, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public partial record Let(Binding[] Bindings, Expr Body) : Expr()
|
public partial record Let(Binding[] Bindings, Expr Body) : Expr()
|
||||||
{
|
{
|
||||||
public override T accept<T>(IExprVisitor<T> visitor)
|
public override TResult accept<TContext, TResult>(TContext context, IExprVisitor<TContext, TResult> visitor)
|
||||||
{
|
{
|
||||||
return visitor.visitLetExpr(this);
|
return visitor.visitLetExpr(context, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public partial record When(Expr Head, Binding[] Cases) : Expr()
|
public partial record When(Expr Head, Binding[] Cases) : Expr()
|
||||||
{
|
{
|
||||||
public override T accept<T>(IExprVisitor<T> visitor)
|
public override TResult accept<TContext, TResult>(TContext context, IExprVisitor<TContext, TResult> visitor)
|
||||||
{
|
{
|
||||||
return visitor.visitWhenExpr(this);
|
return visitor.visitWhenExpr(context, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
158
Interpreter.cs
158
Interpreter.cs
@ -6,18 +6,65 @@ using AST = Finn.AST;
|
|||||||
|
|
||||||
namespace Finn;
|
namespace Finn;
|
||||||
|
|
||||||
public class Interpreter : AST.IExprVisitor<object>
|
public class RuntimeError : Exception
|
||||||
{
|
{
|
||||||
public class RuntimeError : Exception
|
public readonly Token Token;
|
||||||
{
|
|
||||||
public readonly Token Token;
|
|
||||||
|
|
||||||
internal RuntimeError(Token token, String message) : base(message)
|
internal RuntimeError(Token token, String message) : base(message)
|
||||||
{
|
{
|
||||||
Token = token;
|
Token = token;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Env
|
||||||
|
{
|
||||||
|
private readonly Env? enclosing;
|
||||||
|
private readonly Dictionary<string, object> values = new Dictionary<string, object>();
|
||||||
|
|
||||||
|
public Env()
|
||||||
|
{
|
||||||
|
this.enclosing = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Env(Env enclosing)
|
||||||
|
{
|
||||||
|
this.enclosing = enclosing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object this[AST.Name name]
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (values.ContainsKey(name.Value))
|
||||||
|
{
|
||||||
|
// TODO use real location info
|
||||||
|
var tok = new Token(TokenType.Identifier, name.Value, null, 1);
|
||||||
|
throw new RuntimeError(tok, $"Cannot redefine variable {name} in same scope.");
|
||||||
|
}
|
||||||
|
values[name.Value] = value;
|
||||||
|
}
|
||||||
|
get
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return values[name.Value];
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
if (enclosing != null)
|
||||||
|
{
|
||||||
|
return enclosing[name];
|
||||||
|
}
|
||||||
|
// TODO use real location info
|
||||||
|
var tok = new Token(TokenType.Identifier, name.Value, null, 1);
|
||||||
|
throw new RuntimeError(tok, $"Undefined variable {name}.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Interpreter : AST.IExprVisitor<Env, object>
|
||||||
|
{
|
||||||
private static void checkTypesEqual(object a, object b)
|
private static void checkTypesEqual(object a, object b)
|
||||||
{
|
{
|
||||||
var aType = a.GetType();
|
var aType = a.GetType();
|
||||||
@ -156,7 +203,7 @@ public class Interpreter : AST.IExprVisitor<object>
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var value = evaluate(expression);
|
var value = evaluate(new Env(), expression);
|
||||||
Console.WriteLine(value);
|
Console.WriteLine(value);
|
||||||
}
|
}
|
||||||
catch (RuntimeError err)
|
catch (RuntimeError err)
|
||||||
@ -165,9 +212,9 @@ public class Interpreter : AST.IExprVisitor<object>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private object evaluate(AST.Expr expr)
|
private object evaluate(Env env, AST.Expr expr)
|
||||||
{
|
{
|
||||||
return expr.accept(this);
|
return expr.accept(env, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List checkListOperand(Token op, Object operand)
|
private List checkListOperand(Token op, Object operand)
|
||||||
@ -209,10 +256,10 @@ public class Interpreter : AST.IExprVisitor<object>
|
|||||||
throw new RuntimeError(op, "Operand must be <true,false>.");
|
throw new RuntimeError(op, "Operand must be <true,false>.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public object visitBinaryExpr(AST.Binary expr)
|
public object visitBinaryExpr(Env env, AST.Binary expr)
|
||||||
{
|
{
|
||||||
var left = evaluate(expr.Left);
|
var left = evaluate(env, expr.Left);
|
||||||
var right = evaluate(expr.Right);
|
var right = evaluate(env, expr.Right);
|
||||||
|
|
||||||
switch (expr.Op.type)
|
switch (expr.Op.type)
|
||||||
{
|
{
|
||||||
@ -265,42 +312,42 @@ public class Interpreter : AST.IExprVisitor<object>
|
|||||||
throw new ArgumentException($"bad binary op: {expr.Op}");
|
throw new ArgumentException($"bad binary op: {expr.Op}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public object visitCallExpr(AST.Call expr)
|
public object visitCallExpr(Env env, AST.Call expr)
|
||||||
{
|
{
|
||||||
throw new System.NotImplementedException();
|
throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public object visitGroupingExpr(AST.Grouping expr)
|
public object visitGroupingExpr(Env env, AST.Grouping expr)
|
||||||
{
|
{
|
||||||
return evaluate(expr.Expression);
|
return evaluate(env, expr.Expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
public object visitVariableExpr(AST.Variable expr)
|
public object visitVariableExpr(Env env, AST.Variable expr)
|
||||||
{
|
{
|
||||||
throw new System.NotImplementedException();
|
return env[expr.Value];
|
||||||
}
|
}
|
||||||
|
|
||||||
public object visitIfExpr(AST.If expr)
|
public object visitIfExpr(Env env, AST.If expr)
|
||||||
{
|
{
|
||||||
var cond = evaluate(expr.Condition);
|
var cond = evaluate(env, expr.Condition);
|
||||||
// TODO Maybe I should token info in the AST.
|
// TODO Maybe I should token info in the AST.
|
||||||
var vb = checkBoolOperand(new Token(TokenType.If, "if", null, 1), cond);
|
var vb = checkBoolOperand(new Token(TokenType.If, "if", null, 1), cond);
|
||||||
if (vb == Variant.True)
|
if (vb == Variant.True)
|
||||||
{
|
{
|
||||||
return evaluate(expr.Then);
|
return evaluate(env, expr.Then);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return evaluate(expr.Else);
|
return evaluate(env, expr.Else);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public object visitIndexerExpr(AST.Indexer expr)
|
public object visitIndexerExpr(Env env, AST.Indexer expr)
|
||||||
{
|
{
|
||||||
// TODO use real token
|
// TODO use real token
|
||||||
var tok = new Token(TokenType.LBracket, "[", null, 1);
|
var tok = new Token(TokenType.LBracket, "[", null, 1);
|
||||||
var left = checkListOperand(tok, evaluate(expr.Left));
|
var left = checkListOperand(tok, evaluate(env, expr.Left));
|
||||||
var index = checkNumberOperand(tok, evaluate(expr.Index));
|
var index = checkNumberOperand(tok, evaluate(env, expr.Index));
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var item = left[index];
|
var item = left[index];
|
||||||
@ -309,19 +356,42 @@ public class Interpreter : AST.IExprVisitor<object>
|
|||||||
catch { return new Variant("nothing", null); }
|
catch { return new Variant("nothing", null); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public object visitLetExpr(AST.Let expr)
|
public object visitLetExpr(Env env, AST.Let expr)
|
||||||
{
|
{
|
||||||
throw new System.NotImplementedException();
|
var newEnv = new Env(env);
|
||||||
|
foreach (var binding in expr.Bindings)
|
||||||
|
{
|
||||||
|
switch (binding)
|
||||||
|
{
|
||||||
|
case AST.VarBinding(var pattern, var valueExpr):
|
||||||
|
switch (pattern)
|
||||||
|
{
|
||||||
|
case AST.SimplePattern(var identifier):
|
||||||
|
var value = evaluate(env, valueExpr);
|
||||||
|
if (identifier != null)
|
||||||
|
{
|
||||||
|
newEnv[identifier] = value;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException("TODO moar patternz");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException("TODO function bindings");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return evaluate(newEnv, expr.Body);
|
||||||
}
|
}
|
||||||
|
|
||||||
public object visitListExpr(AST.List expr)
|
public object visitListExpr(Env env, AST.List expr)
|
||||||
{
|
{
|
||||||
// TODO use real token
|
// TODO use real token
|
||||||
var tok = new Token(TokenType.LBracket, "[", null, 1);
|
var tok = new Token(TokenType.LBracket, "[", null, 1);
|
||||||
List l = List.Empty;
|
List l = List.Empty;
|
||||||
foreach (var itemExpr in expr.Elements)
|
foreach (var itemExpr in expr.Elements)
|
||||||
{
|
{
|
||||||
var item = evaluate(itemExpr);
|
var item = evaluate(env, itemExpr);
|
||||||
if (!l.IsEmpty)
|
if (!l.IsEmpty)
|
||||||
{
|
{
|
||||||
try { checkTypesEqual(l[0], item); }
|
try { checkTypesEqual(l[0], item); }
|
||||||
@ -332,19 +402,19 @@ public class Interpreter : AST.IExprVisitor<object>
|
|||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
public object visitLiteralExpr(AST.Literal expr)
|
public object visitLiteralExpr(Env env, AST.Literal expr)
|
||||||
{
|
{
|
||||||
return expr.Value;
|
return expr.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public object visitRecordExpr(AST.Record expr)
|
public object visitRecordExpr(Env env, AST.Record expr)
|
||||||
{
|
{
|
||||||
// TODO use real token
|
// TODO use real token
|
||||||
Token tok = new Token(TokenType.LBrace, "{", null, 1);
|
Token tok = new Token(TokenType.LBrace, "{", null, 1);
|
||||||
Record rec = Record.Empty;
|
Record rec = Record.Empty;
|
||||||
if (expr.Base != null)
|
if (expr.Base != null)
|
||||||
{
|
{
|
||||||
var baseRecValue = evaluate(expr.Base.Value);
|
var baseRecValue = evaluate(env, expr.Base.Value);
|
||||||
if (baseRecValue is not Record)
|
if (baseRecValue is not Record)
|
||||||
{
|
{
|
||||||
throw new RuntimeError(tok, "Base record must be a record.");
|
throw new RuntimeError(tok, "Base record must be a record.");
|
||||||
@ -364,7 +434,7 @@ public class Interpreter : AST.IExprVisitor<object>
|
|||||||
if (update.Value == null) throw new NotImplementedException();
|
if (update.Value == null) throw new NotImplementedException();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
baseRec = baseRec.Update(label, evaluate(update.Value));
|
baseRec = baseRec.Update(label, evaluate(env, update.Value));
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@ -386,15 +456,15 @@ public class Interpreter : AST.IExprVisitor<object>
|
|||||||
}
|
}
|
||||||
extLabels.Add(label);
|
extLabels.Add(label);
|
||||||
if (extension.Value == null) throw new NotImplementedException();
|
if (extension.Value == null) throw new NotImplementedException();
|
||||||
rec = rec.Extend(label, evaluate(extension.Value));
|
rec = rec.Extend(label, evaluate(env, extension.Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
return rec;
|
return rec;
|
||||||
}
|
}
|
||||||
|
|
||||||
public object visitSelectorExpr(AST.Selector expr)
|
public object visitSelectorExpr(Env env, AST.Selector expr)
|
||||||
{
|
{
|
||||||
var left = evaluate(expr.Left);
|
var left = evaluate(env, expr.Left);
|
||||||
// TODO Use real token.
|
// TODO Use real token.
|
||||||
var tok = new Token(TokenType.Period, ".", null, 1);
|
var tok = new Token(TokenType.Period, ".", null, 1);
|
||||||
var r = checkRecordOperand(tok, left);
|
var r = checkRecordOperand(tok, left);
|
||||||
@ -408,15 +478,15 @@ public class Interpreter : AST.IExprVisitor<object>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public object visitSequenceExpr(AST.Sequence expr)
|
public object visitSequenceExpr(Env env, AST.Sequence expr)
|
||||||
{
|
{
|
||||||
evaluate(expr.Left);
|
evaluate(env, expr.Left);
|
||||||
return evaluate(expr.Right);
|
return evaluate(env, expr.Right);
|
||||||
}
|
}
|
||||||
|
|
||||||
public object visitUnaryExpr(AST.Unary expr)
|
public object visitUnaryExpr(Env env, AST.Unary expr)
|
||||||
{
|
{
|
||||||
object right = evaluate(expr.Right);
|
object right = evaluate(env, expr.Right);
|
||||||
switch (expr.Op.type)
|
switch (expr.Op.type)
|
||||||
{
|
{
|
||||||
case TokenType.Minus:
|
case TokenType.Minus:
|
||||||
@ -437,12 +507,12 @@ public class Interpreter : AST.IExprVisitor<object>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public object visitVariantExpr(AST.Variant expr)
|
public object visitVariantExpr(Env env, AST.Variant expr)
|
||||||
{
|
{
|
||||||
return new Variant(expr.Tag.Value, expr.Argument);
|
return new Variant(expr.Tag.Value, expr.Argument);
|
||||||
}
|
}
|
||||||
|
|
||||||
public object visitWhenExpr(AST.When expr)
|
public object visitWhenExpr(Env env, AST.When expr)
|
||||||
{
|
{
|
||||||
throw new System.NotImplementedException();
|
throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
|
28
Pattern.g.cs
28
Pattern.g.cs
@ -8,39 +8,39 @@
|
|||||||
namespace Finn.AST;
|
namespace Finn.AST;
|
||||||
|
|
||||||
public abstract record Pattern() {
|
public abstract record Pattern() {
|
||||||
public abstract T accept<T>(IPatternVisitor<T> visitor);
|
public abstract TResult accept<TContext, TResult>(TContext context, IPatternVisitor<TContext, TResult> visitor);
|
||||||
}
|
}
|
||||||
public interface IPatternVisitor<T> {
|
public interface IPatternVisitor<TContext, TResult> {
|
||||||
T visitSimplePatternPattern(SimplePattern pattern);
|
TResult visitSimplePatternPattern(TContext context, SimplePattern pattern);
|
||||||
T visitVariantPatternPattern(VariantPattern pattern);
|
TResult visitVariantPatternPattern(TContext context, VariantPattern pattern);
|
||||||
T visitFieldPatternPattern(FieldPattern pattern);
|
TResult visitFieldPatternPattern(TContext context, FieldPattern pattern);
|
||||||
T visitRecordPatternPattern(RecordPattern pattern);
|
TResult visitRecordPatternPattern(TContext context, RecordPattern pattern);
|
||||||
}
|
}
|
||||||
public partial record SimplePattern(Name? Identifier) : Pattern()
|
public partial record SimplePattern(Name? Identifier) : Pattern()
|
||||||
{
|
{
|
||||||
public override T accept<T>(IPatternVisitor<T> visitor)
|
public override TResult accept<TContext, TResult>(TContext context, IPatternVisitor<TContext, TResult> visitor)
|
||||||
{
|
{
|
||||||
return visitor.visitSimplePatternPattern(this);
|
return visitor.visitSimplePatternPattern(context, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public partial record VariantPattern(Name Tag, Pattern? Argument) : Pattern()
|
public partial record VariantPattern(Name Tag, Pattern? Argument) : Pattern()
|
||||||
{
|
{
|
||||||
public override T accept<T>(IPatternVisitor<T> visitor)
|
public override TResult accept<TContext, TResult>(TContext context, IPatternVisitor<TContext, TResult> visitor)
|
||||||
{
|
{
|
||||||
return visitor.visitVariantPatternPattern(this);
|
return visitor.visitVariantPatternPattern(context, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public partial record FieldPattern(Name Name, Pattern? Pattern) : Pattern()
|
public partial record FieldPattern(Name Name, Pattern? Pattern) : Pattern()
|
||||||
{
|
{
|
||||||
public override T accept<T>(IPatternVisitor<T> visitor)
|
public override TResult accept<TContext, TResult>(TContext context, IPatternVisitor<TContext, TResult> visitor)
|
||||||
{
|
{
|
||||||
return visitor.visitFieldPatternPattern(this);
|
return visitor.visitFieldPatternPattern(context, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public partial record RecordPattern(FieldPattern[] Fields, SimplePattern? Rest) : Pattern()
|
public partial record RecordPattern(FieldPattern[] Fields, SimplePattern? Rest) : Pattern()
|
||||||
{
|
{
|
||||||
public override T accept<T>(IPatternVisitor<T> visitor)
|
public override TResult accept<TContext, TResult>(TContext context, IPatternVisitor<TContext, TResult> visitor)
|
||||||
{
|
{
|
||||||
return visitor.visitRecordPatternPattern(this);
|
return visitor.visitRecordPatternPattern(context, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ class Program
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void runtimeError(Interpreter.RuntimeError err)
|
public static void runtimeError(RuntimeError err)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine($"{err.Message}\n[line {err.Token.line}]");
|
Console.Error.WriteLine($"{err.Message}\n[line {err.Token.line}]");
|
||||||
hadRuntimeError = true;
|
hadRuntimeError = true;
|
||||||
|
@ -64,10 +64,10 @@ let patternTypes =
|
|||||||
let visitorMethod baseName t = $"visit{t.Name}{baseName}"
|
let visitorMethod baseName t = $"visit{t.Name}{baseName}"
|
||||||
|
|
||||||
let renderIVisitor (sw: System.IO.StreamWriter) (baseName: string) types =
|
let renderIVisitor (sw: System.IO.StreamWriter) (baseName: string) types =
|
||||||
sw.Write($"public interface I{baseName}Visitor<T> {{\n")
|
sw.Write($"public interface I{baseName}Visitor<TContext, TResult> {{\n")
|
||||||
|
|
||||||
for t in types do
|
for t in types do
|
||||||
sw.Write($"\tT {visitorMethod baseName t}({t.Name} {baseName.ToLower()});\n")
|
sw.Write($"\tTResult {visitorMethod baseName t}(TContext context, {t.Name} {baseName.ToLower()});\n")
|
||||||
|
|
||||||
sw.Write("}\n")
|
sw.Write("}\n")
|
||||||
|
|
||||||
@ -86,9 +86,9 @@ let renderType (sw: System.IO.StreamWriter) baseName t =
|
|||||||
{{\n"
|
{{\n"
|
||||||
|
|
||||||
sw.Write
|
sw.Write
|
||||||
$"\tpublic override T accept<T>(I{baseName}Visitor<T> visitor)
|
$"\tpublic override TResult accept<TContext, TResult>(TContext context, I{baseName}Visitor<TContext, TResult> visitor)
|
||||||
\t{{
|
\t{{
|
||||||
\t\treturn visitor.{visitorMethod baseName t}(this);
|
\t\treturn visitor.{visitorMethod baseName t}(context, this);
|
||||||
\t}}\n"
|
\t}}\n"
|
||||||
|
|
||||||
sw.Write("}\n")
|
sw.Write("}\n")
|
||||||
@ -108,7 +108,7 @@ let renderAST outputDir baseName types =
|
|||||||
namespace Finn.AST;
|
namespace Finn.AST;
|
||||||
|
|
||||||
public abstract record {baseName}() {{
|
public abstract record {baseName}() {{
|
||||||
\tpublic abstract T accept<T>(I{baseName}Visitor<T> visitor);
|
\tpublic abstract TResult accept<TContext, TResult>(TContext context, I{baseName}Visitor<TContext, TResult> visitor);
|
||||||
}}\n"
|
}}\n"
|
||||||
|
|
||||||
renderIVisitor sw baseName types
|
renderIVisitor sw baseName types
|
||||||
|
Loading…
Reference in New Issue
Block a user