forked from henix/slt2
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathslt2.lua
More file actions
131 lines (113 loc) · 3.45 KB
/
slt2.lua
File metadata and controls
131 lines (113 loc) · 3.45 KB
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
--[[
-- slt2 - Simple Lua Template 2
--
-- Project page: https://github.com/henix/slt2
--
-- @License
-- MIT License
--
-- @Copyright
-- Copyright (C) 2012 henix.
-- momo
-- 2013-06-23
-- Replaced stand IO to asynchronous IO of Nginx
--]]
local slt2 = {}
-- process included file
-- @return string
local function precompile(template, start_tag, end_tag)
local result = {}
local start_tag_inc = start_tag..'include:'
local start1, end1 = string.find(template, start_tag_inc, 1, true)
local start2 = nil
local end2 = 0
while start1 ~= nil do
if start1 > end2 + 1 then -- for beginning part of file
table.insert(result, string.sub(template, end2 + 1, start1 - 1))
end
start2, end2 = string.find(template, end_tag, end1 + 1, true)
assert(start2, 'end tag "'..end_tag..'" missing')
do -- recursively include the file
local filename = assert(loadstring('return '..string.sub(template, end1 + 1, start2 - 1)))()
assert(filename)
local res = assert(ngx.location.capture(filename))
-- TODO: detect cyclic inclusion?
table.insert(result, precompile(res.body, start_tag, end_tag))
end
start1, end1 = string.find(template, start_tag_inc, end2 + 1, true)
end
table.insert(result, string.sub(template, end2 + 1))
return table.concat(result)
end
-- @return function
function slt2.loadstring(template, start_tag, end_tag, tmpl_name)
-- compile it to lua code
local lua_code = {}
start_tag = start_tag or '#{'
end_tag = end_tag or ' }'
local output_func = "coroutine.yield"
template = precompile(template, start_tag, end_tag)
local start1, end1 = string.find(template, start_tag, 1, true)
local start2 = nil
local end2 = 0
local cEqual = string.byte('=', 1)
while start1 ~= nil do
if start1 > end2 + 1 then
table.insert(lua_code, output_func..'('..string.format("%q", string.sub(template, end2 + 1, start1 - 1))..')')
end
start2, end2 = string.find(template, end_tag, end1 + 1, true)
assert(start2, 'end_tag "'..end_tag..'" missing')
if string.byte(template, end1 + 1) == cEqual then
table.insert(lua_code, output_func..'('..string.sub(template, end1 + 2, start2 - 1)..')')
else
table.insert(lua_code, string.sub(template, end1 + 1, start2 - 1))
end
start1, end1 = string.find(template, start_tag, end2 + 1, true)
end
table.insert(lua_code, output_func..'('..string.format("%q", string.sub(template, end2 + 1))..')')
local ret = { name = '=(slt2.loadstring)' }
if setfenv == nil then -- lua 5.2
ret.code = table.concat(lua_code, '\n')
else -- lua 5.1
ret.code = assert(loadstring(table.concat(lua_code, '\n'), tmpl_name))
end
return ret
end
-- @return function
function slt2.loadfile(filename, start_tag, end_tag)
local res = assert(ngx.location.capture(filename))
local all = res.body
local ret = slt2.loadstring(all, start_tag, end_tag, filename)
ret.name = filename
return ret
end
local mt52 = { __index = _ENV }
local mt51 = { __index = _G }
-- @return a coroutine function
function slt2.render_co(t, env)
local f
if setfenv == nil then -- lua 5.2
if env ~= nil then
setmetatable(env, mt52)
end
f = assert(load(t.code, t.name, 't', env or _ENV))
else -- lua 5.1
if env ~= nil then
setmetatable(env, mt51)
end
f = setfenv(t.code, env or _G)
end
return f
end
-- @return string
function slt2.render(t, env)
local result = {}
local f = coroutine.wrap(slt2.render_co(t, env))
local chunk = f()
while chunk ~= nil do
table.insert(result, chunk)
chunk = f()
end
return table.concat(result)
end
return slt2