Warning: this is an htmlized version!
The original is here, and
the conversion rules are here.
-- This file:
--   http://angg.twu.net/LUA/Pis1.lua.html
--   http://angg.twu.net/LUA/Pis1.lua
--           (find-angg "LUA/Pis1.lua")
-- Author: Eduardo Ochs <eduardoochs@gmail.com>
--
-- Supersed by: (find-angg "LUA/Prad1.lua")
--
-- Pict2e stack language: a language for generating pict2e code that
-- can push and pop contexts and indentations, and that can also
-- generate code for sgv.el.
-- 
-- Here is a program in Pis, in pseudocode:
--
--   { print("begin picture with bounds (0,0) and (12,8)")
--     print("set thickness to 2pt")
--     { print("{")
--       local indent = outer indent + 2
--       print("set color to red")
--       print("line from A to B")
--       print("}")
--     }
--     { print "line from B to C"
--       print "line from C to D"
--     }
--     print("end picture")
--   }
--
-- All "print"s append lines to the array "out", and some "{}" blocks
-- create a copy of the current context and discard it when the block
-- ends.

-- (defun l () (interactive) (find-angg "LUA/Pis1.lua"))

-- «.PisOutput»		(to "PisOutput")
-- «.PisOutput-tests»	(to "PisOutput-tests")
-- «.PisContext»	(to "PisContext")
-- «.PisContext-tests»	(to "PisContext-tests")
-- «.PisClass»		(to "PisClass")
-- «.PisClass-tests»	(to "PisClass-tests")


spaces = function (n)
    return string.rep(" ", n)
  end
dellastnewline = function (str)
    return (str:gsub("\n$", ""))
  end

-- «PisOutput»  (to ".PisOutput")
--
PisOutput = Class {
  new  = function () return PisOutput({}) end,
  type = "PisOutput",
  __tostring = function (po)
      return dellastnewline(table.concat(po))
    end,
  __index = {
    add0 = function (po, line)
        table.insert(po, line)
        return po
      end,
    endswithopenbrace = function (po, i)
        return po[i]:match("^(.*{)%%?\n$")
      end,
    startswithnspaces = function (po, j, n)
        if po[j]:sub(1, n) == spaces(n) then return po[j]:sub(n+1) end
      end,
    optimize = function (po) return copy(po):optimize0() end,
    optimize0 = function (po)
        for i=#po-1,1,-1 do
          local a =       po:endswithopenbrace(i)
          local b = a and po:startswithnspaces(i+1, #a)
          if b then
            po[i]   = a
            po[i+1] = b
          end
        end
        return po
      end,
  },
}

-- «PisOutput-tests»  (to ".PisOutput-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Pis1.lua"

po = PisOutput({
  "abcd{%\n",
  "     foo\n"
})
= po
= po:optimize()
PP(po)

--]]


-- «PisContext»  (to ".PisContext")
--
PisContext = Class {
  type = "PisContext",
  new  = function (indent, suffix)
      return PisContext {indent=(indent or ""), suffix=(suffix or "%")}
    end,
  __tostring = mytostring,
  __index = {
    copy    = function (pc) return copy(pc) end,
    set     = function (pc, key, val) pc[key] = val; return pc end,
    copyset = function (pc, key, val) return pc:copy():set(key, val) end, 
    copyindent = function (pc, extraindent)
        return pc:copyset("indent", pc.indent .. (extraindent or " "))
      end,
  },
}

-- «PisContext-tests»  (to ".PisContext-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Pis1.lua"

= PisContext.new()
= PisContext.new():copyindent()
= PisContext.new():copyindent("  ")
= PisContext.new():copy()
= PisContext.new():copy():set("foo", "bar")
= PisContext.new():copyset("foo", "bar")

--]]


