summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/doc/context/sources/general/manuals/lowlevel/lowlevel-conditionals.tex
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/doc/context/sources/general/manuals/lowlevel/lowlevel-conditionals.tex')
-rw-r--r--Master/texmf-dist/doc/context/sources/general/manuals/lowlevel/lowlevel-conditionals.tex182
1 files changed, 168 insertions, 14 deletions
diff --git a/Master/texmf-dist/doc/context/sources/general/manuals/lowlevel/lowlevel-conditionals.tex b/Master/texmf-dist/doc/context/sources/general/manuals/lowlevel/lowlevel-conditionals.tex
index ea3c9e1a244..9be2fb4ec6f 100644
--- a/Master/texmf-dist/doc/context/sources/general/manuals/lowlevel/lowlevel-conditionals.tex
+++ b/Master/texmf-dist/doc/context/sources/general/manuals/lowlevel/lowlevel-conditionals.tex
@@ -6,6 +6,8 @@
[title=conditionals,
color=middleblue]
+\pushoverloadmode
+
\startsection[title=Preamble]
\startsubsection[title=Introduction]
@@ -1121,13 +1123,15 @@ This test is like \type {\ifcmpnum} but for dimensions.
\startsubsection[title={\tex{ifchkdim}}]
-This test is like \type {\ifchknum} but for dimensions.
+This test is like \type {\ifchknum} but for dimensions. The last checked value is
+available as \type {\lastchknum}.
\stopsubsection
\startsubsection[title={\tex{ifdimval}}]
-This test is like \type {\ifnumval} but for dimensions.
+This test is like \type {\ifnumval} but for dimensions. The last checked value is
+available as \type {\lastchkdim}
\stopsubsection
@@ -1224,6 +1228,15 @@ defined at the user level or is a build in one. This one might evolve.
\stopsubsection
+\startsubsection[title={\tex{ifarguments}}]
+
+This conditional can be used to check how many arguments were matched. It only
+makes sense when used with macros defined with the \type {\tolerant} prefix
+and|/|or when the sentinel \type {\ignorearguments} after the arguments is used.
+More details can be found in the lowlevel macros manual.
+
+\stopsubsection
+
\startsubsection[title={\tex{orelse}}]
This it not really a test primitive but it does act that way. Say that we have this:
@@ -1254,13 +1267,16 @@ A bit nicer looks this:
\fi
\stoptyping
-We stay at the same level and the only test that cannot be used this way is \type
-{\ifcondition} but that is no real problem. Sometimes a more flat test tree had
-advantages but if you think that it gives better performance then you will be
-disappointed. The fact that we stay at the same level is compensated by a bit
-more parsing, so unless you have millions such cases (or expansions) it might
-make a bit of a difference. As mentioned, I'm a bit sensitive for how code looks so
-that was the main motivation for introducing it.
+% We stay at the same level and the only test that cannot be used this way is \type
+% {\ifcondition} but that is no real problem. Sometimes a more flat test tree had
+
+We stay at the same level. Sometimes a more flat test tree had advantages but if
+you think that it gives better performance then you will be disappointed. The
+fact that we stay at the same level is compensated by a bit more parsing, so
+unless you have millions such cases (or expansions) it might make a bit of a
+difference. As mentioned, I'm a bit sensitive for how code looks so that was the
+main motivation for introducing it. There is a companion \type {\orunless}
+continuation primitive.
A rather neat trick is the definition of \type {\quitcondition}:
@@ -1294,18 +1310,23 @@ reason to go this complex but obscure \TEX\ code attracts some users so \unknown
When you have a macro that has for instance assignments, and when you expand that
macro inside an \type {\edef}, these assignments are not actually expanded but
-tokenized. In \LUATEX\ there is a way to immediately apply these assignments and
-that feature can be used to write a fully expandable user test. For instance:
+tokenized. In \LUAMETATEX\ there is a way to apply these assignments without side
+effects and that feature can be used to write a fully expandable user test. For
+instance:
\startbuffer
\def\truecondition {\iftrue}
\def\falsecondition{\iffalse}
\def\fontwithidhaschar#1#2%
- {\immediateassignment\scratchcounter\numexpr\fontid\font\relax
- \immediateassignment\setfontid\numexpr#1\relax
+ {\beginlocalcontrol
+ \scratchcounter\numexpr\fontid\font\relax
+ \setfontid\numexpr#1\relax
+ \endlocalcontrol
\iffontchar\font\numexpr#2\relax
- \immediateassignment\setfontid\scratchcounter
+ \beginlocalcontrol
+ \setfontid\scratchcounter
+ \endlocalcontrol
\expandafter\truecondition
\else
\expandafter\falsecondition
@@ -1394,6 +1415,125 @@ with \type {\ifcondition} (it has bitten me already a few times).
\stopsection
+\startsection[title=Relaxing]
+
+When \TEX\ scans for a number or dimension it has to check tokens one by one. On
+the case of a number, the scanning stops when there is no digit, in the case of a
+dimension the unit determine the end of scanning. In the case of a number, when a
+token is not a digit that token gets pushed back. When digits are scanned a
+trailing space or \type {\relax} is pushed back. Instead of a number of dimension
+made from digits, periods and units, the scanner also accepts registers, both the
+direct accessors like \type {\count} and \type {\dimen} and those represented by
+one token. Take these definitions:
+
+\startbuffer
+\newdimen\MyDimenA \MyDimenA=1pt \dimen0=\MyDimenA
+\newdimen\MyDimenB \MyDimenB=2pt \dimen2=\MyDimenB
+\stopbuffer
+
+\typebuffer \getbuffer
+
+I will use these to illustrate the side effects of scanning. Watch the spaces
+in the result.
+
+% \startbuffer[a]
+% \testfeatureonce{1000000}{
+% \whatever{1pt}{2pt}%
+% \whatever{1pt}{1pt}%
+% \whatever{\dimen0}{\dimen2}%
+% \whatever{\dimen0}{\dimen0}%
+% \whatever\MyDimenA\MyDimenB
+% \whatever\MyDimenA\MyDimenB
+% } \elapsedtime
+% \stopbuffer
+
+\startbuffer[b]
+\starttabulate[|T|T|]
+\NC \type {\whatever{1pt}{2pt}} \NC \edef\temp{\whatever {1pt}{2pt}}[\meaning\temp] \NC \NR
+\NC \type {\whatever{1pt}{1pt}} \NC \edef\temp{\whatever {1pt}{1pt}}[\meaning\temp] \NC \NR
+\NC \type {\whatever{\dimen0}{\dimen2}} \NC \edef\temp{\whatever{\dimen0}{\dimen2}}[\meaning\temp] \NC \NR
+\NC \type {\whatever{\dimen0}{\dimen0}} \NC \edef\temp{\whatever{\dimen0}{\dimen0}}[\meaning\temp] \NC \NR
+\NC \type {\whatever\MyDimenA\MyDimenB} \NC \edef\temp{\whatever\MyDimenA\MyDimenB}[\meaning\temp] \NC \NR
+\NC \type {\whatever\MyDimenA\MyDimenB} \NC \edef\temp{\whatever\MyDimenA\MyDimenB}[\meaning\temp] \NC \NR
+\stoptabulate
+\stopbuffer
+
+First I show what effect we want to avoid. When second argument contains a number
+(digits) the zero will become part of it so we actually check \type {\dimen00}
+here.
+
+\startbuffer[c]
+\def\whatever#1#2%
+ {\ifdim#1=#20\else1\fi}
+\stopbuffer
+
+\typebuffer[c] \getbuffer[c,b]
+
+The solution is to add a space but watch how that one can end up in the result:
+
+\startbuffer[c]
+\def\whatever#1#2%
+ {\ifdim#1=#2 0\else1\fi}
+\stopbuffer
+
+\typebuffer[c] \getbuffer[c,b]
+
+A variant is using \type {\relax} and this time we get this token retained in
+the output.
+
+\startbuffer[c]
+\def\whatever#1#2%
+ {\ifdim#1=#2\relax0\else1\fi}
+\stopbuffer
+
+\typebuffer[c] \getbuffer[c,b]
+
+A solution that doesn't have side effects of forcing the end of a number (using a
+space or \type {\relax} is one where we use expressions. The added overhead of
+scanning expressions is taken for granted because the effect is what we like:
+
+\startbuffer[c]
+\def\whatever#1#2%
+ {\ifdim\dimexpr#1\relax=\dimexpr#2\relax0\else1\fi}
+\stopbuffer
+
+\typebuffer[c] \getbuffer[c,b]
+
+Just for completeness we show a more obscure trick: this one hides assignments to
+temporary variables. Although performance is okay, it is the least efficient
+one so far.
+
+\ifdefined\beginlocalcontrol
+
+\startbuffer[c]
+\def\whatever#1#2%
+ {\beginlocalcontrol
+ \MyDimenA#1\relax
+ \MyDimenB#2\relax
+ \endlocalcontrol
+ \ifdim\MyDimenA=\MyDimenB0\else1\fi}
+\stopbuffer
+
+\typebuffer[c] \getbuffer[c,b]
+
+\fi
+
+It is kind of a game to come up with alternatives but for sure those involve
+dirty tricks and more tokens (and runtime). The next can be considered a dirty
+trick too: we use a special variant of \type {\relax}. When a number is scanned
+it acts as relax, but otherwise it just is ignored and disappears.
+
+\ifdefined\norelax\else\let\norelax\relax\fi
+
+\startbuffer[c]
+\def\whatever#1#2%
+ {\ifdim#1=#2\norelax0\else1\fi}
+\stopbuffer
+
+\typebuffer[c] \getbuffer[c,b]
+
+\stopsection
+
\startsubject[title=Colofon]
\starttabulate
@@ -1406,4 +1546,18 @@ with \type {\ifcondition} (it has bitten me already a few times).
\stopsubject
+\popoverloadmode
+
\stopdocument
+
+% \def\foo{foo=bar}
+% \def\oof{foo!bar}
+% \scratchtoks{=}
+
+% \ifhasxtoks\scratchtoks{foo!bar} YES\else NOP\fi\par
+% \ifhasxtoks\scratchtoks{foo=bar} YES\else NOP\fi\par
+
+% \showluatokens\foo
+
+% \ifhastoks\scratchtoks\oof YES\else NOP\fi\par
+% \ifhastoks\scratchtoks\foo YES\else NOP\fi\par