Wire up resolver to interpreter

This commit is contained in:
Brandon Dyck 2023-10-04 17:13:48 -06:00
parent 5168890ea0
commit 6e88a41b72
4 changed files with 283 additions and 241 deletions

View File

@ -64,6 +64,20 @@ public class Env
} }
} }
} }
public Env Ancestor(int distance)
{
Env? curr = this;
for (int i = 0; i < distance; i++)
{
curr = curr.enclosing;
if (curr is null)
{
throw new IndexOutOfRangeException();
}
}
return curr;
}
} }
public interface Callable public interface Callable
@ -302,14 +316,16 @@ public class Interpreter : AST.IExprVisitor<Env, object>
binding.Params[i].accept((arguments[i], env), new PatternBinder()); binding.Params[i].accept((arguments[i], env), new PatternBinder());
} }
return interpreter.evaluate(env, binding.Value); return interpreter.evaluate(env, binding.Value);
// throw new NotImplementedException();
} }
} }
protected internal readonly Env Globals = new Env(); protected internal readonly Env Globals = new Env();
private readonly Resolver Resolver;
public Interpreter() public Interpreter(Resolver resolver)
{ {
Resolver = resolver;
Globals["clock"] = new NativeFunction((args) => Globals["clock"] = new NativeFunction((args) =>
{ {
return (double)DateTimeOffset.Now.ToUnixTimeSeconds(); return (double)DateTimeOffset.Now.ToUnixTimeSeconds();
@ -413,14 +429,14 @@ public class Interpreter : AST.IExprVisitor<Env, object>
case TokenType.BangEqual: case TokenType.BangEqual:
return Variant.FromBool((left, right) switch return Variant.FromBool((left, right) switch
{ {
(String l, String r) => l != r, (string l, string r) => l != r,
(double l, double r) => l != r, (double l, double r) => l != r,
_ => throw new ArgumentException(), _ => throw new ArgumentException(),
}); });
case TokenType.DoubleEqual: case TokenType.DoubleEqual:
return Variant.FromBool((left, right) switch return Variant.FromBool((left, right) switch
{ {
(String l, String r) => l == r, (string l, string r) => l == r,
(double l, double r) => l == r, (double l, double r) => l == r,
_ => throw new ArgumentException(), _ => throw new ArgumentException(),
}); });
@ -453,7 +469,15 @@ public class Interpreter : AST.IExprVisitor<Env, object>
public object visitVariableExpr(Env env, AST.Variable expr) public object visitVariableExpr(Env env, AST.Variable expr)
{ {
return env[expr.Value]; var name = (string)expr.Value.Literal!;
if (Resolver.TryResolve(expr, out var distance))
{
return env.Ancestor(distance)[expr.Value];
}
else
{
return Globals[expr.Value];
}
} }
public object visitIfExpr(Env env, AST.If expr) public object visitIfExpr(Env env, AST.If expr)
@ -499,9 +523,11 @@ public class Interpreter : AST.IExprVisitor<Env, object>
} }
catch (Exception e) catch (Exception e)
{ {
var start = e is PatternMismatchException ? var start = e switch
((PatternMismatchException)e).Start : {
binding.Start; PatternMismatchException pme => pme.Start,
_ => binding.Start,
};
throw new RuntimeError(start, e.Message); throw new RuntimeError(start, e.Message);
} }
break; break;

View File

@ -7,7 +7,8 @@ namespace Finn;
class Program class Program
{ {
private static readonly Interpreter interpreter = new Interpreter(); private static readonly Resolver resolver = new Resolver();
private static readonly Interpreter interpreter = new Interpreter(resolver);
static bool hadError = false; static bool hadError = false;
static bool hadRuntimeError = true; static bool hadRuntimeError = true;
@ -41,16 +42,8 @@ class Program
{ {
var scanner = new Scanner(src); var scanner = new Scanner(src);
List<Token> tokens = scanner.scanTokens(); List<Token> tokens = scanner.scanTokens();
// Console.WriteLine("TOKENS\n=======");
// foreach (var token in tokens)
// {
// Console.WriteLine(token);
// }
Parser parser = new Parser(tokens); Parser parser = new Parser(tokens);
Expr? expression = parser.parse(); Expr? expression = parser.parse();
// Console.WriteLine("\nAST\n=======");
// Console.WriteLine(expression);
// Console.WriteLine();
if (hadError) if (hadError)
{ {
@ -58,6 +51,13 @@ class Program
return; return;
} }
resolver.Add(expression!);
if (hadError)
{
hadError = false;
return;
}
interpreter.Interpret(expression!); interpreter.Interpret(expression!);
} }

View File

@ -8,7 +8,23 @@ using ScopeStack = System.Collections.Immutable.ImmutableStack<System.Collection
using Resolutions = System.Collections.Immutable.ImmutableDictionary<Finn.AST.Expr, int>; using Resolutions = System.Collections.Immutable.ImmutableDictionary<Finn.AST.Expr, int>;
using System.Collections.Generic; using System.Collections.Generic;
class Resolver : IExprVisitor<ScopeStack, Resolutions> public class Resolver
{
private static readonly Resolutions EmptyResolutions = Resolutions.Empty.WithComparers(ReferenceEqualityComparer.Instance);
private Resolutions Resolutions = EmptyResolutions;
public bool TryResolve(Expr expr, out int distance)
{
return Resolutions.TryGetValue(expr, out distance);
}
public void Add(Expr expr)
{
var newResolutions = ResolverBuilder.Instance.Resolve(ScopeStack.Empty, expr);
Resolutions = Resolutions.AddRange(newResolutions);
}
private class ResolverBuilder : IExprVisitor<ScopeStack, Resolutions>
{ {
private class NameCollection private class NameCollection
{ {
@ -74,14 +90,13 @@ class Resolver : IExprVisitor<ScopeStack, Resolutions>
} }
} }
private static readonly Resolutions EmptyResolutions = Resolutions.Empty.WithComparers(ReferenceEqualityComparer.Instance); public static readonly ResolverBuilder Instance = new ResolverBuilder();
public static readonly Resolver Instance = new Resolver();
private Resolver() { } private ResolverBuilder() { }
private static Resolutions AddRange(Resolutions r1, Resolutions r2) => r1.AddRange(r2); private static Resolutions AddRange(Resolutions r1, Resolutions r2) => r1.AddRange(r2);
private Resolutions Resolve(ScopeStack scopes, Expr expr) public Resolutions Resolve(ScopeStack scopes, Expr expr)
{ {
return expr.accept(scopes, this); return expr.accept(scopes, this);
} }
@ -255,3 +270,5 @@ class Resolver : IExprVisitor<ScopeStack, Resolutions>
} }
} }
} }
}

View File

@ -1,4 +1,3 @@
Wire up resolver to interpreter
Move let-expr resolvability check to Resolver Move let-expr resolvability check to Resolver
Remove dynamic type checks (checkXXX methods) from interpreter Remove dynamic type checks (checkXXX methods) from interpreter
Use numerical indices in resolutions Use numerical indices in resolutions