-- -- Templet for Lua. -- Copyright © 2012 Peter Colberg. -- For conditions of distribution and use, see copyright notice in LICENSE. -- local _M = {} -- Cache library functions. local insert, concat = table.insert, table.concat local find, format, sub = string.find, string.format, string.sub -- Parse verbatim blocks containing template expressions. local function parse_expression(result, chunk) local i, n = 1, #chunk while i <= n do local s, e, expr = find(chunk, "$(%b{})", i) if not s or s > i then insert(result, format("_put(%q)", sub(chunk, i, s and s - 1))) end if not s then break end insert(result, format("_put(%s)", sub(expr, 2, -2))) i = e + 1 end end -- Parse template statements. local function parse_statement(result, chunk) local i, n = 1, #chunk while i <= n do local s, e, stmt = find(chunk, "%f[^%z\n]%s*|([^\n]*\n?)", i) if not s or s > i then parse_expression(result, sub(chunk, i, s and s - 1)) end if not s then break end insert(result, stmt) i = e + 1 end end -- Lua 5.1 uses setfenv, Lua 5.2 uses _ENV local setfenv = setfenv local render_to_function if setfenv then function render_to_function(render, f, env) setfenv(render, env) local status, err = pcall(render, f) if not status then return error(err) end end else function render_to_function(render, f, env) local status, err = pcall(render, f, env) if not status then return error(err) end end end local function render_to_string(render, env) local t = {} local f = function(s) if s ~= nil then insert(t, tostring(s)) end end local status, err = pcall(render_to_function, render, f, env) if not status then return error(err) end return concat(t) end --- Lua 5.2 deprecates loadstring local load = loadstring or load local function loadtemplate(s, source) local result = {"local _put, _ENV = ..."} parse_statement(result, s) local render, err = load(concat(result), source) if not render then return error(err) end return function(env, f) local env = env or _G if not f then return render_to_string(render, env) else return render_to_function(render, f, env) end end end function _M.loadstring(s) local status, result = pcall(loadtemplate, s, s) if not status then return error(result) end return result end function _M.loadfile(filename) local f, err = io.open(filename, "r") if not f then return error(err) end local s = f:read("*a") local status, result = pcall(loadtemplate, s, "@" .. filename) if not status then return error(result) end f:close() return result end return _M