math-noa.lmt /size: 86 Kb    last modification: 2021-10-28 13:51
1
if
not
modules
then
modules
=
{
}
end
modules
[
'
math-noa
'
]
=
{
2
version
=
1
.
001
,
3
optimize
=
true
,
4
comment
=
"
companion to math-ini.mkiv
"
,
5
author
=
"
Hans Hagen, PRAGMA-ADE, Hasselt NL
"
,
6
copyright
=
"
PRAGMA ADE / ConTeXt Development Team
"
,
7
license
=
"
see context related readme files
"
8
}
9 10
-- beware: this is experimental code and there will be a more generic (attribute value
11
-- driven) interface too but for the moment this is ok (sometime in 2015-2016 i will
12
-- start cleaning up as by then the bigger picture is clear and code has been used for
13
-- years; the main handlers will get some extensions)
14
--
15
-- we will also make dedicated processors (faster)
16
--
17
-- beware: names will change as we wil make noads.xxx.handler i.e. xxx
18
-- subnamespaces
19 20
-- 20D6 -> 2190
21
-- 20D7 -> 2192
22 23
-- todo: most is mathchar_code so we can have simple dedicated loops
24 25
-- nota bene: uunderdelimiter uoverdelimiter etc are radicals (we have 5 types)
26 27
local
next
,
tonumber
=
next
,
tonumber
28
local
utfchar
,
utfbyte
=
utf
.
char
,
utf
.
byte
29
local
formatters
,
gmatch
=
string
.
formatters
,
string
.
gmatch
30
local
sortedhash
=
table
.
sortedhash
31
local
insert
,
remove
=
table
.
insert
,
table
.
remove
32
local
div
,
round
=
math
.
div
,
math
.
round
33 34
local
fonts
=
fonts
35
local
nodes
=
nodes
36
local
node
=
node
37
local
mathematics
=
mathematics
38
local
context
=
context
39 40
local
otf
=
fonts
.
handlers
.
otf
41
local
otffeatures
=
fonts
.
constructors
.
features
.
otf
42
local
registerotffeature
=
otffeatures
.
register
43 44
local
privateattribute
=
attributes
.
private
45
local
registertracker
=
trackers
.
register
46
local
registerdirective
=
directives
.
register
47
local
logreporter
=
logs
.
reporter
48
local
setmetatableindex
=
table
.
setmetatableindex
49 50
local
texgetmode
=
tex
.
getmode
51
local
mathmode_code
=
tex
.
modelevels
.
math
52 53
local
colortracers
=
nodes
.
tracers
.
colors
54 55
local
trace_remapping
=
false
registertracker
(
"
math.remapping
"
,
function
(
v
)
trace_remapping
=
v
end
)
56
local
trace_processing
=
false
registertracker
(
"
math.processing
"
,
function
(
v
)
trace_processing
=
v
end
)
57
local
trace_analyzing
=
false
registertracker
(
"
math.analyzing
"
,
function
(
v
)
trace_analyzing
=
v
end
)
58
local
trace_normalizing
=
false
registertracker
(
"
math.normalizing
"
,
function
(
v
)
trace_normalizing
=
v
end
)
59
local
trace_collapsing
=
false
registertracker
(
"
math.collapsing
"
,
function
(
v
)
trace_collapsing
=
v
end
)
60
local
trace_fixing
=
false
registertracker
(
"
math.fixing
"
,
function
(
v
)
trace_fixing
=
v
end
)
61
local
trace_patching
=
false
registertracker
(
"
math.patching
"
,
function
(
v
)
trace_patching
=
v
end
)
62
local
trace_goodies
=
false
registertracker
(
"
math.goodies
"
,
function
(
v
)
trace_goodies
=
v
end
)
63
local
trace_variants
=
false
registertracker
(
"
math.variants
"
,
function
(
v
)
trace_variants
=
v
end
)
64
local
trace_alternates
=
false
registertracker
(
"
math.alternates
"
,
function
(
v
)
trace_alternates
=
v
end
)
65
local
trace_italics
=
false
registertracker
(
"
math.italics
"
,
function
(
v
)
trace_italics
=
v
end
)
66
local
trace_kernpairs
=
false
registertracker
(
"
math.kernpairs
"
,
function
(
v
)
trace_kernpairs
=
v
end
)
67
local
trace_domains
=
false
registertracker
(
"
math.domains
"
,
function
(
v
)
trace_domains
=
v
end
)
68
local
trace_families
=
false
registertracker
(
"
math.families
"
,
function
(
v
)
trace_families
=
v
end
)
69
local
trace_fences
=
false
registertracker
(
"
math.fences
"
,
function
(
v
)
trace_fences
=
v
end
)
70
local
trace_unstacking
=
false
registertracker
(
"
math.unstack
"
,
function
(
v
)
trace_unstacking
=
v
end
)
71 72
local
check_coverage
=
true
registerdirective
(
"
math.checkcoverage
"
,
function
(
v
)
check_coverage
=
v
end
)
73 74
local
report_processing
=
logreporter
(
"
mathematics
"
,
"
processing
"
)
75
local
report_remapping
=
logreporter
(
"
mathematics
"
,
"
remapping
"
)
76
local
report_normalizing
=
logreporter
(
"
mathematics
"
,
"
normalizing
"
)
77
local
report_collapsing
=
logreporter
(
"
mathematics
"
,
"
collapsing
"
)
78
local
report_fixing
=
logreporter
(
"
mathematics
"
,
"
fixing
"
)
79
local
report_patching
=
logreporter
(
"
mathematics
"
,
"
patching
"
)
80
local
report_goodies
=
logreporter
(
"
mathematics
"
,
"
goodies
"
)
81
local
report_variants
=
logreporter
(
"
mathematics
"
,
"
variants
"
)
82
local
report_alternates
=
logreporter
(
"
mathematics
"
,
"
alternates
"
)
83
local
report_italics
=
logreporter
(
"
mathematics
"
,
"
italics
"
)
84
local
report_kernpairs
=
logreporter
(
"
mathematics
"
,
"
kernpairs
"
)
85
local
report_domains
=
logreporter
(
"
mathematics
"
,
"
domains
"
)
86
local
report_families
=
logreporter
(
"
mathematics
"
,
"
families
"
)
87
local
report_fences
=
logreporter
(
"
mathematics
"
,
"
fences
"
)
88
local
report_unstacking
=
logreporter
(
"
mathematics
"
,
"
unstack
"
)
89 90
local
a_mathrendering
=
privateattribute
(
"
mathrendering
"
)
91
local
a_exportstatus
=
privateattribute
(
"
exportstatus
"
)
92 93
local
nuts
=
nodes
.
nuts
94
local
nodepool
=
nuts
.
pool
95
local
tonut
=
nuts
.
tonut
96
local
nutstring
=
nuts
.
tostring
97 98
local
setfield
=
nuts
.
setfield
99
local
setlink
=
nuts
.
setlink
100
local
setlist
=
nuts
.
setlist
101
local
setnext
=
nuts
.
setnext
102
local
setprev
=
nuts
.
setprev
103
local
setchar
=
nuts
.
setchar
104
local
setfam
=
nuts
.
setfam
105
local
setsubtype
=
nuts
.
setsubtype
106
local
setattr
=
nuts
.
setattr
107
local
setattrlist
=
nuts
.
setattrlist
108
local
setwidth
=
nuts
.
setwidth
109
local
setheight
=
nuts
.
setheight
110
local
setdepth
=
nuts
.
setdepth
111 112
local
getfield
=
nuts
.
getfield
113
local
getnext
=
nuts
.
getnext
114
local
getprev
=
nuts
.
getprev
115
local
getboth
=
nuts
.
getboth
116
local
getid
=
nuts
.
getid
117
local
getsubtype
=
nuts
.
getsubtype
118
local
getchar
=
nuts
.
getchar
119
local
getfont
=
nuts
.
getfont
120
local
getfam
=
nuts
.
getfam
121
local
getcharspec
=
nuts
.
getcharspec
122
local
getattr
=
nuts
.
getattr
123
local
getattrs
=
nuts
.
getattrs
124
local
getlist
=
nuts
.
getlist
125
local
getwidth
=
nuts
.
getwidth
126
local
getheight
=
nuts
.
getheight
127
local
getdepth
=
nuts
.
getdepth
128 129
local
getnucleus
=
nuts
.
getnucleus
130
local
getsub
=
nuts
.
getsub
131
local
getsup
=
nuts
.
getsup
132
local
getsubpre
=
nuts
.
getsubpre
133
local
getsuppre
=
nuts
.
getsuppre
134 135
local
setnucleus
=
nuts
.
setnucleus
136
local
setsub
=
nuts
.
setsub
137
local
setsup
=
nuts
.
setsup
138
local
setsubpre
=
nuts
.
setsubpre
139
local
setsuppre
=
nuts
.
setsuppre
140 141
local
flushnode
=
nuts
.
flush
142
local
copy_node
=
nuts
.
copy
143
local
slide_nodes
=
nuts
.
slide
144
local
set_visual
=
nuts
.
setvisual
145 146
local
mlisttohlist
=
nuts
.
mlisttohlist
147 148
local
new_kern
=
nodepool
.
kern
149
local
new_submlist
=
nodepool
.
submlist
150
local
new_noad
=
nodepool
.
noad
151
local
new_delimiter
=
nodepool
.
delimiter
152
local
new_fence
=
nodepool
.
fence
153 154
local
fonthashes
=
fonts
.
hashes
155
local
fontdata
=
fonthashes
.
identifiers
156
local
fontcharacters
=
fonthashes
.
characters
157
local
fontitalics
=
fonthashes
.
italics
158
local
fontparameters
=
fonthashes
.
parameters
159 160
local
variables
=
interfaces
.
variables
161
local
texsetattribute
=
tex
.
setattribute
162
local
texgetattribute
=
tex
.
getattribute
163
local
getfontoffamily
=
tex
.
getfontoffamily
164
local
unsetvalue
=
attributes
.
unsetvalue
165
local
implement
=
interfaces
.
implement
166 167
local
v_reset
=
variables
.
reset
168 169
local
chardata
=
characters
.
data
170 171
noads
=
noads
or
{
}
-- todo: only here
172
local
noads
=
noads
173 174
noads
.
processors
=
noads
.
processors
or
{
}
175
local
processors
=
noads
.
processors
176 177
noads
.
handlers
=
noads
.
handlers
or
{
}
178
local
handlers
=
noads
.
handlers
179 180
local
tasks
=
nodes
.
tasks
181
local
enableaction
=
tasks
.
enableaction
182
local
setaction
=
tasks
.
setaction
183 184
local
nodecodes
=
nodes
.
nodecodes
185
local
noadcodes
=
nodes
.
noadcodes
186
local
fencecodes
=
nodes
.
fencecodes
187 188
local
ordnoad_code
=
noadcodes
.
ord
189
local
opnoad_code
=
noadcodes
.
op
190
local
binnoad_code
=
noadcodes
.
bin
191
local
relnode_code
=
noadcodes
.
rel
192
local
opennoad_code
=
noadcodes
.
open
193
local
closenoad_code
=
noadcodes
.
close
194
local
punctnoad_code
=
noadcodes
.
punct
195
local
innernoad_code
=
noadcodes
.
inner
196
local
undernoad_code
=
noadcodes
.
under
197
local
overnoad_code
=
noadcodes
.
over
198
local
vcenternoad_code
=
noadcodes
.
vcenter
199 200
local
noad_code
=
nodecodes
.
noad
-- attr nucleus sub sup
201
local
accent_code
=
nodecodes
.
accent
-- attr nucleus sub sup accent
202
local
radical_code
=
nodecodes
.
radical
-- attr nucleus sub sup left degree
203
local
fraction_code
=
nodecodes
.
fraction
-- attr nucleus sub sup left right
204
local
subbox_code
=
nodecodes
.
subbox
-- attr list
205
local
submlist_code
=
nodecodes
.
submlist
-- attr list
206
local
mathchar_code
=
nodecodes
.
mathchar
-- attr fam char
207
local
mathtextchar_code
=
nodecodes
.
mathtextchar
-- attr fam char
208
local
delimiter_code
=
nodecodes
.
delimiter
-- attr small_fam small_char large_fam large_char
209
----- style_code = nodecodes.style -- attr style
210
----- parameter_code = nodecodes.parameter -- attr style
211
local
math_choice
=
nodecodes
.
choice
-- attr display text script scriptscript
212
local
fence_code
=
nodecodes
.
fence
-- attr subtype
213 214
local
leftfence_code
=
fencecodes
.
left
215
local
middlefence_code
=
fencecodes
.
middle
216
local
rightfence_code
=
fencecodes
.
right
217 218
-- local mathclasses = mathematics.classes
219
-- local fenceclasses = {
220
-- [leftfence_code] = mathclasses.open,
221
-- [middlefence_code] = mathclasses.middle,
222
-- [rightfence_code] = mathclasses.close,
223
-- }
224 225
-- this initial stuff is tricky as we can have removed and new nodes with the same address
226
-- the only way out is a free-per-page list of nodes (not bad anyway)
227 228
-- local gf = getfield local gt = setmetatableindex("number") getfield = function(n,f) gt[f] = gt[f] + 1 return gf(n,f) end mathematics.GETFIELD = gt
229
-- local sf = setfield local st = setmetatableindex("number") setfield = function(n,f,v) st[f] = st[f] + 1 sf(n,f,v) end mathematics.SETFIELD = st
230 231
local
function
process
(
start
,
what
,
n
,
parent
)
232 233
if
n
then
234
n
=
n
+
1
235
else
236
n
=
0
237
end
238
--
239
local
initial
=
start
240
--
241
slide_nodes
(
start
)
-- we still miss a prev in noads -- fences test code
242
--
243
while
start
do
244
local
id
=
getid
(
start
)
245
if
trace_processing
then
246
if
id
=
=
noad_code
then
247
report_processing
(
"
%w%S, class %a
"
,
n
*
2
,
nutstring
(
start
)
,
noadcodes
[
getsubtype
(
start
)
]
)
248
elseif
id
=
=
mathchar_code
then
249
local
char
,
font
,
fam
=
getcharspec
(
start
)
250
report_processing
(
"
%w%S, family %a, font %a, char %a, shape %c
"
,
n
*
2
,
nutstring
(
start
)
,
fam
,
font
,
char
,
char
)
251
else
252
report_processing
(
"
%w%S
"
,
n
*
2
,
nutstring
(
start
)
)
253
end
254
end
255
local
proc
=
what
[
id
]
256
if
proc
then
257
-- report_processing("start processing")
258
local
done
,
newstart
,
newinitial
=
proc
(
start
,
what
,
n
,
parent
)
-- prev is bugged: or getprev(start)
259
if
newinitial
then
260
initial
=
newinitial
-- temp hack .. we will make all return head
261
if
newstart
then
262
start
=
newstart
263
-- report_processing("stop processing (new start)")
264
else
265
-- report_processing("quit processing (done)")
266
break
267
end
268
else
269
if
newstart
then
270
start
=
newstart
271
-- report_processing("stop processing (new start)")
272
else
273
-- report_processing("stop processing")
274
end
275
end
276
elseif
id
=
=
noad_code
then
277
-- single characters are like this
278
local
noad
=
getnucleus
(
start
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- list
279
noad
=
getsup
(
start
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- list
280
noad
=
getsub
(
start
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- list
281
if
getsubpre
then
282
noad
=
getsuppre
(
start
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- list
283
noad
=
getsubpre
(
start
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- list
284
end
285
elseif
id
=
=
mathchar_code
or
id
=
=
mathtextchar_code
or
id
=
=
delimiter_code
then
286
break
287
elseif
id
=
=
subbox_code
or
id
=
=
submlist_code
then
288
local
noad
=
getlist
(
start
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- list (not getlist !)
289
elseif
id
=
=
fraction_code
then
290
local
noad
=
getfield
(
start
,
"
num
"
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- list
291
noad
=
getfield
(
start
,
"
denom
"
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- list
292
noad
=
getfield
(
start
,
"
left
"
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- delimiter
293
noad
=
getfield
(
start
,
"
right
"
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- delimiter
294
elseif
id
=
=
math_choice
then
295
local
noad
=
getfield
(
start
,
"
display
"
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- list
296
noad
=
getfield
(
start
,
"
text
"
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- list
297
noad
=
getfield
(
start
,
"
script
"
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- list
298
noad
=
getfield
(
start
,
"
scriptscript
"
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- list
299
elseif
id
=
=
fence_code
then
300
local
noad
=
getfield
(
start
,
"
delimiter
"
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- delimiter
301
elseif
id
=
=
radical_code
then
302
local
noad
=
getnucleus
(
start
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- list
303
noad
=
getsup
(
start
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- list
304
noad
=
getsub
(
start
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- list
305
if
getsubpre
then
306
noad
=
getsuppre
(
start
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- list
307
noad
=
getsubpre
(
start
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- list
308
end
309
noad
=
getfield
(
start
,
"
left
"
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- delimiter
310
noad
=
getfield
(
start
,
"
degree
"
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- list
311
elseif
id
=
=
accent_code
then
312
local
noad
=
getnucleus
(
start
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- list
313
noad
=
getsup
(
start
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- list
314
noad
=
getsub
(
start
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- list
315
if
getsubpre
then
316
noad
=
getsuppre
(
start
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- list
317
noad
=
getsubpre
(
start
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- list
318
end
319
noad
=
getfield
(
start
,
"
accent
"
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- list
320
noad
=
getfield
(
start
,
"
bot_accent
"
)
if
noad
then
process
(
noad
,
what
,
n
,
start
)
end
-- list
321
-- elseif id == style_code then
322
-- -- has a next
323
-- elseif id == parameter_code then
324
-- -- has a next
325
-- else
326
-- -- glue, penalty, etc
327
end
328
start
=
getnext
(
start
)
329
end
330
if
not
parent
then
331
return
initial
-- only first level -- for now
332
end
333
end
334 335
local
function
processnested
(
current
,
what
,
n
)
336
local
noad
=
nil
337
local
id
=
getid
(
current
)
338
if
id
=
=
noad_code
then
339
noad
=
getnucleus
(
current
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- list
340
noad
=
getsup
(
current
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- list
341
noad
=
getsub
(
current
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- list
342
if
getsubpre
then
343
noad
=
getsuppre
(
current
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- list
344
noad
=
getsubpre
(
current
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- list
345
end
346
elseif
id
=
=
subbox_code
or
id
=
=
submlist_code
then
347
noad
=
getlist
(
current
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- list (not getlist !)
348
elseif
id
=
=
fraction_code
then
349
noad
=
getfield
(
current
,
"
num
"
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- list
350
noad
=
getfield
(
current
,
"
denom
"
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- list
351
noad
=
getfield
(
current
,
"
left
"
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- delimiter
352
noad
=
getfield
(
current
,
"
right
"
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- delimiter
353
elseif
id
=
=
math_choice
then
354
noad
=
getfield
(
current
,
"
display
"
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- list
355
noad
=
getfield
(
current
,
"
text
"
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- list
356
noad
=
getfield
(
current
,
"
script
"
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- list
357
noad
=
getfield
(
current
,
"
scriptscript
"
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- list
358
elseif
id
=
=
fence_code
then
359
noad
=
getfield
(
current
,
"
delimiter
"
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- delimiter
360
elseif
id
=
=
radical_code
then
361
noad
=
getnucleus
(
current
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- list
362
noad
=
getsup
(
current
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- list
363
noad
=
getsub
(
current
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- list
364
if
getsubpre
then
365
noad
=
getsuppre
(
current
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- list
366
noad
=
getsubpre
(
current
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- list
367
end
368
noad
=
getfield
(
current
,
"
left
"
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- delimiter
369
noad
=
getfield
(
current
,
"
degree
"
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- list
370
elseif
id
=
=
accent_code
then
371
noad
=
getnucleus
(
current
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- list
372
noad
=
getsup
(
current
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- list
373
noad
=
getsub
(
current
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- list
374
if
getsubpre
then
375
noad
=
getsuppre
(
current
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- list
376
noad
=
getsubpre
(
current
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- list
377
end
378
noad
=
getfield
(
current
,
"
accent
"
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- list
379
noad
=
getfield
(
current
,
"
bot_accent
"
)
if
noad
then
process
(
noad
,
what
,
n
,
current
)
end
-- list
380
end
381
end
382 383
local
function
processstep
(
current
,
process
,
n
,
id
)
384
local
noad
=
nil
385
local
id
=
id
or
getid
(
current
)
386
if
id
=
=
noad_code
then
387
noad
=
getnucleus
(
current
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- list
388
noad
=
getsup
(
current
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- list
389
noad
=
getsub
(
current
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- list
390
if
getsubpre
then
391
noad
=
getsuppre
(
current
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- list
392
noad
=
getsubpre
(
current
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- list
393
end
394
elseif
id
=
=
subbox_code
or
id
=
=
submlist_code
then
395
noad
=
getlist
(
current
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- list (not getlist !)
396
elseif
id
=
=
fraction_code
then
397
noad
=
getfield
(
current
,
"
num
"
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- list
398
noad
=
getfield
(
current
,
"
denom
"
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- list
399
noad
=
getfield
(
current
,
"
left
"
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- delimiter
400
noad
=
getfield
(
current
,
"
right
"
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- delimiter
401
elseif
id
=
=
math_choice
then
402
noad
=
getfield
(
current
,
"
display
"
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- list
403
noad
=
getfield
(
current
,
"
text
"
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- list
404
noad
=
getfield
(
current
,
"
script
"
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- list
405
noad
=
getfield
(
current
,
"
scriptscript
"
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- list
406
elseif
id
=
=
fence_code
then
407
noad
=
getfield
(
current
,
"
delimiter
"
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- delimiter
408
elseif
id
=
=
radical_code
then
409
noad
=
getnucleus
(
current
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- list
410
noad
=
getsup
(
current
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- list
411
noad
=
getsub
(
current
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- list
412
if
getsubpre
then
413
noad
=
getsuppre
(
current
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- list
414
noad
=
getsubpre
(
current
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- list
415
end
416
noad
=
getfield
(
current
,
"
left
"
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- delimiter
417
noad
=
getfield
(
current
,
"
degree
"
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- list
418
elseif
id
=
=
accent_code
then
419
noad
=
getnucleus
(
current
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- list
420
noad
=
getsup
(
current
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- list
421
noad
=
getsub
(
current
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- list
422
if
getsubpre
then
423
noad
=
getsuppre
(
current
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- list
424
noad
=
getsubpre
(
current
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- list
425
end
426
noad
=
getfield
(
current
,
"
accent
"
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- list
427
noad
=
getfield
(
current
,
"
bot_accent
"
)
if
noad
then
process
(
noad
,
n
,
current
)
end
-- list
428
end
429
end
430 431
local
function
processnoads
(
head
,
actions
,
banner
)
432
if
trace_processing
then
433
report_processing
(
"
start %a
"
,
banner
)
434
head
=
process
(
head
,
actions
)
435
report_processing
(
"
stop %a
"
,
banner
)
436
else
437
head
=
process
(
head
,
actions
)
438
end
439
return
head
440
end
441 442
noads
.
process
=
processnoads
443
noads
.
processnested
=
processnested
444
noads
.
processouter
=
process
445 446
-- experiment (when not present fall back to fam 0) -- needs documentation
447 448
local
unknowns
=
{
}
449
local
checked
=
{
}
-- simple case
450
local
tracked
=
false
trackers
.
register
(
"
fonts.missing
"
,
function
(
v
)
tracked
=
v
end
)
451
local
cached
=
setmetatableindex
(
"
table
"
)
-- complex case
452 453
local
function
errorchar
(
font
,
char
)
454
local
done
=
unknowns
[
char
]
455
if
done
then
456
unknowns
[
char
]
=
done
+
1
457
else
458
unknowns
[
char
]
=
1
459
end
460
if
tracked
then
461
-- slower as we check each font too and we always replace as math has
462
-- more demands than text
463
local
fake
=
cached
[
font
]
[
char
]
464
if
fake
then
465
return
fake
466
else
467
local
kind
,
fake
=
fonts
.
checkers
.
placeholder
(
font
,
char
)
468
if
not
fake
or
kind
~
=
"
char
"
then
-- Also check for "with" here?
469
fake
=
0x3F
470
end
471
cached
[
font
]
[
char
]
=
fake
472
return
fake
473
end
474
else
475
-- only simple checking, report at the end so one should take
476
-- action anyway ... we can miss a few checks but that is ok
477
-- as there is at least one reported
478
if
not
checked
[
char
]
then
479
if
trace_normalizing
then
480
report_normalizing
(
"
character %C is not available
"
,
char
)
481
end
482
checked
[
char
]
=
true
483
end
484
return
0x3F
485
end
486
end
487 488
-- 0-2 regular
489
-- 3-5 bold
490
-- 6-8 pseudobold
491 492
-- this could best be integrated in the remapper, and if we run into problems, we
493
-- might as well do this
494 495
do
496 497
local
families
=
{
}
498
local
a_mathfamily
=
privateattribute
(
"
mathfamily
"
)
499
local
boldmap
=
mathematics
.
boldmap
500 501
local
familymap
=
{
[
0
]
=
502
"
regular
"
,
503
"
regular
"
,
504
"
regular
"
,
505
"
bold
"
,
506
"
bold
"
,
507
"
bold
"
,
508
"
pseudobold
"
,
509
"
pseudobold
"
,
510
"
pseudobold
"
,
511
}
512 513
families
[
fraction_code
]
=
function
(
pointer
,
what
,
n
,
parent
)
514
local
a
=
getattr
(
pointer
,
a_mathfamily
)
515
if
a
and
a
>
=
0
then
516
if
a
>
0
then
517
setattr
(
pointer
,
a_mathfamily
,
0
)
518
if
a
>
5
then
519
a
=
a
-
3
520
end
521
end
522
setfam
(
pointer
,
a
)
523
end
524
processnested
(
pointer
,
families
,
n
+
1
)
525
end
526 527
families
[
noad_code
]
=
function
(
pointer
,
what
,
n
,
parent
)
528
local
a
=
getattr
(
pointer
,
a_mathfamily
)
529
if
a
and
a
>
=
0
then
530
if
a
>
0
then
531
setattr
(
pointer
,
a_mathfamily
,
0
)
532
if
a
>
5
then
533
a
=
a
-
3
534
end
535
end
536
setfam
(
pointer
,
a
)
537
end
538
processnested
(
pointer
,
families
,
n
+
1
)
539
end
540 541
families
[
mathchar_code
]
=
function
(
pointer
)
542
if
getfam
(
pointer
)
=
=
0
then
543
local
a
=
getattr
(
pointer
,
a_mathfamily
)
544
if
a
and
a
>
0
then
545
setattr
(
pointer
,
a_mathfamily
,
0
)
546
if
a
>
5
then
547
local
char
=
getchar
(
pointer
)
548
local
bold
=
boldmap
[
char
]
549
local
newa
=
a
-
3
550
if
not
bold
then
551
if
trace_families
then
552
report_families
(
"
no bold replacement for %C, family %s with remap %s becomes %s with remap %s
"
,
char
,
a
,
familymap
[
a
]
,
newa
,
familymap
[
newa
]
)
553
end
554
setfam
(
pointer
,
newa
)
555
elseif
not
fontcharacters
[
getfontoffamily
(
newa
)
]
[
bold
]
then
556
if
trace_families
then
557
report_families
(
"
no bold character for %C, family %s with remap %s becomes %s with remap %s
"
,
char
,
a
,
familymap
[
a
]
,
newa
,
familymap
[
newa
]
)
558
end
559
if
newa
>
3
then
560
setfam
(
pointer
,
newa
-3
)
561
end
562
else
563
setattr
(
pointer
,
a_exportstatus
,
char
)
564
setchar
(
pointer
,
bold
)
565
if
trace_families
then
566
report_families
(
"
replacing %C by bold %C, family %s with remap %s becomes %s with remap %s
"
,
char
,
bold
,
a
,
familymap
[
a
]
,
newa
,
familymap
[
newa
]
)
567
end
568
setfam
(
pointer
,
newa
)
569
end
570
else
571
local
char
=
getchar
(
pointer
)
572
if
not
fontcharacters
[
getfontoffamily
(
a
)
]
[
char
]
then
573
if
trace_families
then
574
report_families
(
"
no bold replacement for %C
"
,
char
)
575
end
576
else
577
if
trace_families
then
578
report_families
(
"
family of %C becomes %s with remap %s
"
,
char
,
a
,
familymap
[
a
]
)
579
end
580
setfam
(
pointer
,
a
)
581
end
582
end
583
end
584
end
585
end
586
families
[
delimiter_code
]
=
function
(
pointer
)
587
if
getfield
(
pointer
,
"
small_fam
"
)
=
=
0
then
588
local
a
=
getattr
(
pointer
,
a_mathfamily
)
589
if
a
and
a
>
0
then
590
setattr
(
pointer
,
a_mathfamily
,
0
)
591
if
a
>
5
then
592
-- no bold delimiters in unicode
593
a
=
a
-
3
594
end
595
local
fam
=
getfontoffamily
(
a
)
596
local
char
=
getfield
(
pointer
,
"
small_char
"
)
597
local
okay
=
fontcharacters
[
fam
]
[
char
]
598
if
okay
then
599
setfield
(
pointer
,
"
small_fam
"
,
a
)
600
elseif
a
>
2
then
601
setfield
(
pointer
,
"
small_fam
"
,
a
-3
)
602
end
603
local
char
=
getfield
(
pointer
,
"
large_char
"
)
604
local
okay
=
fontcharacters
[
fam
]
[
char
]
605
if
okay
then
606
setfield
(
pointer
,
"
large_fam
"
,
a
)
607
elseif
a
>
2
then
608
setfield
(
pointer
,
"
large_fam
"
,
a
-3
)
609
end
610
else
611
setfield
(
pointer
,
"
small_fam
"
,
0
)
612
setfield
(
pointer
,
"
large_fam
"
,
0
)
613
end
614
end
615
end
616 617
-- will become:
618 619
-- families[delimiter_code] = function(pointer)
620
-- if getfam(pointer) == 0 then
621
-- local a = getattr(pointer,a_mathfamily)
622
-- if a and a > 0 then
623
-- setattr(pointer,a_mathfamily,0)
624
-- if a > 5 then
625
-- -- no bold delimiters in unicode
626
-- a = a - 3
627
-- end
628
-- local char = getchar(pointer)
629
-- local okay = fontcharacters[getfontoffamily(a)][char]
630
-- if okay then
631
-- setfam(pointer,a)
632
-- elseif a > 2 then
633
-- setfam(pointer,a-3)
634
-- end
635
-- else
636
-- setfam(pointer,0)
637
-- end
638
-- end
639
-- end
640 641
families
[
mathtextchar_code
]
=
families
[
mathchar_code
]
642 643
function
handlers
.
families
(
head
,
style
,
penalties
)
644
processnoads
(
head
,
families
,
"
families
"
)
645
return
true
-- not needed
646
end
647 648
end
649 650
-- character remapping
651 652
do
653 654
local
a_mathalphabet
=
privateattribute
(
"
mathalphabet
"
)
655
local
a_mathgreek
=
privateattribute
(
"
mathgreek
"
)
656 657
local
relocate
=
{
}
658 659
local
remapalphabets
=
mathematics
.
remapalphabets
660
local
fallbackstyleattr
=
mathematics
.
fallbackstyleattr
661
local
setnodecolor
=
colortracers
.
set
662 663
local
function
report_remap
(
tag
,
id
,
old
,
new
,
extra
)
664
if
new
then
665
report_remapping
(
"
remapping %s in font (%s,%s) from %C to %C%s
"
,
666
tag
,
id
,
fontdata
[
id
]
.
properties
.
fontname
or
"
"
,
old
,
new
,
extra
)
667
else
668
-- error !
669
report_remapping
(
"
remapping %s in font (%s,%s) from %C to ?
"
,
670
tag
,
id
,
fontdata
[
id
]
.
properties
.
fontname
or
"
"
,
old
)
671
end
672
end
673 674
local
function
checked
(
pointer
)
675
local
char
,
font
=
getcharspec
(
pointer
)
676
local
data
=
fontcharacters
[
font
]
677
if
not
data
[
char
]
then
678
local
specials
=
characters
.
data
[
char
]
.
specials
679
if
specials
and
(
specials
[
1
]
=
=
"
char
"
or
specials
[
1
]
=
=
"
font
"
)
then
680
local
newchar
=
specials
[
#
specials
]
681
if
trace_remapping
then
682
report_remap
(
"
fallback
"
,
font
,
char
,
newchar
)
683
end
684
if
trace_analyzing
then
685
setnodecolor
(
pointer
,
"
font:isol
"
)
686
end
687
setattr
(
pointer
,
a_exportstatus
,
char
)
-- testcase: exponentiale
688
setchar
(
pointer
,
newchar
)
689
return
true
690
end
691
end
692
end
693 694
-- We can optimize this if we really think that math is a bottleneck which it never
695
-- really is. Beware: the font is the text font in the family, so we only check the
696
-- text font here.
697 698
relocate
[
mathchar_code
]
=
function
(
pointer
)
699
local
g
=
getattr
(
pointer
,
a_mathgreek
)
or
0
700
local
a
=
getattr
(
pointer
,
a_mathalphabet
)
or
0
701
-- local g, a = getattrs(pointer,a_mathgreek,a_mathalphabet)
702
-- if not a then a = 0 end
703
-- if not g then g = 0 end
704
local
char
,
font
,
fam
=
getcharspec
(
pointer
)
705
local
characters
=
fontcharacters
[
font
]
706
if
a
>
0
or
g
>
0
then
707
if
a
>
0
then
708
-- not really critital but we could use properties
709
setattr
(
pointer
,
a_mathgreek
,
0
)
710
end
711
if
g
>
0
then
712
-- not really critital but we could use properties
713
setattr
(
pointer
,
a_mathalphabet
,
0
)
714
end
715
local
newchar
=
remapalphabets
(
char
,
a
,
g
)
716
if
newchar
then
717
local
newchardata
=
characters
[
newchar
]
718
if
newchardata
then
719
if
trace_remapping
then
720
report_remap
(
"
char
"
,
font
,
char
,
newchar
,
newchardata
.
commands
and
"
(virtual)
"
or
"
"
)
721
end
722
if
trace_analyzing
then
723
setnodecolor
(
pointer
,
"
font:isol
"
)
724
end
725
setchar
(
pointer
,
newchar
)
726
return
true
727
else
728
local
fallback
=
fallbackstyleattr
(
a
)
729
if
fallback
then
730
local
newchar
=
remapalphabets
(
char
,
fallback
,
g
)
731
if
newchar
then
732
if
characters
[
newchar
]
then
733
if
trace_remapping
then
734
report_remap
(
"
char
"
,
font
,
char
,
newchar
,
"
(fallback remapping used)
"
)
735
end
736
if
trace_analyzing
then
737
setnodecolor
(
pointer
,
"
font:isol
"
)
738
end
739
setchar
(
pointer
,
newchar
)
740
return
true
741
elseif
trace_remapping
then
742
report_remap
(
"
char
"
,
font
,
char
,
newchar
,
"
fails (no fallback character)
"
)
743
end
744
elseif
trace_remapping
then
745
report_remap
(
"
char
"
,
font
,
char
,
newchar
,
"
fails (no fallback remap character)
"
)
746
end
747
elseif
trace_remapping
then
748
report_remap
(
"
char
"
,
font
,
char
,
newchar
,
"
fails (no fallback style)
"
)
749
end
750
end
751
elseif
trace_remapping
then
752
local
chardata
=
characters
[
char
]
753
if
chardata
and
chardata
.
commands
then
754
report_remap
(
"
char
"
,
font
,
char
,
char
,
"
(virtual)
"
)
755
end
756
end
757
end
758
if
not
characters
[
char
]
then
759
local
fnt
=
getfontoffamily
(
fam
,
1
)
760
setchar
(
pointer
,
errorchar
(
font
,
char
)
)
761
if
font
~
=
fnt
then
762
errorchar
(
fnt
,
char
)
763
errorchar
(
getfontoffamily
(
fam
,
2
)
,
char
)
764
end
765
end
766
if
trace_analyzing
then
767
setnodecolor
(
pointer
,
"
font:medi
"
)
768
end
769
if
check_coverage
then
770
return
checked
(
pointer
)
771
end
772
end
773 774
relocate
[
mathtextchar_code
]
=
function
(
pointer
)
775
if
trace_analyzing
then
776
setnodecolor
(
pointer
,
"
font:init
"
)
777
end
778
end
779 780
relocate
[
delimiter_code
]
=
function
(
pointer
)
781
if
trace_analyzing
then
782
setnodecolor
(
pointer
,
"
font:fina
"
)
783
end
784
end
785 786
function
handlers
.
relocate
(
head
,
style
,
penalties
)
787
processnoads
(
head
,
relocate
,
"
relocate
"
)
788
return
true
-- not needed
789
end
790 791
end
792 793
-- rendering (beware, not exported)
794 795
do
796 797
local
render
=
{
}
798 799
local
rendersets
=
mathematics
.
renderings
.
numbers
or
{
}
-- store
800 801
render
[
mathchar_code
]
=
function
(
pointer
)
802
local
attr
=
getattr
(
pointer
,
a_mathrendering
)
803
if
attr
and
attr
>
0
then
804
local
char
,
font
=
getcharspec
(
pointer
)
805
local
renderset
=
rendersets
[
attr
]
806
if
renderset
then
807
local
newchar
=
renderset
[
char
]
808
if
newchar
then
809
local
characters
=
fontcharacters
[
font
]
810
if
characters
and
characters
[
newchar
]
then
811
setchar
(
pointer
,
newchar
)
812
setattr
(
pointer
,
a_exportstatus
,
char
)
813
end
814
end
815
end
816
end
817
end
818 819
function
handlers
.
render
(
head
,
style
,
penalties
)
820
processnoads
(
head
,
render
,
"
render
"
)
821
return
true
-- not needed
822
end
823 824
end
825 826
-- some resize options (this works ok because the content is
827
-- empty and no larger next will be forced)
828
--
829
-- beware: we don't use \delcode but \Udelcode and as such have
830
-- no large_fam; also, we need to check for subtype and/or
831
-- small_fam not being 0 because \. sits in 0,0 by default
832
--
833
-- todo: just replace the character by an ord noad
834
-- and remove the right delimiter as well
835 836
do
837 838
local
a_mathsize
=
privateattribute
(
"
mathsize
"
)
-- this might move into other fence code
839
local
resize
=
{
}
840 841
resize
[
fence_code
]
=
function
(
pointer
)
842
local
subtype
=
getsubtype
(
pointer
)
843
if
subtype
=
=
leftfence_code
or
subtype
=
=
rightfence_code
then
844
local
a
=
getattr
(
pointer
,
a_mathsize
)
845
if
a
and
a
>
0
then
846
local
method
=
div
(
a
,
100
)
847
local
size
=
a
%
100
848
setattr
(
pointer
,
a_mathsize
,
0
)
849
local
delimiter
=
getfield
(
pointer
,
"
delimiter
"
)
850
local
chr
,
fnt
,
fam
=
getcharspec
(
delimiter
)
851
if
chr
>
0
and
fnt
>
0
then
852
local
data
=
fontdata
[
fnt
]
853
local
char
=
mathematics
.
big
(
data
,
chr
,
size
,
method
)
854
local
ht
=
getheight
(
pointer
)
855
local
dp
=
getdepth
(
pointer
)
856
if
ht
=
=
1
or
dp
=
=
1
then
-- 1 scaled point is a signal
857
local
chardata
=
data
.
characters
[
char
]
858
if
ht
=
=
1
then
859
setheight
(
pointer
,
chardata
.
height
)
860
end
861
if
dp
=
=
1
then
862
setdepth
(
pointer
,
chardata
.
depth
)
863
end
864
end
865
if
trace_fences
then
866
report_fences
(
"
replacing %C by %C using method %a and size %a
"
,
chr
,
char
,
method
,
size
)
867
end
868
setchar
(
delimiter
,
char
)
869
end
870
end
871
end
872
end
873 874
function
handlers
.
resize
(
head
,
style
,
penalties
)
875
processnoads
(
head
,
resize
,
"
resize
"
)
876
return
true
-- not needed
877
end
878 879
end
880 881
-- still not perfect:
882 883
do
884 885
local
a_autofence
=
privateattribute
(
"
mathautofence
"
)
886
local
autofences
=
{
}
887
local
dummyfencechar
=
0x2E
888 889
local
function
makefence
(
what
,
char
)
890
local
d
=
new_delimiter
(
)
-- todo: attr
891
local
f
=
new_fence
(
)
-- todo: attr
892
if
char
then
893
local
sym
=
getnucleus
(
char
)
894
local
chr
,
fnt
,
fam
=
getcharspec
(
sym
)
895
if
chr
=
=
dummyfencechar
then
896
chr
=
0
897
end
898
setchar
(
d
,
chr
)
899
setfam
(
d
,
fam
)
900
flushnode
(
sym
)
901
end
902
setattrlist
(
d
,
char
)
903
setattrlist
(
f
,
char
)
904
setsubtype
(
f
,
what
)
905
setfield
(
f
,
"
delimiter
"
,
d
)
906
setfield
(
f
,
"
class
"
,
-1
)
-- tex itself does this, so not fenceclasses[what]
907
return
f
908
end
909 910
local
function
show
(
where
,
pointer
)
911
print
(
"
"
)
912
local
i
=
0
913
for
n
in
nuts
.
traverse
(
pointer
)
do
914
i
=
i
+
1
915
print
(
i
,
where
,
nuts
.
tonode
(
n
)
)
916
end
917
print
(
"
"
)
918
end
919 920
local
function
makelist
(
middle
,
noad
,
f_o
,
o_next
,
c_prev
,
f_c
)
921
-- report_fences(
922
-- "middle %s, noad %s, open %s, opennext %s, closeprev %s, close %s",
923
-- middle or "?",
924
-- noad or "?",
925
-- f_o or "?",
926
-- o_next or "?",
927
-- c_prev or "?",
928
-- f_c or "?"
929
-- )
930
local
list
=
new_submlist
(
)
931
setsubtype
(
noad
,
innernoad_code
)
932
setnucleus
(
noad
,
list
)
933
setlist
(
list
,
f_o
)
934
setlink
(
f_o
,
o_next
)
-- prev of list is nil
935
setlink
(
c_prev
,
f_c
)
-- next of list is nil
936
-- show("list",f_o)
937
if
middle
and
next
(
middle
)
then
938
local
prev
=
f_o
939
local
current
=
o_next
940
while
current
~
=
f_c
do
941
local
midl
=
middle
[
current
]
942
local
next
=
getnext
(
current
)
943
if
midl
then
944
local
fence
=
makefence
(
middlefence_code
,
current
)
945
setnucleus
(
current
)
946
flushnode
(
current
)
947
middle
[
current
]
=
nil
948
-- replace_node
949
setlink
(
prev
,
fence
,
next
)
950
prev
=
fence
951
else
952
prev
=
current
953
end
954
current
=
next
955
end
956
end
957
return
noad
958
end
959 960
-- relinking is now somewhat overdone
961 962
local
function
convert_both
(
open
,
close
,
middle
)
963
local
o_next
=
getnext
(
open
)
964
if
o_next
=
=
close
then
965
return
close
966
else
967
local
c_prev
,
c_next
=
getboth
(
close
)
968
local
f_o
=
makefence
(
leftfence_code
,
open
)
969
local
f_c
=
makefence
(
rightfence_code
,
close
)
970
makelist
(
middle
,
open
,
f_o
,
o_next
,
c_prev
,
f_c
)
971
setnucleus
(
close
)
972
flushnode
(
close
)
973
-- open is now a list
974
setlink
(
open
,
c_next
)
975
return
open
976
end
977
end
978 979
local
function
convert_open
(
open
,
last
,
middle
)
-- last is really last (final case)
980
local
f_o
=
makefence
(
leftfence_code
,
open
)
981
local
f_c
=
makefence
(
rightfence_code
)
982
local
o_next
=
getnext
(
open
)
983
makelist
(
middle
,
open
,
f_o
,
o_next
,
last
,
nil
)
984
-- open is now a list
985
setlink
(
open
,
l_next
)
986
return
open
987
end
988 989
local
function
convert_close
(
first
,
close
,
middle
)
990
local
f_o
=
makefence
(
leftfence_code
)
991
local
f_c
=
makefence
(
rightfence_code
,
close
)
992
local
c_prev
=
getprev
(
close
)
993
local
f_next
=
getnext
(
first
)
994
makelist
(
middle
,
close
,
f_o
,
f_next
,
c_prev
,
f_c
)
995
-- close is now a list
996
if
c_prev
~
=
first
then
997
setlink
(
first
,
close
)
998
end
999
return
close
1000
end
1001 1002
local
stacks
=
setmetatableindex
(
"
table
"
)
1003 1004
-- 1=open 2=close 3=middle 4=both
1005 1006
local
function
processfences
(
pointer
,
n
,
parent
)
1007
local
current
=
pointer
1008
local
last
=
pointer
1009
local
start
=
pointer
1010
local
done
=
false
1011
local
initial
=
pointer
1012
local
stack
=
nil
1013
local
middle
=
nil
-- todo: use properties
1014
while
current
do
1015
-- show("before",pointer)
1016
local
id
=
getid
(
current
)
1017
if
id
=
=
noad_code
then
1018
local
a
=
getattr
(
current
,
a_autofence
)
1019
if
a
and
a
>
0
then
1020
local
stack
=
stacks
[
n
]
1021
setattr
(
current
,
a_autofence
,
0
)
-- hm, better use a property
1022
local
level
=
#
stack
1023
if
a
=
=
1
then
1024
if
trace_fences
then
1025
report_fences
(
"
%2i: level %i, handling %s, action %s
"
,
n
,
level
,
"
open
"
,
"
open
"
)
1026
end
1027
insert
(
stack
,
current
)
1028
elseif
a
=
=
2
then
1029
local
open
=
remove
(
stack
)
1030
if
open
then
1031
if
trace_fences
then
1032
report_fences
(
"
%2i: level %i, handling %s, action %s
"
,
n
,
level
,
"
close
"
,
"
both
"
)
1033
end
1034
current
=
convert_both
(
open
,
current
,
middle
)
1035
elseif
current
=
=
start
then
1036
if
trace_fences
then
1037
report_fences
(
"
%2i: level %i, handling %s, action %s
"
,
n
,
level
,
"
close
"
,
"
skip
"
)
1038
end
1039
else
1040
if
trace_fences
then
1041
report_fences
(
"
%2i: level %i, handling %s, action %s
"
,
n
,
level
,
"
close
"
,
"
close
"
)
1042
end
1043
current
=
convert_close
(
initial
,
current
,
middle
)
1044
if
not
parent
then
1045
initial
=
current
1046
end
1047
end
1048
elseif
a
=
=
3
then
1049
if
trace_fences
then
1050
report_fences
(
"
%2i: level %i, handling %s, action %s
"
,
n
,
level
,
"
middle
"
,
"
middle
"
)
1051
end
1052
if
middle
then
1053
middle
[
current
]
=
last
1054
else
1055
middle
=
{
[
current
]
=
last
}
1056
end
1057
elseif
a
=
=
4
then
1058
if
not
stack
or
#
stack
=
=
0
then
1059
if
trace_fences
then
1060
report_fences
(
"
%2i: level %i, handling %s, action %s
"
,
n
,
level
,
"
both
"
,
"
open
"
)
1061
end
1062
insert
(
stack
,
current
)
1063
else
1064
local
open
=
remove
(
stack
)
1065
if
open
then
1066
if
trace_fences
then
1067
report_fences
(
"
%2i: level %i, handling %s, action %s
"
,
n
,
level
,
"
both
"
,
"
both
"
)
1068
end
1069
current
=
convert_both
(
open
,
current
,
middle
)
1070
elseif
current
=
=
start
then
1071
if
trace_fences
then
1072
report_fences
(
"
%2i: level %i, handling %s, action %s
"
,
n
,
level
,
"
both
"
,
"
skip
"
)
1073
end
1074
else
1075
if
trace_fences
then
1076
report_fences
(
"
%2i: level %i, handling %s, action %s
"
,
n
,
level
,
"
both
"
,
"
close
"
)
1077
end
1078
current
=
convert_close
(
initial
,
current
,
middle
)
1079
if
not
parent
then
1080
initial
=
current
1081
end
1082
end
1083
end
1084
end
1085
done
=
true
1086
else
1087
processstep
(
current
,
processfences
,
n
+
1
,
id
)
1088
end
1089
else
1090
-- next at current level
1091
processstep
(
current
,
processfences
,
n
,
id
)
1092
end
1093
-- show("after",pointer)
1094
last
=
current
1095
current
=
getnext
(
current
)
1096
end
1097
if
done
then
1098
local
stack
=
stacks
[
n
]
1099
local
s
=
#
stack
1100
if
s
>
0
then
1101
for
i
=
1
,
s
do
1102
local
open
=
remove
(
stack
)
1103
if
trace_fences
then
1104
report_fences
(
"
%2i: level %i, handling %s, action %s
"
,
n
,
#
stack
,
"
flush
"
,
"
open
"
)
1105
end
1106
last
=
convert_open
(
open
,
last
,
middle
)
1107
end
1108
-- show("done",pointer)
1109
end
1110
end
1111
end
1112 1113
-- we can have a first changed node .. an option is to have a leading dummy node in math
1114
-- lists like the par node as it can save a lot of mess
1115 1116
local
enabled
=
false
1117 1118
implement
{
1119
name
=
"
enableautofences
"
,
1120
onlyonce
=
true
,
1121
actions
=
function
(
)
1122
enableaction
(
"
math
"
,
"
noads.handlers.autofences
"
)
1123
enabled
=
true
1124
end
1125
}
1126 1127
function
handlers
.
autofences
(
head
,
style
,
penalties
)
1128
if
enabled
then
-- tex.modes.c_math_fences_auto
1129
-- inspect(nodes.totree(head))
1130
processfences
(
head
,
1
)
1131
-- inspect(nodes.totree(head))
1132
end
1133
end
1134 1135
end
1136 1137
-- normalize scripts
1138 1139
do
1140 1141
local
unscript
=
{
}
noads
.
processors
.
unscript
=
unscript
1142
local
superscripts
=
characters
.
superscripts
1143
local
subscripts
=
characters
.
subscripts
1144
local
fractions
=
characters
.
fractions
1145
local
replaced
=
{
}
1146 1147
local
function
replace
(
pointer
,
what
,
n
,
parent
)
1148
pointer
=
parent
-- we're following the parent list (chars trigger this)
1149
local
next
=
getnext
(
pointer
)
1150
local
start_super
,
stop_super
,
start_sub
,
stop_sub
1151
local
mode
=
"
unset
"
1152
while
next
and
getid
(
next
)
=
=
noad_code
do
1153
local
nextnucleus
=
getnucleus
(
next
)
1154
if
nextnucleus
and
getid
(
nextnucleus
)
=
=
mathchar_code
and
not
getsub
(
next
)
and
not
getsup
(
next
)
then
1155
local
char
=
getchar
(
nextnucleus
)
1156
local
s
=
superscripts
[
char
]
1157
if
s
then
1158
if
not
start_super
then
1159
start_super
=
next
1160
mode
=
"
super
"
1161
elseif
mode
=
=
"
sub
"
then
1162
break
1163
end
1164
stop_super
=
next
1165
next
=
getnext
(
next
)
1166
setchar
(
nextnucleus
,
s
)
1167
replaced
[
char
]
=
(
replaced
[
char
]
or
0
)
+
1
1168
if
trace_normalizing
then
1169
report_normalizing
(
"
superscript %C becomes %C
"
,
char
,
s
)
1170
end
1171
else
1172
local
s
=
subscripts
[
char
]
1173
if
s
then
1174
if
not
start_sub
then
1175
start_sub
=
next
1176
mode
=
"
sub
"
1177
elseif
mode
=
=
"
super
"
then
1178
break
1179
end
1180
stop_sub
=
next
1181
next
=
getnext
(
next
)
1182
setchar
(
nextnucleus
,
s
)
1183
replaced
[
char
]
=
(
replaced
[
char
]
or
0
)
+
1
1184
if
trace_normalizing
then
1185
report_normalizing
(
"
subscript %C becomes %C
"
,
char
,
s
)
1186
end
1187
else
1188
break
1189
end
1190
end
1191
else
1192
break
1193
end
1194
end
1195
if
start_super
then
1196
if
start_super
=
=
stop_super
then
1197
setsup
(
pointer
,
getnucleus
(
start_super
)
)
1198
else
1199
local
list
=
new_submlist
(
)
-- todo attr
1200
setlist
(
list
,
start_super
)
1201
setsup
(
pointer
,
list
)
1202
end
1203
if
mode
=
=
"
super
"
then
1204
setnext
(
pointer
,
getnext
(
stop_super
)
)
1205
end
1206
setnext
(
stop_super
)
1207
end
1208
if
start_sub
then
1209 1210
-- if mode == "sub" then
1211
-- local sup = getsup(pointer)
1212
-- if sup and not getsub(pointer) then
1213
-- local nxt = getnext(pointer)
1214
-- local new = new_noad(pointer)
1215
-- setnucleus(new,new_submlist())
1216
-- setlink(pointer,new,nxt)
1217
-- pointer = new
1218
-- end
1219
-- end
1220 1221
if
start_sub
=
=
stop_sub
then
1222
setsub
(
pointer
,
getnucleus
(
start_sub
)
)
1223
else
1224
local
list
=
new_submlist
(
)
-- todo attr
1225
setlist
(
list
,
start_sub
)
1226
setsub
(
pointer
,
list
)
1227
end
1228
if
mode
=
=
"
sub
"
then
1229
setnext
(
pointer
,
getnext
(
stop_sub
)
)
1230
end
1231
setnext
(
stop_sub
)
1232
end
1233
-- we could return stop
1234
end
1235 1236
unscript
[
mathchar_code
]
=
replace
-- not noads as we need to recurse
1237 1238
function
handlers
.
unscript
(
head
,
style
,
penalties
)
1239
processnoads
(
head
,
unscript
,
"
unscript
"
)
1240
return
true
-- not needed
1241
end
1242 1243
end
1244 1245
do
1246 1247
local
unstack
=
{
}
noads
.
processors
.
unstack
=
unstack
1248
local
enabled
=
false
1249
local
a_unstack
=
privateattribute
(
"
mathunstack
"
)
1250 1251
unstack
[
noad_code
]
=
function
(
pointer
)
1252
if
getattr
(
pointer
,
a_unstack
)
then
1253
local
sup
=
getsup
(
pointer
)
1254
local
sub
=
getsub
(
pointer
)
1255
if
sup
and
sub
then
1256
-- if trace_unstacking then
1257
-- report_unstacking() -- todo ... what to show ...
1258
-- end
1259
local
nxt
=
getnext
(
pointer
)
1260
local
new
=
new_noad
(
pointer
)
1261
setnucleus
(
new
,
new_submlist
(
)
)
1262
setsub
(
pointer
)
1263
setsub
(
new
,
sub
)
1264
setlink
(
pointer
,
new
,
nxt
)
1265
end
1266
end
1267
end
1268 1269
function
handlers
.
unstack
(
head
,
style
,
penalties
)
1270
if
enabled
then
1271
processnoads
(
head
,
unstack
,
"
unstack
"
)
1272
return
true
-- not needed
1273
end
1274
end
1275 1276
implement
{
1277
name
=
"
enablescriptunstacking
"
,
1278
onlyonce
=
true
,
1279
actions
=
function
(
)
1280
enableaction
(
"
math
"
,
"
noads.handlers.unstack
"
)
1281
enabled
=
true
1282
end
1283
}
1284 1285
end
1286 1287
do
1288 1289
local
function
collected
(
list
)
1290
if
list
and
next
(
list
)
then
1291
local
n
,
t
=
0
,
{
}
1292
for
k
,
v
in
sortedhash
(
list
)
do
1293
n
=
n
+
1
1294
t
[
n
]
=
formatters
[
"
%C
"
]
(
k
)
1295
end
1296
return
formatters
[
"
% t (n=%s)
"
]
(
t
,
n
)
1297
end
1298
end
1299 1300
statistics
.
register
(
"
math script replacements
"
,
function
(
)
1301
return
collected
(
replaced
)
1302
end
)
1303 1304
statistics
.
register
(
"
unknown math characters
"
,
function
(
)
1305
return
collected
(
unknowns
)
1306
end
)
1307 1308
end
1309 1310
-- math alternates: (in xits lgf: $ABC$ $\cal ABC$ $\mathalternate{cal}\cal ABC$)
1311
-- math alternates: (in lucidaot lgf: $ABC \mathalternate{italic} ABC$)
1312 1313
-- todo: set alternate for specific symbols
1314
-- todo: no need to do this when already loaded
1315
-- todo: use a fonts.hashes.mathalternates
1316 1317
do
1318 1319
local
last
=
0
1320 1321
local
known
=
setmetatableindex
(
function
(
t
,
k
)
1322
local
v
=
0
|
2
^
last
1323
t
[
k
]
=
v
1324
last
=
last
+
1
1325
return
v
1326
end
)
1327 1328
local
defaults
=
{
1329
dotless
=
{
feature
=
'
dtls
'
,
value
=
1
,
comment
=
"
Mathematical Dotless Forms
"
}
,
1330
-- zero = { feature = 'zero', value = 1, comment = "Slashed or Dotted Zero" }, -- in no math font (yet)
1331
}
1332 1333
local
function
initializemathalternates
(
tfmdata
)
1334
local
goodies
=
tfmdata
.
goodies
1335
local
autolist
=
defaults
-- table.copy(defaults)
1336 1337
local
function
setthem
(
newalternates
)
1338
local
resources
=
tfmdata
.
resources
-- was tfmdata.shared
1339
local
mathalternates
=
resources
.
mathalternates
1340
local
alternates
,
attributes
,
registered
,
presets
1341
if
mathalternates
then
1342
alternates
=
mathalternates
.
alternates
1343
attributes
=
mathalternates
.
attributes
1344
registered
=
mathalternates
.
registered
1345
else
1346
alternates
,
attributes
,
registered
=
{
}
,
{
}
,
{
}
1347
mathalternates
=
{
1348
attributes
=
attributes
,
1349
alternates
=
alternates
,
1350
registered
=
registered
,
1351
presets
=
{
}
,
1352
resets
=
{
}
,
1353
hashes
=
setmetatableindex
(
"
table
"
)
1354
}
1355
resources
.
mathalternates
=
mathalternates
1356
end
1357
--
1358
for
name
,
data
in
sortedhash
(
newalternates
)
do
1359
if
alternates
[
name
]
then
1360
-- ignore
1361
else
1362
local
attr
=
known
[
name
]
1363
attributes
[
attr
]
=
data
1364
alternates
[
name
]
=
attr
1365
registered
[
#
registered
+
1
]
=
attr
1366
end
1367
end
1368
end
1369 1370
if
goodies
then
1371
local
done
=
{
}
1372
for
i
=
1
,
#
goodies
do
1373
-- first one counts
1374
-- we can consider sharing the attributes ... todo (only once scan)
1375
local
mathgoodies
=
goodies
[
i
]
.
mathematics
1376
local
alternates
=
mathgoodies
and
mathgoodies
.
alternates
1377
if
alternates
then
1378
if
trace_goodies
then
1379
report_goodies
(
"
loading alternates for font %a
"
,
tfmdata
.
properties
.
name
)
1380
end
1381
for
k
,
v
in
next
,
autolist
do
1382
if
not
alternates
[
k
]
then
1383
alternates
[
k
]
=
v
1384
end
1385
end
1386
setthem
(
alternates
)
1387
return
1388
end
1389
end
1390
end
1391 1392
if
trace_goodies
then
1393
report_goodies
(
"
loading default alternates for font %a
"
,
tfmdata
.
properties
.
name
)
1394
end
1395
setthem
(
autolist
)
1396 1397
end
1398 1399
registerotffeature
{
1400
name
=
"
mathalternates
"
,
1401
description
=
"
additional math alternative shapes
"
,
1402
initializers
=
{
1403
base
=
initializemathalternates
,
1404
node
=
initializemathalternates
,
1405
}
1406
}
1407 1408
-- local getalternate = otf.getalternate (runtime new method so ...)
1409 1410
-- todo: not shared but copies ... one never knows
1411 1412
local
a_mathalternate
=
privateattribute
(
"
mathalternate
"
)
1413
local
alternate
=
{
}
-- processors.alternate = alternate
1414
local
fontdata
=
fonts
.
hashes
.
identifiers
1415
local
fontresources
=
fonts
.
hashes
.
resources
1416 1417
local
function
getalternate
(
fam
,
tag
,
current
)
1418
-- fam is always zero, so we assume a very consistent setup
1419
local
resources
=
fontresources
[
getfontoffamily
(
fam
)
]
1420
local
attribute
=
unsetvalue
1421
if
resources
then
1422
local
mathalternates
=
resources
.
mathalternates
1423
if
mathalternates
then
1424
local
presets
=
mathalternates
.
presets
1425
if
presets
then
1426
local
resets
=
mathalternates
.
resets
1427
attribute
=
presets
[
tag
]
1428
if
not
attribute
then
1429
attribute
=
0
1430
local
alternates
=
mathalternates
.
alternates
1431
for
s
in
gmatch
(
tag
,
"
[^, ]+
"
)
do
1432
if
s
=
=
v_reset
then
1433
resets
[
tag
]
=
true
1434
current
=
unsetvalue
1435
else
1436
local
a
=
alternates
[
s
]
-- or known[s]
1437
if
a
then
1438
attribute
=
attribute
|
a
1439
end
1440
end
1441
end
1442
if
attribute
=
=
0
then
1443
attribute
=
unsetvalue
1444
end
1445
presets
[
tag
]
=
attribute
1446
elseif
resets
[
tag
]
then
1447
current
=
unsetvalue
1448
end
1449
end
1450
end
1451
end
1452
if
attribute
>
0
and
current
and
current
>
0
then
1453
return
current
|
attribute
1454
else
1455
return
attribute
1456
end
1457
end
1458 1459
implement
{
1460
name
=
"
presetmathfontalternate
"
,
1461
arguments
=
"
argument
"
,
1462
public
=
true
,
1463
protected
=
true
,
1464
actions
=
function
(
tag
)
1465
if
texgetmode
(
)
=
=
mathmode_code
then
1466
texsetattribute
(
a_mathalternate
,
getalternate
(
0
,
tag
)
)
1467
end
1468
end
,
1469
}
1470 1471
implement
{
1472
name
=
"
setmathfontalternate
"
,
1473
arguments
=
"
argument
"
,
1474
public
=
true
,
1475
protected
=
true
,
1476
actions
=
function
(
tag
)
1477
if
texgetmode
(
)
=
=
mathmode_code
then
1478
texsetattribute
(
a_mathalternate
,
getalternate
(
0
,
tag
,
texgetattribute
(
a_mathalternate
)
)
)
1479
end
1480
end
,
1481
}
1482 1483
alternate
[
mathchar_code
]
=
function
(
pointer
)
-- slow
1484
local
a
=
getattr
(
pointer
,
a_mathalternate
)
1485
if
a
and
a
>
0
then
1486
setattr
(
pointer
,
a_mathalternate
,
0
)
1487
local
fontid
=
getfont
(
pointer
)
1488
local
resources
=
fontresources
[
fontid
]
1489
if
resources
then
1490
local
mathalternates
=
resources
.
mathalternates
1491
if
mathalternates
then
1492
local
attributes
=
mathalternates
.
attributes
1493
local
registered
=
mathalternates
.
registered
1494
local
hashes
=
mathalternates
.
hashes
1495
for
i
=
1
,
#
registered
do
1496
local
r
=
registered
[
i
]
1497
if
(
a
&
r
)
~
=
0
then
1498
local
char
=
getchar
(
pointer
)
1499
local
alt
=
hashes
[
i
]
[
char
]
1500
if
alt
=
=
nil
then
1501
local
what
=
attributes
[
r
]
1502
alt
=
otf
.
getalternate
(
fontdata
[
fontid
]
,
char
,
what
.
feature
,
what
.
value
)
or
false
1503
if
alt
=
=
char
then
1504
alt
=
false
1505
end
1506
hashes
[
i
]
[
char
]
=
alt
1507
end
1508
if
alt
then
1509
if
trace_alternates
then
1510
local
what
=
attributes
[
r
]
1511
report_alternates
(
"
alternate %a, value %a, replacing glyph %U by glyph %U
"
,
1512
tostring
(
what
.
feature
)
,
tostring
(
what
.
value
)
,
char
,
alt
)
1513
end
1514
setchar
(
pointer
,
alt
)
1515
break
1516
end
1517
end
1518
end
1519
end
1520
end
1521
end
1522
end
1523 1524
function
handlers
.
alternates
(
head
,
style
,
penalties
)
1525
processnoads
(
head
,
alternate
,
"
alternate
"
)
1526
return
true
-- not needed
1527
end
1528 1529
end
1530 1531
-- italics: we assume that only characters matter
1532
--
1533
-- = we check for correction first because accessing nodes is slower
1534
-- = the actual glyph is not that important (we can control it with numbers)
1535 1536
-- Italic correction in luatex math is (was) a mess. There are all kind of assumptions based on
1537
-- old fonts and new fonts. Eventually there should be a flag that can signal to ignore all
1538
-- those heuristics. We want to deal with it ourselves also in the perspective of mixed math
1539
-- and text. Also, for a while in context we had to deal with a mix of virtual math fonts and
1540
-- real ones.
1541 1542
-- in opentype the italic correction of a limop is added to the width and luatex does
1543
-- some juggling that we want to avoid but we need to do something here (in fact, we could
1544
-- better fix the width of the character)
1545 1546
do
1547 1548
local
a_mathitalics
=
privateattribute
(
"
mathitalics
"
)
1549 1550
local
italics
=
{
}
1551
local
default_factor
=
1
/
20
1552 1553
local
setcolor
=
colortracers
.
set
1554
local
resetcolor
=
colortracers
.
reset
1555
local
italic_kern
=
new_kern
1556 1557
local
c_positive_d
=
"
trace:dg
"
1558
local
c_negative_d
=
"
trace:dr
"
1559 1560
local
function
insert_kern
(
current
,
kern
)
1561
local
sub
=
new_submlist
(
)
-- todo: attr
1562
local
noad
=
new_noad
(
)
-- todo: attr
1563
setlist
(
sub
,
kern
)
1564
setnext
(
kern
,
noad
)
1565
setnucleus
(
noad
,
current
)
1566
return
sub
1567
end
1568 1569
registertracker
(
"
math.italics.visualize
"
,
function
(
v
)
1570
if
v
then
1571
italic_kern
=
function
(
k
)
1572
local
n
=
new_kern
(
k
)
-- todo: attr
1573
set_visual
(
n
,
"
italic
"
)
1574
return
n
1575
end
1576
else
1577
italic_kern
=
new_kern
1578
end
1579
end
)
1580 1581
local
function
getcorrection
(
method
,
font
,
char
)
-- -- or character.italic -- (this one is for tex)
1582 1583
local
visual
=
chardata
[
char
]
.
visual
1584 1585
if
method
=
=
1
then
1586
-- check on state
1587
local
italics
=
fontitalics
[
font
]
1588
if
italics
then
1589
local
character
=
fontcharacters
[
font
]
[
char
]
1590
if
character
then
1591
local
correction
=
character
.
italic
1592
if
correction
and
correction
~
=
0
then
1593
return
correction
,
visual
1594
end
1595
end
1596
end
1597
elseif
method
=
=
2
then
1598
-- no check
1599
local
character
=
fontcharacters
[
font
]
[
char
]
1600
if
character
then
1601
local
correction
=
character
.
italic
1602
if
correction
and
correction
~
=
0
then
1603
return
correction
,
visual
1604
end
1605
end
1606
elseif
method
=
=
3
then
1607
-- check on visual
1608
if
visual
=
=
"
it
"
or
visual
=
=
"
bi
"
then
1609
local
character
=
fontcharacters
[
font
]
[
char
]
1610
if
character
then
1611
local
correction
=
character
.
italic
1612
if
correction
and
correction
~
=
0
then
1613
return
correction
,
visual
1614
end
1615
end
1616
end
1617
elseif
method
=
=
4
then
1618
-- combination of 1 and 3
1619
local
italics
=
fontitalics
[
font
]
1620
if
italics
and
(
visual
=
=
"
it
"
or
visual
=
=
"
bi
"
)
then
1621
local
character
=
fontcharacters
[
font
]
[
char
]
1622
if
character
then
1623
local
correction
=
character
.
italic
1624
if
correction
and
correction
~
=
0
then
1625
return
correction
,
visual
1626
end
1627
end
1628
end
1629
end
1630 1631
end
1632 1633
italics
[
mathchar_code
]
=
function
(
pointer
,
what
,
n
,
parent
)
1634
local
method
=
getattr
(
pointer
,
a_mathitalics
)
1635
if
method
and
method
>
0
and
method
<
100
then
1636
local
char
,
font
=
getcharspec
(
pointer
)
1637
local
correction
,
visual
=
getcorrection
(
method
,
font
,
char
)
1638
if
correction
and
correction
~
=
0
then
1639
local
next_noad
=
getnext
(
parent
)
1640
if
not
next_noad
then
1641
if
n
=
=
1
then
1642
-- only at the outer level .. will become an option (always,endonly,none)
1643
if
trace_italics
then
1644
report_italics
(
"
method %a, flagging italic correction %p between %C and end math
"
,
method
,
correction
,
char
)
1645
end
1646
if
correction
>
0
then
1647
correction
=
correction
+
100
1648
else
1649
correction
=
correction
-
100
1650
end
1651
correction
=
round
(
correction
)
1652
setattr
(
pointer
,
a_mathitalics
,
correction
)
1653
setattr
(
parent
,
a_mathitalics
,
correction
)
1654
return
-- so no reset later on
1655
end
1656
end
1657
end
1658
end
1659
setattr
(
pointer
,
a_mathitalics
,
unsetvalue
)
1660
end
1661 1662
function
handlers
.
italics
(
head
,
style
,
penalties
)
1663
processnoads
(
head
,
italics
,
"
italics
"
)
1664
return
true
-- not needed
1665
end
1666 1667
local
enable
=
function
(
)
1668
enableaction
(
"
math
"
,
"
noads.handlers.italics
"
)
1669
if
trace_italics
then
1670
report_italics
(
"
enabling math italics
"
)
1671
end
1672
-- we enable math (unless already enabled elsewhere)
1673
typesetters
.
italics
.
enablemath
(
)
1674
enable
=
false
1675
end
1676 1677
-- best do this only on math mode (less overhead)
1678 1679
function
mathematics
.
setitalics
(
name
)
1680
if
enable
then
1681
enable
(
)
1682
end
1683
texsetattribute
(
a_mathitalics
,
name
and
name
~
=
v_reset
and
tonumber
(
name
)
or
unsetvalue
)
-- maybe also v_none
1684
end
1685 1686
function
mathematics
.
getitalics
(
name
)
1687
if
enable
then
1688
enable
(
)
1689
end
1690
context
(
name
and
name
~
=
v_reset
and
tonumber
(
name
)
or
unsetvalue
)
1691
end
1692 1693
function
mathematics
.
resetitalics
(
)
1694
texsetattribute
(
a_mathitalics
,
unsetvalue
)
1695
end
1696 1697
implement
{
1698
name
=
"
initializemathitalics
"
,
1699
actions
=
enable
,
1700
onlyonce
=
true
,
1701
}
1702 1703
implement
{
1704
name
=
"
setmathitalics
"
,
1705
actions
=
mathematics
.
setitalics
,
1706
arguments
=
"
string
"
,
1707
}
1708 1709
implement
{
1710
name
=
"
getmathitalics
"
,
1711
actions
=
mathematics
.
getitalics
,
1712
arguments
=
"
string
"
,
1713
}
1714 1715
implement
{
1716
name
=
"
resetmathitalics
"
,
1717
actions
=
mathematics
.
resetitalics
1718
}
1719 1720
end
1721 1722
do
1723 1724
-- math kerns (experiment) in goodies:
1725
--
1726
-- mathematics = {
1727
-- kernpairs = {
1728
-- [0x1D44E] = {
1729
-- [0x1D44F] = 400, -- 𝑎𝑏
1730
-- }
1731
-- },
1732
-- }
1733 1734
local
a_kernpairs
=
privateattribute
(
"
mathkernpairs
"
)
1735
local
kernpairs
=
{
}
1736 1737
local
function
enable
(
)
1738
enableaction
(
"
math
"
,
"
noads.handlers.kernpairs
"
)
1739
if
trace_kernpairs
then
1740
report_kernpairs
(
"
enabling math kern pairs
"
)
1741
end
1742
enable
=
false
1743
end
1744 1745
implement
{
1746
name
=
"
initializemathkernpairs
"
,
1747
actions
=
enable
,
1748
onlyonce
=
true
,
1749
}
1750 1751
local
hash
=
setmetatableindex
(
function
(
t
,
font
)
1752
local
g
=
fontdata
[
font
]
.
goodies
1753
local
m
=
g
and
g
[
1
]
and
g
[
1
]
.
mathematics
1754
local
k
=
m
and
m
.
kernpairs
1755
t
[
font
]
=
k
1756
return
k
1757
end
)
1758 1759
-- no correction after prime because that moved to a superscript
1760 1761
kernpairs
[
mathchar_code
]
=
function
(
pointer
,
what
,
n
,
parent
)
1762
if
getattr
(
pointer
,
a_kernpairs
)
=
=
1
then
1763
local
first
,
firstfont
=
getcharspec
(
pointer
)
1764
local
list
=
hash
[
firstfont
]
1765
if
list
then
1766
local
found
=
list
[
first
]
1767
if
found
then
1768
local
next
=
getnext
(
parent
)
1769
if
next
and
getid
(
next
)
=
=
noad_code
then
1770
pointer
=
getnucleus
(
next
)
1771
if
pointer
then
1772
local
second
,
secondfont
=
getcharspec
(
pointer
)
1773
if
secondfont
=
=
firstfont
then
1774
local
kern
=
found
[
second
]
1775
if
kern
then
1776
kern
=
kern
*
fontparameters
[
firstfont
]
.
hfactor
1777
if
trace_kernpairs
then
1778
report_kernpairs
(
"
adding %p kerning between %C and %C
"
,
kern
,
first
,
second
)
1779
end
1780
setlink
(
parent
,
new_kern
(
kern
)
,
getnext
(
parent
)
)
-- todo: attr
1781
end
1782
end
1783
end
1784
end
1785
end
1786
end
1787
end
1788
end
1789 1790
function
handlers
.
kernpairs
(
head
,
style
,
penalties
)
1791
processnoads
(
head
,
kernpairs
,
"
kernpairs
"
)
1792
return
true
-- not needed
1793
end
1794 1795
end
1796 1797
-- primes and such
1798 1799
do
1800 1801
-- is validpair stil needed?
1802 1803
local
a_mathcollapsing
=
privateattribute
(
"
mathcollapsing
"
)
1804
local
collapse
=
{
}
1805
local
mathlists
=
characters
.
mathlists
1806
local
validpair
=
{
1807
[
ordnoad_code
]
=
true
,
1808
[
opnoad_code
]
=
true
,
1809
[
binnoad_code
]
=
true
,
-- new
1810
[
relnode_code
]
=
true
,
1811
[
opennoad_code
]
=
true
,
-- new
1812
[
closenoad_code
]
=
true
,
-- new
1813
[
punctnoad_code
]
=
true
,
-- new
1814
[
innernoad_code
]
=
false
,
1815
[
undernoad_code
]
=
false
,
1816
[
overnoad_code
]
=
false
,
1817
[
vcenternoad_code
]
=
false
,
1818
}
1819 1820
local
reported
=
setmetatableindex
(
"
table
"
)
1821 1822
collapse
[
mathchar_code
]
=
function
(
pointer
,
what
,
n
,
parent
)
1823 1824
if
parent
and
mathlists
[
getchar
(
pointer
)
]
then
1825
local
found
,
last
,
lucleus
,
lsup
,
lsub
,
category
1826
local
tree
=
mathlists
1827
local
current
=
parent
1828
while
current
and
validpair
[
getsubtype
(
current
)
]
do
1829
local
nucleus
=
getnucleus
(
current
)
-- == pointer
1830
local
sub
=
getsub
(
current
)
1831
local
sup
=
getsup
(
current
)
1832
local
char
=
getchar
(
nucleus
)
1833
if
char
then
1834
local
match
=
tree
[
char
]
1835
if
match
then
1836
local
method
=
getattr
(
current
,
a_mathcollapsing
)
1837
if
method
and
method
>
0
and
method
<
=
3
then
1838
local
specials
=
match
.
specials
1839
local
mathlist
=
match
.
mathlist
1840
local
ligature
1841
if
method
=
=
1
then
1842
ligature
=
specials
1843
elseif
method
=
=
2
then
1844
ligature
=
specials
or
mathlist
1845
else
-- 3
1846
ligature
=
mathlist
or
specials
1847
end
1848
if
ligature
then
1849
category
=
mathlist
and
"
mathlist
"
or
"
specials
"
1850
found
=
ligature
1851
last
=
current
1852
lucleus
=
nucleus
1853
lsup
=
sup
1854
lsub
=
sub
1855
end
1856
tree
=
match
1857
if
sub
or
sup
then
1858
break
1859
else
1860
current
=
getnext
(
current
)
1861
end
1862
else
1863
break
1864
end
1865
else
1866
break
1867
end
1868
else
1869
break
1870
end
1871
end
1872
if
found
and
last
and
lucleus
then
1873
local
id
=
getfont
(
lucleus
)
1874
local
characters
=
fontcharacters
[
id
]
1875
local
replace
=
characters
and
characters
[
found
]
1876
if
not
replace
then
1877
if
not
reported
[
id
]
[
found
]
then
1878
reported
[
id
]
[
found
]
=
true
1879
report_collapsing
(
"
%s ligature %C from %s
"
,
"
ignoring
"
,
found
,
category
)
1880
end
1881
elseif
trace_collapsing
then
1882
report_collapsing
(
"
%s ligature %C from %s
"
,
"
creating
"
,
found
,
category
)
1883
end
1884
setchar
(
pointer
,
found
)
1885
local
l
=
getnext
(
last
)
1886
local
c
=
getnext
(
parent
)
1887
if
lsub
then
1888
setsub
(
parent
,
lsub
)
1889
setsub
(
last
)
1890
end
1891
if
lsup
then
1892
setsup
(
parent
,
lsup
)
1893
setsup
(
last
)
1894
end
1895
while
c
~
=
l
do
1896
local
n
=
getnext
(
c
)
1897
flushnode
(
c
)
1898
c
=
n
1899
end
1900
setlink
(
parent
,
l
)
1901
end
1902
end
1903
end
1904 1905
function
noads
.
handlers
.
collapse
(
head
,
style
,
penalties
)
1906
processnoads
(
head
,
collapse
,
"
collapse
"
)
1907
return
true
-- not needed
1908
end
1909 1910
local
enable
=
function
(
)
1911
enableaction
(
"
math
"
,
"
noads.handlers.collapse
"
)
1912
if
trace_collapsing
then
1913
report_collapsing
(
"
enabling math collapsing
"
)
1914
end
1915
enable
=
false
1916
end
1917 1918
implement
{
1919
name
=
"
initializemathcollapsing
"
,
1920
actions
=
enable
,
1921
onlyonce
=
true
,
1922
}
1923 1924
end
1925 1926
do
1927
-- inner under over vcenter
1928 1929
local
fixscripts
=
{
}
1930
local
movesub
=
{
1931
-- primes
1932
[
0x2032
]
=
0xFE932
,
1933
[
0x2033
]
=
0xFE933
,
1934
[
0x2034
]
=
0xFE934
,
1935
[
0x2057
]
=
0xFE957
,
1936
-- reverse primes
1937
[
0x2035
]
=
0xFE935
,
1938
[
0x2036
]
=
0xFE936
,
1939
[
0x2037
]
=
0xFE937
,
1940
}
1941 1942
mathematics
.
virtualize
(
movesub
)
1943 1944
local
nosuperscript_code
=
tex
.
mathoptioncodes
.
nosuperscript
1945 1946
local
function
fixsupscript
(
parent
,
current
,
current_char
,
new_char
)
1947
if
new_char
~
=
current_char
and
new_char
~
=
true
then
1948
setchar
(
current
,
new_char
)
1949
if
trace_fixing
then
1950
report_fixing
(
"
fixing subscript, replacing superscript %U by %U
"
,
current_char
,
new_char
)
1951
end
1952
else
1953
if
trace_fixing
then
1954
report_fixing
(
"
fixing subscript, superscript %U
"
,
current_char
)
1955
end
1956
end
1957
setfield
(
parent
,
"
options
"
,
nosuperscript_code
)
1958
end
1959 1960
local
function
move_none_none
(
parent
,
prev
,
nuc
,
oldchar
,
newchar
)
1961
fixsupscript
(
prev
,
nuc
,
oldchar
,
newchar
)
1962
local
sub
=
getsub
(
parent
)
1963
setsup
(
prev
,
nuc
)
1964
setsub
(
prev
,
sub
)
1965
local
dummy
=
copy_node
(
nuc
)
1966
setchar
(
dummy
,
0
)
1967
setnucleus
(
parent
,
dummy
)
1968
setsub
(
parent
)
1969
end
1970 1971
local
function
move_none_psub
(
parent
,
prev
,
nuc
,
oldchar
,
newchar
)
1972
fixsupscript
(
prev
,
nuc
,
oldchar
,
newchar
)
1973
setsup
(
prev
,
nuc
)
1974
local
dummy
=
copy_node
(
nuc
)
1975
setchar
(
dummy
,
0
)
1976
setnucleus
(
parent
,
dummy
)
1977
end
1978 1979
fixscripts
[
mathchar_code
]
=
function
(
pointer
,
what
,
n
,
parent
,
nested
)
-- todo: switch to turn in on and off
1980
if
parent
then
1981
local
oldchar
=
getchar
(
pointer
)
1982
local
newchar
=
movesub
[
oldchar
]
1983
if
newchar
then
1984
local
nuc
=
getnucleus
(
parent
)
1985
if
pointer
=
=
nuc
then
1986
local
sub
=
getsub
(
pointer
)
1987
local
sup
=
getsup
(
pointer
)
1988
if
sub
then
1989
if
sup
then
1990
-- print("[char] sub sup")
1991
else
1992
-- print("[char] sub ---")
1993
end
1994
elseif
sup
then
1995
-- print("[char] --- sup")
1996
else
1997
local
prev
=
getprev
(
parent
)
1998
if
prev
and
getid
(
prev
)
=
=
noad_code
then
1999
local
psub
=
getsub
(
prev
)
2000
local
psup
=
getsup
(
prev
)
2001
if
psub
then
2002
if
psup
then
2003
-- print("sub sup [char] --- ---")
2004
else
2005
-- print("sub --- [char] --- ---")
2006
move_none_psub
(
parent
,
prev
,
nuc
,
oldchar
,
newchar
)
2007
end
2008
elseif
psup
then
2009
-- print("--- sup [char] --- ---")
2010
else
2011
-- print("[char] --- ---")
2012
move_none_none
(
parent
,
prev
,
nuc
,
oldchar
,
newchar
)
2013
end
2014
else
2015
-- print("no prev [char]")
2016
end
2017
end
2018
else
2019
-- print("[char]")
2020
end
2021
end
2022
end
2023
end
2024 2025
function
noads
.
handlers
.
fixscripts
(
head
,
style
,
penalties
)
2026
processnoads
(
head
,
fixscripts
,
"
fixscripts
"
)
2027
return
true
-- not needed
2028
end
2029 2030
end
2031 2032
-- variants
2033 2034
do
2035 2036
local
variants
=
{
}
2037
local
validvariants
=
{
-- fast check on valid
2038
[
0x2229
]
=
0xFE00
,
[
0x222A
]
=
0xFE00
,
2039
[
0x2268
]
=
0xFE00
,
[
0x2269
]
=
0xFE00
,
2040
[
0x2272
]
=
0xFE00
,
[
0x2273
]
=
0xFE00
,
2041
[
0x228A
]
=
0xFE00
,
[
0x228B
]
=
0xFE00
,
2042
[
0x2293
]
=
0xFE00
,
[
0x2294
]
=
0xFE00
,
2043
[
0x2295
]
=
0xFE00
,
2044
[
0x2297
]
=
0xFE00
,
2045
[
0x229C
]
=
0xFE00
,
2046
[
0x22DA
]
=
0xFE00
,
[
0x22DB
]
=
0xFE00
,
2047
[
0x2A3C
]
=
0xFE00
,
[
0x2A3D
]
=
0xFE00
,
2048
[
0x2A9D
]
=
0xFE00
,
[
0x2A9E
]
=
0xFE00
,
2049
[
0x2AAC
]
=
0xFE00
,
[
0x2AAD
]
=
0xFE00
,
2050
[
0x2ACB
]
=
0xFE00
,
[
0x2ACC
]
=
0xFE00
,
2051
}
2052 2053
variants
[
mathchar_code
]
=
function
(
pointer
,
what
,
n
,
parent
)
-- also set export value
2054
local
char
=
getchar
(
pointer
)
2055
local
selector
=
validvariants
[
char
]
2056
if
selector
then
2057
local
next
=
getnext
(
parent
)
2058
if
next
and
getid
(
next
)
=
=
noad_code
then
2059
local
nucleus
=
getnucleus
(
next
)
2060
if
nucleus
and
getid
(
nucleus
)
=
=
mathchar_code
and
getchar
(
nucleus
)
=
=
selector
then
2061
local
variant
2062
local
tfmdata
=
fontdata
[
getfont
(
pointer
)
]
2063
local
mathvariants
=
tfmdata
.
resources
.
variants
-- and variantdata
2064
if
mathvariants
then
2065
mathvariants
=
mathvariants
[
selector
]
2066
if
mathvariants
then
2067
variant
=
mathvariants
[
char
]
2068
end
2069
end
2070
if
variant
then
2071
setchar
(
pointer
,
variant
)
2072
setattr
(
pointer
,
a_exportstatus
,
char
)
-- we don't export the variant as it's visual markup
2073
if
trace_variants
then
2074
report_variants
(
"
variant (%U,%U) replaced by %U
"
,
char
,
selector
,
variant
)
2075
end
2076
else
2077
if
trace_variants
then
2078
report_variants
(
"
no variant (%U,%U)
"
,
char
,
selector
)
2079
end
2080
end
2081
setprev
(
next
,
pointer
)
2082
setnext
(
parent
,
getnext
(
next
)
)
2083
flushnode
(
next
)
2084
end
2085
end
2086
end
2087
end
2088 2089
function
handlers
.
variants
(
head
,
style
,
penalties
)
2090
processnoads
(
head
,
variants
,
"
unicode variant
"
)
2091
return
true
-- not needed
2092
end
2093 2094
end
2095 2096
-- for manuals
2097 2098
do
2099 2100
local
classes
=
{
}
2101
local
colors
=
{
2102
[
relnode_code
]
=
"
trace:dr
"
,
2103
[
ordnoad_code
]
=
"
trace:db
"
,
2104
[
binnoad_code
]
=
"
trace:dg
"
,
2105
[
opennoad_code
]
=
"
trace:dm
"
,
2106
[
closenoad_code
]
=
"
trace:dm
"
,
2107
[
punctnoad_code
]
=
"
trace:dc
"
,
2108
-- [opnoad_code] = "",
2109
-- [innernoad_code = "",
2110
-- [undernoad_code] = "",
2111
-- [overnoad_code] = "",
2112
-- [vcenternoad_code] = "",
2113
}
2114 2115
local
setcolor
=
colortracers
.
set
2116
local
resetcolor
=
colortracers
.
reset
2117 2118
classes
[
mathchar_code
]
=
function
(
pointer
,
what
,
n
,
parent
)
2119
local
color
=
colors
[
getsubtype
(
parent
)
]
2120
if
color
then
2121
setcolor
(
pointer
,
color
)
2122
else
2123
resetcolor
(
pointer
)
2124
end
2125
end
2126 2127
function
handlers
.
classes
(
head
,
style
,
penalties
)
2128
processnoads
(
head
,
classes
,
"
classes
"
)
2129
return
true
-- not needed
2130
end
2131 2132
registertracker
(
"
math.classes
"
,
function
(
v
)
2133
setaction
(
"
math
"
,
"
noads.handlers.classes
"
,
v
)
2134
end
)
2135 2136
end
2137 2138
-- experimental
2139 2140
do
2141 2142
-- mathematics.registerdomain {
2143
-- name = "foo",
2144
-- parents = { "bar" },
2145
-- characters = {
2146
-- [0x123] = { char = 0x234, class = binary },
2147
-- },
2148
-- }
2149 2150
local
domains
=
{
}
2151
local
categories
=
{
}
2152
local
numbers
=
{
}
2153
local
a_mathdomain
=
privateattribute
(
"
mathdomain
"
)
2154
mathematics
.
domains
=
categories
2155
local
permitted
=
{
2156
ordinary
=
ordnoad_code
,
2157
binary
=
binnoad_code
,
2158
relation
=
relnode_code
,
2159
punctuation
=
punctnoad_code
,
2160
inner
=
innernoad_code
,
2161
}
2162 2163
function
mathematics
.
registerdomain
(
data
)
2164
local
name
=
data
.
name
2165
if
not
name
then
2166
return
2167
end
2168
local
attr
=
#
numbers
+
1
2169
categories
[
name
]
=
data
2170
numbers
[
attr
]
=
data
2171
data
.
attribute
=
attr
2172
-- we delay hashing
2173
return
attr
2174
end
2175 2176
local
enable
2177 2178
enable
=
function
(
)
2179
enableaction
(
"
math
"
,
"
noads.handlers.domains
"
)
2180
if
trace_domains
then
2181
report_domains
(
"
enabling math domains
"
)
2182
end
2183
enable
=
false
2184
end
2185 2186
function
mathematics
.
setdomain
(
name
)
2187
if
enable
then
2188
enable
(
)
2189
end
2190
local
data
=
name
and
name
~
=
v_reset
and
categories
[
name
]
2191
texsetattribute
(
a_mathdomain
,
data
and
data
.
attribute
or
unsetvalue
)
2192
end
2193 2194
function
mathematics
.
getdomain
(
name
)
2195
if
enable
then
2196
enable
(
)
2197
end
2198
local
data
=
name
and
name
~
=
v_reset
and
categories
[
name
]
2199
context
(
data
and
data
.
attribute
or
unsetvalue
)
2200
end
2201 2202
implement
{
2203
name
=
"
initializemathdomain
"
,
2204
actions
=
enable
,
2205
onlyonce
=
true
,
2206
}
2207 2208
implement
{
2209
name
=
"
setmathdomain
"
,
2210
arguments
=
"
string
"
,
2211
actions
=
mathematics
.
setdomain
,
2212
}
2213 2214
implement
{
2215
name
=
"
getmathdomain
"
,
2216
arguments
=
"
string
"
,
2217
actions
=
mathematics
.
getdomain
,
2218
}
2219 2220
local
function
makehash
(
data
)
2221
local
hash
=
{
}
2222
local
parents
=
data
.
parents
2223
if
parents
then
2224
local
function
merge
(
name
)
2225
if
name
then
2226
local
c
=
categories
[
name
]
2227
if
c
then
2228
local
hash
=
c
.
hash
2229
if
not
hash
then
2230
hash
=
makehash
(
c
)
2231
end
2232
for
k
,
v
in
next
,
hash
do
2233
hash
[
k
]
=
v
2234
end
2235
end
2236
end
2237
end
2238
if
type
(
parents
)
=
=
"
string
"
then
2239
merge
(
parents
)
2240
elseif
type
(
parents
)
=
=
"
table
"
then
2241
for
i
=
1
,
#
parents
do
2242
merge
(
parents
[
i
]
)
2243
end
2244
end
2245
end
2246
local
characters
=
data
.
characters
2247
if
characters
then
2248
for
k
,
v
in
next
,
characters
do
2249
-- local chr = n.char
2250
local
cls
=
v
.
class
2251
if
cls
then
2252
v
.
code
=
permitted
[
cls
]
2253
else
2254
-- invalid class
2255
end
2256
hash
[
k
]
=
v
2257
end
2258
end
2259
data
.
hash
=
hash
2260
return
hash
2261
end
2262 2263
domains
[
mathchar_code
]
=
function
(
pointer
,
what
,
n
,
parent
)
2264
local
attr
=
getattr
(
pointer
,
a_mathdomain
)
2265
if
attr
then
2266
local
domain
=
numbers
[
attr
]
2267
if
domain
then
2268
local
hash
=
domain
.
hash
2269
if
not
hash
then
2270
hash
=
makehash
(
domain
)
2271
end
2272
local
char
=
getchar
(
pointer
)
2273
local
okay
=
hash
[
char
]
2274
if
okay
then
2275
local
chr
=
okay
.
char
2276
local
cls
=
okay
.
code
2277
if
chr
and
chr
~
=
char
then
2278
setchar
(
pointer
,
chr
)
2279
end
2280
if
cls
and
cls
~
=
getsubtype
(
parent
)
then
2281
setsubtype
(
parent
,
cls
)
2282
end
2283
end
2284
end
2285
end
2286
end
2287 2288
function
handlers
.
domains
(
head
,
style
,
penalties
)
2289
processnoads
(
head
,
domains
,
"
domains
"
)
2290
return
true
-- not needed
2291
end
2292 2293
end
2294 2295
-- just for me
2296 2297
function
handlers
.
showtree
(
head
,
style
,
penalties
)
2298
inspect
(
nodes
.
totree
(
tonut
(
head
)
)
)
2299
end
2300 2301
registertracker
(
"
math.showtree
"
,
function
(
v
)
2302
setaction
(
"
math
"
,
"
noads.handlers.showtree
"
,
v
)
2303
end
)
2304 2305
-- also for me
2306 2307
do
2308 2309
local
applyvisuals
=
nuts
.
applyvisuals
2310
local
visual
=
false
2311 2312
function
handlers
.
makeup
(
head
)
2313
applyvisuals
(
head
,
visual
)
2314
end
2315 2316
registertracker
(
"
math.makeup
"
,
function
(
v
)
2317
visual
=
v
2318
setaction
(
"
math
"
,
"
noads.handlers.makeup
"
,
v
)
2319
end
)
2320 2321
end
2322 2323
-- the normal builder
2324 2325
-- do
2326
--
2327
-- local force_penalties = false
2328
--
2329
-- function builders.kernel.mlisttohlist(head,style,penalties)
2330
-- return mlisttohlist(head,style,force_penalties or penalties)
2331
-- end
2332
--
2333
-- implement {
2334
-- name = "setmathpenalties",
2335
-- arguments = "integer",
2336
-- actions = function(p)
2337
-- force_penalties = p > 0
2338
-- end,
2339
-- }
2340
--
2341
-- end
2342 2343
builders
.
kernel
.
mlisttohlist
=
mlisttohlist
2344 2345
local
actions
=
tasks
.
actions
(
"
math
"
)
-- head, style, penalties
2346 2347
local
starttiming
,
stoptiming
=
statistics
.
starttiming
,
statistics
.
stoptiming
2348 2349
function
processors
.
mlisttohlist
(
head
,
style
,
penalties
)
2350
starttiming
(
noads
)
2351
head
=
actions
(
head
,
style
,
penalties
)
2352
stoptiming
(
noads
)
2353
return
head
2354
end
2355 2356
callbacks
.
register
(
'
mlist_to_hlist
'
,
processors
.
mlisttohlist
,
"
preprocessing math list
"
)
2357 2358
-- tracing
2359 2360
statistics
.
register
(
"
math processing time
"
,
function
(
)
2361
return
statistics
.
elapsedseconds
(
noads
)
2362
end
)
2363