lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Lua API errors are hard to find without a debugger.
Here is something that might help. I'm posting this to ask people whether this
is useful and if so how it can be improved.
If you find it useful, I'll probably write a LTN about this.
 
The Lua program at the end of the message reads lua.h and outputs two files,
t.c and t.h.
The file t.c contains a set of wrappers to the API.  Here is a typical wrapper:
 
  int Lua_callfunction (lua_Object f,
          const char* _FILE, int _LINE, const char* _FUNC) {
   int rc;
   Lua_tracein("lua_callfunction",_FILE,_LINE,_FUNC);
   rc=lua_callfunction(f);
   Lua_traceout("lua_callfunction",_FILE,_LINE,_FUNC);
   return rc;
  }
 
The file t.h redefines all calls to the official API to go through the wrapper.
Here is the entry for lua_callfunction in t.h:
 
  int Lua_callfunction (lua_Object f,
          const char* _FILE, int _LINE, const char* _FUNC);
 
  #define lua_callfunction(f) \
          Lua_callfunction(f,__FILE__,__LINE__,__FUNCTION__)
 
If you're not using gcc, then do
 
  #ifndef  __GNUC__
  #define __FUNCTION__ ""
  #endif
 
or change the Lua program below.
 
You have to write your own Lua_tracein and Lua_traceout.
Here is a simple implementation, which generates a lot of output.
 
  void Lua_tracein(char* func, char* file, int line, char* parent)
  {
   fprintf(stderr,"lua_trace: { %s:%d [%s] %s\n",file,line,parent,func);
  }
 
  void Lua_traceout(char* func, char* file, int line, char* parent)
  {
   fprintf(stderr,"lua_trace: } %s:%d [%s] %s\n",file,line,parent,func);
  }
 
Another possibility would be to save the args to Lua_tracein into static 
variables that are output when an error happens. You can do this by registering
a function with atexit.
 
Comments welcome.
--lhf

-- make APi wrappers: lua thisfile.lua <lua.h

$debug

function bodyC(l,t,f,p,a,A)
 write(t," Lua_",f," (",p,A,") {\n")
 if t~="void" then write(" ",t," rc;\n") end
 write(" Lua_tracein(\"lua_",f,"\",_FILE,_LINE,_FUNC);\n")
 if t~="void" then write(" rc=") else write(" ") end
 write("lua_",f,"(",a,");\n")
 write(" Lua_traceout(\"lua_",f,"\",_FILE,_LINE,_FUNC);\n")
 if t~="void" then write(" return rc;\n") end
 write("}\n\n")
end

function bodyH(l,t,f,p,a,A)
 write(t," Lua_",f," (",p,A,");\n\n")
 A="__FILE__,__LINE__,__FUNCTION__"
 if p~="" then A=","..A end
 write("#define\tlua_",f,"(",a,") \\\n\tLua_",f,"(",a,A,")\n\n\n")
end

function header(o,e,v)
 _OUTPUT=o
 write("/* luatrace.",e," -- automatically extracted from lua.h (",v,") */\n\n")
end

function body(l)
 l=gsub(l,"[\n\t ]+"," ")
 l=gsub(l," %*","* ")
 local a,b,t,f,p=strfind(l,"(.*) lua_(%w+) %((.*)%)")
 if a==nil or f=="newstate" then return end
 A="const char* _FILE, int _LINE, const char* _FUNC"
 if p=="void" then
  p=""
  a=""
 else
  a=gsub(p..",","%s*.-%s*(%w+),","%1,")
  a=gsub(a,",$","")
  A=",\n\t"..A
 end
 _OUTPUT=C_OUT bodyC(l,t,f,p,a,A)
 _OUTPUT=H_OUT bodyH(l,t,f,p,a,A)
end

C_OUT=openfile("t.c","w")
H_OUT=openfile("t.h","w")
local T=read"*a"
local _,_,v=strfind(T,'LUA_VERSION.-"Lua.- (.-)"')
header(C_OUT,"c",v)
header(H_OUT,"h",v)
gsub(T,'\n([^\n]-%b());',body)