if not modules then modules = { } end modules ['luatex-preprocessor'] = {
version = 1.001,
comment = "companion to luatex-preprocessor.tex",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
}
--[[ldx
This is a stripped down version of the preprocessor. In
we have a bit more, use a different logger, and
use a few optimizations. A few examples are shown at the end.
--ldx]]
local rep, sub, gmatch = string.rep, string.sub, string.gmatch
local insert, remove = table.insert, table.remove
local setmetatable = setmetatable
local stack, top, n, hashes = { }, nil, 0, { }
local function set(s)
if top then
n = n + 1
if n > 9 then
texio.write_nl("number of arguments > 9, ignoring: " .. s)
else
local ns = #stack
local h = hashes[ns]
if not h then
h = rep("#",ns)
hashes[ns] = h
end
m = h .. n
top[s] = m
return m
end
end
end
local function get(s)
local m = top and top[s] or s
return m
end
local function push()
top = { }
n = 0
local s = stack[#stack]
if s then
setmetatable(top,{ __index = s })
end
insert(stack,top)
end
local function pop()
top = remove(stack)
end
local leftbrace = lpeg.P("{")
local rightbrace = lpeg.P("}")
local escape = lpeg.P("\\")
local space = lpeg.P(" ")
local spaces = space^1
local newline = lpeg.S("\r\n")
local nobrace = 1 - leftbrace - rightbrace
local name = lpeg.R("AZ","az")^1
local longname = (leftbrace/"") * (nobrace^1) * (rightbrace/"")
local variable = lpeg.P("#") * lpeg.Cs(name + longname)
local escapedname = escape * name
local definer = escape * (lpeg.P("def") + lpeg.P("egdx") * lpeg.P("def"))
local anything = lpeg.P(1)
local always = lpeg.P(true)
local pushlocal = always / push
local poplocal = always / pop
local declaration = variable / set
local identifier = variable / get
local function matcherror(str,pos)
texio.write_nl("runaway definition at: " .. sub(str,pos-30,pos))
end
local parser = lpeg.Cs { "converter",
definition = pushlocal
* definer
* escapedname
* (declaration + (1-leftbrace))^0
* lpeg.V("braced")
* poplocal,
braced = leftbrace
* ( lpeg.V("definition")
+ identifier
+ lpeg.V("braced")
+ nobrace
)^0
* (rightbrace + lpeg.Cmt(always,matcherror)),
converter = (lpeg.V("definition") + anything)^1,
}
--[[ldx
We provide a few commands.
--ldx]]
-- local texkpse
local function find_file(...)
-- texkpse = texkpse or kpse.new("luatex","tex")
-- return texkpse:find_file(...) or ""
return kpse.find_file(...) or ""
end
commands = commands or { }
function commands.preprocessed(str)
return lpeg.match(parser,str)
end
function commands.inputpreprocessed(name)
local name = find_file(name) or ""
if name ~= "" then
-- we could use io.loaddata as it's loaded in luatex-plain
local f = io.open(name,'rb')
if f then
texio.write("("..name)
local d = commands.preprocessed(f:read("*a"))
if d and d ~= "" then
texio.write("processed: " .. name)
for s in gmatch(d,"[^\n\r]+") do
tex.print(s) -- we do a dumb feedback
end
end
f:close()
texio.write(")")
else
tex.error("preprocessor error, invalid file: " .. name)
end
else
tex.error("preprocessor error, unknown file: " .. name)
end
end
function commands.preprocessfile(oldfile,newfile) -- no checking
if oldfile and oldfile ~= newfile then
local f = io.open(oldfile,'rb')
if f then
local g = io.open(newfile,'wb')
if g then
g:write(lpeg.match(parser,f:read("*a") or ""))
g:close()
end
f:close()
end
end
end
--~ print(preprocessed([[\def\test#oeps{test:#oeps}]]))
--~ print(preprocessed([[\def\test#oeps{test:#{oeps}}]]))
--~ print(preprocessed([[\def\test#{oeps:1}{test:#{oeps:1}}]]))
--~ print(preprocessed([[\def\test#{oeps}{test:#oeps}]]))
--~ preprocessed([[\def\test#{oeps}{test:#oeps \halign{##\cr #oeps\cr}]])
--~ print(preprocessed([[\def\test#{oeps}{test:#oeps \halign{##\cr #oeps\cr}}]]))