Warning: this is an htmlized version!
The original is here, and
the conversion rules are here.
-- This file:
--   http://angg.twu.net/LUA/DFS.lua.html
--   http://angg.twu.net/LUA/DFS.lua
--           (find-angg "LUA/DFS.lua")
-- Author: Eduardo Ochs <eduardoochs@gmail.com>
--
-- (defun d  () (interactive) (find-angg "LUA/DFS.lua"))
-- (defun dt () (interactive) (find-angg "LUA/DFSTriangle.lua"))

-- «.test-triangle»	(to "test-triangle")
-- «.test-tname»	(to "test-tname")

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



-- Experimental, overridden by the next definition.
-- See: (find-angg "LUA/lua50init.lua" "SetL")
--      (find-angg "LUA/lua50init.lua" "SetL" " add =")
--

-- This is a class for doing depth-first searches on graphs that may
-- have loops. Remember that in DFSs we "open" a node A and then we
-- visit recursively all the nodes that are accessible from A; we only
-- "close" A when we have "closed" all nodes accessible from A. This
-- class allows setting a node B to "open" without doing the step that
-- visits the nodes that are accessible from B, has a method
-- :recurseopennodes() that... [TODO: finish explaining this]
--
DFS = Class {
  type = "DFS",
  new  = function ()
      return DFS {
        opened = SetL.new(),
        closed = SetL.new(),
	arrowsfrom = SetL.new(),
	named = SetL.new(),     -- used in some applications
      }
    end,
  __index = {
    --
    -- Very low-level DFS methods.
    isopened = function (d, node) return d.opened:has(node) end,
    isclosed = function (d, node) return d.closed:has(node) end,
    open0    = function (d, node) d.opened:add(node) end,
    close0   = function (d, node) d.closed:add(node) end,
    isnew    = function (d, node)
        return (not d:isopened(node))
           and (not d:isclosed(node))
      end,
    --
    -- Names and arrows.
    -- To register a new name or a new arrow, use name0 and arrow0.
    -- Calling d:name0(node, name2) again will not overwrite the old name.
    -- Calling d:arrow0(src, tgt, arrowname2) will add arrowname2 to
    --   the SetL that stores the names of arrows from src to tgt.
    name0  = function (d, node, name) d.named:add(node, name) end,
    arrow0 = function (d, src, tgt, arrowname)
        if not d.arrowsfrom:has(src) then 
	  d.arrowsfrom:add(src, SetL.new())
	end
	d.arrowsfrom:get(src):add(tgt, arrowname)
      end,
    getname = function (d, node) return d.named:val(node) end,
    genallarrows = function (d) return cow(function ()
	  for src,tgts in d.arrowsfrom:gen() do
	    for tgt,arrowname in tgts:gen() do
	      coy(src, tgt, arrowname)
	    end
	  end
	end)
      end,
    --
    -- These methods can be overriden.
    -- The :genarrowsfrom() below is for :nameluatables().
    -- The :ignorearrowsfrom() is an internal method that is used
    -- only by this implementation of :genarrowsfrom().
    ignorearrowsfrom = function (d, src)
        local ot = otype(src)
        return (ot == "Set") or (ot == "SetL") or (ot == "DFS")
      end,
    genarrowsfrom = function (d, src)
        if not (type(src) == "table") then return cow(nop) end
        if d:ignorearrowsfrom(src) then return cow(nop) end
        return cow(function ()
	    for name,tgt in pairs(src) do
              if type(name) == "string" and type(tgt) == "table" then
		coy(tgt, name)
	      end
	      local mt = getmetatable(o)
	      if type(mt) == "table" then
		coy(mt, "__mt")
	      end
	    end
          end)
      end,
    --
    -- Medium-level methods for DFSs.
    -- In standard DFSs users would only call d:openrec(node).
    -- In hackish DFSs users first call d:open0(nodei) on some nodes
    -- to delay recursion on them, then they call d:openrec(nodej) on
    -- some "normal" nodes, then they call d:recurseopennodes() to
    -- recurse on all the delayed nodes.
    close   = function (d, node) d:open0(node); d:close0(node); end,
    recurse = function (d, node)
        for tgt,arrowname in d:genarrowsfrom(node) do
	  d:arrow0(node, tgt, arrowname)
	  d:openrec(tgt)
	end
      end,
    openrec = function (d, node)
        if d:isnew(node) then
	  d:open0(node)
	  d:recurse(node)
	  d:close0(node)
	end
      end,
    recurseopennodes = function (d)
        for node in (d.opened - d.closed):gen() do
	  d:recurse(node)
	  d:close0(node)
	end
      end,
    --
    -- High-level methodes for DFSs with names.
    namenoderec = function (d, node, name)
        d:name0(node, name)
        d:open0(node, name)
	if not d:isclosed(node) then
	  d:recurse(node)
	  d:close0(node)
	end
      end,
    namenodenonrec = function (d, node, name)
        d:name0(node, name)
        d:open0(node, name)
      end,
    nameglobaltables = function (d)
        d:namenodenonrec(_G, "_G")
        for k,v in pairs(_G) do
	  if type(k) == "string" and type(v) == "table" then
	    local node, name = _G[k], k
	    d:namenodenonrec(node, name)
	  end
	end
      end,
    nameothertables = function (d)
      	for src,tgt,arrowname in d:genallarrows() do
	  local tgtname = d:getname(src) .. "." .. arrowname
	  d:name0(tgt, tgtname)
	end
      end,
    nameluatables = function (d)
        d:nameglobaltables()
	d:recurseopennodes()
        d:nameothertables()
	return d
      end,
    --
    namefunctionsin0 = function (d, tbl, prefix)
        if not type(tbl) == "table" then error("Not a table!") end
        for k,v in pairs(tbl) do
          if type(k) == "string" and type(v) == "function" then
            d:name0(v, prefix..k)
          end
        end
      end,
    namefunctionsin = function (d, o)
        local tbl, prefix
        if o == _G or o == ""      then tbl,prefix = _G, ""
        elseif type(o) == "table"  then tbl,prefix = o, d:getname(o).."." 
        elseif type(o) == "string" then tbl,prefix = expr(o), o.."." 
	end
	d:namefunctionsin0(tbl, prefix)
      end,
    nameallfunctions = function (d)
        d:namefunctionsin("")
        for tbl in d.closed:gen() do d:namefunctionsin(tbl) end
        return d
      end,
  },
}



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

d = DFS.new():nameluatables()
for node in d.closed:gen() do
  print(d:getname(node))
end

= d:getname(_G)
= d:getname(Class)
= d:getname(Set.__index)

--]]



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

d = DFS.new():nameluatables():nameallfunctions()
for a,b in d.named:gen() do
  print(a, b)
end
PPV(infomanual_basedir)

--]]



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