summaryrefslogtreecommitdiff
path: root/doc/context/sources/general/manuals/texit/texit-lookahead.tex
blob: d3652e7440166650d8e2d8d5796480da5444a1a1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
\environment texit-style

\startcomponent texit-lookahead

\startchapter[title={Lookahead}]

When you look at the \TEX\ source of a macro package, your can often see
constructs like this:

\startTEX
\def\foo#1%
  {We do something with  "#1".}
\stopTEX

or maybe:

\startTEX
\def\foo#1{%
    We do something with  "#1".%
}
\stopTEX

Normally the percentage symbol is used to indicate a comment, but here
are no comments. In these cases it makes the definition effectively

\startTEX
\def\foo#1{do something with "#1"!}
\stopTEX

which is different from when we would not have that percent sign there:

\startTEX
\def\foo#1 {We do something with "#1"!}
\stopTEX

That variant is valid \TEX\ code but expects a space as delimiter of the
argument to \type {\foo}. This means that you can say:

\startTEX
\foo{1} \foo 2 \foo {34} and \foo 56 .
\stopTEX

while this can trigger an error message (when no space is seen at some point) or
at least give unexpected results.

\startTEX
\foo{1}\foo 2\foo {34}and\foo 56.
\stopTEX

A different use of the percent is seen in cases like this:

\startTEX
\def\foo#1%
  {We do something %
   with "#1".}
\stopTEX

This time we want to preserve the space after \type {something} because an
end|-|of|-|line would either or not collapse it with \type {with} depending on
how the endofline character is set up. Normally:

\startTEX
\def\foo#1%
  {We do something
   with "#1".}
\stopTEX

Will also add a space after something but when \TEX\ is set up to ignore lines
you get a collapse. So the explicit space is a robust way out. Both cases of
using or omitting the comment symbol are easy to spot as they trigger an error
or result in weird typeset results.

\startbuffer[defs]
\def\fooA#1%
  {\ifnum#1>100
     yes\else nop%
   \fi}

\def\fooB#1{\ifnum#1>100 yes\else nop \fi}

\def\fooC#1%
  {\ifnum#1>100%
     yes\else nop%
   \fi}
\stopbuffer

\typebuffer[defs][option=TEX] \getbuffer[defs]

We test this with:

\startbuffer[demo]
\fooA{100} \fooB{100} \fooC{100}
\fooA{101} \fooB{101} \fooC{101}
\stopbuffer

\typebuffer[demo][option=TEX]

And the result is probably what you expect:

\startlines
\getbuffer[demo]
\stoplines

\startbuffer[defs]
\def\fooA#1%
  {\ifnum#1>100
     1\else 0%
   \fi}

\def\fooB#1{\ifnum#1>100 1\else 0\fi}

\def\fooC#1%
  {\ifnum#1>100%
     1\else 0%
   \fi}
\stopbuffer

However, when we have the following macro body:

\typebuffer[defs][option=TEX] \getbuffer[defs]

We get this output. Do you see the issue?

\startlines
\getbuffer[demo]
\stoplines

A preferred way to catch this is the following as a \type {\relax} ends scanning
for a number:

\startbuffer[defs]
\def\foo#1%
  {\ifnum#1>100\relax
     1\else 0%
   \fi}
\stopbuffer

\typebuffer[defs][option=TEX] \getbuffer[defs]

However, watch what happens here:

\startbuffer[demo]
\edef\result{\foo{123}}
\stopbuffer

\typebuffer[demo][option=TEX] \getbuffer[demo]

The \type {\result} macro has the following body:

\expanded{\setbuffer[result]\meaning\result\endbuffer}

\typebuffer[result][option=TEX]

A neat trick out of this is the following:

\startbuffer[defs]
\def\foo#1%
  {\ifnum#1>\numexpr100\relax
     1\else 0%
   \fi}
\stopbuffer

\typebuffer[defs][option=TEX] \getbuffer[defs]

\getbuffer[demo]

Now the body of \type {\result} looks like this:

\expanded{\setbuffer[result]\meaning\result\endbuffer}

\typebuffer[result][option=TEX]

Of course this also works:

\startTEX
\def\foo#1%
  {\ifnum#1>100 %
     1\else 0%
   \fi}
\stopTEX

as a space also delimits scanning the number. But that method can actually introduce
that space in the output. Think of this definition:

\startbuffer[defs]
\def\foo#1#2%
  {\ifnum#1>#2 %
     1\else 0%
   \fi}
\stopbuffer

\typebuffer[defs][option=TEX] \getbuffer[defs]

