context-2020-implementers.tex /size: 8711 b    last modification: 2021-10-28 13:50
1% language=us
2
3% \enabletrackers[context*]
4
5\usemodule[present-boring,abbreviations-logos]
6
7\startdocument
8  [title={IMPLEMENTERS},
9   banner={an old feature still evolving},
10   location={context\enspace {\bf 2020}\enspace meeting}]
11
12\starttitle[title=Interfacing with \LUA]
13
14\startitemize
15
16\startitem
17    Quite some activity is delegated to \LUA.
18\stopitem
19\startitem
20    Normally the initiative is at the \TEX\ end.
21\stopitem
22\startitem
23    We can set variables or call functions etc.
24\stopitem
25\startitem
26    We can parameters to function calls.
27\stopitem
28\startitem
29    From the \LUA\ end we can use scanners to pick up data.
30\stopitem
31\startitem
32    We provide some consistent interfaces for doing all that.
33\stopitem
34\startitem
35    From \TEX\ to \LUA\ we use \type {\ctxlua{...}} and friends.
36\stopitem
37\startitem
38    From \LUA\ to \TEX\ we use \type {context(...)} and alike.
39\stopitem
40\startitem
41    For adding functionality we use so called implementers.
42\stopitem
43
44\stopitemize
45
46\stoptitle
47
48\starttitle[title=Calling \LUA]
49
50\startbuffer
51\ctxlua{context("ok")}
52\stopbuffer
53
54\typebuffer \getbuffer
55
56\startbuffer
57\ctxlua{context(2 * tokens.scanners.integer())} 10
58\stopbuffer
59
60\typebuffer \getbuffer
61
62\startbuffer
63\startluacode
64function document.MyThing() context(2 * tokens.scanners.integer()) end
65\stopluacode
66\stopbuffer
67
68\typebuffer \getbuffer
69
70\startbuffer
71\ctxlua{document.MyThing()} 20 \quad
72\ctxlua{document.MyThing()} 30 \quad
73\ctxlua{document.MyThing()} 40
74\stopbuffer
75
76\typebuffer \getbuffer
77
78\stoptitle
79
80\starttitle[title=Streamlining \LUA]
81
82\startbuffer
83\startluacode
84interfaces.implement {
85    name      = "MyThing",
86    public    = true,
87    arguments = "integer",
88    actions   =   function(i) context(i * 2) end,
89 -- actions   = { function(i)  return i * 2  end, context },
90}
91\stopluacode
92\stopbuffer
93
94\typebuffer \getbuffer
95
96\startbuffer
97\MyThing 20 \quad \MyThing 30 \quad \MyThing 40
98\stopbuffer
99
100\typebuffer \getbuffer
101
102\stoptitle
103
104\starttitle[title=Making commands]
105
106\startbuffer
107\startluacode
108interfaces.implement {
109    name      = "MyRoot",
110    public    = true,
111    actions   = function()
112        local a = tokens.scanners.integer()
113        if not tokens.scanners.keyword("of") then
114         -- tex.error("the keyword 'of' expected")
115        end
116        local b = tokens.scanners.integer()
117        context("%0.6N",math.sqrt(b,a))
118    end,
119}
120\stopluacode
121\stopbuffer
122
123\typebuffer \getbuffer
124
125\startbuffer
126\MyRoot 2 of 40 \quad \MyRoot 3 60
127\stopbuffer
128
129\typebuffer \getbuffer
130
131\stoptitle
132
133\starttitle[title=Scanners]
134
135There are lots of scanners: \blank
136
137\startalign[flushleft,broad] \tttf
138    \cldcontext { table.concat ( table.sortedkeys (tokens.scanners), " " ) }
139\stopalign
140
141\stoptitle
142
143\starttitle[title=A more complex example]
144
145Let's implement a matcher: \blank
146
147\startbuffer
148\doloopovermatch {(.)} {luametatex} { [#1] }
149\stopbuffer
150
151\typebuffer \getbuffer
152
153\startbuffer
154\doloopovermatch {([\letterpercent w]+)} {\cldloadfile{tufte.tex}} { [#1] }
155\stopbuffer
156
157\typebuffer \getbuffer
158
159\stoptitle
160
161\starttitle[title=A more complex example (\TEX)]
162
163Here is the macro definition of this loop: \blank
164
165\starttyping
166\protected\def\doloopovermatch#1#2#3%
167  {\pushmacro\matchloopcommand
168   \def\matchloopcommand##1##2##3##4##5##6##7##8##9{#3}%
169   \ctxluamatch\matchloopcommand{#1}{#2}%
170   \popmacro\matchloopcommand}
171\stoptyping
172
173\startitemize
174
175\startitem The pushing and popping makes it possible to nest this macro. \stopitem
176\startitem The definition of the internal match macro permits argument references. \stopitem
177
178\stopitemize
179
180\stoptitle
181
182\starttitle[title=A more complex example (\LUA)]
183
184At the \LUA\ end we use an implementer: \blank
185
186\starttyping[style=\small\tt]
187local escape = function(s) return "\\" .. string.byte(s) end
188
189interfaces.implement {
190    name    = "ctxluamatch",
191    public  = true,
192    usage   = "value",
193    actions = function()
194        local command = context[tokens.scanners.csname()]
195        local pattern = string.gsub(tokens.scanners.string(),"\\.",escape)
196        local input   = string.gsub(tokens.scanners.string(),"\\.",escape)
197        for a, b, c, d, e, f, g, h, i in string.gmatch(input,pattern) do
198            command(a, b or "", c or "", d or "", e or "", f or "", g or "",
199                h or "", i or "")
200        end
201        return tokens.values.none
202    end,
203}
204\stoptyping
205
206So what does the \type {usage} key tells the implementer?
207
208\stoptitle
209
210\starttitle[title=Value functions]
211
212Normally we pipe back verbose strings that are interpreted as if they were
213files. Value functions are different;
214
215\startitemize
216
217\startitem
218    The return value indicates what gets fed back in the input.
219\stopitem
220\startitem
221    This can be: \cldcontext { table.concat(token.getfunctionvalues(), ", ", 0) }.
222\stopitem
223\startitem
224    When possible an efficient token is injected.
225\stopitem
226\startitem
227    Value function can check if they are supposed to feed back a value.
228\stopitem
229\startitem
230    So, they can be used as setters and getters.
231\stopitem
232\startitem
233    A variant is a function that is seen as conditional.
234\stopitem
235\startitem
236    In (simple) tracing they are presented as primitives.
237\stopitem
238\startitem
239    They are protected against user overload (aka: frozen).
240\stopitem
241\startitem
242    All this is experimental and might evolve.
243\stopitem
244
245\stopitemize
246
247\stoptitle
248
249\starttitle[title=So, let's step up a level]
250
251Say that we want an expandable command:
252
253\startbuffer
254\edef\foo{\doloopovermatched{.}{123}{(#1)}} \meaning\foo
255\stopbuffer
256
257\typebuffer \blank \getbuffer \blank
258
259Or nested:
260
261\startbuffer
262\edef\foo {%
263    \doloopovermatched {(..)} {123456} {%
264        \doloopovermatched {(.)(.)} {#1} {%
265           [##1][##2]%
266        }%
267    }%
268} \meaning\foo
269\stopbuffer
270
271\typebuffer \blank \getbuffer \blank
272
273\stoptitle
274
275\starttitle[title=So, let's step up a level]
276
277Compare:
278
279\starttyping[style=\small\tt]
280\protected\def\doloopovermatch#1#2#3%
281  {\pushmacro\matchloopcommand
282   \def\matchloopcommand##1##2##3##4##5##6##7##8##9{#3}%
283   \ctxluamatch\matchloopcommand{#1}{#2}%
284   \popmacro\matchloopcommand}
285\stoptyping
286
287With:
288
289\starttyping[style=\small\tt]
290\def\doloopovermatched#1#2#3%
291  {\beginlocalcontrol
292     \pushmacro\matchloopcommand
293     \def\matchloopcommand##1##2##3##4##5##6##7##8##9{#3}%
294   \endlocalcontrol
295   \the\ctxluamatch\matchloopcommand{#1}{#2}%
296   \beginlocalcontrol
297     \popmacro\matchloopcommand
298   \endlocalcontrol}
299\stoptyping
300
301Local control hides the assignments (it basically nests the mail loop).
302
303\stoptitle
304
305\starttitle[title=A few teasers (\TEX)]
306
307\starttyping[style=\small\tt]
308\doloopovermatch {(\letterpercent d+)} {this 1 is 22 a 333 test} { [#1] }
309
310\doloopovermatch {(\letterpercent w+) *(\letterpercent w*)} {aa bb cc dd} {
311    [
312        \doloopovermatch{(\letterpercent w)(\letterpercent w)} {#1} {(##1 ##2)}
313        \doloopovermatch{(\letterpercent w)(\letterpercent w)} {#2} {(##1 ##2)}
314    ]
315}
316
317\doloopovermatch
318    {(.-)\letterpercent{\bf (.-)\letterpercent}(.*)}
319    {this is {\bf a} test}
320    {#1{\it not #2}#3}
321\stoptyping
322
323\stoptitle
324
325\starttitle[title=A few teasers (\LUA)]
326
327\starttyping[style=\small\tt]
328interfaces.implement {
329    name = "bitwisexor", public = true, usage = "value", actions =
330    function(what)
331        local a = tokens.scanners.cardinal()
332        scankeyword("with")
333        local b = tokens.scanners.cardinal()
334        if what == "value" then
335            return tokens.values.cardinal, a ~ b
336        else
337            logs.texerrormessage("you can't use \\bitwiseor this way")
338        end
339    end
340}
341interfaces.implement {
342    name = "ifbitwiseand", public = true, usage = "condition", actions =
343    function(what)
344        local a = tokens.scanners.cardinal()
345        local b = tokens.scanners.cardinal()
346        return tokens.values.boolean, (a & b) ~= 0
347    end
348}
349\stoptyping
350
351\stoptitle
352
353\starttitle[title=Questions and more examples]
354
355More examples will be given in the editor.
356
357\stoptitle
358
359\stopdocument
360
361% \doloopovermatch {(\letterpercent w+) *(\letterpercent w*)} {aa bb cc dd} {
362%     [
363%         \doloopovermatch{(\letterpercent w)(\letterpercent w)} {#1} {(##1 ##2)}
364%         \doloopovermatch{(\letterpercent w)(\letterpercent w)} {#2} {(##1 ##2)}
365%     ]
366% }
367
368% \doloopovermatch {(\letterpercent d+)} {this 1 is 22 a 333 test} { [#1] }
369
370% \testfeatureonce{10000}{\doloopovermatch {(\letterpercent d+)} {this 1 is 22 a 333 test} {}} \elapsedtime
371
372% \doloopovermatch
373%     {(.-)\letterpercent{\bf (.-)\letterpercent}(.*)}
374%     {this is {\bf a} test}
375%     {#1{\it not #2}#3}
376
377% \doloopovermatch {([\letterpercent w]+)} {\cldloadfile{tufte.tex}} { [#1] }
378
379% \testfeatureonce{100}{\doloopovermatch {([\letterpercent w]+)}{\cldloadfile{tufte.tex}} {}} \elapsedtime
380
381