Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
-- This file: -- http://anggtwu.net/LUA/Indent1.lua.html -- http://anggtwu.net/LUA/Indent1.lua -- (find-angg "LUA/Indent1.lua") -- Author: Eduardo Ochs <eduardoochs@gmail.com> -- -- This file is obsolete! -- It was superseded by: -- (find-angg "LUA/Indent2.lua") -- -- -- My first implementation of "indent" only interpreted these kinds of -- "indentation instructions": -- -- "<+2>" increase the indentation by 2 -- "<-3>" decrease the indentation by 3 -- "\n" is converted to something like "\n ", where the number -- of spaces is given by the current indentation -- -- then I added support for: -- -- "<!>" delete all whitespace - i.e., "[ \t\n]*" on both -- sides of the "<!>" -- -- and then I saw that -- This file implements a way to convert strings with "indentation -- instructions" into, aham, "normal strings". The indentation -- instructions are of these kinds: -- "<+2>" increase the indentation by 2 -- "<-3>" decrease the indentation by 3 -- "\n" is converted to something like "\n ", where the number -- of spaces is given by the current indentation -- "<!>" delete all whitespace - i.e., "[ \t\n]*" on both -- sides of the "<!>" -- "<!L>" capture the whitespace on both sides of the "<!L>" -- and then return the whitespace that was at the left -- "<!R>" same, but at the right -- "<!LR>" same, but returns the left and right whitespaces -- concatenated -- -- -- (defun e1 () (interactive) (find-angg "LUA/ELpeg1.lua")) -- (defun i1 () (interactive) (find-angg "LUA/Indent1.lua")) -- (defun p1 () (interactive) (find-angg "LUA/Pict2e1.lua")) -- «.flatten» (to "flatten") -- «.flatten-tests» (to "flatten-tests") -- «.nlify» (to "nlify") -- «.Ind» (to "Ind") -- «.Ind-tests» (to "Ind-tests") -- «.nlify-tests» (to "nlify-tests") -- «.pat_indent» (to "pat_indent") -- «.pat_indent-tests» (to "pat_indent-tests") -- «.Indent» (to "Indent") -- «.string.indent» (to "string.indent") -- «.Indent-tests» (to "Indent-tests") require "ELpeg1" -- (find-angg "LUA/ELpeg1.lua" "Gram") gr,V,VA,VE,PE = Gram.new() _ = S(" ")^0 -- «flatten» (to ".flatten") flatten = function (o) local out = VTable {} local add -- recursive, defined in the next line add = function (x) if type(x) == "table" then map(add, x) else table.insert(out, x) end end add(o) return out end concattables = function (A, ...) A = HTable(copy(A)) for _,B in ipairs({...}) do for _,v in ipairs(B) do table.insert(A, v) end end return A end -- «flatten-tests» (to ".flatten-tests") --[[ * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) dofile "Indent1.lua" = flatten {"a", 22, {33, 44, {print}, 55}} = concattables({10, 20}, {30, 40}, {}, {50, 60}) --]] -- _ _ __ -- _ __ | (_)/ _|_ _ -- | '_ \| | | |_| | | | -- | | | | | | _| |_| | -- |_| |_|_|_|_| \__, | -- |___/ -- -- Nlify splits a string and converts each "\n" in it to a {"nl"}. -- For example, -- nlify("a\nbc\n\nd") -- returns: -- {"a", {"nl"}, "bc", {"nl"}, {"nl"}, "d"} -- -- «nlify» (to ".nlify") V.nl = P"\n" / function () return {"nl"} end V.nonnls = Cs((1-P"\n")^1) V.nlify = Ct((V.nl + V.nonnls)^0) pat_nlify = gr:compile("nlify") nlify = function (str) return pat_nlify:match(str) end -- «nlify-tests» (to ".nlify-tests") --[[ * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) dofile "Indent1.lua" PP(nlify("ab\n\ncd")) PP(nlify("abcd")) PP(nlify("")) gr,V,VA,VE,PE = Gram.new() V._ = Cs(P"_"^1) V.m = Cs(S"abcd\n"^1) / nlify V.all = V._ * V.m * V._ gr:cmp("all", "__ab\n\ncd__") --]] -- ___ _ -- |_ _|_ __ __| | -- | || '_ \ / _` | -- | || | | | (_| | -- |___|_| |_|\__,_| -- -- This is used by one of the patterns in pat_indent. -- (find-es "lpeg" "lpeg-matchtime") -- -- «Ind» (to ".Ind") Ind = Class { type = "Ind", from = function (_) return Ind{_=_, out={}} end, captures = function (_) return Ind.from(_):captures() end, --captures = function (_) PP(_); return PP(Ind.from(_):captures()) end, mtcaptures = function (s,p,_) return p,Ind.captures(_) end, test = function (_) PP(Ind.captures(_)) end, __tostring = function (i) return mytostring(i) end, __index = { sign = function (i) return (i._.sign == "-") and -1 or 1 end, uint = function (i) return tonumber(i._.digits) end, int = function (i) return i:uint() and i:sign()*i:uint() end, indent = function (i) return i:int() and i:int()~=0 end, itable = function (i) return i:indent() and {{"indent", i:int()}} or {} end, -- l = function (i) return i._.l or "" end, r = function (i) return i._.r or "" end, LR = function (i) return i._.LR or "" end, keepl = function (i) return i:LR()=="L" or i:LR()=="LR" end, keepr = function (i) return i:LR()=="R" or i:LR()=="LR" end, ltable = function (i) return i:keepl() and nlify(i:l()) or {} end, rtable = function (i) return i:keepr() and nlify(i:r()) or {} end, -- captures = function (i) return unpack(concattables(i:ltable(), i:itable(), i:rtable())) end, }, } -- «Ind-tests» (to ".Ind-tests") --[[ * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) dofile "Indent1.lua" Ind.test {sign="-", digits="42"} Ind.test {sign="-", digits="42", l=" ", r=" ", LR="LR"} Ind.test {sign="-", digits="42", l=" \n ", r=" \n\n ", LR="LR"} Ind.test {sign="-", digits="42", l=" \n ", r=" \n\n ", LR="L"} Ind.test {sign="-", digits="42", l=" \n ", r=" \n\n ", LR="R"} Ind.test { l=" \n ", r=" \n\n ", LR="R"} PP(Ind.captures {sign="-", digits="42"}) gr,V,VA,VE,PE = Gram.new() V._ = Cs(P"_"^1) V.m = P"a" * Cc {sign="-", digits="42", l=" \n ", r=" \n\n ", LR="LR"} V.mc = P"a" * Cc {sign="-", digits="42", l=" \n ", r=" \n\n ", LR="LR"} V.m = V.mc / Ind.captures V.all = V._ * V.m * V._ gr:cmp("all", "__a__") --]] -- _ _ _ _ -- _ __ __ _| |_ (_)_ __ __| | ___ _ __ | |_ -- | '_ \ / _` | __| | | '_ \ / _` |/ _ \ '_ \| __| -- | |_) | (_| | |_ | | | | | (_| | __/ | | | |_ -- | .__/ \__,_|\__|___|_|_| |_|\__,_|\___|_| |_|\__| -- |_| |_____| -- -- This block defines the lpeg pattern used by the Indent class. -- For example, that pattern "converts" -- "<+23>a\n<-4><!>\nb" -- to: -- {1="indent", 2=23} "a" {1="nl"} {1="indent", 2=-4} "" "b" -- -- These substrings or the original string are treated specially: -- "<+23>" increase the indentation by 23 -- "<-4>" decrease the indentation by 4 -- "\n" print a newline plus the current indentation -- "<!>\n" <!> discards all the newlines immediately after it -- At this moment the delimiters "<" and ">" are hardcoded. -- -- See the classes Indent: -- (to "Indent") -- -- «pat_indent» (to ".pat_indent") V.o = P"<" V.c = P">" Cin = function (tag, pat) return Cs(pat):Cg(tag) end V.sign = Cin("sign", S"+-") V.n = Cin("digits", R"09"^1) V.l = Cin("l", S" \t\n"^0) V.r = Cin("r", S" \t\n"^0) V.LR = Cin("LR", P"LR" + P"L" + P"R" + P"") V.bang0 = (V.sign*V.n + P"!") * V.LR V.bangt = Ct(V.l*V.o* V.bang0 *V.c*V.r) V.bang = V.bangt / Ind.captures V.spaces = Cs(S" \t"^1) V.nl = P"\n" / function () return {"nl"} end V.nonnls = Cs((1-P"\n")^1) V.special = V.bang + V.spaces + V.nl V.text = Cs((-V.special * P(1))^1) V.all = (V.text + V.special)^0 V.tall = Ct(V.all) pat_indent0 = gr:compile("all") -- returns several values pat_indent = gr:compile("tall") -- returns a table -- «pat_indent-tests» (to ".pat_indent-tests") --[[ * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) dofile "Indent1.lua" gr:cmp("bangt", "<+23>") o = gr:cm0("bangt", "<+23>") PP(o) PP(Ind.captures(o)) gr:cmp("bang", "<+23>") gr:cmp( "all", "<+23>a\n<-4>\nb") gr:cmp( "all", "<+23>a\nb\n<-4>\nc") gr:cmp("tall", "<+23>a\nb\n<-4L>\nc") gr:cmp("tall", "<+23>a\nb\n<-4R>\nc") gr:cmp("tall", "<+23>a\n<-4LR>\nb") gr:cmp("tall", "<+23>a\n<-4><!>b") gr:cmp("tall", "<+23>a\n<-4><!>\nb") gr:cmp("tall", "<+23>a\n<-4> <!> b") gr:cmp("tall", "<+23>a\n<-4> <!L> b") gr:cmp("tall", "<+23>a\n<-4> <!R> b") gr:cmp("tall", "<+23>a\n<-4> <!LR> b") PP(pat_indent0:match "<+23>a\n<-4><!>\nb") PP(pat_indent :match "<+23>a\n<-4><!>\nb") --]] -- ___ _ _ -- |_ _|_ __ __| | ___ _ __ | |_ -- | || '_ \ / _` |/ _ \ '_ \| __| -- | || | | | (_| | __/ | | | |_ -- |___|_| |_|\__,_|\___|_| |_|\__| -- -- The class Indent implements the machinery to convert a string like: -- "foo\nbar<+1>\nplic\nploc<-1>\nbof" -- to: -- foo -- bar -- plic -- ploc -- bof -- and it lets us test each step of the conversion separately. -- -- «Indent» (to ".Indent") Indent = Class { type = "Indent", new = function (bigstr) return Indent {bigstr = bigstr} end, indent = function (bigstr, ind) return Indent.new(bigstr):parse():map(ind or 0):concat() end, flatten = function (o) return Indent.indent(table.concat(flatten(o), "\n")) end, __index = { parse = function (ind) ind.A = VTable(pat_indent:match(ind.bigstr)) return ind end, map = function (ind, r) ind.B = VTable {} for _,o in ipairs(ind.A) do if type(o) == "string" then table.insert(ind.B, o) elseif o[1] == "nl" then table.insert(ind.B, "\n"..(" "):rep(r)) elseif o[1] == "indent" then r = r + o[2] else error() end end return ind end, concat = function (ind) return table.concat(ind.B) end, }, } -- «string.indent» (to ".string.indent") string.indent = Indent.indent -- works only on strings indent = Indent.flatten -- works on strings and tables -- «Indent-tests» (to ".Indent-tests") --[[ * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) dofile "Indent1.lua" bigstr = "foo\nbar<+1>\nplic\nploc<-1>\nbof" o = {"foo", {"bar<+1>", "plic", "ploc<-1>"}, "bof"} = indent(bigstr) = indent(o) = bigstr:indent() = bigstr:indent(4) i = Indent.new(bigstr) = i:parse().A = i:parse():map(0).B = i:parse():map(0):concat() = bigstr = Indent.indent(bigstr) = bigstr:indent() = indent "foo\nbar<+1>\nplic\nploc<-1>\nbof" = indent "foo\nbar<+1LR>\nplic\nploc<-1>\nbof" = indent "foo\nbar<+1LR>\nplic\nploc<-1LR>\nbof" --]] -- «Ind-tests» (to ".Ind-tests") --[[ * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) dofile "Indent1.lua" a = Ind { "% Grid", "% Horizontal lines:", "\\Line(-1.2,0)(3.2,0)", "\\Line(-1.2,1)(3.2,1)", "% Vertical lines:", "\\Line(0,-2.2)(0,5.2)", "\\Line(1,-2.2)(1,5.2)", } b = Ind { "\\linethickness{0.5pt}", a } c = Ind { "\\color{gray}", b } d = Ind { "{<+1><!>", c, "}<-1>" } = d:tostring0() = d:tostring() = d:flatten() = d:flatten():indent() * (eepitch-lua51) * (eepitch-kill) * (eepitch-lua51) dofile "Indent1.lua" a = { "%hlines", "%vlines" } b = { "thick", a } c = { "gray", b } d = { "{<+1><!>", c, "}<-1>" } = d PP(d) = Ind.flatten(d) = Ind.flatten(d, "\n") = Ind.flatten(d, "\n", 0) = Ind.tostring (d) = Ind.tostring0(d) e = Ind.fromcopy(d) PP(e) = e = e[2] = e[2][2] --]] -- Local Variables: -- coding: utf-8-unix -- End: