Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
-- luarects.lua: a preprocessor tho let us use literal rectangles in Lua code. -- This file: -- http://angg.twu.net/dednat6/dednat6/luarects.lua -- http://angg.twu.net/dednat6/dednat6/luarects.lua.html -- (find-angg "dednat6/dednat6/luarects.lua") -- -- This is a hack that I wrote for my "Planar Heyting Algebras for -- Children" paper, that is at: -- http://angg.twu.net/math-b.html#zhas-for-children-2 -- http://angg.twu.net/LATEX/2017planar-has-1.pdf -- http://angg.twu.net/LATEX/2017planar-has-1.tgz (full source) -- -- To see examples of how I use this, download the .tgz above and look -- for the "%R"-blocks in 2017planar-has-1.tex. -- (find-LATEXgrep "grep --color -nH --null -e '%R' 2017planar-has-1.tex") -- http://catb.org/jargon/html/Y/You-are-not-expected-to-understand-this.html -- -- Here's a brief low-level view of how it works. -- When this code in a .tex file is executed by a \pu, -- -- %R A = 1/ a \; B = 2/abcd\; -- %R |b c| \efgh/ C = 1/o o \ -- %R | d | | o o| -- %R \ e/ \o o / -- %R -- %R foo(A, B, C) -- -- The effect is the same as executing this "%L"-block: -- -- %L local aR0 = AsciiRect.new(1, {" a ", "b c", " d ", " e"}) -- %L local aR1 = AsciiRect.new(2, {"abcd", "efgh"}) -- %L local aR2 = AsciiRect.new(1, {"o o ", " o o", "o o "}) -- %L A = aR0 ; B = aR1 ; -- %L C = aR2 -- %L -- %L foo(A, B, C) -- -- «.AsciiRect» (to "AsciiRect") -- «.AsciiRect-tests» (to "AsciiRect-tests") -- «.LuaWithRects» (to "LuaWithRects") -- «.luarecteval» (to "luarecteval") -- «.LuaWithRects-tests» (to "LuaWithRects-tests") -- «.ZHAFromPoints» (to "ZHAFromPoints") -- «.ZHAFromPoints-tests» (to "ZHAFromPoints-tests") trim = function (s) return s and (s:match"^(.-)[ \t]*$") end trim1 = function (s) s = s and trim(s); if s ~= "" then return s end end linestomatrixbody = function (lines) if type(lines) == "string" then lines = splitlines(lines) end local celltotex = function (str) if str == "." then return "" end return unabbrev((str:gsub("!", "\\"))) end local linetotex = function (i) return mapconcat(celltotex, split(lines[i]), " & ") end local tex = linetotex(1).." \\\\ \\hline\n" for i=2,#ar.lines do tex = tex..linetotex(i).." \\\\\n" end return tex end -- _ _ _ ____ _ -- / \ ___ ___(_|_) _ \ ___ ___| |_ -- / _ \ / __|/ __| | | |_) / _ \/ __| __| -- / ___ \\__ \ (__| | | _ < __/ (__| |_ -- /_/ \_\___/\___|_|_|_| \_\___|\___|\__| -- -- «AsciiRect» (to ".AsciiRect") -- Note: this class is for rectangles from which we want to READ their -- cells. Compare with rect.lua, -- (find-dn6 "rect.lua") -- which is for write-only-ish rectangles glueable in several ways, -- and with AsciiPicture: -- (find-dn6 "picture.lua" "AsciiPicture") -- -- Example of use: -- for x,y,c in AsciiRect.new(1, " a |b c | d e| f "):gen() do ... end AsciiRect = Class { type = "AsciiRect", new = function (w, lines, x0) if type(lines) == "string" then lines = splitlines((lines:gsub("|", "\n"))) end return AsciiRect {w=w, lines=lines, x0=x0 or 0} end, __tostring = function (ar) return format("w=%d x0=%d\n%s", ar.w, ar.x0, table.concat(ar.lines, "\n")) end, __index = { linetoy = function (ar, l) return #ar.lines - l end, ytoline = function (ar, y) return #ar.lines - y end, coltopos = function (ar, c) return ar.w*c + 1 end, postocol = function (ar, p) return (p - 1)/ar.w end, coltox = function (ar, c) return c - ar.x0 end, xtocol = function (ar, x) return x + ar.x0 end, -- read_linepos = function (ar, l, p) return (ar.lines[l] or ""):sub(p, p+ar.w-1) end, read_ycol = function (ar, y, c) return ar:read_linepos(ar:ytoline(y), ar:coltopos(c)) end, read_xy = function (ar, x, y) return ar:read_ycol(y, ar:xtocol(x)) end, read_linepos1 = function (ar, l, p) return trim1(ar:read_linepos(l, p)) end, read_ycol1 = function (ar, y, c) return trim1(ar:read_ycol(y, c)) end, read_xy1 = function (ar, x, y) return trim1(ar:read_xy(x, y)) end, hasxy = function (ar, x, y) return trim1(ar:read_xy(x, y)) end, -- setx0 = function (ar) local lastline = ar.lines[#ar.lines] ar.x0 = #(lastline:match"^ *") / ar.w return ar end, -- maxline = function (ar) return #ar.lines[l] end, maxcol = function (ar, l) return (#ar.lines[l] / ar.w)-1 end, minx = function (ar) return -ar.x0 end, maxx = function (ar, y) return ar:maxcol(ar:ytoline(y)) - ar.x0 end, maxy = function (ar) return #ar.lines - 1 end, -- gen = function (ar) return cow(function () for line=1,#ar.lines do for col=0,(#ar.lines[line] / ar.w)-1 do local str = ar:read_linepos(line, ar:coltopos(col)) if not str:match"^ *$" then coy(ar:coltox(col), ar:linetoy(line), str) end end end end) end, -- -- Generate all points and all arrows (the black moves) of the zrect. -- Similar to: (find-dn6 "newrect.lua" "ZHA" "points =") -- and: (find-dn6 "newrect.lua" "ZHA" "arrows =") points = function (ar) -- TODO return cow(function () for y=ar:maxy(),0,-1 do for x=ar:minx(y),ar:maxx(y) do local str = ar:read_xy1(x, y) if str then coy(v(x, y), str) end end end end) end, arrows = function (ar, usewhitemoves) local tar = texarrow_smart(usewhitemoves) return cow(function () for y=ar:maxy(),1,-1 do for x=ar:minx(y),ar:maxx(y) do if ar:hasxy(x, y) then if ar:hasxy(x-1, y-1) then coy(v(x, y), -1, -1, tar.sw) end if ar:hasxy(x, y-1) then coy(v(x, y), 0, -1, tar.s ) end if ar:hasxy(x+1, y-1) then coy(v(x, y), 1, -1, tar.se) end -- coy returns: v(x,y), dx, dy, tex end end end end) end, -- toexpr = function (ar) local f = function (s) return format("%q", s) end local body = mapconcat(f, ar.lines, ", ") return format("AsciiRect.new(%d, {%s})", ar.w, body) end, -- -- Uses the ZHAFromPoints class defined below spec = function (ar) local z = ZHAFromPoints.new() for x,y,str in ar:gen() do z:putxy(x, y) end return z:spec() end, -- See: (find-dn6 "newrect.lua" "MixedPicture-tests") zhatomixedpicture0 = function (ar, opts) return mpnew(opts, ar:spec()) end, zhatomixedpicture = function (ar, opts) local mp = mpnew(opts, ar:spec()) for x,y,str in ar:setx0():gen() do mp:put(v(x, y), str) end return mp end, tomixedpicture = function (ar, opts) return MixedPicture.new(opts, nil, nil, ar) end, -- tomp = function (ar, opts) return MixedPicture.new(opts, nil, nil, ar) end, tozmp = function (ar, opts) -- return MixedPicture.new(opts, ar:spec(), nil, ar) return MixedPicture.new(opts, ZHA.fromspec(ar:spec()), nil, ar:setx0()) end, -- tomatrix = function (ar, def) local tex = linestomatrixbody(ar.lines) tex = "\\begin{matrix}\n"..tex.."\\end{matrix}" tex = "\\def\\"..def.."{\n"..tex.."}" output(tex) end, }, } -- «AsciiRect-tests» (to ".AsciiRect-tests") --[[ • (eepitch-lua51) • (eepitch-kill) • (eepitch-lua51) dofile "luarects.lua" ar = AsciiRect.new(1, " a |b c | d e| f ") = ar for x,y,str in ar:gen() do printf("(%d,%d):%s\n", x, y, str) end = ar:setx0() for x,y,str in ar:gen() do printf("(%d,%d):%s\n", x, y, str) end PPV(ar) • (eepitch-lua51) • (eepitch-kill) • (eepitch-lua51) dofile "luarects.lua" dofile "picture.lua" ar = AsciiRect.new(1, " a |b c | d e| f ") for v,str in ar:points() do printf("%s:%s\n", v:xy(), str) end for v,dx,dy,tex in ar:arrows() do printf("%s,%d,%d,%s\n", v:xy(), dx, dy, tex) end = ar:setx0() for x,y,str in ar:gen() do printf("(%d,%d):%s\n", x, y, str) end PPV(ar) --]] -- _ __ ___ _ _ ____ _ -- | | _ _ __ \ \ / (_) |_| |__ | _ \ ___ ___| |_ ___ -- | | | | | |/ _` \ \ /\ / /| | __| '_ \| |_) / _ \/ __| __/ __| -- | |__| |_| | (_| |\ V V / | | |_| | | | _ < __/ (__| |_\__ \ -- |_____\__,_|\__,_| \_/\_/ |_|\__|_| |_|_| \_\___|\___|\__|___/ -- -- «LuaWithRects» (to ".LuaWithRects") LuaWithRects = Class { type = "LuaWithRects", new = function (lines) if type(lines) == "string" then lines = splitlines(lines) end return LuaWithRects {lines=lines, defs="", ars={}} end, __tostring = function (lwr) return lwr:tostring() end, __index = { body = function (lwr) return table.concat(lwr.lines, "\n") end, tostring = function (lwr) return lwr.defs..lwr:body() end, -- read = function (lwr, nline, pos1, pos2) return lwr.lines[nline]:sub(pos1, pos2-1) end, readasciirect = function (lwr, w, nline1, nline2, pos1, pos2) local ar = AsciiRect.new(w, {}) for y=nline1,nline2 do table.insert(ar.lines, lwr:read(y, pos1, pos2)) end return ar end, -- replace = function (lwr, nline, pos1, pos2, newstr, spc) local line = lwr.lines[nline] local a, b, c = line:sub(1, pos1-1), line:sub(pos1, pos2-1), line:sub(pos2) newstr = newstr .. (spc or " "):rep(pos2-pos1) newstr = newstr:sub(1, (pos2-pos1)) lwr.lines[nline] = a..newstr..c return lwr end, replacerect = function (lwr, nline1, nline2, pos1, pos2, newstr, spc) lwr:replace(nline1, pos1, pos2, newstr, spc) for y=nline1+1,nline2 do lwr:replace(y, pos1, pos2, "", spc) end return lwr end, -- matchasciirect = function (lwr, nline1) local pos1, w, pos2 = lwr.lines[nline1]:match "()(%d)/[^\\]+\\()" if pos1 then local yc = function (y) return lwr.lines[y]:sub(pos1+1, pos1+1) end local nline2 = nline1 + 1 while yc(nline2) == "|" do nline2 = nline2 + 1 end if yc(nline2) == "\\" then return w+0, nline1, nline2, pos1, pos2 else error("Rectangle starting at line "..nline1..", ".. "column "..pos1.." does not close") end end end, extractasciirect = function (lwr, w, nline1, nline2, pos1, pos2, newstr) local ar = lwr:readasciirect(w, nline1, nline2, pos1+2, pos2-1) lwr:replacerect(nline1, nline2, pos1, pos2, newstr) return ar end, ntoname = function (lwr, n) return "aR"..n end, extractasciirects = function (lwr) for nline = 1,#lwr.lines do while true do local w, y1, y2, pos1, pos2 = lwr:matchasciirect(nline) if not w then break end local name = lwr:ntoname(#lwr.ars) local ar = lwr:readasciirect(w, y1, y2, pos1+2, pos2-1) lwr:extractasciirect(w, y1, y2, pos1, pos2, name) table.insert(lwr.ars, {name, ar}) lwr.defs = lwr.defs .. format("local %s = %s\n", name, ar:toexpr()) end end return lwr end, }, } -- «luarecteval» (to ".luarecteval") -- See: (find-dn6 "heads6.lua" "luarect-head") luarectexpand = function (bigstr) return LuaWithRects.new(bigstr):extractasciirects():tostring() end luarecteval = function (bigstr, verbose) local code = luarectexpand(bigstr) if verbose then print(code) end return eval(code) end luarectexpr = function (bigstr) return luarecteval("return\n"..bigstr) end -- «LuaWithRects-tests» (to ".LuaWithRects-tests") --[==[ -- High-level tests: • (eepitch-lua51) • (eepitch-kill) • (eepitch-lua51) dofile "luarects.lua" bigstr = [[ A = 1/ a \; B = 2/abcd\; |b c| \efgh/ C = 1/o o \ | d | | o o| \ e/ \o o / ]] lwr = LuaWithRects.new(bigstr) = lwr = lwr:extractasciirects() = lwr:body() = lwr.defs = mytabletostring(lwr.ars) = lwr.ars[1][2] • (eepitch-lua51) • (eepitch-kill) • (eepitch-lua51) dofile "luarects.lua" bigstr = [[ for x,y,str in 2/ .. \:setx0():gen() do print(x,y,str) end | .. | | .. 12 | |.. 11 02| | .. 01 | \ .. / ]] luarecteval(bigstr) = LuaWithRects.new(bigstr) = LuaWithRects.new(bigstr):extractasciirects() = LuaWithRects.new(bigstr):extractasciirects():tostring() eval(LuaWithRects.new(bigstr):extractasciirects():tostring()) luarecteval(bigstr) -- Low-level tests: • (eepitch-lua51) • (eepitch-kill) • (eepitch-lua51) dofile "luarects.lua" bigstr = [[ 1/ a \ |b c| | d | \ e/ ]] lwr = LuaWithRects.new(bigstr) = lwr = lwr:read (2, 3, 6) = lwr:readasciirect(9, 2, 4, 3, 6) = lwr:readasciirect(9, 1, 4, 3, 6) = lwr:replace (2, 3, 6, "!", ".") = lwr:replacerect (1, 4, 3, 6, "!", ".") lwr = LuaWithRects.new(bigstr) = lwr:matchasciirect(1) = lwr:readasciirect(9, 1, 4, 3, 6) w, y1, y2, pos1, pos2 = lwr:matchasciirect(1) ar = lwr:extractasciirect(w, y1, y2, pos1, pos2, "foo") = ar = lwr --]==] -- ______ _ _ _____ ____ _ _ -- |__ / | | | / \ | ___| __ ___ _ __ ___ | _ \ ___ (_)_ __ | |_ ___ -- / /| |_| | / _ \ | |_ | '__/ _ \| '_ ` _ \| |_) / _ \| | '_ \| __/ __| -- / /_| _ |/ ___ \| _|| | | (_) | | | | | | __/ (_) | | | | | |_\__ \ -- /____|_| |_/_/ \_\_| |_| \___/|_| |_| |_|_| \___/|_|_| |_|\__|___/ -- -- «ZHAFromPoints» (to ".ZHAFromPoints") -- The core was copied to: (find-dn6 "zhas.lua" "spec-tools") -- To be moved to: (find-dn6 "zhaspecs.lua" "spec-tools") ZHAFromPoints = Class { type = "ZHAFromPoints", new = function () return ZHAFromPoints {L={}, R={}, W={}} end, __index = { putxy = function (zfp, x, y) zfp.L[y], zfp.R[y] = minmax(zfp.L[y], x, zfp.R[y]) return zfp end, spec = function (zfp) local s = "1" local L, R, W = zfp.L, zfp.R, {} for y=0,#L do W[y] = toint((R[y] - L[y])/2) + 1 end for y=1,#L do if W[y] == W[y-1] then s = s..((L[y]<L[y-1]) and "L" or "R") else s = s..W[y] end end return s end, }, } -- «ZHAFromPoints-tests» (to ".ZHAFromPoints-tests") --[==[ • (eepitch-lua51) • (eepitch-kill) • (eepitch-lua51) dofile "luarects.lua" luarecteval [[ r = 2/ 32 \ | 22 | | 21 12 | |20 11 02| | 10 01 | \ 00 / ]] = r = r:spec() --> 12321L luarecteval [[ ra, rb, rc = 2/ 48 \, 2/ 48 \, 2/ 48 \ | 47 38 | | 47 38 | | 47 38 | | 46 37 28 | | 46 37 28 | | 46 37 | | 45 36 27 18 | | 45 36 27 18 | | 36 | | 44 35 26 17 08| | 44 35 26 17 08| | 35 26 | | 43 34 25 16 07 | | 43 34 25 16 07 | | 34 25 16 | | 42 33 24 15 06 | | 33 24 15 06 | | 33 24 15 06| | 41 32 23 14 05 | | 23 14 05 | | 23 14 05 | |40 31 22 13 04 | | 22 13 04 | | 22 13 04 | | 30 21 12 03 | | 21 12 03 | | 21 12 03 | | 20 11 02 | |20 11 02 | |20 11 02 | | 10 01 | | 10 01 | | 10 01 | \ 00 / \ 00 / \ 00 / print(ra:spec(), rb:spec(), rc:spec()) --> 12345RRRR4321 123RRR45R4321 123RRR43212R1 ]] --]==] -- Local Variables: -- coding: utf-8-unix -- End: