module (..., package.seeall) require "lpeg" local lpeg = lpeg --list of of commands currently recognized local cmdPod = lpeg.P ("=pod") local cmdCut = lpeg.P ("=cut") local cmdHead1 = lpeg.P ("=head1") local cmdHead2 = lpeg.P ("=head2") local cmdHead3 = lpeg.P ("=head3") local cmdHead4 = lpeg.P ("=head4") local cmdOver = lpeg.P ("=over") local cmdItem = lpeg.P ("=item") local cmdBack = lpeg.P ("=back") local cmdBegin = lpeg.P ("=begin") local cmdEnd = lpeg.P ("=end") local cmdFor = lpeg.P ("=for") --indicates if you are generating HTML to be embedded into another HTML document local embedded = nil local doctype = [[ ]] local encoding = [[]] local fileTitle = nil --Declares the parsing function, because it is referenced before its definition local parsing = nil --Keeps the formatting code tags, because they can be nested local formatTable = {} --The output variable local out = nil --Keeps the type of the "=begin =end" region (comment, html etc) local formatNames = { } --Indicates if the POD formatting rules should be used in the current region local isFormatting = { true } --When processing a paragraph inside a "=begin :" or "=for :" region, --each line of the paragraph is read and saved in currentData until --that all the paragraph is read local currentData = { } --Keeps the type of the current "=for" region, if it is an --HTML or biblio region, for example local currentFor = nil --Keeps the number of the current "=head" command local headNumber = 1 --Keeps the current link of a L code Llink = nil --The base url that will be used to resolve links in L codes local baseURL = "localhost" local function Itag (t) if t then return "" else return "" end end local function Btag (t) if t then return "" else return "" end end local function Ctag (t) if t then return "" else return "" end end local function Ltag (t) if t then return "" end end local function Ltagaux () local s = Llink local space = lpeg.P (" ") + lpeg.P ("\t") + lpeg.P ("\n") + lpeg.P ("\f") + lpeg.P ("\r") --this match succeeds if the L tag contains an absolute url local html = lpeg.match (lpeg.C (lpeg.R ("AZ", "az", "09")^1 * ":" * (1 - (lpeg.P (":") + space)) * (1 - space)^0) * -1, s) if html then return html .. "\">" .. html end --it is not an absolute url --now, it will try to match each possible part of a L code --the text part local x = string.find (s, "|") local text = nil if x then text = string.sub (s, 1, x - 1) else x = 0 end --the name part local y = string.find (s, "/", x + 1) local name = nil if y == nil then name = string.sub (s, x + 1) else name = string.sub (s, x + 1, y - 1) end --the section part local section = nil if y then section = string.sub (s, y + 1) end if section == nil and text == nil and string.find (name, "\"") then section = name name = "" end if section then section = string.gsub (section, "\"", "") end if text == nil or text == "" then if section then text = section else text = name end end text = parsing (text, 1, 1, " ", nil) if section then section = string.gsub (section, " ", "_") end local res = "" if name ~= "" then res = baseURL .. name if section then res = res .. "#" .. section end else --it is a link to the current page res = "#" .. section end res = res .. "\">" .. text return res end local function Etag (t) if t then return "&" else return ";" end end local function Ftag (t) if t then return "" else return "" end end local function Xtag (t) return " " end local function Ztag (t) return " " end local function Stag (t) return " " end --this table contains the functions that should treat each formatting code --the functions are currently receiving a boolean parameter, when it is true it indicates --the beginning of the formatting code, when it false it indicates the ending of the --formatting code local tags = { ["I"] = Itag, ["B"] = Btag, ["C"] = Ctag, ["L"] = Ltag, ["E"] = Etag, ["F"] = Ftag, --these functions below don't do anything useful currently ["X"] = Xtag, ["Z"] = Ztag, ["S"] = Stag } local function commentFormatCode (t) if t then return "" end end --This table represents the functions that should treat --"=begin =end" regions local formatCode = { ["comment"] = commentFormatCode } local function initFormatTable () formatTable = {} end local function insertFormatTable (initCode) formatTable[#formatTable + 1] = { l = string.sub (initCode, 1, 1), code = string.sub (initCode, 2) } end parsing = function (s, initPos, endPos, res, lastPos, x1, y1, x2, y2, insideLCode) --what tag (an opening tag or a closing one) was consumed in the previous execution, --so we need to find a new one if lastPos == "init" then x1, y1 = string.find (s, "%a<+", initPos) elseif lastPos == "end" then x2, y2 = string.find (s, ">+", endPos) else x1, y1 = string.find (s, "%a<+", initPos) x2, y2 = string.find (s, ">+", endPos) end --closes unmatched tags if x2 == nil then res = res .. string.sub (s, math.max (initPos, endPos)) for i, v in ipairs (formatTable) do if v.l == "L" then res = res .. "\">" .. tags[v.l] (false) else res = res .. tags[v.l] (false) end end return string.sub (res, 2) end if x1 == nil or x2 < x1 then -- next is ">" local e = formatTable [#formatTable] --changes ">" to "<" to compare with the starting formatting code local tmp = string.gsub (string.sub (s, x2, y2), ">", "<") if e ~= nil and e.code == tmp then table.remove (formatTable) if e.l == "L" then Llink = Llink .. string.sub (s, math.max (initPos, endPos), x2 -1) local tmp = Ltagaux (tmp) res = res .. tmp .. tags[e.l] (false) insideLCode = false else if insideLCode then Llink = Llink .. string.sub (s, math.max (initPos, endPos), x2 - 1) Llink = Llink .. string.sub (s, x2, y2) else res = res .. string.sub (s, math.max (initPos, endPos), x2 - 1) res = res .. tags[e.l] (false) end end else --it is not the end of a formatting code, let's put the text just it is res = res .. string.sub (s, math.max (initPos, endPos), y2) end return parsing (s, initPos, y2 + 1, res, "end", x1, y1, x2, y2, insideLCode) else -- next is "<" if insideLCode then Llink = Llink .. string.sub (s, math.max (initPos, endPos), x1 - 1) else res = res .. string.sub (s, math.max (initPos, endPos), x1 - 1) end insertFormatTable (string.sub (s, x1, y1)) local l = string.sub (s, x1, x1) if tags[l] == nil then print ("Error: invalid formatting code!", string.sub (s, x1, y1)) return nil end if insideLCode then Llink = Llink .. string.sub (s, x1, y1) else res = res .. tags[l] (true) end if l == "L" then insideLCode = true Llink = "" end return parsing (s, y1 + 1, endPos, res, "init", x1, y1, x2, y2, insideLCode) end end local function showNewline () out:write ("\n") end local function start () if not embedded then out:write (doctype) out:write ("\n\n") out:write ("\n") out:write (encoding) out:write ("" .. fileTitle .. "\n") out:write ("\n") out:write ("\n") end out:write ("") end local function finish () if not embedded then out:write ("\n") out:write ("\n") end end local function h1 () out:write ("

") headNumber = 1 end local function h2 () out:write ("

") headNumber = 2 end local function h3 () out:write ("

") headNumber = 3 end local function h4 () out:write ("

") headNumber = 4 end local function display (s) initFormatTable () out:write (parsing (s, 1, 1, " ", nil) or " ") end local function headName (s) out:write ("") display (s) out:write ("") end local function ordinary (s) out:write ("

") display (s) out:write ("

") end --The type of =over back regin can only be determined after the first --paragraph after the =over command. firstItem it is used to indicate --if first paragraph is the first one local firstItem = nil --Keeps what is the kind of item that should be used --in an "=over =back" region local itemType = { } local function over () firstItem = true end local function overIdent (s) firstItem = true end local function item () end local function back () --should not have the "" around false, I need to test this firstItem = false if itemType [#itemType] == "dl" then out:write ("") end out:write ("") table.remove (itemType) end local function verbatim (s) out:write ("
")
    out:write (s)
    out:write ("
") end local function bareItem () if firstItem then out:write ("