private void PushFuncName(LuaDebug ar) { if (ar.NameWhat.Length > 0 && ar.NameWhat[0] != '\0') // is there a name? { API.PushString(string.Format("function '{0}'", ar.Name)); } else if (ar.What.Length > 0 && ar.What[0] == 'm') // main? { API.PushString("main chunk"); } else if (ar.What.Length > 0 && ar.What[0] == 'C') { if (PushGlobalFuncName(ar)) { API.PushString(string.Format("function '{0}'", API.ToString(-1))); API.Remove(-2); //remove name } else { API.PushString("?"); } } else { API.PushString(string.Format("function <{0}:{1}>", ar.ShortSrc, ar.LineDefined)); } }
private int CountLevels() { LuaDebug ar = new LuaDebug(); int li = 1; int le = 1; // find an upper bound while (API.GetStack(le, ar)) { li = le; le *= 2; } // do a binary search while (li < le) { int m = (li + le) / 2; if (API.GetStack(m, ar)) { li = m + 1; } else { le = m; } } return(le - 1); }
private void FuncInfo(LuaDebug ar, StkId func) { Utl.Assert(func.V.TtIsFunction()); if (func.V.ClIsLuaClosure()) { var lcl = func.V.ClLValue(); var p = lcl.Proto; ar.Source = string.IsNullOrEmpty(p.Source) ? "=?" : p.Source; ar.LineDefined = p.LineDefined; ar.LastLineDefined = p.LastLineDefined; ar.What = (ar.LineDefined == 0) ? "main" : "Lua"; } else if (func.V.ClIsCsClosure()) { ar.Source = "=[C#]"; ar.LineDefined = -1; ar.LastLineDefined = -1; ar.What = "C#"; } else { throw new System.NotImplementedException(); } if (ar.Source.Length > LuaDef.LUA_IDSIZE) { ar.ShortSrc = ar.Source.Substring(0, LuaDef.LUA_IDSIZE); } else { ar.ShortSrc = ar.Source; } }
public int L_ArgError(int narg, string extraMsg) { LuaDebug ar = new LuaDebug(); if (!API.GetStack(0, ar)) // no stack frame ? { return(L_Error("bad argument {0} ({1})", narg, extraMsg)); } GetInfo("n", ar); if (ar.NameWhat == "method") { narg--; // do not count 'self' if (narg == 0) // error is in the self argument itself? { return(L_Error("calling '{0}' on bad self", ar.Name)); } } if (ar.Name == null) { ar.Name = PushGlobalFuncName(ar) ? API.ToString(-1) : "?"; } return(L_Error("bad argument {0} to '{1}' ({2})", narg, ar.Name, extraMsg)); }
private const int LEVELS2 = 10; // size of the second part of the stack public void L_Where(int level) { LuaDebug ar = new LuaDebug(); if (API.GetStack(level, ar)) // check function at level { GetInfo("Sl", ar); // get info about it if (ar.CurrentLine > 0) // is there info? { API.PushString(string.Format("{0}:{1}: ", ar.ShortSrc, ar.CurrentLine)); return; } } API.PushString(""); // else, no information available... }
private bool PushGlobalFuncName(LuaDebug ar) { int top = API.GetTop(); GetInfo("f", ar); API.PushGlobalTable(); if (FindField(top + 1, 2)) { API.Copy(-1, top + 1); API.Pop(2); return(true); } else { API.SetTop(top); // remove function and global table return(false); } }
public void L_Traceback(ILuaState otherLua, string msg, int level) { LuaState oLua = otherLua as LuaState; LuaDebug ar = new LuaDebug(); int top = API.GetTop(); int numLevels = oLua.CountLevels(); int mark = (numLevels > LEVELS1 + LEVELS2) ? LEVELS1 : 0; if (msg != null) { API.PushString(string.Format("{0}\n", msg)); } API.PushString("stack traceback:"); while (otherLua.GetStack(level++, ar)) { if (level == mark) // too many levels? { API.PushString("\n\t..."); level = numLevels - LEVELS2; // and skip to last ones } else { oLua.GetInfo("Slnt", ar); API.PushString(string.Format("\n\t{0}:", ar.ShortSrc)); if (ar.CurrentLine > 0) { API.PushString(string.Format("{0}:", ar.CurrentLine)); } API.PushString(" in "); PushFuncName(ar); if (ar.IsTailCall) { API.PushString("\n\t(...tail calls...)"); } API.Concat(API.GetTop() - top); } } API.Concat(API.GetTop() - top); }
public int GetInfo(string what, LuaDebug ar) { CallInfo ci; StkId func; int pos = 0; if (what[pos] == '>') { ci = null; func = Stack[Top.Index - 1]; Utl.ApiCheck(func.V.TtIsFunction(), "function expected"); pos++; Top = Stack[Top.Index - 1]; } else { ci = BaseCI[ar.ActiveCIIndex]; func = Stack[ci.FuncIndex]; Utl.Assert(Stack[ci.FuncIndex].V.TtIsFunction()); } // var IsClosure( func.Value ) ? func.Value int status = AuxGetInfo(what, ar, func, ci); if (what.Contains("f")) { Top.V.SetObj(ref func.V); IncrTop(); } if (what.Contains("L")) { CollectValidLines(func); } return(status); }
bool ILuaAPI.GetStack(int level, LuaDebug ar) { if (level < 0) { return(false); } int index; for (index = CI.Index; level > 0 && index > 0; --index) { level--; } bool status = false; if (level == 0 && index > 0) { status = true; ar.ActiveCIIndex = index; } return(status); }
private int AuxGetInfo(string what, LuaDebug ar, StkId func, CallInfo ci) { int status = 1; for (int i = 0; i < what.Length; ++i) { char c = what[i]; switch (c) { case 'S': { FuncInfo(ar, func); break; } case 'l': { ar.CurrentLine = (ci != null && ci.IsLua) ? GetCurrentLine(ci) : -1; break; } case 'u': { Utl.Assert(func.V.TtIsFunction()); if (func.V.ClIsLuaClosure()) { var lcl = func.V.ClLValue(); ar.NumUps = lcl.Upvals.Length; ar.IsVarArg = lcl.Proto.IsVarArg; ar.NumParams = lcl.Proto.NumParams; } else if (func.V.ClIsCsClosure()) { var ccl = func.V.ClCsValue(); ar.NumUps = ccl.Upvals.Length; ar.IsVarArg = true; ar.NumParams = 0; } else { throw new System.NotImplementedException(); } break; } case 't': { ar.IsTailCall = (ci != null) ? ((ci.CallStatus & CallStatus.CIST_TAIL) != 0) : false; break; } case 'n': { var prevCI = BaseCI[ci.Index - 1]; if (ci != null && ((ci.CallStatus & CallStatus.CIST_TAIL) == 0) && prevCI.IsLua) { ar.NameWhat = GetFuncName(prevCI, out ar.Name); } else { ar.NameWhat = null; } if (ar.NameWhat == null) { ar.NameWhat = ""; // not found ar.Name = null; } break; } case 'L': case 'f': // handled by GetInfo break; default: status = 0; // invalid option break; } } return(status); }