Way better handling of calling functions from CSHarp

This commit is contained in:
Deukhoofd 2018-11-16 14:46:12 +01:00
parent 62ad100aee
commit 47e2dadb8d
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
8 changed files with 55 additions and 15 deletions

View File

@ -25,6 +25,8 @@ namespace Upsilon.BaseTypes.Number
public static implicit operator long(NumberLong n) public static implicit operator long(NumberLong n)
{ {
if (n == null)
return 0;
return n.Value; return n.Value;
} }
} }

View File

@ -38,7 +38,7 @@ namespace Upsilon.Binder
unboundFunctionStatement.Key.IsBound = true; unboundFunctionStatement.Key.IsBound = true;
} }
_unboundFunctions = new Dictionary<FunctionVariableSymbol, UnboundFunctionStatement>(); _unboundFunctions = new Dictionary<FunctionVariableSymbol, UnboundFunctionStatement>();
return new BoundScript(bound); return new BoundScript((BoundBlockStatement) bound);
} }
private BoundStatement BindStatement(StatementSyntax s) private BoundStatement BindStatement(StatementSyntax s)
@ -173,8 +173,9 @@ namespace Upsilon.Binder
_scope.SetVariable(functionVariable); _scope.SetVariable(functionVariable);
} }
_unboundFunctions[function].Block = var unboundFunctionStatement = _unboundFunctions[function];
(BoundBlockStatement) BindBlockStatement(_unboundFunctions[function].UnboundBlock); unboundFunctionStatement.Block =
(BoundBlockStatement) BindBlockStatement(unboundFunctionStatement.UnboundBlock);
_scope = _scope.ParentScope; _scope = _scope.ParentScope;
function.IsBound = true; function.IsBound = true;
_unboundFunctions.Remove(function); _unboundFunctions.Remove(function);
@ -330,7 +331,8 @@ namespace Upsilon.Binder
var block = BindBlockStatement(e.Block); var block = BindBlockStatement(e.Block);
_scope = _scope.ParentScope; _scope = _scope.ParentScope;
((FunctionVariableSymbol) variable).IsBound = true; ((FunctionVariableSymbol) variable).IsBound = true;
return new BoundFunctionStatement(variable, parameters.ToImmutable(), (BoundBlockStatement) block); var func = new BoundFunctionStatement(variable, parameters.ToImmutable(), (BoundBlockStatement) block);
return func;
} }
else else
{ {

View File

@ -6,7 +6,7 @@ namespace Upsilon.Binder
{ {
public VariableSymbol Identifier { get; } public VariableSymbol Identifier { get; }
public ImmutableArray<VariableSymbol> Parameters { get; } public ImmutableArray<VariableSymbol> Parameters { get; }
public BoundBlockStatement Block { get; } public BoundBlockStatement Block { get; set; }
public BoundFunctionStatement(VariableSymbol identifier, ImmutableArray<VariableSymbol> parameters, public BoundFunctionStatement(VariableSymbol identifier, ImmutableArray<VariableSymbol> parameters,
BoundBlockStatement block) BoundBlockStatement block)

View File

@ -1,14 +1,16 @@
using System.Collections.Generic;
namespace Upsilon.Binder namespace Upsilon.Binder
{ {
public class BoundScript : BoundStatement public class BoundScript : BoundStatement
{ {
public BoundScript(BoundStatement statement) public BoundScript(BoundBlockStatement statement)
{ {
Statement = statement; Statement = statement;
} }
public override BoundKind Kind => BoundKind.BoundScript; public override BoundKind Kind => BoundKind.BoundScript;
public BoundStatement Statement { get; } public BoundBlockStatement Statement { get; }
} }
} }

View File

@ -3,21 +3,16 @@ using Upsilon.Parser;
namespace Upsilon.Binder namespace Upsilon.Binder
{ {
public class UnboundFunctionStatement : BoundStatement public class UnboundFunctionStatement : BoundFunctionStatement
{ {
public UnboundFunctionStatement(VariableSymbol identifier, ImmutableArray<VariableSymbol> parameters, public UnboundFunctionStatement(VariableSymbol identifier, ImmutableArray<VariableSymbol> parameters,
BlockStatementSyntax unboundBlock) BlockStatementSyntax unboundBlock) : base(identifier, parameters, null)
{ {
Identifier = identifier;
Parameters = parameters;
UnboundBlock = unboundBlock; UnboundBlock = unboundBlock;
} }
public override BoundKind Kind => BoundKind.BoundPromise; public override BoundKind Kind => BoundKind.BoundPromise;
public VariableSymbol Identifier { get; }
public ImmutableArray<VariableSymbol> Parameters { get; }
public BlockStatementSyntax UnboundBlock { get; } public BlockStatementSyntax UnboundBlock { get; }
public BoundBlockStatement Block { get; set; }
} }
} }

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using Upsilon.BaseTypes; using Upsilon.BaseTypes;
using Upsilon.BaseTypes.Number; using Upsilon.BaseTypes.Number;
using Upsilon.Binder; using Upsilon.Binder;
using Type = Upsilon.BaseTypes.Type;
namespace Upsilon.Evaluator namespace Upsilon.Evaluator
{ {
@ -34,6 +35,18 @@ namespace Upsilon.Evaluator
return _returnValue; return _returnValue;
} }
public LuaType Evaluate(BoundScript e, string functionName)
{
Evaluate(e.Statement);
if (!Scope.TryGet(functionName, out var statement) || statement.Type != Type.Function)
{
throw new ArgumentException(($"Function '{functionName}' could not be found"));
}
var innerEvaluator = new Evaluator(_diagnostics, Scope);
var result = innerEvaluator.Evaluate(((LuaFunction)statement).Block);
return result;
}
private LuaType Evaluate(BoundNode b) private LuaType Evaluate(BoundNode b)
{ {
switch (b.Kind) switch (b.Kind)

View File

@ -12,6 +12,7 @@ namespace Upsilon.Evaluator
private SourceText ScriptString { get; } private SourceText ScriptString { get; }
private Evaluator Evaluator { get; } private Evaluator Evaluator { get; }
private readonly BlockStatementSyntax _parsed; private readonly BlockStatementSyntax _parsed;
private BoundScript _bound;
public Diagnostics Diagnostics { get; } public Diagnostics Diagnostics { get; }
private Binder.Binder Binder { get; } private Binder.Binder Binder { get; }
public EvaluationScope Scope { get; } public EvaluationScope Scope { get; }
@ -30,7 +31,7 @@ namespace Upsilon.Evaluator
public BoundScript Bind() public BoundScript Bind()
{ {
return Binder.BindScript(_parsed); return _bound ?? (_bound = Binder.BindScript(_parsed));
} }
public object Evaluate() public object Evaluate()
@ -38,11 +39,21 @@ namespace Upsilon.Evaluator
return Evaluator.Evaluate(Bind()); return Evaluator.Evaluate(Bind());
} }
public object EvaluateFunction(string functionName)
{
return Evaluator.Evaluate(Bind(), functionName);
}
public T Evaluate<T>() where T : LuaType public T Evaluate<T>() where T : LuaType
{ {
return (T)Evaluator.Evaluate(Bind()); return (T)Evaluator.Evaluate(Bind());
} }
public T EvaluateFunction<T>(string functionName) where T : LuaType
{
return (T)Evaluator.Evaluate(Bind(), functionName);
}
public string PrettyPrintSyntaxTree() public string PrettyPrintSyntaxTree()
{ {
return _parsed.Print(); return _parsed.Print();

View File

@ -151,5 +151,20 @@ a = 87
Assert.Equal(60, (long)(NumberLong)result); Assert.Equal(60, (long)(NumberLong)result);
} }
[Fact]
public void ReturnFromCSharpCall()
{
const string input = @"
function testFunc ()
return 100
end
";
var script = new Script(input);
Assert.Empty(script.Diagnostics.Messages);
var result = script.EvaluateFunction<NumberLong>("testFunc");
Assert.Empty(script.Diagnostics.Messages);
Assert.Equal(100, (long)result);
}
} }
} }