Implemented closure and therefore recursion
This commit is contained in:
parent
ab38d85465
commit
352fa9616e
@ -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);
|
||||||
|
@ -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))
|
||||||
{
|
{
|
||||||
|
2
TODO.txt
2
TODO.txt
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user