Unverified Commit a6721a31 authored by Vinicius Jarina's avatar Vinicius Jarina Committed by GitHub
Browse files

* Fixed array index (#317)

* Cache invalid method call
* Fixed array of byte, sbyte, uint, ulong, short, ushort
* Fixed explicity interface calling.
parent 57c67a9f
......@@ -22,26 +22,27 @@ namespace NLua
{
public class MetaFunctions
{
public LuaNativeFunction GcFunction { get; }
public LuaNativeFunction IndexFunction { get; }
public LuaNativeFunction NewIndexFunction { get; }
public LuaNativeFunction BaseIndexFunction { get; }
public LuaNativeFunction ClassIndexFunction { get; }
public LuaNativeFunction ClassNewIndexFunction { get; }
public LuaNativeFunction ExecuteDelegateFunction { get; }
public LuaNativeFunction CallConstructorFunction { get; }
public LuaNativeFunction ToStringFunction { get; }
public LuaNativeFunction CallDelegateFunction { get; }
public LuaNativeFunction AddFunction { get; }
public LuaNativeFunction SubtractFunction { get; }
public LuaNativeFunction MultiplyFunction { get; }
public LuaNativeFunction DivisionFunction { get; }
public LuaNativeFunction ModulosFunction { get; }
public LuaNativeFunction UnaryNegationFunction { get; }
public LuaNativeFunction EqualFunction { get; }
public LuaNativeFunction LessThanFunction { get; }
public LuaNativeFunction LessThanOrEqualFunction { get; }
public static readonly LuaNativeFunction GcFunction = CollectObject;
public static readonly LuaNativeFunction IndexFunction = GetMethod;
public static readonly LuaNativeFunction NewIndexFunction = SetFieldOrProperty;
public static readonly LuaNativeFunction BaseIndexFunction = GetBaseMethod;
public static readonly LuaNativeFunction ClassIndexFunction = GetClassMethod;
public static readonly LuaNativeFunction ClassNewIndexFunction = SetClassFieldOrProperty;
public static readonly LuaNativeFunction ExecuteDelegateFunction = RunFunctionDelegate;
public static readonly LuaNativeFunction CallConstructorFunction = CallConstructor;
public static readonly LuaNativeFunction ToStringFunction = ToStringLua;
public static readonly LuaNativeFunction CallDelegateFunction = CallDelegate;
public static readonly LuaNativeFunction CallInvalidFunction = CallInvalidMethod;
public static readonly LuaNativeFunction AddFunction = AddLua;
public static readonly LuaNativeFunction SubtractFunction = SubtractLua;
public static readonly LuaNativeFunction MultiplyFunction = MultiplyLua;
public static readonly LuaNativeFunction DivisionFunction = DivideLua;
public static readonly LuaNativeFunction ModulosFunction = ModLua;
public static readonly LuaNativeFunction UnaryNegationFunction = UnaryNegationLua;
public static readonly LuaNativeFunction EqualFunction = EqualLua;
public static readonly LuaNativeFunction LessThanFunction = LessThanLua;
public static readonly LuaNativeFunction LessThanOrEqualFunction = LessThanOrEqualLua;
readonly Dictionary<object, Dictionary<object, object>> _memberCache = new Dictionary<object, Dictionary<object, object>>();
readonly ObjectTranslator _translator;
......@@ -69,25 +70,6 @@ namespace NLua
public MetaFunctions(ObjectTranslator translator)
{
_translator = translator;
GcFunction = CollectObject;
ToStringFunction = ToStringLua;
IndexFunction = GetMethod;
NewIndexFunction = SetFieldOrProperty;
BaseIndexFunction = GetBaseMethod;
CallConstructorFunction =CallConstructor;
ClassIndexFunction = GetClassMethod;
ClassNewIndexFunction = SetClassFieldOrProperty;
ExecuteDelegateFunction = RunFunctionDelegate;
CallDelegateFunction = CallDelegate;
AddFunction = AddLua;
SubtractFunction = SubtractLua;
MultiplyFunction = MultiplyLua;
DivisionFunction = DivideLua;
ModulosFunction = ModLua;
UnaryNegationFunction = UnaryNegationLua;
EqualFunction = EqualLua;
LessThanFunction = LessThanLua;
LessThanOrEqualFunction = LessThanOrEqualLua;
}
/*
......@@ -365,14 +347,34 @@ namespace NLua
if (!string.IsNullOrEmpty(methodName) && IsMemberPresent(proxyType, methodName))
return GetMember(luaState, proxyType, obj, methodName, BindingFlags.Instance);
// Try to access by array if the type is right and index is an int (lua numbers always come across as double)
if (TryAccessByArray(luaState, objType, obj, index))
return 1;
int fallback = GetMethodFallback(luaState, objType, obj, index, methodName);
if (fallback != 0)
return fallback;
if (!string.IsNullOrEmpty(methodName))
{
return PushInvalidMethodCall(luaState, objType, methodName);
}
luaState.PushBoolean(false);
return 2;
}
private int PushInvalidMethodCall(LuaState luaState, Type type, string name)
{
var invokeDelegate = CallInvalidFunction;
SetMemberCache(type, name, invokeDelegate);
_translator.PushFunction(luaState, invokeDelegate);
_translator.Push(luaState, false);
return 2;
}
private bool TryAccessByArray(LuaState luaState,
Type objType,
object obj,
......@@ -416,6 +418,42 @@ namespace NLua
_translator.Push(luaState, arr[intIndex]);
return true;
}
if (type == typeof(byte[]))
{
byte[] arr = (byte[])obj;
_translator.Push(luaState, arr[intIndex]);
return true;
}
if (type == typeof(short[]))
{
short[] arr = (short[])obj;
_translator.Push(luaState, arr[intIndex]);
return true;
}
if (type == typeof(ushort[]))
{
ushort[] arr = (ushort[])obj;
_translator.Push(luaState, arr[intIndex]);
return true;
}
if (type == typeof(ulong[]))
{
ulong[] arr = (ulong[])obj;
_translator.Push(luaState, arr[intIndex]);
return true;
}
if (type == typeof(uint[]))
{
uint[] arr = (uint[])obj;
_translator.Push(luaState, arr[intIndex]);
return true;
}
if (type == typeof(sbyte[]))
{
sbyte[] arr = (sbyte[])obj;
_translator.Push(luaState, arr[intIndex]);
return true;
}
object[] arrObj = (object[])obj;
_translator.Push(luaState, arrObj[intIndex]);
......@@ -429,10 +467,6 @@ namespace NLua
object index,
string methodName)
{
// Try to access by array if the type is right and index is an int (lua numbers always come across as double)
if (TryAccessByArray(luaState, objType, obj, index))
return 0;
object method;
if (!string.IsNullOrEmpty(methodName) && TryGetExtensionMethod(objType, methodName, out method))
{
......@@ -484,6 +518,23 @@ namespace NLua
}
}
// Try find explicity interface implementation
MethodInfo explicitInterfaceMethod = objType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).
FirstOrDefault(m => m.Name == methodName && m.IsPrivate && m.IsVirtual && m.IsFinal);
if (explicitInterfaceMethod != null)
{
var proxyType = new ProxyType(objType);
var methodWrapper = new LuaMethodWrapper(_translator, obj, proxyType, explicitInterfaceMethod);
var invokeDelegate = new LuaNativeFunction(methodWrapper.InvokeFunction);
SetMemberCache(proxyType, methodName, invokeDelegate);
_translator.PushFunction(luaState, invokeDelegate);
_translator.Push(luaState, true);
return 2;
}
return 0;
}
......@@ -1067,6 +1118,21 @@ namespace NLua
return instance.CallDelegateInternal(luaState);
}
/*
* LuaNativeFunction called when the method wasn't found
*/
#if __IOS__ || __TVOS__ || __WATCHOS__
[MonoPInvokeCallback(typeof(LuaNativeFunction))]
#endif
static int CallInvalidMethod(IntPtr state)
{
var luaState = LuaState.FromIntPtr(state);
var translator = ObjectTranslatorPool.Instance.Find(luaState);
translator.ThrowError(luaState, "Trying to invoke invalid method");
luaState.PushNil();
return 1;
}
int CallDelegateInternal(LuaState luaState)
{
var del = _translator.GetRawNetObject(luaState, 1) as Delegate;
......
......@@ -129,16 +129,16 @@ namespace NLua
{
luaState.NewMetaTable("luaNet_searchbase");
luaState.PushString("__gc");
luaState.PushCFunction(metaFunctions.GcFunction);
luaState.PushCFunction(MetaFunctions.GcFunction);
luaState.SetTable(-3);
luaState.PushString("__tostring");
luaState.PushCFunction(metaFunctions.ToStringFunction);
luaState.PushCFunction(MetaFunctions.ToStringFunction);
luaState.SetTable(-3);
luaState.PushString("__index");
luaState.PushCFunction(metaFunctions.BaseIndexFunction);
luaState.PushCFunction(MetaFunctions.BaseIndexFunction);
luaState.SetTable(-3);
luaState.PushString("__newindex");
luaState.PushCFunction(metaFunctions.NewIndexFunction);
luaState.PushCFunction(MetaFunctions.NewIndexFunction);
luaState.SetTable(-3);
luaState.SetTop(-2);
}
......@@ -150,19 +150,19 @@ namespace NLua
{
luaState.NewMetaTable("luaNet_class");
luaState.PushString("__gc");
luaState.PushCFunction(metaFunctions.GcFunction);
luaState.PushCFunction(MetaFunctions.GcFunction);
luaState.SetTable(-3);
luaState.PushString("__tostring");
luaState.PushCFunction(metaFunctions.ToStringFunction);
luaState.PushCFunction(MetaFunctions.ToStringFunction);
luaState.SetTable(-3);
luaState.PushString("__index");
luaState.PushCFunction(metaFunctions.ClassIndexFunction);
luaState.PushCFunction(MetaFunctions.ClassIndexFunction);
luaState.SetTable(-3);
luaState.PushString("__newindex");
luaState.PushCFunction(metaFunctions.ClassNewIndexFunction);
luaState.PushCFunction(MetaFunctions.ClassNewIndexFunction);
luaState.SetTable(-3);
luaState.PushString("__call");
luaState.PushCFunction(metaFunctions.CallConstructorFunction);
luaState.PushCFunction(MetaFunctions.CallConstructorFunction);
luaState.SetTable(-3);
luaState.SetTop(-2);
}
......@@ -172,7 +172,7 @@ namespace NLua
*/
private void SetGlobalFunctions(LuaState luaState)
{
luaState.PushCFunction(metaFunctions.IndexFunction);
luaState.PushCFunction(MetaFunctions.IndexFunction);
luaState.SetGlobal("get_object_member");
luaState.PushCFunction(_importTypeFunction);
luaState.SetGlobal("import_type");
......@@ -199,10 +199,10 @@ namespace NLua
{
luaState.NewMetaTable("luaNet_function");
luaState.PushString("__gc");
luaState.PushCFunction(metaFunctions.GcFunction);
luaState.PushCFunction(MetaFunctions.GcFunction);
luaState.SetTable(-3);
luaState.PushString("__call");
luaState.PushCFunction(metaFunctions.ExecuteDelegateFunction);
luaState.PushCFunction(MetaFunctions.ExecuteDelegateFunction);
luaState.SetTable(-3);
luaState.SetTop(-2);
}
......@@ -677,13 +677,13 @@ namespace NLua
luaState.RawGet(LuaRegistry.Index);
luaState.RawSet(-3);
luaState.PushString("__gc");
luaState.PushCFunction(metaFunctions.GcFunction);
luaState.PushCFunction(MetaFunctions.GcFunction);
luaState.RawSet(-3);
luaState.PushString("__tostring");
luaState.PushCFunction(metaFunctions.ToStringFunction);
luaState.PushCFunction(MetaFunctions.ToStringFunction);
luaState.RawSet(-3);
luaState.PushString("__newindex");
luaState.PushCFunction(metaFunctions.NewIndexFunction);
luaState.PushCFunction(MetaFunctions.NewIndexFunction);
luaState.RawSet(-3);
// Bind C# operator with Lua metamethods (__add, __sub, __mul)
RegisterOperatorsFunctions(luaState, o.GetType());
......@@ -711,7 +711,7 @@ namespace NLua
return;
luaState.PushString("__call");
luaState.PushCFunction(metaFunctions.CallDelegateFunction);
luaState.PushCFunction(MetaFunctions.CallDelegateFunction);
luaState.RawSet(-3);
}
......@@ -720,55 +720,55 @@ namespace NLua
if (type.HasAdditionOperator())
{
luaState.PushString("__add");
luaState.PushCFunction(metaFunctions.AddFunction);
luaState.PushCFunction(MetaFunctions.AddFunction);
luaState.RawSet(-3);
}
if (type.HasSubtractionOperator())
{
luaState.PushString("__sub");
luaState.PushCFunction(metaFunctions.SubtractFunction);
luaState.PushCFunction(MetaFunctions.SubtractFunction);
luaState.RawSet(-3);
}
if (type.HasMultiplyOperator())
{
luaState.PushString("__mul");
luaState.PushCFunction(metaFunctions.MultiplyFunction);
luaState.PushCFunction(MetaFunctions.MultiplyFunction);
luaState.RawSet(-3);
}
if (type.HasDivisionOperator())
{
luaState.PushString("__div");
luaState.PushCFunction(metaFunctions.DivisionFunction);
luaState.PushCFunction(MetaFunctions.DivisionFunction);
luaState.RawSet(-3);
}
if (type.HasModulusOperator())
{
luaState.PushString("__mod");
luaState.PushCFunction(metaFunctions.ModulosFunction);
luaState.PushCFunction(MetaFunctions.ModulosFunction);
luaState.RawSet(-3);
}
if (type.HasUnaryNegationOperator())
{
luaState.PushString("__unm");
luaState.PushCFunction(metaFunctions.UnaryNegationFunction);
luaState.PushCFunction(MetaFunctions.UnaryNegationFunction);
luaState.RawSet(-3);
}
if (type.HasEqualityOperator())
{
luaState.PushString("__eq");
luaState.PushCFunction(metaFunctions.EqualFunction);
luaState.PushCFunction(MetaFunctions.EqualFunction);
luaState.RawSet(-3);
}
if (type.HasLessThanOperator())
{
luaState.PushString("__lt");
luaState.PushCFunction(metaFunctions.LessThanFunction);
luaState.PushCFunction(MetaFunctions.LessThanFunction);
luaState.RawSet(-3);
}
if (type.HasLessThanOrEqualOperator())
{
luaState.PushString("__le");
luaState.PushCFunction(metaFunctions.LessThanOrEqualFunction);
luaState.PushCFunction(MetaFunctions.LessThanOrEqualFunction);
luaState.RawSet(-3);
}
}
......
......@@ -14,6 +14,7 @@ using NLuaTest.TestTypes;
using NUnit.Framework;
using Lua = NLua.Lua;
using LuaFunction = NLua.LuaFunction;
using System.Diagnostics;
// ReSharper disable StringLiteralTypo
......@@ -1161,15 +1162,18 @@ namespace NLuaTest
{
using (Lua lua = new Lua())
{
var t1 = new TestTypes.TestClass();
var t1 = new TestClass();
lua["netobj"] = t1;
lua.DoString("a=netobj:foo()");
lua.DoString("b=netobj['NLuaTest.TestTypes.IFoo1.foo']");
lua.DoString("b=netobj['NLuaTest.TestTypes.IFoo1.foo']()");
int a = (int)lua.GetNumber("a");
int b = (int)lua.GetNumber("b");
Assert.AreEqual(5, a);
Assert.AreEqual(1, b);
Assert.AreEqual(5, a, "#1");
Assert.AreEqual(5, t1.foo(), "#1.1");
IFoo1 foo1 = t1;
Assert.AreEqual(3, b, "#2");
Assert.AreEqual(3, foo1.foo(), "#2.1");
}
}
/*
......@@ -2015,6 +2019,48 @@ namespace NLuaTest
}
}
[Test]
public void TestInexistentExtensionMethods()
{
using (Lua lua = new Lua())
{
lua.LoadCLRPackage();
lua.DoString(@" import ('NLuaTest', 'NLuaTest.TestTypes')
v = Vector()
v.x = 10
v.y = 3
v = v*2 ");
var sw = new Stopwatch();
sw.Start();
try
{
lua.DoString(" v:Lengthx() ");
}
catch (Exception e)
{
Console.WriteLine(e);
}
sw.Stop();
long time1 = sw.ElapsedMilliseconds;
sw.Restart();
try
{
lua.DoString(" v:Lengthx() ");
}
catch (Exception e)
{
Console.WriteLine(e);
}
sw.Stop();
long time2 = sw.ElapsedMilliseconds;
Assert.True(time2 < time1, "#1");
}
}
[Test]
public void TestBaseClassExtensionMethods()
{
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment