Warning: this is an htmlized version!
The original is here, and
the conversion rules are here.
-- This file:
--   http://anggtwu.net/LUA/ToTeX1.lua.html
--   http://anggtwu.net/LUA/ToTeX1.lua
--          (find-angg "LUA/ToTeX1.lua")
-- Author: Eduardo Ochs <eduardoochs@gmail.com>
--
-- This file implements a way to converts ASTs to TeX code.
-- It defines two classes: Subst, that is very low-level, and ToTeX,
-- that is built on top to Subst; ToTeX overrides some of the methods
-- in Subst a tricky way - using the function addoverrides, that is
-- defined in another file. Each ToTeX object is the core of a
-- "totexer"; each totexer is a way to convert ASTs to tex code.
-- Totexers are defined at the end of this file.
--
-- Introduction
-- ============
-- The class Dang in Show2 has two ways of expanding substrings in
-- <D>ouble <ang>le brackets: in
--
--   Dang.replace "a<<2+3>>b<<:return 4+5>>"
--
-- it treats the "2+3" as an "expression" and the "return 4+5" as
-- "statements". For the details, see:
--
--   (find-angg "LUA/Show2.lua")
--   (find-angg "LUA/Show2.lua" "Dang-tests")
--
-- The class Subst extends this idea with other kinds of
-- substitutions. In
--
--   Subst.replace "_<1>_<2+3>_<:return 4+5>_<aa>_"
--
--   the "1"           in <1>           is expanded with expn,
--   the "2+3"         in <2+3>         is expanded with expexpr,
--   the ":return 2+3" in <:return 2+3> is expanded with expeval, and
--   the "aa"          in <aa>          is expanded with expfield.
--
-- In the class Subst all these methods are defined in a way that is
-- suited for debugging; in the class ToTeX they are replaced by methods
-- that are more complex - some are even recursive - and that are
-- suited for generating tex code.
--
-- Supersedes:
--   (find-angg "LUA/Subst1.lua")
-- Used by:
--   (find-angg "LUA/ELpeg1.lua" "AST")
--
-- (defun tt () (interactive) (find-angg "LUA/ToTeX1.lua"))
-- (defun s1 () (interactive) (find-angg "LUA/Subst1.lua"))

-- «.Subst»			(to "Subst")
-- «.Subst-tests»		(to "Subst-tests")
-- «.ToTeX»			(to "ToTeX")
-- «.ToTeX-tests»		(to "ToTeX-tests")
-- «.totexer»			(to "totexer")
-- «.totexer-tests»		(to "totexer-tests")

require "ELpeg1"         -- (find-angg "LUA/ELpeg1.lua")
require "Show2"          -- (find-angg "LUA/Show2.lua")
require "addoverrides1"  -- (find-angg "LUA/addoverrides1.lua")
L = Code.L               -- (find-angg "LUA/Code.lua" "Code")


--  ____        _         _   
-- / ___| _   _| |__  ___| |_ 
-- \___ \| | | | '_ \/ __| __|
--  ___) | |_| | |_) \__ \ |_ 
-- |____/ \__,_|_.__/|___/\__|
--                            
-- (find-angg "LUA/lua50init.lua" "pformat" "myntos =")
-- «Subst»  (to ".Subst")

Subst = Class {
  type    = "Subst",
  replace = function (str,verbose) return Subst{}:replace(str, verbose) end,
  __tostring = function (su) return su:tostring() end,
  __index = {
    tostring = function (tt) return "(Dummy tostring)" end,
    --
    nil_tos    = function (su)      return "(nil)" end,
    number_tos = function (su, n)   return myntos(n) end,
    table_tos  = function (su, tbl) return mytostring(tbl) end,
    tostring1  = function (su, o)
        if type(o) == "string" then return o                end
        if type(o) == "nil"    then return su:nil_tos()     end
        if type(o) == "number" then return su:number_tos(o) end
        if type(o) == "table"  then return su:table_tos(o)  end
        return tostring(o)
      end,
    --
    fields   = {aa="AAA", bb="BBB"},
    hasfield = function (su, s)    return su.fields[s] end,
    expfield = function (su, s)    return su.fields[s] end,
    expn     = function (su, n)    return format("(expn %d)", n) end,
    expexpr  = function (su, code) return format("(expexpr %s)", code) end,
    expeval  = function (su, code) return format("(expeval %s)", code) end,
    --
    classify = function (su, s)
        if s:match("^[0-9]+$") then return "expn",     s+0      end
        if s:match("^:")       then return "expeval",  s:sub(2) end
        if su:hasfield(s)      then return "expfield", s        end
                                    return "expexpr",  s
      end,
    replace = function (su, str, verbose)
        local f = function (b)
            local s = b:sub(2,-2)
            local method,arg = su:classify(s)
            local out = su:tostring1(su[method](su,arg))
            if verbose then PP(s, method, arg, out) end
            return out
          end
        return (str:gsub("%b<>", f))
      end,
  },
}

