2021-06-25 19:31:33 +10:00
|
|
|
-- Generator v2: Borderless Edition
|
2021-06-26 02:06:38 +10:00
|
|
|
-- This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
-- License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
-- file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
2021-06-25 19:31:33 +10:00
|
|
|
|
|
|
|
local generator = {}
|
|
|
|
|
|
|
|
do
|
|
|
|
function generator.parse_ast(file, ast)
|
|
|
|
local gcode = ""
|
|
|
|
for i=1, #ast do
|
|
|
|
local leaf = ast[i]
|
2022-02-09 05:28:37 +11:00
|
|
|
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
|
2021-06-25 19:31:33 +10:00
|
|
|
if leaf.type == "directive" then
|
|
|
|
gcode = gcode .. string.format("call_directive(%q,", leaf.name)
|
|
|
|
local pargs = {}
|
|
|
|
for i=1, #leaf.args do
|
|
|
|
if type(leaf.args[i]) ~= "table" then
|
|
|
|
table.insert(pargs, string.format("%q", leaf.args[i]))
|
|
|
|
elseif leaf.args[i].type == "lua_span" then
|
|
|
|
table.insert(pargs, leaf.args[i].val)
|
|
|
|
elseif leaf.args[i].type == "evar" then
|
|
|
|
table.insert(pargs, string.format("svar.get(%q)", leaf.args[i].val))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
gcode = gcode .. table.concat(pargs, ",")..")\n"
|
|
|
|
elseif leaf.type == "lua_block" then
|
|
|
|
gcode = gcode .. leaf.val .. "\n"
|
|
|
|
elseif leaf.type == "shell_block" then
|
|
|
|
gcode = gcode .. string.format("shell_write(%q)\n", leaf.val)
|
|
|
|
elseif leaf.type == "content" then
|
|
|
|
gcode = gcode .. string.format("write_out(%q)\n", leaf.val)
|
|
|
|
elseif leaf.type == "lua_span" then
|
|
|
|
gcode = gcode .. "write_out("..leaf.val..")\n"
|
|
|
|
elseif leaf.type == "shell_span" then
|
|
|
|
gcode = gcode .. string.format("write_out(svar.get(%q))\n", leaf.val)
|
|
|
|
elseif leaf.type == "evar" then
|
|
|
|
gcode = gcode .. string.format("write_out(string.format(\"%%q\", svar.get(%q)))\n", leaf.val)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return gcode
|
|
|
|
end
|
|
|
|
|
|
|
|
function generator.run_gcode(fname, gcode)
|
2021-06-29 02:00:15 +10:00
|
|
|
fname = fname or "(unknown)"
|
|
|
|
local env = {
|
|
|
|
code = "",
|
|
|
|
fname = fname,
|
|
|
|
pragmas = {
|
|
|
|
include_file_name = "n",
|
|
|
|
prefix_local_file_numbers = "n",
|
2022-02-15 13:48:54 +11:00
|
|
|
wrap_includes = "n",
|
|
|
|
relative_include = "n"
|
2021-06-29 02:00:15 +10:00
|
|
|
}
|
|
|
|
}
|
2021-06-25 19:31:33 +10:00
|
|
|
local fenv = {}
|
|
|
|
for k, v in pairs(_G) do
|
|
|
|
fenv[k] = v
|
|
|
|
end
|
|
|
|
fenv._G = fenv
|
|
|
|
fenv._GENERATOR = env
|
2022-02-09 05:28:37 +11:00
|
|
|
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, ...)
|
2022-02-09 13:32:19 +11:00
|
|
|
if not DEBUGGING then return end
|
2022-02-09 05:28:37 +11:00
|
|
|
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
|
|
|
|
|
2021-06-25 19:31:33 +10:00
|
|
|
function fenv.call_directive(dname, ...)
|
2021-06-26 01:49:40 +10:00
|
|
|
if not directives[dname] then lc_error("@[{_GENERATOR.fname}]", "invalid directive "..dname) end
|
2021-06-25 19:31:33 +10:00
|
|
|
local r, er = directives[dname](env, ...)
|
2021-06-29 02:00:15 +10:00
|
|
|
if not r then lc_error("directive "..dname, er) end
|
2022-02-09 05:28:37 +11:00
|
|
|
debug_add_tag("CALL_DIR", dname, ...)
|
2021-06-25 19:31:33 +10:00
|
|
|
end
|
|
|
|
|
|
|
|
function fenv.write_out(code)
|
|
|
|
env.code = env.code .. code
|
2022-02-09 05:28:37 +11:00
|
|
|
debug_add_tag("CODE", #tostring(code))
|
2021-06-25 19:31:33 +10:00
|
|
|
end
|
|
|
|
|
|
|
|
function fenv.shell_write(cmd)
|
|
|
|
local tmpname = os.tmpname()
|
|
|
|
local f = io.open(tmpname, "w")
|
|
|
|
f:write(cmd)
|
|
|
|
f:close()
|
|
|
|
local h = io.popen(os.getenv("SHELL").." "..tmpname, "r")
|
2022-02-09 05:28:37 +11:00
|
|
|
local r = h:read("*a"):gsub("%s+$", ""):gsub("^%s+", "")
|
|
|
|
env.code = env.code .. r
|
2021-06-25 19:31:33 +10:00
|
|
|
h:close()
|
2022-02-09 05:28:37 +11:00
|
|
|
debug_add_tag("SHELL", cmd, #r)
|
2021-06-25 19:31:33 +10:00
|
|
|
end
|
|
|
|
|
|
|
|
assert(load(gcode, "="..fname, "t", fenv))()
|
|
|
|
|
2022-02-09 05:28:37 +11:00
|
|
|
if DEBUGGING then
|
|
|
|
|
|
|
|
end
|
|
|
|
|
2021-06-25 19:31:33 +10:00
|
|
|
return env.code
|
|
|
|
end
|
|
|
|
end
|