From 47e2dadb8d4b0c79a674962e1496ce1c04a86b63 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Fri, 16 Nov 2018 14:46:12 +0100 Subject: [PATCH] Way better handling of calling functions from CSHarp --- Upsilon/BaseTypes/Number/NumberLong.cs | 2 ++ Upsilon/Binder/Binder.cs | 10 ++++++---- .../BoundStatements/BoundFunctionStatement.cs | 2 +- Upsilon/Binder/BoundStatements/BoundScript.cs | 6 ++++-- .../BoundStatements/UnboundFunctionStatement.cs | 9 ++------- Upsilon/Evaluator/Evaluator.cs | 13 +++++++++++++ Upsilon/Evaluator/Script.cs | 13 ++++++++++++- UpsilonTests/FunctionTests.cs | 15 +++++++++++++++ 8 files changed, 55 insertions(+), 15 deletions(-) diff --git a/Upsilon/BaseTypes/Number/NumberLong.cs b/Upsilon/BaseTypes/Number/NumberLong.cs index 43fb20f..413a0a2 100644 --- a/Upsilon/BaseTypes/Number/NumberLong.cs +++ b/Upsilon/BaseTypes/Number/NumberLong.cs @@ -25,6 +25,8 @@ namespace Upsilon.BaseTypes.Number public static implicit operator long(NumberLong n) { + if (n == null) + return 0; return n.Value; } } diff --git a/Upsilon/Binder/Binder.cs b/Upsilon/Binder/Binder.cs index 8d7d7ac..4e29cfb 100644 --- a/Upsilon/Binder/Binder.cs +++ b/Upsilon/Binder/Binder.cs @@ -38,7 +38,7 @@ namespace Upsilon.Binder unboundFunctionStatement.Key.IsBound = true; } _unboundFunctions = new Dictionary(); - return new BoundScript(bound); + return new BoundScript((BoundBlockStatement) bound); } private BoundStatement BindStatement(StatementSyntax s) @@ -173,8 +173,9 @@ namespace Upsilon.Binder _scope.SetVariable(functionVariable); } - _unboundFunctions[function].Block = - (BoundBlockStatement) BindBlockStatement(_unboundFunctions[function].UnboundBlock); + var unboundFunctionStatement = _unboundFunctions[function]; + unboundFunctionStatement.Block = + (BoundBlockStatement) BindBlockStatement(unboundFunctionStatement.UnboundBlock); _scope = _scope.ParentScope; function.IsBound = true; _unboundFunctions.Remove(function); @@ -330,7 +331,8 @@ namespace Upsilon.Binder var block = BindBlockStatement(e.Block); _scope = _scope.ParentScope; ((FunctionVariableSymbol) variable).IsBound = true; - return new BoundFunctionStatement(variable, parameters.ToImmutable(), (BoundBlockStatement) block); + var func = new BoundFunctionStatement(variable, parameters.ToImmutable(), (BoundBlockStatement) block); + return func; } else { diff --git a/Upsilon/Binder/BoundStatements/BoundFunctionStatement.cs b/Upsilon/Binder/BoundStatements/BoundFunctionStatement.cs index a6854c8..27529ea 100644 --- a/Upsilon/Binder/BoundStatements/BoundFunctionStatement.cs +++ b/Upsilon/Binder/BoundStatements/BoundFunctionStatement.cs @@ -6,7 +6,7 @@ namespace Upsilon.Binder { public VariableSymbol Identifier { get; } public ImmutableArray Parameters { get; } - public BoundBlockStatement Block { get; } + public BoundBlockStatement Block { get; set; } public BoundFunctionStatement(VariableSymbol identifier, ImmutableArray parameters, BoundBlockStatement block) diff --git a/Upsilon/Binder/BoundStatements/BoundScript.cs b/Upsilon/Binder/BoundStatements/BoundScript.cs index 9132563..ecb3e81 100644 --- a/Upsilon/Binder/BoundStatements/BoundScript.cs +++ b/Upsilon/Binder/BoundStatements/BoundScript.cs @@ -1,14 +1,16 @@ +using System.Collections.Generic; + namespace Upsilon.Binder { public class BoundScript : BoundStatement { - public BoundScript(BoundStatement statement) + public BoundScript(BoundBlockStatement statement) { Statement = statement; } public override BoundKind Kind => BoundKind.BoundScript; - public BoundStatement Statement { get; } + public BoundBlockStatement Statement { get; } } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundStatements/UnboundFunctionStatement.cs b/Upsilon/Binder/BoundStatements/UnboundFunctionStatement.cs index 8c335e8..46bca44 100644 --- a/Upsilon/Binder/BoundStatements/UnboundFunctionStatement.cs +++ b/Upsilon/Binder/BoundStatements/UnboundFunctionStatement.cs @@ -3,21 +3,16 @@ using Upsilon.Parser; namespace Upsilon.Binder { - public class UnboundFunctionStatement : BoundStatement + public class UnboundFunctionStatement : BoundFunctionStatement { public UnboundFunctionStatement(VariableSymbol identifier, ImmutableArray parameters, - BlockStatementSyntax unboundBlock) + BlockStatementSyntax unboundBlock) : base(identifier, parameters, null) { - Identifier = identifier; - Parameters = parameters; UnboundBlock = unboundBlock; } public override BoundKind Kind => BoundKind.BoundPromise; - public VariableSymbol Identifier { get; } - public ImmutableArray Parameters { get; } public BlockStatementSyntax UnboundBlock { get; } - public BoundBlockStatement Block { get; set; } } } \ No newline at end of file diff --git a/Upsilon/Evaluator/Evaluator.cs b/Upsilon/Evaluator/Evaluator.cs index ad97b36..00458d4 100644 --- a/Upsilon/Evaluator/Evaluator.cs +++ b/Upsilon/Evaluator/Evaluator.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using Upsilon.BaseTypes; using Upsilon.BaseTypes.Number; using Upsilon.Binder; +using Type = Upsilon.BaseTypes.Type; namespace Upsilon.Evaluator { @@ -34,6 +35,18 @@ namespace Upsilon.Evaluator 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) { switch (b.Kind) diff --git a/Upsilon/Evaluator/Script.cs b/Upsilon/Evaluator/Script.cs index b80cff7..b3b0afb 100644 --- a/Upsilon/Evaluator/Script.cs +++ b/Upsilon/Evaluator/Script.cs @@ -12,6 +12,7 @@ namespace Upsilon.Evaluator private SourceText ScriptString { get; } private Evaluator Evaluator { get; } private readonly BlockStatementSyntax _parsed; + private BoundScript _bound; public Diagnostics Diagnostics { get; } private Binder.Binder Binder { get; } public EvaluationScope Scope { get; } @@ -30,7 +31,7 @@ namespace Upsilon.Evaluator public BoundScript Bind() { - return Binder.BindScript(_parsed); + return _bound ?? (_bound = Binder.BindScript(_parsed)); } public object Evaluate() @@ -38,11 +39,21 @@ namespace Upsilon.Evaluator return Evaluator.Evaluate(Bind()); } + public object EvaluateFunction(string functionName) + { + return Evaluator.Evaluate(Bind(), functionName); + } + public T Evaluate() where T : LuaType { return (T)Evaluator.Evaluate(Bind()); } + public T EvaluateFunction(string functionName) where T : LuaType + { + return (T)Evaluator.Evaluate(Bind(), functionName); + } + public string PrettyPrintSyntaxTree() { return _parsed.Print(); diff --git a/UpsilonTests/FunctionTests.cs b/UpsilonTests/FunctionTests.cs index 97a1c14..55a1bb0 100644 --- a/UpsilonTests/FunctionTests.cs +++ b/UpsilonTests/FunctionTests.cs @@ -151,5 +151,20 @@ a = 87 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("testFunc"); + Assert.Empty(script.Diagnostics.Messages); + Assert.Equal(100, (long)result); + } + } } \ No newline at end of file