What if \type {#2} has a trailing space? What if it is a verbose number? What if
it is a counter variable?

\startbuffer[demo]
\scratchcounter=100
    [\foo{101}{100}] [\foo{101}{100 }] [\foo{101}\scratchcounter]
\scratchcounter=101
    [\foo{100}{101}] [\foo{100}{101 }] [\foo{100}\scratchcounter]
\stopbuffer

\typebuffer[demo][option=TEX]

\startlines
\getbuffer[demo]
\stoplines

If you really want to introduce an unpredictable situation, use a coding style like
this:

\startTEX
\def\foo#1#2#3#4{\if#1=#2#3\else#4\fi}
\stopTEX

This is not that imaginary as you often see users play safe and do things like this:

\startTEX
\ifnum\scratchcounterone=\scratchcountertwo%
    ...
\else
    ...
\fi
\stopTEX

Here the percent sign is useless as the number scanner already got the number,
just try:

\startTEX
\scratchcounterone=1
\scratchcountertwo=1

\ifnum\scratchcounterone=\scratchcountertwo
    yes
\else
    nop
\fi
\stopTEX

A previous one liner formatted like this really is not better!

\startTEX
\def\foo#1#2#3#4%
  {\ifnum#1=#2%
      #3%
   \else
      #4%
   \fi}
\stopTEX

When you define macros more often than not you don't want unexpected spaces (aka spurious spaces)
which is why in \CONTEXT\ for instance setups ignores lines:

\startbuffer[defs]
\startsetups foo
    here
    we ignore
    spaces at the end
    of a line
\stopsetups
\stopbuffer

\typebuffer[defs][option=TEX] \getbuffer[defs]

so we get: \quotation {\directsetup{foo}} which means that the normally few times
that we {\em do} want spaces we need to be explicit:

\startbuffer[defs]
\startsetups foo
    here\space
    we ignore\space
    spaces at the end\space
    of a line\space
\stopsetups
\stopbuffer

\typebuffer[defs][option=TEX] \getbuffer[defs]

Now we're okay: \quotation {\directsetup{foo}}. The same is true for:

\startTEX
\starttexdefinition foo
    here\space
    we ignore\space
    spaces at the end\space
    of a line\space
\stoptexdefinition
\stopTEX

There are more cases where \TEX\ will look further. Take for example skip (glue)
scanning. A glue specification can have \type {plus} and \type {minus} fields.

\startbuffer[defs]
\scratchdimenone=10pt
\scratchskipone =10pt plus 10pt minus 10pt
\scratchskiptwo =0pt
\stopbuffer

\typebuffer[defs][option=TEX]

Now take the following test:

\startbuffer[demo]
{1 \scratchskiptwo  10pt             plus 10pt \relax\the\scratchskiptwo}
{2 \scratchskiptwo  \scratchdimenone plus 10pt \relax\the\scratchskiptwo}
{3 \scratchskiptwo 1\scratchdimenone plus 10pt \relax\the\scratchskiptwo}
{4 \scratchskiptwo  \scratchskipone  plus 10pt \relax\the\scratchskiptwo}
{5 \scratchskiptwo 1\scratchskipone  plus 10pt \relax\the\scratchskiptwo}
\stopbuffer

\typebuffer[demo][option=TEX]

\startlines
\inlinebuffer[defs]\getbuffer[demo]
\stoplines

If you wonder what the second \type {\relax} does, here is a variant:

\startlines
{1 \scratchskiptwo  10pt             plus 10pt \the\scratchskiptwo}
{2 \scratchskiptwo  \scratchdimenone plus 10pt \the\scratchskiptwo}
{3 \scratchskiptwo 1\scratchdimenone plus 10pt \the\scratchskiptwo}
{4 \scratchskiptwo  \scratchskipone  plus 10pt \the\scratchskiptwo}
{5 \scratchskiptwo 1\scratchskipone  plus 10pt \the\scratchskiptwo}
\stoplines

\typebuffer[demo][option=TEX]

\startlines
\inlinebuffer[defs]\getbuffer[demo]
\stoplines

In this second variant \TEX\ happily keep looking for a glue specification when
it sees the \type {\the} so it serializes \type {\scratchskiptwo}. But as it sees
\type {0pt} then, it stops scanning the glue spec. What we get typeset is the old
value, not the new one! If you want to prevent this you need to \type {\relax}.

Another case where \TEX\ keeps scanning is the following:

\startbuffer[demo]
\vrule width 40pt height 2pt depth 5pt \quad
\vrule width 40pt height 20pt depth 5pt height 10pt \quad
\vrule width 40pt height 10pt height 20pt \quad
\vrule width 40pt height 20pt depth 5pt height 10pt width 80pt
\stopbuffer

\typebuffer[demo][option=TEX]

This gives the rules:

\startlinecorrection \darkgray
\getbuffer[demo]
\stoplinecorrection

So you can overload dimensions. The space before the \type {quad} is gobbled as
part of the look ahead for more keywords.

Often rules (just like glue assignments) are wrapped in macro definitions where the
macro writer used \type {\relax} to look ahead. That way you prevent an error message
in cases like:

\startTEX
\def\foo{\vrule width 40pt height 2pt}

The \foo depth of this thought is amazing.
\stopTEX

because \type {of} definitely is not a valid dimension. Even more subtle is:

\startTEX
\def\foo{\hskip 10pt plus 1fil}

The \foo fine points of typesetting can actually become a nightmare.
\stopTEX

As \TEX\ will now see the \type {f} of \type {fine} as further specification and
think that you want \type {1fill}.

So, the most important lesson of this chapter is that you need to be aware of the way
\TEX\ scans for quantities and specifications. In most cases the users can safely use
a \type {\relax} to prevent a lookahead. And try to avoid adding percent signs all
over the place.

\stopchapter

\stopcomponent