1#!/usr/bin/env lua5.3
  2
  3
  4-- special marks:
  5-- \1 - paragraph (empty line)
  6-- \4 - remove spaces around it
  7-- \3 - ref (followed by label|)
  8
  9---------------------------------------------------------------
 10header = [[
 11<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
 12<html>
 13
 14<head>
 15<title>Lua 5.4 Reference Manual</title>
 16<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
 17<link rel="stylesheet" href="lua.css">
 18<link rel="stylesheet" href="manual.css">
 19</head>
 20
 21<body bgcolor="#FFFFFF">
 22
 23<hr>
 24<h1>
 25<a href="http://www.lua.org/home.html"><img src="logo.gif" alt="[Lua logo]" border="0"></a>
 26Lua 5.4 Reference Manual
 27</h1>
 28
 29by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes
 30<p>
 31<small>
 32<a href="http://www.lua.org/copyright.html">Copyright</a>
 33&copy; 2024 Lua.org, PUC-Rio.  All rights reserved.
 34</small>
 35<hr>
 36
 37<!-- ====================================================================== -->
 38<p>
 39
 40]]
 41
 42footer = "\n\n</body></html>\n\n"
 43
 44local seefmt = '(see %s)'
 45
 46if arg[1] == 'port' then
 47  seefmt = '(ver %s)'
 48  header = string.gsub(header, "by (.-)\n",
 49  "%1\n<p>Tradu&ccedil;&atilde;o: S&eacute;rgio Queiroz de Medeiros", 1)
 50  header = string.gsub(header, "Lua (%d+.%d+) Reference Manual",
 51                               "Manual de Refer&ecirc;ncia de Lua %1")
 52  header = string.gsub(header, "All rights reserved",
 53                               "Todos os direitos reservados")
 54end
 55
 56
 57---------------------------------------------------------------
 58
 59local function compose (f,g)
 60  assert(f and g)
 61  return function (s) return g(f(s)) end
 62end
 63
 64local function concat (f, g)
 65  assert(f and g)
 66  return function (s) return f(s) .. g(s) end
 67end
 68
 69
 70local Tag = {}
 71
 72
 73setmetatable(Tag, {
 74  __index = function (t, tag)
 75      local v = function (n, att)
 76        local e = ""
 77        if type(att) == "table" then
 78          for k,v in pairs(att) do e = string.format('%s %s="%s"', e, k, v) end
 79        end
 80        if n then
 81          return string.format("<%s%s>%s</%s>", tag, e, n, tag)
 82        else
 83          return string.format("<%s%s>", tag, e)
 84        end
 85      end
 86      t[tag] = v
 87      return v
 88  end
 89})
 90
 91
 92
 93---------------------------------------------------------------
 94local labels = {}
 95
 96
 97local function anchor (text, label, link, textlink)
 98  if labels[label] then
 99    error("label " .. label .. " already defined")
