Commit 27e4f04c authored by Vinicius Jarina's avatar Vinicius Jarina
Browse files

Fixed call delegate functions.

Automatically register metamethod __call for delegate types.
+ Unit tests.
parent d7f1849b
......@@ -10,14 +10,17 @@ using NLuaTest;
namespace ConsoleTest
{
public class Program
{
static void Main (string [] args)
{
Core c = new Core ();
c.Setup ();
c.Sieve ();
using (var l = new Lua ()) {
Action c = () => { Console.WriteLine ("Ola"); };
l ["d"] = c;
l.DoString (" d () ");
}
}
}
}
......@@ -61,6 +61,7 @@ namespace NLua
public LuaNativeFunction ExecuteDelegateFunction { get; private set; }
public LuaNativeFunction CallConstructorFunction { get; private set; }
public LuaNativeFunction ToStringFunction { get; private set; }
public LuaNativeFunction CallDelegateFunction { get; private set; }
public LuaNativeFunction AddFunction { get; private set; }
public LuaNativeFunction SubtractFunction { get; private set; }
......@@ -109,6 +110,7 @@ namespace NLua
ClassIndexFunction = new LuaNativeFunction (MetaFunctions.GetClassMethod);
ClassNewindexFunction = new LuaNativeFunction (MetaFunctions.SetClassFieldOrProperty);
ExecuteDelegateFunction = new LuaNativeFunction (MetaFunctions.RunFunctionDelegate);
CallDelegateFunction = new LuaNativeFunction (MetaFunctions.CallDelegate);
AddFunction = new LuaNativeFunction (MetaFunctions.AddLua);
SubtractFunction = new LuaNativeFunction (MetaFunctions.SubtractLua);
MultiplyFunction = new LuaNativeFunction (MetaFunctions.MultiplyLua);
......@@ -605,7 +607,16 @@ namespace NLua
SetMemberCache (memberCache, objType, methodName, member);
try {
translator.Push (luaState, field.GetValue (obj));
var value = field.GetValue (obj);
if (!(value is Delegate)) {
translator.Push (luaState, value);
} else {
Delegate del = (Delegate)value;
var wrapper = new LuaNativeFunction ((new LuaMethodWrapper (translator, del.Target, objType, del.Method)).invokeFunction);
translator.PushFunction (luaState, wrapper);
translator.Push (luaState, true);
return 2;
}
} catch {
LuaLib.LuaPushNil (luaState);
}
......@@ -619,8 +630,16 @@ namespace NLua
SetMemberCache (memberCache, objType, methodName, member);
try {
object val = property.GetValue (obj, null);
translator.Push (luaState, val);
object value = property.GetValue (obj, null);
if (!(value is Delegate)) {
translator.Push (luaState, value);
} else {
Delegate del = (Delegate)value;
var wrapper = new LuaNativeFunction ((new LuaMethodWrapper (translator, del.Target, objType, del.Method)).invokeFunction);
translator.PushFunction (luaState, wrapper);
translator.Push (luaState, true);
return 2;
}
} catch (ArgumentException) {
// If we can't find the getter in our class, recurse up to the base class and see
// if they can help.
......@@ -1006,6 +1025,53 @@ namespace NLua
return SetMember (luaState, target, null, BindingFlags.Static);
}
/*
* __call metafunction of Delegates.
*/
#if MONOTOUCH
[MonoTouch.MonoPInvokeCallback (typeof (LuaNativeFunction))]
#endif
static int CallDelegate (LuaState luaState)
{
var translator = ObjectTranslatorPool.Instance.Find (luaState);
var instance = translator.MetaFunctionsInstance;
return instance.CallDelegateInternal (luaState);
}
int CallDelegateInternal (LuaState luaState)
{
object objDelegate = translator.GetRawNetObject (luaState, 1);
if (objDelegate == null || !(objDelegate is Delegate)) {
translator.ThrowError (luaState, "trying to invoke a not delegate or callable value");
LuaLib.LuaPushNil (luaState);
return 1;
}
LuaLib.LuaRemove (luaState, 1);
var validDelegate = new MethodCache ();
Delegate del = (Delegate)objDelegate;
MethodBase methodDelegate = del.Method;
bool isOk = MatchParameters (luaState, methodDelegate, ref validDelegate);
if (isOk) {
object result;
if (methodDelegate.IsStatic)
result = methodDelegate.Invoke (null, validDelegate.args);
else
result = methodDelegate.Invoke (del.Target, validDelegate.args);
translator.Push (luaState, result);
return 1;
}
translator.ThrowError (luaState, "Cannot invoke delegate (invalid arguments for " + methodDelegate.Name + ")");
LuaLib.LuaPushNil (luaState);
return 1;
}
/*
* __call metafunction of type references. Searches for and calls
* a constructor for the type. Returns nil if the constructor is not
......
......@@ -571,6 +571,7 @@ namespace NLua
PushObject (luaState, func, "luaNet_function");
}
/*
* Pushes a CLR object into the Lua stack as an userdata
* with the provided metatable
......@@ -651,6 +652,7 @@ namespace NLua
LuaLib.LuaRawSet (luaState, -3);
// Bind C# operator with Lua metamethods (__add, __sub, __mul)
RegisterOperatorsFunctions (luaState, o.GetType ());
RegisterCallMethodForDelegate (luaState, o);
}
} else
LuaLib.LuaLGetMetatable (luaState, metatable);
......@@ -667,6 +669,16 @@ namespace NLua
LuaLib.LuaRemove (luaState, -2);
}
void RegisterCallMethodForDelegate (LuaState luaState, object o)
{
if (!(o is Delegate))
return;
LuaLib.LuaPushString (luaState, "__call");
LuaLib.LuaPushStdCallCFunction (luaState, metaFunctions.CallDelegateFunction);
LuaLib.LuaRawSet (luaState, -3);
}
void RegisterOperatorsFunctions (LuaState luaState, Type type)
{
if (type.HasAdditionOpertator ()) {
......
......@@ -45,6 +45,14 @@ namespace NLuaTest
}
}
#if MONOTOUCH
[Preserve (AllMembers = true)]
#endif
public class DefaultElementModel
{
public Action<double> DrawMe{ get; set; }
}
#if MONOTOUCH
[Preserve (AllMembers = true)]
#endif
......@@ -2239,6 +2247,68 @@ namespace NLuaTest
}
}
[Test]
public void TestPushLuaFunctionWhenReadingDelegateProperty ()
{
bool called = false;
var _model = new DefaultElementModel ();
_model.DrawMe = (x) => {
called = true;
};
using (var l = new Lua ()) {
l ["model"] = _model;
l.DoString (@" model.DrawMe (0) ");
}
Assert.True (called);
}
[Test]
public void TestCallDelegateWithParameters ()
{
string sval = "";
int nval = 0;
using (var l = new Lua ()) {
Action<string,int> c = (s, n) => { sval = s; nval = n; };
l ["d"] = c;
l.DoString (" d ('string', 10) ");
}
Assert.AreEqual ("string", sval, "#1");
Assert.AreEqual (10 , nval, "#2");
}
[Test]
public void TestCallSimpleDelegate ()
{
bool called = false;
using (var l = new Lua ()) {
Action c = () => { called = true; };
l ["d"] = c;
l.DoString (" d () ");
}
Assert.True (called);
}
[Test]
public void TestCallDelegateWithWrongParametersShouldFail ()
{
bool fail = false;
using (var l = new Lua ()) {
Action c = () => { fail = false; };
l ["d"] = c;
try {
l.DoString (" d (10) ");
}
catch (LuaScriptException e) {
fail = true;
}
}
Assert.True (fail);
}
static Lua m_lua;
}
......
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