Warning: this is an htmlized version!
The original is here, and
the conversion rules are here.
-- This file:
--   http://angg.twu.net/LUA/vtable.lua.html
--   http://angg.twu.net/LUA/vtable.lua
--           (find-angg "LUA/vtable.lua")
-- Author: Eduardo Ochs <eduardoochs@gmail.com>
--
-- (defun e () (interactive) (find-angg "LUA/vtable.lua"))
--
-- The classes HTable and VTable.
-- Version: 2021aug15. Experimental!

-- (find-angg "LUA/lua50init.lua" "Tos")
-- (find-angg "LUA/lua50init.lua" "Tos" "mytabletostring =")
-- (find-angg "LUA/lua50init.lua" "mytostring")
-- (find-angg "LUA/lua50init.lua" "mytostring" "mytostring = tos")

mytostring = function (o) return (Tos{}):o(o) end

hastostring = function (o)
    return getmetatable(o) and getmetatable(o).__tostring
  end

Tos.__index.t0 = function (tos, T, a, sep, b)
    local body = tos:ps(tos:getsortedpairs(T), sep)
    return (a or "{")..body..(b or "}")
  end
Tos.__index.t1 = function (tos, T, a, sep, b)
    if hastostring(T) then return tostring(T) end
    return tos:t0(T, a, sep, b)
  end

Tos.__index.f = function (tos)
    return function (o) return tos:o(o) end
  end

Tos.__index.tv0 = function (tos, T)
    return tos:t0(T, "{ ", ",\n  ", "}")
  end
Tos.__index.tv1 = function (tos, T)
    return tos:t1(T, "{ ", ",\n  ", "}")
  end

Tos_indent = ""

Tos.__index.tv2 = function (tos, T)
    local oldindent = Tos_indent
    Tos_indent = "  " .. Tos_indent
    local result =  tos:t0(T, "{\n"..Tos_indent, ",\n" .. Tos_indent, "}")
    Tos_indent = oldindent
    return result
  end


FooTable = Class {
  type = "FooTable",
  __tostring = function (ft) return "FOO" end,
  __index = {
  },
}


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

-- mytostring0 = function (o) return (Tos{t = Tos.__index.t0}):o(o) end
-- mytostring1 = function (o) return (Tos{t = Tos.__index.t1}):o(o) end
mytostring0 = Tos({t = Tos.__index.t0}):f()
mytostring1 = Tos({t = Tos.__index.t0}):f()

A = FooTable {1, 2, 3}
B = {10, A, 20}
C = {30, B, 40}
= mytostring(A)
= mytostring(B)
= mytostring0(B)
= mytostring1(B)

= Tos({t = Tos.__index.tv0}):f() (A)
= Tos({t = Tos.__index.tv0}):f() (B)
= Tos({t = Tos.__index.tv0}):f() (C)
= Tos({t = Tos.__index.tv1}):f() (C)
= Tos({t = Tos.__index.tv2}):f() (C)

Tos.__index.t = Tos.__index.t0
= mytostring (B)
= mytostring0(B)
= mytostring1(B)

Tos.__index.t = Tos.__index.t1
= mytostring (B)
= mytostring0(B)
= mytostring1(B)

= mytostring(A)
= mytostring(B)
= mytostring(C)





Tos.__index.t0 = function (tos, T)
    return "["..tostring(T).."]"
  end
Tos.__index.t1 = function (tos, T, a, sep, b)
    local body = tos:ps(tos:getsortedpairs(T), sep)
    return (a or "{")..body..(b or "}")
  end

= mytostring(F)

Tos.__index.t = function (tos, T, a, sep, b)
    if hastostring(T) then return tostring(T) end
    return tos:t1(T, a, sep, b)
  end

= mytostring(F)



mynewtostring = function (o) return (Tos{t=Tos.__index.t0}):o(o) end

A = {10, 20, 30}

= mynewtostring(A)
= mynewtostring("foo")



Tos.__index.t0 = Tos.__index.t0 or Tos.__index.t
Tos.__index.t1 = function (tos, T, a, sep, b)
    local mt = getmetatable(T)
    if not mt then return tostring(T) end
    return tos:t0(a, sep, b)
    -- local body = tos:ps(tos:getsortedpairs(T), sep)
    -- return (a or "{")..body..(b or "}")
  end
Tos.__index.t = Tos.__index.t1

htable_tos    = function (o) return (Tos{}):o(o) end
vtable_indent = ""
vtable_tos    = function (o, indent)
    local oi = indent or vtable_indent
    local ni = oi.."  "
    local rv = savevars(function (...)
      vtable_indent = ... end,
      vtable_indent)
    vtable_indent = ni
    local result = (Tos{}):t(o, "{ ", ",\n"..ni, "\n"..oi.."}")
    rv()
    return result
  end

HTable = Class {
  type    = "HTable",
  __tostring = function (ht) return htable_tos(ht) end,
  __index = {
  },
}

VTable = Class {
  type    = "VTable",
  __tostring = function (vt) return vtable_tos(vt) end,
  __index = {
  },
}

ZTable = Class {
  type    = "ZTable",
  __index = {
  },
}

A = HTable {10, 20, 30}
B = VTable {100, 200, 300}
C = ZTable {4, 5, 6}
D = VTable {10, A, B, C}
= A
= B
= C
= D

= B:t1()

a,b,c,d = nil,20,30,nil
PP(a,b,c,d)
rv()



mytostring      = function (o)   return (Tos{}):o(o)                end
mytabletostring = function (o)   return (Tos{}):t(o, "{ ", ",\n  ", "\n}") end


--]]