From c63df3c94198d012036294348ee60a436c171eb5 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sat, 24 Nov 2018 13:35:40 +0100 Subject: [PATCH] Work on standard libraries. - Allows Standard Libraries to work with actual luatypes, to prevent constant back and forth casting - adds ipairs function, doesn't do anything except maintain compatibility with lua - several tests --- Upsilon/BaseTypes/ScriptFunction.cs | 28 ++++++++++++++--- Upsilon/BaseTypes/TypeConversion.cs | 2 +- .../BaseTypes/UserData/DictionaryUserData.cs | 2 +- Upsilon/BaseTypes/UserData/ListUserData.cs | 2 +- Upsilon/BaseTypes/UserData/UserDataMethod.cs | 2 ++ Upsilon/BaseTypes/UserData/UserDataType.cs | 10 +++--- Upsilon/Evaluator/Evaluator.cs | 8 ++--- Upsilon/Evaluator/Script.cs | 4 +-- Upsilon/StandardLibraries/BasicFunctions.cs | 31 ++++++++----------- Upsilon/StandardLibraries/LuaLibrary.cs | 4 +-- ...StandardLibraryScriptFunctionAttribute.cs} | 4 +-- Upsilon/StandardLibraries/StaticScope.cs | 2 +- .../BasicFunctionsTests.cs | 31 +++++++++++++++++++ 13 files changed, 88 insertions(+), 42 deletions(-) rename Upsilon/StandardLibraries/{LuaFunctionAttribute.cs => StandardLibraryScriptFunctionAttribute.cs} (63%) diff --git a/Upsilon/BaseTypes/ScriptFunction.cs b/Upsilon/BaseTypes/ScriptFunction.cs index a44db2a..1180776 100644 --- a/Upsilon/BaseTypes/ScriptFunction.cs +++ b/Upsilon/BaseTypes/ScriptFunction.cs @@ -1,3 +1,6 @@ +using System; +using System.Collections; +using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Reflection; @@ -53,20 +56,32 @@ namespace Upsilon.BaseTypes internal class ScriptMethodInfoFunction : ScriptFunction { - public ScriptMethodInfoFunction(UserDataMethod method, object o) + public ScriptMethodInfoFunction(UserDataMethod method, object o, bool directTypeManipulation) { _method = method; _object = o; + _directTypeManipulation = directTypeManipulation; } private readonly UserDataMethod _method; private readonly object _object; + private readonly bool _directTypeManipulation; public override ScriptType Run(Diagnostics diagnostics, ScriptType[] variables) { - var types = variables.Select(x => x.GetCSharpType()); - var method = _method.GetMethod(types.ToArray()); - var objects = variables.Select(x => x.ToCSharpObject()).ToList(); + var types = _directTypeManipulation + ? variables.Select(x => x.GetType()).ToArray() + : variables.Select(x => x.GetCSharpType()).ToArray(); + var method = _method.GetMethod(types); + if (method == null) + { + throw new Exception( + $"No valid function found on type '{_object.GetType()}' with name '{_method.Name}' " + + $"and parameter types: {string.Join(", ", types.Select(x => $"'{x.Name}'"))}"); + } + var objects = _directTypeManipulation + ? variables.Select(x => (object) x).ToList() + : variables.Select(x => x.ToCSharpObject()).ToList(); var pars = method.GetParameters(); if (pars.Length != objects.Count) { @@ -78,7 +93,10 @@ namespace Upsilon.BaseTypes try { - return method.Invoke(_object, objects.ToArray()).ToLuaType(); + var result = method.Invoke(_object, objects.ToArray()); + if (_directTypeManipulation) + return (ScriptType)result; + return result.ToScriptType(); } catch (TargetInvocationException e) { diff --git a/Upsilon/BaseTypes/TypeConversion.cs b/Upsilon/BaseTypes/TypeConversion.cs index 9adb9e4..e2cfc0d 100644 --- a/Upsilon/BaseTypes/TypeConversion.cs +++ b/Upsilon/BaseTypes/TypeConversion.cs @@ -6,7 +6,7 @@ namespace Upsilon.BaseTypes { internal static class TypeConversion { - public static ScriptType ToLuaType(this object o) + public static ScriptType ToScriptType(this object o) { if (o is ScriptType type) return type; switch (o) diff --git a/Upsilon/BaseTypes/UserData/DictionaryUserData.cs b/Upsilon/BaseTypes/UserData/DictionaryUserData.cs index 0af89c5..1587c07 100644 --- a/Upsilon/BaseTypes/UserData/DictionaryUserData.cs +++ b/Upsilon/BaseTypes/UserData/DictionaryUserData.cs @@ -18,7 +18,7 @@ namespace Upsilon.BaseTypes.UserData var key = index.ToCSharpObject(); if (Dictionary.Contains(key)) { - return Dictionary[key].ToLuaType(); + return Dictionary[key].ToScriptType(); } //TODO: log error return new ScriptNull(); diff --git a/Upsilon/BaseTypes/UserData/ListUserData.cs b/Upsilon/BaseTypes/UserData/ListUserData.cs index badec7b..387d88d 100644 --- a/Upsilon/BaseTypes/UserData/ListUserData.cs +++ b/Upsilon/BaseTypes/UserData/ListUserData.cs @@ -32,7 +32,7 @@ namespace Upsilon.BaseTypes.UserData { return null; } - return List[i].ToLuaType(); + return List[i].ToScriptType(); } public void Set(Diagnostics diagnostics, TextSpan span, ScriptType index, ScriptType value) diff --git a/Upsilon/BaseTypes/UserData/UserDataMethod.cs b/Upsilon/BaseTypes/UserData/UserDataMethod.cs index f02477d..23eb27b 100644 --- a/Upsilon/BaseTypes/UserData/UserDataMethod.cs +++ b/Upsilon/BaseTypes/UserData/UserDataMethod.cs @@ -30,10 +30,12 @@ namespace Upsilon.BaseTypes.UserData public bool IsOptional { get; } } + public string Name { get; } private List MethodParts { get; } public UserDataMethod(MethodInfo method) { + Name = method.Name; var part = new UserDataMethodPart(method); MethodParts = new List() { diff --git a/Upsilon/BaseTypes/UserData/UserDataType.cs b/Upsilon/BaseTypes/UserData/UserDataType.cs index 9538077..3dc71c8 100644 --- a/Upsilon/BaseTypes/UserData/UserDataType.cs +++ b/Upsilon/BaseTypes/UserData/UserDataType.cs @@ -40,15 +40,15 @@ namespace Upsilon.BaseTypes.UserData member = member.ToLowerInvariant(); if (Variables.TryGetValue(member, out var info)) { - return (info.GetValue(value).ToLuaType(), false, null); + return (info.GetValue(value).ToScriptType(), false, null); } if (Properties.TryGetValue(member, out var property)) { - return (property.GetValue(value).ToLuaType(), false, null); + return (property.GetValue(value).ToScriptType(), false, null); } if (Methods.TryGetValue(member, out var method)) { - return (new ScriptMethodInfoFunction(method, value), false, null); + return (new ScriptMethodInfoFunction(method, value, false), false, null); } return (null, true, $"Can't find public member '{member}' on type '{Type}'."); @@ -85,7 +85,7 @@ namespace Upsilon.BaseTypes.UserData return (new ScriptNull(), true); } - return (method.Invoke(value, new[] {par1.ToCSharpObject(), par2.ToCSharpObject()}).ToLuaType(), false); + return (method.Invoke(value, new[] {par1.ToCSharpObject(), par2.ToCSharpObject()}).ToScriptType(), false); } public (ScriptType Type, bool Failed) UnaryOperator(object value, ScriptType par1, OperatorType op) { @@ -95,7 +95,7 @@ namespace Upsilon.BaseTypes.UserData return (new ScriptNull(), true); } - return (method.Invoke(value, new[] {par1.ToCSharpObject()}).ToLuaType(), false); + return (method.Invoke(value, new[] {par1.ToCSharpObject()}).ToScriptType(), false); } } } \ No newline at end of file diff --git a/Upsilon/Evaluator/Evaluator.cs b/Upsilon/Evaluator/Evaluator.cs index 2649455..8d8a3f9 100644 --- a/Upsilon/Evaluator/Evaluator.cs +++ b/Upsilon/Evaluator/Evaluator.cs @@ -476,7 +476,7 @@ namespace Upsilon.Evaluator scope = scopeOwner.EvaluationScope; } - return indexable.Get(_diagnostics, e.Span, e.Index.ToLuaType(), scope); + return indexable.Get(_diagnostics, e.Span, e.Index.ToScriptType(), scope); } private void EvaluateTableAssignmentStatement(BoundTableAssigmentStatement e) @@ -491,7 +491,7 @@ namespace Upsilon.Evaluator else { table = EvaluateExpression(((BoundFullStopIndexExpression)e.TableIndexExpression).Expression); - index = ((BoundFullStopIndexExpression) e.TableIndexExpression).Index.ToLuaType(); + index = ((BoundFullStopIndexExpression) e.TableIndexExpression).Index.ToScriptType(); } var value = EvaluateExpression(e.Value); @@ -499,7 +499,7 @@ namespace Upsilon.Evaluator { throw new Exception("Cant assign to that"); } - indexable.Set(_diagnostics, e.Span, index.ToString().ToLuaType(), value); + indexable.Set(_diagnostics, e.Span, index.ToString().ToScriptType(), value); } private void EvaluateNumericForStatement(BoundNumericForStatement e) @@ -550,7 +550,7 @@ namespace Upsilon.Evaluator { var (key, value) = enumerator.Current; if (e.Variables[0].Name != "_") - innerEvaluator.Scope.CreateLocal(e.Variables[0], key.ToLuaType()); + innerEvaluator.Scope.CreateLocal(e.Variables[0], key.ToScriptType()); if (e.Variables[1].Name != "_") innerEvaluator.Scope.CreateLocal(e.Variables[1], value); innerEvaluator.EvaluateBoundBlockStatement((BoundBlockStatement) e.Block); diff --git a/Upsilon/Evaluator/Script.cs b/Upsilon/Evaluator/Script.cs index 2881bf9..61b61c6 100644 --- a/Upsilon/Evaluator/Script.cs +++ b/Upsilon/Evaluator/Script.cs @@ -69,7 +69,7 @@ namespace Upsilon.Evaluator { foreach (var parameter in parameters) { - luaParameters.Add(parameter.ToLuaType()); + luaParameters.Add(parameter.ToScriptType()); } } return Convert(Evaluator.Evaluate(Bind(), functionName, luaParameters.ToImmutable())); @@ -103,7 +103,7 @@ namespace Upsilon.Evaluator { foreach (var parameter in parameters) { - luaParameters.Add(parameter.ToLuaType()); + luaParameters.Add(parameter.ToScriptType()); } } return Convert(Evaluator.Evaluate(Bind(), functionName, luaParameters.ToImmutable())); diff --git a/Upsilon/StandardLibraries/BasicFunctions.cs b/Upsilon/StandardLibraries/BasicFunctions.cs index 0b32de6..645c775 100644 --- a/Upsilon/StandardLibraries/BasicFunctions.cs +++ b/Upsilon/StandardLibraries/BasicFunctions.cs @@ -12,36 +12,31 @@ namespace Upsilon.StandardLibraries { internal class BasicFunctions : LuaLibrary { - [LuaFunction("assert")] - public void Assert(bool boolean, string message = null) + [StandardLibraryScriptFunction("assert")] + public void Assert(ScriptBoolean boolean, ScriptString message = null) { if (!boolean) { - Error(message ?? "assertion failed!"); + Error(message ?? new ScriptString("assertion failed!")); } } - [LuaFunction("error")] - public void Error(string message) + [StandardLibraryScriptFunction("error")] + public void Error(ScriptString message) { - throw new Exception(message); + throw new Exception(message.Value); } - /* - [LuaFunction("ipairs")] - public ScriptType Pairs(IIterable table) + [StandardLibraryScriptFunction("ipairs")] + public IIterable Pairs(IIterable table) { - if (!table.Next(out var key, out var next)) - { - return new ScriptNull(); - } + return table; + } - return new SimpleScriptTable(new List() {key, next}); - }*/ - - [LuaFunction("tonumber")] - public ScriptNumber ToNumber(string str) + [StandardLibraryScriptFunction("tonumber")] + public ScriptNumber ToNumber(ScriptString obj) { + var str = obj.Value; if (str.Contains(".")) { return new ScriptNumberDouble(double.Parse(str)); diff --git a/Upsilon/StandardLibraries/LuaLibrary.cs b/Upsilon/StandardLibraries/LuaLibrary.cs index d4453f1..e91a8b1 100644 --- a/Upsilon/StandardLibraries/LuaLibrary.cs +++ b/Upsilon/StandardLibraries/LuaLibrary.cs @@ -13,10 +13,10 @@ namespace Upsilon.StandardLibraries var methods = GetType().GetMethods(); foreach (var methodInfo in methods) { - var attr = methodInfo.GetCustomAttribute(); + var attr = methodInfo.GetCustomAttribute(); if (attr != null) { - dictionary.Add(attr.Name, new ScriptMethodInfoFunction(new UserDataMethod(methodInfo), this)); + dictionary.Add(attr.Name, new ScriptMethodInfoFunction(new UserDataMethod(methodInfo), this, true)); } } diff --git a/Upsilon/StandardLibraries/LuaFunctionAttribute.cs b/Upsilon/StandardLibraries/StandardLibraryScriptFunctionAttribute.cs similarity index 63% rename from Upsilon/StandardLibraries/LuaFunctionAttribute.cs rename to Upsilon/StandardLibraries/StandardLibraryScriptFunctionAttribute.cs index 29613d6..56bd555 100644 --- a/Upsilon/StandardLibraries/LuaFunctionAttribute.cs +++ b/Upsilon/StandardLibraries/StandardLibraryScriptFunctionAttribute.cs @@ -3,9 +3,9 @@ using System; namespace Upsilon.StandardLibraries { [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)] - public class LuaFunctionAttribute : Attribute + public class StandardLibraryScriptFunctionAttribute : Attribute { - public LuaFunctionAttribute(string name) + public StandardLibraryScriptFunctionAttribute(string name) { Name = name; } diff --git a/Upsilon/StandardLibraries/StaticScope.cs b/Upsilon/StandardLibraries/StaticScope.cs index b66e83e..a5f2190 100644 --- a/Upsilon/StandardLibraries/StaticScope.cs +++ b/Upsilon/StandardLibraries/StaticScope.cs @@ -54,7 +54,7 @@ namespace Upsilon.StandardLibraries public static void RegisterStaticVariable(string name, object value) { - var luaVariable = value.ToLuaType(); + var luaVariable = value.ToScriptType(); var varSymbol = new VariableSymbol(name, luaVariable.Type, false); BoundScope.AssignToNearest(varSymbol); Scope.AssignToNearest(varSymbol, luaVariable); diff --git a/UpsilonTests/StandardLibraryTests/BasicFunctionsTests.cs b/UpsilonTests/StandardLibraryTests/BasicFunctionsTests.cs index f3647e7..7273e7f 100644 --- a/UpsilonTests/StandardLibraryTests/BasicFunctionsTests.cs +++ b/UpsilonTests/StandardLibraryTests/BasicFunctionsTests.cs @@ -25,5 +25,36 @@ namespace UpsilonTests.StandardLibraryTests Assert.Equal("test_error", e.Message); } + [Fact] + public void IPairsTest() + { + const string input = @" +arr = {100, 56, 28} +value = 0 +for key, val in ipairs(arr) do + value = value + val +end +return value +"; + var script = new Script(input, BoundScope, StaticScope); + Assert.Empty(script.Diagnostics.Messages); + var result = script.Evaluate(); + Assert.Empty(script.Diagnostics.Messages); + Assert.Equal(184, result); + } + + [Fact] + public void ToNumberTest() + { + const string input = @" +return tonumber(""100"") +"; + var script = new Script(input, BoundScope, StaticScope); + Assert.Empty(script.Diagnostics.Messages); + var result = script.Evaluate(); + Assert.Empty(script.Diagnostics.Messages); + Assert.Equal(100, result); + } + } } \ No newline at end of file