diff --git a/src/application.lua b/src/application.lua index 4dd7945..5ca2a1f 100644 --- a/src/application.lua +++ b/src/application.lua @@ -4,11 +4,14 @@ --#include "src/libluacomp.lua" +__DSYM = {} + local parser = argparse(arg[0]:match("[^/]+$"), "LuaComp v"..LUACOMP_VERSION.."\nA preprocessor+postprocessor written in Lua.") parser:argument("input", "Input file (- for STDIN)") parser:option("-O --output", "Output file. (- for STDOUT)", "-") parser:option("-m --minifier", "Sets the postprocessor", "none") parser:option("-x --executable", "Makes the script an executable (default: current lua version)"):args "?" +parser:flag("-g --debugging", "Adds inline debugging utils to assist in debugging."):action(function() DEBUGGING=true end) parser:flag("--generator-code", "Outputs only the code from the generator.") parser:flag("--verbose", "Verbose output. (Debugging)"):action(function() VERBOSE=true end) parser:flag("--post-processors", "Lists postprocessors"):action(function() @@ -48,6 +51,35 @@ else f = io.stdin end local ocode = luacomp.process_file(f, (file == "-") and "stdin" or file, args.generator_code) +if DEBUGGING then + -- generate debugging symbols + local dsyms = {"LEM:LCDEBUG!!!"} + for i=1, #__DSYM do + local sym = __DSYM[i] + local sym_str = string.format("FILE[%s]:START[%d,%d]:END[%d:%d]:FILE[%d,%d]", sym.file, sym.sx or 0, sym.sy or 0, sym.ex or 0, sym.ey or 0, sym.fx or -1, sym.fy or -1) + if sym.tag then + sym_str = sym_str .. ":"..sym.tag + end + table.insert(dsyms, sym_str) + end + ocode = ocode .. "\n--[["..table.concat(dsyms, "\n").."\n]]" +end + +if DEBUGGING then + local dsymt = {} + for i=1, #__DSYM do + local sym = __DSYM[i] + local symstr = string.format("file=%q,sx=%q,sy=%q,ex=%q,ey=%q,fx=%q,fy=%q", sym.file, sym.sx or 0, sym.sy or 0, sym.ex or 0, sym.ey or 0, sym.fx or -1, sym.fy or -1) + if sym.tagv then + for i=1, #sym.tagv.vals do + sym.tagv.vals[i]=string.format("%q", sym.tagv.vals[i]) + end + symstr = symstr .. ",tag={" ..string.format("type=%q,vals={%s}", sym.tagv.type, table.concat(sym.tagv.vals, ",")).."}" + end + table.insert(dsymt,"{"..symstr.."}") + end + ocode = "_G['LCDEBUG!!!'] = {\n"..table.concat(dsymt, ",\n").."\n}\n" .. ocode +end local minifier = providers[args.minifier] dprint("Minifier: "..args.minifier, minifier) diff --git a/src/ast2.lua b/src/ast2.lua index a2387f8..3944b07 100644 --- a/src/ast2.lua +++ b/src/ast2.lua @@ -386,6 +386,19 @@ do return ematch end + function ast.add_debugging_info(list, str, sx, sy) + if DEBUGGING then + local node = list[#list] + node.sx = sx + node.sy = sy + node.ey, node.ex = str:get_yx() + node.file = str.file + if not str.file then + luacomp.error("Node has no file!\n"..debug.traceback()) + end + end + end + -- And now we parse function ast.parse(str) local cast = {} @@ -408,11 +421,13 @@ do end end return true - end, "--#", "$".."[[", "@".."[[", "$".."[{", "@".."[{", "$".."(") -- trust me, this was needed + end, "--".."#", "$".."[[", "@".."[[", "$".."[{", "@".."[{", "$".."(", "//".."##") -- trust me, this was needed --dprint("searched") + local sy, sx = str:get_yx() if not match then --dprint("not found") table.insert(cast, {type="content", val=str:next(str:size())}) + ast.add_debugging_info(cast, str, sx, sy) break end local epos = str:tell() @@ -422,11 +437,12 @@ do local chunk = str:next(size) if not chunk:match("^%s+$") then table.insert(cast, {type="content", val=chunk}) + ast.add_debugging_info(cast, str, sx, sy) end str:skip(#match) end --dprint("match: "..match) - if match == "--#" then + if match == "--".."#" or match == "//".."##" then --str:skip(3) table.insert(cast, ast.parse_directive(str)) elseif match == "$".."[[" then @@ -446,9 +462,10 @@ do local var = ast.parse_envvar(str) table.insert(cast, {type="evar", val=var}) else - ast.parser_error(str, "what") + ast.parser_error(str, "internal compiler error") end --dprint("Parsed") + ast.add_debugging_info(cast, str, sx, sy) end return cast diff --git a/src/directives/include.lua b/src/directives/include.lua index 662fce6..1e1a353 100644 --- a/src/directives/include.lua +++ b/src/directives/include.lua @@ -12,7 +12,7 @@ function directives.include(env, file, asmod) env.code = env.code .. code .. "\n"]] if asmod then env.code = env.code .. "local "..asmod.." = (function()\n" end if env.pragmas.include_file_name == "y" then - env.code = env.code .. "-- " .. file .. "\n" + env.code = env.code .. "-- BEGIN " .. file .. "\n" end local code = luacomp.process_file(file, file) .. "\n" if env.pragmas.prefix_local_file_numbers == "y" then @@ -25,6 +25,9 @@ function directives.include(env, file, asmod) code = newcode end env.code = env.code .. code + if env.pragmas.include_file_name == "y" then + env.code = env.code .. "-- END " .. file .. "\n" + end if asmod then env.code = env.code .. "end)()\n" end return true end \ No newline at end of file diff --git a/src/generator2.lua b/src/generator2.lua index 977a035..de293ba 100644 --- a/src/generator2.lua +++ b/src/generator2.lua @@ -10,6 +10,23 @@ do local gcode = "" for i=1, #ast do local leaf = ast[i] + if DEBUGGING then + if not leaf.file then + local linfo = {} + for k, v in pairs(leaf) do + table.insert(linfo, tostring(k).."\t"..tostring(v)) + end + luacomp.error("Node has no file!\n"..debug.traceback().."\n"..table.concat(linfo, "\n")) + end + table.insert(__DSYM, { + sx = leaf.sx, + sy = leaf.sy, + ex = leaf.ex, + ey = leaf.ey, + file = leaf.file + }) + gcode = gcode .. string.format("push_debuginfo(%d)\n", #__DSYM) + end if leaf.type == "directive" then gcode = gcode .. string.format("call_directive(%q,", leaf.name) local pargs = {} @@ -57,14 +74,49 @@ do end fenv._G = fenv fenv._GENERATOR = env + local lsym + function fenv.push_debuginfo(idx) + local ent = __DSYM[idx] + local linecount = 0 + for l in env.code:gmatch("[^\n]*") do + linecount = linecount+1 + end + local x = 1 + while true do + x = x + 1 + local c = env.code:sub(#env.code-x, #env.code-x) + if c == "\n" or c == "" then + break + end + end + ent.fx = x-1 + ent.fy = linecount + if lsym then + local lent = __DSYM[idx] + lent.fey = ent.fy + end + lsym = idx + end + + local function debug_add_tag(ttype, ...) + local alist = table.pack(...) + for i=1, #alist do + alist[i] = tostring(alist[i]) + end + __DSYM[lsym].tag = string.format("TYPE[%s=%s]", ttype, table.concat(alist,",")) + __DSYM[lsym].tagv = {type=ttype, vals=table.pack(...)} + end + function fenv.call_directive(dname, ...) if not directives[dname] then lc_error("@[{_GENERATOR.fname}]", "invalid directive "..dname) end local r, er = directives[dname](env, ...) if not r then lc_error("directive "..dname, er) end + debug_add_tag("CALL_DIR", dname, ...) end function fenv.write_out(code) env.code = env.code .. code + debug_add_tag("CODE", #tostring(code)) end function fenv.shell_write(cmd) @@ -73,12 +125,18 @@ do f:write(cmd) f:close() local h = io.popen(os.getenv("SHELL").." "..tmpname, "r") - env.code = env.code .. h:read("*a") + local r = h:read("*a"):gsub("%s+$", ""):gsub("^%s+", "") + env.code = env.code .. r h:close() + debug_add_tag("SHELL", cmd, #r) end assert(load(gcode, "="..fname, "t", fenv))() + if DEBUGGING then + + end + return env.code end end \ No newline at end of file diff --git a/src/luacomp_vars.lua b/src/luacomp_vars.lua index 5abda40..675e50b 100644 --- a/src/luacomp_vars.lua +++ b/src/luacomp_vars.lua @@ -10,6 +10,6 @@ end _sv("LUACOMP_V_MAJ", 2) _sv("LUACOMP_V_MIN", 0) -_sv("LUACOMP_V_PAT", 3) +_sv("LUACOMP_V_PAT", 4) _sv("LUACOMP_VERSION", LUACOMP_V_MAJ.."."..LUACOMP_V_MIN.."."..LUACOMP_V_PAT) _sv("LUACOMP_NAME", "LuaComp") \ No newline at end of file