lua-users home
lua-l archive

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


It was thus said that the Great Gavin Wraith once stated:
> I was pleased to get an email from a man who wanted to introduce
> his son to programming using Lua. He ended his email with:
> 
> > Anyway, my conclusion is this would be a good way to introduce my son to
> > programming, but the main obstacle is the debugging!  Throwback into the
> > editor would be ideal, if that could be arranged.
> 
> RISC OS has a module, DDEUtils, which makes throwback very straightforward.
> To use it, I need to define a function with a prototype
> 
> void throw (const char *filename, int linenumber, const char *message);
> 
> This I have done (using ARM assembler) and tested. I get a window
> opening showing the message, which when clicked on opens the file
> specified by filename at line number linenumber. OK so far.
> 
> I have been going through the Lua sources trying to understand what
> happens when an error is raised. The difficulty, from my point of
> view, is that the various error functions appear to be simply concatenating
> lots of error messages. But I need an error datatype
> 
> typedef struct err {
>    char *filename; int linenumber; char *message; } err;
> 
> not just char *message;. I need to extract the requisite filename and
> linenumber. Am I trying to squeeze my big foot into a glass slipper here?
> Any helpful tips would be much appreciated.

  It's not hard, but it's hard to explain.  Let me try.

  At work, I embed Lua within a larger application, and when calling the
main script (written in Lua), I do (basically):

	lua_getglobal(L,"error_handler");
	lua_getglobal(L,"main_function");
	lua_pushinteger(L,1);	/* some parameter to main_function() */
	rc = lua_pcall(L,1,LUA_MULTRET,-2);
	if (rc != 0)
	{
	  /*--------------------------------------------
	  ; an error happened; error_handler() was called.  We can arrange
	  ; to have it return what we need---see below.  Rest of code
	  ; deleted
	  ;-------------------------------------------------
	}

  So I call the main script and funnel any errors to a handler.  This can be
written in C (using the Lua API) or Lua.  Anyway, the one I have is written
in Lua.  In *that* function:

	function error_handler(...)
	{
	  local stack = {}
	  for i = 1 , 10 do 
	    local info = debug.getinfo(i,"Si")
	    if not info then break end
	    table.insert(stack,string.format(" [%s(%d)]",info.source,info.currentline)
	  end
	  syslog('error',"stack=%s",table.concat(stack))
	  return ...
	}

And in syslog(), I get:

	stack= [@foo/src/ddt.lua(92)]  [@foo/src/BAR/baz.lua(88)] [@foo/src/foo.lua(213)]

Line 92 of ddt.lua is error_handler(); the actual problem is in baz.lua on
line 88.  So, if we change the error handler a bit:

	function error_handler(errmsg)
	{
	  -- --------------------------------------
	  -- 2nd entry on the call stack is were the error is.
	  -- grab the location
	  -- -----------------------------

	  local info = debug.getinfo(2,"Si")

	  -- ----------------------------------------
	  -- if so, return some addtional information about 
	  -- the error (location) so we won't have to parse
	  -- it out of the error message.
	  -- ----------------------------------------

	  if info then
	    return errmsg,info.source:sub(2,-1),info.currentline
	  else
	    -- umm ... yeah ... 
	  end
	}

And going back to our C code above:

	rc = lua_pcall(L,1,LUA_MULTRET,-2);
	if (rc != 0)
	{
	  throw(
		lua_tostring(L,-1), /* the filename */
		lua_tointeger(L,-2),/* the location */
		lua_tostring(L,-3)  /* the error message */
	  );
	}

  You could do everything in Lua (except for calling throw()).  Assuming
there's a Lua function throw() (built using the C API) that does the actual
throw, in pure Lua, the only difference would be:

	-- we can use the same error_handler() function as above

	okay,a,b,c = xpcall(function() main_function(1) end,error_handler)
	if not okay then
	  throw(a,b,c)
	end

  I think this is enough information to get you going.

  -spc (I hope ... )