ltp/template.lua

changeset 3
b2df1b3f2c83
child 6
219d7a7304f8
equal deleted inserted replaced
2:3975fa5ed630 3:b2df1b3f2c83
1 --
2 -- Copyright 2007-2008 Savarese Software Research Corporation.
3 --
4 -- Licensed under the Apache License, Version 2.0 (the "License");
5 -- you may not use this file except in compliance with the License.
6 -- You may obtain a copy of the License at
7 --
8 -- http://www.savarese.com/software/ApacheLicense-2.0
9 --
10 -- Unless required by applicable law or agreed to in writing, software
11 -- distributed under the License is distributed on an "AS IS" BASIS,
12 -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 -- See the License for the specific language governing permissions and
14 -- limitations under the License.
15 --
16
17 local ltp = require('ltp.util')
18
19 local function compile_template_to_table(result, data, start_lua, end_lua)
20 local LF, CR, EQ = 10, 13, 61
21 local i1, i2, i3
22
23 i3 = 1
24
25 repeat
26 i2, i1 = data:find(start_lua, i3, true)
27
28 if i2 then
29 if i3 < i2 then
30 table.insert(result, "table.insert(output,")
31 table.insert(result, string.format('%q', data:sub(i3, i2 - 1)))
32 table.insert(result, ");")
33 end
34
35 i1 = i1 + 2
36 i2, i3 = data:find(end_lua, i1, true)
37
38 if i2 then
39 if data:byte(i1-1) == EQ then
40 table.insert(result, "table.insert(output,")
41 table.insert(result, data:sub(i1, i2 - 1))
42 table.insert(result, ");")
43 i3 = i3 + 1
44 else
45 table.insert(result, data:sub(i1, i2 - 1))
46 i3 = i3 + 1
47 if data:byte(i3) == LF then
48 i3 = i3 + 1
49 elseif data:byte(i3) == CR and data:byte(i3+1) == LF then
50 i3 = i3 + 2
51 end
52 end
53 end
54 elseif i3 <= #data then
55 table.insert(result, "table.insert(output,")
56 table.insert(result, string.format('%q', data:sub(i3)))
57 table.insert(result, ");")
58 end
59 until not i2
60
61 return result
62 end
63
64 local function compile_template_as_function(data, start_lua, end_lua)
65 local result = { "return function(output) " }
66 table.insert(compile_template_to_table(result, data, start_lua, end_lua),
67 "end")
68 return table.concat(result)
69 end
70
71 local function compile_template(data, start_lua, end_lua)
72 return
73 table.concat(compile_template_to_table({ }, data, start_lua, end_lua))
74 end
75
76 local function load_template(data, start_lua, end_lua)
77 return
78 assert(loadstring(compile_template_as_function(data, start_lua, end_lua),
79 "=(load)"))()
80 end
81
82 local function execute_template(template, environment, output)
83 setfenv(template, environment)(output)
84 end
85
86 local function basic_environment(merge_global, environment)
87 if not environment then
88 environment = { }
89 end
90
91 if merge_global then
92 ltp.merge_index(environment, _G)
93 else
94 environment.table = table
95 end
96
97 return environment
98 end
99
100 local function load_environment(env_files, merge_global)
101 local environment = nil
102
103 if env_files and #env_files > 0 then
104 for i = 1,#env_files,1 do
105 local efun = assert(loadfile(env_files[i]))
106
107 if i > 1 then
108 environment = ltp.merge_table(setfenv(efun, environment)(), environment)
109 else
110 environment = basic_environment(merge_global, efun())
111 end
112 end
113 else
114 environment = basic_environment(merge_global)
115 end
116
117 return environment
118 end
119
120 local function read_template(template)
121 return ((template == "-" and io.stdin:read("*a")) or ltp.read_all(template))
122 end
123
124 local function render_template(template_data, start_lua, end_lua, environment)
125 local rfun = load_template(template_data, start_lua, end_lua)
126 local output = { }
127 execute_template(rfun, environment, output)
128 return table.concat(output)
129 end
130
131 local function execute_env_code(env_code, environment)
132 for i = 1,#env_code do
133 local fun, emsg = loadstring(env_code[i])
134
135 if fun then
136 setfenv(fun, environment)()
137 else
138 error("error loading " .. env_code[i] .. "\n" .. emsg)
139 end
140 end
141 end
142
143 local function render(outfile, num_passes, template, merge_global,
144 env_files, start_lua, end_lua, env_code)
145 local data = assert(read_template(template), "error reading " .. template)
146 local environment = load_environment(env_files, merge_global)
147
148 execute_env_code(env_code, environment)
149
150 if num_passes > 0 then
151 for i = 1,num_passes do
152 data = render_template(data, start_lua, end_lua, environment)
153 end
154 else
155 -- Prevent an infinite loop by capping expansion to 100 times.
156 num_passes = 1
157 repeat
158 data = render_template(data, start_lua, end_lua, environment)
159 num_passes = num_passes + 1
160 until data:find(start_lua, 1, true) == nil or num_passes >= 100
161 end
162
163 outfile:write(data);
164 end
165
166 local function compile_as_function(outfile, template, start_lua, end_lua)
167 local data = read_template(template)
168 outfile:write(compile_template_as_function(data, start_lua, end_lua))
169 end
170
171 local function compile(outfile, template, start_lua, end_lua)
172 local data = read_template(template)
173 outfile:write(compile_template(data, start_lua, end_lua))
174 end
175
176 return ltp.merge_table(
177 {
178 compile_template_to_table = compile_template_to_table,
179 compile_template_as_function = compile_template_as_function,
180 compile_template = compile_template,
181 load_template = load_template,
182 execute_template = execute_template,
183 basic_environment = basic_environment,
184 load_environment = load_environment,
185 render_template = render_template,
186 execute_env_code = execute_env_code,
187 render = render,
188 compile_as_function = compile_as_function,
189 compile = compile
190 },
191 ltp
192 )

mercurial