Lunatic translator: in error tracebacks, show line numbers of the source file.

Instead of those of the translated code. Also some codegen tweaks and fixes.

git-svn-id: https://svn.eduke32.com/eduke32@3535 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
helixhorned 2013-03-03 16:06:16 +00:00
parent ba0970cede
commit bad2da3026
4 changed files with 153 additions and 24 deletions

View File

@ -1482,10 +1482,26 @@ do
end
end
concode = lunacon.compile(confn)
local lineinfo
concode, lineinfo = lunacon.compile(confn)
assert(lineinfo)
if (concode == nil) then
error("Failure compiling CON code, exiting.", 0)
end
-- Translate one Lua line number to a CON file name + line number
local function transline(lnum)
return string.format("%s:%d", lineinfo:getfline(tonumber(lnum)))
end
-- Register the function that tweaks an error message, looking out for
-- errors from CON and translating the line numbers.
local function tweak_traceback_msg(errmsg)
return errmsg:gsub('%[string "CON"%]:([0-9]+)', transline)
end
set_tweak_traceback_internal(tweak_traceback_msg)
end
-- change the environment of this chunk to the table G_

View File

@ -425,14 +425,18 @@ local walltype_mt = {
end,
_set_nextwall = function(w, nextwall)
-- XXX: this disallows making a red wall white
bcheck.wall_idx(nextwall)
-- NOTE: Allow setting a wall to white too, but no checking of the
-- consistency invariant ".nextwall>=0 iff .nextsector>=0".
if (not (nextwall < 0)) then
bcheck.wall_idx(nextwall)
end
ffi.cast(walltype_ptr_ct, w).nextwall = nextwall
end,
_set_nextsector = function(w, nextsector)
-- XXX: this disallows making a red wall white
check_sector_idx(nextsector)
if (not (nextsector < 0)) then
check_sector_idx(nextsector)
end
ffi.cast(walltype_ptr_ct, w).nextsector = nextsector
end,
@ -679,7 +683,7 @@ function GenStructMetatable(Structname, Boundname, StaticMembersTab)
if (key >= 0 and key < ffiC[Boundname]) then
return ffiC[Structname][key]
end
error("out-of-bounds "..Structname.."[] read access", 2)
error("out-of-bounds "..Structname.."[] read access with index "..key, 2)
elseif (type(key)=="string") then
return StaticMembersTab[key]
end

View File

@ -18,6 +18,7 @@ local loadstring = loadstring
local pairs = pairs
local pcall = pcall
local print = print
local setmetatable = setmetatable
local tonumber = tonumber
local tostring = tostring
local type = type
@ -98,7 +99,7 @@ local g_warn = { ["not-redefined"]=true, ["bad-identifier"]=true,
["number-conversion"]=true, ["system-gamevar"]=true, }
-- Code generation options.
local g_cgopt = { ["no"]=false, }
local g_cgopt = { ["no"]=false, ["debug-lineinfo"]=false, }
-- How many 'if' statements are following immediately each other,
-- needed to cope with CONs dangling-else resolution
@ -2038,9 +2039,9 @@ local Cinner = {
displayrandvarvar = cmd(W,R)
/ "%1=_con._displayrand(%2)",
dist = cmd(W,R,R)
/ "%1=_xmath.dist(sprite[%1],sprite[%2])",
/ "%1=_xmath.dist(sprite[%2],sprite[%3])",
ldist = cmd(W,R,R)
/ "%1=_xmath.ldist(sprite[%1],sprite[%2])",
/ "%1=_xmath.ldist(sprite[%2],sprite[%3])",
dragpoint = cmd(R,R,R)
/ handle.NYI,
rotatepoint = cmd(R,R,R,R,R,W,W)
@ -2420,7 +2421,7 @@ end
-- These are tracers for specific patterns which can be disabled
-- if desired.
local function Keyw(kwname) return TraceFunc(kwname, "kw", false) end
local function NotKeyw(text) return TraceFunc(text, "!kw", false) end
--local function NotKeyw(text) return TraceFunc(text, "!kw", false) end
--local function Ident(idname) return TraceFunc(idname, "id", false) end
local function Stmt(cmdpat) return TraceFunc(cmdpat, "st", false) end
@ -2428,33 +2429,37 @@ local function Stmt(cmdpat) return TraceFunc(cmdpat, "st", false) end
--Cinner["myosx"] = Temp(Cinner["myosx"])
----==== Translator continued ====----
local function after_inner_cmd_Cmt(subj, pos, ...)
local capts = {...}
local function attachlinenum(capts, pos)
capts[1] = capts[1].."--"..getlinecol(pos)
return capts[1]
end
local function after_inner_cmd_Cmt(subj, pos, ...)
if (g_numerrors == inf) then
return nil
end
local capts = {...}
if (type(capts[1])=="string" and capts[2]==nil) then
return true, capts[1] .."--"..linecolstr(pos) --TEMP
return true, attachlinenum(capts, pos)
end
return true
end
local function after_if_cmd_Cmt(subj, pos, ...)
local capts = {...}
if (g_numerrors == inf) then
return nil
end
local capts = {...}
if (capts[1] ~= nil) then
assert(#capts <= 3)
for i=1,#capts do
assert(type(capts[i]=="string"))
end
return true, unpack(capts, 1, #capts)
-- attachlinenum(capts, pos)
return true, unpack(capts)
end
return true
@ -2745,7 +2750,7 @@ local Grammar = Pat{
-- getactor[THISACTOR].x x
-- getactor [THISACTOR].y y
-- This is in need of cleanup!
t_identifier = -NotKeyw(conl.keyword * (sp1 + "[")) * tok.identifier_all,
t_identifier = -(conl.keyword * (sp1 + "[")) * tok.identifier_all,
-- TODO?: SST TC has e.g. "1267AT", relying on it to be parsed as a number "1267".
-- However, this conflicts with bad-identifiers, so it should be checked last.
-- This would also handle LNGA2's "00000000h", though would give problems with
@ -2853,8 +2858,77 @@ local function flatten_codetab(codetab)
return tmpcode
end
local function get_code_string(codetab)
return table.concat(flatten_codetab(g_curcode), "\n")
--== Lua -> CON line number mapping for error messages ==--
local lineinfo_mt = {
__index = {
-- Get CON file name and CON line number from Lua line number.
getfline = function(self, lualine)
local llines, lfiles = self.llines, self.lfiles
assert(lualine >= 1 and lualine <= #llines)
-- Get the CON line number: a simple lookup.
local conline = llines[lualine]
-- Find the CON file name next.
local confile = nil
for i=1,#lfiles do
if (lfiles[i].line > lualine) then
break
end
-- Shorten the file name by stripping the directory parts.
confile = lfiles[i].name:match("[^/]+$")
end
return confile or "???", conline
end,
},
__metatable = true,
}
-- Construct Lua->CON line mapping info. This walks the generated code and
-- looks for our inserted comment strings, so it's kind of hackish.
local function get_lineinfo(flatcode)
local curline, curfile = { 0 }, { "<none>" } -- stacks
-- llines: [<Lua code line number>] = <CON code line number>
-- lfiles: [<sequence number>] = { line=<Lua line number>, name=<filename> }
local llines, lfiles = {}, {}
for i=1,#flatcode do
local code = flatcode[i]
local lnumstr = code:match("%-%-([0-9]+)$")
local begfn = lnumstr and nil or code:match("^%-%- BEGIN (.+)$")
local endfn = lnumstr and nil or code:match("^%-%- END (.+)$")
if (lnumstr) then
curline[#curline] = assert(tonumber(lnumstr))
elseif (begfn) then
curfile[#curfile+1] = begfn
curline[#curline+1] = 1
-- Begin an included file.
lfiles[#lfiles+1] = { line=i, name=begfn }
elseif (endfn) then
assert(endfn==curfile[#curfile]) -- assert proper nesting
curfile[#curfile] = nil
curline[#curline] = nil
-- End an included file, so reset the name to the includer's one.
lfiles[#lfiles+1] = { line=i, name=curfile[#curfile] }
end
llines[i] = assert(curline[#curline])
end
return setmetatable({ llines=llines, lfiles=lfiles }, lineinfo_mt)
end
-- <lineinfop>: Get line info?
local function get_code_string(codetab, lineinfop)
local flatcode = flatten_codetab(codetab)
local lineinfo = lineinfop and get_lineinfo(flatcode)
return table.concat(flatcode, "\n"), lineinfo
end
function on.parse_begin()
@ -2957,6 +3031,9 @@ local function handle_cmdline_arg(str)
g_cgopt["no"] = true
ok = true
end
elseif (str:sub(2)=="fdebug-lineinfo") then
g_cgopt["debug-lineinfo"] = true
ok = true
elseif (kind=="I" and #str >= 3) then
-- default directory (only ONCE, not search path)
g_defaultDir = str:sub(3)
@ -3020,15 +3097,19 @@ if (string.dump) then
local io = require("io")
local file = onlycheck and io.stdout or io.stderr
local code = get_code_string(g_curcode)
local code, lineinfo = get_code_string(g_curcode, g_cgopt["debug-lineinfo"])
local func, errmsg = loadstring(code, "CON")
file:write(format("-- GENERATED CODE for \"%s\":\n", filename))
-- file:write(format("-- GENERATED CODE for \"%s\":\n", filename))
if (func == nil) then
file:write(format("-- (invalid Lua code: %s)\n", errmsg))
file:write(format("-- INVALID Lua CODE: %s\n", errmsg))
end
if (not onlycheck) then
if (lineinfo) then
for i=1,#lineinfo.llines do
file:write(format("%d -> %s:%d\n", i, lineinfo:getfline(i)))
end
elseif (not onlycheck) then
file:write(code)
file:write("\n")
end
@ -3052,6 +3133,6 @@ else
end
end
return get_code_string(g_curcode)
return get_code_string(g_curcode, true)
end
end

View File

@ -30,6 +30,9 @@ int32_t g_elEventRETURN;
uint32_t g_eventCalls[MAXEVENTS], g_actorCalls[MAXTILES];
double g_eventTotalMs[MAXEVENTS], g_actorTotalMs[MAXTILES];
// Used as Lua registry key to the tweak_traceback_msg() function, set to 1 if
// such a function has been registered.
static uint8_t g_tweakTracebackMsg = 0;
// forward-decls...
static int32_t SetEvent_CF(lua_State *L);
@ -219,9 +222,32 @@ static int our_traceback_CF(lua_State *L)
lua_call(L, 1, 1);
Bassert(lua_gettop(L)==2); // Lua will pop off args
if (g_tweakTracebackMsg)
{
// Get tweak_traceback_msg() onto the stack.
lua_pushlightuserdata(L, &g_tweakTracebackMsg);
lua_gettable(L, LUA_REGISTRYINDEX);
lua_pushvalue(L, -2); // push copy of error message string
Bassert(lua_type(L, -1)==LUA_TSTRING);
// Call tweak_traceback_msg(). CAREFUL, it's unprotected!
lua_call(L, 1, 1);
}
return 1;
}
// Registers a function: str = tweak_traceback_msg(str)
static int32_t SetTweakTracebackMsg_CF(lua_State *L)
{
Bassert(lua_gettop(L)==1);
L_CheckAndRegisterFunction(L, &g_tweakTracebackMsg);
g_tweakTracebackMsg = 1;
return 0;
}
////// Lua C-API interfaces for C game functions that may call events.
// http://www.freelists.org/post/luajit/intermitten-lua-pcall-crash-on-x86-64-linux,1
@ -332,6 +358,8 @@ static void El_StateSetup(lua_State *L)
lua_setglobal(L, "gameevent_internal");
lua_pushcfunction(L, SetActor_CF);
lua_setglobal(L, "gameactor_internal");
lua_pushcfunction(L, SetTweakTracebackMsg_CF);
lua_setglobal(L, "set_tweak_traceback_internal");
El_PushCFunctions(L);