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 ...@@ -22,26 +22,27 @@ namespace NLua
{ {
public class MetaFunctions public class MetaFunctions
{ {
public LuaNativeFunction GcFunction { get; } public static readonly LuaNativeFunction GcFunction = CollectObject;
public LuaNativeFunction IndexFunction { get; } public static readonly LuaNativeFunction IndexFunction = GetMethod;
public LuaNativeFunction NewIndexFunction { get; } public static readonly LuaNativeFunction NewIndexFunction = SetFieldOrProperty;
public LuaNativeFunction BaseIndexFunction { get; } public static readonly LuaNativeFunction BaseIndexFunction = GetBaseMethod;
public LuaNativeFunction ClassIndexFunction { get; } public static readonly LuaNativeFunction ClassIndexFunction = GetClassMethod;
public LuaNativeFunction ClassNewIndexFunction { get; } public static readonly LuaNativeFunction ClassNewIndexFunction = SetClassFieldOrProperty;
public LuaNativeFunction ExecuteDelegateFunction { get; } public static readonly LuaNativeFunction ExecuteDelegateFunction = RunFunctionDelegate;
public LuaNativeFunction CallConstructorFunction { get; } public static readonly LuaNativeFunction CallConstructorFunction = CallConstructor;
public LuaNativeFunction ToStringFunction { get; } public static readonly LuaNativeFunction ToStringFunction = ToStringLua;
public LuaNativeFunction CallDelegateFunction { get; } public static readonly LuaNativeFunction CallDelegateFunction = CallDelegate;
public static readonly LuaNativeFunction CallInvalidFunction = CallInvalidMethod;
public LuaNativeFunction AddFunction { get; }
public LuaNativeFunction SubtractFunction { get; } public static readonly LuaNativeFunction AddFunction = AddLua;
public LuaNativeFunction MultiplyFunction { get; } public static readonly LuaNativeFunction SubtractFunction = SubtractLua;
public LuaNativeFunction DivisionFunction { get; } public static readonly LuaNativeFunction MultiplyFunction = MultiplyLua;
public LuaNativeFunction ModulosFunction { get; } public static readonly LuaNativeFunction DivisionFunction = DivideLua;
public LuaNativeFunction UnaryNegationFunction { get; } public static readonly LuaNativeFunction ModulosFunction = ModLua;
public LuaNativeFunction EqualFunction { get; } public static readonly LuaNativeFunction UnaryNegationFunction = UnaryNegationLua;
public LuaNativeFunction LessThanFunction { get; } public static readonly LuaNativeFunction EqualFunction = EqualLua;
public LuaNativeFunction LessThanOrEqualFunction { get; } 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 Dictionary<object, Dictionary<object, object>> _memberCache = new Dictionary<object, Dictionary<object, object>>();
readonly ObjectTranslator _translator; readonly ObjectTranslator _translator;
...@@ -69,25 +70,6 @@ namespace NLua ...@@ -69,25 +70,6 @@ namespace NLua
public MetaFunctions(ObjectTranslator translator) public MetaFunctions(ObjectTranslator translator)
{ {
_translator = 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 ...@@ -365,14 +347,34 @@ namespace NLua
if (!string.IsNullOrEmpty(methodName) && IsMemberPresent(proxyType, methodName)) if (!string.IsNullOrEmpty(methodName) && IsMemberPresent(proxyType, methodName))
return GetMember(luaState, proxyType, obj, methodName, BindingFlags.Instance); 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); int fallback = GetMethodFallback(luaState, objType, obj, index, methodName);
if (fallback != 0) if (fallback != 0)
return fallback; return fallback;
if (!string.IsNullOrEmpty(methodName))
{
return PushInvalidMethodCall(luaState, objType, methodName);
}
luaState.PushBoolean(false); luaState.PushBoolean(false);
return 2; 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, private bool TryAccessByArray(LuaState luaState,
Type objType, Type objType,
object obj, object obj,
...@@ -416,6 +418,42 @@ namespace NLua ...@@ -416,6 +418,42 @@ namespace NLua
_translator.Push(luaState, arr[intIndex]); _translator.Push(luaState, arr[intIndex]);
return true; 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; object[] arrObj = (object[])obj;
_translator.Push(luaState, arrObj[intIndex]); _translator.Push(luaState, arrObj[intIndex]);
...@@ -429,10 +467,6 @@ namespace NLua ...@@ -429,10 +467,6 @@ namespace NLua
object index, object index,
string methodName) 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; object method;
if (!string.IsNullOrEmpty(methodName) && TryGetExtensionMethod(objType, methodName, out method)) if (!string.IsNullOrEmpty(methodName) && TryGetExtensionMethod(objType, methodName, out method))
{ {
...@@ -484,6 +518,23 @@ namespace NLua ...@@ -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; return 0;
} }
...@@ -1067,6 +1118,21 @@ namespace NLua ...@@ -1067,6 +1118,21 @@ namespace NLua
return instance.CallDelegateInternal(luaState); 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) int CallDelegateInternal(LuaState luaState)
{ {
var del = _translator.GetRawNetObject(luaState, 1) as Delegate; var del = _translator.GetRawNetObject(luaState, 1) as Delegate;
......
...@@ -129,16 +129,16 @@ namespace NLua ...@@ -129,16 +129,16 @@ namespace NLua
{ {
luaState.NewMetaTable("luaNet_searchbase"); luaState.NewMetaTable("luaNet_searchbase");
luaState.PushString("__gc"); luaState.PushString("__gc");
luaState.PushCFunction(metaFunctions.GcFunction); luaState.PushCFunction(MetaFunctions.GcFunction);
luaState.SetTable(-3); luaState.SetTable(-3);
luaState.PushString("__tostring"); luaState.PushString("__tostring");
luaState.PushCFunction(metaFunctions.ToStringFunction); luaState.PushCFunction(MetaFunctions.ToStringFunction);
luaState.SetTable(-3); luaState.SetTable(-3);
luaState.PushString("__index"); luaState.PushString("__index");
luaState.PushCFunction(metaFunctions.BaseIndexFunction); luaState.PushCFunction(MetaFunctions.BaseIndexFunction);
luaState.SetTable(-3); luaState.SetTable(-3);
luaState.PushString("__newindex"); luaState.PushString("__newindex");
luaState.PushCFunction(metaFunctions.NewIndexFunction); luaState.PushCFunction(MetaFunctions.NewIndexFunction);
luaState.SetTable(-3); luaState.SetTable(-3);
luaState.SetTop(-2); luaState.SetTop(-2);
} }
...@@ -150,19 +150,19 @@ namespace NLua ...@@ -150,19 +150,19 @@ namespace NLua
{ {
luaState.NewMetaTable("luaNet_class"); luaState.NewMetaTable("luaNet_class");
luaState.PushString("__gc"); luaState.PushString("__gc");
luaState.PushCFunction(metaFunctions.GcFunction); luaState.PushCFunction(MetaFunctions.GcFunction);
luaState.SetTable(-3); luaState.SetTable(-3);
luaState.PushString("__tostring"); luaState.PushString("__tostring");
luaState.PushCFunction(metaFunctions.ToStringFunction); luaState.PushCFunction(MetaFunctions.ToStringFunction);
luaState.SetTable(-3); luaState.SetTable(-3);
luaState.PushString("__index"); luaState.PushString("__index");
luaState.PushCFunction(metaFunctions.ClassIndexFunction); luaState.PushCFunction(MetaFunctions.ClassIndexFunction);
luaState.SetTable(-3); luaState.SetTable(-3);
luaState.PushString("__newindex"); luaState.PushString("__newindex");
luaState.PushCFunction(metaFunctions.ClassNewIndexFunction); luaState.PushCFunction(MetaFunctions.ClassNewIndexFunction);
luaState.SetTable(-3); luaState.SetTable(-3);
luaState.PushString("__call"); luaState.PushString("__call");
luaState.PushCFunction(metaFunctions.CallConstructorFunction); luaState.PushCFunction(MetaFunctions.CallConstructorFunction);
luaState.SetTable(-3); luaState.SetTable(-3);
luaState.SetTop(-2); luaState.SetTop(-2);
} }
...@@ -172,7 +172,7 @@ namespace NLua ...@@ -172,7 +172,7 @@ namespace NLua
*/ */
private void SetGlobalFunctions(LuaState luaState) private void SetGlobalFunctions(LuaState luaState)
{ {
luaState.PushCFunction(metaFunctions.IndexFunction); luaState.PushCFunction(MetaFunctions.IndexFunction);
luaState.SetGlobal("get_object_member"); luaState.SetGlobal("get_object_member");
luaState.PushCFunction(_importTypeFunction); luaState.PushCFunction(_importTypeFunction);
luaState.SetGlobal("import_type"); luaState.SetGlobal("import_type");
...@@ -199,10 +199,10 @@ namespace NLua ...@@ -199,10 +199,10 @@ namespace NLua
{ {
luaState.NewMetaTable("luaNet_function"); luaState.NewMetaTable("luaNet_function");
luaState.PushString("__gc"); luaState.PushString("__gc");
luaState.PushCFunction(metaFunctions.GcFunction); luaState.PushCFunction(MetaFunctions.GcFunction);
luaState.SetTable(-3); luaState.SetTable(-3);
luaState.PushString("__call"); luaState.PushString("__call");
luaState.PushCFunction(metaFunctions.ExecuteDelegateFunction); luaState.PushCFunction(MetaFunctions.ExecuteDelegateFunction);
luaState.SetTable(-3); luaState.SetTable(-3);
luaState.SetTop(-2); luaState.SetTop(-2);
} }
...@@ -677,13 +677,13 @@ namespace NLua ...@@ -677,13 +677,13 @@ namespace NLua
luaState.RawGet(LuaRegistry.Index); luaState.RawGet(LuaRegistry.Index);
luaState.RawSet(-3); luaState.RawSet(-3);
luaState.PushString("__gc"); luaState.PushString("__gc");
luaState.PushCFunction(metaFunctions.GcFunction); luaState.PushCFunction(MetaFunctions.GcFunction);
luaState.RawSet(-3); luaState.RawSet(-3);
luaState.PushString("__tostring"); luaState.PushString("__tostring");
luaState.PushCFunction(metaFunctions.ToStringFunction); luaState.PushCFunction(MetaFunctions.ToStringFunction);
luaState.RawSet(-3); luaState.RawSet(-3);
luaState.PushString("__newindex"); luaState.PushString("__newindex");
luaState.PushCFunction(metaFunctions.NewIndexFunction); luaState.PushCFunction(MetaFunctions.NewIndexFunction);
luaState.RawSet(-3); luaState.RawSet(-3);
// Bind C# operator with Lua metamethods (__add, __sub, __mul) // Bind C# operator with Lua metamethods (__add, __sub, __mul)
RegisterOperatorsFunctions(luaState, o.GetType()); RegisterOperatorsFunctions(luaState, o.GetType());
...@@ -711,7 +711,7 @@ namespace NLua ...@@ -711,7 +711,7 @@ namespace NLua
return; return;
luaState.PushString("__call"); luaState.PushString("__call");
luaState.PushCFunction(metaFunctions.CallDelegateFunction); luaState.PushCFunction(MetaFunctions.CallDelegateFunction);
luaState.RawSet(-3); luaState.RawSet(-3);
} }
...@@ -720,55 +720,55 @@ namespace NLua ...@@ -720,55 +720,55 @@ namespace NLua
if (type.HasAdditionOperator()) if (type.HasAdditionOperator())
{ {
luaState.PushString("__add"); luaState.PushString("__add");
luaState.PushCFunction(metaFunctions.AddFunction); luaState.PushCFunction(MetaFunctions.AddFunction);
luaState.RawSet(-3); luaState.RawSet(-3);
} }
if (type.HasSubtractionOperator()) if (type.HasSubtractionOperator())
{ {
luaState.PushString("__sub"); luaState.PushString("__sub");
luaState.PushCFunction(metaFunctions.SubtractFunction); luaState.PushCFunction(MetaFunctions.SubtractFunction);
luaState.RawSet(-3); luaState.RawSet(-3);
} }
if (type.HasMultiplyOperator()) if (type.HasMultiplyOperator())
{ {
luaState.PushString("__mul"); luaState.PushString("__mul");
luaState.PushCFunction(metaFunctions.MultiplyFunction); luaState.PushCFunction(MetaFunctions.MultiplyFunction);
luaState.RawSet(-3); luaState.RawSet(-3);
} }
if (type.HasDivisionOperator()) if (type.HasDivisionOperator())
{ {
luaState.PushString("__div"); luaState.PushString("__div");
luaState.PushCFunction(metaFunctions.DivisionFunction); luaState.PushCFunction(MetaFunctions.DivisionFunction);
luaState.RawSet(-3); luaState.RawSet(-3);
} }
if (type.HasModulusOperator()) if (type.HasModulusOperator())
{ {
luaState.PushString("__mod"); luaState.PushString("__mod");
luaState.PushCFunction(metaFunctions.ModulosFunction); luaState.PushCFunction(MetaFunctions.ModulosFunction);
luaState.RawSet(-3); luaState.RawSet(-3);
} }
if (type.HasUnaryNegationOperator()) if (type.HasUnaryNegationOperator())
{ {
luaState.PushString("__unm"); luaState.PushString("__unm");
luaState.PushCFunction(metaFunctions.UnaryNegationFunction); luaState.PushCFunction(MetaFunctions.UnaryNegationFunction);
luaState.RawSet(-3); luaState.RawSet(-3);
} }
if (type.HasEqualityOperator()) if (type.HasEqualityOperator())
{ {
luaState.PushString("__eq"); luaState.PushString("__eq");
luaState.PushCFunction(metaFunctions.EqualFunction); luaState.PushCFunction(MetaFunctions.EqualFunction);
luaState.RawSet(-3); luaState.RawSet(-3);
} }
if (type.HasLessThanOperator()) if (type.HasLessThanOperator())
{ {
luaState.PushString("__lt"); luaState.PushString("__lt");
luaState.PushCFunction(metaFunctions.LessThanFunction); luaState.PushCFunction(MetaFunctions.LessThanFunction);
luaState.RawSet(-3); luaState.RawSet(-3);
} }
if (type.HasLessThanOrEqualOperator()) if (type.HasLessThanOrEqualOperator())
{ {
luaState.PushString("__le"); luaState.PushString("__le");
luaState.PushCFunction(metaFunctions.LessThanOrEqualFunction); luaState.PushCFunction(MetaFunctions.LessThanOrEqualFunction);
luaState.RawSet(-3); luaState.RawSet(-3);
} }
} }
......
...@@ -14,6 +14,7 @@ using NLuaTest.TestTypes; ...@@ -14,6 +14,7 @@ using NLuaTest.TestTypes;
using NUnit.Framework; using NUnit.Framework;
using Lua = NLua.Lua; using Lua = NLua.Lua;
using LuaFunction = NLua.LuaFunction; using LuaFunction = NLua.LuaFunction;
using System.Diagnostics;
// ReSharper disable StringLiteralTypo // ReSharper disable StringLiteralTypo
...@@ -1161,15 +1162,18 @@ namespace NLuaTest ...@@ -1161,15 +1162,18 @@ namespace NLuaTest
{ {
using (Lua lua = new Lua()) using (Lua lua = new Lua())
{ {
var t1 = new TestTypes.TestClass(); var t1 = new TestClass();
lua["netobj"] = t1; lua["netobj"] = t1;
lua.DoString("a=netobj:foo()"); 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 a = (int)lua.GetNumber("a");
int b = (int)lua.GetNumber("b"); int b = (int)lua.GetNumber("b");
Assert.AreEqual(5, a); Assert.AreEqual(5, a, "#1");
Assert.AreEqual(1, b); 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 ...@@ -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] [Test]
public void TestBaseClassExtensionMethods() 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