Commit 00eddcac authored by Megax's avatar Megax
Browse files

* Kisebb modositasok.

parent a0afbf36
......@@ -277,8 +277,6 @@ namespace KopiLua
public static int lua_rawequal (lua_State L, int index1, int index2) {
StkId o1 = index2adr(L, index1);
StkId o2 = index2adr(L, index2);
Console.WriteLine("lua_rawequal: {0}", (o1 == luaO_nilobject || o2 == luaO_nilobject));
Console.WriteLine("lua_rawequal2: {0}", luaO_rawequalObj(o1, o2));
return (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0
: luaO_rawequalObj(o1, o2);
}
......@@ -392,11 +390,10 @@ namespace KopiLua
public static uint lua_touserdata2 (lua_State L, int idx) {
StkId o = index2adr(L, idx);
Console.WriteLine("x0:{0}", o);
switch (ttype(o)) {
case LUA_TUSERDATA: Console.WriteLine("x:{0}", rawuvalue(o).len); return (rawuvalue(o).len);
case LUA_TLIGHTUSERDATA: Console.WriteLine("x2:{0}", rawuvalue(o).len); return (rawuvalue(o).len);
default: Console.WriteLine("x3:{0}", 0); return 0;
case LUA_TUSERDATA: return (rawuvalue(o).len);
case LUA_TLIGHTUSERDATA: return (rawuvalue(o).len);
default: return 0;
}
}
......@@ -556,7 +553,6 @@ namespace KopiLua
}
public static void lua_getfield (lua_State L, int idx, CharPtr k) {
Console.WriteLine("lllll:{0}", k);
StkId t;
TValue key = new TValue();
lua_lock(L);
......@@ -624,7 +620,6 @@ namespace KopiLua
res = 1;
}
lua_unlock(L);
Console.WriteLine("nulllll: {0}", res);
return res;
}
......@@ -835,7 +830,6 @@ namespace KopiLua
api_checkvalidindex(L, o);
func = savestack(L, o);
}
Console.WriteLine("func:{0}", func);
c.func = L.top - (nargs+1); /* function to be called */
c.nresults = nresults;
status = luaD_pcall(L, f_call, c, savestack(L, c.func), func);
......
......@@ -758,7 +758,6 @@ namespace KopiLua
public static int luaO_rawequalObj (TValue t1, TValue t2) {
Console.WriteLine("luaO_rawequalObj: {0}", ttype(t1) != ttype(t2));
if (ttype(t1) != ttype(t2)) return 0;
else switch (ttype(t1)) {
case LUA_TNIL:
......@@ -771,9 +770,6 @@ namespace KopiLua
return pvalue(t1) == pvalue(t2) ? 1 : 0;
default:
lua_assert(iscollectable(t1));
Console.WriteLine("luaO_rawequalObj1-0: {0}", gcvalue(t1));
Console.WriteLine("luaO_rawequalObj1-1: {0}", gcvalue(t2));
Console.WriteLine("luaO_rawequalObj1: {0}", gcvalue(t1) == gcvalue(t2));
return gcvalue(t1) == gcvalue(t2) ? 1 : 0;
}
}
......
......@@ -107,7 +107,6 @@ namespace KopiLua
}
//return newlstr(L, str, l, h); /* not found */
TString res = newlstr(L, str, l, h);
Console.WriteLine(res);
return res;
}
......
......@@ -237,11 +237,8 @@ namespace LuaInterface
public object[] DoFile(string fileName)
{
int oldTop=KopiLua.Lua.lua_gettop(luaState);
//Console.WriteLine("aaa: {0}",oldTop);
if(KopiLua.Lua.luaL_loadfile(luaState,fileName)==0)
{
//Console.WriteLine("aaa2: {0}",KopiLua.Lua.lua_pcall(luaState, 0, -1, 0));
//Console.WriteLine("zzzzzzzzzzzzzzzzzz");
if (KopiLua.Lua.lua_pcall(luaState, 0, -1, 0) == 0)
return translator.popValues(luaState, oldTop);
else
......@@ -348,7 +345,8 @@ namespace LuaInterface
public LuaFunction GetFunction(string fullPath)
{
object obj=this[fullPath];
return (obj is KopiLua.Lua.lua_CFunction ? new LuaFunction((KopiLua.Lua.lua_CFunction)obj,this) : (LuaFunction)obj);
//return (obj is KopiLua.Lua.lua_CFunction ? new LuaFunction((KopiLua.Lua.lua_CFunction)obj,this) : (LuaFunction)obj);
return (obj is KopiLua.Lua.lua_CFunction ? new LuaFunction((KopiLua.Lua.lua_CFunction)obj,this) : /*(LuaFunction)*/new LuaFunction(obj.GetHashCode(), this));
}
/*
* Gets a function global variable as a delegate of
......@@ -533,7 +531,7 @@ namespace LuaInterface
* Registers an object's method as a Lua function (global or table field)
* The method may have any signature
*/
public LuaFunction RegisterFunction(string path, object target,MethodInfo function)
public LuaFunction RegisterFunction(string path, object target,MethodInfo function)
{
// We leave nothing on the stack when we are done
int oldTop = KopiLua.Lua.lua_gettop(luaState);
......@@ -545,7 +543,6 @@ namespace LuaInterface
LuaFunction f = GetFunction(path);
KopiLua.Lua.lua_settop(luaState, oldTop);
return f;
}
......
......@@ -270,7 +270,7 @@ namespace LuaWrap
public static int luanet_rawnetobj(Lua.lua_State luaState,int obj)
{
int udata= Convert.ToInt32(Lua.lua_touserdata2(luaState, obj));
int udata= (int)Lua.lua_touserdata2(luaState, obj);
if(udata!=0)
return udata;
return -1;
......@@ -284,25 +284,19 @@ namespace LuaWrap
public static int checkudata_raw(Lua.lua_State luaState, int ud, string tname)
{
int p = (int)Lua.lua_touserdata2(luaState, ud);
Console.WriteLine("z:{0}", p);
if(p != 0)
{
/* value is a userdata? */
Console.WriteLine("z0:{0}", p);
//Console.WriteLine("z2:{0}", Lua.lua_getmetatable(luaState, ud));
if(Lua.lua_getmetatable(luaState, ud)!=0)
{
/* does it have a metatable? */
Console.WriteLine("z1:{0}", p);
Lua.lua_getfield(luaState, (int)PseudoIndex.Registry, tname); /* get correct metatable */
//Console.WriteLine("z3:{0}", p);
bool isEqual = Lua.lua_rawequal(luaState, -1, -2).ToBoolean();
Console.WriteLine("z2:{0}", p);
Console.WriteLine("z2-1:{0}", isEqual);
// NASTY - we need our own version of the lua_pop macro
// lua_pop(L, 2); /* remove both metatables */
Lua.lua_settop(luaState, -(2) - 1);
Console.WriteLine("z3:{0}", p);
if(isEqual) /* does it have the correct mt? */
return p;
}
......@@ -330,29 +324,23 @@ Console.WriteLine("z3:{0}", p);
{
int udata;
Console.WriteLine("asd:"+(Lua.lua_type(luaState, index).ToLuaType() == LuaType.UserData).ToString());
Console.WriteLine("asd:1"+Lua.lua_type(luaState, index));
if(Lua.lua_type(luaState, index).ToLuaType() == LuaType.UserData)
{
if(luaL_checkmetatable(luaState, index))
{
udata = (int)Lua.lua_touserdata2(luaState, index);
Console.WriteLine("asd0:{0}",udata);
if(udata != 0)
return udata;
}
udata = checkudata_raw(luaState, index, "luaNet_class");
Console.WriteLine("asd2:{0}",udata);
if(udata != 0)
return udata;
udata = checkudata_raw(luaState, index, "luaNet_searchbase");
Console.WriteLine("asd3:{0}",udata);
if(udata != 0)
return udata;
udata = checkudata_raw(luaState, index, "luaNet_function");
Console.WriteLine("asd4:{0}",udata);
if(udata != 0)
return udata;
}
......
namespace LuaInterface
{
using System;
using System.IO;
using System.Collections;
using System.Reflection;
using System.Diagnostics;
using System.Collections.Generic;
using LuaWrap;
using System.Runtime.InteropServices;
/*
* Functions used in the metatables of userdata representing
* CLR objects
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
class MetaFunctions
{
/*
* __index metafunction for CLR objects. Implemented in Lua.
*/
internal static string luaIndexFunction =
"local function index(obj,name)\n" +
" local meta=getmetatable(obj)\n" +
" local cached=meta.cache[name]\n" +
" if cached~=nil then\n" +
" return cached\n" +
" else\n" +
" local value,isFunc=get_object_member(obj,name)\n" +
" if isFunc then\n" +
" meta.cache[name]=value\n" +
" end\n" +
" return value\n" +
" end\n" +
"end\n" +
"return index";
private ObjectTranslator translator;
private Hashtable memberCache = new Hashtable();
internal KopiLua.Lua.lua_CFunction gcFunction, indexFunction, newindexFunction,
baseIndexFunction, classIndexFunction, classNewindexFunction,
execDelegateFunction, callConstructorFunction, toStringFunction;
public MetaFunctions(ObjectTranslator translator)
{
this.translator = translator;
gcFunction = new KopiLua.Lua.lua_CFunction(this.collectObject);
toStringFunction = new KopiLua.Lua.lua_CFunction(this.toString);
indexFunction = new KopiLua.Lua.lua_CFunction(this.getMethod);
newindexFunction = new KopiLua.Lua.lua_CFunction(this.setFieldOrProperty);
baseIndexFunction = new KopiLua.Lua.lua_CFunction(this.getBaseMethod);
callConstructorFunction = new KopiLua.Lua.lua_CFunction(this.callConstructor);
classIndexFunction = new KopiLua.Lua.lua_CFunction(this.getClassMethod);
classNewindexFunction = new KopiLua.Lua.lua_CFunction(this.setClassFieldOrProperty);
execDelegateFunction = new KopiLua.Lua.lua_CFunction(this.runFunctionDelegate);
}
/*
* __call metafunction of CLR delegates, retrieves and calls the delegate.
*/
private int runFunctionDelegate(KopiLua.Lua.lua_State luaState)
{
KopiLua.Lua.lua_CFunction func = (KopiLua.Lua.lua_CFunction)translator.getRawNetObject(luaState, 1);
KopiLua.Lua.lua_remove(luaState, 1);
return func(luaState);
}
/*
* __gc metafunction of CLR objects.
*/
private int collectObject(KopiLua.Lua.lua_State luaState)
{
int udata = LuaLib.luanet_rawnetobj(luaState, 1);
if (udata != -1)
{
translator.collectObject(udata);
}
else
{
// Debug.WriteLine("not found: " + udata);
}
return 0;
}
/*
* __tostring metafunction of CLR objects.
*/
private int toString(KopiLua.Lua.lua_State luaState)
{
object obj = translator.getRawNetObject(luaState, 1);
if (obj != null)
{
translator.push(luaState, obj.ToString() + ": " + obj.GetHashCode());
}
else KopiLua.Lua.lua_pushnil(luaState);
return 1;
}
/// <summary>
/// Debug tool to dump the lua stack
/// </summary>
/// FIXME, move somewhere else
public static void dumpStack(ObjectTranslator translator, KopiLua.Lua.lua_State luaState)
{
int depth = KopiLua.Lua.lua_gettop(luaState);
Debug.WriteLine("lua stack depth: " + depth);
for (int i = 1; i <= depth; i++)
{
LuaType type = KopiLua.Lua.lua_type(luaState, i).ToLuaType();
// we dump stacks when deep in calls, calling typename while the stack is in flux can fail sometimes, so manually check for key types
string typestr = (type == LuaType.Table) ? "table" : KopiLua.Lua.lua_typename(luaState, Convert.ToInt32(type)).ToString();
string strrep = KopiLua.Lua.lua_tostring(luaState, i).ToString();
if (type == LuaType.UserData)
{
object obj = translator.getRawNetObject(luaState, i);
strrep = obj.ToString();
}
Debug.Print("{0}: ({1}) {2}", i, typestr, strrep);
}
}
/*
* Called by the __index metafunction of CLR objects in case the
* method is not cached or it is a field/property/event.
* Receives the object and the member name as arguments and returns
* either the value of the member or a delegate to call it.
* If the member does not exist returns nil.
*/
private int getMethod(KopiLua.Lua.lua_State luaState)
{
object obj = translator.getRawNetObject(luaState, 1);
if (obj == null)
{
translator.throwError(luaState, "trying to index an invalid object reference");
KopiLua.Lua.lua_pushnil(luaState);
return 1;
}
object index = translator.getObject(luaState, 2);
//Type indexType = index.GetType();
string methodName = index as string; // will be null if not a string arg
Type objType = obj.GetType();
// Handle the most common case, looking up the method by name
if (methodName != null && isMemberPresent(objType, methodName))
return getMember(luaState, objType, 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 (objType.IsArray && index is double)
{
object[] arr = (object[])obj;
translator.push(luaState, arr[(int)((double)index)]);
}
else
{
// Try to use get_Item to index into this .net object
MethodInfo getter = objType.GetMethod("get_Item");
ParameterInfo[] actualParms = (getter != null) ? getter.GetParameters() : null;
if (actualParms == null || actualParms.Length != 1)
{
translator.throwError(luaState, "method not found (or no indexer): " + index);
KopiLua.Lua.lua_pushnil(luaState);
}
else
{
// Get the index in a form acceptable to the getter
index = translator.getAsType(luaState, 2, actualParms[0].ParameterType);
object[] args = new object[1];
// Just call the indexer - if out of bounds an exception will happen
args[0] = index;
try
{
object result = getter.Invoke(obj, args);
translator.push(luaState, result);
}
catch (TargetInvocationException e)
{
// Provide a more readable description for the common case of key not found
if(e.InnerException is KeyNotFoundException)
translator.throwError(luaState, "key '" + index + "' not found ");
else
translator.throwError(luaState, "exception indexing '" + index + "' " + e.Message);
KopiLua.Lua.lua_pushnil(luaState);
}
}
}
KopiLua.Lua.lua_pushboolean(luaState, 0);
return 2;
}
/*
* __index metafunction of base classes (the base field of Lua tables).
* Adds a prefix to the method name to call the base version of the method.
*/
private int getBaseMethod(KopiLua.Lua.lua_State luaState)
{
object obj = translator.getRawNetObject(luaState, 1);
if (obj == null)
{
translator.throwError(luaState, "trying to index an invalid object reference");
KopiLua.Lua.lua_pushnil(luaState);
KopiLua.Lua.lua_pushboolean(luaState, 0);
return 2;
}
string methodName = KopiLua.Lua.lua_tostring(luaState, 2).ToString();
if (methodName == null)
{
KopiLua.Lua.lua_pushnil(luaState);
KopiLua.Lua.lua_pushboolean(luaState, 0);
return 2;
}
getMember(luaState, obj.GetType(), obj, "__luaInterface_base_" + methodName, BindingFlags.Instance);
KopiLua.Lua.lua_settop(luaState, -2);
if (KopiLua.Lua.lua_type(luaState, -1).ToLuaType() == LuaType.Nil)
{
KopiLua.Lua.lua_settop(luaState, -2);
return getMember(luaState, obj.GetType(), obj, methodName, BindingFlags.Instance);
}
KopiLua.Lua.lua_pushboolean(luaState, 0);
return 2;
}
/// <summary>
/// Does this method exist as either an instance or static?
/// </summary>
/// <param name="objType"></param>
/// <param name="methodName"></param>
/// <returns></returns>
bool isMemberPresent(IReflect objType, string methodName)
{
object cachedMember = checkMemberCache(memberCache, objType, methodName);
if (cachedMember != null)
return true;
MemberInfo[] members = objType.GetMember(methodName, BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
return (members.Length > 0);
}
/*
* Pushes the value of a member or a delegate to call it, depending on the type of
* the member. Works with static or instance members.
* Uses reflection to find members, and stores the reflected MemberInfo object in
* a cache (indexed by the type of the object and the name of the member).
*/
private int getMember(KopiLua.Lua.lua_State luaState, IReflect objType, object obj, string methodName, BindingFlags bindingType)
{
bool implicitStatic = false;
MemberInfo member = null;
object cachedMember = checkMemberCache(memberCache, objType, methodName);
//object cachedMember=null;
if (cachedMember is KopiLua.Lua.lua_CFunction)
{
translator.pushFunction(luaState, (KopiLua.Lua.lua_CFunction)cachedMember);
translator.push(luaState, true);
return 2;
}
else if (cachedMember != null)
{
member = (MemberInfo)cachedMember;
}
else
{
MemberInfo[] members = objType.GetMember(methodName, bindingType | BindingFlags.Public | BindingFlags.NonPublic);
if (members.Length > 0)
member = members[0];
else
{
// If we can't find any suitable instance members, try to find them as statics - but we only want to allow implicit static
// lookups for fields/properties/events -kevinh
members = objType.GetMember(methodName, bindingType | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
if (members.Length > 0)
{
member = members[0];
implicitStatic = true;
}
}
}
if (member != null)
{
if (member.MemberType == MemberTypes.Field)
{
FieldInfo field = (FieldInfo)member;
if (cachedMember == null) setMemberCache(memberCache, objType, methodName, member);
try
{
translator.push(luaState, field.GetValue(obj));
}
catch
{
KopiLua.Lua.lua_pushnil(luaState);
}
}
else if (member.MemberType == MemberTypes.Property)
{
PropertyInfo property = (PropertyInfo)member;
if (cachedMember == null) setMemberCache(memberCache, objType, methodName, member);
try
{
object val = property.GetValue(obj, null);
translator.push(luaState, val);
}
catch (ArgumentException)
{
// If we can't find the getter in our class, recurse up to the base class and see
// if they can help.
if (objType is Type && !(((Type)objType) == typeof(object)))
return getMember(luaState, ((Type)objType).BaseType, obj, methodName, bindingType);
else
KopiLua.Lua.lua_pushnil(luaState);
}
catch(TargetInvocationException e) // Convert this exception into a Lua error
{
ThrowError(luaState, e);
KopiLua.Lua.lua_pushnil(luaState);
}
}
else if (member.MemberType == MemberTypes.Event)
{
EventInfo eventInfo = (EventInfo)member;
if (cachedMember == null) setMemberCache(memberCache, objType, methodName, member);
translator.push(luaState, new RegisterEventHandler(translator.pendingEvents, obj, eventInfo));
}
else if(!implicitStatic)
{
if (member.MemberType == MemberTypes.NestedType)
{
// kevinh - added support for finding nested types
// cache us
if (cachedMember == null) setMemberCache(memberCache, objType, methodName, member);
// Find the name of our class
string name = member.Name;
Type dectype = member.DeclaringType;
// Build a new long name and try to find the type by name
string longname = dectype.FullName + "+" + name;
Type nestedType = translator.FindType(longname);
translator.pushType(luaState, nestedType);
}
else
{
// Member type must be 'method'
KopiLua.Lua.lua_CFunction wrapper = new KopiLua.Lua.lua_CFunction((new LuaMethodWrapper(translator, objType, methodName, bindingType)).call);
if (cachedMember == null) setMemberCache(memberCache, objType, methodName, wrapper);
translator.pushFunction(luaState, wrapper);
translator.push(luaState, true);
return 2;
}
}
else
{
// If we reach this point we found a static method, but can't use it in this context because the user passed in an instance
translator.throwError(luaState, "can't pass instance to static method " + methodName);
KopiLua.Lua.lua_pushnil(luaState);
}
}
else
{
// kevinh - we want to throw an exception because meerly returning 'nil' in this case
// is not sufficient. valid data members may return nil and therefore there must be some
// way to know the member just doesn't exist.
translator.throwError(luaState, "unknown member name " + methodName);
KopiLua.Lua.lua_pushnil(luaState);
}
// push false because we are NOT returning a function (see luaIndexFunction)
translator.push(luaState, false);
return 2;
}
/*
* Checks if a MemberInfo object is cached, returning it or null.
*/
private object checkMemberCache(Hashtable memberCache, IReflect objType, string memberName)
{
Hashtable members = (Hashtable)memberCache[objType];
if (members != null)
return members[memberName];
else
return null;
}
/*
* Stores a MemberInfo object in the member cache.
*/
private void setMemberCache(Hashtable memberCache, IReflect objType, string memberName, object member)
{
Hashtable members = (Hashtable)memberCache[objType];
if (members == null)
{
members = new Hashtable();
memberCache[objType] = members;
}
members[memberName] = member;
}
/*
* __newindex metafunction of CLR objects. Receives the object,
* the member name and the value to be stored as arguments. Throws
* and error if the assignment is invalid.
*/
private int setFieldOrProperty(KopiLua.Lua.lua_State luaState)
{
object target = translator.getRawNetObject(luaState, 1);
if (target == null)
{
translator.throwError(luaState, "trying to index and invalid object reference");
return 0;
}
Type type = target.GetType();
// First try to look up the parameter as a property name
string detailMessage;
bool didMember = trySetMember(luaState, type, target, BindingFlags.Instance, out detailMessage);
if (didMember)
return 0; // Must have found the property name
// We didn't find a property name, now see if we can use a [] style this accessor to set array contents
try
{
if (type.IsArray && KopiLua.Lua.lua_isnumber(luaState, 2).ToBoolean())
{
int index = (int)KopiLua.Lua.lua_tonumber(luaState, 2);
Array arr = (Array)target;
object val = translator.getAsType(luaState, 3, arr.GetType().GetElementType());
arr.SetValue(val, index);
}
else
{
// Try to see if we have a this[] accessor
MethodInfo setter = type.GetMethod("set_Item");
if (setter != null)
{
ParameterInfo[] args = setter.GetParameters();
Type valueType = args[1].ParameterType;
// The new val ue the user specified
object val = translator.getAsType(luaState, 3, valueType);
Type indexType = args[0].ParameterType;
object index = translator.getAsType(luaState, 2, indexType);
object[] methodArgs = new object[2];
// Just call the indexer - if out of bounds an exception will happen
methodArgs[0] = index;
methodArgs[1] = val;
setter.Invoke(target, methodArgs);
}
else
{
translator.throwError(luaState, detailMessage); // Pass the original message from trySetMember because it is probably best
}
}
}
catch (SEHException)
{
// If we are seeing a C++ exception - this must actually be for Lua's private use. Let it handle it
throw;
}
catch (Exception e)
{
ThrowError(luaState, e);
}
return 0;
}
/// <summary>
/// Tries to set a named property or field
/// </summary>
/// <param name="luaState"></param>
/// <param name="targetType"></param>
/// <param name="target"></param>
/// <param name="bindingType"></param>
/// <returns>false if unable to find the named member, true for success</returns>
private bool trySetMember(KopiLua.Lua.lua_State luaState, IReflect targetType, object target, BindingFlags bindingType, out string detailMessage)
{
detailMessage = null; // No error yet
// If not already a string just return - we don't want to call tostring - which has the side effect of
// changing the lua typecode to string
// Note: We don't use isstring because the standard lua C isstring considers either strings or numbers to
// be true for isstring.
if (KopiLua.Lua.lua_type(luaState, 2).ToLuaType() != LuaType.String)
{
detailMessage = "property names must be strings";
return false;
}
// We only look up property names by string
string fieldName = KopiLua.Lua.lua_tostring(luaState, 2).ToString();
if (fieldName == null || fieldName.Length < 1 || !(char.IsLetter(fieldName[0]) || fieldName[0] == '_'))
{
detailMessage = "invalid property name";
return false;
}
// Find our member via reflection or the cache
MemberInfo member = (MemberInfo)checkMemberCache(memberCache, targetType, fieldName);
if (member == null)
{
MemberInfo[] members = targetType.GetMember(fieldName, bindingType | BindingFlags.Public | BindingFlags.NonPublic);
if (members.Length > 0)
{
member = members[0];
setMemberCache(memberCache, targetType, fieldName, member);
}
else
{
detailMessage = "field or property '" + fieldName + "' does not exist";
return false;
}
}
if (member.MemberType == MemberTypes.Field)
{
FieldInfo field = (FieldInfo)member;
object val = translator.getAsType(luaState, 3, field.FieldType);
try
{
field.SetValue(target, val);
}
catch (Exception e)
{
ThrowError(luaState, e);
}
// We did a call
return true;
}
else if (member.MemberType == MemberTypes.Property)
{
PropertyInfo property = (PropertyInfo)member;
object val = translator.getAsType(luaState, 3, property.PropertyType);
try
{
property.SetValue(target, val, null);
}
catch (Exception e)
{
ThrowError(luaState, e);
}
// We did a call
return true;
}
detailMessage = "'" + fieldName + "' is not a .net field or property";
return false;
}
/*
* Writes to fields or properties, either static or instance. Throws an error
* if the operation is invalid.
*/
private int setMember(KopiLua.Lua.lua_State luaState, IReflect targetType, object target, BindingFlags bindingType)
{
string detail;
bool success = trySetMember(luaState, targetType, target, bindingType, out detail);
if(!success)
translator.throwError(luaState, detail);
return 0;
}
/// <summary>
/// Convert a C# exception into a Lua error
/// </summary>
/// <param name="e"></param>
/// We try to look into the exception to give the most meaningful description
void ThrowError(KopiLua.Lua.lua_State luaState, Exception e)
{
// If we got inside a reflection show what really happened
TargetInvocationException te = e as TargetInvocationException;
if (te != null)
e = te.InnerException;
translator.throwError(luaState, e);
}
/*
* __index metafunction of type references, works on static members.
*/
private int getClassMethod(KopiLua.Lua.lua_State luaState)
{
IReflect klass;
object obj = translator.getRawNetObject(luaState, 1);
if (obj == null || !(obj is IReflect))
{
translator.throwError(luaState, "trying to index an invalid type reference");
KopiLua.Lua.lua_pushnil(luaState);
return 1;
}
else klass = (IReflect)obj;
if (KopiLua.Lua.lua_isnumber(luaState, 2).ToBoolean())
{
int size = (int)KopiLua.Lua.lua_tonumber(luaState, 2);
translator.push(luaState, Array.CreateInstance(klass.UnderlyingSystemType, size));
return 1;
}
else
{
string methodName = KopiLua.Lua.lua_tostring(luaState, 2).ToString();
if (methodName == null)
{
KopiLua.Lua.lua_pushnil(luaState);
return 1;
}
else return getMember(luaState, klass, null, methodName, BindingFlags.FlattenHierarchy | BindingFlags.Static);
}
}
/*
* __newindex function of type references, works on static members.
*/
private int setClassFieldOrProperty(KopiLua.Lua.lua_State luaState)
{
IReflect target;
object obj = translator.getRawNetObject(luaState, 1);
if (obj == null || !(obj is IReflect))
{
translator.throwError(luaState, "trying to index an invalid type reference");
return 0;
}
else target = (IReflect)obj;
return setMember(luaState, target, null, BindingFlags.FlattenHierarchy | BindingFlags.Static);
}
/*
* __call metafunction of type references. Searches for and calls
* a constructor for the type. Returns nil if the constructor is not
* found or if the arguments are invalid. Throws an error if the constructor
* generates an exception.
*/
private int callConstructor(KopiLua.Lua.lua_State luaState)
{
MethodCache validConstructor = new MethodCache();
IReflect klass;
object obj = translator.getRawNetObject(luaState, 1);
if (obj == null || !(obj is IReflect))
{
translator.throwError(luaState, "trying to call constructor on an invalid type reference");
KopiLua.Lua.lua_pushnil(luaState);
return 1;
}
else klass = (IReflect)obj;
KopiLua.Lua.lua_remove(luaState, 1);
ConstructorInfo[] constructors = klass.UnderlyingSystemType.GetConstructors();
foreach (ConstructorInfo constructor in constructors)
{
bool isConstructor = matchParameters(luaState, constructor, ref validConstructor);
if (isConstructor)
{
try
{
translator.push(luaState, constructor.Invoke(validConstructor.args));
}
catch (TargetInvocationException e)
{
ThrowError(luaState, e);
KopiLua.Lua.lua_pushnil(luaState);
}
catch
{
KopiLua.Lua.lua_pushnil(luaState);
}
return 1;
}
}
string constructorName = (constructors.Length == 0) ? "unknown" : constructors[0].Name;
translator.throwError(luaState, String.Format("{0} does not contain constructor({1}) argument match",
klass.UnderlyingSystemType,
constructorName));
KopiLua.Lua.lua_pushnil(luaState);
return 1;
}
/*
* Matches a method against its arguments in the Lua stack. Returns
* if the match was succesful. It it was also returns the information
* necessary to invoke the method.
*/
internal bool matchParameters(KopiLua.Lua.lua_State luaState, MethodBase method, ref MethodCache methodCache)
{
ExtractValue extractValue;
bool isMethod = true;
ParameterInfo[] paramInfo = method.GetParameters();
int currentLuaParam = 1;
int nLuaParams = KopiLua.Lua.lua_gettop(luaState);
ArrayList paramList = new ArrayList();
List<int> outList = new List<int>();
List<MethodArgs> argTypes = new List<MethodArgs>();
foreach (ParameterInfo currentNetParam in paramInfo)
{
if (!currentNetParam.IsIn && currentNetParam.IsOut) // Skips out params
{
outList.Add(paramList.Add(null));
}
else if (currentLuaParam > nLuaParams) // Adds optional parameters
{
if (currentNetParam.IsOptional)
{
paramList.Add(currentNetParam.DefaultValue);
}
else
{
isMethod = false;
break;
}
}
else if ((extractValue = translator.typeChecker.checkType(luaState, currentLuaParam, currentNetParam.ParameterType)) != null) // Type checking
{
int index = paramList.Add(extractValue(luaState, currentLuaParam));
MethodArgs methodArg = new MethodArgs();
methodArg.index = index;
methodArg.extractValue = extractValue;
argTypes.Add(methodArg);
if (currentNetParam.ParameterType.IsByRef)
outList.Add(index);
currentLuaParam++;
} // Type does not match, ignore if the parameter is optional
else if (currentNetParam.IsOptional)
{
paramList.Add(currentNetParam.DefaultValue);
}
else // No match
{
isMethod = false;
break;
}
}
if (currentLuaParam != nLuaParams + 1) // Number of parameters does not match
using System;
using System.IO;
using System.Collections;
using System.Reflection;
using System.Diagnostics;
using System.Collections.Generic;
using LuaWrap;
using System.Runtime.InteropServices;
/*
* Functions used in the metatables of userdata representing
* CLR objects
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
class MetaFunctions
{
/*
* __index metafunction for CLR objects. Implemented in Lua.
*/
internal static string luaIndexFunction =
"local function index(obj,name)\n" +
" local meta=getmetatable(obj)\n" +
" local cached=meta.cache[name]\n" +
" if cached~=nil then\n" +
" return cached\n" +
" else\n" +
" local value,isFunc=get_object_member(obj,name)\n" +
" if isFunc then\n" +
" meta.cache[name]=value\n" +
" end\n" +
" return value\n" +
" end\n" +
"end\n" +
"return index";
private ObjectTranslator translator;
private Hashtable memberCache = new Hashtable();
internal KopiLua.Lua.lua_CFunction gcFunction, indexFunction, newindexFunction,
baseIndexFunction, classIndexFunction, classNewindexFunction,
execDelegateFunction, callConstructorFunction, toStringFunction;
public MetaFunctions(ObjectTranslator translator)
{
this.translator = translator;
gcFunction = new KopiLua.Lua.lua_CFunction(this.collectObject);
toStringFunction = new KopiLua.Lua.lua_CFunction(this.toString);
indexFunction = new KopiLua.Lua.lua_CFunction(this.getMethod);
newindexFunction = new KopiLua.Lua.lua_CFunction(this.setFieldOrProperty);
baseIndexFunction = new KopiLua.Lua.lua_CFunction(this.getBaseMethod);
callConstructorFunction = new KopiLua.Lua.lua_CFunction(this.callConstructor);
classIndexFunction = new KopiLua.Lua.lua_CFunction(this.getClassMethod);
classNewindexFunction = new KopiLua.Lua.lua_CFunction(this.setClassFieldOrProperty);
execDelegateFunction = new KopiLua.Lua.lua_CFunction(this.runFunctionDelegate);
}
/*
* __call metafunction of CLR delegates, retrieves and calls the delegate.
*/
private int runFunctionDelegate(KopiLua.Lua.lua_State luaState)
{
KopiLua.Lua.lua_CFunction func = (KopiLua.Lua.lua_CFunction)translator.getRawNetObject(luaState, 1);
KopiLua.Lua.lua_remove(luaState, 1);
return func(luaState);
}
/*
* __gc metafunction of CLR objects.
*/
private int collectObject(KopiLua.Lua.lua_State luaState)
{
int udata = LuaLib.luanet_rawnetobj(luaState, 1);
if (udata != -1)
{
translator.collectObject(udata);
}
else
{
// Debug.WriteLine("not found: " + udata);
}
return 0;
}
/*
* __tostring metafunction of CLR objects.
*/
private int toString(KopiLua.Lua.lua_State luaState)
{
object obj = translator.getRawNetObject(luaState, 1);
if (obj != null)
{
translator.push(luaState, obj.ToString() + ": " + obj.GetHashCode());
}
else KopiLua.Lua.lua_pushnil(luaState);
return 1;
}
/// <summary>
/// Debug tool to dump the lua stack
/// </summary>
/// FIXME, move somewhere else
public static void dumpStack(ObjectTranslator translator, KopiLua.Lua.lua_State luaState)
{
int depth = KopiLua.Lua.lua_gettop(luaState);
Debug.WriteLine("lua stack depth: " + depth);
for (int i = 1; i <= depth; i++)
{
LuaType type = KopiLua.Lua.lua_type(luaState, i).ToLuaType();
// we dump stacks when deep in calls, calling typename while the stack is in flux can fail sometimes, so manually check for key types
string typestr = (type == LuaType.Table) ? "table" : KopiLua.Lua.lua_typename(luaState, Convert.ToInt32(type)).ToString();
string strrep = KopiLua.Lua.lua_tostring(luaState, i).ToString();
if (type == LuaType.UserData)
{
object obj = translator.getRawNetObject(luaState, i);
strrep = obj.ToString();
}
Debug.Print("{0}: ({1}) {2}", i, typestr, strrep);
}
}
/*
* Called by the __index metafunction of CLR objects in case the
* method is not cached or it is a field/property/event.
* Receives the object and the member name as arguments and returns
* either the value of the member or a delegate to call it.
* If the member does not exist returns nil.
*/
private int getMethod(KopiLua.Lua.lua_State luaState)
{
object obj = translator.getRawNetObject(luaState, 1);
if (obj == null)
{
translator.throwError(luaState, "trying to index an invalid object reference");
KopiLua.Lua.lua_pushnil(luaState);
return 1;
}
object index = translator.getObject(luaState, 2);
//Type indexType = index.GetType();
string methodName = index as string; // will be null if not a string arg
Type objType = obj.GetType();
// Handle the most common case, looking up the method by name
if (methodName != null && isMemberPresent(objType, methodName))
return getMember(luaState, objType, 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 (objType.IsArray && index is double)
{
object[] arr = (object[])obj;
translator.push(luaState, arr[(int)((double)index)]);
}
else
{
// Try to use get_Item to index into this .net object
MethodInfo getter = objType.GetMethod("get_Item");
ParameterInfo[] actualParms = (getter != null) ? getter.GetParameters() : null;
if (actualParms == null || actualParms.Length != 1)
{
translator.throwError(luaState, "method not found (or no indexer): " + index);
KopiLua.Lua.lua_pushnil(luaState);
}
else
{
// Get the index in a form acceptable to the getter
index = translator.getAsType(luaState, 2, actualParms[0].ParameterType);
object[] args = new object[1];
// Just call the indexer - if out of bounds an exception will happen
args[0] = index;
try
{
object result = getter.Invoke(obj, args);
translator.push(luaState, result);
}
catch (TargetInvocationException e)
{
// Provide a more readable description for the common case of key not found
if(e.InnerException is KeyNotFoundException)
translator.throwError(luaState, "key '" + index + "' not found ");
else
translator.throwError(luaState, "exception indexing '" + index + "' " + e.Message);
KopiLua.Lua.lua_pushnil(luaState);
}
}
}
KopiLua.Lua.lua_pushboolean(luaState, 0);
return 2;
}
/*
* __index metafunction of base classes (the base field of Lua tables).
* Adds a prefix to the method name to call the base version of the method.
*/
private int getBaseMethod(KopiLua.Lua.lua_State luaState)
{
object obj = translator.getRawNetObject(luaState, 1);
if (obj == null)
{
translator.throwError(luaState, "trying to index an invalid object reference");
KopiLua.Lua.lua_pushnil(luaState);
KopiLua.Lua.lua_pushboolean(luaState, 0);
return 2;
}
string methodName = KopiLua.Lua.lua_tostring(luaState, 2).ToString();
if (methodName == null)
{
KopiLua.Lua.lua_pushnil(luaState);
KopiLua.Lua.lua_pushboolean(luaState, 0);
return 2;
}
getMember(luaState, obj.GetType(), obj, "__luaInterface_base_" + methodName, BindingFlags.Instance);
KopiLua.Lua.lua_settop(luaState, -2);
if (KopiLua.Lua.lua_type(luaState, -1).ToLuaType() == LuaType.Nil)
{
KopiLua.Lua.lua_settop(luaState, -2);
return getMember(luaState, obj.GetType(), obj, methodName, BindingFlags.Instance);
}
KopiLua.Lua.lua_pushboolean(luaState, 0);
return 2;
}
/// <summary>
/// Does this method exist as either an instance or static?
/// </summary>
/// <param name="objType"></param>
/// <param name="methodName"></param>
/// <returns></returns>
bool isMemberPresent(IReflect objType, string methodName)
{
object cachedMember = checkMemberCache(memberCache, objType, methodName);
if (cachedMember != null)
return true;
MemberInfo[] members = objType.GetMember(methodName, BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
return (members.Length > 0);
}
/*
* Pushes the value of a member or a delegate to call it, depending on the type of
* the member. Works with static or instance members.
* Uses reflection to find members, and stores the reflected MemberInfo object in
* a cache (indexed by the type of the object and the name of the member).
*/
private int getMember(KopiLua.Lua.lua_State luaState, IReflect objType, object obj, string methodName, BindingFlags bindingType)
{
bool implicitStatic = false;
MemberInfo member = null;
object cachedMember = checkMemberCache(memberCache, objType, methodName);
//object cachedMember=null;
if (cachedMember is KopiLua.Lua.lua_CFunction)
{
translator.pushFunction(luaState, (KopiLua.Lua.lua_CFunction)cachedMember);
translator.push(luaState, true);
return 2;
}
else if (cachedMember != null)
{
member = (MemberInfo)cachedMember;
}
else
{
MemberInfo[] members = objType.GetMember(methodName, bindingType | BindingFlags.Public | BindingFlags.NonPublic);
if (members.Length > 0)
member = members[0];
else
{
// If we can't find any suitable instance members, try to find them as statics - but we only want to allow implicit static
// lookups for fields/properties/events -kevinh
members = objType.GetMember(methodName, bindingType | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
if (members.Length > 0)
{
member = members[0];
implicitStatic = true;
}
}
}
if (member != null)
{
if (member.MemberType == MemberTypes.Field)
{
FieldInfo field = (FieldInfo)member;
if (cachedMember == null) setMemberCache(memberCache, objType, methodName, member);
try
{
translator.push(luaState, field.GetValue(obj));
}
catch
{
KopiLua.Lua.lua_pushnil(luaState);
}
}
else if (member.MemberType == MemberTypes.Property)
{
PropertyInfo property = (PropertyInfo)member;
if (cachedMember == null) setMemberCache(memberCache, objType, methodName, member);
try
{
object val = property.GetValue(obj, null);
translator.push(luaState, val);
}
catch (ArgumentException)
{
// If we can't find the getter in our class, recurse up to the base class and see
// if they can help.
if (objType is Type && !(((Type)objType) == typeof(object)))
return getMember(luaState, ((Type)objType).BaseType, obj, methodName, bindingType);
else
KopiLua.Lua.lua_pushnil(luaState);
}
catch(TargetInvocationException e) // Convert this exception into a Lua error
{
ThrowError(luaState, e);
KopiLua.Lua.lua_pushnil(luaState);
}
}
else if (member.MemberType == MemberTypes.Event)
{
EventInfo eventInfo = (EventInfo)member;
if (cachedMember == null) setMemberCache(memberCache, objType, methodName, member);
translator.push(luaState, new RegisterEventHandler(translator.pendingEvents, obj, eventInfo));
}
else if(!implicitStatic)
{
if (member.MemberType == MemberTypes.NestedType)
{
// kevinh - added support for finding nested types
// cache us
if (cachedMember == null) setMemberCache(memberCache, objType, methodName, member);
// Find the name of our class
string name = member.Name;
Type dectype = member.DeclaringType;
// Build a new long name and try to find the type by name
string longname = dectype.FullName + "+" + name;
Type nestedType = translator.FindType(longname);
translator.pushType(luaState, nestedType);
}
else
{
// Member type must be 'method'
KopiLua.Lua.lua_CFunction wrapper = new KopiLua.Lua.lua_CFunction((new LuaMethodWrapper(translator, objType, methodName, bindingType)).call);
if (cachedMember == null) setMemberCache(memberCache, objType, methodName, wrapper);
translator.pushFunction(luaState, wrapper);
translator.push(luaState, true);
return 2;
}
}
else
{
// If we reach this point we found a static method, but can't use it in this context because the user passed in an instance
translator.throwError(luaState, "can't pass instance to static method " + methodName);
KopiLua.Lua.lua_pushnil(luaState);
}
}
else
{
// kevinh - we want to throw an exception because meerly returning 'nil' in this case
// is not sufficient. valid data members may return nil and therefore there must be some
// way to know the member just doesn't exist.
translator.throwError(luaState, "unknown member name " + methodName);
KopiLua.Lua.lua_pushnil(luaState);
}
// push false because we are NOT returning a function (see luaIndexFunction)
translator.push(luaState, false);
return 2;
}
/*
* Checks if a MemberInfo object is cached, returning it or null.
*/
private object checkMemberCache(Hashtable memberCache, IReflect objType, string memberName)
{
Hashtable members = (Hashtable)memberCache[objType];
if (members != null)
return members[memberName];
else
return null;
}
/*
* Stores a MemberInfo object in the member cache.
*/
private void setMemberCache(Hashtable memberCache, IReflect objType, string memberName, object member)
{
Hashtable members = (Hashtable)memberCache[objType];
if (members == null)
{
members = new Hashtable();
memberCache[objType] = members;
}
members[memberName] = member;
}
/*
* __newindex metafunction of CLR objects. Receives the object,
* the member name and the value to be stored as arguments. Throws
* and error if the assignment is invalid.
*/
private int setFieldOrProperty(KopiLua.Lua.lua_State luaState)
{
object target = translator.getRawNetObject(luaState, 1);
if (target == null)
{
translator.throwError(luaState, "trying to index and invalid object reference");
return 0;
}
Type type = target.GetType();
// First try to look up the parameter as a property name
string detailMessage;
bool didMember = trySetMember(luaState, type, target, BindingFlags.Instance, out detailMessage);
if (didMember)
return 0; // Must have found the property name
// We didn't find a property name, now see if we can use a [] style this accessor to set array contents
try
{
if (type.IsArray && KopiLua.Lua.lua_isnumber(luaState, 2).ToBoolean())
{
int index = (int)KopiLua.Lua.lua_tonumber(luaState, 2);
Array arr = (Array)target;
object val = translator.getAsType(luaState, 3, arr.GetType().GetElementType());
arr.SetValue(val, index);
}
else
{
// Try to see if we have a this[] accessor
MethodInfo setter = type.GetMethod("set_Item");
if (setter != null)
{
ParameterInfo[] args = setter.GetParameters();
Type valueType = args[1].ParameterType;
// The new val ue the user specified
object val = translator.getAsType(luaState, 3, valueType);
Type indexType = args[0].ParameterType;
object index = translator.getAsType(luaState, 2, indexType);
object[] methodArgs = new object[2];
// Just call the indexer - if out of bounds an exception will happen
methodArgs[0] = index;
methodArgs[1] = val;
setter.Invoke(target, methodArgs);
}
else
{
translator.throwError(luaState, detailMessage); // Pass the original message from trySetMember because it is probably best
}
}
}
catch (SEHException)
{
// If we are seeing a C++ exception - this must actually be for Lua's private use. Let it handle it
throw;
}
catch (Exception e)
{
ThrowError(luaState, e);
}
return 0;
}
/// <summary>
/// Tries to set a named property or field
/// </summary>
/// <param name="luaState"></param>
/// <param name="targetType"></param>
/// <param name="target"></param>
/// <param name="bindingType"></param>
/// <returns>false if unable to find the named member, true for success</returns>
private bool trySetMember(KopiLua.Lua.lua_State luaState, IReflect targetType, object target, BindingFlags bindingType, out string detailMessage)
{
detailMessage = null; // No error yet
// If not already a string just return - we don't want to call tostring - which has the side effect of
// changing the lua typecode to string
// Note: We don't use isstring because the standard lua C isstring considers either strings or numbers to
// be true for isstring.
if (KopiLua.Lua.lua_type(luaState, 2).ToLuaType() != LuaType.String)
{
detailMessage = "property names must be strings";
return false;
}
// We only look up property names by string
string fieldName = KopiLua.Lua.lua_tostring(luaState, 2).ToString();
if (fieldName == null || fieldName.Length < 1 || !(char.IsLetter(fieldName[0]) || fieldName[0] == '_'))
{
detailMessage = "invalid property name";
return false;
}
// Find our member via reflection or the cache
MemberInfo member = (MemberInfo)checkMemberCache(memberCache, targetType, fieldName);
if (member == null)
{
MemberInfo[] members = targetType.GetMember(fieldName, bindingType | BindingFlags.Public | BindingFlags.NonPublic);
if (members.Length > 0)
{
member = members[0];
setMemberCache(memberCache, targetType, fieldName, member);
}
else
{
detailMessage = "field or property '" + fieldName + "' does not exist";
return false;
}
}
if (member.MemberType == MemberTypes.Field)
{
FieldInfo field = (FieldInfo)member;
object val = translator.getAsType(luaState, 3, field.FieldType);
try
{
field.SetValue(target, val);
}
catch (Exception e)
{
ThrowError(luaState, e);
}
// We did a call
return true;
}
else if (member.MemberType == MemberTypes.Property)
{
PropertyInfo property = (PropertyInfo)member;
object val = translator.getAsType(luaState, 3, property.PropertyType);
try
{
property.SetValue(target, val, null);
}
catch (Exception e)
{
ThrowError(luaState, e);
}
// We did a call
return true;
}
detailMessage = "'" + fieldName + "' is not a .net field or property";
return false;
}
/*
* Writes to fields or properties, either static or instance. Throws an error
* if the operation is invalid.
*/
private int setMember(KopiLua.Lua.lua_State luaState, IReflect targetType, object target, BindingFlags bindingType)
{
string detail;
bool success = trySetMember(luaState, targetType, target, bindingType, out detail);
if(!success)
translator.throwError(luaState, detail);
return 0;
}
/// <summary>
/// Convert a C# exception into a Lua error
/// </summary>
/// <param name="e"></param>
/// We try to look into the exception to give the most meaningful description
void ThrowError(KopiLua.Lua.lua_State luaState, Exception e)
{
// If we got inside a reflection show what really happened
TargetInvocationException te = e as TargetInvocationException;
if (te != null)
e = te.InnerException;
translator.throwError(luaState, e);
}
/*
* __index metafunction of type references, works on static members.
*/
private int getClassMethod(KopiLua.Lua.lua_State luaState)
{
IReflect klass;
object obj = translator.getRawNetObject(luaState, 1);
if (obj == null || !(obj is IReflect))
{
translator.throwError(luaState, "trying to index an invalid type reference");
KopiLua.Lua.lua_pushnil(luaState);
return 1;
}
else klass = (IReflect)obj;
if (KopiLua.Lua.lua_isnumber(luaState, 2).ToBoolean())
{
int size = (int)KopiLua.Lua.lua_tonumber(luaState, 2);
translator.push(luaState, Array.CreateInstance(klass.UnderlyingSystemType, size));
return 1;
}
else
{
string methodName = KopiLua.Lua.lua_tostring(luaState, 2).ToString();
if (methodName == null)
{
KopiLua.Lua.lua_pushnil(luaState);
return 1;
}
else return getMember(luaState, klass, null, methodName, BindingFlags.FlattenHierarchy | BindingFlags.Static);
}
}
/*
* __newindex function of type references, works on static members.
*/
private int setClassFieldOrProperty(KopiLua.Lua.lua_State luaState)
{
IReflect target;
object obj = translator.getRawNetObject(luaState, 1);
if (obj == null || !(obj is IReflect))
{
translator.throwError(luaState, "trying to index an invalid type reference");
return 0;
}
else target = (IReflect)obj;
return setMember(luaState, target, null, BindingFlags.FlattenHierarchy | BindingFlags.Static);
}
/*
* __call metafunction of type references. Searches for and calls
* a constructor for the type. Returns nil if the constructor is not
* found or if the arguments are invalid. Throws an error if the constructor
* generates an exception.
*/
private int callConstructor(KopiLua.Lua.lua_State luaState)
{
MethodCache validConstructor = new MethodCache();
IReflect klass;
object obj = translator.getRawNetObject(luaState, 1);
if (obj == null || !(obj is IReflect))
{
translator.throwError(luaState, "trying to call constructor on an invalid type reference");
KopiLua.Lua.lua_pushnil(luaState);
return 1;
}
else klass = (IReflect)obj;
KopiLua.Lua.lua_remove(luaState, 1);
ConstructorInfo[] constructors = klass.UnderlyingSystemType.GetConstructors();
foreach (ConstructorInfo constructor in constructors)
{
bool isConstructor = matchParameters(luaState, constructor, ref validConstructor);
if (isConstructor)
{
try
{
translator.push(luaState, constructor.Invoke(validConstructor.args));
}
catch (TargetInvocationException e)
{
ThrowError(luaState, e);
KopiLua.Lua.lua_pushnil(luaState);
}
catch
{
KopiLua.Lua.lua_pushnil(luaState);
}
return 1;
}
}
string constructorName = (constructors.Length == 0) ? "unknown" : constructors[0].Name;
translator.throwError(luaState, String.Format("{0} does not contain constructor({1}) argument match",
klass.UnderlyingSystemType,
constructorName));
KopiLua.Lua.lua_pushnil(luaState);
return 1;
}
/*
* Matches a method against its arguments in the Lua stack. Returns
* if the match was succesful. It it was also returns the information
* necessary to invoke the method.
*/
internal bool matchParameters(KopiLua.Lua.lua_State luaState, MethodBase method, ref MethodCache methodCache)
{
ExtractValue extractValue;
bool isMethod = true;
ParameterInfo[] paramInfo = method.GetParameters();
int currentLuaParam = 1;
int nLuaParams = KopiLua.Lua.lua_gettop(luaState);
ArrayList paramList = new ArrayList();
List<int> outList = new List<int>();
List<MethodArgs> argTypes = new List<MethodArgs>();
foreach (ParameterInfo currentNetParam in paramInfo)
{
if (!currentNetParam.IsIn && currentNetParam.IsOut) // Skips out params
{
outList.Add(paramList.Add(null));
}
else if (currentLuaParam > nLuaParams) // Adds optional parameters
{
if (currentNetParam.IsOptional)
{
paramList.Add(currentNetParam.DefaultValue);
}
else
{
isMethod = false;
break;
}
}
else if ((extractValue = translator.typeChecker.checkType(luaState, currentLuaParam, currentNetParam.ParameterType)) != null) // Type checking
{
int index = paramList.Add(extractValue(luaState, currentLuaParam));
MethodArgs methodArg = new MethodArgs();
methodArg.index = index;
methodArg.extractValue = extractValue;
argTypes.Add(methodArg);
if (currentNetParam.ParameterType.IsByRef)
outList.Add(index);
currentLuaParam++;
} // Type does not match, ignore if the parameter is optional
else if (currentNetParam.IsOptional)
{
paramList.Add(currentNetParam.DefaultValue);
}
else // No match
{
isMethod = false;
break;
}
}
if (currentLuaParam != nLuaParams + 1) // Number of parameters does not match
isMethod = false;
if (isMethod)
{
methodCache.args = paramList.ToArray();
methodCache.cachedMethod = method;
methodCache.outList = outList.ToArray();
methodCache.argTypes = argTypes.ToArray();
}
return isMethod;
}
}
if (isMethod)
{
methodCache.args = paramList.ToArray();
methodCache.cachedMethod = method;
methodCache.outList = outList.ToArray();
methodCache.argTypes = argTypes.ToArray();
}
return isMethod;
}
}
}
\ No newline at end of file
......@@ -106,13 +106,15 @@ namespace LuaInterface
object targetObject=target;
bool failedCall=true;
int nReturnValues=0;
Console.WriteLine("asyyyyyyyyyyyyyy");
if(!KopiLua.Lua.lua_checkstack(luaState,5).ToBoolean())
throw new LuaException("Lua stack overflow");
Console.WriteLine("asyyyyyyyyyyyyyy1");
bool isStatic = (bindingType & BindingFlags.Static) == BindingFlags.Static;
Console.WriteLine("asyyyyyyyyyyyyyy2");
SetPendingException(null);
Console.WriteLine("asyyyyyyyyyyyyyy3");
Console.WriteLine(methodToCall==null);
if(methodToCall==null) // Method from name
{
if (isStatic)
......@@ -120,6 +122,9 @@ namespace LuaInterface
else
targetObject=extractTarget(luaState,1);
//KopiLua.Lua.lua_remove(luaState,1); // Pops the receiver
Console.WriteLine("asdxxxxxx");
Console.WriteLine(lastCalledMethod.cachedMethod);
Console.WriteLine(lastCalledMethod.cachedMethod!=null);
if(lastCalledMethod.cachedMethod!=null) // Cached?
{
int numStackToSkip = isStatic ? 0 : 1; // If this is an instance invoe we will have an extra arg on the stack for the targetObject
......@@ -131,6 +136,8 @@ namespace LuaInterface
throw new LuaException("Lua stack overflow");
try
{
Console.WriteLine("0");
Console.WriteLine(lastCalledMethod.argTypes.Length);
for(int i=0;i<lastCalledMethod.argTypes.Length;i++)
{
lastCalledMethod.args[lastCalledMethod.argTypes[i].index]=
......@@ -142,12 +149,14 @@ namespace LuaInterface
throw new LuaException("argument number "+(i+1)+" is invalid");
}
}
Console.WriteLine("asd");
if((bindingType & BindingFlags.Static)==BindingFlags.Static)
{
translator.push(luaState,lastCalledMethod.cachedMethod.Invoke(null,lastCalledMethod.args));
}
else
{
Console.WriteLine("asd2");
if(lastCalledMethod.cachedMethod.IsConstructor)
translator.push(luaState,((ConstructorInfo)lastCalledMethod.cachedMethod).Invoke(lastCalledMethod.args));
else
......
......@@ -618,6 +618,7 @@ namespace LuaInterface
if(udata!=-1)
return objects[udata];
else
//return null;
return getUserData(luaState,index);
}
default:
......@@ -749,7 +750,6 @@ namespace LuaInterface
{
// Make sure we are _really_ ILuaGenerated
Type typ = o.GetType();
return (typ.GetInterface("ILuaGeneratedType") != null);
}
else
......
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