node-nut.lua /size: 25 Kb    last modification: 2021-10-28 13:50
1
    
if
not
modules
then
modules
=
{
}
end
modules
[
'
node-nut
'
]
=
{
2
version
=
1
.
001
,
3
comment
=
"
companion to node-ini.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
-- Here starts some more experimental code that Luigi and I use in a next stage of
10
-- exploring and testing potential speedups in the engines. This code is not meant
11
-- for users and can change (or be removed) any moment. During the experiments I'll
12
-- do my best to keep the code as fast as possible by using two codebases. See
13
-- about-fast.pdf for some more info about impacts. Although key based access has
14
-- more charm, function based is somewhat faster and has more potential for future
15
-- speedups.
16 17
-- This next iteration is flagged direct because we avoid user data which has a price
18
-- in allocation and metatable tagging. Although in this stage we pass numbers around
19
-- future versions might use light user data, so never depend on what direct function
20
-- return. Using the direct approach had some speed advantages but you loose the key
21
-- based access. The speed gain is only measurable in cases with lots of access. For
22
-- instance when typesettign arabic with advanced fonts, we're talking of many millions
23
-- of function calls and there we can get a 30\% or more speedup. On average complex
24
-- \CONTEXT\ runs the gain can be 10\% to 15\% percent. Because mixing the two models
25
-- (here we call then nodes and nuts) is not possible you need to cast either way which
26
-- has a penalty. Also, error messages in nuts mode are less clear and \LUATEX\ will
27
-- often simply abort when you make mistakes of mix the models. So, development (at least
28
-- in \CONTEXT) can be done in node mode and not in nuts mode. Only robust code will
29
-- be turned nuts afterwards and quite likely not all code. The official \LUATEX\ api
30
-- to nodes is userdata!
31
--
32
-- Listening to 'lunatic soul' at the same time helped wrapping my mind around the mixed
33
-- usage of both models. Just for the record: the potential of the direct approach only
34
-- became clear after experimenting for weeks and partly adapting code. It is one of those
35
-- (sub)projects where you afterwards wonder if it was worth the trouble, but users that
36
-- rely on lots of complex functionality and font support will probably notice the speedup.
37
--
38
-- luatex luajittex
39
-- ------------- ----- -------------------- ---------------------------------
40
-- name pages old new pct old new pct
41
-- ------------- ----- -------------------- ---------------------------------
42
-- fonts-mkiv 166 9.3 7.7/7.4 17.2 7.4 (37.5) 5.9/5.7 (55.6) 20.3
43
-- about 60 3.3 2.7/2.6 20.4 2.5 (39.5) 2.1 (57.0) 23.4
44
-- arabic-001 61 25.3 15.8 18.2 15.3 (46.7) 6.8 (54.7) 16.0
45
-- torture-001 300 21.4 11.4 24.2 13.9 (35.0) 6.3 (44.7) 22.2
46
--
47
-- so:
48
--
49
-- - we run around 20% faster on documents of average complexity and gain more when
50
-- dealing with scripts like arabic and such
51
-- - luajittex benefits a bit more so a luajittex job can (in principle) now be much
52
-- faster
53
-- - if we reason backwards, and take luajittex as norm we get 1:2:3 on some jobs for
54
-- luajittex direct:luatex direct:luatex normal i.e. we can be 3 times faster
55
-- - keep in mind that these are tex/lua runs so the real gain at the lua end is much
56
-- larger
57
--
58
-- Because we can fake direct mode a little bit by using the fast getfield and setfield
59
-- at the cost of wrapped getid and alike, we still are running quite ok. As we could gain
60
-- some 5% with fast mode, we can sacrifice some on wrappers when we use a few fast core
61
-- functions. This means that simulated direct mode runs font-mkiv in 9.1 seconds (we could
62
-- get down to 8.7 seconds in fast mode) and that we can migrate slowely to direct mode.
63
--
64
-- The following measurements are from 2013-07-05 after adapting some 47 files to nuts. Keep
65
-- in mind that the old binary can fake a fast getfield and setfield but that the other
66
-- getters are wrapped functions. The more we have, the slower it gets.
67
--
68
-- fonts about arabic
69
-- old mingw, indexed plus some functions : 8.9 3.2 20.3
70
-- old mingw, fake functions : 9.9 3.5 27.4
71
-- new mingw, node functions : 9.0 3.1 20.8
72
-- new mingw, indexed plus some functions : 8.6 3.1 19.6
73
-- new mingw, direct functions : 7.5 2.6 14.4
74
--
75
-- \starttext \dorecurse{1000}{test\page} \stoptext :
76
--
77
-- luatex 560 pps
78
-- luajittex 600 pps
79
--
80
-- \setupbodyfont[pagella]
81
--
82
-- \edef\zapf{\cldcontext{context(io.loaddata(resolvers.findfile("zapf.tex")))}}
83
--
84
-- \starttext \dorecurse{1000}{\zapf\par} \stoptext
85
--
86
-- luatex 3.9 sec / 54 pps
87
-- luajittex 2.3 sec / 93 pps
88 89
local
type
,
rawget
=
type
,
rawget
90 91
local
nodes
=
nodes
92
local
direct
=
node
.
direct
93 94
local
fastcopy
=
table
.
fastcopy
95 96
local
nodecodes
=
nodes
.
nodecodes
97
local
hlist_code
=
nodecodes
.
hlist
98
local
vlist_code
=
nodecodes
.
vlist
99
local
glyph_code
=
nodecodes
.
glyph
100 101
local
nuts
=
nodes
.
nuts
or
{
}
102
nodes
.
nuts
=
nuts
103 104
nodes
.
isnode
=
direct
.
isnode
or
function
(
)
return
true
end
105
nodes
.
isdirect
=
direct
.
isdirect
or
function
(
)
return
false
end
106
nodes
.
isnut
=
nodes
.
isdirect
107 108
-- casters
109 110
local
tonode
=
direct
.
tonode
or
function
(
n
)
return
n
end
111
local
tonut
=
direct
.
todirect
or
function
(
n
)
return
n
end
112 113
nuts
.
tonode
=
tonode
114
nuts
.
tonut
=
tonut
115 116
nodes
.
tonode
=
tonode
117
nodes
.
tonut
=
tonut
118 119
-- helpers
120 121
local
nuts
=
nodes
.
nuts
122 123
nuts
.
checkdiscretionaries
=
direct
.
check_discretionaries
124
nuts
.
copy
=
direct
.
copy
125
nuts
.
copynode
=
direct
.
copy
126
nuts
.
copyonly
=
direct
.
copy_only
or
direct
.
copy
127
nuts
.
copylist
=
direct
.
copy_list
128
nuts
.
count
=
direct
.
count
129
nuts
.
currentattribute
=
direct
.
current_attr
130
nuts
.
currentattr
=
direct
.
current_attr
131
nuts
.
delete
=
direct
.
delete
132
nuts
.
dimensions
=
direct
.
dimensions
133
nuts
.
endofmath
=
direct
.
end_of_math
134
nuts
.
findattribute
=
direct
.
find_attribute
135
nuts
.
firstglyph
=
direct
.
first_glyph
136
nuts
.
flattendiscretionaries
=
direct
.
flatten_discretionaries
137
nuts
.
flush
=
direct
.
flush_node
138
nuts
.
flushlist
=
direct
.
flush_list
139
nuts
.
flushnode
=
direct
.
flush_node
140
nuts
.
free
=
direct
.
free
141
nuts
.
getsynctexfields
=
direct
.
get_synctex_fields
142
nuts
.
hasattribute
=
direct
.
has_attribute
143
nuts
.
hasfield
=
direct
.
has_field
144
nuts
.
hasglyph
=
direct
.
has_glyph
or
direct
.
first_glyph
145
nuts
.
hpack
=
direct
.
hpack
146
nuts
.
insertafter
=
direct
.
insert_after
147
nuts
.
insertbefore
=
direct
.
insert_before
148
nuts
.
isdirect
=
direct
.
is_direct
149
nuts
.
isnode
=
direct
.
is_node
150
nuts
.
isnut
=
direct
.
is_direct
151
nuts
.
kerning
=
direct
.
kerning
152
nuts
.
hyphenating
=
direct
.
hyphenating
153
nuts
.
lastnode
=
direct
.
last_node
154
nuts
.
length
=
direct
.
length
155
nuts
.
ligaturing
=
direct
.
ligaturing
156
nuts
.
new
=
direct
.
new
157
nuts
.
protectglyph
=
direct
.
protect_glyph
158
nuts
.
protectglyphs
=
direct
.
protect_glyphs
159
nuts
.
protrusionskippable
=
direct
.
protrusion_skippable
160
nuts
.
rangedimensions
=
direct
.
rangedimensions
161
nuts
.
setattribute
=
direct
.
set_attribute
162
nuts
.
setsynctexfields
=
direct
.
set_synctex_fields
163
nuts
.
slide
=
direct
.
slide
164
nuts
.
tail
=
direct
.
tail
165
nuts
.
tostring
=
direct
.
tostring
166
nuts
.
traverse
=
direct
.
traverse
167
nuts
.
traversechar
=
direct
.
traverse_char
168
nuts
.
traverseglyph
=
direct
.
traverse_glyph
169
nuts
.
traverseid
=
direct
.
traverse_id
170
nuts
.
traverselist
=
direct
.
traverse_list
171
nuts
.
unprotectglyph
=
direct
.
unprotect_glyph
172
nuts
.
unprotectglyphs
=
direct
.
unprotect_glyphs
173
nuts
.
unsetattribute
=
direct
.
unset_attribute
174
nuts
.
unsetattribute
=
direct
.
unset_attribute
175
nuts
.
usedlist
=
direct
.
usedlist
176
nuts
.
usesfont
=
direct
.
uses_font
177
nuts
.
vpack
=
direct
.
vpack
178
nuts
.
write
=
direct
.
write
179
nuts
.
mlisttohlist
=
direct
.
mlist_to_hlist
180
nuts
.
hasdimensions
=
direct
.
has_dimensions
181
nuts
.
startofpar
=
direct
.
start_of_par
182
nuts
.
migrate
=
direct
.
migrate
183 184
if
not
nuts
.
mlisttohlist
then
185 186
local
n_mlisttohlist
=
node
.
mlist_to_hlist
187 188
function
nuts
.
mlisttohlist
(
head
,
...
)
189
if
head
then
190
local
head
=
n_mlisttohlist
(
tonode
(
head
)
,
...
)
191
if
head
then
192
return
tonut
(
head
)
193
end
194
end
195
end
196 197
end
198 199
if
not
nuts
.
hasdimensions
then
200 201
local
getwhd
=
direct
.
getwhd
202 203
function
nuts
.
hasdimensions
(
n
)
204
local
wd
,
ht
,
dp
=
getwhd
(
n
)
205
return
wd
~
=
0
or
(
ht
+
dp
)
~
=
0
206
end
207 208
end
209 210
local
getfield
=
direct
.
getfield
211
local
setfield
=
direct
.
setfield
212 213
nuts
.
getfield
=
getfield
214
nuts
.
setfield
=
setfield
215 216
nuts
.
getnext
=
direct
.
getnext
217
nuts
.
setnext
=
direct
.
setnext
218 219
nuts
.
getid
=
direct
.
getid
220 221
nuts
.
getprev
=
direct
.
getprev
222
nuts
.
setprev
=
direct
.
setprev
223 224
local
getattribute
=
direct
.
get_attribute
225
local
setattribute
=
direct
.
set_attribute
226
local
unsetattribute
=
direct
.
unset_attribute
227 228
nuts
.
getattr
=
getattribute
229
nuts
.
setattr
=
setattribute
230
nuts
.
takeattr
=
unsetattribute
-- ?
231 232
nuts
.
getattribute
=
getattribute
233
nuts
.
setattribute
=
setattribute
234
nuts
.
unsetattribute
=
unsetattribute
-- ?
235 236
nuts
.
iszeroglue
=
direct
.
is_zero_glue
237
nuts
.
effectiveglue
=
direct
.
effective_glue
238 239
nuts
.
getglue
=
direct
.
getglue
240
nuts
.
setglue
=
direct
.
setglue
241
nuts
.
getboxglue
=
direct
.
getglue
242
nuts
.
setboxglue
=
direct
.
setglue
243 244
nuts
.
getdisc
=
direct
.
getdisc
245
nuts
.
setdisc
=
direct
.
setdisc
246
nuts
.
getdiscretionary
=
direct
.
getdisc
247
nuts
.
setdiscretionary
=
direct
.
setdisc
248 249
nuts
.
getpre
=
direct
.
getpre
250
nuts
.
setpre
=
direct
.
setpre
251
nuts
.
getpost
=
direct
.
getpost
252
nuts
.
setpost
=
direct
.
setpost
253
nuts
.
getreplace
=
direct
.
getreplace
254
nuts
.
setreplace
=
direct
.
setreplace
255 256
local
getdata
=
direct
.
getdata
257
local
setdata
=
direct
.
setdata
258 259
nuts
.
getdata
=
getdata
260
nuts
.
setdata
=
setdata
261
nuts
.
getvalue
=
getdata
262
nuts
.
setvalue
=
setdata
263 264
nuts
.
getexpansion
=
direct
.
getexpansion
265
nuts
.
setexpansion
=
direct
.
setexpansion
266 267
nuts
.
getwhd
=
direct
.
getwhd
268
nuts
.
setwhd
=
direct
.
setwhd
269
nuts
.
getwidth
=
direct
.
getwidth
270
nuts
.
setwidth
=
direct
.
setwidth
271
nuts
.
getheight
=
direct
.
getheight
272
nuts
.
setheight
=
direct
.
setheight
273
nuts
.
getdepth
=
direct
.
getdepth
274
nuts
.
setdepth
=
direct
.
setdepth
275
nuts
.
getshift
=
direct
.
getshift
276
nuts
.
setshift
=
direct
.
setshift
277
nuts
.
gettotal
=
direct
.
gettotal
278 279
-- lmtx compatibility
280 281
nuts
.
getorientation
=
direct
.
getorientation
or
function
(
)
end
282
nuts
.
setorientation
=
direct
.
setorientation
or
function
(
)
end
283 284
nuts
.
getglyphdata
=
direct
.
getglyphdata
or
getattribute
285
nuts
.
setglyphdata
=
direct
.
setglyphdata
or
function
(
n
,
d
)
setattribute
(
n
,
0
,
d
)
end
286 287
nuts
.
getruledata
=
direct
.
getglyphdata
and
getdata
or
function
(
n
)
return
getfield
(
n
,
"
transform
"
)
end
288
nuts
.
setruledata
=
direct
.
setglyphdata
and
setdata
or
function
(
n
,
d
)
return
setfield
(
n
,
"
transform
"
,
d
)
end
289 290
-- maybe some day: [g|s]etglyphoptions and then use attribute for mkiv / generic but not now
291 292
nuts
.
getoptions
=
direct
.
getoptions
or
function
(
)
return
0
end
293
nuts
.
setoptions
=
direct
.
setoptions
or
function
(
)
end
294 295
-- so far
296 297
nuts
.
getnucleus
=
direct
.
getnucleus
298
nuts
.
setnucleus
=
direct
.
setnucleus
299
nuts
.
getsup
=
direct
.
getsup
300
nuts
.
setsup
=
direct
.
setsup
301
nuts
.
getsub
=
direct
.
getsub
302
nuts
.
setsub
=
direct
.
setsub
303
nuts
.
getsuppre
=
direct
.
getsuppre
304
nuts
.
setsuppre
=
direct
.
setsuppre
305
nuts
.
getsubpre
=
direct
.
getsubpre
306
nuts
.
setsubpre
=
direct
.
setsubpre
307 308
nuts
.
getchar
=
direct
.
getchar
309
nuts
.
setchar
=
direct
.
setchar
310
nuts
.
getfont
=
direct
.
getfont
311
nuts
.
setfont
=
direct
.
setfont
312
nuts
.
getfam
=
direct
.
getfam
313
nuts
.
setfam
=
direct
.
setfam
314 315
nuts
.
getboth
=
direct
.
getboth
316
nuts
.
setboth
=
direct
.
setboth
317
nuts
.
setlink
=
direct
.
setlink
318
nuts
.
exchange
=
direct
.
exchange
319
nuts
.
reverse
=
direct
.
reverse
320
nuts
.
setsplit
=
direct
.
setsplit
321 322
nuts
.
getlist
=
direct
.
getlist
-- only hlist and vlist !
323
nuts
.
setlist
=
direct
.
setlist
324
nuts
.
getleader
=
direct
.
getleader
325
nuts
.
setleader
=
direct
.
setleader
326
nuts
.
getcomponents
=
direct
.
getcomponents
327
nuts
.
setcomponents
=
direct
.
setcomponents
328 329
nuts
.
getsubtype
=
direct
.
getsubtype
330
nuts
.
setsubtype
=
direct
.
setsubtype
331 332
nuts
.
getlang
=
direct
.
getlang
333
nuts
.
setlang
=
direct
.
setlang
334
nuts
.
getlanguage
=
direct
.
getlang
335
nuts
.
setlanguage
=
direct
.
setlang
336 337
nuts
.
getattrlist
=
direct
.
getattributelist
338
nuts
.
setattrlist
=
direct
.
setattributelist
339
nuts
.
getattributelist
=
direct
.
getattributelist
340
nuts
.
setattributelist
=
direct
.
setattributelist
341 342
nuts
.
getoffsets
=
direct
.
getoffsets
343
nuts
.
setoffsets
=
direct
.
setoffsets
344 345
nuts
.
getkern
=
direct
.
getkern
346
nuts
.
setkern
=
direct
.
setkern
347 348
nuts
.
getdir
=
direct
.
getdir
349
nuts
.
setdir
=
direct
.
setdir
350 351
nuts
.
getdirection
=
direct
.
getdirection
352
nuts
.
setdirection
=
direct
.
setdirection
353 354
nuts
.
getpenalty
=
direct
.
getpenalty
355
nuts
.
setpenalty
=
direct
.
setpenalty
356 357
nuts
.
getbox
=
direct
.
getbox
358
nuts
.
setbox
=
direct
.
setbox
359 360
nuts
.
ischar
=
direct
.
is_char
361
nuts
.
isglyph
=
direct
.
is_glyph
362 363
local
d_remove_node
=
direct
.
remove
364
local
d_flushnode
=
direct
.
flush_node
365
local
d_getnext
=
direct
.
getnext
366
local
d_getprev
=
direct
.
getprev
367
local
d_getid
=
direct
.
getid
368
local
d_getlist
=
direct
.
getlist
369
local
d_find_tail
=
direct
.
tail
370
local
d_insertafter
=
direct
.
insert_after
371
local
d_insertbefore
=
direct
.
insert_before
372
local
d_slide
=
direct
.
slide
373
local
d_traverse
=
direct
.
traverse
374
local
d_setlink
=
direct
.
setlink
375
local
d_setboth
=
direct
.
setboth
376
local
d_getboth
=
direct
.
getboth
377 378
local
remove
=
function
(
head
,
current
,
free_too
)
379
if
current
then
380
local
h
,
c
=
d_remove_node
(
head
,
current
)
381
if
free_too
then
382
d_flushnode
(
current
)
383
return
h
,
c
384
else
385
d_setboth
(
current
)
386
return
h
,
c
,
current
387
end
388
end
389
return
head
,
current
390
end
391 392
-- for now
393 394
if
not
nuts
.
startofpar
then
395 396
local
parcodes
=
nodes
.
parcodes
397
local
hmodepar_code
=
parcodes
.
vmode_par
398
local
vmodepar_code
=
parcodes
.
hmode_par
399 400
local
getsubtype
=
nuts
.
getsubtype
401 402
function
nuts
.
startofpar
(
n
)
403
local
s
=
getsubtype
(
n
)
404
return
s
=
=
hmodepar_code
or
s
=
=
vmodepar_code
405
end
406 407
end
408 409
-- for now
410 411
if
not
nuts
.
exchange
then
412 413
local
d_getprev
=
direct
.
getprev
414
local
d_getnext
=
direct
.
getnext
415
local
d_setlink
=
direct
.
setlink
416 417
function
nuts
.
exchange
(
head
,
first
,
second
)
418
if
first
then
419
if
not
second
then
420
second
=
d_getnext
(
first
)
421
end
422
if
second
then
423
d_setlink
(
d_getprev
(
first
)
,
second
,
first
,
d_getnext
(
second
)
)
424
if
first
=
=
head
then
425
return
second
426
end
427
end
428
end
429
return
head
430
end
431 432
end
433 434
-- for now
435 436
if
not
nuts
.
getpre
then
437 438
local
d_getdisc
=
direct
.
getdisc
439
local
d_setfield
=
direct
.
setfield
440 441
function
nuts
.
getpre
(
n
)
local
h
,
_
,
_
,
t
,
_
,
_
=
d_getdisc
(
n
,
true
)
return
h
,
t
end
442
function
nuts
.
getpost
(
n
)
local
_
,
h
,
_
,
_
,
t
,
_
=
d_getdisc
(
n
,
true
)
return
h
,
t
end
443
function
nuts
.
getreplace
(
n
)
local
_
,
_
,
h
,
_
,
_
,
t
=
d_getdisc
(
n
,
true
)
return
h
,
t
end
444 445
function
nuts
.
setpre
(
n
,
h
)
d_setfield
(
n
,
"
pre
"
,
h
)
end
446
function
nuts
.
setpost
(
n
,
h
)
d_setfield
(
n
,
"
post
"
,
h
)
end
447
function
nuts
.
setreplace
(
n
,
h
)
d_setfield
(
n
,
"
replace
"
,
h
)
end
448 449
end
450 451
if
not
nuts
.
gettotal
then
452 453
local
d_getheight
=
direct
.
getheight
454
local
d_getdepth
=
direct
.
getdepth
455 456
function
nuts
.
gettotal
(
n
)
457
return
(
d_getheight
(
n
)
or
0
)
+
(
d_getdepth
(
n
)
or
0
)
458
end
459 460
end
461 462
-- alias
463 464
nuts
.
getsurround
=
nuts
.
getkern
465
nuts
.
setsurround
=
nuts
.
setkern
466 467
nuts
.
remove
=
remove
468 469
function
nuts
.
delete
(
head
,
current
)
470
return
remove
(
head
,
current
,
true
)
471
end
472 473
function
nuts
.
replace
(
head
,
current
,
new
)
-- no head returned if false
474
if
not
new
then
475
head
,
current
,
new
=
false
,
head
,
current
476
end
477
local
prev
,
next
=
d_getboth
(
current
)
478
if
prev
or
next
then
479
d_setlink
(
prev
,
new
,
next
)
480
end
481
if
head
then
482
if
head
=
=
current
then
483
head
=
new
484
end
485
d_flushnode
(
current
)
486
return
head
,
new
487
else
488
d_flushnode
(
current
)
489
return
new
490
end
491
end
492 493
local
function
countall
(
stack
,
flat
)
494
local
n
=
0
495
while
stack
do
496
local
id
=
d_getid
(
stack
)
497
if
not
flat
and
id
=
=
hlist_code
or
id
=
=
vlist_code
then
498
local
list
=
d_getlist
(
stack
)
499
if
list
then
500
n
=
n
+
1
+
countall
(
list
)
-- self counts too
501
else
502
n
=
n
+
1
503
end
504
else
505
n
=
n
+
1
506
end
507
stack
=
d_getnext
(
stack
)
508
end
509
return
n
510
end
511 512
nuts
.
countall
=
countall
513 514
function
nodes
.
countall
(
stack
,
flat
)
515
return
countall
(
tonut
(
stack
)
,
flat
)
516
end
517 518
function
nuts
.
append
(
head
,
current
,
...
)
519
for
i
=
1
,
select
(
"
#
"
,
...
)
do
520
head
,
current
=
d_insertafter
(
head
,
current
,
(
select
(
i
,
...
)
)
)
521
end
522
return
head
,
current
523
end
524 525
function
nuts
.
prepend
(
head
,
current
,
...
)
526
for
i
=
1
,
select
(
"
#
"
,
...
)
do
527
head
,
current
=
d_insertbefore
(
head
,
current
,
(
select
(
i
,
...
)
)
)
528
end
529
return
head
,
current
530
end
531 532
function
nuts
.
linked
(
...
)
-- slides !
533
local
head
,
last
534
for
i
=
1
,
select
(
"
#
"
,
...
)
do
535
local
next
=
select
(
i
,
...
)
536
if
next
then
537
if
head
then
538
d_setlink
(
last
,
next
)
539
else
540
head
=
next
541
end
542
last
=
d_find_tail
(
next
)
-- we could skip the last one
543
end
544
end
545
return
head
546
end
547 548
function
nuts
.
concat
(
list
)
-- consider tail instead of slide
549
local
head
,
tail
550
for
i
=
1
,
#
list
do
551
local
li
=
list
[
i
]
552
if
li
then
553
if
head
then
554
d_setlink
(
tail
,
li
)
555
else
556
head
=
li
557
end
558
tail
=
d_slide
(
li
)
559
end
560
end
561
return
head
,
tail
562
end
563 564
function
nuts
.
reference
(
n
)
565
return
n
or
"
<none>
"
566
end
567 568
-- quick and dirty tracing of nuts
569 570
-- for k, v in next, nuts do
571
-- if string.find(k,"box") then
572
-- nuts[k] = function(...) print(k,...) return v(...) end
573
-- end
574
-- end
575 576
function
nodes
.
vianuts
(
f
)
return
function
(
n
,
...
)
return
tonode
(
f
(
tonut
(
n
)
,
...
)
)
end
end
577
function
nodes
.
vianodes
(
f
)
return
function
(
n
,
...
)
return
tonut
(
f
(
tonode
(
n
)
,
...
)
)
end
end
578 579
nuts
.
vianuts
=
nodes
.
vianuts
580
nuts
.
vianodes
=
nodes
.
vianodes
581 582
function
nodes
.
insertlistafter
(
h
,
c
,
n
)
583
local
t
=
n_tail
(
n
)
584
if
c
then
585
local
cn
=
n_getnext
(
c
)
586
if
cn
then
587
-- no setboth here yet
588
n_setfield
(
t
,
"
next
"
,
cn
)
589
n_setfield
(
cn
,
"
prev
"
,
t
)
590
else
591
n_setfield
(
t
,
"
next
"
,
nil
)
592
end
593
n_setfield
(
c
,
"
next
"
,
n
)
594
n_setfield
(
n
,
"
prev
"
,
c
)
595
return
h
,
n
596
end
597
return
n
,
t
598
end
599 600
function
nuts
.
insertlistafter
(
h
,
c
,
n
)
601
local
t
=
d_tail
(
n
)
602
if
c
then
603
local
cn
=
d_getnext
(
c
)
604
if
cn
then
605
d_setlink
(
t
,
cn
)
606
else
607
d_setnext
(
t
)
608
end
609
d_setlink
(
c
,
n
)
610
return
h
,
n
611
end
612
return
n
,
t
613
end
614 615
-- test code only
616 617
-- collectranges and mix
618 619
local
report
=
logs
.
reporter
(
"
sliding
"
)
620 621
local
function
message
(
detail
,
head
,
current
,
previous
)
622
report
(
"
error: %s, current: %s:%s, previous: %s:%s, list: %s, text: %s
"
,
623
detail
,
624
nodecodes
[
d_getid
(
current
)
]
,
625
current
,
626
nodecodes
[
d_getid
(
previous
)
]
,
627
previous
,
628
nodes
.
idstostring
(
head
)
,
629
nodes
.
listtoutf
(
head
)
630
)
631
utilities
.
debugger
.
showtraceback
(
report
)
632
end
633 634
local
function
warn
(
)
635
report
(
)
636
report
(
"
warning: the slide tracer is enabled
"
)
637
report
(
)
638
warn
=
false
639
end
640 641
local
function
tracedslide
(
head
)
642
if
head
then
643
if
warn
then
644
warn
(
)
645
end
646
local
next
=
d_getnext
(
head
)
647
if
next
then
648
local
prev
=
head
649
for
n
in
d_traverse
(
next
)
do
650
local
p
=
d_getprev
(
n
)
651
if
not
p
then
652
message
(
"
unset
"
,
head
,
n
,
prev
)
653
-- break
654
elseif
p
~
=
prev
then
655
message
(
"
wrong
"
,
head
,
n
,
prev
)
656
-- break
657
end
658
prev
=
n
659
end
660
end
661
return
d_slide
(
head
)
662
end
663
end
664 665
local
function
nestedtracedslide
(
head
,
level
)
-- no sliding !
666
if
head
then
667
if
warn
then
668
warn
(
)
669
end
670
local
id
=
d_getid
(
head
)
671
local
next
=
d_getnext
(
head
)
672
if
next
then
673
report
(
"
%whead:%s
"
,
level
or
0
,
nodecodes
[
id
]
)
674
local
prev
=
head
675
for
n
in
d_traverse
(
next
)
do
676
local
p
=
d_getprev
(
n
)
677
if
not
p
then
678
message
(
"
unset
"
,
head
,
n
,
prev
)
679
-- break
680
elseif
p
~
=
prev
then
681
message
(
"
wrong
"
,
head
,
n
,
prev
)
682
-- break
683
end
684
prev
=
n
685
local
id
=
d_getid
(
n
)
686
if
id
=
=
hlist_code
or
id
=
=
vlist_code
then
687
nestedtracedslide
(
d_getlist
(
n
)
,
(
level
or
0
)
+
1
)
688
end
689
end
690
elseif
id
=
=
hlist_code
or
id
=
=
vlist_code
then
691
report
(
"
%wlist:%s
"
,
level
or
0
,
nodecodes
[
id
]
)
692
nestedtracedslide
(
d_getlist
(
head
)
,
(
level
or
0
)
+
1
)
693
end
694
-- return d_slide(head)
695
end
696
end
697 698
local
function
untracedslide
(
head
)
699
if
head
then
700
if
warn
then
701
warn
(
)
702
end
703
local
next
=
d_getnext
(
head
)
704
if
next
then
705
local
prev
=
head
706
for
n
in
d_traverse
(
next
)
do
707
local
p
=
d_getprev
(
n
)
708
if
not
p
then
709
return
"
unset
"
,
d_getid
(
n
)
710
elseif
p
~
=
prev
then
711
return
"
wrong
"
,
d_getid
(
n
)
712
end
713
prev
=
n
714
end
715
end
716
return
d_slide
(
head
)
717
end
718
end
719 720
nuts
.
tracedslide
=
tracedslide
721
nuts
.
untracedslide
=
untracedslide
722
nuts
.
nestedtracedslide
=
nestedtracedslide
723 724
-- this might move
725 726
local
propertydata
=
direct
.
get_properties_table
(
true
)
727 728
local
getattr
=
nuts
.
getattr
729
local
setattr
=
nuts
.
setattr
730 731
nodes
.
properties
=
{
732
data
=
propertydata
,
733
}
734 735
if
direct
.
set_properties_mode
then
736
direct
.
set_properties_mode
(
true
,
true
)
-- create metatable, slower but needed for font-otj.lua (unless we use an intermediate table)
737
function
direct
.
set_properties_mode
(
)
end
738
end
739 740
-- experimental code with respect to copying attributes has been removed
741
-- as it doesn't pay of (most attributes are only accessed once anyway)
742 743
nuts
.
getprop
=
function
(
n
,
k
)
744
local
p
=
propertydata
[
n
]
745
if
p
then
746
if
k
then
747
return
p
[
k
]
748
else
749
return
p
750
end
751
end
752
end
753 754
nuts
.
rawprop
=
function
(
n
,
k
)
755
local
p
=
rawget
(
propertydata
,
n
)
756
if
p
then
757
if
k
then
758
return
p
[
k
]
759
else
760
return
p
761
end
762
end
763
end
764 765
nuts
.
setprop
=
function
(
n
,
k
,
v
)
766
local
p
=
propertydata
[
n
]
767
if
p
then
768
p
[
k
]
=
v
769
else
770
propertydata
[
n
]
=
{
[
k
]
=
v
}
771
end
772
end
773 774
nuts
.
theprop
=
function
(
n
)
775
local
p
=
propertydata
[
n
]
776
if
not
p
then
777
p
=
{
}
778
propertydata
[
n
]
=
p
779
end
780
return
p
781
end
782 783
local
getstate
=
direct
.
getstate
784
local
setstate
=
direct
.
setstate
785 786
if
not
setstate
or
not
getstate
then
787 788
setstate
=
function
(
n
,
v
)
789
local
p
=
propertydata
[
n
]
790
if
p
then
791
p
.
state
=
v
792
else
793
propertydata
[
n
]
=
{
state
=
v
}
794
end
795
end
796 797
getstate
=
function
(
n
,
v
)
798
local
p
=
propertydata
[
n
]
799
if
p
then
800
if
v
then
801
return
p
.
state
=
=
v
802
else
803
return
p
.
state
804
end
805
else
806
return
nil
807
end
808
end
809
end
810 811
nuts
.
setstate
=
setstate
812
nuts
.
getstate
=
getstate
813 814
local
getscript
=
direct
.
getscript
or
function
(
n
,
v
)
end
-- elsewhere
815
local
setscript
=
direct
.
setscript
or
function
(
n
,
v
)
end
-- elsewhere
816 817
nuts
.
setscript
=
setscript
818
nuts
.
getscript
=
getscript
819 820
function
nuts
.
isdone
(
n
,
k
)
821
local
p
=
propertydata
[
n
]
822
if
not
p
then
823
propertydata
[
n
]
=
{
[
k
]
=
true
}
824
return
false
825
end
826
local
v
=
p
[
k
]
827
if
v
=
=
nil
then
828
propertydata
[
n
]
=
{
[
k
]
=
true
}
829
return
false
830
end
831
return
v
832
end
833 834
function
nuts
.
copy_properties
(
source
,
target
,
what
)
835
local
newprops
=
propertydata
[
source
]
836
if
not
newprops
then
837
-- nothing to copy
838
return
839
end
840
if
what
then
841
-- copy one category
842
newprops
=
rawget
(
source
,
what
)
843
if
newprops
then
844
newprops
=
fastcopy
(
newprops
)
845
local
p
=
rawget
(
propertydata
,
target
)
846
if
p
then
847
p
[
what
]
=
newprops
848
else
849
propertydata
[
target
]
=
{
850
[
what
]
=
newprops
,
851
}
852
end
853
end
854
else
855
-- copy all properties
856
newprops
=
fastcopy
(
newprops
)
857
propertydata
[
target
]
=
newprops
858
end
859
return
newprops
-- for checking
860
end
861