-- «Subst-tests»  (to ".Subst-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "ToTeX1.lua"
= Subst.replace("_<2+3>_<:return 4+5>_<aa>_")
= Subst.replace("_<2+3>_<:return 4+5>_<aa>_", "verbose")

s = Subst {}
= s
= s:tostring1("a")
= s:tostring1(nil)
= s:tostring1(true)
= s:tostring1(1.23456)
= s:tostring1({20,30})

--]]






--  _____   _____   __  __
-- |_   _|_|_   _|__\ \/ /
--   | |/ _ \| |/ _ \\  / 
--   | | (_) | |  __//  \ 
--   |_|\___/|_|\___/_/\_\
--                        
-- TODO: explain how I used expexpr and expeval to implement expn
--
-- «ToTeX»  (to ".ToTeX")

ToTeX = Class {
  type = "ToTeX",
  from = function (tbl)
      return addoverrides(Subst(shallowcopy(tbl)), ToTeX.__index)
    end,
  __index = {
    witho    = function (tt,o) tt=shallowcopy(tt); tt.o=o; return tt end,
    tostring = function (tt) return tt:tostring1(tt.o) end,
    expexpr  = function (tt,code) return L("tt,o => "..code)(tt, tt.o) end,
    expeval  = function (tt,code)        L("tt,o => "..code)(tt, tt.o) end,
    --
    -- Overrides for table_tos
    tag  = function (tt) return tt.o[0] end,
    fmt  = function (tt) return tt.fmts[tt:tag()] end,
    table_tos = function (tt)
        if not tt:tag() then return "[No tag]" end
        if not tt:fmt() then return "[No fmt: "..tt:tag().."]" end
        return tt:replace(tt:fmt())
      end,
    --
    -- Overrides for expn
    getn0 = function (tt, n) return          tt.o[n]  end,
    getn  = function (tt, n) return tt:witho(tt.o[n]) end,
    expn  = function (tt, n) return tostring(tt:getn(n)) end,
    --
    show00 = function (tt,...) return tostring(a):show00(...) end,
    show0  = function (tt,...) return tostring(a):show0 (...) end,
    show   = function (tt,...) return tostring(a):show  (...) end,
  },
}

