/*
* This file is part of LuaInterface.
*
* Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz.
* Copyright (C) 2012 Megax
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.IO;
using System.Reflection;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using LuaInterface.Method;
using LuaInterface.Exceptions;
using LuaInterface.Extensions;
namespace LuaInterface
{
using LuaCore = KopiLua.Lua;
/*
* Passes objects from the CLR to Lua and vice-versa
*
* Author: Fabio Mascarenhas
* Version: 1.0
*/
public class ObjectTranslator
{
private LuaCore.lua_CFunction registerTableFunction, unregisterTableFunction, getMethodSigFunction,
getConstructorSigFunction, importTypeFunction, loadAssemblyFunction;
// object to object #
public readonly Dictionary objectsBackMap = new Dictionary();
// object # to object (FIXME - it should be possible to get object address as an object #)
public readonly Dictionary objects = new Dictionary();
internal EventHandlerContainer pendingEvents = new EventHandlerContainer();
private MetaFunctions metaFunctions;
private List assemblies;
internal CheckType typeChecker;
internal Lua interpreter;
///
/// We want to ensure that objects always have a unique ID
///
private int nextObj = 0;
public ObjectTranslator(Lua interpreter, LuaCore.lua_State luaState)
{
this.interpreter = interpreter;
typeChecker = new CheckType(this);
metaFunctions = new MetaFunctions(this);
assemblies = new List();
importTypeFunction = new LuaCore.lua_CFunction(this.importType);
loadAssemblyFunction = new LuaCore.lua_CFunction(this.loadAssembly);
registerTableFunction = new LuaCore.lua_CFunction(this.registerTable);
unregisterTableFunction = new LuaCore.lua_CFunction(this.unregisterTable);
getMethodSigFunction = new LuaCore.lua_CFunction(this.getMethodSignature);
getConstructorSigFunction = new LuaCore.lua_CFunction(this.getConstructorSignature);
createLuaObjectList(luaState);
createIndexingMetaFunction(luaState);
createBaseClassMetatable(luaState);
createClassMetatable(luaState);
createFunctionMetatable(luaState);
setGlobalFunctions(luaState);
}
/*
* Sets up the list of objects in the Lua side
*/
private void createLuaObjectList(LuaCore.lua_State luaState)
{
LuaLib.lua_pushstring(luaState, "luaNet_objects");
LuaLib.lua_newtable(luaState);
LuaLib.lua_newtable(luaState);
LuaLib.lua_pushstring(luaState, "__mode");
LuaLib.lua_pushstring(luaState, "v");
LuaLib.lua_settable(luaState, -3);
LuaLib.lua_setmetatable(luaState, -2);
LuaLib.lua_settable(luaState, (int)LuaIndexes.Registry);
}
/*
* Registers the indexing function of CLR objects
* passed to Lua
*/
private void createIndexingMetaFunction(LuaCore.lua_State luaState)
{
LuaLib.lua_pushstring(luaState, "luaNet_indexfunction");
LuaLib.luaL_dostring(luaState, MetaFunctions.luaIndexFunction); // steffenj: lua_dostring renamed to luaL_dostring
//LuaLib.lua_pushstdcallcfunction(luaState, indexFunction);
LuaLib.lua_rawset(luaState, (int)LuaIndexes.Registry);
}
/*
* Creates the metatable for superclasses (the base
* field of registered tables)
*/
private void createBaseClassMetatable(LuaCore.lua_State luaState)
{
LuaLib.luaL_newmetatable(luaState, "luaNet_searchbase");
LuaLib.lua_pushstring(luaState, "__gc");
LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.gcFunction);
LuaLib.lua_settable(luaState, -3);
LuaLib.lua_pushstring(luaState, "__tostring");
LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.toStringFunction);
LuaLib.lua_settable(luaState, -3);
LuaLib.lua_pushstring(luaState, "__index");
LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.baseIndexFunction);
LuaLib.lua_settable(luaState, -3);
LuaLib.lua_pushstring(luaState, "__newindex");
LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.newindexFunction);
LuaLib.lua_settable(luaState, -3);
LuaLib.lua_settop(luaState, -2);
}
/*
* Creates the metatable for type references
*/
private void createClassMetatable(LuaCore.lua_State luaState)
{
LuaLib.luaL_newmetatable(luaState, "luaNet_class");
LuaLib.lua_pushstring(luaState, "__gc");
LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.gcFunction);
LuaLib.lua_settable(luaState, -3);
LuaLib.lua_pushstring(luaState, "__tostring");
LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.toStringFunction);
LuaLib.lua_settable(luaState, -3);
LuaLib.lua_pushstring(luaState, "__index");
LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.classIndexFunction);
LuaLib.lua_settable(luaState, -3);
LuaLib.lua_pushstring(luaState, "__newindex");
LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.classNewindexFunction);
LuaLib.lua_settable(luaState, -3);
LuaLib.lua_pushstring(luaState, "__call");
LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.callConstructorFunction);
LuaLib.lua_settable(luaState, -3);
LuaLib.lua_settop(luaState, -2);
}
/*
* Registers the global functions used by LuaInterface
*/
private void setGlobalFunctions(LuaCore.lua_State luaState)
{
LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.indexFunction);
LuaLib.lua_setglobal(luaState, "get_object_member");
LuaLib.lua_pushstdcallcfunction(luaState, importTypeFunction);
LuaLib.lua_setglobal(luaState, "import_type");
LuaLib.lua_pushstdcallcfunction(luaState, loadAssemblyFunction);
LuaLib.lua_setglobal(luaState, "load_assembly");
LuaLib.lua_pushstdcallcfunction(luaState, registerTableFunction);
LuaLib.lua_setglobal(luaState, "make_object");
LuaLib.lua_pushstdcallcfunction(luaState, unregisterTableFunction);
LuaLib.lua_setglobal(luaState, "free_object");
LuaLib.lua_pushstdcallcfunction(luaState, getMethodSigFunction);
LuaLib.lua_setglobal(luaState, "get_method_bysig");
LuaLib.lua_pushstdcallcfunction(luaState, getConstructorSigFunction);
LuaLib.lua_setglobal(luaState, "get_constructor_bysig");
}
/*
* Creates the metatable for delegates
*/
private void createFunctionMetatable(LuaCore.lua_State luaState)
{
LuaLib.luaL_newmetatable(luaState, "luaNet_function");
LuaLib.lua_pushstring(luaState, "__gc");
LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.gcFunction);
LuaLib.lua_settable(luaState, -3);
LuaLib.lua_pushstring(luaState, "__call");
LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.execDelegateFunction);
LuaLib.lua_settable(luaState, -3);
LuaLib.lua_settop(luaState, -2);
}
/*
* Passes errors (argument e) to the Lua interpreter
*/
internal void throwError(LuaCore.lua_State luaState, object e)
{
// We use this to remove anything pushed by luaL_where
int oldTop = LuaLib.lua_gettop(luaState);
// Stack frame #1 is our C# wrapper, so not very interesting to the user
// Stack frame #2 must be the lua code that called us, so that's what we want to use
LuaLib.luaL_where(luaState, 1);
var curlev = popValues(luaState, oldTop);
// Determine the position in the script where the exception was triggered
string errLocation = string.Empty;
if(curlev.Length > 0)
errLocation = curlev[0].ToString();
string message = e as string;
if(!message.IsNull())
{
// Wrap Lua error (just a string) and store the error location
e = new LuaScriptException(message, errLocation);
}
else
{
var ex = e as Exception;
if(!ex.IsNull())
{
// Wrap generic .NET exception as an InnerException and store the error location
e = new LuaScriptException(ex, errLocation);
}
}
push(luaState, e);
LuaLib.lua_error(luaState);
}
/*
* Implementation of load_assembly. Throws an error
* if the assembly is not found.
*/
private int loadAssembly(LuaCore.lua_State luaState)
{
try
{
string assemblyName = LuaLib.lua_tostring(luaState, 1).ToString();
Assembly assembly = null;
try
{
assembly = Assembly.Load(assemblyName);
}
catch(BadImageFormatException)
{
// The assemblyName was invalid. It is most likely a path.
}
if(assembly.IsNull())
assembly = Assembly.Load(AssemblyName.GetAssemblyName(assemblyName));
if(!assembly.IsNull() && !assemblies.Contains(assembly))
assemblies.Add(assembly);
}
catch(Exception e)
{
throwError(luaState, e);
}
return 0;
}
internal Type FindType(string className)
{
foreach(var assembly in assemblies)
{
var klass = assembly.GetType(className);
if(!klass.IsNull())
return klass;
}
return null;
}
/*
* Implementation of import_type. Returns nil if the
* type is not found.
*/
private int importType(LuaCore.lua_State luaState)
{
string className = LuaLib.lua_tostring(luaState, 1).ToString();
var klass = FindType(className);
if(!klass.IsNull())
pushType(luaState, klass);
else
LuaLib.lua_pushnil(luaState);
return 1;
}
/*
* Implementation of make_object. Registers a table (first
* argument in the stack) as an object subclassing the
* type passed as second argument in the stack.
*/
private int registerTable(LuaCore.lua_State luaState)
{
if(LuaLib.lua_type(luaState, 1) == LuaTypes.Table)
{
var luaTable = getTable(luaState, 1);
string superclassName = LuaLib.lua_tostring(luaState, 2).ToString();
if(!superclassName.IsNull())
{
var klass = FindType(superclassName);
if(!klass.IsNull())
{
// Creates and pushes the object in the stack, setting
// it as the metatable of the first argument
object obj = CodeGeneration.Instance.GetClassInstance(klass, luaTable);
pushObject(luaState, obj, "luaNet_metatable");
LuaLib.lua_newtable(luaState);
LuaLib.lua_pushstring(luaState, "__index");
LuaLib.lua_pushvalue(luaState, -3);
LuaLib.lua_settable(luaState, -3);
LuaLib.lua_pushstring(luaState, "__newindex");
LuaLib.lua_pushvalue(luaState, -3);
LuaLib.lua_settable(luaState, -3);
LuaLib.lua_setmetatable(luaState, 1);
// Pushes the object again, this time as the base field
// of the table and with the luaNet_searchbase metatable
LuaLib.lua_pushstring(luaState, "base");
int index = addObject(obj);
pushNewObject(luaState, obj, index, "luaNet_searchbase");
LuaLib.lua_rawset(luaState, 1);
}
else
throwError(luaState, "register_table: can not find superclass '" + superclassName + "'");
}
else
throwError(luaState, "register_table: superclass name can not be null");
}
else
throwError(luaState, "register_table: first arg is not a table");
return 0;
}
/*
* Implementation of free_object. Clears the metatable and the
* base field, freeing the created object for garbage-collection
*/
private int unregisterTable(LuaCore.lua_State luaState)
{
try
{
if(LuaLib.lua_getmetatable(luaState, 1) != 0)
{
LuaLib.lua_pushstring(luaState, "__index");
LuaLib.lua_gettable(luaState, -2);
object obj = getRawNetObject(luaState, -1);
if(obj.IsNull())
throwError(luaState, "unregister_table: arg is not valid table");
var luaTableField = obj.GetType().GetField("__luaInterface_luaTable");
if(luaTableField.IsNull())
throwError(luaState, "unregister_table: arg is not valid table");
luaTableField.SetValue(obj, null);
LuaLib.lua_pushnil(luaState);
LuaLib.lua_setmetatable(luaState, 1);
LuaLib.lua_pushstring(luaState, "base");
LuaLib.lua_pushnil(luaState);
LuaLib.lua_settable(luaState, 1);
}
else
throwError(luaState, "unregister_table: arg is not valid table");
}
catch(Exception e)
{
throwError(luaState, e.Message);
}
return 0;
}
/*
* Implementation of get_method_bysig. Returns nil
* if no matching method is not found.
*/
private int getMethodSignature(LuaCore.lua_State luaState)
{
IReflect klass;
object target;
int udata = LuaLib.luanet_checkudata(luaState, 1, "luaNet_class");
if(udata != -1)
{
klass = (IReflect)objects[udata];
target = null;
}
else
{
target = getRawNetObject(luaState, 1);
if(target.IsNull())
{
throwError(luaState, "get_method_bysig: first arg is not type or object reference");
LuaLib.lua_pushnil(luaState);
return 1;
}
klass = target.GetType();
}
string methodName = LuaLib.lua_tostring(luaState, 2).ToString();
var signature = new Type[LuaLib.lua_gettop(luaState)-2];
for(int i = 0; i < signature.Length; i++)
signature[i] = FindType(LuaLib.lua_tostring(luaState, i+3).ToString());
try
{
//CP: Added ignore case
var method = klass.GetMethod(methodName, BindingFlags.Public | BindingFlags.Static |
BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.IgnoreCase, null, signature, null);
pushFunction(luaState, new LuaCore.lua_CFunction((new LuaMethodWrapper(this, target, klass, method)).call));
}
catch(Exception e)
{
throwError(luaState, e);
LuaLib.lua_pushnil(luaState);
}
return 1;
}
/*
* Implementation of get_constructor_bysig. Returns nil
* if no matching constructor is found.
*/
private int getConstructorSignature(LuaCore.lua_State luaState)
{
IReflect klass = null;
int udata = LuaLib.luanet_checkudata(luaState, 1, "luaNet_class");
if(udata != -1)
klass = (IReflect)objects[udata];
if(klass.IsNull())
throwError(luaState, "get_constructor_bysig: first arg is invalid type reference");
var signature = new Type[LuaLib.lua_gettop(luaState)-1];
for(int i = 0; i < signature.Length; i++)
signature[i] = FindType(LuaLib.lua_tostring(luaState, i+2).ToString());
try
{
ConstructorInfo constructor = klass.UnderlyingSystemType.GetConstructor(signature);
pushFunction(luaState, new LuaCore.lua_CFunction((new LuaMethodWrapper(this, null, klass, constructor)).call));
}
catch(Exception e)
{
throwError(luaState, e);
LuaLib.lua_pushnil(luaState);
}
return 1;
}
/*
* Pushes a type reference into the stack
*/
internal void pushType(LuaCore.lua_State luaState, Type t)
{
pushObject(luaState, new ProxyType(t), "luaNet_class");
}
/*
* Pushes a delegate into the stack
*/
internal void pushFunction(LuaCore.lua_State luaState, LuaCore.lua_CFunction func)
{
pushObject(luaState, func, "luaNet_function");
}
/*
* Pushes a CLR object into the Lua stack as an userdata
* with the provided metatable
*/
internal void pushObject(LuaCore.lua_State luaState, object o, string metatable)
{
int index = -1;
// Pushes nil
if(o.IsNull())
{
LuaLib.lua_pushnil(luaState);
return;
}
// Object already in the list of Lua objects? Push the stored reference.
bool found = objectsBackMap.TryGetValue(o, out index);
if(found)
{
LuaLib.luaL_getmetatable(luaState, "luaNet_objects");
LuaLib.lua_rawgeti(luaState, -1, index);
// Note: starting with lua5.1 the garbage collector may remove weak reference items (such as our luaNet_objects values) when the initial GC sweep
// occurs, but the actual call of the __gc finalizer for that object may not happen until a little while later. During that window we might call
// this routine and find the element missing from luaNet_objects, but collectObject() has not yet been called. In that case, we go ahead and call collect
// object here
// did we find a non nil object in our table? if not, we need to call collect object
var type = LuaLib.lua_type(luaState, -1);
if(type != LuaTypes.Nil)
{
LuaLib.lua_remove(luaState, -2); // drop the metatable - we're going to leave our object on the stack
return;
}
// MetaFunctions.dumpStack(this, luaState);
LuaLib.lua_remove(luaState, -1); // remove the nil object value
LuaLib.lua_remove(luaState, -1); // remove the metatable
collectObject(o, index); // Remove from both our tables and fall out to get a new ID
}
index = addObject(o);
pushNewObject(luaState, o, index, metatable);
}
/*
* Pushes a new object into the Lua stack with the provided
* metatable
*/
private void pushNewObject(LuaCore.lua_State luaState, object o, int index, string metatable)
{
if(metatable == "luaNet_metatable")
{
// Gets or creates the metatable for the object's type
LuaLib.luaL_getmetatable(luaState, o.GetType().AssemblyQualifiedName);
if(LuaLib.lua_isnil(luaState, -1))
{
LuaLib.lua_settop(luaState, -2);
LuaLib.luaL_newmetatable(luaState, o.GetType().AssemblyQualifiedName);
LuaLib.lua_pushstring(luaState, "cache");
LuaLib.lua_newtable(luaState);
LuaLib.lua_rawset(luaState, -3);
LuaLib.lua_pushlightuserdata(luaState, LuaLib.luanet_gettag());
LuaLib.lua_pushnumber(luaState, 1);
LuaLib.lua_rawset(luaState, -3);
LuaLib.lua_pushstring(luaState, "__index");
LuaLib.lua_pushstring(luaState, "luaNet_indexfunction");
LuaLib.lua_rawget(luaState, (int)LuaIndexes.Registry);
LuaLib.lua_rawset(luaState, -3);
LuaLib.lua_pushstring(luaState, "__gc");
LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.gcFunction);
LuaLib.lua_rawset(luaState, -3);
LuaLib.lua_pushstring(luaState, "__tostring");
LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.toStringFunction);
LuaLib.lua_rawset(luaState, -3);
LuaLib.lua_pushstring(luaState, "__newindex");
LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.newindexFunction);
LuaLib.lua_rawset(luaState, -3);
}
}
else
LuaLib.luaL_getmetatable(luaState, metatable);
// Stores the object index in the Lua list and pushes the
// index into the Lua stack
LuaLib.luaL_getmetatable(luaState, "luaNet_objects");
LuaLib.luanet_newudata(luaState, index);
LuaLib.lua_pushvalue(luaState, -3);
LuaLib.lua_remove(luaState, -4);
LuaLib.lua_setmetatable(luaState, -2);
LuaLib.lua_pushvalue(luaState, -1);
LuaLib.lua_rawseti(luaState, -3, index);
LuaLib.lua_remove(luaState, -2);
}
/*
* Gets an object from the Lua stack with the desired type, if it matches, otherwise
* returns null.
*/
internal object getAsType(LuaCore.lua_State luaState, int stackPos, Type paramType)
{
var extractor = typeChecker.checkType(luaState, stackPos, paramType);
return !extractor.IsNull() ? extractor(luaState, stackPos) : null;
}
///
/// Given the Lua int ID for an object remove it from our maps
///
///
internal void collectObject(int udata)
{
object o;
bool found = objects.TryGetValue(udata, out o);
// The other variant of collectObject might have gotten here first, in that case we will silently ignore the missing entry
if(found)
{
// Debug.WriteLine("Removing " + o.ToString() + " @ " + udata);
objects.Remove(udata);
objectsBackMap.Remove(o);
}
}
///
/// Given an object reference, remove it from our maps
///
///
private void collectObject(object o, int udata)
{
// Debug.WriteLine("Removing " + o.ToString() + " @ " + udata);
objects.Remove(udata);
objectsBackMap.Remove(o);
}
private int addObject(object obj)
{
// New object: inserts it in the list
int index = nextObj++;
// Debug.WriteLine("Adding " + obj.ToString() + " @ " + index);
objects[index] = obj;
objectsBackMap[obj] = index;
return index;
}
/*
* Gets an object from the Lua stack according to its Lua type.
*/
internal object getObject(LuaCore.lua_State luaState, int index)
{
var type = LuaLib.lua_type(luaState, index);
switch(type)
{
case LuaTypes.Number:
{
return LuaLib.lua_tonumber(luaState, index);
}
case LuaTypes.String:
{
return LuaLib.lua_tostring(luaState, index);
}
case LuaTypes.Boolean:
{
return LuaLib.lua_toboolean(luaState, index);
}
case LuaTypes.Table:
{
return getTable(luaState, index);
}
case LuaTypes.Function:
{
return getFunction(luaState, index);
}
case LuaTypes.UserData:
{
int udata = LuaLib.luanet_tonetobject(luaState, index);
return udata != -1 ? objects[udata] : getUserData(luaState, index);
}
default:
return null;
}
}
/*
* Gets the table in the index positon of the Lua stack.
*/
internal LuaTable getTable(LuaCore.lua_State luaState, int index)
{
LuaLib.lua_pushvalue(luaState, index);
return new LuaTable(LuaLib.lua_ref(luaState, 1), interpreter);
}
/*
* Gets the userdata in the index positon of the Lua stack.
*/
internal LuaUserData getUserData(LuaCore.lua_State luaState, int index)
{
LuaLib.lua_pushvalue(luaState, index);
return new LuaUserData(LuaLib.lua_ref(luaState, 1), interpreter);
}
/*
* Gets the function in the index positon of the Lua stack.
*/
internal LuaFunction getFunction(LuaCore.lua_State luaState, int index)
{
LuaLib.lua_pushvalue(luaState, index);
return new LuaFunction(LuaLib.lua_ref(luaState, 1), interpreter);
}
/*
* Gets the CLR object in the index positon of the Lua stack. Returns
* delegates as Lua functions.
*/
internal object getNetObject(LuaCore.lua_State luaState, int index)
{
int idx = LuaLib.luanet_tonetobject(luaState, index);
return idx != -1 ? objects[idx] : null;
}
/*
* Gets the CLR object in the index positon of the Lua stack. Returns
* delegates as is.
*/
internal object getRawNetObject(LuaCore.lua_State luaState, int index)
{
int udata = LuaLib.luanet_rawnetobj(luaState, index);
return udata != -1 ? objects[udata] : null;
}
/*
* Pushes the entire array into the Lua stack and returns the number
* of elements pushed.
*/
internal int returnValues(LuaCore.lua_State luaState, object[] returnValues)
{
if(LuaLib.lua_checkstack(luaState, returnValues.Length+5))
{
for(int i = 0; i < returnValues.Length; i++)
push(luaState, returnValues[i]);
return returnValues.Length;
}
else
return 0;
}
/*
* Gets the values from the provided index to
* the top of the stack and returns them in an array.
*/
internal object[] popValues(LuaCore.lua_State luaState, int oldTop)
{
int newTop = LuaLib.lua_gettop(luaState);
if(oldTop == newTop)
return null;
else
{
var returnValues = new ArrayList();
for(int i = oldTop+1; i <= newTop; i++)
returnValues.Add(getObject(luaState, i));
LuaLib.lua_settop(luaState, oldTop);
return returnValues.ToArray();
}
}
/*
* Gets the values from the provided index to
* the top of the stack and returns them in an array, casting
* them to the provided types.
*/
internal object[] popValues(LuaCore.lua_State luaState, int oldTop, Type[] popTypes)
{
int newTop = LuaLib.lua_gettop(luaState);
if(oldTop == newTop)
return null;
else
{
int iTypes;
var returnValues = new ArrayList();
if(popTypes[0] == typeof(void))
iTypes = 1;
else
iTypes = 0;
for(int i = oldTop+1; i <= newTop; i++)
{
returnValues.Add(getAsType(luaState, i, popTypes[iTypes]));
iTypes++;
}
LuaLib.lua_settop(luaState, oldTop);
return returnValues.ToArray();
}
}
// kevinh - the following line doesn't work for remoting proxies - they always return a match for 'is'
// else if(o is ILuaGeneratedType)
private static bool IsILua(object o)
{
if(o is ILuaGeneratedType)
{
// Make sure we are _really_ ILuaGenerated
var typ = o.GetType();
return (!typ.GetInterface("ILuaGeneratedType").IsNull ());
}
else
return false;
}
/*
* Pushes the object into the Lua stack according to its type.
*/
internal void push(LuaCore.lua_State luaState, object o)
{
if(o.IsNull())
LuaLib.lua_pushnil(luaState);
else if(o is sbyte || o is byte || o is short || o is ushort ||
o is int || o is uint || o is long || o is float ||
o is ulong || o is decimal || o is double)
{
double d = Convert.ToDouble(o);
LuaLib.lua_pushnumber(luaState, d);
}
else if(o is char)
{
double d = (char)o;
LuaLib.lua_pushnumber(luaState, d);
}
else if(o is string)
{
string str = (string)o;
LuaLib.lua_pushstring(luaState, str);
}
else if(o is bool)
{
bool b = (bool)o;
LuaLib.lua_pushboolean(luaState, b);
}
else if(IsILua(o))
(((ILuaGeneratedType)o).__luaInterface_getLuaTable()).push(luaState);
else if(o is LuaTable)
((LuaTable)o).push(luaState);
else if(o is LuaCore.lua_CFunction)
pushFunction(luaState, (LuaCore.lua_CFunction)o);
else if(o is LuaFunction)
((LuaFunction)o).push(luaState);
else
pushObject(luaState, o, "luaNet_metatable");
}
/*
* Checks if the method matches the arguments in the Lua stack, getting
* the arguments if it does.
*/
internal bool matchParameters(LuaCore.lua_State luaState, MethodBase method, ref MethodCache methodCache)
{
return metaFunctions.matchParameters(luaState, method, ref methodCache);
}
}
}