math-ini.lua /size: 25 Kb    last modification: 2021-10-28 13:50
1if not modules then modules = { } end modules ['math-ini'] = {
2    version   = 1.001,
3    comment   = "companion to math-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-- if needed we can use the info here to set up xetex definition files
10-- the "8000 hackery influences direct characters (utf) as indirect \char's
11--
12-- isn't characters.data loaded already ... shortcut it here
13--
14-- replace code 7 by 0 as we don't use it anyway (chars with code 7 will adapt to
15-- to the fam when set ... we use other means .. ok, we could use it for spacing but
16-- then we also have to set the other characters (only a subset done now)
17
18local next, type = next, type
19local formatters, find = string.formatters, string.find
20local utfchar, utfbyte, utflength = utf.char, utf.byte, utf.length
21----- floor = math.floor
22local sortedhash = table.sortedhash
23local toboolean = toboolean
24
25local context               = context
26local commands              = commands
27local implement             = interfaces.implement
28
29local ctx_sprint            = context.sprint
30local ctx_doifelsesomething = commands.doifelsesomething
31
32local trace_defining        = false  trackers.register("math.defining", function(v) trace_defining = v end)
33
34local report_math           = logs.reporter("mathematics","initializing")
35
36mathematics                 = mathematics or { }
37local mathematics           = mathematics
38
39mathematics.extrabase       = fonts.privateoffsets.mathextrabase -- here we push some virtuals
40mathematics.privatebase     = fonts.privateoffsets.mathbase      -- here we push the ex
41
42local unsetvalue            = attributes.unsetvalue
43local allocate              = utilities.storage.allocate
44local chardata              = characters.data
45
46local texsetattribute       = tex.setattribute
47local setmathcode           = tex.setmathcode
48local setdelcode            = tex.setdelcode
49
50local families = allocate {
51    mr = 0,
52    mb = 1,
53}
54
55--- to be checked  .. afew defaults in char-def that should be alpha
56
57local classes = allocate {
58    ord         =  0, -- mathordcomm     mathord
59    op          =  1, -- mathopcomm      mathop
60    bin         =  2, -- mathbincomm     mathbin
61    rel         =  3, -- mathrelcomm     mathrel
62    open        =  4, -- mathopencomm    mathopen
63    middle      =  4,
64    close       =  5, -- mathclosecomm   mathclose
65    punct       =  6, -- mathpunctcomm   mathpunct
66    alpha       =  7, -- mathalphacomm   firstofoneargument
67    accent      =  8, -- class 0
68    radical     =  9,
69    xaccent     = 10, -- class 3
70    topaccent   = 11, -- class 0
71    botaccent   = 12, -- class 0
72    under       = 13,
73    over        = 14,
74    delimiter   = 15,
75    inner       =  0, -- mathinnercomm   mathinner
76    nothing     =  0, -- mathnothingcomm firstofoneargument
77    choice      =  0, -- mathchoicecomm  @@mathchoicecomm
78    box         =  0, -- mathboxcomm     @@mathboxcomm
79    limop       =  1, -- mathlimopcomm   @@mathlimopcomm
80    nolop       =  1, -- mathnolopcomm   @@mathnolopcomm
81    --
82    ordinary    =  0, -- ord
83    alphabetic  =  7, -- alpha
84    unknown     =  0, -- nothing
85    default     =  0, -- nothing
86    punctuation =  6, -- punct
87    normal      =  0, -- nothing
88    opening     =  4, -- open
89    closing     =  5, -- close
90    binary      =  2, -- bin
91    relation    =  3, -- rel
92    fence       =  0, -- unknown
93    diacritic   =  8, -- accent
94    large       =  1, -- op
95    variable    =  7, -- alphabetic
96    number      =  7, -- alphabetic
97    root        = 16, -- a private one
98}
99
100local open_class      =  4
101local middle_class    =  4
102local close_class     =  5
103local accent_class    =  8
104local radical_class   =  9
105local topaccent_class = 11
106local botaccent_class = 12
107local under_class     = 13
108local over_class      = 14
109local delimiter_class = 15
110local root_class      = 16
111
112local accents = allocate {
113    accent    = true, -- some can be both
114    topaccent = true,  [11] = true,
115    botaccent = true,  [12] = true,
116    under     = true,  [13] = true,
117    over      = true,  [14] = true,
118    unknown   = false,
119}
120
121local codes = allocate {
122    ordinary       = 0, [0] = "ordinary",
123    largeoperator  = 1,       "largeoperator",
124    binaryoperator = 2,       "binaryoperator",
125    relation       = 3,       "relation",
126    openingsymbol  = 4,       "openingsymbol",
127    closingsymbol  = 5,       "closingsymbol",
128    punctuation    = 6,       "punctuation",
129    variable       = 7,       "variable",
130}
131
132local extensibles = allocate {
133           unknown    = 0,
134    l = 1, left       = 1,
135    r = 2, right      = 2,
136    h = 3, horizontal = 3,-- lr or rl
137    u = 5, up         = 4,
138    d = 5, down       = 5,
139    v = 6, vertical   = 6,-- ud or du
140    m = 7, mixed      = 7,
141}
142
143table.setmetatableindex(extensibles,function(t,k) t[k] = 0 return 0 end)
144
145local virtualized = allocate {
146}
147
148function mathematics.virtualize(unicode,virtual)
149
150    local function virtualize(k,v)
151        local c = virtualized[k]
152        if c == v then
153            report_math("character %C is already virtualized to %C",k,v)
154        elseif c then
155            report_math("character %C is already virtualized to %C, ignoring mapping to %C",k,c,v)
156        else
157            virtualized[k] = v
158        end
159    end
160
161    if type(unicode) == "table" then
162        for k, v in next, unicode do
163            virtualize(k,v)
164        end
165    elseif type(unicode) == "number" and type(virtual) == "number" then
166        virtualize(unicode,virtual)
167 -- else
168        -- error
169    end
170end
171
172mathematics.extensibles = extensibles
173mathematics.classes     = classes
174mathematics.codes       = codes
175-----------.accents     = codes
176mathematics.families    = families
177mathematics.virtualized = virtualized
178
179-- there will be proper functions soon (and we will move this code in-line)
180-- no need for " in class and family (saves space)
181
182-- local function mathchar(class,family,slot)
183--     return formatters['\\Umathchar "%X "%X "%X '](class,family,slot)
184-- end
185--
186-- local function mathaccent(class,family,slot)
187--     return formatters['\\Umathaccent "%X "%X "%X '](0,family,slot) -- no class
188-- end
189--
190-- local function delimiter(class,family,slot)
191--     return formatters['\\Udelimiter "%X "%X "%X '](class,family,slot)
192-- end
193--
194-- local function radical(family,slot)
195--     return formatters['\\Uradical "%X "%X '](family,slot)
196-- end
197--
198-- local function root(family,slot)
199--     return formatters['\\Uroot "%X "%X '](family,slot)
200-- end
201--
202-- local function mathchardef(name,class,family,slot)
203--     return formatters['\\Umathchardef\\%s "%X "%X "%X '](name,class,family,slot)
204-- end
205--
206-- local function mathcode(target,class,family,slot)
207--     return formatters['\\Umathcode%s="%X "%X "%X '](target,class,family,slot)
208-- end
209--
210-- local function mathtopaccent(class,family,slot)
211--     return formatters['\\Umathaccent "%X "%X "%X '](0,family,slot) -- no class
212-- end
213--
214-- local function mathbotaccent(class,family,slot)
215--     return formatters['\\Umathaccent bottom "%X "%X "%X '](0,family,slot) -- no class
216-- end
217--
218-- local function mathtopdelimiter(class,family,slot)
219--     return formatters['\\Udelimiterover "%X "%X '](family,slot) -- no class
220-- end
221--
222-- local function mathbotdelimiter(class,family,slot)
223--     return formatters['\\Udelimiterunder "%X "%X '](family,slot) -- no class
224-- end
225
226local escapes = characters.filters.utf.private.escapes
227
228-- not that many so no need to reuse tables
229
230local setmathcharacter = function(class,family,slot,unicode,mset,dset)
231    if mset and codes[class] then -- regular codes < 7
232        setmathcode("global",slot,class,family,unicode)
233        mset = false
234    end
235    if dset and class == open_class or class == close_class or class == middle_class then
236        setdelcode("global",slot,family,unicode,0,0)
237        dset = false
238    end
239    return mset, dset
240end
241
242-- todo: make nice setters for this in lua
243
244local f_accent    = formatters[ [[\defUmathtopaccent \%s{%X}{%X}{%X}]] ]
245local f_topaccent = formatters[ [[\defUmathtopaccent \%s{%X}{%X}{%X}]] ]
246local f_botaccent = formatters[ [[\defUmathbotaccent \%s{%X}{%X}{%X}]] ]
247local f_over      = formatters[ [[\defUdelimiterover \%s{%X}{%X}{%X}]] ]
248local f_under     = formatters[ [[\defUdelimiterunder\%s{%X}{%X}{%X}]] ]
249local f_fence     = formatters[ [[\defUdelimiter     \%s{%X}{%X}{%X}]] ]
250local f_delimiter = formatters[ [[\defUdelimiter     \%s{%X}{%X}{%X}]] ]
251local f_radical   = formatters[ [[\defUradical       \%s{%X}{%X}]]     ]
252local f_root      = formatters[ [[\defUroot          \%s{%X}{%X}]]     ]
253local f_char      = formatters[ [[\defUmathchar      \%s{%X}{%X}{%X}]] ]
254
255local texmathchardef = tex.mathchardef
256
257-- local setmathsymbol = function(name,class,family,slot) -- hex is nicer for tracing
258--     if class == classes.accent then
259--         ctx_sprint(f_topaccent(name,0,family,slot))
260--     elseif class == classes.topaccent then
261--         ctx_sprint(f_topaccent(name,0,family,slot))
262--     elseif class == classes.botaccent then
263--         ctx_sprint(f_botaccent(name,0,family,slot))
264--     elseif class == classes.over then
265--         ctx_sprint(f_over(name,0,family,slot))
266--     elseif class == classes.under then
267--         ctx_sprint(f_under(name,0,family,slot))
268--     elseif class == open_class or class == close_class or class == middle_class then
269--         setdelcode("global",slot,{family,slot,0,0})
270--         ctx_sprint(f_fence(name,class,family,slot))
271--     elseif class == classes.delimiter then
272--         setdelcode("global",slot,{family,slot,0,0})
273--         ctx_sprint(f_delimiter(name,0,family,slot))
274--     elseif class == classes.radical then
275--         ctx_sprint(f_radical(name,family,slot))
276--     elseif class == classes.root then
277--         ctx_sprint(f_root(name,family,slot))
278--     elseif texmathchardef then
279--         texmathchardef(name,class,family,slot,"permanent")
280--     else
281--         -- beware, open/close and other specials should not end up here
282--         ctx_sprint(f_char(name,class,family,slot))
283--     end
284-- end
285
286local setmathsymbol = function(name,class,family,slot) -- hex is nicer for tracing
287    if class == accent_class then
288        ctx_sprint(f_topaccent(name,0,family,slot))
289    elseif class == topaccent_class then
290        ctx_sprint(f_topaccent(name,0,family,slot))
291    elseif class == botaccent_class then
292        ctx_sprint(f_botaccent(name,0,family,slot))
293    elseif class == over_class then
294        ctx_sprint(f_over(name,0,family,slot))
295    elseif class == under_class then
296        ctx_sprint(f_under(name,0,family,slot))
297    elseif class == open_class or class == close_class or class == middle_class then
298        setdelcode("global",slot,{family,slot,0,0})
299        ctx_sprint(f_fence(name,class,family,slot))
300    elseif class == delimiter_class then
301        setdelcode("global",slot,{family,slot,0,0})
302        ctx_sprint(f_delimiter(name,0,family,slot))
303    elseif class == radical_class then
304        ctx_sprint(f_radical(name,family,slot))
305    elseif class == root_class then
306        ctx_sprint(f_root(name,family,slot))
307    elseif texmathchardef then
308        texmathchardef(name,class,family,slot,"permanent")
309    else
310        -- beware, open/close and other specials should not end up here
311        ctx_sprint(f_char(name,class,family,slot))
312    end
313end
314
315local function report(class,family,unicode,name)
316    local nametype = type(name)
317    if nametype == "string" then
318        report_math("class name %a, class %a, family %a, char %C, name %a",classname,class,family,unicode,name)
319    elseif nametype == "number" then
320        report_math("class name %a, class %a, family %a, char %C, number %U",classname,class,family,unicode,name)
321    else
322        report_math("class name %a, class %a, family %a, char %C", classname,class,family,unicode)
323    end
324end
325
326-- there will be a combined \(math)chardef (tracker)
327
328function mathematics.define(family)
329    family = family or 0
330    family = families[family] or family
331    local data = characters.data
332    for unicode, character in sortedhash(data) do
333        local symbol = character.mathsymbol
334        local mset   = true
335        local dset   = true
336        if symbol then
337            local other = data[symbol]
338            local class = other.mathclass
339            if class then
340                class = classes[class] or class -- no real checks needed
341                if trace_defining then
342                    report(class,family,unicode,symbol)
343                end
344                mset, dset = setmathcharacter(class,family,unicode,symbol,mset,dset)
345            end
346            local spec = other.mathspec
347            if spec then
348                for i=1,#spec do
349                    local m = spec[i]
350                    local class = m.class
351                    if class then
352                        class = classes[class] or class -- no real checks needed
353                        mset, dset = setmathcharacter(class,family,unicode,symbol,mset,dset)
354                    end
355                end
356            end
357        end
358        local mathclass = character.mathclass
359        local mathspec = character.mathspec
360        if mathspec then
361            if mathclass then
362                local name = character.mathname
363                if name then
364                    report_math("fatal error, conflicting mathclass and mathspec for %C",unicode)
365                    os.exit()
366                else
367                    local class = classes[mathclass] or mathclass -- no real checks needed
368                    if not class then
369                        if trace_defining then
370                            report("unknown",family,unicode)
371                        end
372                    else
373                        if trace_defining then
374                            report(class,family,unicode)
375                        end
376                        mset, dset = setmathcharacter(class,family,unicode,unicode,mset,dset)
377                    end
378                end
379            end
380            for i=1,#mathspec do
381                local m = mathspec[i]
382                local name = m.name
383                local class = m.class
384                if class then
385                    class = classes[class] or class -- no real checks needed
386                    if name then
387                        if trace_defining then
388                            report(class,family,unicode,name)
389                        end
390                        setmathsymbol(name,class,family,unicode)
391                    else
392                        name = (class == classes.variable or class == classes.number) and character.adobename -- bad
393                        if name and trace_defining then
394                            report(class,family,unicode,name)
395                        end
396                    end
397                    mset, dset = setmathcharacter(class,family,unicode,m.unicode or unicode,mset,dset) -- see solidus
398                end
399            end
400        elseif mathclass then
401            local name = character.mathname
402            local class = classes[mathclass] or mathclass -- no real checks needed
403            if not class then
404                if trace_defining then
405                    report("unknown",family,unicode,name)
406                end
407            elseif name == false then
408                if trace_defining then
409                    report(class,family,unicode,name)
410                end
411                mset, dset = setmathcharacter(class,family,unicode,unicode,mset,dset)
412            else
413             -- if not name then
414             --     name = character.contextname -- too dangerous, we loose textslash and a few more
415             -- end
416                if name then
417                    if trace_defining then
418                        report(class,family,unicode,name)
419                    end
420                    setmathsymbol(name,class,family,unicode)
421                else
422                    if trace_defining then
423                        report(class,family,unicode,character.adobename)
424                    end
425                end
426                mset, dset = setmathcharacter(class,family,unicode,unicode,mset,dset)
427            end
428        end
429    end
430end
431
432-- needed for mathml analysis
433-- string with # > 1 are invalid
434-- we could cache
435
436local lpegmatch = lpeg.match
437
438local utf8byte  = lpeg.patterns.utf8byte * lpeg.P(-1)
439
440-- function somechar(c)
441--     local b = lpegmatch(utf8byte,c)
442--     return b and chardata[b]
443-- end
444
445
446local somechar = { }
447
448table.setmetatableindex(somechar,function(t,k)
449    if k then
450        local b = lpegmatch(utf8byte,k)
451        local v = b and chardata[b] or false
452        t[k] = v
453        return v
454    end
455end)
456
457local function utfmathclass(chr, default)
458    local cd = somechar[chr]
459    return cd and cd.mathclass or default or "unknown"
460end
461
462local function utfmathlimop(chr)
463    local cd = somechar[chr]
464    return cd and cd.mathclass == "limop" or false
465end
466
467local function utfmathaccent(chr,default,asked1,asked2)
468    local cd = somechar[chr]
469    if not cd then
470        return default or false
471    end
472    if asked1 and asked1 ~= "" then
473        local mc = cd.mathclass
474        if mc and (mc == asked1 or mc == asked2) then
475            return true
476        end
477        local ms = cd.mathspec
478        if not ms then
479            local mp = cd.mathparent
480            if mp then
481                ms = chardata[mp].mathspec
482            end
483        end
484        if ms then
485            for i=1,#ms do
486                local msi = ms[i]
487                local mc = msi.class
488                if mc and (mc == asked1 or mc == asked2) then
489                    return true
490                end
491            end
492        end
493    else
494        local mc = cd.mathclass
495        if mc then
496            return accents[mc] or default or false
497        end
498        local ms = cd.mathspec
499        if ms then
500            for i=1,#ms do
501                local msi = ms[i]
502                local mc = msi.class
503                if mc then
504                    return accents[mc] or default or false
505                end
506            end
507        end
508    end
509    return default or false
510end
511
512local function utfmathstretch(chr,default) -- "h", "v", "b", ""
513    local cd = somechar[chr]
514    return cd and cd.mathstretch or default or ""
515end
516
517local function utfmathcommand(chr,default,asked1,asked2)
518    local cd = somechar[chr]
519    if not cd then
520        return default or ""
521    end
522    if asked1 then
523        local mn = cd.mathname
524        local mc = cd.mathclass
525        if mn and mc and (mc == asked1 or mc == asked2) then
526            return mn
527        end
528        local ms = cd.mathspec
529        if not ms then
530            local mp = cd.mathparent
531            if mp then
532                ms = chardata[mp].mathspec
533            end
534        end
535        if ms then
536            for i=1,#ms do
537                local msi = ms[i]
538                local mn = msi.name
539                if mn then
540                    local mc = msi.class
541                    if mc == asked1 or mc == asked2 then
542                        return mn
543                    end
544                end
545            end
546        end
547    else
548        local mn = cd.mathname
549        if mn then
550            return mn
551        end
552        local ms = cd.mathspec
553        if ms then
554            for i=1,#ms do
555                local msi = ms[i]
556                local mn = msi.name
557                if mn then
558                    return mn
559                end
560            end
561        end
562    end
563    return default or ""
564end
565
566local function utfmathfiller(chr, default)
567    local cd = somechar[chr]
568    local cmd = cd and cd.mathfiller -- or cd.mathname
569    return cmd or default or ""
570end
571
572mathematics.utfmathclass   = utfmathclass
573mathematics.utfmathstretch = utfmathstretch
574mathematics.utfmathcommand = utfmathcommand
575mathematics.utfmathfiller  = utfmathfiller
576mathematics.utfmathaccent  = utfmathaccent
577
578-- interfaced
579
580implement {
581    name      = "utfmathclass",
582    actions   = { utfmathclass, context },
583    arguments = "string"
584}
585
586implement {
587    name      = "utfmathstretch",
588    actions   = { utfmathstretch, context },
589    arguments = "string"
590}
591
592implement {
593    name      = "utfmathcommand",
594    actions   = { utfmathcommand, context },
595    arguments = "string"
596}
597
598implement {
599    name      = "utfmathfiller",
600    actions   = { utfmathfiller, context },
601    arguments = "string"
602}
603
604implement {
605    name      = "utfmathcommandabove",
606    actions   = { utfmathcommand, context },
607    arguments = { "string", false, "'topaccent'","'over'" }
608}
609
610implement {
611    name      = "utfmathcommandbelow",
612    actions   = { utfmathcommand, context },
613    arguments = { "string", false, "'botaccent'","'under'" }
614}
615
616implement {
617    name      = "utfmathcommandfiller",
618    actions   = { utfmathfiller, context },
619    arguments = "string"
620}
621
622-- todo: make this a helper:
623
624implement {
625    name      = "doifelseutfmathabove",
626    actions   = { utfmathaccent, ctx_doifelsesomething },
627    arguments = { "string", false, "'topaccent'", "'over'" }
628}
629
630implement {
631    name      = "doifelseutfmathbelow",
632    actions   = { utfmathaccent, ctx_doifelsesomething },
633    arguments = { "string", false, "'botaccent'", "'under'" }
634}
635
636implement {
637    name      = "doifelseutfmathaccent",
638    actions   = { utfmathaccent, ctx_doifelsesomething },
639    arguments = "string",
640}
641
642implement {
643    name      = "doifelseutfmathfiller",
644    actions   = { utfmathfiller, ctx_doifelsesomething },
645    arguments = "string",
646}
647
648implement {
649    name      = "doifelseutfmathlimop",
650    actions   = { utfmathlimop, ctx_doifelsesomething },
651    arguments = "string",
652}
653
654-- helpers
655--
656-- 1: step 1
657-- 2: step 2
658-- 3: htdp * 1.33^n
659-- 4: size * 1.33^n
660
661function mathematics.big(tfmdata,unicode,n,method)
662    local t = tfmdata.characters
663    local c = t[unicode]
664    if c and n > 0 then
665        local vv = c.vert_variants or c.next and t[c.next].vert_variants
666        if vv then
667            local vvn = vv[n]
668            return vvn and vvn.glyph or vv[#vv].glyph or unicode
669        elseif method == 1 or method == 2 then
670            if method == 2 then -- large steps
671                n = n * 2
672            end
673            local next = c.next
674            while next do
675                if n <= 1 then
676                    return next
677                else
678                    n = n - 1
679                    local tn = t[next].next
680                    if tn then
681                        next = tn
682                    else
683                        return next
684                    end
685                end
686            end
687        elseif method >= 3 then
688            local size = 1.33^n
689            if method == 4 then
690                size = tfmdata.parameters.size * size
691            else -- if method == 3 then
692                size = (c.height + c.depth) * size
693            end
694            local next = c.next
695            while next do
696                local cn = t[next]
697                if (cn.height + cn.depth) >= size then
698                    return next
699                else
700                    local tn = cn.next
701                    if tn then
702                        next = tn
703                    else
704                        return next
705                    end
706                end
707            end
708        end
709    end
710    return unicode
711end
712
713-- experimental
714
715-- local categories = { } -- indexed + hashed
716--
717-- local a_mathcategory = attributes.private("mathcategory")
718--
719-- local function registercategory(category,tag,data) -- always same data for tag
720--     local c = categories[category]
721--     if not c then
722--         c = { }
723--         categories[category] = c
724--     end
725--     local n = c[tag]
726--     if not n then
727--         n = #c + 1
728--         c[n] = data
729--         n = n * 1000 + category
730--         c[tag] = n
731--     end
732--     return n
733-- end
734--
735-- function mathematics.getcategory(n)
736--     local category = n % 1000
737--     return category, categories[category][floor(n/1000)]
738-- end
739--
740-- mathematics.registercategory = registercategory
741--
742-- function commands.taggedmathfunction(tag,label)
743--     if label then
744--         texsetattribute(a_mathcategory,registercategory(1,tag,tag))
745--         context.mathlabeltext(tag)
746--     else
747--         texsetattribute(a_mathcategory,1)
748--         context(tag)
749--     end
750-- end
751
752local categories       = { }
753mathematics.categories = categories
754
755local a_mathcategory = attributes.private("mathcategory")
756
757local functions    = storage.allocate()
758local noffunctions = 1000 -- offset
759
760categories.functions = functions
761
762implement {
763    name      = "tagmfunctiontxt",
764    arguments = { "string", "conditional" },
765    actions   = function(tag,apply)
766        local delta = apply and 1000 or 0
767        texsetattribute(a_mathcategory,1000 + delta)
768    end
769}
770
771implement {
772    name      = "tagmfunctionlab",
773    arguments = { "string", "conditional" },
774    actions   = function(tag,apply)
775        local delta = apply and 1000 or 0
776        local n = functions[tag]
777        if not n then
778            noffunctions = noffunctions + 1
779            functions[noffunctions] = tag
780            functions[tag] = noffunctions
781            texsetattribute(a_mathcategory,noffunctions + delta)
782        else
783            texsetattribute(a_mathcategory,n + delta)
784        end
785    end
786}
787
788--
789
790local list
791
792function mathematics.resetattributes()
793    if not list then
794        list = { }
795        for k, v in next, attributes.numbers do
796            if find(k,"^math") then
797                list[#list+1] = v
798            end
799        end
800    end
801    for i=1,#list do
802        texsetattribute(list[i],unsetvalue)
803    end
804end
805
806implement {
807    name    = "resetmathattributes",
808    actions = mathematics.resetattributes
809}
810
811-- weird to do this here but it's a side affect of math anyway
812
813interfaces.implement {
814    name     = "enableasciimode",
815    onlyonce = true,
816    actions  = resolvers.macros.enablecomment,
817}
818