Warning: this is an htmlized version!
The original is here, and
the conversion rules are here.
-- This file:
--   https://anggtwu.net/LUA/TreeSegs1.lua.html
--   https://anggtwu.net/LUA/TreeSegs1.lua
--           (find-angg "LUA/TreeSegs1.lua")
-- Author: Eduardo Ochs <eduardoochs@gmail.com>
--
-- The functions in this file handle the whitespace-sparated
-- "segments" in "%:"-blocks, using data structures that are easy to
-- print, but that need classes that can't be defined in a bottom-up
-- fashion.
--
-- Each "%:"-line becomes a "Segments" object.
-- Each "Segments" object is a list of "Segment" objects.
-- The "AllSegments" object is almost a list of "Segments" objects -
-- "almost" because it can contains nils.
--
-- To obtain the segments above a "Segment" object `seg' we use
-- "seg:segsabove()", that takes the fields `y', `l', and `r' of
-- `seg', looks at allsegments[y-1], and returns the segments that
-- intersect the interval [l,r].
--
-- The code in heads["%:"] adds "Segments" objects to `allsegments',
-- and for each `rootseg' of the form "^Name" it runs
-- rootseg:rootnode():totreenode(), converts the resulting "TreeNode"
-- object to LaTeX, and outputs LaTeX code of this form:
--
--   \defded{Name}{...}
--
-- To understand the data structures, run the tests in:
--   (to "high-level-test")
--
-- Supersedes:
--   (find-dn6 "treesegs.lua")
--
-- (defun e () (interactive) (find-angg "LUA/TreeSegs1.lua"))
-- (defun o () (interactive) (find-dn6 "treesegs.lua"))
--
-- «.TreeNode»		(to "TreeNode")
-- «.TreeNode-defded»	(to "TreeNode-defded")
-- «.TreeNode-tests»	(to "TreeNode-tests")
-- «.DefDed»		(to "DefDed")
-- «.DefDed-tests»	(to "DefDed-tests")
-- «.AllSegments»	(to "AllSegments")
-- «.allsegments»	(to "allsegments")
-- «.allsegments-tests»	(to "allsegments-tests")
-- «.segtotreenode»	(to "segtotreenode")
-- «.intersects»	(to "intersects")
-- «.Segment»		(to "Segment")
-- «.Segments»		(to "Segments")
-- «.tosegments»	(to "tosegments")
-- «.treesegtest»	(to "treesegtest")
-- «.high-level-test»	(to "high-level-test")
-- «.head»		(to "head")
-- «.head-:»		(to "head-:")
-- «.head-tests»	(to "head-tests")


require "DednatParse1"    -- (find-angg "LUA/DednatParse1.lua")

-- (find-angg "LUA/lua50init.lua" "DedTree")
-- (find-dn6 "heads6.lua" "tree-head")


--  _____              _   _           _      
-- |_   _| __ ___  ___| \ | | ___   __| | ___ 
--   | || '__/ _ \/ _ \  \| |/ _ \ / _` |/ _ \
--   | || | |  __/  __/ |\  | (_) | (_| |  __/
--   |_||_|  \___|\___|_| \_|\___/ \__,_|\___|
--                                            
-- «TreeNode»  (to ".TreeNode")
-- Based on: (find-dn6 "treetex.lua" "TreeNode")
--      See: (find-dn6 "treetex.lua" "TreeNode" "format is much more strict")
--           (find-angg "LUA/lua50init.lua" "DedTree")
--           (find-angg "LUA/Rect.lua" "DedTree")
--
TreeNode = Class {
  type = "TreeNode",
  from = function (o)
      if type(o) == "string" then return TreeNode {[0]=o} end
      if type(o) == "table"  then
        local tn = {[0]=o[0], bar=o.bar, label=o.label}
        for i=1,#o do tn[i] = TreeNode.from(o[i]) end
        if #tn > 0 then tn.bar = tn.bar or "-" end
        return TreeNode(tn)
      end
      Error("TreeNode.from(o) failed")
    end,
  __tostring  = function (tn) return tostring(tn:torect()) end,
  __index = {
    torect       = function (tn) return dedtorect(tn) end,
    hasbar       = function (tn) return tn.bar ~= nil end,
    barchar      = function (tn) return tn.bar end,
    TeX_root     = function (tn) return tn[0] end,
    TeX_label    = function (tn) return tn.label end,
    nhyps        = function (tn) return #tn end,
    hypslist     = function (tn) return tn end,
    outputdefded = function (tn) DefDed.fromnameseg(tn):output() end,
  },
}

