Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
#!/usr/bin/env lua5.1 ---- This is a one-file version of dednat5, generated ---- automatically by build.lua on 2012Jun11 13:55 BRT. See: ---- http://angg.twu.net/dednat5/build.lua.html ---- {sp}(find-dn5 "build.lua") ---- http://angg.twu.net/dednat5/dednat5.lua.html ---- {sp}(find-dn5 "dednat5.lua") ---- Index to the modules: -- «.common.lua» (to "common.lua") -- «.eoo.lua» (to "eoo.lua") -- «.errors.lua» (to "errors.lua") -- «.prefixes.lua» (to "prefixes.lua") -- «.parse.lua» (to "parse.lua") -- «.preamble.lua» (to "preamble.lua") -- «.process.lua» (to "process.lua") -- «.treetex.lua» (to "treetex.lua") -- «.treesegs.lua» (to "treesegs.lua") -- «.treehead.lua» (to "treehead.lua") -- «.diagstacks.lua» (to "diagstacks.lua") -- «.diagtex.lua» (to "diagtex.lua") -- «.diagforth.lua» (to "diagforth.lua") -- «.diagmiddle.lua» (to "diagmiddle.lua") -- «.begriff.lua» (to "begriff.lua") -- «.repl.lua» (to "repl.lua") -- «.options.lua» (to "options.lua") ---- From: (find-dn5 "common") ---- «common.lua» (to ".common.lua") ---- This block is from: (find-dn5 "common.lua") -- common.lua: functions from my LUA_INIT file. -- This file: -- http://angg.twu.net/dednat5/common.lua.html -- http://angg.twu.net/dednat5/common.lua -- (find-dn5 "common.lua") -- Author: Eduardo Ochs <eduardoochs@gmail.com> -- Version: 2011dec03 -- License: GPL3 -- (find-blogme4 "common.lua") -- (find-angg "LUA/lua50init.lua" "PP") -- «.readfile» (to "readfile") -- «.writefile» (to "writefile") -- «.split» (to "split") -- «.untabify» (to "untabify") -- «.printf» (to "printf") -- «.PP» (to "PP") -- «.pack-and-unpack» (to "pack-and-unpack") -- «.guill» (to "guill") -- «.gformat» (to "gformat") -- «.ee_template» (to "ee_template") -- «.errors» (to "errors") -- «readfile» (to ".readfile") -- «writefile» (to ".writefile") -- (find-angg "LUA/lua50init.lua" "readfile") -- (find-angg "LUA/lua50init.lua" "writefile") readfile = function (fname) local f = assert(io.open(fname, "r")) local bigstr = f:read("*a") f:close() return bigstr end writefile = function (fname, bigstr) local f = assert(io.open(fname, "w+")) f:write(bigstr) f:close() end -- (find-angg "LUA/lua50init.lua" "mapconcat") map = function (f, arr, n) local brr = {} for i=1,(n or #arr) do table.insert(brr, f(arr[i])) end return brr end mapconcat = function (f, tbl, sep) return table.concat(map(f, tbl), sep) end nop = function () end id = function (...) return ... end -- (find-luamanualw3m "#pdf-table.sort") sorted = function (tbl, lt) table.sort(tbl, lt); return tbl end -- «split» (to ".split") -- (find-angg "LUA/lua50init.lua" "split") split = function (str, pat) local arr = {} string.gsub(str, pat or "([^%s]+)", function (word) table.insert(arr, word) end) return arr end -- «untabify» (to ".untabify") -- (find-angg "LUA/lua50init.lua" "untabify") -- Note: to untabify strings in encodings where chars can be more than -- 1-byte long, change the "#" below... (I never had to do that, -- though). untabify_table = {" ", " ", " ", " ", " ", " ", " ", " "} --{"--------", "-------", "------", "-----", "----", "---", "--", "-"} untabify_strtab = function (strbeforetab) return strbeforetab .. untabify_table[math.mod(#strbeforetab, 8) + 1] end untabify = function (str) return (gsub(str, "([^\t\r\n]*)\t", untabify_strtab)) end -- (find-angg "LUA/lua50init.lua" "mytostring") tos_compare_pairs = function (pair1, pair2) local key1, key2 = pair1.key, pair2.key local type1, type2 = type(key1), type(key2) if type1 == type2 then if type1 == "number" then return key1 < key2 end if type1 == "string" then return key1 < key2 end return tostring(key1) < tostring(key2) -- fast else return type1 < type2 -- numbers before strings before tables, etc end end tos_sorted_pairs = function (T) local Tpairs = {} for key,val in pairs(T) do table.insert(Tpairs, {key=key, val=val}) end return sorted(Tpairs, tos_compare_pairs) end tos_table_orig = function (T, sep) return "{"..mapconcat(tos_pair, tos_sorted_pairs(T), sep or ", ").."}" end tos_table = tos_table_orig tos = function (o) local t = type(o) if t=="number" then return tostring(o) end if t=="string" then return string.format("%q", o) end if t=="table" then return tos_table(o) end return "<"..tostring(o)..">" end tos_key = tos -- change this to print string keys differently tos_pair = function (pair) return tos_key(pair.key).."="..tos(pair.val) end mysort = tos_sorted_pairs -- compatibility mytostring = tos -- compatibility mytostring_arg = function (T, sep) return mapconcat(tos, T, sep or " ", T.n) end -- Tools for building extensions tos_good_string_key = function (key) return type(key) == "string" and key:match("^[A-Za-z_][A-Za-z_0-9]*$") end tos_has_tostring = function (o) return getmetatable(T) and getmetatable(T).__tostring end tos_has_eootype = function (o) return type(o) == "table" and getmetatable(o) and getmetatable(o).type end -- «printf» (to ".printf") -- (find-angg "LUA/lua50init.lua" "printf") printf = function (...) io.write(string.format(...)) end -- «PP» (to ".PP") -- (find-angg "LUA/lua50init.lua" "PP") -- Examples: -- PP(nil, true, false, 22, "22", "a\nb", print, nil) --> <nil> <true> <false> 22 "22" "a\ -- b" <function: 0x806b388> <nil> -- -- PP({44, 55, nil, 77, [{a=11}]={[22]="b"}, [{}]={}, [{}]={}}) --> {1=44, 2=55, 4=77, {"a"=11}={22="b"}, {}={}, {}={}} -- PP = function (...) local arg = arg or pack(...) -- for Lua 5.2 for i=1,arg.n do printf(" %s", mytostring(arg[i])) end printf("\n") return myunpack(arg) -- todo: change to "..." (a 5.1-ism) end -- «pack-and-unpack» (to ".pack-and-unpack") -- (find-angg "LUA/lua50init.lua" "pack-and-unpack") -- (find-luamanualw3m "#pdf-unpack") pack = table.pack or function (...) return arg end unpack = unpack or table.unpack myunpack = function (arg) return unpack(arg, 1, arg.n) end -- «guill» (to ".guill") -- «gformat» (to ".gformat") -- «ee_template» (to ".ee_template") -- (find-angg "LUA/lua50init.lua" "gformat") -- (find-angg "LUA/lua50init.lua" "ee_template") -- These are mostly for build.lua... guill = function (str) return (str:gsub("<<", "\171"):gsub(">>", "\187")) end gformat = function (fmt, pat) return function (str) return (str:gsub((pat or "^.*$"), fmt)) end end ee_template = function (pairs, templatestr) return (string.gsub(templatestr, "{([^{}]+)}", pairs)) end -- «errors» (to ".errors") -- (find-dn5 "errors.lua") ---- From: (find-dn5 "eoo") ---- «eoo.lua» (to ".eoo.lua") ---- This block is from: (find-dn5 "eoo.lua") -- eoo.lua: Edrx'x simple OO scheme. -- This file: -- http://angg.twu.net/dednat5/eoo.lua.html -- http://angg.twu.net/dednat5/eoo.lua -- (find-dn5 "eoo.lua") -- (find-tkdiff "~/blogme4/eoo.lua" "~/dednat5/eoo.lua") -- Author: Eduardo Ochs <eduardoochs@gmail.com> -- Version: 2011nov21 -- License: GPL3 -- -- A very simple object system. -- The metatable of each object points to its class, -- and classes are callable, and act as creators. -- New classes can be created with, e.g.: -- Circle = Class { type = "Circle", __index = {...} } -- then: -- Circle {size = 1} -- sets the metatable of the table {size = 1} to Circle, -- and returns the table {size = 1} (with its mt modified). -- -- Originally from: (find-angg "LUA/canvas2.lua" "Class") -- A tool: (find-angg ".emacs.templates" "class") -- «.test-eoo» (to "test-eoo") -- «.box-diagram» (to "box-diagram") Class = { type = "Class", __call = function (class, o) return setmetatable(o, class) end, } setmetatable(Class, Class) otype = function (o) -- works like type, except on my "objects" local mt = getmetatable(o) return mt and mt.type or type(o) end -- Code for inheritance (2011nov21), untested... -- The examples of usage for this are coming soon! over = function (uppertable) return function (lowertable) setmetatable(uppertable, {__index=lowertable}) return uppertable end end ClassOver = function (upperclassmt) return function (lowerclass) setmetatable(upperclassmt.__index, {__index=lowerclass.__index}) return Class(upperclassmt) end end ---- From: (find-dn5 "errors") ---- «errors.lua» (to ".errors.lua") ---- This block is from: (find-dn5 "errors.lua") -- errors.lua: -- This file: -- http://angg.twu.net/dednat5/errors.lua.html -- http://angg.twu.net/dednat5/errors.lua -- (find-dn5 "errors.lua") -- Author: Eduardo Ochs <eduardoochs@gmail.com> -- Version: 2011feb27? -- License: GPL3 -- -- require "eoo" -- (find-dn5 "eoo.lua") error_ = function (str) print((fname or "<nil>")..":"..(nline or "<nil>")..":"..(str or "?")) printf(" (find-fline %q %d)", (fname or "<nil>"), (nline or 0)) error() end Error = function (str) -- generic error error_(" "..(str or "?")) end FError = function (str) -- error in a Forth word error_((word or "<nil>")..": "..(str or "?")) end FGetword = function (str) return getword() or FError(str or "missing argument") end FGetword = function () return getword() or FError("missing argument") end FGetword1 = function () return getword() or FError("missing 1st argument") end FGetword2 = function () return getword() or FError("missing 2nd argument") end ---- From: (find-dn5 "prefixes") ---- «prefixes.lua» (to ".prefixes.lua") ---- This block is from: (find-dn5 "prefixes.lua") -- prefixes.lua: handle expansions, abbrev tables and tables of prefixes. -- This file: -- http://angg.twu.net/dednat5/prefixes.lua.html -- http://angg.twu.net/dednat5/prefixes.lua -- (find-dn5 "prefixes.lua") -- Author: Eduardo Ochs <eduardoochs@gmail.com> -- Version: 2011apr10 -- License: GPL3 -- -- «.unabbrev» (to "unabbrev") -- (find-dn4 "dednat5.lua" "prefixes-and-ptables") -- (find-dn4 "dednat5.lua" "heads") -- (find-dn4 "dednat5.lua" "abbrevs") -- We have two standard "prefix tables" in dednat5: abbrevs and heads. -- The way to search for a "longest prefix" is the same in both... -- Here is an example, to explain both the data structure and the -- basic algorithm. If we only have two abbreviations, "a"->"<a>" and -- "abc"->"<abc>", then the table "abbrevs" will be like this: -- abbrevs = { ["a"]="<a>", -- ["ab"]=0, -- ["abc"]="<abc>" } -- and then: -- unabbrev("ababc") -- returns: -- "<a>b<abc>" -- To calculate the "unabbreviated form" of the string "ababc" we -- start at the left, and try to find the longest substring of -- "ababc", starting at 1, which has an expansion... "a" has an -- expansion, and "ab" has not; but the table abbrevs has an entry -- ["ab"]=0, that means "keep trying" - because even though "ab" does -- not have an expansion, some strings starting with "ab" may have. abbrevs = {} longestprefix = function (str, j, pt) j = j or 1 -- starting position pt = pt or abbrevs -- prefix table local longest = nil -- longest prefix having an expansion for k=j,#str do local candidate = str:sub(j, k) local e = pt[candidate] if e == nil then break end -- if e==nil we can stop if e ~= 0 then -- if e==0 we keep trying longest = candidate -- if e~=nil and e~=0 we record the match end end return longest, pt[longest] -- return the best match and its "expansion" end findfirstexpansion = function (str, i, pt) for j=i,#str do local longest, expansion = longestprefix(str, j, pt) if longest then return j, longest, expansion end end end -- «unabbrev» (to ".unabbrev") unabbrev = function (str, i, pt) i = i or 1 local j, longest, expansion = findfirstexpansion(str, i, pt) if j then return str:sub(i, j-1) .. -- the unexpandable part, then expansion .. -- the expansion, then... unabbrev(str, j+#longest, pt) -- recurse! end return str:sub(i) -- or all the rest of the string. end -- (find-dn4 "dednat4.lua" "abbrevs") addabbrev = function (abbrev, expansion, pt) pt = pt or abbrevs for i=1,#abbrev-1 do local prefix = abbrev:sub(1, i) pt[prefix] = pt[prefix] or 0 end pt[abbrev] = expansion end addabbrevs = function (...) local arg = {...} for i=1,#arg,2 do addabbrev(arg[i], arg[i+1]) end end delabbrev = function (abbrev, pt) (pt or abbrevs)[abbrev] = 0 -- yep! end ---- From: (find-dn5 "parse") ---- «parse.lua» (to ".parse.lua") ---- This block is from: (find-dn5 "parse.lua") -- parse.lua: functions to parse words keeping track of the column. -- These functions are used to parse tree segments (in "%:" lines) -- and 2D grids (in both "%D 2Dx" and "%D 2D" lines). -- This file: -- http://angg.twu.net/dednat5/parse.lua.html -- http://angg.twu.net/dednat5/parse.lua -- (find-dn5 "parse.lua") -- Author: Eduardo Ochs <eduardoochs@gmail.com> -- Version: 2011apr07 -- License: GPL3 -- setsubj = function (subj_, pos_) subj = subj_ pos = pos_ or 3 startcol, endcol = 1, pos end getword = function () local spaces, word_, newpos = subj:match("( *)([^ ]+)()", pos) if spaces then startcol = endcol + #spaces endcol = endcol + #spaces + #word_ -- change for UTF-8 word = word_ pos = newpos return word end end getwordasluaexpr = function () local expr = getword() local code = "return "..expr return assert(loadstring(code))() end getrestofline = function () local spaces, word_, newpos = subj:match("( *)(.*)()", pos) if spaces then startcol = endcol + #spaces endcol = endcol + #spaces + #word_ -- change for UTF-8 word = word_ pos = newpos return word end end ---- From: (find-dn5 "preamble") ---- «preamble.lua» (to ".preamble.lua") ---- This block is from: (find-dn5 "preamble.lua") -- preamble.lua: functions about the TeX definitions in the .dnt file. -- This file: -- http://angg.twu.net/dednat5/preamble.lua.html -- http://angg.twu.net/dednat5/preamble.lua -- (find-dn5 "preamble.lua") -- Author: Eduardo Ochs <eduardoochs@gmail.com> -- Version: 2011may12 -- License: GPL3 -- -- Adapted from: -- (find-dn4ex "edrx08.sty") -- (find-dn4ex "edrxdnt.tex" "defded") -- (find-dn4ex "edrxdnt.tex" "defdiag") -- See also: -- (find-dn4ex "edrxmain.tex") -- (find-dn4ex "edrxmain41.tex") -- (find-dn4ex "edrxmain41a.tex") preamble = [==[ % These definitions - the "preable" of a .dnt file - are from: % http://angg.twu.net/dednat5/preamble.lua.html % http://angg.twu.net/dednat5/preamble.lua % (find-dn5 "preamble.lua") % \usepackage{proof} % For derivation trees ("%:" lines) \input diagxy % For 2D diagrams ("%D" lines) \xyoption{curve} % For the ".curve=" feature in 2D diagrams % \def\defded#1#2{\expandafter\def\csname ded-#1\endcsname{#2}} \def\ifdedundefined#1{\expandafter\ifx\csname ded-#1\endcsname\relax} \def\ded#1{\ifdedundefined{#1} \errmessage{UNDEFINED DEDUCTION: #1} \else \csname ded-#1\endcsname \fi } \def\defdiag#1#2{\expandafter\def\csname diag-#1\endcsname{\bfig#2\efig}} \def\defdiagprep#1#2#3{\expandafter\def\csname diag-#1\endcsname{{#2\bfig#3\efig}}} \def\ifdiagundefined#1{\expandafter\ifx\csname diag-#1\endcsname\relax} \def\diag#1{\ifdiagundefined{#1} \errmessage{UNDEFINED DIAGRAM: #1} \else \csname diag-#1\endcsname \fi } % End of the preamble. ]==] ---- From: (find-dn5 "process") ---- «process.lua» (to ".process.lua") ---- This block is from: (find-dn5 "process.lua") -- process.lua: process files, lines, and heads. -- all the lines in a file (by heads) -- This file: -- http://angg.twu.net/dednat5/process.lua.html -- http://angg.twu.net/dednat5/process.lua -- (find-dn5 "process.lua") -- Author: Eduardo Ochs <eduardoochs@gmail.com> -- Version: 2011apr09 -- License: GPL3 -- untabify (find-angg "LUA/lua50init.lua" "untabify") -- parse_pattern (find-blogme4 "eval.lua" "parse_pattern") -- ProcessLine (find-dn4 "dednat4.lua" "abbrev-head") -- ProcessBlock (find-dn4 "dednat4.lua" "lua-head") -- ProcessFile (find-dn4 "dednat4.lua" "process") -- ProcessWord uses subj and pos; used by trees and dforth -- Head -- heads (find-dn4 "dednat4.lua" "heads") -- registerhead -- AbbrevHead -- LuaHead -- «.main-loop» (to "main-loop") -- «.abbrev-head» (to "abbrev-head") -- «.lua-head» (to "lua-head") -- require "prefixes" -- (find-dn5 "prefixes.lua") -- (find-dn4 "dednat4.lua" "heads") heads = {} registerhead = function (headstr) return function (head) head.headstr = headstr addabbrev(headstr, head, heads) end end registerhead "" {} headstrfor_ = function (lstr) return longestprefix(lstr, 1, heads) or "" end headfor_ = function (lstr) return heads[headstrfor_(lstr)] end headstrfor = function (lstr) return lstr and headstrfor_(lstr) end headfor = function (lstr) return lstr and headfor_(lstr) end -- fname = "<none>" -- used in error messages flines = {} -- like "subj", but is an array of strings nline = 1 -- like "pos" -- linehead = function (n) return headfor (flines[n or nline]) end lineheadstr = function (n) return headstrfor(flines[n or nline]) end nextheadstr = function () return lineheadstr(nline + 1) end -- set_nline = function (nline_) nline = nline_; linestr = flines[nline] end set_flines = function (flines_, fname_) fname = fname_ or "<none>" flines = flines_ allsegments = {} -- (find-dn5 "segments.lua") set_nline(1) end use_bigstr = function (bigstr, fname) set_flines(splitlines(bigstr), fname) end use_fname = function (fname) use_bigstr(readfile(fname), fname) end -- «main-loop» (to ".main-loop") processlines = function () while nline <= #flines do local head = linehead() if head.action then head.action() end set_nline(nline + 1) end end process_bigstr = function (bstr, fn) use_bigstr(bstr, fn) processlines() end process_fname = function (fname) use_fname(fname) processlines() end -- Two trivial heads: -- «abbrev-head» (to ".abbrev-head") -- (find-dn4 "dednat4.lua" "abbrev-head") -- (find-dn5 "prefixes.lua") registerhead "%:*" { action = function () local abbrev, expansion = linestr:match("^%%:*(.-)*(.-)*") assert(abbrev) addabbrev(abbrev, expansion) end, } -- «lua-head» (to ".lua-head") -- (find-dn4 "dednat4.lua" "lua-head") lualinebody = function () return untabify(linestr):match("^%%L ?(.*)") end registerhead "%L" { action = function () local chunkname = fname..":%L:"..nline local lualines = { lualinebody() } -- get body of first line while nextheadstr() == "%L" do -- when the next line is also %L set_nline(nline + 1) -- advance pointer table.insert(lualines, lualinebody()) -- add its body to the chunk end local luacode = table.concat(lualines, "\n") assert(loadstring(luacode, chunkname))() end, } ---- From: (find-dn5 "treetex") ---- «treetex.lua» (to ".treetex.lua") ---- This block is from: (find-dn5 "treetex.lua") -- treetex.lua: derivation trees and functions to convert them to TeX. -- This file: -- http://angg.twu.net/dednat5/treetex.lua.html -- http://angg.twu.net/dednat5/treetex.lua -- (find-dn5 "treetex.lua") -- Author: Eduardo Ochs <eduardoochs@gmail.com> -- Version: 2011apr04 -- License: GPL3 -- -- intersecting (find-dn4 "dednat4.lua" "tree-lib") -- tatsuta (find-dn4 "dednat4.lua" "tree-out") -- paultaylor -- require "eoo" -- (find-dn5 "eoo.lua") TreeNode = Class { type = "TreeNode", __index = { hasbar = function (tn) return tn.bar ~= nil end, barchar = function (tn) return tn.bar end, TeX_root = function (tn) return tn[0] end, TeX_label = function (tn) return tn.label end, nhyps = function (tn) return #tn end, hypslist = function (tn) return tn end, }, } TeX_subtree_tatsuta = function (tn, i_) if not tn:hasbar() then return i_.."\\mathstrut "..tn:TeX_root() else local r_ = tn:TeX_root() local b_ = tn:barchar() local l_ = tn:TeX_label() local h_ = tn:hypslist() local r = "\\mathstrut "..r_ local b = ({["-"]="", ["="]="=", [":"]="*"})[b_] local l = (l_ and "[{"..l_.."}]") or "" local i = i_.." " local f = function (tn) return TeX_subtree_tatsuta(tn, i) end local h = mapconcat(f, h_, " &\n") return i_.."\\infer"..b..l.."{ "..r.." }{\n"..h.." }" end end TeX_deftree_tatsuta = function (tn, name, link) return "\\defded{"..name.."}{"..(link or "").."\n".. TeX_subtree_tatsuta(tn, " ").." }" end TreeNode.__index.TeX_subtree = TeX_subtree_tatsuta TreeNode.__index.TeX_deftree = TeX_deftree_tatsuta ---- From: (find-dn5 "treesegs") ---- «treesegs.lua» (to ".treesegs.lua") ---- This block is from: (find-dn5 "treesegs.lua") -- treesegs.lua: -- This file: -- http://angg.twu.net/dednat5/treesegs.lua.html -- http://angg.twu.net/dednat5/treesegs.lua -- (find-dn5 "treesegs.lua") -- Author: Eduardo Ochs <eduardoochs@gmail.com> -- Version: 2011mar28 -- License: GPL3 -- -- «.allsegments-test» (to "allsegments-test") -- require "eoo" -- (find-dn5 "eoo.lua") -- require "parse" -- (find-dn5 "parse.lua") intersects = function (start1, end1, start2, end2) if end1 <= start2 then return false end if end2 <= start1 then return false end return true end allsegments = {} -- allsegment[5] is a Segments object containing the list of all -- Segment objects at line 5 of the current file. Segment = Class { type = "Segment", __index = { iswithin = function (seg, l, r) return intersects(seg.l, seg.r, l, r) end, intersects = function (seg1, seg2) return intersects(seg1.l, seg1.r, seg2.l, seg2.r) end, segsabove_ = function (seg, dy) return allsegments[seg.y - dy] or Segments {} end, segsabove = function (seg) return seg:segsabove_(1):allintersecting(seg) end, firstsegabove = function (seg) return seg:segsabove()[1] end, rootnode = function (seg) return seg:segsabove_(2):firstwithin(seg.l, seg.l + 1) end, }, } Segments = Class { type = "Segments", __index = { allwithin = function (segs, l, r) local T = {} for _,seg in ipairs(segs) do if seg:iswithin(l, r) then table.insert(T, seg) end end return T end, firstwithin = function (segs, l, r) return segs:allwithin(l, r)[1] end, allintersecting = function (segs, seg) return segs:allwithin(seg.l, seg.r) end, firstintersecting = function (segs, seg) return segs:allwithin(seg.l, seg.r)[1] end, }, } -- (find-dn5 "parse.lua") tosegments = function (str, line) local T = {} setsubj(untabify(str)) while getword() do table.insert(T, Segment {l=startcol, r=endcol, t=word, y=line, i=#T+1}) end return Segments(T) end ---- From: (find-dn5 "treehead") ---- «treehead.lua» (to ".treehead.lua") ---- This block is from: (find-dn5 "treehead.lua") -- treehead.lua: -- This file: -- http://angg.twu.net/dednat5/treehead.lua.html -- http://angg.twu.net/dednat5/treehead.lua -- (find-dn5 "treehead.lua") -- Author: Eduardo Ochs <eduardoochs@gmail.com> -- Version: 2011feb27 -- License: GPL3 -- -- require "segments" -- (find-dn5 "segments.lua") -- require "trees" -- (find-dn5 "trees.lua") -- require "process" -- (find-dn5 "process.lua") output = output or print -- (find-dn5 "segments.lua") -- This should be enough for the moment. segtotreenode = function (seg) local bar = seg:firstsegabove() if bar then local bart = bar.t local barchars = bart:match("-+") or bart:match("=+") or bart:match(":+") if not barchars then Error("Bad bar: "..bart) end local barchar = bart:sub(1, 1) local label = bart:sub(1 + #barchars) local hyps = bar:segsabove() local T = map(segtotreenode, hyps) T[0] = seg.t T.bar = barchar T.label = label return TreeNode(T) end return TreeNode {[0]=seg.t} end -- Add new methods to an existing class Segment.__index.totreenode = segtotreenode -- (find-dn5 "trees.lua") -- (find-dn5 "segments.lua") registerhead "%:" { action = function () allsegments[nline] = tosegments(linestr, nline) for _,seg in ipairs(allsegments[nline]) do local name = seg.t:match("^%^(.*)") if name then output(seg:rootnode():totreenode():TeX_deftree(name)) end end end, } ---- From: (find-dn5 "diagstacks") ---- «diagstacks.lua» (to ".diagstacks.lua") ---- This block is from: (find-dn5 "diagstacks.lua") -- diagstacks.lua: the stack, the metastack, and the arrays "nodes" and "arrows". -- This file: -- http://angg.twu.net/dednat5/diagstacks.lua.html -- http://angg.twu.net/dednat5/diagstacks.lua -- (find-dn5 "diagstacks.lua") -- Author: Eduardo Ochs <eduardoochs@gmail.com> -- Version: 2011apr10 -- License: GPL3 -- -- «.Stack» (to "Stack") -- «.MetaStack» (to "MetaStack") -- «.nodes» (to "nodes") -- «.arrows» (to "arrows") -- require "eoo" -- (find-dn5 "eoo.lua") -- «Stack» (to ".Stack") push = function (stack, o) table.insert(stack, o) end pop = function (stack, msg) assert(#stack > 0, msg or "Empty stack") return table.remove(stack) end popuntil = function (stack, depth) while #stack > depth do pop(stack) end end pick = function (stack, offset) return stack[#stack - offset] end pock = function (stack, offset, o) stack[#stack - offset] = o end Stack = Class { type = "Stack", __index = { push = push, pop = pop, popuntil = popuntil, clear = function (s) s:popuntil(0) end, pick = pick, pock = pock, }, } -- Current fragilities: pushing a nil is a no-op; -- and pick and pock do not check depth. -- Beware: in dednat4 we stored the stack elements in the "wrong" -- order just to make pick and pock trivial to implement (tos was -- ds[1] in dednat4)... Now the conventions are: -- ds:pick(0) returns the tos ("top of stack") -- ds:pick(1) returns the element below tos -- ds:pock(0, "a") replaces the tos by "a" -- ds:pock(1, "b") replaces the element below tos by "b" ds = Stack {} -- (find-miniforthgempage 3 "DS={ 5 }") -- «MetaStack» (to ".MetaStack") -- (find-dn5 "diagforth.lua" "metastack") MetaStack = ClassOver(Stack) { type = "MetaStack", __index = { ppush = function (ms) push(ms, #(ms.stack)) end, ppop = function (ms) popuntil(ms.stack, pop(ms, "Empty metastack")) end, metapick = function (ms, offset) return ms.stack[ms:pick(0) + offset] end, }, } depths = MetaStack {stack=ds} -- «nodes» (to ".nodes") nodes = {} -- has numeric and string indices storenode = function (node) table.insert(nodes, node) node.noden = #nodes -- nodes[node.noden] == node if node.tag then -- was: "and not nodes[node.tag]"... nodes[node.tag] = node -- nodes[node.tag] == node end return node end -- «arrows» (to ".arrows") arrows = {} -- has numeric and string indices storearrow = function (arrow) table.insert(arrows, arrow) arrow.arrown = #arrows -- arrows[arrow.arrown] == arrow if arrow.tag then -- (unused at the moment) arrows[arrow.tag] = arrow -- arrows[arrow.tag] == arrow end return arrow end ---- From: (find-dn5 "diagtex") ---- «diagtex.lua» (to ".diagtex.lua") ---- This block is from: (find-dn5 "diagtex.lua") -- diagtex.lua: -- This file: -- http://angg.twu.net/dednat5/diagtex.lua.html -- http://angg.twu.net/dednat5/diagtex.lua -- (find-dn5 "diagtex.lua") -- Author: Eduardo Ochs <eduardoochs@gmail.com> -- Version: 2011apr10 -- License: GPL3 -- «.coords» (to "coords") -- «.arrow_to_TeX» (to "arrow_to_TeX") -- «.DxyArrow» (to "DxyArrow") -- «.DxyPlace» (to "DxyPlace") -- «.DxyLiteral» (to "DxyLiteral") -- «.DxyLoop» (to "DxyLoop") -- «.arrows_to_defdiag» (to "arrows_to_defdiag") -- require "eoo" -- (find-dn5 "eoo.lua") -- require "diagstacks" -- (find-dn5 "diagstacks.lua") -- require "prefixes" -- (find-dn5 "prefixes.lua") -- (find-dn5 "prefixes.lua" "unabbrev") -- «coords» (to ".coords") -- (find-dn4 "dednat4.lua" "diag-out" "dxyorigx =") dxyorigx = 100 dxyorigy = 100 dxyscale = 15 realx = function (x) return dxyscale * (x - dxyorigx) end realy = function (y) return -dxyscale * (y - dxyorigy) end realxy = function (x, y) return realx(x), realy(y) end -- «arrow_to_TeX» (to ".arrow_to_TeX") -- (find-diagxypage 6 "2" " The basic syntax") -- (find-diagxytext "2" " The basic syntax") -- (find-diagxypage 6 "\\morphism(x,y)|p|/{sh}/<dx,dy>[N`N;L]") -- (find-diagxytext "\\morphism(x,y)|p|/{sh}/<dx,dy>[N`N;L]") -- (find-diagxypage 7 "@{shape}") -- (find-diagxytext "@{shape}") -- (find-diagxypage 23 "4.3" " Empty placement and moving labels") -- (find-diagxytext "4.3" " Empty placement and moving labels") -- (find-dn4 "dednat4.lua" "diag-out" "arrowtoTeX =") -- (find-dn4 "dednat4.lua" "lplacement") node_to_TeX = function (node) local tex = node.tex or node.tag local TeX = node.TeX or (tex and unabbrev(tex)) return (TeX and "{"..TeX.."}") or "" end arrow_to_TeX = function (arrow) local node1 = nodes[arrow.from] local node2 = nodes[arrow.to] local x1, y1 = realxy(node1.x, node1.y) local x2, y2 = realxy(node2.x, node2.y) local dx, dy = x2 - x1, y2 - y1 local N1 = node_to_TeX(node1) local N2 = node_to_TeX(node2) local Label = arrow.Label or (arrow.label and unabbrev(arrow.label)) local L = Label and "{"..Label.."}" or "" -- local p = arrow.placement and "|"..arrow.placement.."|" or "" local shape = arrow.shape or "->" local slide = arrow.slide and "@<"..arrow.slide..">" local curve = arrow.curve and "@/"..arrow.curve.."/" local lplace = arrow.lplacement and arrow.lplacement.."{"..label.."}" local sh if slide or curve or lplace then sh = format("/{@{%s}%s%s%s}/", shape, (lplace or ""), (slide or ""), (curve or "")) else sh = "/"..shape.."/" end if lplace then p = "||"; L = "" end -- return format("\\morphism(%d,%d)%s%s<%d,%d>[%s`%s;%s]", x1, y1, p, sh, dx, dy, N1, N2, L) end -- The kinds of things that we store in the array "arrows". -- (find-dn5 "diagstacks.lua" "arrows") -- «DxyArrow» (to ".DxyArrow") DxyArrow = Class { type = "DxyArrow", __index = { TeX = function (ar) return arrow_to_TeX(ar) end, }, } -- «DxyPlace» (to ".DxyPlace") DxyPlace = Class { type = "DxyPlace", __index = { TeX = function (pseudoar) local node = pseudoar[1] local x, y = realxy(node.x, node.y) return format("\\place(%d,%d)[{%s}]", x, y, node_to_TeX(node)) end, }, } -- «DxyLiteral» (to ".DxyLiteral") DxyLiteral = Class { type = "DxyLiteral", __index = { TeX = function (pseudoar) return pseudoar[1] end, }, } -- «DxyLoop» (to ".DxyLoop") -- (find-dn4 "experimental.lua" "loop") DxyLoop = Class { type = "DxyLoop", __index = { TeX = function (pseudoar) local node, dTeX = pseudoar[1], pseudoar.dTeX local x, y = realxy(node.x, node.y) return format("\\Loop(%d,%d){%s}%s", x, y, node_to_TeX(node), dTeX) end, }, } -- «arrows_to_defdiag» (to ".arrows_to_defdiag") arrows_to_TeX = function (prefix) local f = function (ar) return (prefix or " ")..ar:TeX().."\n" end return mapconcat(f, arrows, "") end arrows_to_defdiag = function (name, hyperlink) return format("\\defdiag{%s}{%s\n%s}", name, (hyperlink or ""), arrows_to_TeX(" ")) end ---- From: (find-dn5 "diagforth") ---- «diagforth.lua» (to ".diagforth.lua") ---- This block is from: (find-dn5 "diagforth.lua") -- diagforth.lua: interpreting the words in "%D" lines in dednat5 files. -- This file: -- http://angg.twu.net/dednat5/diagforth.lua.html -- http://angg.twu.net/dednat5/diagforth.lua -- (find-dn5 "diagforth.lua") -- Author: Eduardo Ochs <eduardoochs@gmail.com> -- Version: 2011may13 -- License: GPL3 -- -- (find-blogme4 "eval.lua" "parse_pattern") -- (find-angg "LUA/lua50init.lua" "untabify") -- (find-blogme4 "eval.lua" "readvword") -- «.metastack» (to "metastack") -- «.diag-head» (to "diag-head") -- «.diagram» (to "diagram") -- «.enddiagram» (to "enddiagram") -- «.nodes» (to "nodes") -- «.2D-and-2Dx» (to "2D-and-2Dx") -- «.run» (to "run") -- «.forths» (to "forths") -- require "diagtex" -- (find-dn5 "diagtex.lua") -- require "parse" -- (find-dn5 "parse.lua") -- require "process" -- (find-dn5 "process.lua") -- require "errors" -- (find-dn5 "errors.lua") forths = {} -- «metastack» (to ".metastack") -- (find-dn5 "diagstacks.lua" "MetaStack") forths["(("] = function () depths:ppush() end forths["))"] = function () depths:ppop() end forths["@"] = function () ds:push(depths:metapick(1 + getwordasluaexpr())) end -- «run» (to ".run") -- «diag-head» (to ".diag-head") -- (find-dn5file "segments.lua" "tosegments =") dxyrun = function (str, pos) setsubj(str, pos or 1) while getword() do -- PP(word) if forths[word] then forths[word]() elseif nodes[word] then ds:push(nodes[word]) else Error("Unknown word: "..word) end end end registerhead "%D" { action = function () dxyrun(untabify(linestr), 3) end, } -- «diagram» (to ".diagram") -- «enddiagram» (to ".enddiagram") forths["diagram"] = function () diagramname = getword() or derror("No diagram name") xys = {} nodes = {} arrows = {} lasty = nil end forths["enddiagram"] = function () output(arrows_to_defdiag(diagramname, " % no hyperlink yet")) end -- «2D-and-2Dx» (to ".2D-and-2Dx") -- (find-dn4file "dednat4.lua" "dxy2Dx =") torelativenumber = function (prevn, str) local sign, strn = str:match("^([-+]?)([0-9.]+)$") if not sign then return end -- fail local n = tonumber(strn) if sign == "" then return n end if sign == "+" then return prevn + n else return prev - n end end dxy2Dx = function () xs = {} local lastx = nil while getword() do local n = torelativenumber(lastx, word) if n then xs[startcol] = n lastx = n end end end forths["2Dx"] = dxy2Dx firstxin = function (s, e) for i=s,e do if xs[i] then return xs[i] end end end dxy2Ddo = function (y, word) if word == "#" then getrestofline(); return end local x = firstxin(startcol, endcol-1) if not x then return end storenode {x=x, y=y, tag=word} end dxy2D = function () if not getword() then return end thisy = torelativenumber(lasty, word) if not thisy then getrestofline(); return end while getword() do dxy2Ddo(thisy, word) end lasty = thisy end forths["2D"] = dxy2D -- «forths» (to ".forths") forths["#"] = function () getrestofline() end -- «nodes» (to ".nodes") forths["node:"] = function () local x,y = getwordasluaexpr() local tag = getword() ds:push(storenode {x=x, y=y, tag=tag}) end forths[".tex="] = function () ds:pick(0).tex = getword() or werror() end forths[".TeX="] = function () ds:pick(0).TeX = getword() or werror() end -- (find-dn4 "dednat4.lua" "diag-arrows") forths[".p="] = function () ds:pick(0).placement = getword() or werror() end forths[".slide="] = function () ds:pick(0).slide = getword() or werror() end forths[".curve="] = function () ds:pick(0).curve = getword() or werror() end forths[".label="] = function () ds:pick(0).label = getword() or werror() end forths[".plabel="] = function () ds:pick(0).placement = getword() or error() ds:pick(0).label = getword() or error() end pusharrow = function (shape) local from, to = ds:pick(1), ds:pick(0) ds:push(storearrow(DxyArrow {from=from.noden, to=to.noden, shape=shape})) end forths["->"] = function () pusharrow("->") end forths["=>"] = function () pusharrow("=>") end forths[".>"] = function () pusharrow(".>") end forths[":>"] = function () pusharrow(":>") end forths["|.>"] = function () pusharrow("|.>") end forths["-->"] = function () pusharrow("-->") end forths["==>"] = function () pusharrow("==>") end forths["|->"] = function () pusharrow("|->") end forths["`->"] = function () pusharrow("^{ (}->") end forths["<-"] = function () pusharrow("<-") end forths["<-|"] = function () pusharrow("<-|") end forths["<--"] = function () pusharrow("<--") end forths["sl^^"] = function () ds:pick(0).slide = "5pt" end forths["sl^"] = function () ds:pick(0).slide = "2.5pt" end forths["sl_"] = function () ds:pick(0).slide = "-2.5pt" end forths["sl__"] = function () ds:pick(0).slide = "-5pt" end defarrows = function (bigstr) for _,spec in ipairs(split(bigstr)) do forths[spec] = function () pusharrow(spec) end end end forths["place"] = function () ds:push(storearrow(DxyPlace {ds:pick(0)})) end forths["loop"] = function () ds:push(storearrow(DxyLoop {ds:pick(0), dTeX=getword()})) end ---- From: (find-dn5 "diagmiddle") ---- «diagmiddle.lua» (to ".diagmiddle.lua") ---- This block is from: (find-dn5 "diagmiddle.lua") -- diagmiddle.lua: words for drawing arrows between the sides of rectangles. -- This file: -- http://angg.twu.net/dednat5/diagmiddle.lua.html -- http://angg.twu.net/dednat5/diagmiddle.lua -- (find-dn5 "diagmiddle.lua") -- Author: Eduardo Ochs <eduardoochs@gmail.com> -- Version: 2011may09 -- License: GPL3 -- -- This corresponds to: -- (find-dn4 "experimental.lua" "splitdist") -- and at the moment (?) it is not included by default in dednat5. -- The test that uses this file is at: -- (find-dn5 "tests/test3.tex") phantomnode = "\\phantom{O}" -- «midpoint» (to ".midpoint") forths["midpoint"] = function () local node1, node2 = ds[2], ds[1] local midx, midy = (node1.x + node2.x)/2, (node1.y + node2.y)/2 ds[2] = storenode{x=midx, y=midy, TeX=phantomnode} dspop() end -- Words for drawing arrows in the middle of rectangles. -- Actually these words build the vertex nodes for those arrows. -- "harrownodes" is for horizontal arrows, -- "varrownodes" is for vertical arrows, -- "dharrownodes" and -- "dvarrownodes" are for diagonal arrows. -- They all expect two nodes on the stack, "node1" and "node2", and -- they read three parameters with getwordasluaexpr(): "dx0", "dx1", -- and "dx2" (or "dy0", "dy1" and "dy2"). -- "dx0" controls how far from "node1" the arrow starts, -- "dx1" controls the length of the arrow, -- "dx2" controls how far from "node2" the arrow starts. -- Some of dx0, dx1, and dx2 can be nil; see "splitdist" below. -- "harrownodes" uses y = (node1.y+node2.y)/2. -- "varrownodes" uses x = (node1.x+nodex.y)/2. -- This needs more documentation. Sorry. -- Also, the "\phantom{O}" shouldn't be hardcoded. -- «splitdist» (to ".splitdist") splitdist = function (x1, x2, dx0, dx1, dx2) local dx = x2-x1 local rest = dx-(dx0 or 0)-(dx1 or 0)-(dx2 or 0) local type = (dx0 and "n" or "_")..(dx1 and "n" or "_").. (dx2 and "n" or "_") if type=="_n_" then return x1+rest/2, x2-rest/2 elseif type=="n_n" then return x1+dx0, x2-dx2 elseif type=="nn_" then return x1+dx0+rest/2, x2-rest/2 elseif type=="_nn" then return x1+rest/2, x2-dx2-rest/2 end local p = function (n) return n or "nil" end print("Bad splitdist pattern: "..p(dx0).." "..p(dx1).." "..p(dx2)) end harrownodes = function (dx0, dx1, dx2, TeX1, TeX2) local node1, node2 = ds:pick(1), ds:pick(0) local midy = (node1.y + node2.y)/2 local x1, x2 = splitdist(node1.x, node2.x, dx0, dx1, dx2) ds:push(storenode{x=x1, y=midy, TeX=(TeX1 or phantomnode)}) ds:push(storenode{x=x2, y=midy, TeX=(TeX2 or phantomnode)}) end varrownodes = function (dy0, dy1, dy2, TeX1, TeX2) local node1, node2 = ds:pick(1), ds:pick(0) local midx = (node1.x + node2.x)/2 local y1, y2 = splitdist(node1.y, node2.y, dy0, dy1, dy2) ds:push(storenode{x=midx, y=y1, TeX=(TeX1 or phantomnode)}) ds:push(storenode{x=midx, y=y2, TeX=(TeX2 or phantomnode)}) end forths["harrownodes"] = function () harrownodes(getwordasluaexpr(), getwordasluaexpr(), getwordasluaexpr()) end forths["varrownodes"] = function () varrownodes(getwordasluaexpr(), getwordasluaexpr(), getwordasluaexpr()) end ---- From: (find-dn5 "begriff") ---- «begriff.lua» (to ".begriff.lua") ---- This block is from: (find-dn5 "begriff.lua") -- begriff.lua: -- This file: -- http://angg.twu.net/dednat5/begriff.lua.html -- http://angg.twu.net/dednat5/begriff.lua -- (find-dn5 "begriff.lua") -- Author: Eduardo Ochs <eduardoochs@gmail.com> -- Version: 2011may15 -- License: GPL3 -- -- *** This is a prototype!!! *** -- I am still discussing with Alessandro Bandeira Duarte - -- see his homepage, at <http://frege.hdfree.com.br/> - -- which syntax we want this to support, its interface, etc. -- If you are interested in using this please get in touch!!!! -- (find-angg "LUA/begriff.lua") -- (find-fline "/usr/share/doc/texlive-doc/latex/begriff/README") -- \BGassert - generates an assertion sign -- \BGcontent - generates an assertion sign -- \BGnot - generates a negation sign -- \BGquant{v} - generates a universal quantifier with variable v -- \BGconditional{a}{c} - generates a conditional with antecendent -- a and consequent c. Note that in the Begriffsschrift, -- the antecendent is placed below the consequent. -- -- (the following three commands were introduced in version 1.5) -- -- \BGterm{x} - creates a right-justified terminal node x -- \BGstem{x} - inserts arbitrary LaTeX maths x into a non-terminal node -- \BGbracket{x} - places the expression x inside brackets -- (find-books "__frege/__frege.el" "heijenoort") -- «.begriff_classes» (to "begriff_classes") -- «.begriff_parse» (to "begriff_parse") -- «.begriff_head» (to "begriff_head") -- «.begriff_preamble» (to "begriff_preamble") --[[ * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) -- require "begriff" --]] -- require "eoo" -- (find-dn5 "eoo.lua") -- require "process" -- (find-dn5 "process.lua") -- «begriff_classes» (to ".begriff_classes") BegCond = Class { type = "BegCond", __index = { TeX = function (o, p) local pp = p.." " local a, c = o.a:TeX(pp), o.c:TeX(pp) -- return "\\BGconditional{\n".. -- pp..a.."\n".. -- p.."}{"..c.."\n".. -- p.."}" return "\\BGrevconditional{\n".. pp..c.."\n".. p.."}{"..a.."\n".. p.."}" end, }, } BegNot = Class { type = "BegNot", __index = { TeX = function (o, p) return "\\BGnot"..o[1]:TeX(p) end, }, } BegAssert = Class { type = "BegAssert", __index = { TeX = function (o, p) return "\\BGassert"..o[1]:TeX(p) end, }, } BegQuant = Class { type = "BegQuant", __index = { TeX = function (o, p) return "\\BGquant{"..o.v.."}"..o[1]:TeX(p) end, }, } BegTerm = Class { type = "BegTerm", __index = { -- TeX = function (o) return "\\BGterm "..o[1] end, TeX = function (o, p) return " "..o[1] end, }, } -- «begriff_parse» (to ".begriff_parse") beglines = {} bperror = function (x, y, msg) error(format("x=%d y=%d msg=%s", x, y, msg or "?")) end bpterm = function (x, y) local xx = beglines[y]:match("^[^ ]*()", x) while 1 do local xxx = beglines[y]:match("^ [^ ]+()", xx) if xxx then xx = xxx else break end end return beglines[y]:sub(x, xx) end -- bprest = function (x, y) return beglines[y]:sub(x) end bpstart = function (x, y) if beglines[y]:match("^|", x) then return BegAssert {bptree(x+1, y)} end return bptree(x, y) end bptree = function (x, y) local hyphs = beglines[y]:match("^-+", x) if hyphs then return bptree(x+#hyphs, y) or bperror(x, y, "hyphs") end if beglines[y]:match("^~", x) then return BegNot {bptree(x+1, y) or bperror(x+1, y, "~")} end local quant = beglines[y]:match("^%b()", x) if quant then local v = quant:sub(2, -2) return BegQuant {v=v, bptree(x+#quant, y) or bperror(x+#quant, y, "()")} end if beglines[y]:match("^%.", x) then local ya = y + 1 while beglines[ya]:sub(x, x) == "|" do ya = ya + 1 end local c = bptree(x+1, y) or bperror(x+1, y, "c") local a = bptree(x+1, ya) or bperror(x+1, ya, "a") -- I am not testing for the "\\" yet return BegCond {a=a, c=c} end if beglines[y]:match("^ ", x) then return BegTerm {bpterm(x+1, y) or bperror(x, y, "term")} end bperror(x, y, "?") end -- «begriff_head» (to ".begriff_head") -- (find-dn5 "process.lua" "lua-head") registerhead "%B" { action = function () local chunkname = fname..":%B:"..nline beglines = { untabify(linestr) } -- get body of first line while nextheadstr() == "%B" do -- when the next line is also %B set_nline(nline + 1) -- advance pointer table.insert(beglines, untabify(linestr)) -- add its body to the chunk end processbeglines() end, } processbeglines = function () for y,line in ipairs(beglines) do for name,x in line:gmatch"([^ ]+) :+> ()" do local body = bpstart(x, y):TeX(" ") local link = " % no hyperlink yet" local def = format("\\defbegr{%s}{%s\n %s}", name, link, body) output(def) end end end -- «begriff_preamble» (to ".begriff_preamble") begriff_preamble = [[ % From: (find-dn5 "begriff.lua" "begriff_preamble") \usepackage{begriff} \def\defbegr#1#2{\expandafter\def\csname begr-#1\endcsname{#2}} \def\ifbegrundefined#1{\expandafter\ifx\csname begr-#1\endcsname\relax} \def\begr#1{\ifbegrundefined{#1} \errmessage{UNDEFINED BEGRIFFSSCHRIFT DIAGRAM: #1} \else \csname begr-#1\endcsname \fi } \def\BGrevconditional#1#2{\BGconditional{#2}{#1}} ]] ---- From: (find-dn5 "repl") ---- «repl.lua» (to ".repl.lua") ---- This block is from: (find-dn5 "repl.lua") -- repl.lua: a repl for Lua (new version). -- This file: -- http://angg.twu.net/dednat5/repl2.lua.html -- http://angg.twu.net/dednat5/repl2.lua -- (find-dn5 "repl2.lua") -- -- Author: Eduardo Ochs <eduardoochs@gmail.com> -- Version: 2011dec05 -- License: GPL3 -- -- REPLs are hard to implement! As I've tried to explain in my notes in -- http://angg.twu.net/repl.html -- (find-TH "repl") -- the control flow of a REPL can be daunting... -- -- The class "Repl", defined below, is an attempt to implement all the -- ideas mentioned in those notes, plus a few more - e.g., different -- prefixes - without using any tricks like throw/catch, gotos, or -- tail cails; we just use Repl object with a "status" field, plus -- several other fields for temporary data. -- -- The logic of a REPL is, very roughly, this: -- -- /--------------------\ -- | | -- v | -- R ---> E ---> P ---> L -- -- which means: Try to [R]ead a command, possibly spanning several -- lines; after reading it, try to [E]val it; if the eval was -- successful, [P]rint the results, otherwise display the error; if -- not abort has been requested, [L]oop. -- -- The logic of [R]ead is roughly this: read a first line of input, -- with prompt ">"; while what we've got is an incomplete command - -- like "if foo() then bar() else", read more input, now with prompt -- ">>", again testing for completeness after adding each line. But -- there are several kinds of errors that we must handle, so here is -- -- The full pseudocode -- =================== -- (Note that this is to be read while you follow the real code!) -- -- "Read()" is this: -- Readfirst(), and while not Incomplete() do Readanother(); end; -- if not Compilationerror() then return true end. -- If either "Readfirst()" or "Readanother" receive a "^C", a "^D" -- or an "eof" in its input, return nil. -- Note that: -- 1) Compilationerror() may set the status to "compilation -- error", and in this case Read() returns nil. -- 2) If Read() returns true this means that we have something -- to Eval(). -- 3) There are several cases in which Read() returns nil: -- r.status = "eof" -> means: abort the REPL -- r.status = "^D" -> means: abort the REPL -- r.status = "compilation error" -> means: read more -- r.status = "^C" -> means: read more -- 4) Incomplete() runs r.f, r.err = loadstring(r.code) and -- tests if r.err holds certain a certain type of error (that -- means that the code ends prematurely). The values in r.f -- and r.err are reused by Compilationerror() and Eval(). -- 5) Readfirst() runs Identify(), which detects which prefix is -- being used and sets some variables (e.g. r.print) -- accordingly. -- "Eval()" is this: -- Run r.f() with xpcall, using a simple error handler to display -- a traceback in case of runtime errors; when a runtime error -- occurs, set r.status to "runtime error" and return nil, and -- when there are no runtime errors set r.fresults to a closure -- that returns the same return values as r.f(), and return true. -- Note that when Eval() returns true that means that we may have -- something to print. -- "Print()" is this: -- Run r.print(r:fresults()). For some prefixes, like "=", r.print -- is set to a function that prints the results; for other -- prefixes, like "", r.print is set to nop, which do not print -- the results. -- "ReadEvalPrint()" is this: -- r:Read() and r:Eval() and r:Print(). -- After running that, r.status can be one of: "eof", "^C", "^D", -- "compilation error", "runtime error", or some other (garbage) -- values, all meaning "ok". When the status is "eof" or "^D" -- ReadEvalPrint() returns nil, in all other cases it returns -- true. When ReadEvalPrint() returns true that means that we -- should loop. -- -- How did I develop that -- ====================== -- I examined this sample interaction, -- -- > r = Repl {} -- > r:Repl() -- L> = 2 + -- LL> 3, 4 -- 5 4 -- L> ^D -- > -- -- and wrote down how the fields in the Repl object "r" should be -- changed, and in which order, and by which function: -- -- r.line = "= 2 +" <-- set by Readline -- r.str = "= 2 +" <-- set by Readfirst -- r.prefix = "=" <-- set by Identify -- r.body = " 2 +" <-/ -- r.code = "return 2 +" <-/ -- r.print = <function print> <-/ -- r.status = "incomplete" <-- set by Incomplete -- r.line = "3, 4" <-- set by Readline -- r.str = "= 2 +\n 3, 4" <-- set by Readanother -- r.body = " 2 +\n 3, 4" <-/ -- r.code = "return 2 +\n 3, 4" <-/ -- r.status = "complete" <-- set by Incomplete -- r.f, r.err = loadstring("return 2 +\n 3, 4") <-- set by Eval -- r.out = {true, 5, 4, n=3} <-/ -- r.results() = 5, 4 <-/ -- r.line = "^D" <-- set by Readline -- r.status = "^D" -- -- Then, starting from the sketchy data flow diagram above, I -- discovered how should be the control flow, and wrote the code. -- -- A note: I'm cheap, so I decided to support "^C" and "^D" only as -- lines holding a LITERAL caret then an uppercase "C" or "D" - I -- don't want to have to deal with real signals right now! 8-\ -- -- (find-es "lua5" "loadstring_and_eof") -- (find-es "lua5" "traceback") -- (find-luamanualw3m "#pdf-xpcall") -- (find-luamanualw3m "#pdf-unpack") -- (find-luamanualw3m "#pdf-select") -- require "common" -- (find-dn5 "common.lua") -- require "eoo" -- (find-dn5 "eoo.lua") Repl = Class { type = "Repl", __index = { Readline = function (r, prompt) io.write(prompt) r.line = io.read() if r.line == nil then r.status = "eof"; return end if r.line == "^C" then r.status = "^C"; return end if r.line == "^D" then r.status = "^D"; return end return true end, Identify = function (r) local prefix, body = r.line:match("^(==?)(.*)$") r.str = r.line if prefix then r.prefix = prefix r.body = body r.code = "return "..body r.print = print r.print = PP else r.prefix = "" r.body = r.line r.code = r.line r.print = function (...) end end end, Incomplete = function (r) local pat = "<eof>.$" r.f, r.err = loadstring(r.code) if r.err and r.err:match(pat) then r.status = "incomplete" return true end end, Compilationerror = function (r) if r.err then r.status = "compilation error" print(r.err) return true end end, Readfirst = function (r) if r:Readline("L> ") then r:Identify() return true end end, Readanother = function (r) if r:Readline("LL> ") then r.str = r.str .."\n"..r.line r.body = r.body.."\n"..r.line r.code = r.code.."\n"..r.line return true end end, Read = function (r) if not r:Readfirst() then return end while r:Incomplete() do if not r:Readanother() then return end end if r:Compilationerror() then return end return true end, Eval = function (r) local handler = function () print(debug.traceback()) end local out = pack(xpcall(r.f, handler)) if not out[1] then r.status = "runtime error"; return end r.fresults = function () return unpack(out, 2, out.n) end return true end, Print = function (r) r.print(r:fresults()) end, ReadEvalPrint = function (r) if r:Read() and r:Eval() then r:Print() end if r.status == "^D" or r.status == "eof" then return nil end return true end, Repl = function (r) while r:ReadEvalPrint() do end end, }, } repl = function () Repl{}:Repl() end ---- From: (find-dn5 "options") ---- «options.lua» (to ".options.lua") ---- This block is from: (find-dn5 "options.lua") -- options.lua: process command-line options. This is a prototype! -- This file: -- http://angg.twu.net/dednat5/options.lua.html -- http://angg.twu.net/dednat5/options.lua -- (find-dn5 "options.lua") -- Author: Eduardo Ochs <eduardoochs@gmail.com> -- Version: 2011apr10 -- License: GPL3 -- -- See: (find-LATEX "2011ebl-slides.tex") -- (find-dn5 "build.lua") -- (find-blogme4 "options.lua") -- require "preamble" -- (find-dn5 "preamble.lua") -- require "process" -- (find-dn5 "process.lua") -- require "treehead" -- (find-dn5 "treehead.lua") -- require "diagforth" -- (find-dn5 "diagforth.lua") dooption_t = function (texfile) local fname_tex = texfile local fname = texfile:match("^(.*)%.tex$") if not fname then error(fname_tex.." does not end with .tex!\n".. "`-t' refuses to run.") end local fname_dnt = fname .. ".dnt" output = function (str) table.insert(outputs, str) end outputs = {preamble} process_fname(fname_tex) writefile(fname_dnt, table.concat(outputs, "\n").."\n") print(" "..fname_tex.." -> "..fname_dnt) end dooption_e = function (luacode) assert(loadstring(luacode))() end _O = _O or {} _O["-t"] = function (texfile, ...) dooption_t(texfile); dooptions(...) end _O["-e"] = function (luacode, ...) dooption_e(luacode); dooptions(...) end dooptions = function (optionname, ...) -- PP("o", optionname, ...) if not optionname then return end if not _O[optionname] then error(format("Not in _O (for dooptions): %q", optionname)) end -- PP("g", ...) _O[optionname](...) end dooptions(...) -- (find-dn4 "dednat4.lua" "main") -- (find-luamanualw3m "#6" "arg =") -- (find-dn5 "process.lua" "main-loop") -- Local Variables: -- coding: raw-text-unix -- ee-anchor-format: "«%s»" -- End: