1 ----------------------------------------------------------------------------
2 -- Lua Pages Template Preprocessor.
4 -- @release $Id: lp.lua,v 1.7 2007/04/18 14:28:39 tomas Exp $
5 ----------------------------------------------------------------------------
7 local assert, error, getfenv, loadstring, setfenv = assert, error, getfenv, loadstring, setfenv
8 local find, format, gsub, strsub = string.find, string.format, string.gsub, string.sub
9 local concat, tinsert = table.concat, table.insert
14 ----------------------------------------------------------------------------
15 -- function to do output
16 local outfunc = "io.write"
17 -- accepts the old expression field: `$| <Lua expression> |$'
18 local compatmode = true
21 -- Builds a piece of Lua code which outputs the (part of the) given string.
23 -- @param i Number with the initial position in the string.
24 -- @param f Number with the final position in the string (default == -1).
25 -- @return String with the correspondent Lua code which outputs the part of the string.
27 local function out (s, i, f)
28 s = strsub(s, i, f or -1)
29 if s == "" then return s end
30 -- we could use `%q' here, but this way we have better control
31 s = gsub(s, "([\\\n\'])", "\\%1")
32 -- substitute '\r' by '\'+'r' and let `loadstring' reconstruct it
33 s = gsub(s, "\r", "\\r")
34 return format(" %s('%s'); ", outfunc, s)
38 ----------------------------------------------------------------------------
39 -- Translate the template to Lua code.
40 -- @param s String to translate.
41 -- @return String with translated code.
42 ----------------------------------------------------------------------------
43 function translate (s)
45 s = gsub(s, "$|(.-)|%$", "<?lua = %1 ?>")
46 s = gsub(s, "<!%-%-$$(.-)$$%-%->", "<?lua %1 ?>")
48 s = gsub(s, "<%%(.-)%%>", "<?lua %1 ?>")
50 local start = 1 -- start of untranslated part in `s'
52 local ip, fp, target, exp, code = find(s, "<%?(%w*)[ \t]*(=?)(.-)%?>", start)
53 if not ip then break end
54 tinsert(res, out(s, start, ip-1))
55 if target ~= "" and target ~= "lua" then
56 -- not for Lua; pass whole instruction to the output
57 tinsert(res, out(s, ip, fp))
59 if exp == "=" then -- expression?
60 tinsert(res, format(" %s(%s);", outfunc, code))
62 tinsert(res, format(" %s ", code))
67 tinsert(res, out(s, start))
72 ----------------------------------------------------------------------------
73 -- Defines the name of the output function.
74 -- @param f String with the name of the function which produces output.
76 function setoutfunc (f)
80 ----------------------------------------------------------------------------
81 -- Turns on or off the compatibility with old CGILua 3.X behavior.
82 -- @param c Boolean indicating if the compatibility mode should be used.
84 function setcompatmode (c)
88 ----------------------------------------------------------------------------
89 -- Internal compilation cache.
93 ----------------------------------------------------------------------------
94 -- Translates a template into a Lua function.
95 -- Does NOT execute the resulting function.
96 -- Uses a cache of templates.
97 -- @param string String with the template to be translated.
98 -- @param chunkname String with the name of the chunk, for debugging purposes.
99 -- @return Function with the resulting translation.
101 function compile (string, chunkname)
102 local f, err = cache[string]
103 if f then return f end
104 f, err = loadstring (translate (string), chunkname)
105 if not f then error (err, 3) end
110 ----------------------------------------------------------------------------
111 -- Translates and executes a template in a given file.
112 -- The translation creates a Lua function which will be executed in an
113 -- optionally given environment.
114 -- @param filename String with the name of the file containing the template.
115 -- @param env Table with the environment to run the resulting function.
117 function include (filename, env)
118 -- read the whole contents of the file
119 local fh = assert (open (filename))
120 local src = fh:read("*a")
122 -- translates the file into a function
123 local prog = compile (src, '@'..filename)
126 _env = getfenv (prog)