-- «ToTeX-tests»  (to ".ToTeX-tests")
--[==[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "ToTeX1.lua"

fmts["+"]   = "<1> + <2>"
fmts["*"]   = "<1> \\cdot <2>"
fmts["L"]   = "\\leaf "
tt0         = ToTeX.from {fmts=fmts}
o3          =            mkast("*", "a", 2.3456)
o5          = mkast("+", mkast("*", "a", 2.3456), 99)
tt3         = tt0:witho(o3)
tt5         = tt0:witho(o5)

= tt3
= tt5
= tt3:fmt()
= tt3:getn(1)
= tt3:getn(2)
= tt3:getn(2).o

= tt3:replace("_<2+3>_")
= tt3:replace("_<2>_")         -- err
= tt3:replace("_<tt.o[1]>_")
= tt3:replace("_<tt.o[2]>_")
= tt3:replace("_<tt:getn(1)>_")
= tt3:replace("_<tostring(tt:getn(1))>_")
= tt3:replace("_<tostring(tt:getn(2))>_")
= tt3:replace("_<tt:getn(2)>_")

= tt3:replace("_<tt:getn(2)>_")

= tt3:replace("_<tostring(tt)>_")
= tt3:replace("_<tostring(tt:getn(1))>_")
= tt3:replace("_<tostring(tt:getn(2))>_")
= tt3:replace("_<rawtostring(tt)>_")
= tt3:replace("_<:2+3>_")
= tt3:replace("_<:2+3+>_")        -- err
= tt3:replace("_<:print(2+3)>_")

gm  = function (o) return getmetatable(o)         end
gmi = function (o) return getmetatable(o).__index end

PPV(tt3)
PPV(gm(tt3))
PPV(gmi(tt3))

= type(PrintFunction.tostring(print))

= print
setmetatable(print, PrintFunction.fmetatable())  -- broken
setmetatable({}, PrintFunction.fmetatable())     -- broken



= tt3.expeval
= prf(tt3.expeval)               -- broken
= tt3:expeval("print 'hello'")
  tt3:expeval("print(tt,o)")
  tt3:expeval("print(tt)")
= tt3
= prf(gmi(tt3).__tostring)
= prf(gm (tt3).__tostring)
= prf(    tt3 .  tostring)
= PPV(gmi(tt3))
= PPV(gmi(tt3))

PPV(gm(tt3))

= tt0:replace("foo", "verbose")
= tt0:replace("foo <1>", "verbose")

= tt0:witho(2)
= tt0:witho(o3)
= tt0:witho(o3):getn0(1)
= tt0:witho(o3):getn (1)
= tt0:witho(o3):getn0(2)
= tt0:witho(o3):getn(2)
= tt0:witho(2.3456)
= tt0:witho({[0]="L"})
  tt1 = tt0:witho(o3)
= tt1
= tt1:getn0(1)
= tt1:getn0(2)
= tt1:getn(2)
= tt1:expn(1)
= tt1:expn(2)



= tt0:witho(o3)
tt1         = tt0:witho(o5)

= tt1
= tt1:tostring()
= tt1:replace "foo"
= tt1:tostring()
= tt1.o
= tt1.fmts
= tt1:tag()
= tt1:fmt()

keyss = function (T)
    local ks = sorted(keys(T), rawtostring_comp)
    return mapconcat(mytostring, ks, " ")
  end

= keyss {20, 30, a=40}




funs        = VTable {}
funs["sin"] = VTable {}

= totex  (o)
= totex0 (o)
= totex00(o)
= totex00(o).o
= totex00(o):tag()
= totex00(o):fmt()
= totex00(o):getn(1)
= totex00(o):getn(1).o
= totex00(o):getn(2)
= totex00(o):getn(2).o
= totex00(o):getn(2):fmt()
= totex00(o):getn(2):getn(2)
= totex00(o):getn(2):getn(2).o
= totex00()
= totex00():gsub("a<2+3>b")

--]==]



--  _        _                     
-- | |_ ___ | |_ _____  _____ _ __ 
-- | __/ _ \| __/ _ \ \/ / _ \ '__|
-- | || (_) | ||  __/>  <  __/ |   
--  \__\___/ \__\___/_/\_\___|_|   
--                                 
-- «totexer»  (to ".totexer")
-- A "totexer" is a function that converts ASTs to LaTeX code. The
-- "default totexer" consists of five global variables below.
-- TODO: write examples showing how to build several different totexers
-- and how to make them all available in parallel.
--
fmts    = VTable {}
funs    = VTable {}
totex00 = ToTeX.from {fmts=fmts, funs=funs}
totex0  = function (o) return totex00:witho(o) end
totex   = function (o) return totex0(o):tostring() end

-- Add to:   (find-angg "LUA/ELpeg1.lua" "AST")
-- Based on: (find-angg "LUA/Pict3.lua" "Points2-methods")
--           (find-angg "LUA/Show2.lua" "StringShow")
table.addentries(AST.__index,
  { show00 = function (a,...) return totex(a):show00(...) end,
    show0  = function (a,...) return totex(a):show0 (...) end,
    show   = function (a,...) return totex(a):show  (...) end,
  })

-- «totexer-tests»  (to ".totexer-tests")
--[[
* (show2-use "/tmp/")
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "ToTeX1.lua"
fmts["+"]   = "<1> + <2>"
fmts["*"]   = "<1> \\cdot <2>"
o5          = mkast("+", "a", mkast("*", 2.3456, 3.4567))

= otype(totex0(o5))
= otype(totex (o5))
=       totex0(o5)
=       totex0(o5).o
=       totex (o5)

= o5:show00 {em=1}
= o5:show0  {em=1}
= o5:show   {em=1}
* (etv)

--]]






--
-- (defun s1 () (interactive) (find-angg "LUA/Subst1.lua"))
-- (defun s2 () (interactive) (find-angg "LUA/Subst2.lua"))










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