diff options
Diffstat (limited to 'macros/luatex/generic/penlight/pl/template.lua')
-rw-r--r-- | macros/luatex/generic/penlight/pl/template.lua | 202 |
1 files changed, 0 insertions, 202 deletions
diff --git a/macros/luatex/generic/penlight/pl/template.lua b/macros/luatex/generic/penlight/pl/template.lua deleted file mode 100644 index 9961a1bdfe..0000000000 --- a/macros/luatex/generic/penlight/pl/template.lua +++ /dev/null @@ -1,202 +0,0 @@ ---- A template preprocessor. --- Originally by [Ricki Lake](http://lua-users.org/wiki/SlightlyLessSimpleLuaPreprocessor) --- --- There are two rules: --- --- * lines starting with # are Lua --- * otherwise, `$(expr)` is the result of evaluating `expr` --- --- Example: --- --- # for i = 1,3 do --- $(i) Hello, Word! --- # end --- ===> --- 1 Hello, Word! --- 2 Hello, Word! --- 3 Hello, Word! --- --- Other escape characters can be used, when the defaults conflict --- with the output language. --- --- > for _,n in pairs{'one','two','three'} do --- static int l_${n} (luaState *state); --- > end --- --- See @{03-strings.md.Another_Style_of_Template|the Guide}. --- --- Dependencies: `pl.utils` --- @module pl.template - -local utils = require 'pl.utils' - -local append,format,strsub,strfind,strgsub = table.insert,string.format,string.sub,string.find,string.gsub - -local APPENDER = "\n__R_size = __R_size + 1; __R_table[__R_size] = " - -local function parseDollarParen(pieces, chunk, exec_pat, newline) - local s = 1 - for term, executed, e in chunk:gmatch(exec_pat) do - executed = '('..strsub(executed,2,-2)..')' - append(pieces, APPENDER..format("%q", strsub(chunk,s, term - 1))) - append(pieces, APPENDER..format("__tostring(%s or '')", executed)) - s = e - end - local r - if newline then - r = format("%q", strgsub(strsub(chunk,s),"\n","")) - else - r = format("%q", strsub(chunk,s)) - end - if r ~= '""' then - append(pieces, APPENDER..r) - end -end - -local function parseHashLines(chunk,inline_escape,brackets,esc,newline) - local exec_pat = "()"..inline_escape.."(%b"..brackets..")()" - - local esc_pat = esc.."+([^\n]*\n?)" - local esc_pat1, esc_pat2 = "^"..esc_pat, "\n"..esc_pat - local pieces, s = {"return function()\nlocal __R_size, __R_table, __tostring = 0, {}, __tostring", n = 1}, 1 - while true do - local _, e, lua = strfind(chunk,esc_pat1, s) - if not e then - local ss - ss, e, lua = strfind(chunk,esc_pat2, s) - parseDollarParen(pieces, strsub(chunk,s, ss), exec_pat, newline) - if not e then break end - end - if strsub(lua, -1, -1) == "\n" then lua = strsub(lua, 1, -2) end - append(pieces, "\n"..lua) - s = e + 1 - end - append(pieces, "\nreturn __R_table\nend") - - -- let's check for a special case where there is nothing to template, but it's - -- just a single static string - local short = false - if (#pieces == 3) and (pieces[2]:find(APPENDER, 1, true) == 1) then - pieces = { "return " .. pieces[2]:sub(#APPENDER+1,-1) } - short = true - end - -- if short == true, the generated function will not return a table of strings, - -- but a single string - return table.concat(pieces), short -end - -local template = {} - ---- expand the template using the specified environment. --- This function will compile and render the template. For more performant --- recurring usage use the two step approach by using `compile` and `ct:render`. --- There are six special fields in the environment table `env` --- --- * `_parent`: continue looking up in this table (e.g. `_parent=_G`). --- * `_brackets`: bracket pair that wraps inline Lua expressions, default is '()'. --- * `_escape`: character marking Lua lines, default is '#' --- * `_inline_escape`: character marking inline Lua expression, default is '$'. --- * `_chunk_name`: chunk name for loaded templates, used if there --- is an error in Lua code. Default is 'TMP'. --- * `_debug`: if truthy, the generated code will be printed upon a render error --- --- @string str the template string --- @tab[opt] env the environment --- @return `rendered template + nil + source_code`, or `nil + error + source_code`. The last --- return value (`source_code`) is only returned if the debug option is used. -function template.substitute(str,env) - env = env or {} - local t, err = template.compile(str, { - chunk_name = rawget(env,"_chunk_name"), - escape = rawget(env,"_escape"), - inline_escape = rawget(env,"_inline_escape"), - inline_brackets = rawget(env,"_brackets"), - newline = nil, - debug = rawget(env,"_debug") - }) - if not t then return t, err end - - return t:render(env, rawget(env,"_parent"), rawget(env,"_debug")) -end - ---- executes the previously compiled template and renders it. --- @function ct:render --- @tab[opt] env the environment. --- @tab[opt] parent continue looking up in this table (e.g. `parent=_G`). --- @bool[opt] db if thruthy, it will print the code upon a render error --- (provided the template was compiled with the debug option). --- @return `rendered template + nil + source_code`, or `nil + error + source_code`. The last return value --- (`source_code`) is only returned if the template was compiled with the debug option. --- @usage --- local ct, err = template.compile(my_template) --- local rendered , err = ct:render(my_env, parent) -local render = function(self, env, parent, db) - env = env or {} - if parent then -- parent is a bit silly, but for backward compatibility retained - setmetatable(env, {__index = parent}) - end - setmetatable(self.env, {__index = env}) - - local res, out = xpcall(self.fn, debug.traceback) - if not res then - if self.code and db then print(self.code) end - return nil, out, self.code - end - return table.concat(out), nil, self.code -end - ---- compiles the template. --- Returns an object that can repeatedly be rendered without parsing/compiling --- the template again. --- The options passed in the `opts` table support the following options: --- --- * `chunk_name`: chunk name for loaded templates, used if there --- is an error in Lua code. Default is 'TMP'. --- * `escape`: character marking Lua lines, default is '#' --- * `inline_escape`: character marking inline Lua expression, default is '$'. --- * `inline_brackets`: bracket pair that wraps inline Lua expressions, default is '()'. --- * `newline`: string to replace newline characters, default is `nil` (not replacing newlines). --- * `debug`: if truthy, the generated source code will be retained within the compiled template object, default is `nil`. --- --- @string str the template string --- @tab[opt] opts the compilation options to use --- @return template object, or `nil + error + source_code` --- @usage --- local ct, err = template.compile(my_template) --- local rendered , err = ct:render(my_env, parent) -function template.compile(str, opts) - opts = opts or {} - local chunk_name = opts.chunk_name or 'TMP' - local escape = opts.escape or '#' - local inline_escape = opts.inline_escape or '$' - local inline_brackets = opts.inline_brackets or '()' - - local code, short = parseHashLines(str,inline_escape,inline_brackets,escape,opts.newline) - local env = { __tostring = tostring } - local fn, err = utils.load(code, chunk_name,'t',env) - if not fn then return nil, err, code end - - if short then - -- the template returns a single constant string, let's optimize for that - local constant_string = fn() - return { - fn = fn(), - env = env, - render = function(self) -- additional params can be ignored - -- skip the metatable magic and error handling in the render - -- function above for this special case - return constant_string, nil, self.code - end, - code = opts.debug and code or nil, - } - end - - return { - fn = fn(), - env = env, - render = render, - code = opts.debug and code or nil, - } -end - -return template |