Commit 45b0e721 authored by Vinicius Jarina's avatar Vinicius Jarina
Browse files

[NLua] Fixed #100 HasOpertator extensions throwing AmbiguousMatchException

parent 7817d0d0
......@@ -8,22 +8,27 @@ using NLuaTest.Mock;
namespace ConsoleTest
{
struct Sub2 {
int someval;
public class Vector
{
public double x;
public double y;
public static Vector operator *(float k, Vector v)
{
var r = new Vector();
r.x = v.x * k;
r.y = v.y * k;
return r;
}
struct Sub {
public Sub2 z;
public static Vector operator * (Vector v, float k)
{
var r = new Vector ();
r.x = v.x * k;
r.y = v.y * k;
return r;
}
struct Top {
public Sub y;
}
public class Program
{
public static void func()
......@@ -41,22 +46,22 @@ namespace ConsoleTest
using (Lua lua = new Lua())
{
lua.DebugHook += DebugHook;
lua.LoadCLRPackage ();
lua.SetDebugHook (NLua.Event.EventMasks.LUA_MASKLINE, 0);
lua.DoString (@" import ('System.Numerics')
c = Complex (10, 5)
c = -c ");
var a = new System.Numerics.Complex (10, 0);
var b = new System.Numerics.Complex (10, 0);
var c = lua ["c"];
var x = a + b;
lua.DoString (@" import ('ConsoleTest')
v = Vector()
v.x = 10
v.y = 3
v = v*2
v = 3 * v
");
var v = lua ["v"];
// lua.LoadCLRPackage ();
lua ["a"] = a;
lua ["b"] = b;
var res = lua.DoString (@"return a ~= b")[0];
}
......
......@@ -23,7 +23,9 @@
* THE SOFTWARE.
*/
using System;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
namespace NLua.Extensions
{
......@@ -57,13 +59,18 @@ namespace NLua.Extensions
static class TypeExtensions
{
public static bool HasMethod (this Type t, string name)
{
var op = t.GetMethods (BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
return op.Count (m => m.Name == name) > 0;
}
public static bool HasAdditionOpertator (this Type t)
{
if (t.IsPrimitive)
return true;
var op_add = t.GetMethod ("op_Addition");
return op_add != null;
return t.HasMethod ("op_Addition");
}
public static bool HasSubtractionOpertator (this Type t)
......@@ -71,8 +78,7 @@ namespace NLua.Extensions
if (t.IsPrimitive)
return true;
var op_add = t.GetMethod ("op_Subtraction");
return op_add != null;
return t.HasMethod ("op_Subtraction");
}
public static bool HasMultiplyOpertator (this Type t)
......@@ -80,8 +86,7 @@ namespace NLua.Extensions
if (t.IsPrimitive)
return true;
var op_add = t.GetMethod ("op_Multiply");
return op_add != null;
return t.HasMethod ("op_Multiply");
}
public static bool HasDivisionOpertator (this Type t)
......@@ -89,8 +94,7 @@ namespace NLua.Extensions
if (t.IsPrimitive)
return true;
var op_add = t.GetMethod ("op_Division");
return op_add != null;
return t.HasMethod ("op_Division");
}
public static bool HasModulusOpertator (this Type t)
......@@ -98,26 +102,23 @@ namespace NLua.Extensions
if (t.IsPrimitive)
return true;
var op_add = t.GetMethod ("op_Modulus");
return op_add != null;
return t.HasMethod ("op_Modulus");
}
public static bool HasUnaryNegationOpertator (this Type t)
{
if (t.IsPrimitive)
return true;
var op_add = t.GetMethod ("op_UnaryNegation");
return op_add != null;
// Unary - will always have only one version.
var op = t.GetMethod ("op_UnaryNegation",BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
return op != null;
}
public static bool HasEqualityOpertator (this Type t)
{
if (t.IsPrimitive)
return true;
var op_add = t.GetMethod ("op_Equality");
return op_add != null;
return t.HasMethod ("op_Equality");
}
public static bool HasLessThanOpertator (this Type t)
......@@ -125,17 +126,19 @@ namespace NLua.Extensions
if (t.IsPrimitive)
return true;
var op_add = t.GetMethod ("op_LessThan");
return op_add != null;
return t.HasMethod ("op_LessThan");
}
public static bool HasLessThanOrEqualOpertator (this Type t)
{
if (t.IsPrimitive)
return true;
return t.HasMethod ("op_LessThanOrEqual");
}
var op_add = t.GetMethod ("op_LessThanOrEqual");
return op_add != null;
public static IEnumerable<MethodInfo> GetMethods (this Type t, string name, BindingFlags flags)
{
return t.GetMethods (flags).Where (m => m.Name == name);
}
}
......
......@@ -23,6 +23,7 @@
* THE SOFTWARE.
*/
using System;
using System.Linq;
using System.IO;
using System.Collections;
using System.Reflection;
......@@ -187,6 +188,7 @@ namespace NLua
return 1;
}
/*
* __add metafunction of CLR objects.
*/
......@@ -197,30 +199,7 @@ namespace NLua
static int AddLua (LuaState luaState)
{
var translator = ObjectTranslatorPool.Instance.Find (luaState);
return AddLua (luaState, translator);
}
static int AddLua (LuaState luaState, ObjectTranslator translator)
{
object obj1 = translator.GetRawNetObject (luaState, 1);
object obj2 = translator.GetRawNetObject (luaState, 2);
if (obj1 == null || obj2 == null) {
translator.ThrowError (luaState, "Cannot add a nil object");
LuaLib.LuaPushNil (luaState);
return 1;
}
Type type = obj1.GetType ();
MethodInfo opAddition = type.GetMethod ("op_Addition");
if (opAddition == null) {
translator.ThrowError (luaState, "Cannot add object (" + type.Name+ " does not overload the operator +)");
LuaLib.LuaPushNil (luaState);
return 1;
}
obj1 = opAddition.Invoke (obj1, new object[] { obj1, obj2 });
translator.Push (luaState, obj1);
return 1;
return MatchOperator (luaState, "op_Addition", translator);
}
/*
......@@ -233,30 +212,7 @@ namespace NLua
static int SubtractLua (LuaState luaState)
{
var translator = ObjectTranslatorPool.Instance.Find (luaState);
return SubtractLua (luaState, translator);
}
static int SubtractLua (LuaState luaState, ObjectTranslator translator)
{
object obj1 = translator.GetRawNetObject (luaState, 1);
object obj2 = translator.GetRawNetObject (luaState, 2);
if (obj1 == null || obj2 == null) {
translator.ThrowError (luaState, "Cannot subtract a nil object");
LuaLib.LuaPushNil (luaState);
return 1;
}
Type type = obj1.GetType ();
MethodInfo opSubtract = type.GetMethod ("op_Subtraction");
if (opSubtract == null) {
translator.ThrowError (luaState, "Cannot subtract object (" + type.Name + " does not overload the operator -)");
LuaLib.LuaPushNil (luaState);
return 1;
}
obj1 = opSubtract.Invoke (obj1, new object [] { obj1, obj2 });
translator.Push (luaState, obj1);
return 1;
return MatchOperator (luaState, "op_Multiply", translator);
}
/*
......@@ -269,30 +225,7 @@ namespace NLua
static int MultiplyLua (LuaState luaState)
{
var translator = ObjectTranslatorPool.Instance.Find (luaState);
return MultiplyLua (luaState, translator);
}
static int MultiplyLua (LuaState luaState, ObjectTranslator translator)
{
object obj1 = translator.GetRawNetObject (luaState, 1);
object obj2 = translator.GetRawNetObject (luaState, 2);
if (obj1 == null || obj2 == null) {
translator.ThrowError (luaState, "Cannot multiply a nil object");
LuaLib.LuaPushNil (luaState);
return 1;
}
Type type = obj1.GetType ();
MethodInfo opMultiply = type.GetMethod ("op_Multiply");
if (opMultiply == null) {
translator.ThrowError (luaState, "Cannot multiply object (" + type.Name + " does not overload the operator *)");
LuaLib.LuaPushNil (luaState);
return 1;
}
obj1 = opMultiply.Invoke (obj1, new object [] { obj1, obj2 });
translator.Push (luaState, obj1);
return 1;
return MatchOperator (luaState, "op_Multiply", translator);
}
/*
......@@ -305,30 +238,7 @@ namespace NLua
static int DivideLua (LuaState luaState)
{
var translator = ObjectTranslatorPool.Instance.Find (luaState);
return DivideLua (luaState, translator);
}
static int DivideLua (LuaState luaState, ObjectTranslator translator)
{
object obj1 = translator.GetRawNetObject (luaState, 1);
object obj2 = translator.GetRawNetObject (luaState, 2);
if (obj1 == null || obj2 == null) {
translator.ThrowError (luaState, "Cannot divide a nil object");
LuaLib.LuaPushNil (luaState);
return 1;
}
Type type = obj1.GetType ();
MethodInfo opDivide = type.GetMethod ("op_Division");
if (opDivide == null) {
translator.ThrowError (luaState, "Cannot divide object (" + type.Name + " does not overload the operator /)");
LuaLib.LuaPushNil (luaState);
return 1;
}
obj1 = opDivide.Invoke (obj1, new object [] { obj1, obj2 });
translator.Push (luaState, obj1);
return 1;
return MatchOperator (luaState, "op_Division", translator);
}
/*
......@@ -341,30 +251,7 @@ namespace NLua
static int ModLua (LuaState luaState)
{
var translator = ObjectTranslatorPool.Instance.Find (luaState);
return ModLua (luaState, translator);
}
static int ModLua (LuaState luaState, ObjectTranslator translator)
{
object obj1 = translator.GetRawNetObject (luaState, 1);
object obj2 = translator.GetRawNetObject (luaState, 2);
if (obj1 == null || obj2 == null) {
translator.ThrowError (luaState, "Cannot mod a nil object");
LuaLib.LuaPushNil (luaState);
return 1;
}
Type type = obj1.GetType ();
MethodInfo opMod = type.GetMethod ("op_Modulus");
if (opMod == null) {
translator.ThrowError (luaState, "Cannot mod object (" + type.Name + " does not overload the operator %)");
LuaLib.LuaPushNil (luaState);
return 1;
}
obj1 = opMod.Invoke (obj1, new object [] { obj1, obj2 });
translator.Push (luaState, obj1);
return 1;
return MatchOperator (luaState, "op_Modulus", translator);
}
/*
......@@ -413,32 +300,8 @@ namespace NLua
static int EqualLua (LuaState luaState)
{
var translator = ObjectTranslatorPool.Instance.Find (luaState);
return EqualLua (luaState, translator);
return MatchOperator (luaState, "op_Equality", translator);
}
static int EqualLua (LuaState luaState, ObjectTranslator translator)
{
object obj1 = translator.GetRawNetObject (luaState, 1);
object obj2 = translator.GetRawNetObject (luaState, 2);
if (obj1 == null || obj2 == null) {
translator.ThrowError (luaState, "Cannot compare a nil object");
LuaLib.LuaPushNil (luaState);
return 1;
}
Type type = obj1.GetType ();
MethodInfo opEqual = type.GetMethod ("op_Equality");
if (opEqual == null) {
translator.ThrowError (luaState, "Cannot compare object (" + type.Name + " does not overload the operator =)");
LuaLib.LuaPushNil (luaState);
return 1;
}
obj1 = opEqual.Invoke (obj1, new object [] { obj1, obj2 });
translator.Push (luaState, obj1);
return 1;
}
/*
* __lt metafunction of CLR objects.
......@@ -450,30 +313,7 @@ namespace NLua
static int LessThanLua (LuaState luaState)
{
var translator = ObjectTranslatorPool.Instance.Find (luaState);
return LessThanLua (luaState, translator);
}
static int LessThanLua (LuaState luaState, ObjectTranslator translator)
{
object obj1 = translator.GetRawNetObject (luaState, 1);
object obj2 = translator.GetRawNetObject (luaState, 2);
if (obj1 == null || obj2 == null) {
translator.ThrowError (luaState, "Cannot compare a nil object");
LuaLib.LuaPushNil (luaState);
return 1;
}
Type type = obj1.GetType ();
MethodInfo opLessThan = type.GetMethod ("op_LessThan");
if (opLessThan == null) {
translator.ThrowError (luaState, "Cannot compare object (" + type.Name + " does not overload the operator <)");
LuaLib.LuaPushNil (luaState);
return 1;
}
obj1 = opLessThan.Invoke (obj1, new object [] { obj1, obj2 });
translator.Push (luaState, obj1);
return 1;
return MatchOperator (luaState, "op_LessThan", translator);
}
/*
......@@ -486,30 +326,7 @@ namespace NLua
static int LessThanOrEqualLua (LuaState luaState)
{
var translator = ObjectTranslatorPool.Instance.Find (luaState);
return LessThanOrEqualLua (luaState, translator);
}
static int LessThanOrEqualLua (LuaState luaState, ObjectTranslator translator)
{
object obj1 = translator.GetRawNetObject (luaState, 1);
object obj2 = translator.GetRawNetObject (luaState, 2);
if (obj1 == null || obj2 == null) {
translator.ThrowError (luaState, "Cannot compare a nil object");
LuaLib.LuaPushNil (luaState);
return 1;
}
Type type = obj1.GetType ();
MethodInfo opLessThanOrEqual = type.GetMethod ("op_LessThanOrEqual");
if (opLessThanOrEqual == null) {
translator.ThrowError (luaState, "Cannot compare object (" + type.Name + " does not overload the operator <=)");
LuaLib.LuaPushNil (luaState);
return 1;
}
obj1 = opLessThanOrEqual.Invoke (obj1, new object [] { obj1, obj2 });
translator.Push (luaState, obj1);
return 1;
return MatchOperator (luaState, "op_LessThanOrEqual", translator);
}
/// <summary>
......@@ -1170,10 +987,64 @@ namespace NLua
LuaLib.LuaPushNil (luaState);
return 1;
}
private static bool IsInteger(double x) {
static bool IsInteger(double x) {
return Math.Ceiling(x) == x;
}
static object GetTargetObject (LuaState luaState, string operation, ObjectTranslator translator)
{
Type t;
object target = translator.GetRawNetObject (luaState, 1);
if (target != null) {
t = target.GetType ();
if (t.HasMethod (operation))
return target;
}
target = translator.GetRawNetObject (luaState, 2);
if (target != null) {
t = target.GetType ();
if (t.HasMethod (operation))
return target;
}
return null;
}
static int MatchOperator (LuaState luaState, string operation, ObjectTranslator translator)
{
var validOperator = new MethodCache ();
object target = GetTargetObject (luaState, operation, translator);
if (target == null) {
translator.ThrowError (luaState, "Cannot call " + operation + " on a nil object");
LuaLib.LuaPushNil (luaState);
return 1;
}
Type type = target.GetType ();
var operators = type.GetMethods (operation, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
foreach (var op in operators) {
bool isOk = translator.MatchParameters (luaState, op, ref validOperator);
if (!isOk)
continue;
object result;
if (op.IsStatic)
result = op.Invoke (null, validOperator.args);
else
result = op.Invoke (target, validOperator.args);
translator.Push (luaState, result);
return 1;
}
translator.ThrowError (luaState, "Cannot call (" + operation + ") on object type " + type.Name);
LuaLib.LuaPushNil (luaState);
return 1;
}
internal Array TableToArray (Func<int, object> luaParamValueExtractor, Type paramArrayType, int startIndex, int count)
{
......@@ -1226,7 +1097,7 @@ namespace NLua
/*
* Matches a method against its arguments in the Lua stack. Returns
* if the match was succesful. It it was also returns the information
* if the match was successful. It it was also returns the information
* necessary to invoke the method.
*/
internal bool MatchParameters (LuaState luaState, MethodBase method, ref MethodCache methodCache)
......@@ -1306,7 +1177,6 @@ namespace NLua
methodCache.outList = outList.ToArray ();
methodCache.argTypes = argTypes.ToArray ();
}
return isMethod;
}
......
......@@ -34,6 +34,30 @@ namespace NLuaTest
}
}
#if MONOTOUCH
[Preserve (AllMembers = true)]
#endif
public class Vector
{
public double x;
public double y;
public static Vector operator * (float k, Vector v)
{
var r = new Vector ();
r.x = v.x * k;
r.y = v.y * k;
return r;
}
public static Vector operator * (Vector v, float k)
{
var r = new Vector ();
r.x = v.x * k;
r.y = v.y * k;
return r;
}
}
[TestFixture]
#if MONOTOUCH
[Preserve (AllMembers = true)]
......@@ -2047,6 +2071,31 @@ namespace NLuaTest
}
}
[Test]
public void TestStaticOperators ()
{
using (Lua lua = new Lua ()) {
lua.LoadCLRPackage ();
lua.DoString (@" import ('NLuaTest')
v = Vector()
v.x = 10
v.y = 3
v = v*2 ");
var v = (Vector)lua ["v"];
Assert.AreEqual (20, v.x, "#1");
Assert.AreEqual (6, v.y, "#2");
lua.DoString (@" x = 2 * v");
var x = (Vector)lua ["x"];
Assert.AreEqual (40, x.x, "#3");
Assert.AreEqual (12, x.y, "#4");
}
}
}
......
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