Warning: this is an htmlized version!
The original is here, and
the conversion rules are here.
-- This file:
-- http://angg.twu.net/dednat5/rect.lua
-- http://angg.twu.net/dednat5/rect.lua.html
--  (find-angg        "dednat5/rect.lua")
--
-- Author:  Eduardo Ochs <eduardoochs@gmail.com>
-- Version: 2015aug05
-- Licence: GPL3
--
-- This is a total rewrite (different data structures, methods, etc) of:
-- (find-dn5 "gab.lua" "Rect")
-- Example:
--   > = synttorect {[0]="+", {[0]="*", "2", "3"}, {[0]="*", "4", "5"}}
--   +_____.
--   |     |
--   *__.  *__.
--   |  |  |  |
--   2  3  4  5


copy = function (A)
    local B = {}
    for k,v in pairs(A) do B[k] = v end
    setmetatable(B, getmetatable(A))
    return B
  end

torect = function (o)
    if otype(o) == "Rect" then return o end
    if type(o) == "string" then return Rect.new(o) end
    error()
  end

Rect = Class {
  type = "Rect",
  new  = function (str) return Rect(splitlines(str)) end,
  rep  = function (str, n) local r=Rect{}; for i=1,n do r[i]=str end; return r end,
  __tostring = function (rect) return rect:tostring() end,
  __concat = function (r1, r2) return torect(r1):concat(torect(r2)) end,
  __index = {
    tostring = function (rect) return table.concat(rect, "\n") end,
    copy = function (rect) return copy(rect) end,
    width = function (rect) return foldl(max, 0, map(string.len, rect)) end,
    push1 = function (rect, str) table.insert(rect, 1, str); return rect end,
    push2 = function (rect, str1, str2) return rect:push1(str2):push1(str1) end,
    pad0  = function (rect, y, w, c, rstr)
        rect[y] = ((rect[y] or "")..(c or " "):rep(w)):sub(1, w)..(rstr or "")
        return rect
      end,
    lower = function (rect, n, str)
        for i=1,n do rect:push1(str or "") end
        return rect
      end,
    concat = function (r1, r2, w, dy)
        r1 = r1:copy()
        w = w or r1:width()
        dy = dy or 0
        for y=#r1+1,#r2+dy do r1[y] = "" end
        for y=1,#r2 do r1:pad0(y+dy, w, nil, r2[y]) end
        return r1
      end,
    prepend = function (rect, str) return Rect.rep(str, #rect)..rect end,
    --
    syn1 = function (r1, opname) return r1:copy():push2(opname or ".", "|") end,
    synconcat = function (r1, r2)
        return r1:copy():pad0(1, r1:width()+2, "_")..r2:copy():push2(".", "|")
      end,
    --
    dedconcat = function (r1, r2)
        local w = r1:width() + 2
        if #r1 <  #r2 then return r1:copy():lower(#r2-#r1):concat(r2, w) end
        if #r1 == #r2 then return r1:copy():concat(r2, w) end
        if #r1  > #r2 then return r1:copy():concat(r2, w, #r1-#r2) end
      end,
    dedroot = function (rect, str)
        table.insert(rect, ""); table.insert(rect, str); return rect
      end,
    dedbar = function (rect, c, label)
        local abovebar, belowbar = rect[#rect-2], rect[#rect]
        local w = max(#(abovebar or ""), #belowbar)
        rect:pad0(#rect-1, w, c or "-", label)
        return rect
      end,
  },
}

synttorect = function (o)
    if type(o) == "string" then return torect(o) end
    if type(o) == "table" then
      local r = synttorect(o[1]):syn1(o[0])
      for i=2,#o do r = r:synconcat(synttorect(o[i])) end
      return r
    end
    error()
  end

dedtorect = function (o)
    if type(o) == "string" then return torect(o) end
    if type(o) == "table" then
      local r = dedtorect(o[1])
      for i=2,#o do r = r:dedconcat(dedtorect(o[i])) end
      return r:dedroot(o[0] or "?"):dedbar(o.b or "-", o.label)
    end
    error()
  end

synttotex = function (o)
    if type(o) == "string" then return o end
    if type(o) == "table" then
      return (o.tex:gsub("<([%d])>", function (n) return synttotex(o[n+0]) end))
    end
    error()
  end




--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "rect.lua"

r = Rect.new "a\nbb\nccc"
= r
PP(r)
= r:width()
= r:copy():pad0(1, 4, nil, "d")
= r:copy():pad0(1, 4, "_", "d")
= r:copy():push2("op", "|")
= r:copy():push2("op", "|"):pad0(1, r:width()+1, "_")..r:copy():push2(".", "|")
= "This => "..r.." <="

= torect("a"):dedconcat(torect("b"))
= torect("a"):dedconcat(torect("b")):dedroot("c"):dedbar("-", "foo")
= torect("a"):dedconcat(torect("bbbbbb")):dedroot("c"):dedbar("-", "foo")
= torect("a"):dedconcat(torect("b")):dedroot("cccccc"):dedbar("-", "foo")
= torect("2"):syn1("*"):synconcat(torect("3"))
tree = {[0]="+", {[0]="*", "2", "3"}, {[0]="*", "4", "5"}}
tree = {[0]="+", {[0]="*", "2", "3"}, {[0]="*", "4", "5"}, b="=", label="hi"}
= synttorect(tree)
= dedtorect (tree)

tree = { { { "[P&Q]^1",
             [0]="P"
           },
           { { "[P&Q]^1",
               [0]="Q"
             },
             "Q->R",
             [0]="R"
           },
           [0]="P&R"
         },
         label="1",
         [0]="P&Q->P&R"
       }
= dedtorect (tree)

--]]


-- Local Variables:
-- coding: raw-text-unix
-- End: