cldf-lmt.lua /size: 17 Kb    last modification: 2020-07-01 14:35
1
if
not
modules
then
modules
=
{
}
end
modules
[
'
cldf-lmt
'
]
=
{
2
version
=
1
.
001
,
3
comment
=
"
companion to toks-scn.mkiv
"
,
4
author
=
"
Hans Hagen, PRAGMA-ADE, Hasselt NL
"
,
5
copyright
=
"
PRAGMA ADE / ConTeXt Development Team
"
,
6
license
=
"
see context related readme files
"
7
}
8 9
local
next
,
load
=
next
,
load
10 11
local
setmetatableindex
=
table
.
setmetatableindex
12
local
setmetatablenewindex
=
table
.
setmetatablenewindex
13
local
serialize
=
table
.
serialize
14 15
local
random
=
math
.
random
16
local
randomseed
=
math
.
randomseed
17
local
round
=
math
.
round
18
local
abs
=
math
.
abs
19 20
local
implement
=
interfaces
.
implement
21 22
local
scanners
=
tokens
.
scanners
23
local
scanword
=
scanners
.
word
24
local
scanstring
=
scanners
.
string
25
local
scanboolean
=
scanners
.
boolean
26
local
scandimen
=
scanners
.
dimen
27
local
scanfloat
=
scanners
.
float
28
local
scaninteger
=
scanners
.
integer
29
local
scannumber
=
scanners
.
luanumber
30
local
scanluainteger
=
scanners
.
luainteger
31
local
scanluacardinal
=
scanners
.
luacardinal
32
local
scanluanumber
=
scanners
.
luanumber
33
local
scanargument
=
scanners
.
argument
34
local
scantoken
=
scanners
.
token
35
local
scancsname
=
scanners
.
csname
36 37
local
getindex
=
token
.
get_index
38 39
local
texsetdimen
=
tex
.
setdimen
40
local
texget
=
tex
.
get
41 42
local
values
=
tokens
.
values
43
local
none_code
=
values
.
none
44
local
integer_code
=
values
.
integer
45
local
cardinal_code
=
values
.
cardinal
46
local
dimension_code
=
values
.
dimension
47
local
skip_code
=
values
.
skip
48
local
boolean_code
=
values
.
boolean
49
local
float_code
=
values
.
float
50 51
local
context
=
context
52 53
-- variables --
54 55
local
floats
=
{
}
56
local
integers
=
{
}
57
local
cardinals
=
{
}
58
local
numbers
=
{
}
59 60
implement
{
61
name
=
"
luafloat
"
,
62
public
=
true
,
63
value
=
true
,
64
actions
=
function
(
b
)
65
local
n
=
scanword
(
)
66
if
b
=
=
"
value
"
then
67
context
(
"
%.99g
"
,
floats
[
n
]
or
0
)
68
else
69
floats
[
n
]
=
scanluanumber
(
true
)
70
-- floats[n] = scanfloat(true)
71
end
72
end
,
73
}
74 75
implement
{
76
name
=
"
luainteger
"
,
77
public
=
true
,
78
value
=
true
,
79
actions
=
function
(
b
)
80
local
n
=
scanword
(
)
81
if
b
=
=
"
value
"
then
82
context
(
"
%i
"
,
integers
[
n
]
or
0
)
83
else
84
integers
[
n
]
=
scanluainteger
(
true
)
85
end
86
end
,
87
}
88 89
implement
{
90
name
=
"
luacount
"
,
91
public
=
true
,
92
value
=
true
,
93
actions
=
function
(
b
)
94
local
n
=
scanword
(
)
95
if
b
=
=
"
value
"
then
96
return
integer_code
,
integers
[
n
]
or
0
97
else
98
integers
[
n
]
=
scaninteger
(
true
)
99
end
100
end
,
101
}
102 103
implement
{
104
name
=
"
luadimen
"
,
105
public
=
true
,
106
value
=
true
,
107
actions
=
function
(
b
)
108
local
n
=
scanword
(
)
109
if
b
=
=
"
value
"
then
110
return
dimension_code
,
integers
[
n
]
or
0
111
else
112
integers
[
n
]
=
scandimen
(
false
,
false
,
true
)
113
end
114
end
,
115
}
116 117
implement
{
118
name
=
"
luacardinal
"
,
119
public
=
true
,
120
value
=
true
,
121
actions
=
function
(
b
)
122
local
n
=
scanword
(
)
123
if
b
=
=
"
value
"
then
124
context
(
"
%1.0f
"
,
cardinals
[
n
]
or
0
)
125
else
126
cardinals
[
n
]
=
scanluacardinal
(
true
)
127
end
128
end
,
129
}
130 131
implement
{
132
name
=
"
luanumber
"
,
133
public
=
true
,
134
value
=
true
,
135
actions
=
function
(
b
)
136
local
n
=
scanword
(
)
137
if
b
=
=
"
value
"
then
138
context
(
"
%N
"
,
floats
[
n
]
or
integers
[
n
]
or
cardinals
[
n
]
or
0
)
-- maybe %N
139
else
140
-- floats[n] = scanfloat(true)
141
floats
[
n
]
=
scanluanumber
(
true
)
142
end
143
end
,
144
}
145 146
implement
{
147
name
=
"
luarandom
"
,
148
public
=
true
,
149
value
=
true
,
150
actions
=
function
(
b
)
151
if
b
=
=
"
value
"
then
152
return
integer_code
,
random
(
scanluainteger
(
)
,
scanluainteger
(
)
)
153
else
154
randomseed
(
scanluainteger
(
true
)
)
155
end
156
end
,
157
}
158 159
interfaces
.
floats
=
floats
160
interfaces
.
integers
=
integers
161
interfaces
.
cardinals
=
cardinals
162 163
interfaces
.
numbers
=
table
.
setmetatableindex
(
function
(
t
,
k
)
164
return
floats
[
k
]
or
integers
[
k
]
or
cardinals
[
k
]
165
end
)
166 167
-- arrays --
168 169
local
arrays
=
{
}
170 171
interfaces
.
arrays
=
arrays
172 173
local
newindex
=
lua
.
newindex
174 175
implement
{
176
name
=
"
newarray
"
,
177
public
=
true
,
178
protected
=
true
,
179
arguments
=
{
{
180
{
"
name
"
,
"
string
"
}
,
181
{
"
nx
"
,
"
integer
"
}
,
182
{
"
ny
"
,
"
integer
"
}
,
183
{
"
type
"
,
"
string
"
}
,
184
}
}
,
185
actions
=
function
(
t
)
186
local
name
=
t
.
name
187
if
t
.
name
then
188
local
nx
=
t
.
nx
189
local
ny
=
t
.
ny
190
local
ty
=
t
.
type
or
"
integer
"
191
local
df
=
nil
192
if
ty
=
=
"
integer
"
or
ty
=
=
"
float
"
or
ty
=
=
"
dimension
"
then
193
df
=
0
194
elseif
ty
=
=
"
boolean
"
then
195
df
=
false
196
else
197
ty
=
nil
198
end
199
if
nx
and
ty
~
=
nil
then
200
local
data
201
if
ny
then
202
data
=
newindex
(
t
.
ny
)
203
for
i
=
1
,
ny
do
204
data
[
i
]
=
newindex
(
nx
,
df
)
205
end
206
else
207
data
=
newindex
(
nx
,
df
)
208
end
209
arrays
[
name
]
=
data
210
data
.
nx
=
nx
211
data
.
ny
=
ny
212
data
.
type
=
ty
213
if
ty
=
=
"
integer
"
then
214
data
.
scanner
=
scaninteger
215
elseif
ty
=
=
"
boolean
"
then
216
data
.
scanner
=
scanboolean
217
elseif
ty
=
=
"
dimension
"
then
218
data
.
scanner
=
scandimen
219
elseif
ty
=
=
"
float
"
then
220
data
.
scanner
=
scanfloat
221
end
222
if
ty
=
=
"
integer
"
then
223
data
.
code
=
integer_code
224
elseif
ty
=
=
"
boolean
"
then
225
data
.
code
=
boolean_code
226
elseif
ty
=
=
"
dimension
"
then
227
data
.
code
=
dimension_code
228
elseif
ty
=
=
"
float
"
then
229
data
.
code
=
float_code
230
end
231
end
232
end
233
end
,
234
}
235 236
implement
{
237
name
=
"
arrayvalue
"
,
238
public
=
true
,
239
value
=
true
,
240
actions
=
function
(
b
)
241
local
name
=
scanstring
(
)
242
if
name
then
243
local
a
=
arrays
[
name
]
244
if
a
then
245
local
nx
=
a
.
nx
246
local
ny
=
a
.
ny
247
local
d
=
a
248
if
ny
then
249
d
=
d
[
scaninteger
(
)
]
250
end
251
local
x
=
scaninteger
(
)
252
if
b
=
=
"
value
"
then
253
local
code
=
a
.
code
254
if
code
=
=
float_code
then
255
context
(
"
%.99g
"
,
d
[
x
]
)
256
else
257
return
code
,
d
[
x
]
258
end
259
else
260
d
[
x
]
=
a
.
scanner
(
)
261
end
262
end
263
end
264
end
,
265
}
266 267
implement
{
268
name
=
"
arrayequals
"
,
269
public
=
true
,
270
value
=
true
,
271
actions
=
function
(
b
)
272
local
name
=
scanstring
(
)
273
if
name
then
274
local
a
=
arrays
[
name
]
275
if
a
then
276
local
nx
=
a
.
nx
277
local
ny
=
a
.
ny
278
local
d
=
a
279
if
ny
then
280
d
=
d
[
scaninteger
(
)
]
281
end
282
local
x
=
scaninteger
(
)
283
if
b
=
=
"
value
"
then
284
return
boolean_code
,
a
.
scanner
(
)
=
=
d
[
x
]
285
end
286
end
287
end
288
end
,
289
}
290 291
implement
{
292
name
=
"
arraycompare
"
,
293
public
=
true
,
294
value
=
true
,
295
actions
=
function
(
b
)
296
local
name
=
scanstring
(
)
297
if
name
then
298
local
a
=
arrays
[
name
]
299
if
a
then
300
local
nx
=
a
.
nx
301
local
ny
=
a
.
ny
302
local
d
=
a
303
if
ny
then
304
d
=
d
[
scaninteger
(
)
]
305
end
306
local
x
=
scaninteger
(
)
307
if
b
=
=
"
value
"
then
308
local
v
=
a
.
scanner
(
)
309
local
d
=
d
[
x
]
310
if
d
<
v
then
311
return
integer_code
,
0
312
elseif
d
=
=
v
then
313
return
integer_code
,
1
314
else
315
return
integer_code
,
2
316
end
317
end
318
end
319
end
320
end
,
321
}
322 323
implement
{
324
name
=
"
showarray
"
,
325
public
=
true
,
326
protected
=
true
,
327
actions
=
function
(
)
328
local
name
=
scanstring
(
)
329
if
name
then
330
inspect
(
arrays
[
name
]
)
331
end
332
end
,
333
}
334 335
-- expressions --
336 337
local
cache
=
table
.
setmetatableindex
(
function
(
t
,
k
)
338
local
code
=
"
return function() local n = interfaces.numbers local a = interfaces.arrays return
"
.
.
k
.
.
"
end
"
339
code
=
loadstring
(
code
)
340
if
code
then
341
code
=
code
(
)
342
end
343
t
[
k
]
=
code
or
false
344
return
code
345
end
)
346 347
table
.
makeweak
(
cache
)
348 349
implement
{
350
name
=
"
luaexpression
"
,
351
public
=
true
,
352
actions
=
function
(
)
353
local
how
=
scanword
(
)
354
local
code
=
cache
[
scanargument
(
)
]
355
if
code
then
356
local
result
=
code
(
)
357
if
result
then
358
if
not
how
then
359
context
(
tostring
(
code
(
)
)
)
360
elseif
how
=
=
"
float
"
then
361
context
(
"
%.99g
"
,
result
)
362
elseif
how
=
=
"
integer
"
then
363
context
(
"
%i
"
,
round
(
result
)
)
364
elseif
how
=
=
"
cardinal
"
then
365
context
(
"
%d
"
,
abs
(
round
(
result
)
)
)
366
elseif
how
=
=
"
dimen
"
then
367
context
(
"
%p
"
,
result
)
368
elseif
how
=
=
"
boolean
"
then
369
context
(
"
%d
"
,
result
and
1
or
0
)
370
elseif
how
=
=
"
lua
"
then
371
context
(
"
%q
"
,
result
)
372
else
373
context
(
tostring
(
code
(
)
)
)
374
end
375
end
376
end
377
end
378
}
379 380
local
dimenfactors
=
number
.
dimenfactors
381 382
implement
{
383
name
=
"
nodimen
"
,
384
public
=
true
,
385
value
=
true
,
386
actions
=
function
(
b
)
387
if
b
=
=
"
value
"
then
388
local
how
=
scanword
(
)
389
local
what
=
scandimen
(
)
390
if
how
then
391
local
factor
=
dimenfactors
[
how
]
392
if
factor
then
393
context
(
"
%.6N%s
"
,
factor
*
what
,
how
)
394
else
395
return
dimension_code
,
what
396
end
397
else
398
return
dimension_code
,
what
399
end
400
else
401
local
t
=
scantoken
(
)
402
if
t
then
403
local
i
=
getindex
(
t
)
404
if
i
then
405
local
d
=
scandimen
(
false
,
false
,
true
)
406
texsetdimen
(
i
,
d
)
407
end
408
end
409
end
410
end
,
411
}
412 413
-- experimental:
414 415
local
grouped
=
{
}
416
local
slots
=
{
}
417
local
nofslots
=
0
418
local
nofgrouped
=
0
419 420
local
getdata
=
tokens
.
getdata
421
local
setdata
=
tokens
.
setdata
422 423
local
report
=
logs
.
reporter
(
"
lua table
"
)
424 425
local
ctxsprint
=
context
.
sprint
426 427
-- we could have an extra one that collects all end of grouped actions
428
-- so that we dispose more in one go but it doesn's pay off
429 430
local
function
newluatable
(
name
,
mt
,
dispose
)
431
local
g
=
{
}
432
local
t
=
slots
[
nofslots
]
433
slots
[
nofslots
]
=
false
434
nofslots
=
nofslots
-
1
435
if
not
t
then
436
nofgrouped
=
nofgrouped
+
1
437
t
=
nofgrouped
438
end
439
if
mt
then
440
mt
=
getdata
(
name
)
441
if
mt
then
442
mt
=
grouped
[
mt
]
443
if
mt
then
444
setmetatableindex
(
g
,
mt
)
445
end
446
end
447
end
448
grouped
[
t
]
=
g
449
setdata
(
name
,
t
)
450
-- This is the slow part. Doing this at the TeX end saved 10% runtime. I'll
451
-- think of something that we can set it at the Lua end.
452
if
dispose
then
453
ctxsprint
(
"
\\atendofgrouped{\\disposeluatable\\
"
.
.
name
.
.
"
}
"
)
454
end
455
end
456 457
local
function
disposeluatable
(
name
)
458
local
t
=
getdata
(
name
)
459
local
g
=
grouped
[
t
]
460
if
g
then
461
grouped
[
t
]
=
false
462
nofslots
=
nofslots
+
1
463
slots
[
nofslots
]
=
t
464
end
465
end
466 467
local
function
setluatable
(
name
,
kv
)
468
local
t
=
getdata
(
name
)
469
local
g
=
grouped
[
t
]
470
if
g
and
kv
then
471
for
k
,
v
in
next
,
kv
do
472
g
[
k
]
=
v
473
end
474
end
475
end
476 477
local
function
getfromluatable
(
name
,
k
)
478
local
t
=
getdata
(
name
)
479
local
g
=
grouped
[
t
]
480
if
g
then
481
local
v
=
g
[
k
]
482
if
v
then
483
context
(
v
)
484
else
485
local
n
=
tonumber
(
k
)
486
if
n
then
487
local
v
=
g
[
n
]
488
if
v
then
489
context
(
v
)
490
end
491
end
492
end
493
end
494
end
495 496
local
function
idxfromluatable
(
name
,
k
)
497
local
t
=
getdata
(
name
)
498
local
g
=
grouped
[
t
]
499
if
g
then
500
local
v
=
g
[
k
]
501
if
v
then
502
context
(
v
)
503
end
504
end
505
end
506 507
local
function
getluatable
(
name
,
k
)
508
local
t
=
getdata
(
name
)
509
local
g
=
grouped
[
t
]
510
if
g
then
511
return
g
512
end
513
end
514 515
local
function
inspectluatable
(
name
)
516
local
t
=
getdata
(
name
)
517
local
g
=
grouped
[
t
]
518
if
g
then
519
report
(
"
%s
"
,
serialize
(
g
,
'
[grouped slot
'
.
.
t
.
.
'
]
'
)
)
520
end
521
end
522 523
local
function
showluatables
(
)
524
report
(
"
nofgrouped %i, nofslots %i
"
,
nofgrouped
,
nofslots
)
525
for
t
=
1
,
nofgrouped
do
526
local
g
=
grouped
[
t
]
527
if
g
then
528
report
(
"
%s
"
,
serialize
(
g
,
'
[grouped slot
'
.
.
t
.
.
'
]
'
)
)
529
end
530
end
531
end
532 533
implement
{
534
name
=
"
newluatable
"
,
535
protected
=
true
,
536
-- public = true,
537
arguments
=
"
csname
"
,
538
actions
=
newluatable
,
539
}
540 541
implement
{
542
name
=
"
useluatable
"
,
543
protected
=
true
,
544
-- public = true,
545
arguments
=
{
"
csname
"
,
true
}
,
546
actions
=
newluatable
,
547
}
548 549
implement
{
550
name
=
"
disposeluatable
"
,
551
protected
=
true
,
552
public
=
true
,
553
arguments
=
"
csname
"
,
554
actions
=
disposeluatable
,
555
}
556 557
implement
{
558
name
=
"
inspectluatable
"
,
559
protected
=
true
,
560
public
=
true
,
561
arguments
=
"
csname
"
,
562
actions
=
inspectluatable
,
563
}
564 565
implement
{
566
name
=
"
showluatables
"
,
567
protected
=
true
,
568
public
=
true
,
569
actions
=
showluatables
,
570
}
571 572
implement
{
573
name
=
"
setluatable
"
,
574
protected
=
true
,
575
public
=
true
,
576
arguments
=
{
"
csname
"
,
"
argument
"
}
,
577
actions
=
function
(
name
,
data
)
578
data
=
load
(
"
return {
"
.
.
data
.
.
"
}
"
)
579
if
data
then
580
data
=
data
(
)
581
if
data
then
582
setluatable
(
name
,
data
)
583
end
584
end
585
end
586
}
587 588
implement
{
589
name
=
"
getfromluatable
"
,
590
protected
=
false
,
591
public
=
true
,
592
arguments
=
{
"
csname
"
,
"
argument
"
}
,
593
actions
=
getfromluatable
,
594
}
595 596
implement
{
597
name
=
"
idxfromluatable
"
,
598
protected
=
false
,
599
public
=
true
,
600
arguments
=
{
"
csname
"
,
"
integer
"
}
,
601
actions
=
idxfromluatable
,
602
}
603 604
context
.
luatables
=
{
605
new
=
function
(
name
)
newluatable
(
name
,
false
,
true
)
end
,
606
use
=
function
(
name
)
useluatable
(
name
,
true
,
true
)
end
,
607
dispose
=
disposeluatable
,
608
set
=
setluatable
,
609
get
=
getluatable
,
610
getfrom
=
getfromluatable
,
611
idxfrom
=
idxfromluatable
,
612
inspect
=
inspectluatable
,
613
show
=
showluatables
,
614
}
615 616
-- Here's another mechanism ...
617 618
local
tables
=
{
}
619
local
stack
=
setmetatableindex
(
"
table
"
)
620 621
interfaces
.
implement
{
622
name
=
"
droptablegroup
"
,
623
public
=
true
,
624
actions
=
function
(
)
625
local
g
=
texget
(
"
currentgrouplevel
"
)
-- todo: tex.getgrouplevel()
626
local
s
=
stack
[
g
]
627
if
s
then
628
for
t
,
data
in
next
,
s
do
629
for
k
,
v
in
next
,
data
do
630
t
[
k
]
=
v
631
end
632
end
633
stack
[
g
]
=
{
}
634
end
635
end
,
636
}
637 638
local
ctx_atendofgroup
=
context
.
core
.
cs
.
atendofgroup
639
local
ctx_droptablegroup
=
context
.
core
.
cs
.
droptablegroup
640 641
local
function
handletable
(
t
,
b
,
array
)
642
if
b
=
=
"
value
"
then
643
local
k
=
array
and
scaninteger
(
)
or
scanargument
(
)
644
local
v
=
t
[
k
]
645
if
v
then
646
context
(
v
)
647
end
648
else
649
local
data
=
scanargument
(
)
650
data
=
load
(
"
return {
"
.
.
data
.
.
"
}
"
)
651
if
data
then
652
data
=
data
(
)
653
if
data
then
654
local
l
=
t
.
level
655
local
g
=
texget
(
"
currentgrouplevel
"
)
-- todo: tex.getgrouplevel()
656
local
s
=
stack
[
g
]
657
local
d
=
s
[
t
]
658
if
not
d
then
659
d
=
{
}
660
s
[
t
]
=
d
661
ctx_atendofgroup
(
)
662
ctx_droptablegroup
(
)
663
end
664
for
k
,
v
in
next
,
data
do
665
if
not
d
[
k
]
then
666
d
[
k
]
=
t
[
k
]
667
end
668
t
[
k
]
=
v
669
end
670
if
b
=
=
"
global
"
then
671
for
k
,
v
in
next
,
stack
do
672
local
t
=
s
[
t
]
673
if
t
then
674
for
k
,
v
in
next
,
data
do
675
if
t
[
k
]
then
676
t
[
k
]
=
nil
677
end
678
end
679
end
680
end
681
end
682
end
683
end
684
end
685
end
686 687
local
function
newtable
(
array
)
688
local
name
=
scancsname
(
true
)
689
if
not
tables
[
name
]
then
690
local
t
=
{
}
691
tables
[
name
]
=
t
692
interfaces
.
implement
{
693
name
=
name
,
694
public
=
true
,
695
value
=
true
,
696
actions
=
function
(
b
)
697
handletable
(
t
,
b
,
array
)
698
end
,
699
}
700
else
701
-- already defined
702
end
703
end
704 705
implement
{
706
name
=
"
newhashedtable
"
,
707
protected
=
true
,
708
public
=
true
,
709
actions
=
newtable
,
710
}
711 712
implement
{
713
name
=
"
newindexedtable
"
,
714
protected
=
true
,
715
public
=
true
,
716
actions
=
function
(
)
newtable
(
true
)
end
,
717
}
718 719
context
.
hashedtables
=
setmetatableindex
(
function
(
t
,
k
)
return
tables
[
k
]
end
)
720
context
.
indexedtables
=
context
.
hashedtables
721