diff options
Diffstat (limited to 'lualibs-util-tpl.lua')
-rw-r--r-- | lualibs-util-tpl.lua | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/lualibs-util-tpl.lua b/lualibs-util-tpl.lua new file mode 100644 index 0000000..7a6abef --- /dev/null +++ b/lualibs-util-tpl.lua @@ -0,0 +1,174 @@ +if not modules then modules = { } end modules ['util-tpl'] = { + version = 1.001, + comment = "companion to luat-lib.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- This is experimental code. Coming from dos and windows, I've always used %whatever% +-- as template variables so let's stick to it. After all, it's easy to parse and stands +-- out well. A double %% is turned into a regular %. + +utilities.templates = utilities.templates or { } +local templates = utilities.templates + +local trace_template = false trackers.register("templates.trace",function(v) trace_template = v end) +local report_template = logs.reporter("template") + +local tostring = tostring +local format, sub = string.format, string.sub +local P, C, Cs, Carg, lpegmatch = lpeg.P, lpeg.C, lpeg.Cs, lpeg.Carg, lpeg.match + +-- todo: make installable template.new + +local replacer + +local function replacekey(k,t,how,recursive) + local v = t[k] + if not v then + if trace_template then + report_template("unknown key %a",k) + end + return "" + else + v = tostring(v) + if trace_template then + report_template("setting key %a to value %a",k,v) + end + if recursive then + return lpegmatch(replacer,v,1,t,how,recursive) + else + return v + end + end +end + +local sqlescape = lpeg.replacer { + { "'", "''" }, + { "\\", "\\\\" }, + { "\r\n", "\\n" }, + { "\r", "\\n" }, + -- { "\t", "\\t" }, +} + +local sqlquotedescape = lpeg.Cs(lpeg.Cc("'") * sqlescape * lpeg.Cc("'")) + +-- escapeset : \0\1\2\3\4\5\6\7\8\9\10\11\12\13\14\15\16\17\18\19\20\21\22\23\24\25\26\27\28\29\30\31\"\\\127 +-- test string: [[1\0\31test23"\\]] .. string.char(19) .. "23" +-- +-- slow: +-- +-- local luaescape = lpeg.replacer { +-- { '"', [[\"]] }, +-- { '\\', [[\\]] }, +-- { R("\0\9") * #R("09"), function(s) return "\\00" .. byte(s) end }, +-- { R("\10\31") * #R("09"), function(s) return "\\0" .. byte(s) end }, +-- { R("\0\31") , function(s) return "\\" .. byte(s) end }, +-- } +-- +-- slightly faster: +-- +-- local luaescape = Cs (( +-- P('"' ) / [[\"]] + +-- P('\\') / [[\\]] + +-- Cc("\\00") * (R("\0\9") / byte) * #R("09") + +-- Cc("\\0") * (R("\10\31") / byte) * #R("09") + +-- Cc("\\") * (R("\0\31") / byte) + +-- P(1) +-- )^0) + +local escapers = { + lua = function(s) + return sub(format("%q",s),2,-2) + end, + sql = function(s) + return lpegmatch(sqlescape,s) + end, +} + +local quotedescapers = { + lua = function(s) + return format("%q",s) + end, + sql = function(s) + return lpegmatch(sqlquotedescape,s) + end, +} + +lpeg.patterns.sqlescape = sqlescape +lpeg.patterns.sqlescape = sqlquotedescape + +local luaescaper = escapers.lua +local quotedluaescaper = quotedescapers.lua + +local function replacekeyunquoted(s,t,how,recurse) -- ".. \" " + local escaper = how and escapers[how] or luaescaper + return escaper(replacekey(s,t,how,recurse)) +end + +local function replacekeyquoted(s,t,how,recurse) -- ".. \" " + local escaper = how and quotedescapers[how] or quotedluaescaper + return escaper(replacekey(s,t,how,recurse)) +end + +local single = P("%") -- test %test% test : resolves test +local double = P("%%") -- test 10%% test : %% becomes % +local lquoted = P("%[") -- test '%[test]%' test : resolves to test with escaped "'s +local rquoted = P("]%") -- +local lquotedq = P("%(") -- test %(test)% test : resolves to 'test' with escaped "'s +local rquotedq = P(")%") -- + +local escape = double / '%%' +local nosingle = single / '' +local nodouble = double / '' +local nolquoted = lquoted / '' +local norquoted = rquoted / '' +local nolquotedq = lquotedq / '' +local norquotedq = rquotedq / '' + +local key = nosingle * ((C((1-nosingle )^1) * Carg(1) * Carg(2) * Carg(3)) / replacekey ) * nosingle +local quoted = nolquotedq * ((C((1-norquotedq)^1) * Carg(1) * Carg(2) * Carg(3)) / replacekeyquoted ) * norquotedq +local unquoted = nolquoted * ((C((1-norquoted )^1) * Carg(1) * Carg(2) * Carg(3)) / replacekeyunquoted) * norquoted +local any = P(1) + + replacer = Cs((unquoted + quoted + escape + key + any)^0) + +local function replace(str,mapping,how,recurse) + if mapping and str then + return lpegmatch(replacer,str,1,mapping,how or "lua",recurse or false) or str + else + return str + end +end + +-- print(replace("test '%[x]%' test",{ x = [[a 'x' a]] })) +-- print(replace("test '%[x]%' test",{ x = true })) +-- print(replace("test '%[x]%' test",{ x = [[a 'x' a]], y = "oeps" },'sql')) +-- print(replace("test '%[x]%' test",{ x = [[a '%y%' a]], y = "oeps" },'sql',true)) +-- print(replace([[test %[x]% test]],{ x = [[a "x" a]]})) +-- print(replace([[test %(x)% test]],{ x = [[a "x" a]]})) + +templates.replace = replace + +function templates.load(filename,mapping,how,recurse) + local data = io.loaddata(filename) or "" + if mapping and next(mapping) then + return replace(data,mapping,how,recurse) + else + return data + end +end + +function templates.resolve(t,mapping,how,recurse) + if not mapping then + mapping = t + end + for k, v in next, t do + t[k] = replace(v,mapping,how,recurse) + end + return t +end + +-- inspect(utilities.templates.replace("test %one% test", { one = "%two%", two = "two" })) +-- inspect(utilities.templates.resolve({ one = "%two%", two = "two", three = "%three%" })) |