summaryrefslogtreecommitdiff
path: root/doc/context/sources/general/manuals/about/about-luafunctions.tex
blob: 810de10fdf506bd0e8a31b74150d49e8d0996dca (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
% language=uk

\startcomponent about-properties

\environment about-environment

\startchapter[title=Functions]

\startsection[title=Introduction]

As part of the crited project Luigi and I also tried to identity weak spots in
the engine and although we found some issues not all were dealt with because
complicating the machinery makes no sense. However just like the new \type
{properties} mechanism provides a real simple way to associate extra \LUA\ data
to a node without bothering about freeing it when a node is flushed, the next
\type {luafunctions} mechanism provides an additional and fast way to cross the
\TEX||\LUA\ boundary.

\stopsection

\startsection[title=Callbacks]

In \LUATEX\ we can create more functionality by using \LUA\ which means that we
end up (at least in \CONTEXT) with a constant switching between \TEX\ macro
expansion and \LUA\ code interpretation. The magic word in this process is \type
{callback} and there are two variants:

\startitemize

\startitem At well defined moments in processing its input and node lists, \TEX\
will check if a specific callback is defined and if so, it will run that code.
\stopitem

\startitem As part of the input you can have a \type {\directlua} command and
that one gets expanded and processed. It can print back content into the current
input buffer. \footnote {Currently this process is somewhat more complex than
needed, which is a side effect of supporting multiple \LUA\ states in the first
versions of \LUATEX. We will clean up this mechanism at some point.} \stopitem

\stopitemize

The first type is call a \quote {direct} callback because \TEX\ calls it
directly, and the second one is an \quote {indirect} one (even if the command is
\type {\directlua}). It has a deferred cousin \type {\latelua} that results in a
node being inserted that will become a \LUA\ call during shipout, when the page
is turned into a \PDF\ stream.

A callback of the first category is pretty fast because the code is already
translated in \LUA\ bytecode. Checking if a callback has been assigned at all is
fast too. The second variant is slower because each time the input has to be
interpreted and checked on validity. Then there is of course some overhead in
making the call itself.

There is a subtle aspect there. If you have a document that needs say ten calls
like:

\starttyping
\directlua{tex.print("[x]")}
\stoptyping

and you have these calls inlined, you end up with ten times conversion into
tokens (\TEX's internal view) and ten times conversion back to a string that gets
fed into \LUA. On the other hand,

\starttyping
\def\MyCall{\directlua{tex.print("[x]")}}
\stoptyping

where we call \type {\MyCall} ten times is more efficient because we have already
tokenized the \type {\directlua}. If we have

\starttyping
foo foo foo \directlua{tex.print("[1]")} ...
bar bar bar \directlua{tex.print("[2]")} ...
\stoptyping

It makes sense to wrap this into a definition:

\starttyping
\def\MyCall#1{\directlua{tex.print("[#1]")}}
\stoptyping

and use:

\starttyping
foo foo foo \MyCall{1} bar bar bar \MyCall{1} ...
\stoptyping

Of course this is not unique for \type {\directlua} and to be honest, apart from
convenience (read: less input) the gain often can be neglected. Because a macro
package wraps functionality in (indeed) macros we already save us the tokenization
step. We can save some time by wrapping more in a function at the \LUA\ end:

\starttyping
\startluacode
function MyFloat(f)
    tex.print(string.format("%0.5f",f))
end
\stopluacode

\def\MyFloat#1%
  {\directlua{MyFloat(#1)}}
\stoptyping

This is somewhat more efficient than:

\starttyping
\def\MyFloat#1%
  {\directlua{tex.print(string.format("\letterpercent0.5f",#1))}}
\stoptyping

\stopsection

Of course this is only true when we call this macro a lot of times.

\startsection[title=Shortcuts]

When we talk of \quote {often} or \quote {a lot} we mean many thousands of calls.
There are some places in \CONTEXT\ where this is indeed the case, for instance
when we process large registers in critical editions: a few hundred pages of
references generated in \LUA\ is no exception there. Think of the following:

\starttyping
\startluacode
function GetTitle(n)
    tex.print(Entries[n].title)
end
\stopluacode

\def\GetTitle#1%
  {\directlua{GetTitle(#1)}}
\stoptyping

If we call \type {\GetTitle} ourselves it's the same as the \type {\MyFloat}
example, but how about this:

\starttyping
\def\GetTitle#1%
  {{\bf \directlua{GetTitle(#1)}}}

\startluacode
function GetTitle(n)
    tex.print(Entries[n].title)
end

function GetEntry(n)
    if Entries[n] then
        tex.print("\\directlua{GetTitle(",n,")}")
        -- some more action
    end
end
\stopluacode
\stoptyping

Here we have two calls where one is delayed till a later time. This delay results
in a tokenization and transation to \LUA\ so it will cost time. A way out is this:

\starttyping
\def\GetTitle#1%
  {{\bf \luafunction#1}}

\startluacode
local functions = tex.get_functions_table()

function GetTitle(n)
    tex.print(Entries[n].title)
end

function GetEntry(n)
    if Entries[n] then
        local m = #functions+1
        functions[m] = function() GetTitle(n) end
        tex.print("\\GetTitle{",m,"}")
        -- some more action
    end
end
\stopluacode
\stoptyping

We define a function at the \LUA\ end and just print a macro call. That call itself
calls the defined function using \type {\luafunction}. For a large number
of calls this is more efficient but it will be clear that you need to make sure that
used functions are cleaned up. A simple way is to start again at slot one after (say)
100.000 functions, another method is to reset used functions and keep counting.

\starttyping
\startluacode
local functions = tex.get_functions_table()

function GetTitle(n)
    tex.print(Entries[n].title)
end

function GetEntry(n)
    if Entries[n] then
        local m = #functions+1
        functions[m] = function(slot) -- the slot number is always
            GetTitle(n)               -- passed as argument so that
            functions[slot] = nil     -- we can reset easily
        end
        tex.print("\\GetTitle{",m,"}")
        -- some more action
    end
end
\stopluacode
\stoptyping

As you can expect, in \CONTEXT\ users are not expect to deal directly with
functions at all. Already for years you can so this:

\starttyping
\def\GetTitle#1%
  {{\bf#1}}

\startluacode
function GetEntry(n)
    if Entries[n] then
        context(function() context.GetTitle(Entries[n].title) end)
        -- some more action
    end
end
\stopluacode
\stoptyping

Upto \LUATEX\ 0.78 we had a \CONTEXT\ specific implementation of functions and
from 0.79 onwards we use this new mechanism but users won't see that in practice.
In the \type {cld-mkiv.pdf} manual you can find more about accessing \CONTEXT\
from the \LUA\ end.

Keep in mind that \type {\luafunction} is not that clever: it doesn't pick up
arguments. That will be part of future more extensive token handling but of
course that will then also be a real slow downer because a mix of \TEX\
tokenization and serialization is subtoptimal (we already did extensive tests
with that).

\stopsection

\startsection[title=Helpers]

The above mechanism demands some orchestration in the macro package. For instance
freeing slots should be consistent and therefore user should not mess directly
with the functions table. If you really want to use this feature you can best do this:

\starttyping
\startctxfunction MyFunctionA
    context(" A1 ")
\stopctxfunction

\startctxfunctiondefinition MyFunctionB
    context(" B2 ")
\stopctxfunctiondefinition

\starttext
    \dorecurse{10000}{\ctxfunction{MyFunctionA}}   \page
    \dorecurse{10000}{\MyFunctionB}                \page
    \dorecurse{10000}{\ctxlua{context(" C3 ")}}    \page
    \dorecurse{10000}{\ctxlua{tex.sprint(" D4 ")}} \page
\stoptext
\stoptyping

In case you're curious about performance, here are timing. Given that we have
10.000 calls the gain is rather neglectable especially because the whole run
takes 2.328 seconds for 52 processed pages resulting in 22.4 pages per second.
The real gain is in more complex calls with more tokens involved and in \CONTEXT\
we have some placed where we run into the hundreds of thousands. A similar
situation occurs when your input comes from databases and is fetched stepwise.

\starttabulate[|c|c|c|c|]
\NC \bf A \NC \bf B \NC \bf C \NC \bf D \NC \NR
\NC 0.053 \NC 0.044 \NC 0.081 \NC 0.081 \NC \NR
\stoptabulate

So, we can save 50\% runtime but on a simple document like this a few percent is
not that much. Of course many such few percentages can add up, and it's one of
the reasons why \CONTEXT\ \MKIV\ is pretty fast in spite of all the switching
between \TEX\ and \LUA. One objective is that an average complex document should
be processed with a rate of at least 20 pages per second and in most cases we
succeed. This fast function accessing can of course trigger new features in
\CONTEXT, ones we didn't consider useful because of overhead.

Keep in mind that in most cases, especially when programming in \LUA\ directly
the \type {context} command already does all kind of housekeeping for you. For
instance it also keeps track of so called trial typesetting runs and can inject
nodes in the current stream as well. So, be warned: there is no real need to
complicate your code with this kind of hackery if some high level subsystem
provides the functionality already.

\stopsection

\stopchapter

\stopcomponent