diff --git a/NeoLua.Dbg/NeoLua.Dbg.csproj b/NeoLua.Dbg/NeoLua.Dbg.csproj index 1e7826f..68e1990 100644 --- a/NeoLua.Dbg/NeoLua.Dbg.csproj +++ b/NeoLua.Dbg/NeoLua.Dbg.csproj @@ -4,7 +4,7 @@ Neo.Lua.Dbg Neo.IronLua true - net45;netcoreapp2.1 + net45;netcoreapp3.1 true NeoLua.snk NeoLuaDebug diff --git a/NeoLua.NuGet/common.targets b/NeoLua.NuGet/common.targets index 1a1f0f1..22aff57 100644 --- a/NeoLua.NuGet/common.targets +++ b/NeoLua.NuGet/common.targets @@ -12,9 +12,9 @@ git 5.3.0.0 - 1.3.14.0 + 1.4.0.0 - + beta.0 ^(\d+)\.(\d+)\.(\d+) $([System.Text.RegularExpressions.Regex]::Match($(FileVersion), $(SimpleVersionPattern))) diff --git a/NeoLua.Test/ControlStructures.cs b/NeoLua.Test/ControlStructures.cs index b998312..da8970c 100644 --- a/NeoLua.Test/ControlStructures.cs +++ b/NeoLua.Test/ControlStructures.cs @@ -362,6 +362,12 @@ public void Control19() TestCode(GetLines("Lua.Control19.lua"), 4); } + [TestMethod] + public void Control20() + { + TestCode(GetLines("Lua.Control20.lua"), 500000500000, 500000500001); + } + [TestMethod] public void TestVariableAssign01() { diff --git a/NeoLua.Test/Lua/Control20.lua b/NeoLua.Test/Lua/Control20.lua new file mode 100644 index 0000000..64e6d8c --- /dev/null +++ b/NeoLua.Test/Lua/Control20.lua @@ -0,0 +1,8 @@ +local t = {}; +local j = 1; +for i = 500000500000, 500000500001 do + print(tostring(i)); + t[j] = i; + j = j + 1; +end; +return t[1], t[2]; \ No newline at end of file diff --git a/NeoLua.Test/LuaTable.cs b/NeoLua.Test/LuaTable.cs index e7eb500..ebdd3f1 100644 --- a/NeoLua.Test/LuaTable.cs +++ b/NeoLua.Test/LuaTable.cs @@ -3,8 +3,6 @@ using System.Diagnostics; using System.Linq; using System.Reflection; -using System.Text; -using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.IronLua; @@ -13,6 +11,45 @@ namespace LuaDLR.Test [TestClass] public class LuaTableTests : TestHelper { + #region -- class ObjectInit --------------------------------------------------- + + public const string ObjectInitLua = ""; + + public class ObjectInit + { + private readonly object[] values = new object[10]; + + public void TestEvent() + { + Assert.IsNotNull(Event); + } + + public object this[int idx] { get => values[idx]; set => values[idx] = value; } + + public int fieldValue; + + public int Value { get; set; } = 100; + public Func Action { get; set; } + + public event EventHandler Event; + } + + #endregion + + #region -- class ObjectInitS -------------------------------------------------- + + public class ObjectInitS + { + public ObjectInitS(LuaTable t) + { + Value = (int)t.GetMemberValue(nameof(Value)); + } + + public int Value { get; } + } + + #endregion + #region -- TestMember ------------------------------------------------------------- [TestMethod] @@ -393,19 +430,83 @@ public void TestMetaTable11() #region -- TestConvert ------------------------------------------------------------ [TestMethod] - public void TestConvert01() + public void TestConvert01a() + => TestCode("return cast(LuaDLR.Test.LuaTypeTests.SubStruct, { Value = 2 }).Value", 2); + + [TestMethod] + public void TestConvert01b() { - using (Lua l = new Lua()) + using (var l = new Lua()) { l.PrintExpressionTree = Console.Out; var g = l.CreateEnvironment(); - var r = g.DoChunk("return cast(System.Diagnostics.ProcessStartInfo, { FileName = 'Test.exe', Arguments = 'aaa' });", "dummy"); - ProcessStartInfo psi = (ProcessStartInfo)r[0]; - Assert.IsTrue(psi.FileName == "Test.exe"); - Assert.IsTrue(psi.Arguments == "aaa"); + var r = g.DoChunk("return cast(LuaDLR.Test.LuaTableTests.ObjectInit, { Value = 42, 1, 2, 3 });", "dummy"); + var o = (ObjectInit)r[0]; + Assert.AreEqual(o.Value, 42); + Assert.AreEqual(o[0], 1); + Assert.AreEqual(o[1], 2); + Assert.AreEqual(o[2], 3); } } // func TestConvert01 + [TestMethod] + public void TestConvert02a() + { + using (var l = new Lua()) + { + var g = l.CreateEnvironment(); + var t = (LuaTable)g.DoChunk("return { fieldValue = 42, Value = 23, Action = function() : int return 44 end, Event = function(s, e) : void print('test') end, 1, 2, 3 };", "dummy")[0]; + + var o = t.InitObject(true); + Assert.AreEqual(o.Value, 23); + Assert.AreEqual(o.fieldValue, 42); + Assert.AreEqual(o.Action(), 44); + o.TestEvent(); + Assert.AreEqual(o[0], 1); + Assert.AreEqual(o[1], 2); + Assert.AreEqual(o[2], 3); + } + } + + [TestMethod] + public void TestConvert02b() + { + using (var l = new Lua()) + { + var g = l.CreateEnvironment(); + var t = (LuaTable)g.DoChunk("return { fieldValue = 42, err = 23, Value = 23, Action = function() : int return 44 end, Event = function(s, e) : void print('test') end, 1, 2, 3 };", "dummy")[0]; + + var o = t.InitObject(false); + Assert.AreEqual(o.Value, 23); + Assert.AreEqual(o.fieldValue, 42); + Assert.AreEqual(o.Action(), 44); + o.TestEvent(); + Assert.AreEqual(o[0], 1); + Assert.AreEqual(o[1], 2); + Assert.AreEqual(o[2], 3); + } + } + + [TestMethod] + public void TestConvert02c() + { + using (var l = new Lua()) + { + var g = l.CreateEnvironment(); + var t = (LuaTable)g.DoChunk("return { err = 23 };", "dummy")[0]; + + try + { + var o = t.InitObject(true); + Assert.Fail(); + } + catch (InvalidOperationException e) + { + Console.WriteLine(e.Message); + } + } + } + #endregion #region -- Length ----------------------------------------------------------------- diff --git a/NeoLua.Test/LuaType.cs b/NeoLua.Test/LuaType.cs index c8d7651..d6e90cb 100644 --- a/NeoLua.Test/LuaType.cs +++ b/NeoLua.Test/LuaType.cs @@ -2,12 +2,11 @@ using System.Collections.Generic; using System.Drawing; using System.IO; -using System.Linq; using System.Reflection; using System.Text; -using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.IronLua; +using static LuaDLR.Test.LuaTableTests; namespace LuaDLR.Test { @@ -35,6 +34,9 @@ public override int Foo() public class DataTypeTest { public Type DataType; + + public static explicit operator DataTypeTest(LuaTable t) + => t.SetObjectMember(new DataTypeTest()); } public class Graph @@ -308,14 +310,14 @@ public void TypeTest07() public void TypeTest08() { TestCode(Lines("local t : System.Type = clr.System.Text.StringBuilder;", - "return t"), typeof(System.Text.StringBuilder)); + "return t"), typeof(StringBuilder)); } [TestMethod] public void TypeTest09() { TestCode(Lines("local t : LuaDLR.Test.LuaTypeTests.DataTypeTest = { DataType = clr.System.Text.StringBuilder };", - "return t.DataType"), typeof(System.Text.StringBuilder)); + "return t.DataType"), typeof(StringBuilder)); } [TestMethod] @@ -497,9 +499,32 @@ public void CtorTest02() } [TestMethod] - public void CtorTest03() + public void CtorTest10() { - TestCode("return cast(LuaDLR.Test.LuaTypeTests.SubStruct, { Value = 2 }).Value", 2); + using (var l = new Lua()) + { + l.PrintExpressionTree = Console.Out; + var g = l.CreateEnvironment(); + var r = g.DoChunk("return clr.LuaDLR.Test.LuaTableTests.ObjectInit(){ Value = 42, 1, 2, 3 };", "dummy"); + var o = (ObjectInit)r[0]; + Assert.AreEqual(o.Value, 42); + Assert.AreEqual(o[0], 1); + Assert.AreEqual(o[1], 2); + Assert.AreEqual(o[2], 3); + } + } + + [TestMethod] + public void CtorTest11() + { + using (var l = new Lua()) + { + l.PrintExpressionTree = Console.Out; + var g = l.CreateEnvironment(); + var r = g.DoChunk("return clr.LuaDLR.Test.LuaTableTests.ObjectInitS{ Value = 42, 1, 2, 3 };", "dummy"); + var o = (ObjectInitS)r[0]; + Assert.AreEqual(o.Value, 42); + } } [TestMethod] diff --git a/NeoLua.Test/NeoLua.Test.csproj b/NeoLua.Test/NeoLua.Test.csproj index 4020210..ec26d0a 100644 --- a/NeoLua.Test/NeoLua.Test.csproj +++ b/NeoLua.Test/NeoLua.Test.csproj @@ -25,6 +25,7 @@ + @@ -51,6 +52,7 @@ + diff --git a/NeoLua.Test/RunLuaTests.cs b/NeoLua.Test/RunLuaTests.cs index 09949a2..1cee925 100644 --- a/NeoLua.Test/RunLuaTests.cs +++ b/NeoLua.Test/RunLuaTests.cs @@ -1,10 +1,7 @@ using System; -using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.IronLua; diff --git a/NeoLua.Test/Runtime.cs b/NeoLua.Test/Runtime.cs index bb3fb0b..9fd02e8 100644 --- a/NeoLua.Test/Runtime.cs +++ b/NeoLua.Test/Runtime.cs @@ -1,14 +1,10 @@ using System; using System.Collections.Generic; -using System.Dynamic; -using System.Globalization; using System.IO; -using System.Linq; using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.IronLua; +using static LuaDLR.Test.LuaTableTests; namespace LuaDLR.Test { @@ -229,7 +225,7 @@ public void TestToNumber01() [TestMethod] public void TestDateTime01() { - using (Lua l = new Lua()) + using (var l = new Lua()) { dynamic g = l.CreateEnvironment(); @@ -283,7 +279,7 @@ public void TestConvert01() { var t = new LuaTable(); t["DataType"] = typeof(StringBuilder); - var r = Lua.RtConvertValue(t, typeof(LuaDLR.Test.LuaTypeTests.DataTypeTest)); + var r = Lua.RtConvertValue(t, typeof(LuaTypeTests.DataTypeTest)); Assert.AreEqual(typeof(LuaTypeTests.DataTypeTest), r.GetType()); Assert.AreEqual(typeof(StringBuilder), ((LuaTypeTests.DataTypeTest)r).DataType); } @@ -561,7 +557,73 @@ public void Invoke01() Assert.AreEqual(r[0], "a"); Assert.AreEqual(r[1], null); } + + [TestMethod] + public void Invoke02() + { + using (var l = new Lua()) + { + var g = new LuaGlobal(l); + l.PrintExpressionTree = Console.Out; + var o = new ObjectInit(); + var r = g.DoChunk(Lines("local function f456() return 4,5,6; end; local t = o{ fieldValue = 42, Value = 23, Action = function() : int return 44 end, Event = function(s, e) : void print('test') end, 1, 2, 3, f456() }.Value; return t;"), "dummy", new KeyValuePair("o", o)); + + Assert.AreEqual(r[0], 23); + Assert.AreEqual(o.Value, 23); + Assert.AreEqual(o.fieldValue, 42); + Assert.AreEqual(o.Action(), 44); + o.TestEvent(); + Assert.AreEqual(o[0], 1); + Assert.AreEqual(o[1], 2); + Assert.AreEqual(o[2], 3); + Assert.AreEqual(o[3], 4); + Assert.AreEqual(o[4], 5); + Assert.AreEqual(o[5], 6); + } + } + + [TestMethod] + public void Invoke03() + { + using (var l = new Lua()) + { + var g = new LuaGlobal(l); + l.PrintExpressionTree = Console.Out; + + var o = new ObjectInit(); + var c = l.CompileChunk(Lines("o{ fieldValue = 42, Value = 23, Action = function() : int return 44 end, Event = function(s, e) : void print('test') end, 1, 2, 3 }"), "dummy", null, new KeyValuePair("o", typeof(object))); + c.Run(g, o); + + Assert.AreEqual(o.Value, 23); + Assert.AreEqual(o.fieldValue, 42); + Assert.AreEqual(o.Action(), 44); + o.TestEvent(); + Assert.AreEqual(o[0], 1); + Assert.AreEqual(o[1], 2); + Assert.AreEqual(o[2], 3); + } + } + + [TestMethod] + public void Invoke04() + { + using (var l = new Lua()) + { + var g = new LuaGlobal(l); + l.PrintExpressionTree = Console.Out; + var o = new ObjectInit(); + g.DoChunk(Lines("local t : table = { fieldValue = 42, Value = 23, Action = function() : int return 44 end, Event = function(s, e) : void print('test') end, 1, 2, 3 }; o(t)"), "dummy", new KeyValuePair("o", o)); + + Assert.AreEqual(o.Value, 23); + Assert.AreEqual(o.fieldValue, 42); + Assert.AreEqual(o.Action(), 44); + o.TestEvent(); + Assert.AreEqual(o[0], 1); + Assert.AreEqual(o[1], 2); + Assert.AreEqual(o[2], 3); + } + } } - } //class Runtime +} //class Runtime diff --git a/NeoLua/Lua.Binder.cs b/NeoLua/Lua.Binder.cs index 8ee0086..cdf16ea 100644 --- a/NeoLua/Lua.Binder.cs +++ b/NeoLua/Lua.Binder.cs @@ -284,15 +284,8 @@ public override DynamicMetaObject FallbackInvoke(DynamicMetaObject target, Dynam { var restrictions = GetMethodSignatureRestriction(target, args); Expression expr; - var invokeTarget = target.Value as Delegate; - if (invokeTarget == null) - { - if (errorSuggestion != null) - return errorSuggestion; - expr = ThrowExpression(LuaEmitException.GetMessageText(LuaEmitException.InvokeNoDelegate, target.LimitType.Name), typeof(object)); - } - else + if (target.Value is Delegate invokeTarget) { var methodParameters = invokeTarget.GetMethodInfo().GetParameters(); var parameters = (ParameterInfo[])null; @@ -333,6 +326,16 @@ public override DynamicMetaObject FallbackInvoke(DynamicMetaObject target, Dynam expr = ThrowExpression(e.Message, ReturnType); } } + else if (IsTypeInitializable(target.LimitType) && args.Length == 1 && args[0].LimitType == typeof(LuaTable)) + { + expr = Expression.Call(EnsureType(args[0].Expression, typeof(LuaTable)), TableSetObjectMemberMethodInfo, EnsureType(target.Expression, typeof(object)), Expression.Constant(false, typeof(bool))); + } + else + { + if (errorSuggestion != null) + return errorSuggestion; + expr = ThrowExpression(LuaEmitException.GetMessageText(LuaEmitException.InvokeNoDelegate, target.LimitType.Name), typeof(object)); + } return new DynamicMetaObject(expr, restrictions); } @@ -852,6 +855,9 @@ internal static Expression EnsureType(Expression expr, Type exprType, Type retur return EnsureType(expr, returnType, forResult); } // func Expression + internal static bool IsTypeInitializable(Type type) + => !type.IsPrimitive && type != typeof(string); + #endregion } // class Lua diff --git a/NeoLua/Lua.Runtime.cs b/NeoLua/Lua.Runtime.cs index cca3927..fbe46ea 100644 --- a/NeoLua/Lua.Runtime.cs +++ b/NeoLua/Lua.Runtime.cs @@ -185,7 +185,7 @@ static Lua() TableDefineMethodLightMethodInfo = tiLuaTable.FindDeclaredMethod(nameof(LuaTable.DefineMethodLight), ReflectionFlag.None, typeof(string), typeof(Delegate)); TableGetCallMemberMethodInfo = tiLuaTable.FindDeclaredMethod(nameof(LuaTable.GetCallMember), ReflectionFlag.NoArguments); - TableSetObjectMemberMethodInfo = tiLuaTable.FindDeclaredMethod(nameof(LuaTable.SetObjectMember), ReflectionFlag.None, typeof(object)); + TableSetObjectMemberMethodInfo = tiLuaTable.FindDeclaredMethod(nameof(LuaTable.SetObjectMember), ReflectionFlag.None, typeof(object), typeof(bool)); TableEntriesFieldInfo = tiLuaTable.FindDeclaredField("entries", ReflectionFlag.None); TablePropertyChangedMethodInfo = tiLuaTable.FindDeclaredMethod("OnPropertyChanged", ReflectionFlag.None, typeof(string)); @@ -256,7 +256,7 @@ static Lua() GetResultValuesMethodInfo = tiLua.FindDeclaredMethod(nameof(Lua.RtGetResultValues), ReflectionFlag.None, typeof(LuaResult), typeof(int), typeof(Type)); CombineArrayWithResultMethodInfo = tiLua.FindDeclaredMethod(nameof(Lua.RtCombineArrayWithResult), ReflectionFlag.None, typeof(Array), typeof(LuaResult), typeof(Type)); ConvertArrayMethodInfo = tiLua.FindDeclaredMethod(nameof(Lua.RtConvertArray), ReflectionFlag.None, typeof(Array), typeof(Type)); - TableSetObjectsMethod = tiLua.FindDeclaredMethod(nameof(Lua.RtTableSetObjects), ReflectionFlag.None, typeof(LuaTable), typeof(object), typeof(int)); + TableSetObjectsMethod = tiLua.FindDeclaredMethod(nameof(Lua.RtTableSetObjects), ReflectionFlag.None, typeof(object), typeof(object), typeof(int)); ConcatStringMethodInfo = tiLua.FindDeclaredMethod(nameof(Lua.RtConcatString), ReflectionFlag.None | ReflectionFlag.NoArguments); ConvertDelegateMethodInfo = tiLua.FindDeclaredMethod(nameof(Lua.RtConvertDelegate), ReflectionFlag.None | ReflectionFlag.NoArguments); InitArray1MethodInfo = tiLua.FindDeclaredMethod(nameof(Lua.RtInitArray), ReflectionFlag.None, typeof(Type), typeof(object)); @@ -1219,7 +1219,7 @@ public static int RtLength(object v) #region -- RtTableSetObjects -------------------------------------------------- - internal static object RtTableSetObjects(LuaTable t, object value, int startIndex) + internal static LuaTable RtTableSetObjects(LuaTable t, object value, int startIndex) { if (value is LuaResult r) { @@ -1231,6 +1231,34 @@ internal static object RtTableSetObjects(LuaTable t, object value, int startInde return t; } // func RtTableSetObjects + internal static object RtTableSetObjects(object o, object value, int startIndex) + { + if (o is LuaTable t) + return RtTableSetObjects(t, value, startIndex); + else + { + var type = o.GetType(); + var indexProperty = type.GetRuntimeProperties().Where(LuaTable.IsIndexSetter).FirstOrDefault() + ?? throw new LuaEmitException(LuaEmitException.IndexNotFound, type.Name); + + var idx = new object[1]; + if (value is LuaResult r) + { + for (var i = 0; i < r.Count; i++) + { + idx[0] = startIndex++; + indexProperty.SetValue(o, r[i], idx); + } + } + else if (value != null) + { + idx[0] = startIndex; + indexProperty.SetValue(o, value, idx); + } + } + return o; + } // func RtTableSetObjects + #endregion #region -- RtInvoke ----------------------------------------------------------- diff --git a/NeoLua/Lua.cs b/NeoLua/Lua.cs index 2635d4c..838007d 100644 --- a/NeoLua/Lua.cs +++ b/NeoLua/Lua.cs @@ -285,7 +285,7 @@ public static bool IsConstantScript(ILuaLexer code) internal LuaChunk CompileChunkCore(ILuaLexer lex, LuaCompileOptions options, IEnumerable> args) { if (options == null) - options = new LuaCompileOptions(); + options = DefaultCompileOptions ?? new LuaCompileOptions(); var registerMethods = options.DebugEngine != null && (options.DebugEngine.Level & LuaDebugLevel.RegisterMethods) == LuaDebugLevel.RegisterMethods; if (registerMethods) @@ -323,7 +323,7 @@ public Delegate CreateLambda(string name, string code, Type delegateType, Type r { using (var l = LuaLexer.Create(name, new StringReader(code))) { - var expr = Parser.ParseChunk(this, new LuaCompileOptions(), false, l, delegateType, returnType, arguments); + var expr = Parser.ParseChunk(this, DefaultCompileOptions ?? new LuaCompileOptions(), false, l, delegateType, returnType, arguments); if (printExpressionTree != null) { @@ -547,7 +547,15 @@ public static Version Version } } // prop Version -#if !NETSTANDARD2_0 && !NETCOREAPP2_1 && !NET5_0 + /// + /// Get/Set the default compile options + /// + public LuaCompileOptions DefaultCompileOptions + { + get; set; + } = new LuaCompileOptions(); + +#if !NETSTANDARD2_1 && !NETCOREAPP1_0_OR_GREATER /// Stack trace compile options. public static LuaCompileOptions StackTraceCompileOptions { get; } = new LuaCompileOptions { DebugEngine = LuaStackTraceDebugger.Default }; #endif diff --git a/NeoLua/LuaChunk.cs b/NeoLua/LuaChunk.cs index 157aaba..47d350a 100644 --- a/NeoLua/LuaChunk.cs +++ b/NeoLua/LuaChunk.cs @@ -72,7 +72,7 @@ public LuaResult Run(LuaTable env, params object[] callArgs) try { var r = chunk.DynamicInvoke(args); - return r is LuaResult ? (LuaResult)r : new LuaResult(r); + return r is LuaResult t ? t : new LuaResult(r); } catch (TargetInvocationException e) { diff --git a/NeoLua/LuaEmit.cs b/NeoLua/LuaEmit.cs index 1bdbf8c..0b8a830 100644 --- a/NeoLua/LuaEmit.cs +++ b/NeoLua/LuaEmit.cs @@ -1798,6 +1798,13 @@ public static LuaTrySetMemberReturn TrySetMember(Expression target, Type targetT result = Expression.Assign(Expression.Field(target != null ? Lua.EnsureType(target, targetType) : null, fieldInfo), set(fieldInfo.FieldType)); return LuaTrySetMemberReturn.ValidExpression; } + else if (memberInfo is EventInfo eventInfo) + { + result = target == null + ? Expression.Call(eventInfo.AddMethod, set(eventInfo.EventHandlerType)) + : Expression.Call(target, eventInfo.AddMethod, set(eventInfo.EventHandlerType)); + return LuaTrySetMemberReturn.ValidExpression; + } else { result = null; @@ -1831,7 +1838,7 @@ public static Expression SetIndex(Lua runtime, TARG instance, TARG[] argum if (isParse && IsDynamicType(instanceType)) { return DynamicExpression.Dynamic(runtime.GetSetIndexMember(new CallInfo(arguments.Length)), typeof(object), - CreateDynamicArgs(getExpr(instance), instanceType, arguments, setTo, getExpr, getType) + CreateDynamicArgs(getExpr(instance), instanceType, arguments, setTo, getExpr, getType) ); } @@ -2769,7 +2776,7 @@ internal static Expression InvokeMethod(Lua lua, MethodInfo methodInfo, TA emitCall = convertedArguments => Expression.Call(null, methodInfo, convertedArguments); } - result = BindParameter(lua, + result = BindParameter(lua, emitCall, methodInfo.GetParameters(), callInfo, diff --git a/NeoLua/LuaGlobal.cs b/NeoLua/LuaGlobal.cs index 9c8fd93..9c2325a 100644 --- a/NeoLua/LuaGlobal.cs +++ b/NeoLua/LuaGlobal.cs @@ -29,6 +29,8 @@ public class LuaGlobal : LuaTable public LuaGlobal(Lua lua) { this.lua = lua ?? throw new ArgumentNullException(nameof(lua)); + + InitializeLibraries(); } // ctor /// Redirects the invoke binder to the script manager/compiler. @@ -37,14 +39,119 @@ public LuaGlobal(Lua lua) protected override CallSiteBinder GetInvokeBinder(CallInfo callInfo) => lua.GetInvokeBinder(callInfo); - #endregion - - #region -- void RegisterPackage ----------------------------------------------- - - /// Registers a type as an library. - /// - /// - public void RegisterPackage(string name, Type type) + #endregion + + #region -- Initialize libraries------------------------------------------------- + + /// + /// Initialize the library tables with the appropriate functions (and constants) + /// + private void InitializeLibraries() + { + InitializeMathLibrary(); + InitializeStringLibrary(); + InitializeTableLibrary(); + } + + #region --- Math Lib ---------------------------------------------------------- + private void InitializeMathLibrary() + { + LuaTable math = new LuaTable(); + this["math"] = math; + + math["huge"] = LuaLibraryMath.huge; + math["pi"] = LuaLibraryMath.pi; + math["e"] = LuaLibraryMath.e; + math["mininteger"] = LuaLibraryMath.mininteger; + math["maxinteger"] = LuaLibraryMath.maxinteger; + + math["abs"] = new Func(LuaLibraryMath.abs); + math["acos"] = new Func(LuaLibraryMath.acos); + math["asin"] = new Func(LuaLibraryMath.asin); + math["atan"] = new Func(LuaLibraryMath.atan); + math["atan2"] = new Func(LuaLibraryMath.atan2); + math["ceil"] = new Func(LuaLibraryMath.ceil); + math["cos"] = new Func(LuaLibraryMath.cos); + math["cosh"] = new Func(LuaLibraryMath.cosh); + math["deg"] = new Func(LuaLibraryMath.deg); + math["exp"] = new Func(LuaLibraryMath.exp); + math["floor"] = new Func(LuaLibraryMath.floor); + math["fmod"] = new Func(LuaLibraryMath.fmod); + math["frexp"] = new Func(LuaLibraryMath.frexp); + math["ldexp"] = new Func(LuaLibraryMath.ldexp); + math["log"] = new Func(LuaLibraryMath.log); + math["max"] = new Func(LuaLibraryMath.max); + math["min"] = new Func(LuaLibraryMath.min); + math["modf"] = new Func(LuaLibraryMath.modf); + math["pow"] = new Func(LuaLibraryMath.pow); + math["rad"] = new Func(LuaLibraryMath.rad); + math["random"] = new Func(LuaLibraryMath.random); + math["randomseed"] = new Action(LuaLibraryMath.randomseed); + math["sin"] = new Func(LuaLibraryMath.sin); + math["sinh"] = new Func(LuaLibraryMath.sinh); + math["sqrt"] = new Func(LuaLibraryMath.sqrt); + math["tan"] = new Func(LuaLibraryMath.tan); + math["tanh"] = new Func(LuaLibraryMath.tanh); + math["type"] = new Func(LuaLibraryMath.type); + math["tointeger"] = new Func(LuaLibraryMath.tointeger); + math["ult"] = new Func(LuaLibraryMath.ult); + } + #endregion + + #region --- String Lib ------------------------------------------------ + + //Delegates for types that can't be stuffed into generics + private delegate LuaResult byteDelg(string s, int? i = null, int? j = null); + private delegate string charDelg(params int [] chars); + private delegate string formatDelg(string format, params object [] prms); + + private void InitializeStringLibrary() + { + LuaTable str = new LuaTable(); + this["string"] = str; + str["byte"] = new byteDelg(Neo.IronLua.LuaLibraryString.@byte); + str["char"] = new charDelg(Neo.IronLua.LuaLibraryString.@char); + str["dump"] = new Func(Neo.IronLua.LuaLibraryString.dump); + str["find"] = new Func(Neo.IronLua.LuaLibraryString.find); + str["format"] = new formatDelg(Neo.IronLua.LuaLibraryString.format); + str["gmatch"] = new Func(Neo.IronLua.LuaLibraryString.gmatch); + str["gsub"] = new Func(Neo.IronLua.LuaLibraryString.gsub); + str["len"] = new Func(Neo.IronLua.LuaLibraryString.len); + str["lower"] = new Func(Neo.IronLua.LuaLibraryString.lower); + str["match"] = new Func(Neo.IronLua.LuaLibraryString.match); + str["rep"] = new Func(Neo.IronLua.LuaLibraryString.rep); + str["reverse"] = new Func(Neo.IronLua.LuaLibraryString.reverse); + str["sub"] = new Func(Neo.IronLua.LuaLibraryString.sub); + str["upper"] = new Func(Neo.IronLua.LuaLibraryString.upper); + } + #endregion + + #region --- Table Lib ------------------------------------------------ + + private delegate string concatDelg(LuaTable t, string sep = null, int? i = null, int? j = null); + + private void InitializeTableLibrary() + { + LuaTable tbl = new LuaTable(); + this["table"] = tbl; + tbl["concat"] = new concatDelg(LuaTable.concat); + tbl["insert"] = new Action(LuaTable.insert); + tbl["move"] = new Action(LuaTable.move); + tbl["pack"] = new Func(LuaTable.pack); + tbl["remove"] = new Func(LuaTable.remove); + tbl["sort"] = new Action(LuaTable.sort); + tbl["unpack"] = new Func(LuaTable.unpack); + } + #endregion + + #endregion + + #region -- void RegisterPackage ----------------------------------------------- + + /// Registers a type as an library. + /// + /// + public void RegisterPackage(string name, Type type) { if (String.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name)); @@ -354,32 +461,62 @@ private object LuaLoadFile(string filename, string mode, LuaTable env) if (mode == "b") // binary chunks are not implementeted throw new NotImplementedException(); + if(!File.Exists(filename)) + { + return new LuaResult(null, string.Format(Properties.Resources.rsNoFile, filename)); + } + // create the chunk - return LuaLoadReturn(Lua.CompileChunk(filename, DefaultCompileOptions, new KeyValuePair("...", typeof(object[]))), env); + try + { + return LuaLoadReturn(Lua.CompileChunk(filename, DefaultCompileOptions, new KeyValuePair("...", typeof(object[]))), env); + } + catch(Exception exc) + { + //Load file does not propogate errors, it returns nil plus the error message + return new LuaResult(null, exc.Message); + } } // func LuaLoadFile #endregion #region -- LuaRequire --------------------------------------------------------- - internal readonly Dictionary loaded = new Dictionary(); - [LuaMember("require")] private LuaResult LuaRequire(object modname) { if (modname == null) throw new ArgumentNullException(); - - // check if the modul is loaded in this global - if (loaded.TryGetValue(modname, out var currentlyLoaded)) - return new LuaResult(currentlyLoaded); + + object cachedResult; + if((cachedResult = LuaPackage.loaded[modname]) != null) + { + return new LuaResult(cachedResult); + } // check if the modul is loaded in a different global - var chunk = ((LuaLibraryPackage)LuaPackage).LuaRequire(this, modname as string); - if (chunk != null) - return new LuaResult(loaded[modname] = DoChunk(chunk)[0]); + LuaResult requireResult = ((LuaLibraryPackage)LuaPackage).LuaRequire(modname as string, out string checkedPathsOnFailed); + if (requireResult != null) + { + //Requiring ONLY EVER returns the first value from the require. If that value is null (or missing) require returns TRUE + //for a required library. + //However it is possible that the chunk itself set the value for package.loaded, if that is the case, we return whatever it set + if(LuaPackage.loaded[modname] == null) + { + object propagatedRequireResult = (requireResult.Values.Length > 0 ? requireResult.Values[0] : null) ?? true; //NEVER a null value + LuaPackage.loaded[modname] = propagatedRequireResult; + } + + return new LuaResult(LuaPackage.loaded[modname]); + } else - return LuaResult.Empty; + { + string errorMessage = string.Format(Properties.Resources.rsModuleNotFound, modname); + errorMessage += "\n"; + errorMessage += checkedPathsOnFailed; + + throw new LuaRuntimeException(errorMessage, 1, true); + } } // func LuaRequire #endregion @@ -756,15 +893,6 @@ private LuaResult LuaXPCall(object target, object msgh, params object[] args) [LuaMember("debug")] private static dynamic LuaLibraryDebug => LuaType.GetType(typeof(LuaLibraryDebug)); - [LuaMember("math")] - private static dynamic LuaLibraryMath => LuaType.GetType(typeof(LuaLibraryMath)); - - [LuaMember("string")] - private static dynamic LuaLibraryString => LuaType.GetType(typeof(LuaLibraryString)); - - [LuaMember("table")] - private static dynamic LuaLibraryTable => LuaType.GetType(typeof(LuaTable)); - /// [LuaMember("io")] public dynamic LuaLibraryIO diff --git a/NeoLua/LuaLibraries.cs b/NeoLua/LuaLibraries.cs index 960388a..7dd0e2e 100644 --- a/NeoLua/LuaLibraries.cs +++ b/NeoLua/LuaLibraries.cs @@ -1380,152 +1380,148 @@ static LuaFilePackage() /// public sealed class LuaLibraryPackage { - /// - public const string CurrentDirectoryPathVariable = "%currentdirectory%"; - /// - public const string ExecutingDirectoryPathVariable = "%executingdirectory%"; - - #region -- class LuaLoadedTable ----------------------------------------------- - - private class LuaLoadedTable : LuaTable - { - private LuaGlobal global; - - public LuaLoadedTable(LuaGlobal global) - { - this.global = global; - } // ctor - - protected override object OnIndex(object key) - { - if (global.loaded != null && global.loaded.TryGetValue(key, out var value)) - return value; - return base.OnIndex(key); - } // func OnIndex - - protected override bool OnNewIndex(object key, object value) - { - if (global.loaded != null) - { - if (value == null) - global.loaded.Remove(key); - else - global.loaded[key] = value; - } - return true; - } // func OnNewIndex - } // class LuaLoadedTable - - #endregion - - private readonly object packageLock = new object(); - private Dictionary loadedModuls = null; - private string[] paths; - private LuaCompileOptions compileOptions = null; + private LuaGlobal globals; /// /// public LuaLibraryPackage(LuaGlobal global) { - this.loaded = new LuaLoadedTable(global); - this.path = CurrentDirectoryPathVariable; + globals = global; + string currentDirectory = System.IO.Path.GetDirectoryName(Environment.CurrentDirectory); + currentDirectory = currentDirectory.Replace(System.IO.Path.DirectorySeparatorChar, '/'); + this.path = string.Format("{0}/?;{0}/?.lua", currentDirectory); + + //Setup the searchers like lua 5.3 (ignoring antrhing after the unloaded package searcher, since we don't support C packages) + this.searchers[1] = new Func(LuaPreloadPackage); //Preloads don't actually work, but keep this in index 1 for Lua consistency + this.searchers[2] = new Func(LuaFindUnloadedPackage); } // ctor - internal LuaChunk LuaRequire(LuaGlobal global, string moduleName) + /// + /// Loads the LuaChunk for the require using the set searchers + /// + internal LuaResult LuaRequire(string moduleName, out string checkedPathsOnFailed) { + checkedPathsOnFailed = null; if (String.IsNullOrEmpty(moduleName)) - return null; - - if (LuaRequireFindFile(moduleName, out var fileName, out var stamp)) - { - lock (packageLock) - { - LuaChunk chunk; - var cacheId = fileName + ";" + stamp.ToString("o"); - - // is the modul loaded - if (loadedModuls == null - || !loadedModuls.TryGetValue(cacheId, out var rc) - || !rc.IsAlive) - { - // compile the modul - chunk = global.Lua.CompileChunk(fileName, compileOptions); - - // Update Cache - if (loadedModuls == null) - loadedModuls = new Dictionary(); - loadedModuls[cacheId] = new WeakReference(chunk); - } - else - chunk = (LuaChunk)rc.Target; - - return chunk; - } - } - else - return null; + throw new ArgumentException(Properties.Resources.rsModuleCannotBeNull); + + int searchIndex = 1; + object oSearcher; + List loadErrors = new List(); + + LuaChunk chunkFound = null; + while (chunkFound == null && (oSearcher = searchers[searchIndex++]) != null) + { + Func searcherFunc = oSearcher as Func; + if (searcherFunc != null) + { + LuaResult searcherResult = searcherFunc(moduleName); + if(searcherResult.Values == null || searcherResult.Values.Length == 0) continue; + + //this is an error detailing why it was not loaded + if(searcherResult.Values[0] is string) + { + loadErrors.Add(searcherResult.Values[0] as string); + } + else if(searcherResult[0] is Func) + { + //custom loader + Func loader = searcherResult[0] as Func; + string extraData = (searcherResult.Values.Length > 1 ? searcherResult.Values[1] : null) as string; + LuaResult res = loader(new object [] {extraData}); + return res; + } + else if(searcherResult[0] != null) + { + loadErrors.Add(String.Format(Properties.Resources.rsUnexpectedSearcherType, searcherResult[0].GetType() )); + } + } + } + + checkedPathsOnFailed = string.Join("\n", loadErrors); + return null; } // func LuaRequire - private DateTime? LuaRequireCheckFile(ref string fileName) - { - try - { - // replace variables - if (fileName.Contains(CurrentDirectoryPathVariable)) - fileName = fileName.Replace(CurrentDirectoryPathVariable, Environment.CurrentDirectory); - if (fileName.Contains(ExecutingDirectoryPathVariable)) - fileName = fileName.Replace(ExecutingDirectoryPathVariable, System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)); - - // check if the file exists - if (!File.Exists(fileName)) - return null; - - // get the time stamp - return File.GetLastWriteTime(fileName); - } - catch (IOException) - { - return null; - } - } // func LuaRequireCheckFile - - private bool LuaRequireFindFile(string modulName, out string fileName, out DateTime stamp) + /// + /// Preloader + /// + private LuaResult LuaPreloadPackage(object oModuleName) + { + //Preloading is not supported + return new LuaResult(); + } + + /// + /// Return a chunk that looks for the already loaded package and just returns that value + /// + /// + /// + private LuaResult LuaFindUnloadedPackage(object oModuleName) + { + string moduleName = oModuleName.ToString(); + LuaResult searchResult = this.searchpath(moduleName, this.path); + if(searchResult.Values[0] == null) + { + //notfound return the searchpath as a string + return new LuaResult(searchResult.Values[1] as string); + } + else if(searchResult.Values[0] is string) + { + //found, return a result value that takes the filename + string foundFilePath = searchResult.Values[0] as string; + LuaChunk chunk = globals.Lua.CompileChunk(foundFilePath, globals.Lua.DefaultCompileOptions); + var loader = new Func( (prms) => chunk.Run(globals) ); + return new LuaResult(loader, foundFilePath); + } + else + { + //How did we get here? + throw new ApplicationException("Invalid result from searchpath"); + } + } + + #region -- package.searchpath --------------------------------------------------------- + + private LuaResult searchpath(string name, string path, string sep=";", string rep="/") { - stamp = DateTime.MinValue; - fileName = null; + if (name == null) + throw new ArgumentNullException(); + + string [] pathsToSearch = path.Split(new string[] {sep}, StringSplitOptions.None); + List pathsSearched = new List(pathsToSearch.Length); + foreach(string pathCheckWC in pathsToSearch) + { + string pathCheck = pathCheckWC.Replace("?", name); + + if(File.Exists(pathCheck)) + { + return new LuaResult(pathCheck); + } + + pathsSearched.Add(pathCheck); + } + + //No file could be found, return nil and an error containing all the paths searched (this mimics the Lua 5.3 function) + System.Text.StringBuilder sb = new System.Text.StringBuilder(); + foreach(string pathSearched in pathsSearched) + { + sb.AppendFormat(Properties.Resources.rsNoFile, pathSearched); + sb.AppendLine(); + } + return new LuaResult(null, sb.ToString()); + } // func searchpath - // replace dots blind to directory seperator, like lua it does. - if (modulName.IndexOf(System.IO.Path.DirectorySeparatorChar) >= 0) - modulName = modulName.Replace('.', System.IO.Path.DirectorySeparatorChar); - // add .lua - if (!modulName.EndsWith(".lua", StringComparison.OrdinalIgnoreCase)) - modulName += ".lua"; + #endregion - foreach (var c in paths) - { - if (String.IsNullOrEmpty(c)) - continue; - else - { - var testFileName = System.IO.Path.Combine(c, modulName); - var testStamp = LuaRequireCheckFile(ref testFileName); - if (testStamp.HasValue) - { - if (fileName == null || stamp < testStamp.Value) - { - fileName = testFileName; - stamp = testStamp.Value; - } - } - } - } + /// + public LuaTable loaded { get; private set; } = new LuaTable(); - return fileName != null; - } // func LuaRequireFindFile + /// Searchers, see https://www.lua.org/manual/5.3/manual.html#pdf-package.searchers + /// The general gist of this table is that it is used by require to set the search order of the functions + /// + public LuaTable searchers { get; private set; } = new LuaTable(); - /// - public LuaTable loaded { get; private set; } /// public string path { @@ -1540,8 +1536,7 @@ public string path /// public string[] Path => paths; - /// - public LuaCompileOptions CompileOptions { get => compileOptions; set => compileOptions = value; } + } // class LuaLibraryPackage #endregion diff --git a/NeoLua/LuaStackTraceDebugger.cs b/NeoLua/LuaStackTraceDebugger.cs index f419736..276d151 100644 --- a/NeoLua/LuaStackTraceDebugger.cs +++ b/NeoLua/LuaStackTraceDebugger.cs @@ -18,7 +18,7 @@ // under the License. // #endregion -#if !NETSTANDARD2_0 && !NETCOREAPP2_1 && !NET5_0 +#if !NETSTANDARD2_1 && !NETCOREAPP1_0_OR_GREATER using System; using System.Collections.Generic; using System.Linq.Expressions; diff --git a/NeoLua/LuaTable.cs b/NeoLua/LuaTable.cs index ad6a996..b244f98 100644 --- a/NeoLua/LuaTable.cs +++ b/NeoLua/LuaTable.cs @@ -138,9 +138,7 @@ private BindingRestrictions GetBinaryRestrictions(DynamicMetaObject arg) } // func GetBinaryRestrictions private BindingRestrictions GetLuaTableRestriction() - { - return BindingRestrictions.GetExpressionRestriction(Expression.TypeIs(Expression, typeof(LuaTable))); - } // func GetLuaTableRestriction + => BindingRestrictions.GetExpressionRestriction(Expression.TypeIs(Expression, typeof(LuaTable))); private Expression CreateSetExpresion(object binder, DynamicMetaObject value, Type typeConvertTo, ref BindingRestrictions restrictions) { @@ -637,27 +635,6 @@ public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, Dy #endregion - #region -- BindConvert ---------------------------------------------------------- - - public override DynamicMetaObject BindConvert(ConvertBinder binder) - { - // Automatic convert to a special type, only for classes and structure - var typeInfo = binder.Type.GetTypeInfo(); - if (!typeInfo.IsPrimitive && // no primitiv - !typeInfo.IsAssignableFrom(Value.GetType().GetTypeInfo()) && // not assignable by defaut - binder.Type != typeof(LuaResult)) // no result - { - return new DynamicMetaObject( - Lua.EnsureType( - Expression.Call(Lua.EnsureType(Expression, typeof(LuaTable)), Lua.TableSetObjectMemberMethodInfo, Lua.EnsureType(Expression.New(binder.Type), typeof(object))), - binder.ReturnType), - GetLuaTableRestriction()); - } - return base.BindConvert(binder); - } // func BindConvert - - #endregion - /// /// public override IEnumerable GetDynamicMemberNames() @@ -1964,16 +1941,9 @@ public object GetMemberValue(string memberName, bool ignoreCase = false, bool ra // find the member var entryIndex = FindKey(memberName, GetMemberHashCode(memberName), ignoreCase ? compareStringIgnoreCase : comparerObject); if (entryIndex < 0) - { - if (rawGet) - return null; - else - return OnIndex(memberName); - } + return rawGet ? null : OnIndex(memberName); else if (entryIndex < classDefinition.Count) - { return GetClassMemberValue(entryIndex, memberName, rawGet); - } else return entries[entryIndex].value; } // func GetMemberValue @@ -2827,33 +2797,139 @@ private LuaResult RtInvokeSiteCached(object[] args) #region -- SetObjectMember ---------------------------------------------------- - /// Sets the given object with the members of the table. - /// - public object SetObjectMember(object obj) + private static bool IsPublicMethod(MethodInfo methodInfo) + => methodInfo != null && methodInfo.IsPublic && !methodInfo.IsStatic; + + internal static bool IsIndexSetter(PropertyInfo propertyInfo) { - if (obj == null) - return obj; + var setMethod = propertyInfo.SetMethod; + if (IsPublicMethod(setMethod)) + { + var args = setMethod.GetParameters(); + return args.Length == 2 && args[0].ParameterType == typeof(int); + } + else + return false; + } // func IsIndexSetter - var type = obj.GetType(); + private bool TryGetMemberValue(string memberName, Type type, out object value) + { + value = GetMemberValue(memberName); + if (value is null) + return false; + else + { + value = Lua.RtConvertValue(value, type); + return true; + } + } // func TryGetMemberValue + + private object SetObjectArray(PropertyInfo indexProperty, object obj) + { + var idx = new object[1]; + for (var i = 1; i <= ArrayList.Count; i++) + { + idx[0] = i - 1; + indexProperty.SetValue(obj, GetArrayValue(i, rawGet: true), idx); + } + return obj; + } // proc SetObjectArray + + private object SetObjectMemberStrict(Type type, object obj) + { + foreach (var kv in Members) + { + var memberName = kv.Key; + + var memberInfo = type.GetMember(memberName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetField | BindingFlags.SetProperty).FirstOrDefault(); + switch (memberInfo) + { + case null: + throw new InvalidOperationException(String.Format(Properties.Resources.rsTableSetValueFailed, memberName, type.Name)); + case PropertyInfo pi: + pi.SetValue(obj, Lua.RtConvertValue(kv.Value, pi.PropertyType)); + break; + case FieldInfo fi: + fi.SetValue(obj, Lua.RtConvertValue(kv.Value, fi.FieldType)); + break; + case EventInfo ev: + ev.AddEventHandler(obj, (Delegate)Lua.RtConvertValue(kv.Value, ev.EventHandlerType)); + break; + } + } + // set array elements + var indexProperty = type.GetRuntimeProperties().Where(IsIndexSetter).FirstOrDefault(); + return indexProperty == null ? obj : SetObjectArray(indexProperty, obj); + } // func SetObjectMemberStrict + + private object SetObjectMemberDynamic(Type type, object obj) + { // set all fields foreach (var field in type.GetRuntimeFields().Where(fi => fi.IsPublic && !fi.IsStatic && !fi.IsInitOnly)) { - var entryIndex = FindKey(field.Name, GetMemberHashCode(field.Name), compareString); - if (entryIndex >= 0) - field.SetValue(obj, Lua.RtConvertValue(entries[entryIndex].value, field.FieldType)); + if (TryGetMemberValue(field.Name, field.FieldType, out var value)) + field.SetValue(obj, value); } // set all properties - foreach (var property in type.GetRuntimeProperties().Where(pi => pi.SetMethod != null && pi.SetMethod.IsPublic && !pi.SetMethod.IsStatic)) + foreach (var property in type.GetRuntimeProperties().Where(c => IsPublicMethod(c.SetMethod))) { - var entryIndex = FindKey(property.Name, GetMemberHashCode(property.Name), compareString); - if (entryIndex >= 0) - property.SetValue(obj, Lua.RtConvertValue(entries[entryIndex].value, property.PropertyType), null); + var arguments = property.SetMethod.GetParameters(); + if (arguments.Length == 1) + { + if (TryGetMemberValue(property.Name, property.PropertyType, out var value)) + property.SetValue(obj, value); + } + else if (arguments.Length == 2 && arguments[0].ParameterType == typeof(int)) + SetObjectArray(property, obj); + } + + // set all events + foreach (var ev in type.GetRuntimeEvents().Where(c => c.AddMethod.IsPublic && !c.AddMethod.IsStatic)) + { + if (TryGetMemberValue(ev.Name, ev.EventHandlerType, out var value)) + ev.AddEventHandler(obj, (Delegate)value); } + // set array elements return obj; - } // proc SetObjectMember + } // func SetObjectMemberDynamic + + /// Update members of an object. + /// + /// + /// Only allows to set direct declared values. + /// + public T SetObjectMember(T obj, bool strict = false) + => (T)(strict ? SetObjectMemberStrict(typeof(T), obj) : SetObjectMemberDynamic(typeof(T), obj)); + + /// Sets the given object with the members of the table. + /// + /// Only allows to set direct declared values. + /// + public object SetObjectMember(object obj, bool strict) + { + if (obj == null) + return null; + + var type = obj.GetType(); + return strict ? SetObjectMemberStrict(type, obj) : SetObjectMemberDynamic(type, obj); + } // func SetObjectMember + + /// Initialize an object with the current set of members. + /// + /// Only allows to set direct declared values. + /// The new object + public T InitObject(bool strict = false) + => SetObjectMember(Activator.CreateInstance(), strict); + + /// Initialize an object with the current set of members. + /// + /// Only allows to set direct declared values. + /// The new object + public object InitObject(Type type, bool strict = false) + => SetObjectMember(Activator.CreateInstance(type), strict); #endregion @@ -3523,7 +3599,7 @@ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() private static readonly object[] emptyObjectArray = new object[0]; private static readonly int[] emptyIntArray = new int[0]; - #region -- Table Manipulation --------------------------------------------------- + #region -- Table Manipulation ------------------------------------------------- #region -- concat -- @@ -3533,7 +3609,7 @@ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() /// /// /// - public static string concat(LuaTable t, string sep = null, Nullable i = null, Nullable j = null) + public static string concat(LuaTable t, string sep = null, int? i = null, int? j = null) { if (!i.HasValue) i = 1; @@ -3541,7 +3617,7 @@ public static string concat(LuaTable t, string sep = null, Nullable i = nul j = t.arrayLength; var r = collect(t, i.Value, j.Value, null); - return r == null ? String.Empty : String.Join(sep == null ? String.Empty : sep, r); + return r == null ? String.Empty : String.Join(sep ?? String.Empty, r); } // func concat #endregion @@ -3568,8 +3644,7 @@ public static void insert(LuaTable t, object pos, object value) else { // insert the value at the position - int index; - if (IsIndexKey(pos, out index) && index >= 1 && index <= t.arrayLength + 1) + if (IsIndexKey(pos, out var index) && index >= 1 && index <= t.arrayLength + 1) t.ArrayOnlyInsert(index - 1, value); else t.SetValue(pos, value, true); @@ -3580,21 +3655,13 @@ public static void insert(LuaTable t, object pos, object value) #region -- move -- - /// - /// - /// - /// - /// - public static void move(LuaTable t1, int f, int e, int t) - => move(t1, f, e, t, t1); - /// /// /// /// /// /// - public static void move(LuaTable t1, int f, int e, int t, LuaTable t2) + public static void move(LuaTable t1, int f, int e, int t, LuaTable t2=null) { if (f < 0) throw new ArgumentOutOfRangeException(nameof(f)); @@ -3603,6 +3670,9 @@ public static void move(LuaTable t1, int f, int e, int t, LuaTable t2) if (f > e) return; + if(t2 == null) + t2 = t1; + while (f < e) t2[t++] = t1[f++]; } // proc move @@ -3618,6 +3688,9 @@ public static void move(LuaTable t1, int f, int e, int t, LuaTable t2) /// public static LuaTable merge(LuaTable targetTable, LuaTable mergeTable, bool overwrite = true) { + if (targetTable == null) + targetTable = new LuaTable(); + foreach (var kv in mergeTable) { if (kv.Value is LuaTable m) @@ -3666,19 +3739,18 @@ public static LuaTable pack(T[] values) #region -- remove -- - /// Removes from list the last element. - /// - public static object remove(LuaTable t) - => remove(t, t.Length); - /// Removes from list the element at position pos, returning the value of the removed element. /// /// - public static object remove(LuaTable t, int pos) + public static object remove(LuaTable t, object pos=null) { object r; - int index; - if (IsIndexKey(pos, out index)) + if(pos == null) + { + pos = t.Length; + } + + if (IsIndexKey(pos, out var index)) { if (index >= 1 && index <= t.arrayLength) // remove the element and shift the follower { @@ -3703,8 +3775,8 @@ public static object remove(LuaTable t, int pos) #region -- sort -- - /////////////////////////////////////////////////////////////////////////////// - /// + #region -- class SortComparer ------------------------------------------------- + private sealed class SortComparer : IComparer { private readonly LuaTable t; @@ -3742,6 +3814,8 @@ public int Compare(object x, object y) } // func Compare } // class SortComparer + #endregion + /// /// /// @@ -3752,26 +3826,18 @@ public static void sort(LuaTable t, object sort = null) #region -- unpack -- - /// Returns the elements from the given table. - /// - /// - public static LuaResult unpack(LuaTable t) - => unpack(t, 1, t.Length); - - /// Returns the elements from the given table. - /// - /// - /// - public static LuaResult unpack(LuaTable t, int i) - => unpack(t, i, t.Length); - /// Returns the elements from the given table. /// /// /// /// - public static LuaResult unpack(LuaTable t, int i, int j) - => new LuaResult(LuaResult.CopyMode.None, unpack(t, i, j, LuaResult.Empty.Values)); + public static LuaResult unpack(LuaTable t, int i=-1, int j=-1) + { + if(i < 0) i = 1; + if(j < 0) j = t.Length; + + return new LuaResult(LuaResult.CopyMode.None, unpack(t, i, j, LuaResult.Empty.Values)); + } /// Returns the elements from the given table as a sequence. /// @@ -3784,8 +3850,8 @@ public static T[] unpack(LuaTable t, int i, int j, T[] empty) if (j < i) return empty; - T[] list = new T[j - i + 1]; - for (int k = 0; k < list.Length; k++) + var list = new T[j - i + 1]; + for (var k = 0; k < list.Length; k++) list[k] = (T)Lua.RtConvertValue(t[k + i], typeof(T)); return list; @@ -3833,8 +3899,8 @@ public static T[] collect(LuaTable t, int i, int j, T[] empty) var list = new T[j - i + 1]; // convert the values - int iLength = list.Length; - for (int k = 0; k < iLength; k++) + var l = list.Length; + for (var k = 0; k < l; k++) list[k] = (T)Lua.RtConvertValue(t.arrayList[i + k - 1], typeof(T)); return list; @@ -3846,9 +3912,9 @@ public static T[] collect(LuaTable t, int i, int j, T[] empty) // scan array part if (i <= t.arrayList.Length && j >= 1) { - int idxStart = Math.Max(i - 1, 0); - int idxEnd = Math.Min(t.arrayList.Length - 1, j - 1); - for (int k = idxStart; k <= idxEnd; k++) + var idxStart = Math.Max(i - 1, 0); + var idxEnd = Math.Min(t.arrayList.Length - 1, j - 1); + for (var k = idxStart; k <= idxEnd; k++) if (t.arrayList[k] != null) indexList.Add(new KeyValuePair(k + 1, (T)Lua.RtConvertValue(t.arrayList[k], typeof(T)))); } @@ -3858,7 +3924,7 @@ public static T[] collect(LuaTable t, int i, int j, T[] empty) { if (t.entries[k].key is int) { - int l = (int)t.entries[k].key; + var l = (int)t.entries[k].key; if (l >= i && l <= j) indexList.Add(new KeyValuePair(l, (T)Lua.RtConvertValue(t.entries[k].value, typeof(T)))); } @@ -3873,7 +3939,7 @@ public static T[] collect(LuaTable t, int i, int j, T[] empty) // create the result array var result = new T[indexList.Count]; - for (int k = 0; k < result.Length; k++) + for (var k = 0; k < result.Length; k++) result[k] = indexList[k].Value; return result; @@ -3883,6 +3949,26 @@ public static T[] collect(LuaTable t, int i, int j, T[] empty) #endregion + #region -- new, set -- + + /// Sets the given object with the members of the table. + /// + /// + /// Only allows to set direct declared values. + /// + public static object set(object obj, LuaTable t, bool strict = false) + => t.SetObjectMember(obj, strict); + + /// Initialize an object with the current set of members. + /// Only allows to set direct declared values. + /// + /// + /// The new object + public static object @new(LuaTable t, LuaType luaType, bool strict = false) + => t.InitObject(luaType.Type, strict); + + #endregion + #endregion #region -- Lua Script Object Notation -- To ----------------------------------- @@ -4684,7 +4770,7 @@ object ParseElement() ? t : new LuaTable() { [1] = r }; } // func FromJsonParse - /// + /// public static LuaTable FromJson(TextReader tr) { using (var lex = new LuaCharLexer("json", tr, 1)) diff --git a/NeoLua/LuaType.cs b/NeoLua/LuaType.cs index 06ec3de..cde6116 100644 --- a/NeoLua/LuaType.cs +++ b/NeoLua/LuaType.cs @@ -445,7 +445,7 @@ private DynamicMetaObject BindNewObject(LuaType luaType, CallInfo callInfo, Dyna constructorInfo = null; else { - constructorInfo = LuaEmit.FindMember( + constructorInfo = LuaEmit.FindMember( luaType.EnumerateMembers( LuaMethodEnumerate.Typed, declaredMembers => declaredMembers.OfType().Where(c => c.DeclaringType == type) @@ -459,7 +459,7 @@ private DynamicMetaObject BindNewObject(LuaType luaType, CallInfo callInfo, Dyna // ctor not found for a class if (constructorInfo == null && !isValueType) return new DynamicMetaObject(Lua.ThrowExpression(String.Format(Properties.Resources.rsMemberNotResolved, luaType.FullName, "ctor"), returnType), restrictions); - else // create the object + else // create the object { var expr = Lua.EnsureType( LuaEmit.BindParameter(null, @@ -470,6 +470,7 @@ private DynamicMetaObject BindNewObject(LuaType luaType, CallInfo callInfo, Dyna mo => mo.Expression, mo => mo.LimitType, false), returnType, true ); + return new DynamicMetaObject(expr, restrictions); } } // func BindNewObject @@ -860,15 +861,15 @@ private IEnumerable EnumerateMembers(bool searchStatic, Func Neo.Lua Neo.IronLua - net45;net47;netstandard2.0;netcoreapp2.1;net5.0 + net45;net47;netstandard2.1;netcoreapp3.1;net5.0 true A Lua implementation for the Dynamic Language Runtime (DLR). NeoLua diff --git a/NeoLua/Parser.Emit.cs b/NeoLua/Parser.Emit.cs index fd6d327..55d6859 100644 --- a/NeoLua/Parser.Emit.cs +++ b/NeoLua/Parser.Emit.cs @@ -198,8 +198,7 @@ private static Expression MemberSetExpressionCore(Lua lua, Token tokenStart, Exp } else { - Expression result; - switch (LuaEmit.TrySetMember(instance, instance.Type, memberName, false, (setType) => ConvertExpression(lua, tokenStart, set, setType), out result)) + switch (LuaEmit.TrySetMember(instance, instance.Type, memberName, false, (setType) => ConvertExpression(lua, tokenStart, set, setType), out var result)) { case LuaTrySetMemberReturn.None: throw ParseError(tokenStart, LuaEmitException.GetMessageText(LuaEmitException.MemberNotFound, instance.Type.Name, memberName)); @@ -346,12 +345,10 @@ private static Expression IndexSetExpression(Lua runtime, Token tStart, Expressi return SafeExpression(() => LuaEmit.SetIndex(runtime, instance, indexes, set, getExpressionFunction, getExpressionTypeFunction, true), tStart); } // func IndexSetExpression - private static Expression InvokeExpression(Scope scope, Token tStart, Expression instance, InvokeResult result, ArgumentsList arguments, bool lParse) + private static Expression InvokeExpression(Scope scope, Token tStart, Expression instance, InvokeResult result, ArgumentsList arguments) { MethodInfo mi; - ConstantExpression constInstance = instance as ConstantExpression; - LuaType t; - if (constInstance != null && (t = constInstance.Value as LuaType) != null && t.Type != null) // we have a type, bind the ctor + if (instance is ConstantExpression constInstance && constInstance.Value is LuaType t && t.Type != null) // we have a type, bind the ctor { var type = t.Type; var typeInfo = type.GetTypeInfo(); @@ -387,7 +384,7 @@ from c in arguments.Expressions select Lua.EnsureType(c, typeof(object)) (mi = instance.Type.GetRuntimeMethods().Where(c => !c.IsStatic && c.IsPublic && c.Name == "Invoke").FirstOrDefault()) != null) // Search the Invoke method for the arguments { return EnsureInvokeResult(scope, tStart, - SafeExpression(() => LuaEmit.BindParameter( + SafeExpression(() => LuaEmit.BindParameter( scope.Runtime, args => Expression.Invoke(instance, args), mi.GetParameters(), @@ -397,6 +394,13 @@ from c in arguments.Expressions select Lua.EnsureType(c, typeof(object)) result, instance, null ); } + else if (arguments.Count == 1 && typeof(LuaTable).IsAssignableFrom(arguments.FirstArgument.Type)) + { + return SafeExpression( + () => Expression.Call(arguments.FirstArgument, Lua.TableSetObjectMemberMethodInfo, instance, Expression.Constant(false, typeof(bool))) + , tStart + ); + } else throw ParseError(tStart, LuaEmitException.GetMessageText(LuaEmitException.InvokeNoDelegate, instance.Type.Name)); } // func InvokeExpression @@ -433,8 +437,7 @@ private static Expression InvokeMemberExpression(Scope scope, Token tStart, Expr return EnsureInvokeResult(scope, tStart, SafeExpression(() => { - Expression expr; - if (!LuaEmit.TryInvokeMember(scope.Runtime, LuaType.GetType(instance.Type), instance, arguments.CallInfo, arguments.Expressions, memberName, false, e => e, e => e.Type, true, out expr)) + if (!LuaEmit.TryInvokeMember(scope.Runtime, LuaType.GetType(instance.Type), instance, arguments.CallInfo, arguments.Expressions, memberName, false, e => e, e => e.Type, true, out var expr)) throw new LuaEmitException(LuaEmitException.MemberNotFound, instance.Type, memberName); return expr; }, tStart), result, instance, memberName diff --git a/NeoLua/Parser.cs b/NeoLua/Parser.cs index f53dc38..38a7c17 100644 --- a/NeoLua/Parser.cs +++ b/NeoLua/Parser.cs @@ -416,7 +416,7 @@ private sealed class ArgumentsList private readonly List arguments = new List(); private readonly List names = new List(); - private Lazy callInfo; + private readonly Lazy callInfo; public ArgumentsList(params Expression[] expr) { @@ -458,6 +458,8 @@ public CallInfo CallInfo public int Count => arguments.Count; + + public Expression FirstArgument => arguments.First(); } // class ArgumentsList #endregion @@ -474,16 +476,17 @@ public PrefixMemberInfo(Token position, Expression instance, string sMember, Exp Member = sMember; Indices = indices; Arguments = arguments; + NextInstance = null; } // ctor public Expression GenerateSet(Scope scope, Expression exprToSet) { Expression expr; - if (Instance != null && Member == null && Indices != null && Arguments == null) + if (Instance != null && Member == null && Indices != null && Arguments == null && NextInstance == null) expr = IndexSetExpression(scope.Runtime, Position, Instance, Indices, exprToSet); - else if (Instance != null && Member != null && Indices == null && Arguments == null) + else if (Instance != null && Member != null && Indices == null && Arguments == null && NextInstance == null) return MemberSetExpression(scope.Runtime, Position, Instance, Member, MethodMember, exprToSet); - else if (Instance != null && Member == null && Indices == null && Arguments == null && Instance is ParameterExpression) + else if (Instance != null && Member == null && Indices == null && Arguments == null && NextInstance == null && Instance is ParameterExpression) { // Assign the value to a variable expr = Expression.Assign(Instance, ConvertExpression(scope.Runtime, Position, exprToSet, Instance.Type)); @@ -496,7 +499,7 @@ public Expression GenerateSet(Scope scope, Expression exprToSet) public Expression GenerateGet(Scope scope, InvokeResult result) { - if (Instance != null && Member == null && Indices != null && Arguments == null) + if (Instance != null && Member == null && Indices != null && Arguments == null && NextInstance== null) { if (Indices.Length > 0) { @@ -507,7 +510,7 @@ public Expression GenerateGet(Scope scope, InvokeResult result) Instance = IndexGetExpression(scope, Position, Instance, Indices); Indices = null; } - else if (Instance != null && Member != null && Indices == null && Arguments == null && !MethodMember) + else if (Instance != null && Member != null && Indices == null && Arguments == null && NextInstance == null && !MethodMember) { // Convert the member to an instance Instance = WrapDebugInfo(scope.EmitExpressionDebug, true, Position, Position, Instance); @@ -515,11 +518,16 @@ public Expression GenerateGet(Scope scope, InvokeResult result) Member = null; MethodMember = false; } - else if (Instance != null && Member == null && Indices == null && Arguments == null) + else if (Instance != null && Member == null && Indices == null && Arguments == null && NextInstance == null) { // Nothing to todo, we have already an instance } - else if (Instance != null && Indices == null && (Arguments != null || MethodMember)) + else if (Instance != null && Member == null && Indices == null && Arguments == null && NextInstance != null) + { + Instance = NextInstance; + NextInstance = null; + } + else if (Instance != null && Indices == null && (Arguments != null || MethodMember) && NextInstance == null) { Arguments = Arguments ?? new ArgumentsList(); if (Arguments.Count > 0) @@ -531,7 +539,7 @@ public Expression GenerateGet(Scope scope, InvokeResult result) Instance = WrapDebugInfo(scope.EmitExpressionDebug, true, Position, Position, Instance); if (String.IsNullOrEmpty(Member)) - Instance = InvokeExpression(scope, Position, Instance, result, Arguments, true); + Instance = InvokeExpression(scope, Position, Instance, result, Arguments); else Instance = InvokeMemberExpression(scope, Position, Instance, Member, result, Arguments); @@ -554,6 +562,7 @@ public void SetMember(Token tMember, bool lMethod) public Token Position { get; set; } public Expression Instance { get; set; } + public Expression NextInstance { get; set; } public string Member { get; private set; } public bool MethodMember { get; private set; } public Expression[] Indices { get; set; } @@ -875,16 +884,18 @@ private static void ParseExpressionStatement(Scope scope, ILuaLexer code, bool i { ParseIdentifierAndType(scope, code, out var tVar, out var typeVar); - var exprVar = scope.LookupExpression(tVar.Value, true) as ParameterExpression; - if (exprVar == null) + if (scope.LookupExpression(tVar.Value, true) is ParameterExpression exprVar) + { + if (exprVar.Type != typeVar) + throw ParseError(tVar, Properties.Resources.rsParseTypeRedef); + } + else { exprVar = Expression.Variable(typeVar, tVar.Value); if (registerLocals == null) registerLocals = new List(); registerLocals.Add(exprVar); } - else if (exprVar.Type != typeVar) - throw ParseError(tVar, Properties.Resources.rsParseTypeRedef); prefixes.Add(new PrefixMemberInfo(tVar, exprVar, null, null, null)); } @@ -987,7 +998,7 @@ private static void ParseExpressionStatement(Scope scope, ILuaLexer code, bool i #endregion } - // Führe die restlichen Expressions aus + // Execute all remaining expressions while (expr.MoveNext()) scope.AddExpression(expr.Current); } @@ -996,7 +1007,7 @@ private static void ParseExpressionStatement(Scope scope, ILuaLexer code, bool i { for (var i = 0; i < prefixes.Count; i++) { - if (prefixes[i].Arguments == null) // do not execute getMember + if (prefixes[i].Arguments == null && prefixes[i].NextInstance == null) // do not execute getMember throw ParseError(prefixes[i].Position, Properties.Resources.rsParseAssignmentExpected); scope.AddExpression(prefixes[i].GenerateGet(scope, InvokeResult.None)); @@ -1257,7 +1268,12 @@ private static PrefixMemberInfo ParseSuffix(Scope scope, ILuaLexer code, PrefixM case LuaToken.BracketCurlyOpen: // LuaTable as an argument info.GenerateGet(scope, InvokeResult.Object); - info.Arguments = new ArgumentsList(ParseTableConstructor(scope, code)); + if (Lua.IsTypeInitializable(info.Instance.Type) && !LuaEmit.IsDynamicType(info.Instance.Type)) + { + info.NextInstance = ParseObjectConstructor(scope, code, info.Instance); + } + else + info.Arguments = new ArgumentsList(ParseTableConstructor(scope, code)); break; case LuaToken.String: // String as an argument @@ -1663,8 +1679,14 @@ private static Expression ParsePrefixCast(Scope scope, ILuaLexer code) luaType = ParseType(scope, code, true); FetchToken(LuaToken.Comma, code); - var doWrap = scope.EmitExpressionDebug; - var expr = ParseExpression(scope, code, InvokeResult.Object, ref doWrap); + Expression expr; + if (code.Current.Typ == LuaToken.BracketCurlyOpen) + expr = ParseObjectConstructor(scope, code, Expression.New(luaType.Type)); + else + { + var doWrap = scope.EmitExpressionDebug; + expr = ParseExpression(scope, code, InvokeResult.Object, ref doWrap); + } FetchToken(LuaToken.BracketClose, code); @@ -1969,8 +1991,16 @@ private static void ParseForLoop(Scope scope, ILuaLexer code) code.Next(); loopStep = ParseExpression(scope, code, InvokeResult.Object, scope.EmitExpressionDebug); } + else if (loopStart.Type == typeof(int)) + loopStep = Expression.Constant(1); + else if (loopStart.Type == typeof(long)) + loopStep = Expression.Constant(1L); + else if (loopStart.Type == typeof(float)) + loopStep = Expression.Constant(1.0f); + else if (loopStart.Type == typeof(double)) + loopStep = Expression.Constant(1.0); else - loopStep = Expression.Constant(1, loopStart.Type); + loopStep = Expression.Constant(Lua.RtConvertValue(1, loopStart.Type)); var loopScope = new LoopScope(scope); var loopVarParameter = loopScope.RegisterVariable(typeLoopVar == typeof(object) ? LuaEmit.LiftType(LuaEmit.LiftType(loopStart.Type, loopEnd.Type), loopStep.Type) : typeLoopVar, tLoopVar.Value); @@ -2141,7 +2171,8 @@ private static Expression GenerateForLoop(LoopScope loopScope, Token tStart, Lis // local tmp = f(s, var) Expression.Assign(varTmp, InvokeExpression(loopScope, tStart, varFunc, InvokeResult.LuaResult, - new ArgumentsList(varState, varVar), true) + new ArgumentsList(varState, varVar) + ) ), // var = tmp[0] @@ -2337,7 +2368,27 @@ private static void ParseLamdaDefinitionArgList(LambdaScope scope, List Expression.Call(Lua.TableSetObjectsMethod, + Expression.Convert( objectVariable, typeof(object)), + Expression.Convert(expr, typeof(object)), + Expression.Constant(i, typeof(int)) + ), tStart ) ); } else // Normal index set { scope.AddExpression( - IndexSetExpression(scope.Runtime, code.Current, tableVar, new Expression[] { Expression.Constant(iIndex++, typeof(object)) }, expr) + IndexSetExpression(scope.Runtime, code.Current, objectVariable, new Expression[] { Expression.Constant(index++, typeof(int)) }, expr) ); } } diff --git a/NeoLua/Properties/Resources.Designer.cs b/NeoLua/Properties/Resources.Designer.cs index 2d5b2a1..26e72ef 100644 --- a/NeoLua/Properties/Resources.Designer.cs +++ b/NeoLua/Properties/Resources.Designer.cs @@ -19,7 +19,7 @@ namespace Neo.IronLua.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { @@ -294,6 +294,24 @@ internal static string rsMethodStaticMix { } } + /// + /// Looks up a localized string similar to Module name cannot be null. + /// + internal static string rsModuleCannotBeNull { + get { + return ResourceManager.GetString("rsModuleCannotBeNull", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to module '{0}' not found:. + /// + internal static string rsModuleNotFound { + get { + return ResourceManager.GetString("rsModuleNotFound", resourceCulture); + } + } + /// /// Looks up a localized string similar to Can not call nil value.. /// @@ -312,6 +330,15 @@ internal static string rsNilOperatorError { } } + /// + /// Looks up a localized string similar to no file '{0}'. + /// + internal static string rsNoFile { + get { + return ResourceManager.GetString("rsNoFile", resourceCulture); + } + } + /// /// Looks up a localized string similar to No length for {0}.. /// @@ -591,6 +618,15 @@ internal static string rsTableRecursionLevelError { } } + /// + /// Looks up a localized string similar to Could not set member {1}.{0}.. + /// + internal static string rsTableSetValueFailed { + get { + return ResourceManager.GetString("rsTableSetValueFailed", resourceCulture); + } + } + /// /// Looks up a localized string similar to Name for type alias is invalid '{0}'.. /// @@ -644,5 +680,14 @@ internal static string rsTypeParseError { return ResourceManager.GetString("rsTypeParseError", resourceCulture); } } + + /// + /// Looks up a localized string similar to Unexpected searcher type: {0}. + /// + internal static string rsUnexpectedSearcherType { + get { + return ResourceManager.GetString("rsUnexpectedSearcherType", resourceCulture); + } + } } } diff --git a/NeoLua/Properties/Resources.de.resx b/NeoLua/Properties/Resources.de.resx index 119f4b6..742cf94 100644 --- a/NeoLua/Properties/Resources.de.resx +++ b/NeoLua/Properties/Resources.de.resx @@ -294,6 +294,9 @@ Tabelle ist zu tief geschachtelt. + + Member kann nicht gesetzt werden {1}.{0}. + Name für Type ist ungültig '{0}'. diff --git a/NeoLua/Properties/Resources.resx b/NeoLua/Properties/Resources.resx index 63a6681..3028339 100644 --- a/NeoLua/Properties/Resources.resx +++ b/NeoLua/Properties/Resources.resx @@ -195,12 +195,21 @@ Can not mix static and non-static methods ({0}). + + Module name cannot be null + + + module '{0}' not found: + Can not call nil value. Operator is not defined for nil-values. + + no file '{0}' + No length for {0}. @@ -294,6 +303,9 @@ Recursion level is to deep. + + Could not set member {1}.{0}. + Name for type alias is invalid '{0}'. @@ -312,4 +324,7 @@ Invalid type format for '{0}' (unexpected: {1} at {2}; expected: {3}) + + Unexpected searcher type: {0} + \ No newline at end of file