cld-scanners.tex /size: 24 Kb    last modification: 2021-10-28 13:50
1% language=us runpath=texruns:manuals/cld
2
3\startcomponent cld-ctxscanners
4
5\environment cld-environment
6
7\startchapter[title={Scanners}]
8
9\startsection[title={Introduction}]
10
11\index {implementors}
12\index {scanners}
13
14Here we discuss methods to define macros that directly interface with the \LUA\
15side. It involves all kind of scanners. There are actually more than we discuss
16here but some are meant for low level usage. What is describe here has been used
17for ages and works quite well.
18
19{\em We don't discuss some of the more obscure options here. Some are there just
20because we need them as part of bootstrapping or initializing code and are of no
21real use to users.}
22
23\stopsection
24
25\startsection[title={A teaser first}]
26
27Most of this chapter is examples and you learn \TEX\ (and \LUA) best by just
28playing around. The nice thing about \TEX\ is that it's all about visual output,
29so that's why in the next examples we just typeset some of what we just scanned.
30Of course in practice the \type {actions} will be more complex.
31
32\unexpanded\def\showmeaning#1%
33  {\begingroup
34   \dontleavehmode
35   \ttbf\string #1\space
36   \tttf\meaning#1%
37   \endgroup}
38
39\startbuffer[definition]
40\startluacode
41    interfaces.implement {
42        name      = "MyMacroA",
43        public    = true,
44        permanent = false,
45        arguments = "string",
46        actions   = function(s)
47            context("(%s)",s)
48        end,
49    }
50\stopluacode
51\stopbuffer
52
53\startbuffer[usage]
54\MyMacroA{123}
55\MyMacroA{abc}
56\edef\temp{\MyMacroA{abc}}
57\stopbuffer
58
59\typebuffer[definition] \getbuffer[definition]
60
61By default a macro gets defined in the \type {\clf_} namespace but the \type
62{public} option makes it visible. This default indicates that it is actually a
63low level mechanism in origin. More often than not these interfaces are used like
64this:
65
66\starttyping
67\def\MyMacro#1{... \clf_MyMacroA{#1} ...}
68\stoptyping
69
70When we look at the meaning of \type {\MyMacroA} we get:
71
72\blank \showmeaning\MyMacroA \blank
73
74And when we apply this macro as:
75
76\typebuffer[usage]
77
78We get
79
80\blank \getbuffer[usage] \blank
81
82The meaning of \type {\temp} is:
83
84\blank \showmeaning\temp \blank
85
86We can also define the macro to be protected (\type {\unexpanded}) in \CONTEXT\
87speak). We can overload existing scanners but unless we specify the \type
88{overload} option, we get a warning on the console. However, in \LMTX\ there is
89catch. Implementers by default define macros as permanent unless one explicitly
90disables this so this is why in the previous definition we have done so. The
91overload flag below only makes sense in special cases, when for instance format
92file is made. (Of course overload protection only kicks in when it has been
93enabled.)
94
95\startbuffer[definition]
96\startluacode
97    interfaces.implement {
98        name      = "MyMacroA",
99        public    = true,
100     -- overload  = true,
101        protected = true,
102        arguments = "string",
103        actions   = function(s)
104            context("[%s]",s)
105        end,
106    }
107\stopluacode
108\stopbuffer
109
110\typebuffer[definition] \getbuffer[definition]
111
112This time we get:
113
114\getbuffer[usage]
115
116The meaning of \type {\temp} is:
117
118\blank \showmeaning\temp \blank
119
120\stopsection
121
122\startsection[title={Basic data types}]
123
124\index {implementors+arguments}
125
126It is actually possible to write very advanced scanners but unless you're in for
127obscurity the limited subset discussed here is normally enough. The \CONTEXT\
128user interface is rather predictable, unless you want to show off with weird
129additional interfaces, for instance by using delimiters other than curly braces
130and brackets, or by using separators other than commas.
131
132\startbuffer[definition]
133\startluacode
134    interfaces.implement {
135        name      = "MyMacroB",
136        public    = true,
137        arguments = { "string", "integer", "boolean", "dimen" },
138        actions   = function(s,i,b,d)
139            context("<%s> <%i> <%l> <%p>",s,i,b,d)
140        end,
141    }
142\stopluacode
143\stopbuffer
144
145\typebuffer[definition] \getbuffer[definition]
146
147This time we grab four arguments, each of a different type:
148
149\startbuffer[usage]
150\MyMacroB{foo} 123 true 45.67pt
151
152\def\temp       {oof}
153\scratchcounter 321
154\scratchdimen   76.54pt
155
156\MyMacroB\temp \scratchcounter false \scratchdimen
157\stopbuffer
158
159\typebuffer[usage]
160
161The above usage gives:
162
163\getbuffer[usage]
164
165As you can see, registers can be used as well, and the \type {\temp} macro is
166also accepted as argument. The integer and dimen arguments scan standard \TEX\
167values. If you want a \LUA\ number you can specify that as well. As our first
168example showed, when there is one argument you don't need an array to specify
169it.
170
171\startbuffer[definition]
172\startluacode
173    interfaces.implement {
174        name      = "MyMacroC",
175        public    = true,
176        arguments = "number",
177        actions   = function(f)
178            context("<%.2f>",f)
179        end,
180    }
181\stopluacode
182\stopbuffer
183
184\typebuffer[definition] \getbuffer[definition]
185
186\startbuffer[usage]
187\MyMacroC 1.23
188\MyMacroC 1.23E4
189\MyMacroC -1.23E4
190\MyMacroC 0x1234
191\stopbuffer
192
193As you can see, hexadecimal numbers are also accepted:
194
195\typebuffer[usage]
196
197The above usage gives:
198
199\getbuffer[usage]
200
201\stopsection
202
203\startsection[title={Tables}]
204
205\index {implementors+tables}
206
207A list can be grabbed too. The individual items are separated by spaces and
208items can be bound by braces.
209
210\startbuffer[definition]
211\startluacode
212    interfaces.implement {
213        name      = "MyMacroD",
214        public    = true,
215        arguments = "list",
216        actions   = function(t)
217            context("< % + t >",t)
218        end,
219    }
220\stopluacode
221\stopbuffer
222
223\typebuffer[definition] \getbuffer[definition]
224
225\startbuffer[usage]
226\MyMacroD { 1 2 3 4 {5 6} }
227\stopbuffer
228
229The macro call:
230
231\typebuffer[usage]
232
233results in:
234
235\getbuffer[usage]
236
237Often in \LUA\ scripts tables are uses all over the place. Picking up a table is
238also supported by the implementer.
239
240\startbuffer[definition]
241\startluacode
242    interfaces.implement {
243        name      = "MyMacroE",
244        public    = true,
245        arguments = {
246            {
247                { "bar", "integer" },
248                { "foo", "dimen" },
249            }
250        },
251        actions   = function(t)
252            context("<foo : %p> <bar : %i>",t.foo,t.bar)
253        end,
254    }
255\stopluacode
256\stopbuffer
257
258\typebuffer[definition] \getbuffer[definition]
259
260\startbuffer[usage]
261\MyMacroE {
262    foo 12pt
263    bar 34
264}
265\stopbuffer
266
267Watch out, we don't use equal signs and commas here:
268
269\typebuffer[usage]
270
271We get:
272
273\getbuffer[usage]
274
275All the above can be combined:
276
277\startbuffer[definition]
278\startluacode
279    interfaces.implement {
280        name      = "MyMacroF",
281        public    = true,
282        arguments = {
283            "string",
284            {
285                { "bar", "integer" },
286                { "foo", "dimen" },
287            },
288            {
289                { "one", "string" },
290                { "two", "string" },
291            },
292        },
293        actions   = function(s,t1,t2)
294            context("<%s> <%p> <%i> <%s> <%s>",s,t1.foo,t1.bar,t2.one,t2.two)
295        end,
296    }
297\stopluacode
298\stopbuffer
299
300\typebuffer[definition] \getbuffer[definition]
301
302\startbuffer[usage]
303\MyMacroF
304    {oeps}
305    { foo 12pt bar 34 }
306    { one {x} two {y} }
307\stopbuffer
308
309The following call:
310
311\typebuffer[usage]
312
313Results in one string and two table arguments.
314
315\getbuffer[usage]
316
317You can nest tables, as in:
318
319\startbuffer[definition]
320\startluacode
321    interfaces.implement {
322        name      = "MyMacroG",
323        public    = true,
324        arguments = {
325            "string",
326            "string",
327            {
328                { "data", "string" },
329                { "tab", "string" },
330                { "method", "string" },
331                { "foo", {
332                    { "method", "integer" },
333                    { "compact", "number" },
334                    { "nature" },
335                    { "*" }, -- any key
336                } },
337                { "compact", "string", "tonumber" },
338                { "nature", "boolean" },
339                { "escape" },
340            },
341            "boolean",
342        },
343        actions   = function(s1, s2, t, b)
344            context("<%s> <%s>",s1,s2)
345            context("<%s> <%s> <%s>",t.data,t.tab,t.compact)
346            context("<%i> <%s> <%s>",t.foo.method,t.foo.nature,t.foo.whatever)
347            context("<%l>",b)
348        end,
349    }
350\stopluacode
351\stopbuffer
352
353\typebuffer[definition] \getbuffer[definition]
354
355\startbuffer[usage]
356\MyMacroG
357    {s1}
358    {s2}
359    {
360        data    {d}
361        tab     {t}
362        compact {12.34}
363        foo     { method 1 nature {n} whatever {w} }
364    }
365    true
366\relax
367\stopbuffer
368
369Although the \type {\relax} is not really needed in the next calls, I often use
370it to indicate that we're done:
371
372\typebuffer[usage]
373
374This typesets:
375
376\getbuffer[usage]
377
378\stopsection
379
380\startsection[title=Expansion]
381
382\index {implementors+expansion}
383
384When working with scanners it is important to realize that we have to do with an
385expansion engine. When \TEX\ picks up a token, it can be done as-is, that is the
386raw token, but it can also expand that token first (which can be recursive) and
387then pick up the first token that results from that. Sometimes you want that
388expansion, for instance when you pick up keywords, sometimes you don't.
389
390Expansion effects are most noticeable when we pickup a \quote {string} kind of
391value. In the implementor we have two methods for that: \type {string} and \type
392{argument}. The argument method has an expandable form (the default) and one
393that doesn't expand. Take this:
394
395\startbuffer[definition]
396\startluacode
397    interfaces.implement {
398        name      = "MyMacroH",
399        public    = true,
400        arguments = {
401            "string",
402            "argument",
403            "argumentasis",
404        },
405        actions   = function(a,b,c)
406            context.type(a or "-") context.quad()
407            context.type(b or "-") context.quad()
408            context.type(c or "-") context.crlf()
409        end,
410    }
411\stopluacode
412\stopbuffer
413
414\typebuffer[definition] \getbuffer[definition]
415
416Now take this input: % we use \C* because \c is already defined
417
418\startbuffer[usage]
419\def\Ca{A} \def\Cb{B} \def\Cc{C}
420\MyMacroH{a}{b}{c}
421\MyMacroH{a\Ca}{b\Cb}{c\Cc}
422\MyMacroH\Ca\Cb\Cc\relax
423\MyMacroH\Ca xx\relax
424\stopbuffer
425
426\typebuffer[usage]
427
428We we use the string method we need a \type {\relax} (or some spacer) to end
429scanning of the string when we don't use curly braces. The last line is
430actually kind of tricky because the macro expects two arguments after
431scanning the first string.
432
433\blank {\getbuffer[usage]} \blank
434
435\startbuffer[definition]
436\startluacode
437    interfaces.implement {
438        name      = "MyMacroI",
439        public    = true,
440        arguments = {
441            "argument",
442            "argumentasis",
443        },
444        actions   = function(a,b,c)
445            context.type(a or "-") context.quad()
446            context.type(b or "-") context.quad()
447            context.type(c or "-") context.crlf()
448        end,
449    }
450\stopluacode
451\stopbuffer
452
453Here is a variant:
454
455\typebuffer[definition] \getbuffer[definition]
456
457\startbuffer[usage]
458\def\a{A} \def\b{B}
459\MyMacroI{a}{b}
460\MyMacroI{a\a}{b\b}
461\MyMacroI\a\b\relax
462\stopbuffer
463
464With:
465
466\typebuffer[usage]
467
468we get:
469
470\blank {\getbuffer[usage]} \blank
471
472\stopsection
473
474\startsection[title=Boxes]
475
476\index {implementors+boxes}
477
478You can pick up a box too. The value returned is a list node:
479
480\startbuffer[definition]
481\startluacode
482    interfaces.implement {
483        name      = "MyMacroJ",
484        public    = true,
485        arguments = "box",
486        actions   = function(b)
487            context(b)
488        end,
489    }
490\stopluacode
491\stopbuffer
492
493\typebuffer[definition] \getbuffer[definition]
494
495The usual box specifiers are supported:
496
497\startbuffer[usage]
498\MyMacroJ \hbox        {\strut Test 1}
499\MyMacroJ \hbox to 4cm {\strut Test 2}
500\stopbuffer
501
502So, with:
503
504\typebuffer[usage]
505
506we get:
507
508\blank {\forgetall\dontcomplain\getbuffer[usage]} \blank
509
510There are three variants that don't need the box operator \type {hbox}, \type
511{vbox} and \type {vtop}:
512
513\startbuffer[definition]
514\startluacode
515    interfaces.implement {
516        name      = "MyMacroL",
517        public    = true,
518        arguments = {
519            "hbox",
520            "vbox",
521        },
522        actions   = function(h,v)
523            context(h)
524            context(v)
525        end,
526    }
527\stopluacode
528\stopbuffer
529
530\typebuffer[definition] \getbuffer[definition]
531
532Again, the usual box specifiers are supported:
533
534\startbuffer[usage]
535\MyMacroL            {\strut Test 1h} to 10mm {\vfill Test 1v\vfill}
536\MyMacroL spread 1cm {\strut Test 2h} to 15mm {\vfill Test 2v\vfill}
537\stopbuffer
538
539This:
540
541\typebuffer[usage]
542
543gives:
544
545\blank {\forgetall\dontcomplain\showboxes \getbuffer[usage]} \blank
546
547\stopsection
548
549\startsection[title=Like \CONTEXT]
550
551\index {implementors+hashes}
552\index {implementors+arrays}
553
554The previously discussed scanners don't use equal signs and commas as separators,
555but you can enforce that regime in the following way:
556
557
558\startbuffer[definition]
559\startluacode
560    interfaces.implement {
561        name      = "MyMacroN",
562        public    = true,
563        arguments = {
564            "hash",
565            "array",
566        },
567        actions   = function(h, a)
568            context.totable(h)
569            context.quad()
570            context.totable(a)
571        end,
572    }
573\stopluacode
574\stopbuffer
575
576\typebuffer[definition] \getbuffer[definition]
577
578\startbuffer[usage]
579\MyMacroN
580    [ a = 1,  b = 2 ]
581    [ 3, 4, 5, {6 7} ]
582\stopbuffer
583
584This:
585
586\typebuffer[usage]
587
588gives:
589
590\blank {\getbuffer[usage]} \blank
591
592\stopsection
593
594\startsection[title=Verbatim]
595
596\index {implementors+verbatim}
597
598There are a couple of rarely used scanners (there are more of course but these
599are pretty low level and not really used directly using implementors).
600
601\startbuffer[definition]
602\startluacode
603    interfaces.implement {
604        name      = "MyMacroO",
605        public    = true,
606        arguments = "verbatim",
607        actions   = function(v)
608            context.type(v)
609        end,
610    }
611\stopluacode
612\stopbuffer
613
614\typebuffer[definition] \getbuffer[definition]
615
616\startbuffer[usage]
617\MyMacroO{this is \something verbatim}
618\stopbuffer
619
620There is no expansion applied in:
621
622\typebuffer[usage]
623
624so we get what we input:
625
626\blank {\getbuffer[usage]} \blank
627
628\stopsection
629
630\startsection[title=Macros]
631
632\index {implementors+macros}
633
634We can pick up a control sequence without bothering what it actually
635represents:
636
637\startbuffer[definition]
638\startluacode
639    interfaces.implement {
640        name      = "MyMacroP",
641        public    = true,
642        arguments = "csname",
643        actions   = function(c)
644            context("{\\ttbf name:} {\\tttf %s}",c)
645        end,
646    }
647\stopluacode
648\stopbuffer
649
650\typebuffer[definition] \getbuffer[definition]
651
652\startbuffer[usage]
653\MyMacroP\framed
654\stopbuffer
655
656The next control sequence is picked up and its name without the leading
657escape character is returned:
658
659\typebuffer[usage]
660
661So here we get:
662
663\blank {\getbuffer[usage]} \blank
664
665\stopsection
666
667\startsection[title={Token lists}]
668
669\index {implementors+token lists}
670
671If you have no clue what tokens are in the perspective of \TEX, you can skip this
672section. We can grab a token list in two ways. The most \LUA ish way is to grab
673it as a table:
674
675\startbuffer[definition]
676\startluacode
677    interfaces.implement {
678        name      = "MyMacroQ",
679        public    = true,
680        arguments = "toks",
681        actions   = function(t)
682            context("%S : ",t)
683            context.sprint(t)
684            context.crlf()
685        end,
686    }
687\stopluacode
688\stopbuffer
689
690\typebuffer[definition] \getbuffer[definition]
691
692\startbuffer[usage]
693\MyMacroQ{this is a {\bf token} list}
694\MyMacroQ{this is a \inframed{token} list}
695\stopbuffer
696
697\typebuffer[usage]
698
699The above sample code gives us:
700
701\blank {\getbuffer[usage]} \blank
702
703An alternative is to keep the list a user data object:
704
705\startbuffer[definition]
706\startluacode
707    interfaces.implement {
708        name      = "MyMacroR",
709        public    = true,
710        arguments = "tokenlist",
711        actions   = function(t)
712            context("%S : ",t)
713            context.sprint(t)
714            context.crlf()
715        end,
716    }
717\stopluacode
718\stopbuffer
719
720\typebuffer[definition] \getbuffer[definition]
721
722\startbuffer[usage]
723\MyMacroR{this is a {\bf token} list}
724\MyMacroR{this is a \inframed{token} list}
725\stopbuffer
726
727\typebuffer[usage]
728
729Now we get:
730
731\blank {\getbuffer[usage]} \blank
732
733\stopsection
734
735\startsection[title={Actions}]
736
737\index {implementors+actions}
738
739The plural \type {actions} suggests that there can be more than one and indeed
740that is the case. The next example shows a sequence of actions that are applied.
741The first one gets the arguments passes.
742
743\startbuffer[definition]
744\startluacode
745    interfaces.implement {
746        name      = "MyMacroS",
747        public    = true,
748        arguments = "string",
749        actions   = { characters.upper, context },
750    }
751\stopluacode
752\stopbuffer
753
754\typebuffer[definition] \getbuffer[definition]
755
756\startbuffer[usage]
757\MyMacroS{uppercase}
758\stopbuffer
759
760\typebuffer[usage]
761
762Gives: \inlinebuffer[usage]
763
764You can pass default arguments too. That way you can have multiple macros using
765the same action. Here's how to do that:
766
767\startbuffer[definition]
768\startluacode
769    local function MyMacro(a,b,sign)
770        if sign then
771            context("$%i + %i = %i$",a,b,a+b)
772        else
773            context("$%i - %i = %i$",a,b,a-b)
774        end
775    end
776
777    interfaces.implement {
778        name      = "MyMacroPlus",
779        public    = true,
780        arguments = { "integer", "integer", true },
781        actions   = MyMacro,
782    }
783
784    interfaces.implement {
785        name      = "MyMacroMinus",
786        public    = true,
787        arguments = { "integer", "integer", false },
788        actions   = MyMacro,
789    }
790\stopluacode
791\stopbuffer
792
793\typebuffer[definition] \getbuffer[definition]
794
795So,
796
797\startbuffer[usage]
798\MyMacroPlus  654 321 \crlf
799\MyMacroMinus 654 321 \crlf
800\stopbuffer
801
802\typebuffer[usage]
803
804Gives:
805
806\getbuffer[usage]
807
808If you need to pass a string, you pass it as \type {"'preset'"}, so single quotes
809inside the double ones. Otherwise strings are interpreted as scanner types.
810
811\stopsection
812
813\startsection[title={Embedded \LUA\ code}]
814
815When you mix \TEX\ and \LUA, you can put the \LUA\ code in a \TEX\ file, for
816instance a style. In the previous sections we used this approach:
817
818\starttyping
819\startluacode
820    -- lua code
821\stopluacode
822\stoptyping
823
824This method is both reliable and efficient but you need to keep into mind that
825macros get expanded. In the next code, the second line will give an error when
826you have not defined \type {\foo} as expandable macro. When it is unexpandable it
827will get passed as it is and \LUA\ will see a \type {\f} as an escaped character.
828So, when you want a macro be passes as macro, you need to do it as in the third
829line. The fact that there is a comment trigger (\type {--}) doesn't help here.
830
831\starttyping
832\startluacode
833    context("foo")
834 -- context("\foo")
835    context("\\bar")
836\stopluacode
837\stoptyping
838
839When you use \type {\ctxlua} the same is true but there you also need to keep an
840eye on special characters. For instance a percent sign is then interpreted in the
841\TEX\ way and because all becomes one line, a \type {--} somewhere in the middle
842will make the rest of the line comment:
843
844\starttyping
845\ctxlua {
846    context("foo")
847 %  context("\foo")
848 -- context("\\bar")
849}
850\stoptyping
851
852Here, the second line goes away (\TEX\ comment) and the third line obscures all
853that follows. You can use \type {\letterpercent} to smuggle a percent sign in a
854\type {\ctxlua} call. Special characters like a hash symbol also need to be
855passed by name. Normally curly braces are no problem because \LUA\ also likes
856them properly nested.
857
858When things become too messy and complex you can always put the code in an
859external file and load that one (e.g. with \type {require}.
860
861In the examples in this chapter we put the function in the table, but for long
862ones you might want to do this:
863
864\starttyping
865\startluacode
866    local function MyMacro(s)
867        -- lots of code
868    end
869
870    interfaces.implement {
871        name      = "MyMacro",
872        public    = true,
873        arguments = "string",
874        actions   = MyMacro,
875    }
876\stopluacode
877\stoptyping
878
879It is a common mistake not to define variables and functions as local. If you
880define them global for sure there will become a time when this bites you.
881
882\stopsection
883
884\stopchapter
885
886\stopcomponent
887
888% conditional   : true|false|0=true|!0=false : too weird for users
889% bracketed     : maybe, but first I need a use case
890% bracketedasis : maybe, but first I need a use case
891% optional      : maybe, but first I need a use case
892
893\startluacode
894
895    local function Grabbed(t)
896        context(t)
897    end
898
899    interfaces.implement {
900        name      = "GrabC",
901        public    = true,
902        actions   = Grabbed,
903        arguments = "bracketed",
904    }
905    interfaces.implement {
906        name      = "GrabD",
907        public    = true,
908        actions   = Grabbed,
909        arguments = "bracketedasis",
910    }
911    interfaces.implement {
912        name      = "GrabE",
913        public    = true,
914        actions   = Grabbed,
915        arguments = "optional",
916    }
917\stopluacode
918
919\GrabC [foo {\red okay C} bar] \par
920\GrabC                         \par
921\GrabD [foo {\red okay D} bar] \par
922\GrabE [foo {\red okay E} bar] \par
923\GrabE                         \par
924
925% once stable:
926
927\startluacode
928    local random       = math.random
929    local randomseed   = math.randomseed
930
931    local scan_word    = tokens.scanners.word
932    local scan_integer = tokens.scanners.integer
933    local scan_dimen   = tokens.scanners.dimen
934    local scan_number  = tokens.scanners.float
935
936    local scan_integer  = tokens.scanners.luainteger
937    local scan_cardinal = tokens.scanners.luacardinal
938    local scan_number   = tokens.scanners.luanumber
939
940    local I = 0
941    local D = 0
942    local F = 0
943
944    interfaces.implement {
945        name      = "TestInteger",
946        public    = true,
947        actions   = function(b) if b then return I else I = scan_integer() end end,
948        valuetype = "count",
949    }
950
951    interfaces.implement {
952        name      = "TestDimension",
953        public    = true,
954        actions   = function(b) if b then return D else D = scan_dimen() end end,
955        valuetype = "dimen",
956    }
957
958    interfaces.implement {
959        name      = "TestFloat",
960        public    = true,
961        actions   = function(b)
962            if b then
963                context("%q",F)
964            else
965                F = scan_number()
966            end
967        end,
968        valuetype = "none",
969    }
970
971    interfaces.implement {
972        name      = "TestThis",
973        public    = true,
974        actions   = function(b)
975            if b then
976                return random(scan_integer(),scan_integer())
977            else
978                randomseed(scan_integer(true))
979            end
980        end,
981        valuetype = "count",
982    }
983
984\stopluacode
985
986{\tttf [set:\TestInteger           808714][get: \the\TestInteger  ]}\par % [get: \number\TestInteger  ]}\par
987{\tttf [set:\TestDimension        12.34pt][get: \the\TestDimension]}\par % [get: \number\TestDimension]}\par
988{\tttf [set:\TestFloat     12.34567890e99][get: \the\TestFloat    ]}\par % [get: \number\TestFloat    ]}\par
989
990{\tttf \TestThis 123 \dorecurse{10}{\the \TestThis 1 10 \space}}\par
991{\tttf \TestThis 123 \dorecurse{10}{\the \TestThis 1 10 \space}}\par
992{\tttf \TestThis 456 \dorecurse{10}{\the \TestThis 1 10 \space}}\par
993{\tttf               \dorecurse{10}{\the \TestThis 1 10 \space}}\par
994
995\TestFloat  .1e20\relax
996\TestFloat  -0x1.693d8e8943f17p+332\relax
997\TestFloat   0x1.693d8e8943f17p+332\relax
998
999\TestFloat  123.345E67\relax
1000
1001{\tttf [\the\TestFloat]}
1002
1003% maybe some day:
1004
1005% \startluacode
1006%     local t1 = token.get_next()
1007%     local t2 = token.get_next()
1008%     local t3 = token.get_next()
1009%     local t4 = token.get_next()
1010%     -- watch out, we flush in sequence
1011%     token.put_next { t1, t2 }
1012%     -- but this one gets pushed in front
1013%     token.put_next ( t3, t4 )
1014% \stopluacode
1015% abcd
1016
1017% \ctxlua{whatever = { } whatever.bf = token.get_next()}\bf
1018
1019\startluacode
1020    local t_bf = whatever and whatever.bf or token.create("bf")
1021    local put  = token.put_next
1022
1023    interfaces.implement {
1024        name    = "whateverbfone",
1025        public  = true,
1026        actions = function()
1027            put(t_bf)
1028        end
1029    }
1030
1031    local ctx_whateverbfxxx = context.whateverbfxxx
1032
1033    interfaces.implement {
1034        name    = "whateverbftwo",
1035        public  = true,
1036        actions = function()
1037            ctx_whateverbfxxx(false)
1038        end
1039    }
1040
1041    interfaces.implement {
1042        name    = "whateverbfthree",
1043        public  = true,
1044        actions = context.core.cs.whateverbfxxx
1045    }
1046
1047\stopluacode
1048
1049\let\whateverbfxxx\bf
1050
1051\dontleavehmode{xxx: \whateverbfxxx     xxx}\quad
1052\dontleavehmode{one: \whateverbfone     one}\quad
1053\dontleavehmode{two: \whateverbftwo     two}\quad
1054\dontleavehmode{two: \whateverbfthree three}\par
1055