diff options
Diffstat (limited to 'Master/texmf-dist/tex/luatex/optex/if-macros.opm')
-rw-r--r-- | Master/texmf-dist/tex/luatex/optex/if-macros.opm | 215 |
1 files changed, 172 insertions, 43 deletions
diff --git a/Master/texmf-dist/tex/luatex/optex/if-macros.opm b/Master/texmf-dist/tex/luatex/optex/if-macros.opm index 5e56503bd87..601c4fbee7c 100644 --- a/Master/texmf-dist/tex/luatex/optex/if-macros.opm +++ b/Master/texmf-dist/tex/luatex/optex/if-macros.opm @@ -1,15 +1,18 @@ %% This is part of OpTeX project, see http://petr.olsak.net/optex -\_codedecl \newif {Special if-macros, is-macros and loops <2020-02-27>} % preloaded in format +\_codedecl \newif {Special if-macros, is-macros and loops <2020-04-15>} % preloaded in format \_doc ---------------------------- - The `\newif` macro works like in plain \TeX. It means that + \secc Classical \code{\\newif} + The \`\newif` macro implements boolean value. + It works as in plain \TeX. It means that after `\newif\ifxxx` you can use `\xxxtrue` or `\xxxfalse` to set the boolean value and use `\ifxxx true\else false\fi` - to test this value. The defalut value is false. + to test this value. The default value is false. - The macro `\_newifi` enables to declare `\_ifxxx` and to use `\_xxxtrue` and - `\_xxxfalse`. This means that it is usable for _prefixed macros. + The macro \`\_newifi` enables to declare `\_ifxxx` and to use `\_xxxtrue` and + `\_xxxfalse`. This means that it is usable for internal name space + (`_`prefixed macros). \_cod ---------------------------- \_def\_newif #1{\_ea\_newifA \_string #1\_relax#1} @@ -24,57 +27,145 @@ \_sdef{_#1false}{\_let#2=\_iffalse}% \_let#2=\_iffalse } +\_public \newif ; \_doc ---------------------------- - The `\loop <codeA> \ifsomething <codeB> \repeat` loops `<codeA> <codeB>` + \secc Loops + The \`\loop` `<codeA> \ifsomething <codeB>` \`\repeat` loops `<codeA><codeB>` until `\ifsomething` is false. Then `<codeB>` is not executed and loop is - finished. This works like in plain \TeX, but implementation is soewhat + finished. This works like in plain \TeX, but implementation is somewhat better (you can use `\else` clause after the `\ifsomething`). There are public version `\loop...\repeat` and private version - `\_loop...\_repeat`. You canot mix both versions in one loop. + \`\_loop` ...\`\_repeat`. You cannot mix both versions in one loop. + + The `\loop` macro keeps its original plain TeX meaning. It is not + expandable and nested `\loop`s are possible only in a \TeX/ group. \_cod ---------------------------- -\_def \_loop #1\_repeat{\_def\_body{#1}\_iterate} +\_long\_def \_loop #1\_repeat{\_def\_body{#1}\_iterate} \_def \loop #1\repeat{\_def\_body{#1}\_iterate} \_let \_repeat=\_fi % this makes \loop...\if...\repeat skippable \_let \repeat=\_fi \_def \_iterate {\_body \_ea \_iterate \_fi} + \_doc ----------------------------- + \`\foreach` `<list>` \`\do` `{<what>}` + repeats `<what>` for each element of the + `<list>`. The `<what>` can include `#1` which is substituted by each + element of the `<list>`. The macro is expandable. + + \`\fornum` `<from>..<to>` \`\do` `{<what>}` or + \`\fornumstep` `<num>: <from>..<to>` \`\do` `{<what>}` + repeats `<what>` for each number from `<from>` to `<to>` (with step `<num>` + or with step one). The `<what>` can include `#1` which is substituted by + current number. The sequence `<from>..<to>` can be decreasing too. + The macro is expandable. + + Recommendation: it is better to + use private variants of \`\_foreach` and \`\_fornum`. + When the user writes `\input tikz` then `\foreach` macro is redefined! The + private variants use \`\_do` separator instead `\do` separator. + \_cod ----------------------------- + +\_newcount\_frnum % the numeric variable used in \fornum +\_def\_do{\_doundefined} % we need to ask \_ifx#1\_do ... + +\_long\_def\_foreach #1\_do#2{\_putforstack + \_immediateassignment\_def\_fbody##1{#2}% + \_foreachA #1\_do} +\_long\_def\_foreachA #1{\_ifx\_do#1\_getforstack\_else\_fbody{#1}\_ea\_foreachA\_fi} + +\_def\_fornum#1..#2\_do{\_fornumstep 1:#1..#2\_do} +\_long\_def\_fornumstep#1:#2..#3\_do#4{\_putforstack + \_immediateassigned{% + \_def\_fbody##1{#4}% + \_def\_fornumsgn{}% + \_def\_fornumrel{<}% + \_frnum=\_numexpr#2\_relax + \_ifnum\_numexpr#3<\_frnum \_def\_fornumrel{>}\_fi %decreasing sequence + \_ifnum\_numexpr#1\_fornumrel0 \_def\_fornumsgn{-}\_fi % correction + }% + \_fornumB{#3}{#1}% +} +\_def\_fornumB #1#2{\_ifnum\_numexpr#1\_fornumrel\_frnum \_getforstack \_else + \_ea\_fbody\_ea{\_the\_frnum}% + \_immediateassignment\_advance\_frnum by\_numexpr\_fornumsgn#2\_relax + \_afterfi{\_fornumB{#1}{#2}}\_fi +} +\_def\_afterfi#1#2\_fi{\_fi#1} + +\_def\foreach #1\do{\_foreach #1\_do} +\_def\fornum#1..#2\do{\_fornumstep 1:#1..#2\_do} +\_def\fornumstep#1:#2..#3\do{\_fornumstep #1:#2..#3\_do} + \_doc ---------------------------- - The macro `\isnextchar <char>{<codeA>}{<codeB>}` executes `<codeA>` if next - character is equal to <char>. Else the `<codeB>` is executed. The macro is - not expandable. + The `\foreach` and `\fornum` macros can be nested and arbitrary combined. + When they are nested then use `##1` for the variable of nested level, + `####1` for the variable of second nested level etc. Example: + \begtt + \foreach ABC \do {\fornum 1..5 \do {letter:#1, number: ##1. }} + \endtt + Implementation note: + we cannot use \TeX/-groups for nesting levels because we want to do the + macros expandable. We must implement a special for-stack which saves the + data needed by `\foreach` and `\fornum`. The \`\_putforstack` is used + when `\for*` is initialized and \`\_getforstack` is used when the + `\for*` macro ends. The \`\_forlevel` variable keeps the current nesting + level. If it is zero, then we need not save nor restore any data. \_cod ---------------------------- -\_long\_def\_isnextchar#1#2#3{\_begingroup\_toks0={\_endgroup#2}\_toks1={\_endgroup#3}% - \_let\_tmp=#1\_futurelet\_next\_isnextcharA -} -\_def\_isnextcharA{\_the\_toks\_ifx\_tmp\_next0\_else1\_fi\_space} +\_newcount\_forlevel +\_def\_putforstack{\_immediateassigned{% + \_ifnum\_forlevel>0 + \_sdef{_frnum:\_the\_forlevel\_ea}\_ea{\_the\_frnum}% + \_slet{_fbody:\_the\_forlevel}{_fbody}% + \_fi + \_advance\_forlevel by1 +}} +\def\_getforstack{\_immediateassigned{% + \_advance\_forlevel by-1 + \_ifnum\_forlevel>0 + \_slet{_fbody}{_fbody:\_the\_forlevel}% + \_frnum=\_cs{_frnum:\_the\_forlevel}\_space + \_fi +}} \_doc ---------------------------- - The macro `\isempty{<text>}\iftrue <codeA>\else <codeB>\fi` executes <codeA> - if <text> is empty and <codeB> if it is non-empty. You can use - `\isempty{<text>}\iffalse <codeB>\else <codeA>\fi` too. This macro is - expandable. + \secc Is-macros + There are a collection of macros + `\isempty`, `\istoksempty`, `\isequal`, `\ismacro`, `\isdefined`, `\isinlist` and `\isfile` + with common syntax: + \begtt \catcode`\<=13 + \issomething <params> \iftrue <codeA> \else <codeB> \fi + or + \issomething <params> \iffalse <codeB> \else <codeA> \fi + \endtt + The `\else` part is optional. The `<codeA>` is processed if + `\issomething<params>` generates true condition. The `<codeB>` + is processed if `\issomething<params>` generates false condition. - There are a collection of macros with commnon syntax: - `\issomething<params>\iftrue` or `\issomething<params>\iffalse`. - The `\iftrue` or `\iffalse` is a part of this syntax because we need to keep - skippable nested `\if` conditions. + The `\iftrue` or `\iffalse` is an integral part of this syntax + because we need to keep skippable nested `\if` conditions. - We read this `\iftrue` or `\iffalse` into unseparated parameter and repeat + Implementation note: + we read this `\iftrue` or `\iffalse` into unseparated parameter and repeat it because we need to remove an optional space before this command. + + \medskip\noindent + \`\isempty` `{<text>}\iftrue` + is true if the `<text>` is empty. This macro is expandable.\nl + \`\istoksempty` `<tokens variable>\iftrue` + is true if the `<tokens variable>` is empty. It is expandable. \_cod ---------------------------- -\_def \_isempty #1#2{\_ea\_ifx\_ea\_relax\_detokenize{#1}\_relax - \_else \_ea\_unless \_fi #2} -\_def \_isnoempty #1#2{\_ea\_ifx\_ea\_relax\_detokenize{#1}\_relax - \_ea\_unless \_fi #2} -\_def \_istoksempty #1{\_ea\_isempty\_ea{\_the#1}} +\_def \_isempty #1#2{\_if\_relax\_detokenize{#1}\_relax \_else \_ea\_unless \_fi#2} +\_def \_istoksempty #1#2{\_ea\_isempty\_ea{\_the#1}#2} +\_public \isempty \istoksempty ; \_doc ---------------------------- - `\isequal{<textA>}{<textB>}\iftrue` is true if the <textA> and <textB> are + \`\isequal` `{<textA>}{<textB>}\iftrue` + is true if the <textA> and <textB> are equal, only from strings point of view, category codes are ignored. The macro is expandable. \_cod ---------------------------- @@ -82,47 +173,85 @@ \_def\_isequal#1#2#3{\_directlua{% if "\_luaescapestring{\_detokenize{#1}}"=="\_luaescapestring{\_detokenize{#2}}" then else tex.print("\_nbb unless") end}#3} +\_public \isequal ; \_doc ---------------------------- - `\ismacro\macro{text}\iftrue` is true if macro is defined as {<text>}. + \`\ismacro` `\macro{text}\iftrue` is true if macro is defined as {<text>}. Category codes are ignored in this testing. The macro is expandable. \_cod ---------------------------- \_def\_ismacro#1{\_ea\_isequal\_ea{#1}} +\_public \ismacro ; \_doc ---------------------------- - `\isinlist\list{<text>}\iftrue` is true if the - `<text>` is included the macro body of the `\list`. - The catogory code are relevant here. THe macro is not expandable. + \`\isdefined` `{<csname>}\iftrue` is true if `\<csname>` is defined. + The macro is expandable. \_cod ---------------------------- \_def\_isdefined #1#2{\_ifcsname #1\_endcsname \_else \_ea\_unless \_fi #2} +\_public \isdefined ; \_doc ---------------------------- - `\isdefined{<csname>}\iftrue` is true if `\<csname>` is defined. + \`\isinlist` `\list{<text>}\iftrue` is true if the + `<text>` is included the macro body of the `\list`. + The category code are relevant here. The macro is not expandable. \_cod ---------------------------- \_long\_def\_isinlist#1#2{\_begingroup - \_long\_def\_tmp##1#2##2\_end/_{\_endgroup\_isnoempty{##2}}% + \_long\_def\_tmp##1#2##2\_end/_% + {\_endgroup\_if\_relax\_detokenize{##2}\_relax \_ea\_unless\_fi}% \_ea\_tmp#1\_endlistsep#2\_end/_% } +\_public \isinlist ; - \_doc ---------------------------- - `\isfile{<filename>}\iftrue` is true if the file <filename> exists and are + \_doc ----------------------------- + \`\isfile` `{<filename>}\iftrue` is true if the file <filename> exists and are readable by \TeX. - \_cod \_fin ---------------------- + \_cod ----------------------------- \_newread \_testin - \_def\_isfile #1{% \_openin\_testin ={#1}\_relax \_ifeof\_testin \_ea\_unless \_else \_closein\_testin \_fi } +\_public \isfile ; + + \_doc ----------------------------- + \`\isfont` `{<fontname or [fontfile]>}\iftrue` + is true if given font exists. The result of this testing + is saved to the \`\_ifexistfam`. + \_cod ----------------------------- + +\_newifi \_ifexistfam +\_def\_isfont#1#2{% + \_begingroup + \_suppressfontnotfounderror=1 + \_font\_testfont={#1}\_relax + \_ifx\_testfont\_nullfont \_def\_tmp{\_existfamfalse \_unless} + \else \_def\_tmp{\_existfamtrue}\_fi + \_ea \_endgroup \_tmp #2% +} +\_public \isfont ; + + \_doc ---------------------------- + The last macro \`\isnextchar` `<char>{<codeA>}{<codeB>}` + has different syntax than all others is-macros. + It executes `<codeA>` if next character is equal to <char>. + Else the `<codeB>` is executed. The macro is not expandable. + \_cod ---------------------------- + +\_long\_def\_isnextchar#1#2#3{\_begingroup\_toks0={\_endgroup#2}\_toks1={\_endgroup#3}% + \_let\_tmp=#1\_futurelet\_next\_isnextcharA +} +\_def\_isnextcharA{\_the\_toks\_ifx\_tmp\_next0\_else1\_fi\_space} + +\_public \isnextchar ; -\_public - \newif \isnextchar \isempty \isequal \ismacro \isdefined \isinlist \isfile ; \_endcode +2020-04-15 \fornumstep 3: 1..12 instead \fornum 1..12\step 3 +2020-04-15 \fornum, \foreach can be nested without groups +2020-04-01 implemented |