From 1fb658cc9435346a6f399e846f07f05c08260fc7 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Sun, 29 Jul 2012 17:06:24 +0000 Subject: interpreter (10jun12) git-svn-id: svn://tug.org/texlive/trunk@27232 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/doc/luatex/interpreter/README | 8 +- .../doc/luatex/interpreter/interpreter-doc.pdf | Bin 102479 -> 110003 bytes .../doc/luatex/interpreter/interpreter-doc.tex | 4 +- .../doc/luatex/interpreter/interpreter-doc.txt | 185 ++++++++------------- .../tex/luatex/interpreter/interpreter.lua | 165 +++++++++++------- .../tex/luatex/interpreter/interpreter.sty | 4 +- .../tex/luatex/interpreter/interpreter.tex | 2 +- 7 files changed, 186 insertions(+), 182 deletions(-) (limited to 'Master') diff --git a/Master/texmf-dist/doc/luatex/interpreter/README b/Master/texmf-dist/doc/luatex/interpreter/README index c91f26a1d59..f3e1c56c528 100644 --- a/Master/texmf-dist/doc/luatex/interpreter/README +++ b/Master/texmf-dist/doc/luatex/interpreter/README @@ -2,15 +2,15 @@ This is the README file for the Interpreter package. Author: Paul Isambert. E-mail: zappathustra AT free DOT fr Comments and suggestions are welcome. -Date: December 2011. -Version: 1.1. +Date: June 2012. +Version: 1.2. Interpreter preprocesses input files on the fly (no external program) and manipulates input lines, e.g. to turn some markup into proper TeX syntax. Interpreter doesn't work with ConTeXt. -LuaTeX is required, as is, since version 1.1, the Lua side of the -Gates package (i.e. gates.lua). +LuaTeX is required, and the Lua side of the Gates package (i.e. gates.lua), +version at least 0.2. Relevant information can be found in interpreter-doc.pdf or interpreter-doc.txt (source of the doc readable in a text editor). diff --git a/Master/texmf-dist/doc/luatex/interpreter/interpreter-doc.pdf b/Master/texmf-dist/doc/luatex/interpreter/interpreter-doc.pdf index ea76a6c65cd..2dcc32ea485 100644 Binary files a/Master/texmf-dist/doc/luatex/interpreter/interpreter-doc.pdf and b/Master/texmf-dist/doc/luatex/interpreter/interpreter-doc.pdf differ diff --git a/Master/texmf-dist/doc/luatex/interpreter/interpreter-doc.tex b/Master/texmf-dist/doc/luatex/interpreter/interpreter-doc.tex index 8a1ab383a81..30a1da52ba4 100644 --- a/Master/texmf-dist/doc/luatex/interpreter/interpreter-doc.tex +++ b/Master/texmf-dist/doc/luatex/interpreter/interpreter-doc.tex @@ -1,7 +1,7 @@ % This is the master file producing interpreter-doc.pdf. The version of the % documentation readable in a text editor is interpreter-doc.txt (input below). % -% Paul Isambert - zappathustra AT free DOT fr - December 2011 +% Paul Isambert - zappathustra AT free DOT fr - June 2012 \input pitex @@ -97,7 +97,7 @@ end % Title \vbox to 3\baselineskip{ \hbox to \hsize{\big Interpreter\hfil\normalsize Paul Isambert} -\hbox to \hsize{v.1.1, December 2011 \hfil \tcode{zappathustra AT free DOT fr}} +\hbox to \hsize{v.1.2, June 2012 \hfil \tcode{zappathustra AT free DOT fr}} \vfil } diff --git a/Master/texmf-dist/doc/luatex/interpreter/interpreter-doc.txt b/Master/texmf-dist/doc/luatex/interpreter/interpreter-doc.txt index 0156c3e07d8..6257aa6733e 100644 --- a/Master/texmf-dist/doc/luatex/interpreter/interpreter-doc.txt +++ b/Master/texmf-dist/doc/luatex/interpreter/interpreter-doc.txt @@ -578,27 +578,13 @@ which is why it is so heavy; it receives a file handle: . . . check_direct . . . insert_line . . apply_classes - . . . initialize . . . pass_class . . . . pass_pattern - . . . . . pass_line - . . . . . . check_index - . . . . . . . call - . . . . . . . replace - . . . . . . . protect - . . . . . . increment_line - . . . . . increment_pattern - . . . . increment_class - . . . apply_class0 - . . . . initialize0 - . . . . pass_pattern - . . . . . pass_line - . . . . . . check_index - . . . . . . . call - . . . . . . . replace - . . . . . . . protect - . . . . . . increment_line - . . . . . increment_pattern + . . . . . process_lines + . . . . . . switch + . . . . . . call + . . . . . . replace + . . . . . . protect . . . unprotect . . . . undo_protected . . . . unprotect_lines @@ -641,64 +627,65 @@ which is why it is so heavy; it receives a file handle: "interpreter.core.lines" shouldn't be empty, and "interpreter.active" should be true. -> initialize () [m-gate] - Returns "1, 1, 1, 1"; it simply starts the following loop. - -> pass_class () [l-gate] - An l-gate called as long as "interpreter.core.reader.protected" isn't - a boolean value (see "unprotect" below) and isn't larger than - "#interpreter.core.classes"; see "increment_class" below, which returns - "+1". In other words, "pass_class" will be repeated for each - class. +> pass_class () [l-gate] + This gate iterates on all classes in "interpreter.core.classes" and + then on class 0. On each iteration it checks beforehand whether the + paragraph is protected, i.e. "interpreter.core.reader.protected" isn't + a boolean (see "unprotecte" below). On each iteration, the class + number and the class itself are returned. (This behavior is + implemented with a Gates iterator.) -> pass_pattern (, ) [l-gate] +> pass_pattern (, ) [l-gate] Same as "pass_class", except it iterates on the patterns in "class": - it is executed as long as "interpreter.core.reader.protected" isn't - a boolean and "" isn't larger than "#interpreter.core.classes[]". - See "increment_pattern" below. In other words, it will be repeated - for each pattern in . - -> pass_line (, , ), [l-gate] - Here we go again, except we check, besides protection, that - isn't larger than "#interpreter.core.lines". See "increment_line" - below. - -> check_index (, , , ) [l-gate] - This time we check that "interpreter.core.classes[][].pattern" - occurs in "interpreter.core.lines[]", starting at . - Protection is checked too, as is the type of "interpreter.core.lines[]"; - indeed, individual lines are protected by turning them into tables - (with a single entry, the line itself), see "protect" below. The - occurrence of the pattern in the line is checked with - "interpreter.core.tools.get_index". - -> call (, , , ) [m-gate] - This is executed if and only if the pattern table (i.e. - "interpreter.core.classes[][]") has a "call" entry. - The index where the pattern occurs is retrieved with - "interpreter.core.tools.get_index" and stored in , and then - the "call" entry is executed as: - - call (interpreter.core.lines, - , , ) - - where is defined as above; if call returns one value, - it is assigned to ; if it returns two, they are assigned to - and . The gate returns the four arguments. - -> replace (, , , ) [m-gate] - This is executed only if the pattern table, as defined above, has a - "replace" field and no "call" field; it applies "interpreter.core.tools.xsub" - as: + it is executed as long as "interpreter.core.reader.protected" and + returns the patter number and the pattern itself. (The + argument isn't used; it is for the "pass_class" iterator; the same + holds for the following gates.) + +> process_lines (, ) [l-gate] + Again, this calls an iterator. It browses each line in "interpreter.core.lines" + and returns the line's number (provided it is valid, i.e. not a table, + see "protect" below), and the current index in that line. + To keep track of the current line and index, two internal numbers are + used: "interpreter.core.reader.current_line" and + "interpreter.core.reader.current_index". + +> switch (, , ) [m-gate] + If has a "call" entry, it sets the "call" gate below to + "ajar"; otherwise, if has a "replace" entry, it sets the + "replace" gate to "ajar". + +> call (, , ) [m-gate] + This gate is closed by default and set to "ajar" by "switch" above. + If, starting at , the 's "pattern" entry can be + found in with "interpreter.core.tools.get_index" (which makes + sure that protectors are obeyed and returns , where the + pattern is found if it occurs), the 's "call" entry is + applied as + + .call(interpreter.core.lines, + , , ) + + This may returned zero, one or two values. If nothing is returned, + "interpreter.core.reader.current_index" is set to 0, which makes + the "process_lines" iterator consider the next line. If one value is + returned, it is the new current index and "process_lines" will not + update the line number. If two values are returned, the first is the + new current line number and the second the new current index. + +> replace (, , ) [m-gate] + This gate is closed by default and set to "ajar" by "switch" above. + This tries to find the 's "pattern" like "call" above, and if + it is found, it applies "interpreter.core.tools.xsub" as: xsub (interpreter.core.lines[], - , .pattern, - .replace) + , .pattern, .replace) where is defined as in "call". The return value of "xsub" - is assigned to "interpreter.core.lines[]". The gate returns - its four argument, with incremented by the value of the - "offset" entry of the pattern, if any. + is assigned to "interpreter.core.lines[]", and the current + index is set to plus the 's "offset" if any. If the + pattern wasn't found, the current index is set to 0, which makes + "process_lines" turn to the next line as explained in "call". > protect () [m-gate] The "interpreter.protect()" function can either protect the whole @@ -707,48 +694,13 @@ which is why it is so heavy; it receives a file handle: takes the value "true", which is checked in various gates above. In the second case, "interpreter.core.tools.protected" is a table with each index indicating a line to be protected. This gate implements - the protection in that case: for each entry in the table, it protects - the line with the same index in "interpreter.core.lines" by transforming - it into a table (with a single entry, the string representing the - original line); the type of the line is checked in "check_index" - above. This gate is executed if and only if "interpreter.core.tools.protected" - is a table. The four arguments returned by "call" or "replace" are - automatically returned, so that "check_index" is reexecuted if its - "loop" conditional evaluates to "true". - -> increment_line (, , , ) [m-gate] - Returns , , + 1, , so "pass_line" is - reexecuted if its "loop" conditional evaluates to "true". - -> increment_pattern (, , , ) [m-gate] - Returns , + 1, , , so "pass_pattern" - is reexecuted if its "loop" conditional evaluates to "true". - -> increment_class (, , , ) [m-gate] - Returns + 1, , , , so "pass_class" is - reexecuted if its "loop" conditional evaluates to "true". - -> apply_class0 () [l-gate] - The l-gate that does roughly the same job as "apply_classes", but - with class 0. It is called if and only if "interpreter.core.reader.protected" - isn't a boolean. - -> initialize0 () [m-gate] - The same as "initialize", except it returns "0, 1, 1, 1", since - we're interested in class 0. - -> pass_pattern (, ) [l-gate] - The same as above. (Note that this version of the gate doesn't occur - in the same l-gate as the previous one, so its local "loop" is also - different.) - -There is one important difference between "apply_class" and "apply_class0": -the latter has "pass_pattern" as its immediate subgate, without -"pass_class" as an intermediary l-gate. That makes sense, since we don't -want to loop on all the classes here (as that was done in "apply_class"), -but we're only interested in class 0. Apart from that, the "pass_pattern" -gate is really the same in both, so all the subgates of "pass_pattern" -are also reapplied here; I won't describe them again. + the protection in that case: it iterates on all entries in the table + with "pairs" and protects the line with the same index in + "interpreter.core.lines" by transforming it into a table (with a + single entry, the string representing the original line); the type + of the line is checked in the "process_lines" iterator above. The + gate's iterator doesn't take arguments, but the function itself is + defined as taking a number (the line). > unprotect () [l-gate] Now all the patterns in all the classes have been applied to the @@ -757,10 +709,13 @@ are also reapplied here; I won't describe them again. > undo_protected () [m-gate] Simply sets "interpreter.core.tools.protected" to "nil" so it is - ready for the next paragraph. + ready for the next paragraph. > unprotect_lines () [m-gate] - Restore all the lines in "interpreter.core.lines" as simple strings. + Restores all the lines in "interpreter.core.lines" as simple strings. + The gate uses an iterator that simply runs "ipairs" on "interpreter.core.lines", + so the function's definition actually takes the line's number and + the line itself as arguments. > remove_escape () [m-gate] If "interpreter.escape" is defined, removes all its occurrences in diff --git a/Master/texmf-dist/tex/luatex/interpreter/interpreter.lua b/Master/texmf-dist/tex/luatex/interpreter/interpreter.lua index 2a87d979195..05de6eb791f 100644 --- a/Master/texmf-dist/tex/luatex/interpreter/interpreter.lua +++ b/Master/texmf-dist/tex/luatex/interpreter/interpreter.lua @@ -1,6 +1,6 @@ -- This is the main Lua file for the Interpreter package. -- Further information in interpreter-doc.pdf or interpreter-doc.txt. --- Paul Isambert - zappathustra AT free DOT fr - December 2011 +-- Paul Isambert - zappathustra AT free DOT fr - June 2012 -- -- Beware, this is written with Gates. Please read the Gates doc if -- you want to understand something. @@ -8,7 +8,12 @@ local find, gsub, match, sub = string.find, string.gsub, string.match, string.sub local insert, sort, remove = table.insert, table.sort, table.remove local io_open = io.open +local ipairs, pairs, type = ipairs, pairs, type require("gates.lua") +if not gates.iterator then + tex.error("Interpreter error: Your version of Gates should be at least v.0.2. I quit. Expect chaos") + return +end interpreter = gates.new("interpreter") @@ -251,7 +256,8 @@ interpreter.direct = "%%%%I%s+" -- At last, the function to be registered in open_read_file, defining the -- function that reads a file. - +interpreter.core.reader.current_line = 0 +interpreter.core.reader.current_line = 0 interpreter.core.reader.list{"read_file", {"make_paragraph", conditional = function () return #interpreter.core.lines == 0 end, @@ -274,71 +280,114 @@ interpreter.core.reader.list{"read_file", insert(interpreter.core.lines, line) end}}, {"apply_classes", conditional = function () return #interpreter.core.lines > 0 and interpreter.active end, - {"initialize", - function () - return 1, 1, 1, 1 - end}, - {"pass_class", loop = function (c) return type(interpreter.core.reader.protected) ~= "boolean" - and c <= #interpreter.core.classes end, - {"pass_pattern", loop = function (c, p) return type(interpreter.core.reader.protected) ~= "boolean" - and p <= #interpreter.core.classes[c] end, - {"pass_line", loop = function (c, p, l) return type(interpreter.core.reader.protected) ~= "boolean" - and l <= #interpreter.core.lines end, - {"check_index", loop = function (c, p, l, i) - return (type(interpreter.core.lines[l]) == "string" and type(interpreter.core.reader.protected) ~= "boolean") - and interpreter.core.tools.get_index(interpreter.core.lines[l], interpreter.core.classes[c][p].pattern, i) - end, - {"call", conditional = function (c, p) return interpreter.core.classes[c][p].call end, - function(c, p, l, i) - local line, pattern = interpreter.core.lines[l], interpreter.core.classes[c][p] - local index = interpreter.core.tools.get_index(line, pattern.pattern, i) - local L, O = pattern.call(interpreter.core.lines, l, index, pattern) - if O then - l, i = L, O - elseif L then - i = L + {"pass_class", iterator = function () + local done_zero + local function f (t, i) + if type(interpreter.core.reader.protected) ~= "boolean" then + if not done_zero then + i = i+1 + local v = t[i] + if v then + return i, v + else + done_zero = true + return 0, t[0] + end + end + end + end + return f, interpreter.core.classes, 0 + end, + {"pass_pattern", iterator = function (_, class) + local function f (t, i) + if type(interpreter.core.reader.protected) ~= "boolean" then + i = i+1 + local v = t[i] + if v then + return i, v + end + end + end + return f, class, 0 + end, + {"process_lines", iterator = function (_, pattern) + interpreter.core.reader.current_line = 0 + interpreter.core.reader.current_index = 0 + return function () + if type(interpreter.core.reader.protected) ~= "boolean" then + local l = interpreter.core.reader.current_line + local i = interpreter.core.reader.current_index + if i == 0 then + l, i = l + 1, 1 + end + line = interpreter.core.lines[l] + -- When protected, a line is a table. + while type(line) == "table" do + l, i = l+1, 1 + line = interpreter.core.lines[l] + end + if line then + interpreter.core.reader.current_line = l + interpreter.core.reader.current_index = i + return l, pattern, i + end + end + end + end, + {"switch", autoreturn = true, + function (_, pattern) + if pattern.call then + interpreter.core.reader.ajar("call", "process_lines") + elseif pattern.replace then + interpreter.core.reader.ajar("replace", "process_lines") end - return c, p, l, i - end}, - {"replace", conditional = function (c, p) return not interpreter.core.classes[c][p].call - and interpreter.core.classes[c][p].replace end, - function(c, p, l, i) - local line, pattern = interpreter.core.lines[l], interpreter.core.classes[c][p] - local index = interpreter.core.tools.get_index(line, pattern.pattern, i) - interpreter.core.lines[l] = interpreter.core.tools.xsub(line, index, pattern.pattern, pattern.replace) - i = index + (pattern.offset or 0) - return c, p, l, i end}, - {"protect", conditional = function () return type(interpreter.core.reader.protected) == "table" end, - autoreturn = true, - function () - for n, _ in pairs(interpreter.core.reader.protected) do - if type(interpreter.core.lines[n]) == "string" then - interpreter.core.lines[n] = {interpreter.core.lines[n]} + {"call", status = "close", + function(i, pattern, ind) + local line = interpreter.core.lines[i] + local index = interpreter.core.tools.get_index(line, pattern.pattern, ind) + if index then + local L, O = pattern.call(interpreter.core.lines, i, index, pattern) + if O then + interpreter.core.reader.current_line = L + interpreter.core.reader.current_index = O + elseif L then + interpreter.core.reader.current_index = L end + else + interpreter.core.reader.current_index = 0 end - end}}, - {"increment_line", function (c, p, l, i) return c, p, l+1, 1 end}}, - {"increment_pattern", function (c, p, l) return c, p+1, 1, 1 end}}, - {"increment_class", function (c) return c+1, 1, 1, 1 end}}, - {"apply_class0", conditional = function () return type(interpreter.core.reader.protected) ~= "boolean" end, - {"initialize0", - function () - return 0, 1, 1, 1 - end}, - {"pass_pattern", loop = function (c, p) return type(interpreter.core.reader.protected) ~= "boolean" - and p <= #interpreter.core.classes[c] end}}, + end}, + {"replace", status = "close", + function(i, pattern, ind) + local line = interpreter.core.lines[i] + local index = interpreter.core.tools.get_index(line, pattern.pattern, ind) + if index then + interpreter.core.lines[i] = interpreter.core.tools.xsub(line, index, pattern.pattern, pattern.replace) + interpreter.core.reader.current_index = index + (pattern.offset or 0) + else + interpreter.core.reader.current_index = 0 + end + end}, + {"protect", iterator = function () + if type(interpreter.core.reader.protected) == "table" then + return pairs(interpreter.core.reader.protected) + end + end, + function (n) + if type(interpreter.core.lines[n]) == "string" then + interpreter.core.lines[n] = {interpreter.core.lines[n]} + end + end}}}}, {"unprotect", {"undo_protected", function () interpreter.core.reader.protected = nil end}, - {"unprotect_lines", - function () - for n, l in ipairs(interpreter.core.lines) do - if type(l) == "table" then - interpreter.core.lines[n] = l[1] - end + {"unprotect_lines", iterator = function () return ipairs(interpreter.core.lines) end, + function (i, l) + if type(l) == "table" then + interpreter.core.lines[i] = l[1] end end}}, {"remove_escape", conditional = function () return interpreter.escape end, diff --git a/Master/texmf-dist/tex/luatex/interpreter/interpreter.sty b/Master/texmf-dist/tex/luatex/interpreter/interpreter.sty index 94f94443ad9..ba16a86256f 100644 --- a/Master/texmf-dist/tex/luatex/interpreter/interpreter.sty +++ b/Master/texmf-dist/tex/luatex/interpreter/interpreter.sty @@ -5,10 +5,10 @@ % Author: Paul Isambert. % E-mail: zappathustra AT free DOT fr % Comments and suggestions are welcome. -% Date: December 2011. +% Date: June 2012. \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{interpreter}[2011/12/03 v.1.1 Preprocessing input files on the fly.] +\ProvidesPackage{interpreter}[2012/06/10 v.1.2 Preprocessing input files on the fly.] % Needed to prevent LaTeX check input, which would call open_read_file and % thus remove Interpreter's main function (which is removed as soon as it is % used). diff --git a/Master/texmf-dist/tex/luatex/interpreter/interpreter.tex b/Master/texmf-dist/tex/luatex/interpreter/interpreter.tex index 3f58083dd72..3568fc90e9d 100644 --- a/Master/texmf-dist/tex/luatex/interpreter/interpreter.tex +++ b/Master/texmf-dist/tex/luatex/interpreter/interpreter.tex @@ -1,7 +1,7 @@ % This is the main TeX file for the Interpreter package. % Further information in interpreter-doc.pdf or interpreter-doc.txt. % -% Paul Isambert - zappathustra AT free DOT fr - December 2011 +% Paul Isambert - zappathustra AT free DOT fr - June 2012 % \csname Oh no, Interpreter won't be loaded twice!\endcsname \expandafter\let\csname Oh no, Interpreter won't be loaded twice!\endcsname\endinput -- cgit v1.2.3