100  end
101  labels[label] = {text = textlink, link = link}
102  return Tag.a(text, {name=link})
103end
104
105local function makeref (label)
106  assert(not string.find(label, "|"))
107  return string.format("\3%s\3", label)
108end
109
110local function ref (label)
111  local l = labels[label]
112  if not l then
113    io.stderr:write("label ", label, " undefined\n")
114    return "@@@@@@@"
115  else
116    return Tag.a(l.text, {href="#"..l.link})
117  end
118end
119
120---------------------------------------------------------------
121local function nopara (t)
122  t = string.gsub(t, "\1", "\n\n")
123  t = string.gsub(t, "<p>%s*</p>", "")
124  return t
125end
126
127local function fixpara (t)
128  t = string.gsub(t, "\1", "\n</p>\n\n<p>\n")
129  t = string.gsub(t, "<p>%s*</p>", "")
130  return t
131end
132
133local function antipara (t)
134  return "</p>\n" .. t .. "<p>"
135end
136
137
138Tag.pre = compose(Tag.pre, antipara)
139Tag.ul = compose(Tag.ul, antipara)
140
141---------------------------------------------------------------
142local Gfoots = 0
143local footnotes = {}
144
145local line = Tag.hr(nil)
146
147local function dischargefoots ()
148  if #footnotes == 0 then return "" end
149  local fn = table.concat(footnotes)
150  footnotes = {}
151  return line .. Tag.h3"footnotes:" .. fn .. line
152end
153
154
155local Glists = 0
156local listings = {}
157
158local function dischargelist ()
159  if #listings == 0 then return "" end
160  local l = listings
161  listings = {}
162  return line .. table.concat(l, line..line) .. line
163end
164
165---------------------------------------------------------------
166local counters = {
167h1 = {val = 1},
168h2 = {father = "h1", val = 1},
169h3 = {father = "h2", val = 1},
170listing = {father = "h1", val = 1},
171}
172
173local function inccounter (count)
174  counters[count].val = counters[count].val + 1
175  for c, v in pairs(counters) do
176    if v.father == count then v.val = 1 end
177  end
178end
179
180local function getcounter (count)
181  local c = counters[count]
182  if c.father then
183    return getcounter(c.father) .. "." .. c.val
184  else
185    return c.val .. ""
186  end
187end
188---------------------------------------------------------------
189
190
191local function fixed (x)
192  return function () return x end
193end
194
195local function id (x) return x end
196
197
198local function prepos (x, y)
199  assert(x and y)
200  return function (s) return string.format("%s%s%s", x, s, y) end
201end
202
203
204local rw = Tag.b
205
206
207
208
209local function LuaName (name)
210  return Tag.code(name)
211end
212
213
214local function getparam (s)
215  local i, e = string.find(s, "^[^%s@|]+|")
216  if not i then return nil, s
217  else return string.sub(s, i, e - 1), string.sub(s, e + 1)
218  end
219end
220
221
222local function gettitle (h)
223  local title, p = assert(string.match(h, "<title>(.-)</title>()"))
224  return title, string.sub(h, p)
225end
226
227local function getparamtitle (what, h, nonum)
228    local label, title, c, count
229    label, h = getparam(h)
230    title, h = gettitle(h)
231    if not nonum then
232      count = getcounter(what)
233      inccounter(what)
234      c = string.format("%s &ndash; ", count)
235    else
236      c = ""
237    end
238    label = label or count
239    if label then
240      title = anchor(title, label, count, "&sect;"..count)
241    end
242    title = string.format("%s%s", c, title)
243    return title, h
244end
245
246local function section (what, nonum)
247  return function (h)
248    local title
249    title, h = getparamtitle(what, h, nonum)
250    local fn = what == "h1" and dischargefoots() or ""
251    h = fixpara(Tag.p(h))
252    return "</p>\n" .. Tag[what](title) .. h .. fn ..
253           dischargelist() .. "<p>"
254  end
255end
256
257
258local function verbatim (s)
259  s = nopara(s)
260  s = string.gsub(s, "\n", "\n     ")
261  s = string.gsub(s, "\n%s*$", "\n")
262  return Tag.pre(s)
263end
264
265
266local function verb (s)
267  return Tag.code(s)
268end
269
270
271local function lua2link (e)
272  return string.find(e, "luaL?_") and e or "pdf-"..e
273end
274
275
276local verbfixed = verb
277
278
279local Tex = {
280
281ANSI = function (func)
282           return "ISO&nbsp;C function " .. Tag.code(func)
283         end,
284At = fixed"@",
285B = Tag.b,
286bigskip = fixed"",
287bignum = id,
288C = fixed"",
289Ci = prepos("<!-- ", " -->"),
290CId = function (func)
291        return "C&nbsp;function " .. Tag.code(func)
292      end,
293chapter = section"h1",
294Char = compose(verbfixed, prepos("'", "'")),
295Cdots = fixed"&middot;&middot;&middot;",
296Close = fixed"}",
297col = Tag.td,
298defid = function (name)
299          local l = lua2link(name)
300          local c = Tag.code(name)
301          return anchor(c, l, l, c)
302        end,
303def = Tag.em,
304description = compose(nopara, Tag.ul),
305Em = fixed("\4" .. "&mdash;" .. "\4"),
306emph = Tag.em,
307emphx = Tag.em,    -- emphasis plus index (if there was an index)
308En = fixed("&ndash;"),
309format = fixed"",
310["false"] = fixed(Tag.b"false"),
311id = Tag.code,
312idx = Tag.code,
313index = fixed"",
314Lidx = fixed"",  -- Tag.code,
315ldots = fixed"...",
316x = id,
317itemize = compose(nopara, Tag.ul),
318leq = fixed"&le;",
319Lid = function (s)
320        return makeref(lua2link(s))
321      end,
322M = Tag.em,
323N = function (s) return (string.gsub(s, " ", "&nbsp;")) end,
324NE = id,        -- tag"foreignphrase",
325num = id,
326["nil"] = fixed(Tag.b"nil"),
327fail = fixed(Tag.b"fail"),
328Open = fixed"{",
329part = section("h1", true),
330Pat = compose(verbfixed, prepos("'", "'")),
331preface = section("h1", true),
332psect = section("h2", true),
333Q = prepos('"', '"'),
334refchp = makeref,
335refcode = makeref,
336refsec = makeref,
337
338pi = fixed"&pi;",
339rep = Tag.em,  -- compose(prepos("&lt;", "&gt;"), Tag.em),
340Rw = rw,
341rw = rw,
342sb = Tag.sub,
343sp = Tag.sup,
344St = compose(verbfixed, prepos('"', '"')),
345sect1 = section"h1",
346sect2 = section"h2",
347sect3 = section"h3",
348sect4 = section("h4", true),
349simplesect = id,
350Tab2 = function (s) return Tag.table(s, {border=1}) end,
351row = Tag.tr,
352title = Tag.title,
353todo = Tag.todo,
354["true"] = fixed(Tag.b"true"),
355T = verb,
356
357item = function (s)
358         local t, p = string.match(s, "^([^\n|]+)|()")
359         if t then
360           s = string.sub(s, p)
361           s = Tag.b(t..": ") .. s
362         end
363         return Tag.li(fixpara(s))
364       end,
365
366verbatim = verbatim,
367
368manual = id,
369
370
371-- for the manual
372
373link =function (s)
374  local l, t = getparam(s)
375  assert(l)
376  return string.format("%s (%s)", t, makeref(l))
377end,
378
379see = function (s) return string.format(seefmt, makeref(s)) end,
380See = makeref,
381seeC = function (s)
382         return string.format(seefmt, makeref(s))
383       end,
384
385seeF = function (s)
386         return string.format(seefmt, makeref(lua2link(s)))
387       end,
388
389APIEntry = function (e)
390  local h, name
391  h, e = string.match(e, "^%s*(.-)%s*|(.*)$")
392  name = string.match(h, "(luaL?_[%w_]+)%)? +%(") or
393         string.match(h, "luaL?_[%w_]+")
394  local a = anchor(Tag.code(name), name, name, Tag.code(name))
395  local apiicmd, ne = string.match(e, "^(.-</span>)(.*)")
396--io.stderr:write(e)
397  if not apiicmd then
398    return antipara(Tag.hr() .. Tag.h3(a)) .. Tag.pre(h) .. e
399  else
400    return antipara(Tag.hr() .. Tag.h3(a)) .. apiicmd .. Tag.pre(h) .. ne
401  end
402end,
403
404LibEntry = function (e)
405  local h, name
406  h, e = string.match(e, "^(.-)|(.*)$")
407  name = string.gsub(h, " (.+", "")
408  local l = lua2link(name)
409  local a = anchor(Tag.code(h), l, l, Tag.code(name))
410  return Tag.hr() .. Tag.h3(a) .. e
411end,
412
413Produc = compose(nopara, Tag.pre),
414producname = prepos("\t", " ::= "),
415Or = fixed" | ",
416VerBar = fixed"&#124;",  -- vertical bar
417OrNL = fixed" | \4",
418bnfNter = prepos("", ""),
419bnfopt = prepos("[", "]"),
420bnfrep = prepos("{", "}"),
421bnfter = compose(Tag.b, prepos("&lsquo;", "&rsquo;")),
422producbody = function (s)
423           s = string.gsub(s, "%s+", " ")
424           s = string.gsub(s, "\4", "\n\t\t")
425           return s
426         end,
427
428apii = function (s)
429        local pop,push,err = string.match(s, "^(.-),(.-),(.*)$")
430        if pop ~= "?" and string.find(pop, "%W") then
431          pop = "(" .. pop .. ")"
432        end
433        if push ~= "?" and string.find(push, "%W") then
434          push = "(" .. push .. ")"
435        end
436        err = (err == "-") and "&ndash;" or Tag.em(err)
437        return Tag.span(
438                 string.format("[-%s, +%s, %s]", pop, push, err),
439                 {class="apii"}
440               )
441      end,
442}
443
444local others = prepos("?? "," ??")
445
446local function trata (t)
447  t = string.gsub(t, "@(%w+)(%b{})", function (w, f)
448        f = trata(string.sub(f, 2, -2))
449        if type(Tex[w]) ~= "function" then
450         io.stderr:write(w .. "\n")
451         return others(f)
452        else
453         return Tex[w](f, w)
454        end
455      end)
456  return t
457end
458
459
460---------------------------------------------------------------------
461---------------------------------------------------------------------
462
463-- read whole book
464t = io.read"*a"
465
466t = string.gsub(t, "[<>&\128-\255]",
467  {["<"] = "&lt;",
468   [">"] = "&gt;",
469   ["&"] = "&amp;",
470   ["\170"] = "&ordf;",
471   ["\186"] = "&ordm;",
472   ["\192"] = "&Agrave;",
473   ["\193"] = "&Aacute;",
474   ["\194"] = "&Acirc;",
475   ["\195"] = "&Atilde;",
476   ["\199"] = "&Ccedil;",
477   ["\201"] = "&Eacute;",
478   ["\202"] = "&Ecirc;",
479   ["\205"] = "&Iacute;",
480   ["\211"] = "&Oacute;",
481   ["\212"] = "&Ocirc;",
482   ["\218"] = "&Uacute;",
483   ["\224"] = "&agrave;",
484   ["\225"] = "&aacute;",
485   ["\226"] = "&acirc;",
486   ["\227"] = "&atilde;",
487   ["\231"] = "&ccedil;",
488   ["\233"] = "&eacute;",
489   ["\234"] = "&ecirc;",
490   ["\237"] = "&iacute;",
491   ["\243"] = "&oacute;",
492   ["\244"] = "&ocirc;",
493   ["\245"] = "&otilde;",
494   ["\250"] = "&uacute;",
495   ["\252"] = "&uuml;"
496  })
497
498t = string.gsub(t, "\n\n+", "\1")
499
500
501
502-- complete macros with no arguments
503t = string.gsub(t, "(@%w+)([^{%w])", "%1{}%2")
504
505t = trata(t)
506
507-- correct references
508t = string.gsub(t, "\3(.-)\3", ref)
509
510-- remove extra space (??)
511t = string.gsub(t, "%s*\4%s*", "")
512
513t = nopara(t)
514
515-- HTML 3.2 does not need </p> (but complains when it is in wrong places :)
516t = string.gsub(t, "</p>", "")
517
518io.write(header, t, footer)
519