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 AST = Finn.AST;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Net; using System.Net;
using Finn.AST;
namespace Finn; namespace Finn;
@ -80,14 +81,6 @@ public record NativeFunction(Func<object[], object> Function) : Callable
public override string ToString() => "<native func>"; 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> public class Interpreter : AST.IExprVisitor<Env, object>
{ {
private class PatternMismatchException : Exception 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() public Interpreter()
{ {
globals["clock"] = new NativeFunction((args) => Globals["clock"] = new NativeFunction((args) =>
{ {
return (double)DateTimeOffset.Now.ToUnixTimeSeconds(); return (double)DateTimeOffset.Now.ToUnixTimeSeconds();
}); });
@ -313,7 +320,7 @@ public class Interpreter : AST.IExprVisitor<Env, object>
{ {
try try
{ {
var value = evaluate(globals, expression); var value = evaluate(Globals, expression);
Console.WriteLine(value); Console.WriteLine(value);
} }
catch (RuntimeError err) catch (RuntimeError err)
@ -475,14 +482,14 @@ public class Interpreter : AST.IExprVisitor<Env, object>
catch { return new Variant("nothing", null); } 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); var newEnv = new Env(env);
foreach (var binding in expr.Bindings) foreach (var binding in expr.Bindings)
{ {
switch (binding) switch (binding)
{ {
case AST.VarBinding(var pattern, var valueExpr): case VarBinding(var pattern, var valueExpr):
var value = evaluate(env, valueExpr); var value = evaluate(env, valueExpr);
try try
{ {
@ -496,8 +503,11 @@ public class Interpreter : AST.IExprVisitor<Env, object>
throw new RuntimeError(start, e.Message); throw new RuntimeError(start, e.Message);
} }
break; break;
case FuncBinding fb:
newEnv[(string)fb.Name.Literal!] = new FinnFunction(fb, newEnv);
break;
default: default:
throw new NotImplementedException("TODO function bindings"); throw new Exception("wtf there are no other binding types");
} }
} }
return evaluate(newEnv, expr.Body); return evaluate(newEnv, expr.Body);

View File

@ -237,8 +237,7 @@ class Parser
} }
var letToken = previous(); var letToken = previous();
List<Binding> bindings = new List<Binding>(); List<Binding> bindings = new List<Binding> { parseBinding() };
bindings.Add(parseBinding());
while (match(TokenType.And)) while (match(TokenType.And))
{ {
bindings.Add(parseBinding()); bindings.Add(parseBinding());
@ -252,7 +251,7 @@ class Parser
Pattern p = pattern(); Pattern p = pattern();
switch (p) 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>(); List<Pattern> funcParams = new List<Pattern>();
while (!check(TokenType.RParen)) 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 Figure out multiple-binding let-expr semantics
Inject error handling into parser and scanner Inject error handling into parser and scanner
Think about a way to hide record fields Think about a way to hide record fields