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;
|
||||
|
||||
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> {
|
||||
T visitSequenceExpr(Sequence expr);
|
||||
T visitBinaryExpr(Binary expr);
|
||||
T visitGroupingExpr(Grouping expr);
|
||||
T visitLiteralExpr(Literal expr);
|
||||
T visitUnaryExpr(Unary expr);
|
||||
T visitIfExpr(If expr);
|
||||
T visitVariableExpr(Variable expr);
|
||||
T visitListExpr(List expr);
|
||||
T visitVariantExpr(Variant expr);
|
||||
T visitRecordExpr(Record expr);
|
||||
T visitSelectorExpr(Selector expr);
|
||||
T visitIndexerExpr(Indexer expr);
|
||||
T visitCallExpr(Call expr);
|
||||
T visitLetExpr(Let expr);
|
||||
T visitWhenExpr(When expr);
|
||||
public interface IExprVisitor<TContext, TResult> {
|
||||
TResult visitSequenceExpr(TContext context, Sequence expr);
|
||||
TResult visitBinaryExpr(TContext context, Binary expr);
|
||||
TResult visitGroupingExpr(TContext context, Grouping expr);
|
||||
TResult visitLiteralExpr(TContext context, Literal expr);
|
||||
TResult visitUnaryExpr(TContext context, Unary expr);
|
||||
TResult visitIfExpr(TContext context, If expr);
|
||||
TResult visitVariableExpr(TContext context, Variable expr);
|
||||
TResult visitListExpr(TContext context, List expr);
|
||||
TResult visitVariantExpr(TContext context, Variant expr);
|
||||
TResult visitRecordExpr(TContext context, Record expr);
|
||||
TResult visitSelectorExpr(TContext context, Selector expr);
|
||||
TResult visitIndexerExpr(TContext context, Indexer expr);
|
||||
TResult visitCallExpr(TContext context, Call expr);
|
||||
TResult visitLetExpr(TContext context, Let expr);
|
||||
TResult visitWhenExpr(TContext context, When 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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);
|
||||
}
|
||||
}
|
||||
|
146
Interpreter.cs
146
Interpreter.cs
@ -6,8 +6,6 @@ using AST = Finn.AST;
|
||||
|
||||
namespace Finn;
|
||||
|
||||
public class Interpreter : AST.IExprVisitor<object>
|
||||
{
|
||||
public class RuntimeError : Exception
|
||||
{
|
||||
public readonly Token Token;
|
||||
@ -18,6 +16,55 @@ public class Interpreter : AST.IExprVisitor<object>
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
var aType = a.GetType();
|
||||
@ -156,7 +203,7 @@ public class Interpreter : AST.IExprVisitor<object>
|
||||
{
|
||||
try
|
||||
{
|
||||
var value = evaluate(expression);
|
||||
var value = evaluate(new Env(), expression);
|
||||
Console.WriteLine(value);
|
||||
}
|
||||
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)
|
||||
@ -209,10 +256,10 @@ public class Interpreter : AST.IExprVisitor<object>
|
||||
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 right = evaluate(expr.Right);
|
||||
var left = evaluate(env, expr.Left);
|
||||
var right = evaluate(env, expr.Right);
|
||||
|
||||
switch (expr.Op.type)
|
||||
{
|
||||
@ -265,42 +312,42 @@ public class Interpreter : AST.IExprVisitor<object>
|
||||
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();
|
||||
}
|
||||
|
||||
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.
|
||||
var vb = checkBoolOperand(new Token(TokenType.If, "if", null, 1), cond);
|
||||
if (vb == Variant.True)
|
||||
{
|
||||
return evaluate(expr.Then);
|
||||
return evaluate(env, expr.Then);
|
||||
}
|
||||
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
|
||||
var tok = new Token(TokenType.LBracket, "[", null, 1);
|
||||
var left = checkListOperand(tok, evaluate(expr.Left));
|
||||
var index = checkNumberOperand(tok, evaluate(expr.Index));
|
||||
var left = checkListOperand(tok, evaluate(env, expr.Left));
|
||||
var index = checkNumberOperand(tok, evaluate(env, expr.Index));
|
||||
try
|
||||
{
|
||||
var item = left[index];
|
||||
@ -309,19 +356,42 @@ public class Interpreter : AST.IExprVisitor<object>
|
||||
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
|
||||
var tok = new Token(TokenType.LBracket, "[", null, 1);
|
||||
List l = List.Empty;
|
||||
foreach (var itemExpr in expr.Elements)
|
||||
{
|
||||
var item = evaluate(itemExpr);
|
||||
var item = evaluate(env, itemExpr);
|
||||
if (!l.IsEmpty)
|
||||
{
|
||||
try { checkTypesEqual(l[0], item); }
|
||||
@ -332,19 +402,19 @@ public class Interpreter : AST.IExprVisitor<object>
|
||||
return l;
|
||||
}
|
||||
|
||||
public object visitLiteralExpr(AST.Literal expr)
|
||||
public object visitLiteralExpr(Env env, AST.Literal expr)
|
||||
{
|
||||
return expr.Value;
|
||||
}
|
||||
|
||||
public object visitRecordExpr(AST.Record expr)
|
||||
public object visitRecordExpr(Env env, AST.Record expr)
|
||||
{
|
||||
// TODO use real token
|
||||
Token tok = new Token(TokenType.LBrace, "{", null, 1);
|
||||
Record rec = Record.Empty;
|
||||
if (expr.Base != null)
|
||||
{
|
||||
var baseRecValue = evaluate(expr.Base.Value);
|
||||
var baseRecValue = evaluate(env, expr.Base.Value);
|
||||
if (baseRecValue is not 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();
|
||||
try
|
||||
{
|
||||
baseRec = baseRec.Update(label, evaluate(update.Value));
|
||||
baseRec = baseRec.Update(label, evaluate(env, update.Value));
|
||||
}
|
||||
catch
|
||||
{
|
||||
@ -386,15 +456,15 @@ public class Interpreter : AST.IExprVisitor<object>
|
||||
}
|
||||
extLabels.Add(label);
|
||||
if (extension.Value == null) throw new NotImplementedException();
|
||||
rec = rec.Extend(label, evaluate(extension.Value));
|
||||
rec = rec.Extend(label, evaluate(env, extension.Value));
|
||||
}
|
||||
|
||||
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.
|
||||
var tok = new Token(TokenType.Period, ".", null, 1);
|
||||
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);
|
||||
return evaluate(expr.Right);
|
||||
evaluate(env, expr.Left);
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
public object visitWhenExpr(AST.When expr)
|
||||
public object visitWhenExpr(Env env, AST.When expr)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
28
Pattern.g.cs
28
Pattern.g.cs
@ -8,39 +8,39 @@
|
||||
namespace Finn.AST;
|
||||
|
||||
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> {
|
||||
T visitSimplePatternPattern(SimplePattern pattern);
|
||||
T visitVariantPatternPattern(VariantPattern pattern);
|
||||
T visitFieldPatternPattern(FieldPattern pattern);
|
||||
T visitRecordPatternPattern(RecordPattern pattern);
|
||||
public interface IPatternVisitor<TContext, TResult> {
|
||||
TResult visitSimplePatternPattern(TContext context, SimplePattern pattern);
|
||||
TResult visitVariantPatternPattern(TContext context, VariantPattern pattern);
|
||||
TResult visitFieldPatternPattern(TContext context, FieldPattern pattern);
|
||||
TResult visitRecordPatternPattern(TContext context, RecordPattern 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 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 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 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}]");
|
||||
hadRuntimeError = true;
|
||||
|
@ -64,10 +64,10 @@ let patternTypes =
|
||||
let visitorMethod baseName t = $"visit{t.Name}{baseName}"
|
||||
|
||||
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
|
||||
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")
|
||||
|
||||
@ -86,9 +86,9 @@ let renderType (sw: System.IO.StreamWriter) baseName t =
|
||||
{{\n"
|
||||
|
||||
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\treturn visitor.{visitorMethod baseName t}(this);
|
||||
\t\treturn visitor.{visitorMethod baseName t}(context, this);
|
||||
\t}}\n"
|
||||
|
||||
sw.Write("}\n")
|
||||
@ -108,7 +108,7 @@ let renderAST outputDir baseName types =
|
||||
namespace Finn.AST;
|
||||
|
||||
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"
|
||||
|
||||
renderIVisitor sw baseName types
|
||||
|
Loading…
Reference in New Issue
Block a user