-- «TreeNode-tests»  (to ".TreeNode-tests")
--[==[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "TreeSegs1.lua"
ded = {[0]="a", "b", {[0]="c", "d",      "e",           bar="=", label="foo"}}
ded = {[0]="a", "b", {[0]="c", "d", {[0]="e", bar="-"}, bar="=", label="foo"}}
= dedtorect(ded)
tn = TreeNode.from(ded)
PPV(ded)
PPV(tn)
= tn
= otype(tn)
= otype(tn[1])
= otype(ded)
= otype(ded[1])
TreeNode_deftree 
= tn:TeX_subtree("")
= tn:TeX_subtree("  ")
= tn:TeX_deftree("foo", "?")

--]==]




--  ____        __ ____           _ 
-- |  _ \  ___ / _|  _ \  ___  __| |
-- | | | |/ _ \ |_| | | |/ _ \/ _` |
-- | |_| |  __/  _| |_| |  __/ (_| |
-- |____/ \___|_| |____/ \___|\__,_|
--                                  
-- «DefDed»  (to ".DefDed")
-- See: (find-angg "LUA/TreeTeX1.lua" "ProofSty" "Replaces:")

DefDed = Class {
  type = "DefDed",
  fromnameseg = function (nameseg)
      local name     = nameseg.t:gsub("^%^", "")
      local rootnode = nameseg:rootnode()
      local comment  = tf and ("  % "..tf:hyperlink()) or ""
      return DefDed {nameseg=nameseg, name=name, rootnode=rootnode, comment=comment}
    end,
  __index = {
    output_print = function (dd)
        print(dd.name..":")
        print("  "..dd.rootnode:totreenode():torect())
        print()
      end,
    output_proofsty = function (dd)
        local p = proofsty:defded(dd.name, dd.rootnode:totreenode(), dd.comment)
        output(tostring(p))
      end,
    output_ebproof = function (dd)
        local p = ebproof:defded(dd.name, dd.rootnode:totreenode(), dd.comment)
        output(tostring(p))
      end,
    --
    output = function (dd) return dd:output_print() end,
  },
}

-- «DefDed-tests»  (to ".DefDed-tests")
--[==[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
require "TreeSegs1"
= treesegtest [[
%:                       H
%:  -                   ...
%:  A  B  C   E  F      \Pi
%:  =======r  ::::\phi  ...
%:     D       G         I
%:     -------------------
%:             J
%:
%:             ^bars
]]
  nameseg = allsegments[y-1][1]
= nameseg
  dd = DefDed.fromnameseg(nameseg)
= dd.rootnode
= dd.rootnode:totreenode()
  dd:output()

require "TreeTeX1"
output = print
  dd:output_proofsty()

DefDed.__index.output = function (dd) return dd:output_proofsty() end
  dd:output()

DefDed.__index.output = function (dd) return dd:output_ebproof() end
  dd:output()

--]==]




--     _    _ _ ____                                  _       
--    / \  | | / ___|  ___  __ _ _ __ ___   ___ _ __ | |_ ___ 
--   / _ \ | | \___ \ / _ \/ _` | '_ ` _ \ / _ \ '_ \| __/ __|
--  / ___ \| | |___) |  __/ (_| | | | | | |  __/ | | | |_\__ \
-- /_/   \_\_|_|____/ \___|\__, |_| |_| |_|\___|_| |_|\__|___/
--                         |___/                              
--
-- «AllSegments»  (to ".AllSegments")
-- «allsegments»  (to ".allsegments")
AllSegments = Class {
  type      = "AllSegments",
  __tostring = function (allsegs) return allsegs:tostring() end,
  __index = {
    last = function (allsegs, linenow)         -- unused?
        for i=linenow,1,-1 do
          if allsegs[i] and allsegs[i][1] then return allsegs[i][1] end
        end
      end,
    lastlinen = function (allsegs)
        return table.reverse(sortedkeys(allsegments))[1]
      end,
    tostring = function (allsegs)
        local f = function (n) return pformat("%s: %s", n, allsegs[n]) end
        return mapconcat(f, seq(1, allsegs:lastlinen() or 0), "\n")
      end,
  },
}
allsegments = AllSegments {}

-- «allsegments-tests»  (to ".allsegments-tests")
-- See: (to "treesegtest-tests")
--[==[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "TreeSegs1.lua"
= treesegtest [[
%:
%:  a  b 
%:  ----?
%:    c     
%:
%:    ^C
]]
= allsegments
= allsegments[y-1]
= allsegments[y-3]
= allsegments[y-3][1]
= allsegments[y-3][1]:totreenode()

--]==]


--                 _        _                                 _      
--  ___  ___  __ _| |_ ___ | |_ _ __ ___  ___ _ __   ___   __| | ___ 
-- / __|/ _ \/ _` | __/ _ \| __| '__/ _ \/ _ \ '_ \ / _ \ / _` |/ _ \
-- \__ \  __/ (_| | || (_) | |_| | |  __/  __/ | | | (_) | (_| |  __/
-- |___/\___|\__, |\__\___/ \__|_|  \___|\___|_| |_|\___/ \__,_|\___|
--           |___/                                                   
--
-- «segtotreenode» (to ".segtotreenode")
-- See: (find-angg "LUA/TreeTeX1.lua" "TreeNode")
segtotreenode = function (seg)
    local bar = seg:firstsegabove()
    if bar then
      local bart = bar.t
      local barchars = bart:match("^-+") or
                       bart:match("^=+") or
                       bart:match("^:+") or
                       bart:match("^.+")
      if not barchars then Error("Bad bar: "..bart) end
      local barchar = bart:sub(1, 1)
      local label   = bart:sub(1 + #barchars)
      local hyps    = bar:segsabove()
      local T       = map(segtotreenode, hyps)
      T[0] = seg.t
      T.bar = barchar
      T.label = label
      return TreeNode(T)
    end
    return TreeNode {[0]=seg.t}
  end

-- «intersects»  (to ".intersects")
intersects = function (start1, end1, start2, end2)
    if end1 <= start2 then return false end
    if end2 <= start1 then return false end
    return true
  end


--  ____                                  _   
-- / ___|  ___  __ _ _ __ ___   ___ _ __ | |_ 
-- \___ \ / _ \/ _` | '_ ` _ \ / _ \ '_ \| __|
--  ___) |  __/ (_| | | | | | |  __/ | | | |_ 
-- |____/ \___|\__, |_| |_| |_|\___|_| |_|\__|
--             |___/                          
--
-- «Segment» (to ".Segment")
Segment = Class {
  type    = "Segment",
  __tostring = function (seg) return seg:tostring()
    end,
  __index = {
    tostring = function (seg)
        return pformat("[y:%s i:%s l-r:%s-%s t:%s]",
                       seg.y, seg.i, seg.l, seg.r, seg.t)
      end,
    iswithin = function (seg, l, r)
        return intersects(seg.l, seg.r, l, r)
      end,
    intersects = function (seg1, seg2)
        return intersects(seg1.l, seg1.r, seg2.l, seg2.r)
      end,
    segsabove_ = function (seg, dy)
        return allsegments[seg.y - dy] or Segments {}
      end,
    segsabove = function (seg)
        return seg:segsabove_(1):allintersecting(seg)
      end,
    firstsegabove = function (seg) return seg:segsabove()[1] end,
    rootnode = function (seg)
        return seg:segsabove_(2):firstwithin(seg.l, seg.l + 1)
      end,
    totreenode = function (seg) return segtotreenode(seg) end,
    torect = function (seg) return dedtorect(seg:totreenode()) end,
  },
}


--  ____                                  _       
-- / ___|  ___  __ _ _ __ ___   ___ _ __ | |_ ___ 
-- \___ \ / _ \/ _` | '_ ` _ \ / _ \ '_ \| __/ __|
--  ___) |  __/ (_| | | | | | |  __/ | | | |_\__ \
-- |____/ \___|\__, |_| |_| |_|\___|_| |_|\__|___/
--             |___/                              
--
-- «Segments» (to ".Segments")
Segments = Class {
  type    = "Segments",
  __tostring = function (segs) return segs:tostring() end,
  __index = {
    tostring = function (segs)
        local f = function (i) return pformat("%s=%s", i, segs[i]) end
        return mapconcat(f, sortedkeys(segs), "  ")
      end,
    --
    allwithin = function (segs, l, r)
        local segsw = Segments {}
        for _,seg in ipairs(segs) do
          if seg:iswithin(l, r) then table.insert(segsw, seg) end
        end
        return segsw
      end,
    firstwithin = function (segs, l, r)
        return segs:allwithin(l, r)[1]
      end,
    allintersecting = function (segs, seg)
        return segs:allwithin(seg.l, seg.r)
      end,
    firstintersecting = function (segs, seg)
        return segs:allwithin(seg.l, seg.r)[1]
      end,
    --
    outputdefdeds = function (segs)
        for _,seg in ipairs(segs) do
          local name = seg.t:match("^%^(.*)")
          if name then DefDed.fromnameseg(seg):output() end
        end
      end,
  },
}


-- «tosegments» (to ".tosegments")
-- Uses: (find-angg "LUA/DednatParse1.lua" "setsubj")
--       (find-angg "LUA/DednatParse1.lua" "getword")
tosegments = function (str, y, pos_)
    local T = {}
    setsubj(untabify8(str), pos_)
    while getword() do
      table.insert(T, Segment {y=y, i=#T+1, l=startcol, r=endcol, t=word})
    end
    return Segments(T)
  end

-- «treesegtest»  (to ".treesegtest")
treesegtest = function (bigstr)
    y = 1
    for _,li in ipairs(splitlines(bigstr)) do
      allsegments[y] = tosegments(li, y)
      y = y + 1
    end
    return allsegments[y - 1][1]   -- return first segment from last line
  end


-- «high-level-test»  (to ".high-level-test")
--[==[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "TreeSegs1.lua"
root = treesegtest [[
%:
%:  a  b 
%:  ====?
%:    c     
%:
%:    ^r
]]
= otype(allsegments)
= otype(allsegments[y-1])
= otype(allsegments[y-1][1])
= otype(root)

= allsegments
= allsegments[y-1]
= allsegments[y-1][1]
= root
= root:rootnode()
= root:rootnode():totreenode()

= allsegments[3]
= allsegments[3][1]:segsabove()
= allsegments[3][1]:firstsegabove()
= allsegments[6]
= allsegments[6]:outputdefdeds()

--]==]


--  _   _                _ 
-- | | | | ___  __ _  __| |
-- | |_| |/ _ \/ _` |/ _` |
-- |  _  |  __/ (_| | (_| |
-- |_| |_|\___|\__,_|\__,_|
--                         
-- «head»    (to ".head")
-- «head-:»  (to ".head-:")
-- (find-dn6 "heads6.lua" "tree-head")
registerhead = registerhead or function () return nop end
registerhead "%:" {
  name   = "tree",
  action = function ()
      local i,j,treelines = tf:getblock()
      for k=i,j do
        allsegments[k] = tosegments(tf[k], k)
        allsegments[k]:outputdefdeds()
      end
    end,
}

-- «head-tests»  (to ".head-tests")
--[==[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
loaddednat7()
dednat7oldheads()
= heads
= help(heads["%:"].action)

bigstr = [[
%:             -
%:  a  b    d  e
%:  ====?   ::::foo
%:    c       f
%:
%:    ^r      ^s
]]
  tf = TeXFile.from("A", bigstr)
  texlines = tf
= tf:info()
  pu("end")
= tf:info()

require "TreeSegs1"
  tf = TeXFile.from("A", bigstr)
  pu("end")

require "TreeTeX1"
  tf = TeXFile.from("A", bigstr)
  pu("end")

= help(heads["%:"].action)

--]==]





-- Local Variables:
-- coding:  utf-8-unix
-- End: