summaryrefslogtreecommitdiff
path: root/doc/context/sources/general/manuals/cld/cld-abitoflua.tex
blob: e6150792968f27abd577e8dba41d6666373d7d1e (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
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
% language=uk

\startcomponent cld-abitoflua

\environment cld-environment

\startchapter[title=A bit of Lua]

\startsection[title=The language]

\index[lua]{\LUA}

Small is beautiful and this is definitely true for the programming language \LUA\
(moon in Portuguese). We had good reasons for using this language in \LUATEX:
simplicity, speed, syntax and size to mention a few. Of course personal taste
also played a role and after using a couple of scripting languages extensively
the switch to \LUA\ was rather pleasant.

As the \LUA\ reference manual is an excellent book there is no reason to discuss
the language in great detail: just buy \quote {Programming in \LUA} by the \LUA\
team. Nevertheless I will give a short summary of the important concepts but
consult the book if you want more details.

\stopsection

\startsection[title=Data types]

\index{functions}
\index{variables}
\index{strings}
\index{numbers}
\index{booleans}
\index{tables}

The most basic data type is \type {nil}. When we define a variable, we don't need
to give it a value:

\starttyping
local v
\stoptyping

Here the variable \type {v} can get any value but till that
happens it equals \type {nil}. There are simple data types like
\type {numbers}, \type {booleans} and \type {strings}. Here are
some numbers:

\starttyping
local n = 1 + 2 * 3
local x = 2.3
\stoptyping

Numbers are always floats \footnote {This is true for all versions upto 5.2 but
following version can have a more hybrid model.} and you can use the normal
arithmetic operators on them as well as functions defined in the math library.
Inside \TEX\ we have only integers, although for instance dimensions can be
specified in points using floats but that's more syntactic sugar. One reason for
using integers in \TEX\ has been that this was the only way to guarantee
portability across platforms. However, we're 30 years along the road and in \LUA\
the floats are implemented identical across platforms, so we don't need to worry
about compatibility.

Strings in \LUA\ can be given between quotes or can be so called long strings
forced by square brackets.

\starttyping
local s = "Whatever"
local t = s .. ' you want'
local u = t .. [[ to know]] .. [[--[ about Lua!]--]]
\stoptyping

The two periods indicate a concatenation. Strings are hashed, so when you say:

\starttyping
local s = "Whatever"
local t = "Whatever"
local u = t
\stoptyping

only one instance of \type {Whatever} is present in memory and this fact makes
\LUA\ very efficient with respect to strings. Strings are constants and therefore
when you change variable \type {s}, variable \type {t} keeps its value. When you
compare strings, in fact you compare pointers, a method that is really fast. This
compensates the time spent on hashing pretty well.

Booleans are normally used to keep a state or the result from an expression.

\starttyping
local b = false
local c = n > 10 and s == "whatever"
\stoptyping

The other value is \type {true}. There is something that you need
to keep in mind when you do testing on variables that are yet
unset.

\starttyping
local b = false
local n
\stoptyping

The following applies when \type {b} and \type {n} are defined this way:

\starttabulate[|Tl|Tl|]
\NC b == false \NC true  \NC \NR
\NC n == false \NC false \NC \NR
\NC n == nil   \NC true  \NC \NR
\NC b == nil   \NC false \NC \NR
\NC b == n     \NC false \NC \NR
\NC n == nil   \NC true  \NC \NR
\stoptabulate

Often a test looks like:

\starttyping
if somevar then
    ...
else
    ...
end
\stoptyping

In this case we enter the else branch when \type {somevar} is either \type {nil}
or \type {false}. It also means that by looking at the code we cannot beforehand
conclude that \type {somevar} equals \type {true} or something else. If you want
to really distinguish between the two cases you can be more explicit:

\starttyping
if somevar == nil then
    ...
elseif somevar == false then
    ...
else
    ...
end
\stoptyping

or

\starttyping
if somevar == true then
    ...
else
    ...
end
\stoptyping

but such an explicit test is seldom needed.

There are a few more data types: tables and functions. Tables are very important
and you can recognize them by the same curly braces that make \TEX\ famous:

\starttyping
local t = { 1, 2, 3 }
local u = { a = 4, b = 9, c = 16 }
local v = { [1] = "a", [3] = "2", [4] = false }
local w = { 1, 2, 3, a = 4, b = 9, c = 16 }
\stoptyping

The \type {t} is an indexed table and \type {u} a hashed table. Because the
second slot is empty, table \type {v} is partially indexed (slot 1) and partially
hashed (the others). There is a gray area there, for instance, what happens when
you nil a slot in an indexed table? In practice you will not run into problems as
you will either use a hashed table, or an indexed table (with no holes), so table
\type {w} is not uncommon.

We mentioned that strings are in fact shared (hashed) but that an assignment of a
string to a variable makes that variable behave like a constant. Contrary to
that, when you assign a table, and then copy that variable, both variables can be
used to change the table. Take this:

\starttyping
local t = { 1, 2, 3 }
local u = t
\stoptyping

We can change the content of the table as follows:

\starttyping
t[1], t[3] = t[3], t[1]
\stoptyping

Here we swap two cells. This is an example of a parallel assigment. However, the
following does the same:

\starttyping
t[1], t[3] = u[3], u[1]
\stoptyping

After this, both \type {t} and \type {u} still share the same table. This kind of
behaviour is quite natural. Keep in mind that expressions are evaluated first, so

\starttyping
t[#t+1], t[#t+1] = 23, 45
\stoptyping

Makes no sense, as the values end up in the same slot. There is no gain in speed
so using parallel assignments is mostly a convenience feature.

There are a few specialized data types in \LUA, like \type {coroutines} (built
in), \type {file} (when opened), \type {lpeg} (only when this library is linked
in or loaded). These are called \quote {userdata} objects and in \LUATEX\ we have
more userdata objects as we will see in later chapters. Of them nodes are the
most noticeable: they are the core data type of the \TEX\ machinery. Other
libraries, like \type {math} and \type {bit32} are just collections of functions
operating on numbers.

Functions look like this:

\starttyping
function sum(a,b)
  print(a, b, a + b)
end
\stoptyping

or this:

\starttyping
function sum(a,b)
  return a + b
end
\stoptyping

There can be many arguments of all kind of types and there can be multiple return
values. A function is a real type, so you can say:

\starttyping
local f = function(s) print("the value is: " .. s) end
\stoptyping

In all these examples we defined variables as \type {local}. This is a good
practice and avoids clashes. Now watch the following:

\starttyping
local n = 1

function sum(a,b)
  n = n + 1
  return a + b
end

function report()
  print("number of summations: " .. n)
end
\stoptyping

Here the variable \type {n} is visible after its definition and accessible for
the two global functions. Actually the variable is visible to all the code
following, unless of course we define a new variable with the same name. We can
hide \type {n} as follows:

\starttyping
do
  local n = 1

  sum = function(a,b)
    n = n + 1
    return a + b
  end

  report = function()
    print("number of summations: " .. n)
  end
end
\stoptyping

This example also shows another way of defining the function: by assignment.

The \typ {do ... end} creates a so called closure. There are many places where
such closures are created, for instance in function bodies or branches like \typ
{if ... then ... else}. This means that in the following snippet, variable \type
{b} is not seen after the end:

\starttyping
if a > 10 then
  local b = a + 10
  print(b*b)
end
\stoptyping

When you process a blob of \LUA\ code in \TEX\ (using \type {\directlua} or \type
{\latelua}) it happens in a closure with an implied \typ {do ... end}. So, \type
{local} defined variables are really local.

\stopsection

\startsection[title=\TEX's data types]

We mentioned \type {numbers}. At the \TEX\ end we have counters as well as
dimensions. Both are numbers but dimensions are specified differently

\starttyping
local n = tex.count[0]
local m = tex.dimen.lineheight
local o = tex.sp("10.3pt") -- sp or 'scaled point' is the smallest unit
\stoptyping

The unit of dimension is \quote {scaled point} and this is a pretty small unit:
10 points equals to 655360 such units.

Another accessible data type is tokens. They are automatically converted to
strings and vice versa.

\starttyping
tex.toks[0] = "message"
print(tex.toks[0])
\stoptyping

Be aware of the fact that the tokens are letters so the following will come out
as text and not issue a message:

\starttyping
tex.toks[0] = "\message{just text}"
print(tex.toks[0])
\stoptyping

\stopsection

\startsection[title=Control structures]

\index{loops}

Loops are not much different from other languages: we have \typ {for ... do},
\typ {while ... do} and \typ {repeat ... until}. We start with the simplest case:

\starttyping
for index=1,10 do
  print(index)
end
\stoptyping

You can specify a step and go downward as well:

\starttyping
for index=22,2,-2 do
  print(index)
end
\stoptyping

Indexed tables can be traversed this way:

\starttyping
for index=1,#list do
  print(index, list[index])
end
\stoptyping

Hashed tables on the other hand are dealt with as follows:

\starttyping
for key, value in next, list do
  print(key, value)
end
\stoptyping

Here \type {next} is a built in function. There is more to say about this
mechanism but the average user will use only this variant. Slightly less
efficient is the following, more readable variant:

\starttyping
for key, value in pairs(list) do
  print(key, value)
end
\stoptyping

and for an indexed table:

\starttyping
for index, value in ipairs(list) do
  print(index, value)
end
\stoptyping

The function call to \type {pairs(list)} returns \typ {next, list} so there is an
(often neglectable) extra overhead of one function call.

The other two loop variants, \type {while} and \type {repeat}, are similar.

\starttyping
i = 0
while i < 10  do
  i = i + 1
  print(i)
end
\stoptyping

This can also be written as:

\starttyping
i = 0
repeat
  i = i + 1
  print(i)
until i = 10
\stoptyping

Or:

\starttyping
i = 0
while true do
  i = i + 1
  print(i)
  if i = 10 then
    break
  end
end
\stoptyping
\stopsection

Of course you can use more complex expressions in such constructs.

\startsection[title=Conditions]

\index{expressions}

Conditions have the following form:

\starttyping
if a == b or c > d or e then
  ...
elseif f == g then
  ...
else
  ...
end
\stoptyping

Watch the double \type {==}. The complement of this is \type {~=}. Precedence is
similar to other languages. In practice, as strings are hashed. Tests like

\starttyping
if key == "first" then
  ...
end
\stoptyping

and

\starttyping
if n == 1 then
  ...
end
\stoptyping

are equally efficient. There is really no need to use numbers to identify states
instead of more verbose strings.

\stopsection

\startsection[title=Namespaces]

\index{namespaces}

Functionality can be grouped in libraries. There are a few default libraries,
like \type {string}, \type {table}, \type {lpeg}, \type {math}, \type {io} and
\type {os} and \LUATEX\ adds some more, like \type {node}, \type {tex} and \type
{texio}.

A library is in fact nothing more than a bunch of functionality organized using a
table, where the table provides a namespace as well as place to store public
variables. Of course there can be local (hidden) variables used in defining
functions.

\starttyping
do
  mylib = { }

  local n = 1

  function mylib.sum(a,b)
    n = n + 1
    return a + b
  end

  function mylib.report()
    print("number of summations: " .. n)
  end
end
\stoptyping

The defined function can be called like:

\starttyping
mylib.report()
\stoptyping

You can also create a shortcut, This speeds up the process because there are less
lookups then. In the following code multiple calls take place:

\starttyping
local sum = mylib.sum

for i=1,10 do
  for j=1,10 do
    print(i, j, sum(i,j))
  end
end

mylib.report()
\stoptyping

As \LUA\ is pretty fast you should not overestimate the speedup, especially not
when a function is called seldom. There is an important side effect here: in the
case of:

\starttyping
  print(i, j, sum(i,j))
\stoptyping

the meaning of \type {sum} is frozen. But in the case of

\starttyping
  print(i, j, mylib.sum(i,j))
\stoptyping

The current meaning is taken, that is: each time the interpreter will access
\type {mylib} and get the current meaning of \type {sum}. And there can be a good
reason for this, for instance when the meaning is adapted to different
situations.

In \CONTEXT\ we have quite some code organized this way. Although much is exposed
(if only because it is used all over the place) you should be careful in using
functions (and data) that are still experimental. There are a couple of general
libraries and some extend the core \LUA\ libraries. You might want to take a look
at the files in the distribution that start with \type {l-}, like \type
{l-table.lua}. These files are preloaded.\footnote {In fact, if you write scripts
that need their functionality, you can use \type {mtxrun} to process the script,
as \type {mtxrun} has the core libraries preloaded as well.} For instance, if you
want to inspect a table, you can say:

\starttyping
local t = { "aap", "noot", "mies" }
table.print(t)
\stoptyping

You can get an overview of what is implemented by running the following command:

\starttyping
context s-tra-02 --mode=tablet
\stoptyping

{\em todo: add nice synonym for this module and also add helpinfo at the to so
that we can do \type {context --styles}}

\stopsection

\startsection[title=Comment]

\index{comment}

You can add comments to your \LUA\ code. There are basically two methods: one
liners and multi line comments.

\starttyping
local option = "test" -- use this option with care

local method = "unknown" --[[comments can be very long and when entered
                             this way they and span multiple lines]]
\stoptyping

The so called long comments look like long strings preceded by \type {--} and
there can be more complex boundary sequences.

\stopsection

\startsection[title=Pitfalls]

Sometimes \type {nil} can bite you, especially in tables, as they have a dual nature:
indexed as well as hashed.

\startbuffer
\startluacode
local n1 = # { nil, 1, 2, nil }      -- 3
local n2 = # { nil, nil, 1, 2, nil } -- 0

context("n1 = %s and n2 = %s",n1,n2)
\stopluacode
\stopbuffer

\typebuffer

results in: \getbuffer

So, you cannot really depend on the length operator here. On the other hand, with:

\startbuffer
\startluacode
local function check(...)
    return select("#",...)
end

local n1 = check ( nil, 1, 2, nil )      -- 4
local n2 = check ( nil, nil, 1, 2, nil ) -- 5

context("n1 = %s and n2 = %s",n1,n2)
\stopluacode
\stopbuffer

\typebuffer

we get: \getbuffer, so the \type {select} is quite useable. However, that function also
has its specialities. The following example needs some close reading:

\startbuffer
\startluacode
local function filter(n,...)
    return select(n,...)
end

local v1 = { filter ( 1, 1, 2, 3 ) }
local v2 = { filter ( 2, 1, 2, 3 ) }
local v3 = { filter ( 3, 1, 2, 3 ) }

context("v1 = %+t and v2 = %+t and v3 = %+t",v1,v2,v3)
\stopluacode
\stopbuffer

\typebuffer

We collect the result in a table and show the concatination:

\getbuffer

So, what you effectively get is the whole list starting with the given offset.

\startbuffer
\startluacode
local function filter(n,...)
    return (select(n,...))
end

local v1 = { filter ( 1, 1, 2, 3 ) }
local v2 = { filter ( 2, 1, 2, 3 ) }
local v3 = { filter ( 3, 1, 2, 3 ) }

context("v1 = %+t and v2 = %+t and v3 = %+t",v1,v2,v3)
\stopluacode
\stopbuffer

\typebuffer

Now we get: \getbuffer. The extra \type {()} around the result makes sure that
we only get one return value.

Of course the same effect can be achieved as follows:

\starttyping
local function filter(n,...)
    return select(n,...)
end

local v1 = filter ( 1, 1, 2, 3 )
local v2 = filter ( 2, 1, 2, 3 )
local v3 = filter ( 3, 1, 2, 3 )

context("v1 = %s and v2 = %s and v3 = %s",v1,v2,v3)
\stoptyping

\stopsection

\startsection[title={A few suggestions}]

You can wrap all kind of functionality in functions but sometimes it makes no
sense to add the overhead of a call as the same can be done with hardly any code.

If you want a slice of a table, you can copy the range needed to a new table. A
simple version with no bounds checking is:

\starttyping
local new = { } for i=a,b do new[#new+1] = old[i] end
\stoptyping

Another, much faster, variant is the following.

\starttyping
local new = { unpack(old,a,b) }
\stoptyping

You can use this variant for slices that are not extremely large. The function
\type {table.sub} is an equivalent:

\starttyping
local new = table.sub(old,a,b)
\stoptyping

An indexed table is empty when its size equals zero:

\starttyping
if #indexed == 0 then ... else ... end
\stoptyping

Sometimes this is better:

\starttyping
if indexed and #indexed == 0 then ... else ... end
\stoptyping

So how do we test if a hashed table is empty? We can use the
\type {next} function as in:

\starttyping
if hashed and next(indexed) then ... else ... end
\stoptyping

Say that we have the following table:

\starttyping
local t = { a=1, b=2, c=3 }
\stoptyping

The call \type {next(t)} returns the first key and value:

\starttyping
local k, v = next(t)   -- "a", 1
\stoptyping

The second argument to \type {next} can be a key in which case the
following key and value in the hash table is returned. The result
is not predictable as a hash is unordered. The generic for loop
uses this to loop over a hashed table:

\starttyping
for k, v in next, t do
    ...
end
\stoptyping

Anyway, when \type {next(t)} returns zero you can be sure that the table is
empty. This is how you can test for exactly one entry:

\starttyping
if t and not next(t,next(t)) then ... else ... end
\stoptyping

Here it starts making sense to wrap it into a function.

\starttyping
function table.has_one_entry(t)
    t and not next(t,next(t))
end
\stoptyping

On the other hand, this is not that usefull, unless you can spent the runtime on
it:

\starttyping
function table.is_empty(t)
    return not t or not next(t)
end
\stoptyping

\stopsection

\startsection[title=Interfacing]

We have already seen that you can embed \LUA\ code using commands like:

\starttyping
\startluacode
    print("this works")
\stopluacode
\stoptyping

This command should not be confused with:

\starttyping
\startlua
    print("this works")
\stoplua
\stoptyping

The first variant has its own catcode regime which means that tokens between the start
and stop command are treated as \LUA\ tokens, with the exception of \TEX\ commands. The
second variant operates under the regular \TEX\ catcode regime.

Their short variants are \type {\ctxluacode} and \type {\ctxlua} as in:

\starttyping
\ctxluacode{print("this works")}
\ctxlua{print("this works")}
\stoptyping

In practice you will probably use \type {\startluacode} when using or defining % \stopluacode
a blob of \LUA\ and \type {\ctxlua} for inline code. Keep in mind that the
longer versions need more initialization and have more overhead.

There are some more commands. For instance \type {\ctxcommand} can be used as
an efficient way to access functions in the \type {commands} namespace. The
following two calls are equivalent:

\starttyping
\ctxlua    {commands.thisorthat("...")}
\ctxcommand         {thisorthat("...")}
\stoptyping

There are a few shortcuts to the \type {context} namespace. Their use can best be
seen from their meaning:

\starttyping
\cldprocessfile#1{\directlua{context.runfile("#1")}}
\cldloadfile   #1{\directlua{context.loadfile("#1")}}
\cldcontext    #1{\directlua{context(#1)}}
\cldcommand    #1{\directlua{context.#1}}
\stoptyping

The \type {\directlua{}} command can also be implemented using the token parser
and \LUA\ itself. A variant is therefore \type {\luascript{}} which can be
considered an alias but with a bit different error reporting. A variant on this
is the \type {\luathread {name} {code}} command. Here is an example of their
usage:

\startbuffer
\luascript        {        context("foo 1:") context(i) } \par
\luathread {test} { i = 10 context("bar 1:") context(i) } \par
\luathread {test} {        context("bar 2:") context(i) } \par
\luathread {test} {} % resets
\luathread {test} {        context("bar 3:") context(i) } \par
\luascript        {        context("foo 2:") context(i) } \par
\stopbuffer

\typebuffer

These commands result in:

\startpacked \getbuffer \stoppacked

% \testfeatureonce{100000}{\directlua        {local a = 10 local a = 10 local a = 10}} % 0.53s
% \testfeatureonce{100000}{\luascript        {local a = 10 local a = 10 local a = 10}} % 0.62s
% \testfeatureonce{100000}{\luathread {test} {local a = 10 local a = 10 local a = 10}} % 0.79s

The variable \type {i} is local to the thread (which is not really a thread in
\LUA\ but more a named piece of code that provides an environment which is shared
over the calls with the same name. You will probably never need these.

Each time a call out to \LUA\ happens the argument eventually gets parsed, converted
into tokens, then back into a string, compiled to bytecode and executed. The next
example code shows a mechanism that avoids this:

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

\startctxfunctiondefinition MyFunctionB
    context(" B2 ")
\stopctxfunctiondefinition
\stoptyping

The first command associates a name with some \LUA\ code and that code can be
executed using:

\starttyping
\ctxfunction{MyFunctionA}
\stoptyping

The second definition creates a command, so there we do:

\starttyping
\MyFunctionB
\stoptyping

There are some more helpers but for use in document sources they make less sense. You
can always browse the source code for examples.

\stopsection

\stopchapter

\stopcomponent