More improvements to error reporting.

This commit is contained in:
Bruce Hill 2018-05-29 19:10:03 -07:00
parent 8806d7639e
commit 21e3a7b375
2 changed files with 87 additions and 55 deletions

View File

@ -1501,7 +1501,7 @@ OPTIONS
break break
end end
level = level + 1 level = level + 1
local name = calling_fn.name local name = calling_fn.name and "function '" .. tostring(calling_fn.name) .. "'" or nil
if calling_fn.linedefined == 0 then if calling_fn.linedefined == 0 then
name = "main chunk" name = "main chunk"
end end
@ -1527,20 +1527,17 @@ OPTIONS
assert(filename) assert(filename)
local file = FILE_CACHE[filename]:sub(tonumber(start), tonumber(stop)) local file = FILE_CACHE[filename]:sub(tonumber(start), tonumber(stop))
local err_line = get_line(file, calling_fn.currentline):sub(1, -2) local err_line = get_line(file, calling_fn.currentline):sub(1, -2)
local offending_statement = colored.red(err_line) local offending_statement = colored.bright(colored.red(err_line:match("^[ ]*(.*)")))
line = colored.yellow(tostring(filename) .. ":" .. tostring(calling_fn.currentline) .. "\n" .. tostring(offending_statement))
do do
local arg_orders = nomsu.environment.ARG_ORDERS[calling_fn.func] local arg_orders = nomsu.environment.ARG_ORDERS[calling_fn.func]
if arg_orders then if arg_orders then
name = colored.bright(colored.yellow(next(arg_orders))) name = "action '" .. tostring(next(arg_orders)) .. "'"
else else
name = colored.bright(colored.yellow("main chunk")) name = "main chunk"
end end
end end
line = colored.yellow(tostring(filename) .. ":" .. tostring(calling_fn.currentline) .. " in " .. tostring(name) .. "\n " .. tostring(offending_statement))
else else
if calling_fn.istailcall and not name then
name = "<tail call>"
end
local file local file
ok, file = pcall(function() ok, file = pcall(function()
return FILE_CACHE[calling_fn.short_src] return FILE_CACHE[calling_fn.short_src]
@ -1549,20 +1546,40 @@ OPTIONS
file = nil file = nil
end end
local line_num local line_num
if name == nil and debug.getinfo(level + 1) then if name == nil then
local i = 1 local search_level = level
while true do local _info = debug.getinfo(search_level)
local varname, val = debug.getlocal(level + 1, i) while _info and (_info.func == pcall or _info.func == xpcall) do
search_level = search_level + 1
_info = debug.getinfo(search_level)
end
if _info then
for i = 1, 999 do
local varname, val = debug.getlocal(search_level, i)
if not varname then if not varname then
break break
end end
if val == calling_fn.func then if val == calling_fn.func then
name = varname name = "local '" .. tostring(varname) .. "'"
if not varname:match("%(") then if not varname:match("%(") then
break break
end end
end end
i = i + 1 end
if not (name) then
for i = 1, _info.nups do
local varname, val = debug.getupvalue(_info.func, i)
if not varname then
break
end
if val == calling_fn.func then
name = "upvalue '" .. tostring(varname) .. "'"
if not varname:match("%(") then
break
end
end
end
end
end end
end end
if file and calling_fn.short_src:match(".moon$") and LINE_TABLES[file] then if file and calling_fn.short_src:match(".moon$") and LINE_TABLES[file] then
@ -1571,22 +1588,26 @@ OPTIONS
for _ in file:sub(1, char):gmatch("\n") do for _ in file:sub(1, char):gmatch("\n") do
line_num = line_num + 1 line_num = line_num + 1
end end
line = colored.cyan(tostring(calling_fn.short_src) .. ":" .. tostring(line_num)) line = colored.cyan(tostring(calling_fn.short_src) .. ":" .. tostring(line_num) .. " in " .. tostring(name or '?'))
name = colored.bright(colored.cyan(name or "???"))
else else
line_num = calling_fn.currentline line_num = calling_fn.currentline
line = colored.blue(tostring(calling_fn.short_src) .. ":" .. tostring(calling_fn.currentline)) if calling_fn.short_src == '[C]' then
name = colored.bright(colored.blue(name or "???")) line = colored.green(tostring(calling_fn.short_src) .. " in " .. tostring(name or '?'))
else
line = colored.blue(tostring(calling_fn.short_src) .. ":" .. tostring(calling_fn.currentline) .. " in " .. tostring(name or '?'))
end
end end
if file then if file then
local err_line = get_line(file, line_num):sub(1, -2) local err_line = get_line(file, line_num):sub(1, -2)
local offending_statement = colored.red(err_line) local offending_statement = colored.bright(colored.red(err_line:match("^[ ]*(.*)$")))
line = line .. ("\n " .. offending_statement) line = line .. ("\n " .. offending_statement)
end end
end end
end end
local _from = colored.dim(colored.white("|")) io.stderr:write(" " .. tostring(line) .. "\n")
io.stderr:write(("%32s %s %s\n"):format(name, _from, line)) if calling_fn.istailcall then
io.stderr:write(" " .. tostring(colored.dim(colored.white(" (...tail calls...)"))) .. "\n")
end
_continue_0 = true _continue_0 = true
until true until true
if not _continue_0 then if not _continue_0 then
@ -1727,7 +1748,7 @@ OPTIONS
do do
local ldt local ldt
ok, ldt = pcall(require, 'ldt') ok, ldt = pcall(require, 'ldt')
if ok then if ok and false then
ldt.guard(run) ldt.guard(run)
else else
xpcall(run, err_hand) xpcall(run, err_hand)

View File

@ -1056,7 +1056,7 @@ OPTIONS
if not calling_fn then break if not calling_fn then break
if calling_fn.func == run then break if calling_fn.func == run then break
level += 1 level += 1
name = calling_fn.name name = calling_fn.name and "function '#{calling_fn.name}'" or nil
if calling_fn.linedefined == 0 then name = "main chunk" if calling_fn.linedefined == 0 then name = "main chunk"
if name == "run_lua_fn" then continue if name == "run_lua_fn" then continue
line = nil line = nil
@ -1072,46 +1072,57 @@ OPTIONS
assert(filename) assert(filename)
file = FILE_CACHE[filename]\sub(tonumber(start),tonumber(stop)) file = FILE_CACHE[filename]\sub(tonumber(start),tonumber(stop))
err_line = get_line(file, calling_fn.currentline)\sub(1,-2) err_line = get_line(file, calling_fn.currentline)\sub(1,-2)
offending_statement = colored.red(err_line) offending_statement = colored.bright(colored.red(err_line\match("^[ ]*(.*)")))
line = colored.yellow("#{filename}:#{calling_fn.currentline}\n#{offending_statement}")
if arg_orders = nomsu.environment.ARG_ORDERS[calling_fn.func] if arg_orders = nomsu.environment.ARG_ORDERS[calling_fn.func]
name = colored.bright(colored.yellow next(arg_orders)) name = "action '#{next(arg_orders)}'"
else else
name = colored.bright(colored.yellow "main chunk") name = "main chunk"
line = colored.yellow("#{filename}:#{calling_fn.currentline} in #{name}\n #{offending_statement}")
else else
if calling_fn.istailcall and not name
name = "<tail call>"
ok, file = pcall ->FILE_CACHE[calling_fn.short_src] ok, file = pcall ->FILE_CACHE[calling_fn.short_src]
if not ok then file = nil if not ok then file = nil
local line_num local line_num
if name == nil and debug.getinfo(level+1) if name == nil
i = 1 search_level = level
while true _info = debug.getinfo(search_level)
-- '+1' to get to one level higher than the callsite while _info and (_info.func == pcall or _info.func == xpcall)
varname, val = debug.getlocal(level+1, i) search_level += 1
_info = debug.getinfo(search_level)
if _info
for i=1,999
varname, val = debug.getlocal(search_level, i)
if not varname then break if not varname then break
if val == calling_fn.func if val == calling_fn.func
name = varname name = "local '#{varname}'"
if not varname\match("%(")
break
unless name
for i=1,_info.nups
varname, val = debug.getupvalue(_info.func, i)
if not varname then break
if val == calling_fn.func
name = "upvalue '#{varname}'"
if not varname\match("%(") if not varname\match("%(")
break break
i += 1
if file and calling_fn.short_src\match(".moon$") and LINE_TABLES[file] if file and calling_fn.short_src\match(".moon$") and LINE_TABLES[file]
char = LINE_TABLES[file][calling_fn.currentline] char = LINE_TABLES[file][calling_fn.currentline]
line_num = 1 line_num = 1
for _ in file\sub(1,char)\gmatch("\n") do line_num += 1 for _ in file\sub(1,char)\gmatch("\n") do line_num += 1
line = colored.cyan("#{calling_fn.short_src}:#{line_num}") line = colored.cyan("#{calling_fn.short_src}:#{line_num} in #{name or '?'}")
name = colored.bright(colored.cyan(name or "???"))
else else
line_num = calling_fn.currentline line_num = calling_fn.currentline
line = colored.blue("#{calling_fn.short_src}:#{calling_fn.currentline}") if calling_fn.short_src == '[C]'
name = colored.bright(colored.blue(name or "???")) line = colored.green("#{calling_fn.short_src} in #{name or '?'}")
else
line = colored.blue("#{calling_fn.short_src}:#{calling_fn.currentline} in #{name or '?'}")
if file if file
err_line = get_line(file, line_num)\sub(1,-2) err_line = get_line(file, line_num)\sub(1,-2)
offending_statement = colored.red(err_line) offending_statement = colored.bright(colored.red(err_line\match("^[ ]*(.*)$")))
line ..= "\n "..offending_statement line ..= "\n "..offending_statement
_from = colored.dim colored.white "|" io.stderr\write(" #{line}\n")
io.stderr\write(("%32s %s %s\n")\format(name, _from, line)) if calling_fn.istailcall
io.stderr\write(" #{colored.dim colored.white " (...tail calls...)"}\n")
io.stderr\flush! io.stderr\flush!
@ -1218,7 +1229,7 @@ OPTIONS
--require('ProFi')\profile "scratch/profile.txt", (profi)-> --require('ProFi')\profile "scratch/profile.txt", (profi)->
do do
ok, ldt = pcall(require,'ldt') ok, ldt = pcall(require,'ldt')
if ok if ok and false
ldt.guard run ldt.guard run
else xpcall(run, err_hand) else xpcall(run, err_hand)