Implemented closure and therefore recursion

This commit is contained in:
Brandon Dyck 2023-09-27 22:34:38 -06:00
parent ab38d85465
commit 352fa9616e
3 changed files with 27 additions and 18 deletions

View File

@ -6,6 +6,7 @@ using System.Collections.Immutable;
using AST = Finn.AST;
using System.Runtime.CompilerServices;
using System.Net;
using Finn.AST;
namespace Finn;
@ -80,14 +81,6 @@ public record NativeFunction(Func<object[], object> Function) : Callable
public override string ToString() => "<native func>";
}
public class UserFunction : Callable
{
public object Call(Interpreter interpreter, object[] arguments)
{
throw new NotImplementedException();
}
}
public class Interpreter : AST.IExprVisitor<Env, object>
{
private class PatternMismatchException : Exception
@ -299,11 +292,25 @@ public class Interpreter : AST.IExprVisitor<Env, object>
}
}
private readonly Env globals = new Env();
public record FinnFunction(FuncBinding binding, Env closure) : Callable
{
public object Call(Interpreter interpreter, object[] arguments)
{
Env env = new Env(closure);
for (int i = 0; i < binding.Params.Length; i++)
{
binding.Params[i].accept((arguments[i], env), new PatternBinder());
}
return interpreter.evaluate(env, binding.Value);
// throw new NotImplementedException();
}
}
protected internal readonly Env Globals = new Env();
public Interpreter()
{
globals["clock"] = new NativeFunction((args) =>
Globals["clock"] = new NativeFunction((args) =>
{
return (double)DateTimeOffset.Now.ToUnixTimeSeconds();
});
@ -313,7 +320,7 @@ public class Interpreter : AST.IExprVisitor<Env, object>
{
try
{
var value = evaluate(globals, expression);
var value = evaluate(Globals, expression);
Console.WriteLine(value);
}
catch (RuntimeError err)
@ -475,14 +482,14 @@ public class Interpreter : AST.IExprVisitor<Env, object>
catch { return new Variant("nothing", null); }
}
public object visitLetExpr(Env env, AST.Let expr)
public object visitLetExpr(Env env, Let expr)
{
var newEnv = new Env(env);
foreach (var binding in expr.Bindings)
{
switch (binding)
{
case AST.VarBinding(var pattern, var valueExpr):
case VarBinding(var pattern, var valueExpr):
var value = evaluate(env, valueExpr);
try
{
@ -496,8 +503,11 @@ public class Interpreter : AST.IExprVisitor<Env, object>
throw new RuntimeError(start, e.Message);
}
break;
case FuncBinding fb:
newEnv[(string)fb.Name.Literal!] = new FinnFunction(fb, newEnv);
break;
default:
throw new NotImplementedException("TODO function bindings");
throw new Exception("wtf there are no other binding types");
}
}
return evaluate(newEnv, expr.Body);

View File

@ -237,8 +237,7 @@ class Parser
}
var letToken = previous();
List<Binding> bindings = new List<Binding>();
bindings.Add(parseBinding());
List<Binding> bindings = new List<Binding> { parseBinding() };
while (match(TokenType.And))
{
bindings.Add(parseBinding());
@ -252,7 +251,7 @@ class Parser
Pattern p = pattern();
switch (p)
{
case (SimplePattern(var funcName)) when funcName != null && match(TokenType.LParen):
case SimplePattern(var funcName) when funcName != null && match(TokenType.LParen):
List<Pattern> funcParams = new List<Pattern>();
while (!check(TokenType.RParen))
{

View File

@ -1,4 +1,4 @@
Implement Finn functions
Allow variable defs to reference earlier ones in same binding list
Figure out multiple-binding let-expr semantics
Inject error handling into parser and scanner
Think about a way to hide record fields