/* * 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); }
/* * Creates a new table as a global variable or as a field * inside an existing table */ public void NewTable(string fullPath) { string[] path = fullPath.Split(new char[] { '.' }); int oldTop = LuaLib.lua_gettop(luaState); if (path.Length == 1) { LuaLib.lua_newtable(luaState); LuaLib.lua_setglobal(luaState, fullPath); } else { LuaLib.lua_getglobal(luaState, path[0]); for (int i = 1; i < path.Length - 1; i++) { LuaLib.lua_pushstring(luaState, path[i]); LuaLib.lua_gettable(luaState, -2); } LuaLib.lua_pushstring(luaState, path[path.Length - 1]); LuaLib.lua_newtable(luaState); LuaLib.lua_settable(luaState, -3); } LuaLib.lua_settop(luaState, oldTop); }
/* * 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()); } }
/* * Excutes a Lua file and returns all the chunk's return * values in an array */ public object[] DoFile(string fileName) { int oldTop = LuaLib.lua_gettop(luaState); if (LuaLib.luaL_loadfile(luaState, fileName) == 0) { executing = true; try { if (LuaLib.lua_pcall(luaState, 0, -1, 0) == 0) { return(translator.popValues(luaState, oldTop)); } else { ThrowExceptionFromError(oldTop); } } finally { executing = false; } } else { ThrowExceptionFromError(oldTop); } return(null); // Never reached - keeps compiler happy }
/* * Sets a field of the table or userdata corresponding the the provided reference * to the provided value */ internal void setObject(int reference, string field, object val) { int oldTop = LuaLib.lua_gettop(luaState); LuaLib.lua_getref(luaState, reference); setObject(field.Split(new char[] { '.' }), val); LuaLib.lua_settop(luaState, oldTop); }
/* * Indexer for global variables from the LuaInterpreter * Supports navigation of tables by using . operator */ public object this[string fullPath] { get { object returnValue = null; int oldTop = LuaLib.lua_gettop(luaState); string[] path = fullPath.Split(new char[] { '.' }); LuaLib.lua_getglobal(luaState, path[0]); returnValue = translator.getObject(luaState, -1); if (path.Length > 1) { string[] remainingPath = new string[path.Length - 1]; Array.Copy(path, 1, remainingPath, 0, path.Length - 1); returnValue = getObject(remainingPath); } LuaLib.lua_settop(luaState, oldTop); return(returnValue); } set { int oldTop = LuaLib.lua_gettop(luaState); string[] path = fullPath.Split(new char[] { '.' }); if (path.Length == 1) { translator.push(luaState, value); LuaLib.lua_setglobal(luaState, fullPath); } else { LuaLib.lua_getglobal(luaState, path[0]); string[] remainingPath = new string[path.Length - 1]; Array.Copy(path, 1, remainingPath, 0, path.Length - 1); setObject(remainingPath, value); } LuaLib.lua_settop(luaState, oldTop); // Globals auto-complete if (value.IsNull()) { // Remove now obsolete entries globals.Remove(fullPath); } else { // Add new entries if (!globals.Contains(fullPath)) { registerGlobal(fullPath, value.GetType(), 0); } } } }
/* * Sets a numeric field of the table or userdata corresponding the the provided reference * to the provided value */ internal void setObject(int reference, object field, object val) { int oldTop = LuaLib.lua_gettop(luaState); LuaLib.lua_getref(luaState, reference); translator.push(luaState, field); translator.push(luaState, val); LuaLib.lua_settable(luaState, -3); LuaLib.lua_settop(luaState, oldTop); }
/* * Gets a field of the table or userdata corresponding to the provided reference */ internal object getObject(int reference, string field) { int oldTop = LuaLib.lua_gettop(luaState); LuaLib.lua_getref(luaState, reference); object returnValue = getObject(field.Split(new char[] { '.' })); LuaLib.lua_settop(luaState, oldTop); return(returnValue); }
/* * Compares the two values referenced by ref1 and ref2 for equality */ internal bool compareRef(int ref1, int ref2) { int top = LuaLib.lua_gettop(luaState); LuaLib.lua_getref(luaState, ref1); LuaLib.lua_getref(luaState, ref2); int equal = LuaLib.lua_equal(luaState, -1, -2); LuaLib.lua_settop(luaState, top); return(equal != 0); }
/* * Gets a numeric field of the table or userdata corresponding the the provided reference */ internal object getObject(int reference, object field) { int oldTop = LuaLib.lua_gettop(luaState); LuaLib.lua_getref(luaState, reference); translator.push(luaState, field); LuaLib.lua_gettable(luaState, -2); object returnValue = translator.getObject(luaState, -1); LuaLib.lua_settop(luaState, oldTop); return(returnValue); }
/* * Gets a field of the table corresponding to the provided reference * using rawget (do not use metatables) */ internal object rawGetObject(int reference, string field) { int oldTop = LuaLib.lua_gettop(luaState); LuaLib.lua_getref(luaState, reference); LuaLib.lua_pushstring(luaState, field); LuaLib.lua_rawget(luaState, -2); object obj = translator.getObject(luaState, -1); LuaLib.lua_settop(luaState, oldTop); return(obj); }
/* * 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, MethodBase function /*MethodInfo function*/) //CP: Fix for struct constructor by Alexander Kappner (link: http://luaforge.net/forum/forum.php?thread_id = 2859&forum_id = 145) { // We leave nothing on the stack when we are done int oldTop = LuaLib.lua_gettop(luaState); var wrapper = new LuaMethodWrapper(translator, target, function.DeclaringType, function); translator.push(luaState, new LuaCore.lua_CFunction(wrapper.call)); this[path] = translator.getObject(luaState, -1); var f = GetFunction(path); LuaLib.lua_settop(luaState, oldTop); return(f); }
/// <summary> /// /// </summary> /// <param name = "fileName"></param> /// <returns></returns> public LuaFunction LoadFile(string fileName) { int oldTop = LuaLib.lua_gettop(luaState); if (LuaLib.luaL_loadfile(luaState, fileName) != 0) { ThrowExceptionFromError(oldTop); } var result = translator.getFunction(luaState, -1); translator.popValues(luaState, oldTop); return(result); }
/* * 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); }
public ListDictionary GetTableDict(LuaTable table) { var dict = new ListDictionary(); int oldTop = LuaLib.lua_gettop(luaState); translator.push(luaState, table); LuaLib.lua_pushnil(luaState); while (LuaLib.lua_next(luaState, -2) != 0) { dict[translator.getObject(luaState, -2)] = translator.getObject(luaState, -1); LuaLib.lua_settop(luaState, -2); } LuaLib.lua_settop(luaState, oldTop); return(dict); }
/// <summary> /// Debug tool to dump the lua stack /// </summary> /// FIXME, move somewhere else public static void dumpStack(ObjectTranslator translator, LuaCore.lua_State luaState) { int depth = LuaLib.lua_gettop(luaState); Debug.WriteLine("lua stack depth: " + depth); for (int i = 1; i <= depth; i++) { var type = LuaLib.lua_type(luaState, i); // 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 == LuaTypes.Table) ? "table" : LuaLib.lua_typename(luaState, type); string strrep = LuaLib.lua_tostring(luaState, i).ToString(); if (type == LuaTypes.UserData) { object obj = translator.getRawNetObject(luaState, i); strrep = obj.ToString(); } } }
/* * 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()); } }
/* * Calls the object as a function with the provided arguments and * casting returned values to the types in returnTypes before returning * them in an array */ internal object[] callFunction(object function, object[] args, Type[] returnTypes) { int nArgs = 0; int oldTop = LuaLib.lua_gettop(luaState); if (!LuaLib.lua_checkstack(luaState, args.Length + 6)) { throw new LuaException("Lua stack overflow"); } translator.push(luaState, function); if (!args.IsNull()) { nArgs = args.Length; for (int i = 0; i < args.Length; i++) { translator.push(luaState, args[i]); } } executing = true; try { int error = LuaLib.lua_pcall(luaState, nArgs, -1, 0); if (error != 0) { ThrowExceptionFromError(oldTop); } } finally { executing = false; } return(!returnTypes.IsNull() ? translator.popValues(luaState, oldTop, returnTypes) : translator.popValues(luaState, oldTop)); }
/* * 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); }
/// <summary> /// /// </summary> /// <param name = "chunk"></param> /// <param name = "name"></param> /// <returns></returns> public LuaFunction LoadString(string chunk, string name) { int oldTop = LuaLib.lua_gettop(luaState); executing = true; try { if (LuaLib.luaL_loadbuffer(luaState, chunk, name) != 0) { ThrowExceptionFromError(oldTop); } } finally { executing = false; } var result = translator.getFunction(luaState, -1); translator.popValues(luaState, oldTop); return(result); }
/* * 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(LuaCore.lua_State luaState, MethodBase method, ref MethodCache methodCache) { ExtractValue extractValue; bool isMethod = true; var paramInfo = method.GetParameters(); int currentLuaParam = 1; int nLuaParams = LuaLib.lua_gettop(luaState); var paramList = new ArrayList(); var outList = new List <int>(); var argTypes = new List <MethodArgs>(); foreach (var 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 (_IsTypeCorrect(luaState, currentLuaParam, currentNetParam, out extractValue)) // Type checking { int index = paramList.Add(extractValue(luaState, currentLuaParam)); var 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 (_IsParamsArray(luaState, currentLuaParam, currentNetParam, out extractValue)) { object luaParamValue = extractValue(luaState, currentLuaParam); var paramArrayType = currentNetParam.ParameterType.GetElementType(); Array paramArray; if (luaParamValue is LuaTable) { var table = (LuaTable)luaParamValue; var tableEnumerator = table.GetEnumerator(); paramArray = Array.CreateInstance(paramArrayType, table.Values.Count); tableEnumerator.Reset(); int paramArrayIndex = 0; while (tableEnumerator.MoveNext()) { paramArray.SetValue(Convert.ChangeType(tableEnumerator.Value, currentNetParam.ParameterType.GetElementType()), paramArrayIndex); paramArrayIndex++; } } else { paramArray = Array.CreateInstance(paramArrayType, 1); paramArray.SetValue(luaParamValue, 0); } int index = paramList.Add(paramArray); var methodArg = new MethodArgs(); methodArg.index = index; methodArg.extractValue = extractValue; methodArg.isParamsArray = true; methodArg.paramsArrayType = paramArrayType; argTypes.Add(methodArg); currentLuaParam++; } 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); }
/// <summary> /// Pops a value from the lua stack. /// </summary> /// <returns>Returns the top value from the lua stack.</returns> /// <author>Reinhard Ostermeier</author> public object Pop() { int top = LuaLib.lua_gettop(luaState); return(translator.popValues(luaState, top - 1)[0]); }