blob: 6a791d8a05cd62b2b026371bd30cff8f3c299c33 [file] [log] [blame]
--- **LIBEZT-1.0** Is a simple library for importing/rendering EZT templates
-- @class file
-- @name LIBEZT-1.0
--[[ LIBEZT-1.0
Revision: $Rev: 1707563 $
Author(s): Humbedooh
Description: EZT import library
License: Apache License, v/2.0
]]
local LIBEZT_MAJOR = "LibEZT-1.0"
-- version number of this file (automatically generated by SVN)
local LIBEZT_MINOR = tonumber(("$Rev: 1707563 $"):match("(%d+)")) or 10000;
local LIBEZT = false;
if LibStub then
LIBEZT = LibStub:NewLibrary(LIBEZT_MAJOR, LIBEZT_MINOR)
_G.LIBEZT = LIBEZT;
else
if not _G.LIBEZT or (type(_G.LIBEZT) == "table" and _G.LIBEZT.rev < LIBEZT_MINOR) then
_G.LIBEZT = {rev = LIBEZT_MINOR};
end
LIBEZT = _G.LIBEZT;
end
if not LIBEZT then return end
function LIBEZT:version()
return LIBEZT_MINOR
end
function LIBEZT.parseargs(s)
local arg = {};
for w in s:gmatch("([%w:%-]+)") do table.insert(arg,w) end
return arg;
end
function LIBEZT.at(s,e)
local l = 1;
for n = 1, e do if s:sub(n,n)=="\n" then l=l+1 end end
return l
end
function LIBEZT:import(s, loose)
local tremove, parseargs,tinsert = table.remove, LIBEZT.parseargs,table.insert;
local stack = {};
local top = {};
tinsert(stack, top);
local ni,c,class,args;
local i, j = 1, 1;
local ci, cj -- start and end of HTML comment (if any)
local searchComment = true -- whether there are comments still to find
while true do
-- class: (alpha | '_') (alphanum | '_' | '-')*
-- args = anything afterwards
ni,j,class,args = s:find("%[([%l%u_][%w%-_]*)([^%]]*)%]", i);
if not ni then break end
--[[
HTML comments may contain constructs that look like ezt sytnax, e.g.
<!--[if lt IE 9]> ... <![endif]-->
In order to support HTML comments, we need to scan for either a comment or an EZT command
However Lua does not support RE alternation, so this needs to be done as a separate search.
Also Lua does not support a "continue" clause so we need to use a nested if
]]
if searchComment then ci, cj = s:find("<!%-%-.-%-%->", i) end -- find next HTML comment (if any)
if not ci then searchComment = False end -- no comment found; there cannot be any more
if searchComment and ci < ni then -- the comment starts before the ezt command
top[#top+1]=s:sub(i, cj);
i = cj + 1 -- skip the comment
-- and continue to look for next ezt command
else
-- found an ezt command outside an HTML comment
local text = s:sub(i, ni-1);
if text:find("%S") then
top[#top+1]=text;
end
if (class ~= "ezt" and class ~= "end" and class ~= "if" and class~= "is" and class~= "if-any" and class ~= "define" and class~= "for") then -- empty element
top[#top+1] ={class=class, args=parseargs(args), empty=true, ni=ni};
elseif class ~= "end" then -- start tag
-- print("open " .. class)
top = {class=class, args=parseargs(args), ni=ni};
stack[#stack+1] = top; -- new level
elseif class == "end" then -- end tag
local toclose = tremove(stack); -- pop the top and get the opening tag
--print("close " .. toclose.class)
top = stack[#stack];
if #stack < 1 then
-- print( ("%s: No opening tag found for <%s> (at line %u)!"):format("LibEZT", class, LIBEZT.at(s,ni)))
return nil, ("%s: No opening tag found for <%s> (at line %u)!"):format("LibEZT", class, LIBEZT.at(s,ni));
end
top[#top+1] = toclose;
end
i = j+1;
end
end
local text = s:sub(i);
if not text:find("^%s*$") then
local st = stack[#stack];
st[#st+1] = text;
end
if #stack > 1 then
local l = LIBEZT.at(s, (stack[#stack].ni or 0))
print(("%s: EZT data ended without closing [%s] (at line %u)!"):format("LibEZT", stack[#stack].class, l))
return nil, ("%s: EZT data ended without closing <%s> (at line %u)!"):format("LibEZT", stack[#stack].class, l);
end
return stack[1];
end
function LIBEZT.construct(self, child, defs)
if type(child) == "string" then
return child or ""
elseif type(child) == "table" and #table > 0 then
-- print("got a root")
local rv = ""
for k, v in pairs(child) do
print(k) -- TODO this looks like a debug statement, should it still be enabled?
rv = rv .. LIBEZT.construct(self, v, defs)
end
return rv
elseif child.class then
if child.class == "ezt" then
-- print("Starting EZT...")
local rv = ""
for k, v in ipairs(child) do
rv = rv .. LIBEZT.construct(self, v, defs)
end
return rv
elseif child.class == "define" then
-- print("got a define")
local key = child.args[1]
defs.strings[key] = child[1]
-- print("set", key, child[1])
return ""
elseif child.class == "for" then
local rv = ""
-- print("Doing for...")
if child.args[1] and defs.arrays[child.args[1]] then
for x,y in pairs(defs.arrays[child.args[1]]) do
defs.strings[child.args[1]] = y
for k, v in ipairs(child) do
--print(k)
rv = rv .. LIBEZT.construct(self, v, defs)
end
end
end
return rv
elseif child.class == "if-any" then
local rv = ""
-- print("Doing if..")
if child.args[1] then
if defs.strings[child.args[1]] or defs.arrays[child.args[1]] then
for k, v in ipairs(child) do
rv = rv .. LIBEZT.construct(self, v, defs)
end
end
end
return rv
elseif child.class == "is" then
local rv = ""
-- print("Doing is..")
rv = ""
if #child.args == 2 then
local a = defs.strings[child.args[1]] or nil
local b = defs.strings[child.args[2]] or nil
if a == b then
for k, v in ipairs(child) do
rv = rv .. LIBEZT.construct(self, v, defs)
end
end
end
return rv
elseif child.empty then
--print(child.class)
return tostring(defs.strings[child.class] or "")
end
else
local rv = ""
for k, v in pairs(child) do
rv = rv .. LIBEZT.construct(self, v, defs)
end
return rv
end
end
return LIBEZT