5

I'm using Lua to parse scripts written in some language (let's call it L) and create Lua-code that can be run by e.g. LuaJIT. But to simplify debugging for the users, I want to map the run time errors given by Lua/LuaJIT to the correct line in the L-files. I do this by xpcalling the created Lua-code, translating the error message and stacktrace and then calling error with this message. Unfortunately this gives me two stack traces, one created by me and one tracing back to the function that called error. Is it possible to get rid of this stack trace, or is there some better way of doing this?

local status, err = xpcall(loadedCode, debug.traceback)
if not status then
  error(createANewErrorMessageWithPrettyTraceback(err),0)
end

Output:

luajit: ./my/file.name:5: Some error message
stack traceback:
    my pretty traceback
stack traceback:
    [C]: in function 'error'
    ./my/file/calling/error.lua:44: in function <./my/file/calling/error.lua:26>
    ./my-main:16: in main chunk
    [C]: at 0x00404180

I know that e.g. Moonscript does something similar to this, but as far as I can see they just write the new error message to stderr and then continues as normal, instead of stopping the program which is what I want to do.
There is a possibility of doing this and then calling error with no arguments, which will make the program fail (actually I think it's error that fails), but this feels like quite an ugly solution, so I'll rather keep the stupid second trace than doing that.
PS: I assume what the title asks actually doesn't work (as error only takes two arguments), so what I'm actually asking is more how something like this can be achieved. (Are there other functions that do similar things perhaps, or where I should look to figure out how to write that function myself.)
Edit: Is it perhaps possible to edit the function that error's using to get its traceback, as it is with debug.traceback?

2
  • Why not just print the traceback instead of calling error? Commented Dec 15, 2013 at 0:22
  • Because I want the program to fail when it has an error, instead of just telling the user that something happened. But as Ryan Stein pointed out below, I can just call os.exit. Commented Dec 16, 2013 at 8:13

2 Answers 2

3

I wanted to do something similar (only from Lua directly) and I ended up overwriting debug.traceback function itself to change the stack trace to suit my needs. My code is below; see if this method works for you as well:

  local dtraceback = debug.traceback
  debug.traceback = function (...)
    if select('#', ...) >= 1 then
      local err, lvl = ...
      if err and type(err) ~= 'thread' then
        local trace = dtraceback(err, (lvl or 2)+1)
        if genv.print == iobase.print then -- no remote redirect
          return trace
        else
          genv.print(trace) -- report the error remotely
          return -- don't report locally to avoid double reporting
        end
      end
    end
    -- direct call to debug.traceback: return the original.
    -- debug.traceback(nil, level) doesn't work in Lua 5.1
    -- (http://lua-users.org/lists/lua-l/2011-06/msg00574.html), so
    -- simply remove first frame from the stack trace
    return (dtraceback(...):gsub("(stack traceback:\n)[^\n]*\n", "%1"))
  end
Sign up to request clarification or add additional context in comments.

Comments

2

You could simply display the modified traceback that you want and exit.

local function errh(err)
    print(createANewErrorMessageWithPrettyTraceback(debug.traceback(err, 2)))
    os.exit(-1) -- error code
end

local status, result = xpcall(loadedCode, errh)
-- The script will never reach this point if there is an error.
print(result)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.