|
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: