From 879b98eec4e2ae34374a4a5f6d426f926b52bb5a Mon Sep 17 00:00:00 2001 From: g012 Date: Wed, 27 Sep 2017 23:57:50 +0200 Subject: [PATCH] Improved error messages. --- 6502.lua | 48 +++++++++++++++++---------- embed.c | 2 +- l65.lua | 99 ++++++++++++++++++++++++++++++++++++++++---------------- 3 files changed, 103 insertions(+), 46 deletions(-) diff --git a/6502.lua b/6502.lua index f1296d1..c393441 100644 --- a/6502.lua +++ b/6502.lua @@ -636,8 +636,9 @@ cycles_def=2 xcross_def=0 local opimm={ } M.opimm = opimm for k,v in pairs(opimm) do M[k .. 'imm'] = function(late, early) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local size = function() late,early = size_op(late,early) return 2 end - local asbin = function(b) b[#b+1]=v.opc b[#b+1]=op_eval_byte(late,early) end + local asbin = function(b) local l65dbg=l65dbg b[#b+1]=v.opc b[#b+1]=op_eval_byte(late,early) end table.insert(M.section_current.instructions, { size=size, cycles=2, asbin=asbin }) end end @@ -650,8 +651,9 @@ cycles_def=3 xcross_def=0 local opzpg={ } M.opzpg = opzpg for k,v in pairs(opzpg) do M[k .. 'zpg'] = function(late, early) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local size = function() late,early = size_op(late,early) return 2 end - local asbin = function(b) b[#b+1]=v.opc b[#b+1]=op_eval_byte(late,early) end + local asbin = function(b) local l65dbg=l65dbg b[#b+1]=v.opc b[#b+1]=op_eval_byte(late,early) end table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, asbin=asbin }) end end @@ -664,8 +666,9 @@ cycles_def=4 xcross_def=0 local opabs={ } M.opabs = opabs for k,v in pairs(opabs) do M[k .. 'abs'] = function(late, early) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local size = function() late,early = size_op(late,early) return 3 end - local asbin = function(b) + local asbin = function(b) local l65dbg=l65dbg local x = op_eval_word(late,early) b[#b+1]=v.opc b[#b+1]=x&0xff b[#b+1]=x>>8 end @@ -682,9 +685,10 @@ for k,_ in pairs(opzab) do if x >= -32768 and x <= 0xffff then return M[k .. 'abs'](late, early) end error("value out of word range: " .. x) end + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local abs = opabs[k] local ins = { cycles=abs.cycles } - ins.size = function() + ins.size = function() local l65dbg=l65dbg local r,x = M.pcall_za(late, early or 0) if not r then return 3 end size_ref(x) @@ -700,7 +704,7 @@ for k,_ in pairs(opzab) do ins.asbin = function(b) b[#b+1]=abs.opc b[#b+1]=x&0xff b[#b+1]=x>>8 end return 3 end - ins.asbin = function(b) + ins.asbin = function(b) local l65dbg=l65dbg local x = word_normalize(late(early or 0)) -- since we assumed absolute on link phase, we must generate absolute in binary if x <= 0xff and opzpg[k] then print("warning: forcing abs on zpg operand for opcode " .. k) end @@ -716,8 +720,9 @@ cycles_def=4 xcross_def=0 local opzpx={ } M.opzpx = opzpx for k,v in pairs(opzpx) do M[k .. 'zpx'] = function(late, early) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local size = function() late,early = size_op(late,early) return 2 end - local asbin = function(b) b[#b+1]=v.opc b[#b+1]=op_eval_byte(late,early) end + local asbin = function(b) local l65dbg=l65dbg b[#b+1]=v.opc b[#b+1]=op_eval_byte(late,early) end table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, asbin=asbin }) end end @@ -729,8 +734,9 @@ cycles_def=4 xcross_def=1 local opabx={ } M.opabx = opabx for k,v in pairs(opabx) do M[k .. 'abx'] = function(late, early) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local size = function() late,early = size_op(late,early) return 3 end - local asbin = function(b) + local asbin = function(b) local l65dbg=l65dbg local x = op_eval_word(late,early) b[#b+1]=v.opc b[#b+1]=x&0xff b[#b+1]=x>>8 end @@ -747,9 +753,10 @@ for k,_ in pairs(opzax) do if x >= -32768 and x <= 0xffff then return M[k .. 'abx'](late, early) end error("value out of word range: " .. x) end + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local abx = opabx[k] local ins = { cycles=abx.cycles } - ins.size = function() + ins.size = function() local l65dbg=l65dbg local r,x = M.pcall_za(late, early or 0) if not r then return 3 end size_ref(x) @@ -765,7 +772,7 @@ for k,_ in pairs(opzax) do ins.asbin = function(b) b[#b+1]=abx.opc b[#b+1]=x&0xff b[#b+1]=x>>8 end return 3 end - ins.asbin = function(b) + ins.asbin = function(b) local l65dbg=l65dbg local x = word_normalize(late(early or 0)) -- since we assumed absolute on link phase, we must generate absolute in binary if x <= 0xff and opzpx[k] then print("warning: forcing abx on zpx operand for opcode " .. k) end @@ -780,8 +787,9 @@ cycles_def=4 xcross_def=0 local opzpy={ } M.opzpy = opzpy for k,v in pairs(opzpy) do M[k .. 'zpy'] = function(late, early) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local size = function() late,early = size_op(late,early) return 2 end - local asbin = function(b) b[#b+1]=v.opc b[#b+1]=op_eval_byte(late,early) end + local asbin = function(b) local l65dbg=l65dbg b[#b+1]=v.opc b[#b+1]=op_eval_byte(late,early) end table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, asbin=asbin }) end end @@ -793,8 +801,9 @@ cycles_def=4 xcross_def=1 local opaby={ } M.opaby = opaby for k,v in pairs(opaby) do M[k .. 'aby'] = function(late, early) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local size = function() late,early = size_op(late,early) return 3 end - local asbin = function(b) + local asbin = function(b) local l65dbg=l65dbg local x = op_eval_word(late,early) b[#b+1]=v.opc b[#b+1]=x&0xff b[#b+1]=x>>8 end @@ -811,9 +820,10 @@ for k,_ in pairs(opzay) do if x >= -32768 and x <= 0xffff then return M[k .. 'aby'](late, early) end error("value out of word range: " .. x) end + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local aby = opaby[k] local ins = { cycles=aby.cycles } - ins.size = function() + ins.size = function() local l65dbg=l65dbg local r,x = M.pcall_za(late, early or 0) if not r then return 3 end size_ref(x) @@ -829,7 +839,7 @@ for k,_ in pairs(opzay) do ins.asbin = function(b) b[#b+1]=aby.opc b[#b+1]=x&0xff b[#b+1]=x>>8 end return 3 end - ins.asbin = function(b) + ins.asbin = function(b) local l65dbg=l65dbg local x = word_normalize(late(early or 0)) -- since we assumed absolute on link phase, we must generate absolute in binary if x <= 0xff and opzpy[k] then print("warning: forcing aby on zpy operand for opcode " .. k) end @@ -843,6 +853,7 @@ cycles_def=2 xcross_def=0 local oprel={ } M.oprel = oprel for k,v in pairs(oprel) do M[k .. 'rel'] = function(label) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local parent,offset = M.label_current local section,rorg = M.section_current,M.location_current.rorg local op = { cycles=2 } @@ -851,7 +862,7 @@ for k,v in pairs(oprel) do label = size_dc(label) return 2 end - op.asbin = function(b) + op.asbin = function(b) local l65dbg=l65dbg local x,l = label,label if type(x) == 'function' then x=x() end if type(x) == 'string' then @@ -872,8 +883,9 @@ cycles_def=5 xcross_def=0 local opind={ } M.opind = opind for k,v in pairs(opind) do M[k .. 'ind'] = function(late, early) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local size = function() late,early = size_op(late,early) return 3 end - local asbin = function(b) + local asbin = function(b) local l65dbg=l65dbg local x = op_eval_word(late,early) b[#b+1]=v.opc b[#b+1]=x&0xff b[#b+1]=x>>8 end @@ -887,8 +899,9 @@ cycles_def=6 xcross_def=0 local opinx={ } M.opinx = opinx for k,v in pairs(opinx) do M[k .. 'inx'] = function(late, early) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local size = function() late,early = size_op(late,early) return 2 end - local asbin = function(b) b[#b+1]=v.opc b[#b+1]=op_eval_byte(late,early) end + local asbin = function(b) local l65dbg=l65dbg b[#b+1]=v.opc b[#b+1]=op_eval_byte(late,early) end table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, asbin=asbin }) end end @@ -899,8 +912,9 @@ cycles_def=5 xcross_def=1 local opiny={ } for k,v in pairs(opiny) do M[k .. 'iny'] = function(late, early) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local size = function() late,early = size_op(late,early) return 2 end - local asbin = function(b) b[#b+1]=v.opc b[#b+1]=op_eval_byte(late,early) end + local asbin = function(b) local l65dbg=l65dbg b[#b+1]=v.opc b[#b+1]=op_eval_byte(late,early) end table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, asbin=asbin }) end end diff --git a/embed.c b/embed.c index dc5c4b5..b0eb05c 100644 --- a/embed.c +++ b/embed.c @@ -77,7 +77,7 @@ static int writer(lua_State* L, const void* p, size_t size, void* f) fprintf(f, "0x%02X, ", (int)(((unsigned char*)p)[i])); } w_o += size; - return size == 0; + return 0; } static int pmain(lua_State* L) diff --git a/l65.lua b/l65.lua index e2048a1..7b45786 100644 --- a/l65.lua +++ b/l65.lua @@ -740,7 +740,7 @@ local function LexLua(src) end -local function ParseLua(src) +local function ParseLua(src, src_name) local st, tok if type(src) ~= 'table' then st, tok = LexLua(src) @@ -752,7 +752,7 @@ local function ParseLua(src) end -- local function GenerateError(msg) - local err = ">> :"..tok:Peek().Line..":"..tok:Peek().Char..": "..msg.."\n" + local err = (src_name or '=(string)') .. ":"..tok:Peek().Line..":"..tok:Peek().Char..": "..msg.."\n " --find the line local lineNum = 0 if type(src) == 'string' then @@ -760,7 +760,7 @@ local function ParseLua(src) if line:sub(-1,-1) == '\n' then line = line:sub(1,-2) end lineNum = lineNum+1 if lineNum == tok:Peek().Line then - err = err..">> '"..line:gsub('\t',' ').."'\n" + err = err..line:gsub('\t',' ').."\n" for i = 1, tok:Peek().Char do local c = line:sub(i,i) if c == '\t' then @@ -769,7 +769,7 @@ local function ParseLua(src) err = err..' ' end end - err = err.." ^^^^" + err = err.."^^^^" break end end @@ -2252,7 +2252,7 @@ local function Format65(ast) appendNextToken( ")" ) else - print("Unknown AST Type: ", statement.AstType) + error(string.format("Unknown AST Type: %s\n", tostring(statement.AstType))) end assert(tok_it == #expr.Tokens + 1) @@ -2441,7 +2441,7 @@ local function Format65(ast) elseif statement.AstType == 'SemicolonStatement' then else - print("Unknown AST Type: ", statement.AstType) + error(string.format("Unknown AST Type: %s\n", tostring(statement.AstType))) end if statement.Semicolon then @@ -2478,6 +2478,52 @@ l65 = { loadfile_org = loadfile, dofile_org = dofile, } +l65.report = function(success, ...) + if success then return success,... end + local message=... io.stderr:write(message..'\n') + os.exit(-1) +end +l65.msghandler = function(msg) + msg = tostring(msg) + msg = msg:gsub('%[string "(.-%.l65)"%]', '%1') -- [string "xxx.l65"] -> xxx.l65 + local trace_cur = debug.traceback() + trace_cur = trace_cur:gsub('%[string "(.-%.l65)"%]', '%1') -- [string "xxx.l65"] -> xxx.l65 + + local i=2 + while debug.getinfo(i) do + local j = 1 + while true do + local n,v = debug.getlocal(i, j) + if not n then break end + if n == 'l65dbg' then + local o = function(s) io.stderr:write(s) end + o(string.format("%s\n", msg)) + local trace_cur = debug.traceback() + if trace_cur:find("in local 'late'") then + local lines = {} + for line in trace_cur:gmatch("[^\n]+") do + if line:find("in local 'late'") then break end + table.insert(lines, line) + end + print(table.concat(lines,'\n')) + end + local trace = v.trace:match(".-\n(.*)\n.-'xpcall'") + trace = trace:gsub('%[string "(.-%.l65)"%]', '%1') + print(trace) + os.exit(-2) + end + j = j + 1 + end + i = i + 1 + end + + trace_cur = trace_cur:match(".-\n(.*)\n.-'xpcall'") + io.stderr:write(string.format("%s\n%s\n", msg, trace_cur)) + os.exit(-3) +end +l65.require = function() + -- TODO +end do local getembedded = type(arg[-1]) == 'function' and arg[-1] l65.load_embedded = function(name) @@ -2485,15 +2531,14 @@ do local src,isl65 = getembedded(name) if not src then return end if isl65 then - local filename = name .. '.l65' - local st, ast = assert(l65.parse(src)) - local bc = assert(l65.load_org(l65.format(ast), filename)) - return bc, filename + name = name .. '.l65' + local st, ast = l65.report(l65.parse(src, name)) + src = l65.format(ast) else - local filename = name .. '.lua' - local bc = assert(l65.load_org(src, filename)) - return bc, filename + name = name .. '.lua' end + local bc = assert(l65.load_org(src, name)) + return bc, name end end l65.searcher = function(name) @@ -2502,7 +2547,7 @@ l65.searcher = function(name) local file = assert(io.open(filename, 'rb')) local src = file:read('*a') file:close() - local st, ast = assert(l65.parse(src)) + local st, ast = l65.report(l65.parse(src, filename)) local bc = assert(l65.load_org(l65.format(ast), filename)) return bc, filename end @@ -2514,14 +2559,10 @@ l65.load = function(chunk, chunkname, mode, ...) s = table.concat(s) else return nil, string.format("invalid type for chunk %s: %s", chunkname or "=(load)", chunk_t) end - local st, ast = l65.parse(s) - if not st then - if not mode or mode:sub(1,1)=='b' then - local f = l65.load_org(s, chunkname, mode, ...) - if f then return f end - end - return nil,ast + if s:sub(1,4) == "\x1bLua" then -- a binary file + return l65.load_org(s, chunkname, mode, ...) end + local st, ast = l65.report(l65.parse(s, chunkname or "=(load)")) return l65.load_org(l65.format(ast), chunkname, 't', ...) end l65.loadfile = function(filename, mode, ...) @@ -2536,8 +2577,8 @@ l65.loadfile = function(filename, mode, ...) return l65.load(s, filename, mode, ...) end l65.dofile = function(filename) - local f = assert(l65.loadfile(filename)) - return f() + local f = l65.report(l65.loadfile(filename)) + return xpcall(f, l65.msghandler) end l65.installhooks = function() if package.searchers[l65.searcher_index] ~= l65.searcher then @@ -2599,17 +2640,19 @@ local cfg=require"l65cfg" l65.cfg=cfg local version = function() print(string.format("l65 %s", cfg.version)) end -local usage = function() - print(string.format([[ +local usage = function(f) + if not f then f = io.stdout end + f:write(string.format([[ Usage: %s [options] file Options: -d Dump the Lua code after l65 parsing into file -h Display this information - -v Display the release version]], arg[0])) + -v Display the release version +]], arg[0])) end local invalid_usage = function() - print("Invalid usage.") - usage() + io.stderr:write("Invalid usage.\n") + usage(io.stderr) end local inf,dump