-- «PisClass»  (to ".PisClass")
--
PisClass = Class {
  type = "PisClass",
  from = function (classtable)
      Class(classtable)
      setmetatable(classtable.__index, { __index = PisClass.__index })
      return classtable
    end,
  __index = {
    add0 = function (pis, out, ctx, line)
        return out:add0(line)
      end,
    add1 = function (pis, out, ctx, line)
        return out:add0(ctx.indent .. line .. ctx.suffix .. "\n")
      end,
    additem = function (pis, out, ctx, item)
        if type(item) == "string"
        then pis:add1(out, ctx, item)
        else item:texprint(out, ctx)
        end
      end,
    adds = function (pis, out, ctx, items)
        for i,item in ipairs(items) do
          pis:additem(out, ctx, item)
        end
      end,
    tolatex = function (pis, out, ctx)
        if type(ctx) == "string" then
          ctx = PisContext.new(ctx)
        end
        out = out or PisOutput.new()
        ctx = ctx or PisContext.new()
        pis:texprint(out, ctx)
        return out
      end,
    --
    tostructsortedkvs = function (pis)
        return Tos({}):getsortedkvs(pis)
      end,
    tostructbe = function (pis, key)
        local class = getmetatable(pis) and getmetatable(pis).type
        local k = key and (mytostring(key).."=") or ""
        if class then return k..class.."({", "})" end
        return k.."{", "}"
      end,
    tostructprint = function (pis, out, ctx, key)
        local newctx = ctx:copyindent()
	local b,e = pis:tostructbe(key)
	local kvs = pis:tostructsortedkvs()
        pis:add1(out, ctx, b)
	for _,kvs in ipairs(kvs) do
	  local k,v = kvs.key, kvs.val
	  if type(v) == "string" then
            local line = format("%s=%s", mytostring(k), mytostring(v))
            pis:add1(out, newctx, line)
	  else
	    v:tostructprint(out, newctx, k)
          end
        end
        pis:add1(out, ctx, e)
      end,
    tostruct = function (pis, out, ctx, key)
        if type(ctx) == "string" then
          ctx = PisContext.new(ctx, "")
        end
        out = out or PisOutput.new()
        ctx = ctx or PisContext.new("", "")
        pis:tostructprint(out, ctx, key)
        return out
      end,
  },
}

PisList = PisClass.from {
  type       = "PisList",
  __tostring = function (pis) return tostring(pis:tolatex()) end,
  __index    = {
    texprint = function (pis, out, ctx)
        pis:adds(out, ctx, pis)
      end,
  },
}

PisSub = PisClass.from {
  type    = "PisSub",
  __tostring = function (pis) return tostring(pis:tolatex()) end,
  __index = {
    texprint = function (pis, out, ctx)
        local newctx = ctx:copyindent()
        pis:add1(out, ctx, (pis.b or "{"))
        pis:adds(out, newctx, pis)
        pis:add1(out, ctx, (pis.e or "}"))
      end,
  },
}


-- «PisClass-tests»  (to ".PisClass-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Pis1.lua"

-- High-level tests:
a = PisList({"aa", "aaa"})
b = PisSub ({"bb", "bbb"})
= a:tolatex()
= b:tolatex()
c = PisList({"cc", a, b, "ccc"})
= c:tolatex()
= c:tolatex():optimize()
= c:tolatex(nil, ":: ")
= PisList({"% Blah: ",         c}):tolatex()
= PisSub ({"% Blah: ",         c}):tolatex()
= PisSub ({"% Blah: ",         c}):tolatex():optimize()
= PisSub ({b="BEGIN", e="END", c}):tolatex()
= PisSub ({b="BEGIN", e="END", c})
= PisSub ({b="BEGIN", e="END", c}):tostruct()

-- Tests for tostruct:
a = PisSub ({b="BEGIN", e="END", "aa", "bb"})
PP(a:tostructsortedkvs())
PP(a:tostructbe())
= a:tostruct()
= a:tostruct(nil, nil, "foo")
= a:tostruct(nil, nil, 123)
b = PisSub ({b="BOGIN", e="OND", a, "cc", "dd"})
= b:tostruct()
= b

-- Low-level tests:
pl = PisLiteral({})
= pl
pl:bar()
PP(PisClass.__index)
PP(PisLiteral)
PP(PisLiteral.__index)
PP(getmetatable(PisLiteral.__index))

o = PisOutput.new()
c = PisContext.new()
s = PisSub({"foo", "bar"})
= o
= o:optimize()
= o

= s:tolatex()
= s:tolatex():optimize()
= s:tolatex(nil, PisContext.new("::")):optimize()

--]]








PisClass.__index.def = function (pis, name)
    local b = "\\def\\"..name.."{{"
    local e = "}}"
    return PisSub({b=b, pis, e=e})
  end
PisClass.__index.precolor = function (pis, color)
    local c = "\\color{"..color.."}"
    return PisList({c, pis})
  end
PisClass.__index.prethickness = function (pis, thickness)
    local c = "\\linethickness{"..thickness.."}"
    return PisList({c, pis})
  end
PisClass.__index.preunitlength = function (pis, unitlength)
    local c = "\\unitlength="..unitlength
    return PisList({c, pis})
  end
PisClass.__index.bhbox = function (pis)
    local b = "\\bhbox{$"
    local e = "$}"
    return PisSub({b=b, pis, e=e})
  end
PisClass.__index.myvcenter = function (pis)
    local b = "\\myvcenter{"
    local e = "}"
    return PisSub({b=b, pis, e=e})
  end


--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "Pis1.lua"
a = PisList({"foo", "bar"})
= a
= a:preunitlength("2pt"):prethickness("3pt")
= a:preunitlength("2pt"):prethickness("3pt"):def("NAME")
= a:preunitlength("2pt"):prethickness("3pt"):def("NAME")
= a:preunitlength("2pt"):prethickness("3pt"):myvcenter():bhbox()
= a

--]]













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