1if not modules then modules = { } end modules ['x-mathml'] = {
2 version = 1.001,
3 comment = "companion to x-mathml.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
10
11
12local type, next = type, next
13local formatters, lower, find, gsub, match = string.formatters, string.lower, string.find, string.gsub, string.match
14local strip = string.strip
15local xmlsprint, xmlcprint, xmltext, xmlcontent, xmlempty = xml.sprint, xml.cprint, xml.text, xml.content, xml.empty
16local lxmlcollected, lxmlfilter = lxml.collected, lxml.filter
17local getid = lxml.getid
18local utfchar, utfcharacters, utfsplit, utflen = utf.char, utf.characters, utf.split, utf.len
19local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns
20local P, Cs = lpeg.P, lpeg.Cs
21
22local mathml = { }
23moduledata.mathml = mathml
24lxml.mathml = mathml
25
26local context = context
27
28local ctx_enabledelimiter = context.enabledelimiter
29local ctx_disabledelimiter = context.disabledelimiter
30local ctx_xmlflush = context.xmlflush
31
32local ctx_halign = context.halign
33local ctx_noalign = context.noalign
34local ctx_bgroup = context.bgroup
35local ctx_egroup = context.egroup
36local ctx_crcr = context.crcr
37
38local ctx_bTABLE = context.bTABLE
39local ctx_eTABLE = context.eTABLE
40local ctx_bTR = context.bTR
41local ctx_eTR = context.eTR
42local ctx_bTD = context.bTD
43local ctx_eTD = context.eTD
44
45local ctx_mn = context.mn
46local ctx_mi = context.mi
47local ctx_mo = context.mo
48local ctx_startimath = context.startimath
49local ctx_ignorespaces = context.ignorespaces
50local ctx_removeunwantedspaces = context.removeunwantedspaces
51local ctx_stopimath = context.stopimath
52
53local ctx_mmlapplycsymbol = context.mmlapplycsymbol
54
55local ctx_mathopnolimits = context.mathopnolimits
56local ctx_left = context.left
57local ctx_right = context.right
58
59
60
61
62
63
64
65
66
67local doublebar = utfchar(0x2016)
68
69local n_replacements = {
70
71 ["."] = "{.}",
72 [","] = "{,}",
73 [" "] = "",
74}
75
76local l_replacements = {
77 ["|"] = "\\mmlleftdelimiter\\vert",
78 ["{"] = "\\mmlleftdelimiter\\lbrace",
79 ["("] = "\\mmlleftdelimiter(",
80 ["["] = "\\mmlleftdelimiter[",
81 ["<"] = "\\mmlleftdelimiter<",
82 [doublebar] = "\\mmlleftdelimiter\\Vert",
83}
84local r_replacements = {
85 ["|"] = "\\mmlrightdelimiter\\vert",
86 ["}"] = "\\mmlrightdelimiter\\rbrace",
87 [")"] = "\\mmlrightdelimiter)",
88 ["]"] = "\\mmlrightdelimiter]",
89 [">"] = "\\mmlrightdelimiter>",
90 [doublebar] = "\\mmlrightdelimiter\\Vert",
91}
92
93
94
95
96
97local o_replacements = {
98 ["@l"] = "\\mmlleftdelimiter.",
99 ["@r"] = "\\mmlrightdelimiter.",
100 ["{"] = "\\mmlleftdelimiter \\lbrace",
101 ["}"] = "\\mmlrightdelimiter\\rbrace",
102 ["|"] = "\\mmlleftorrightdelimiter\\vert",
103
104 ["/"] = "\\mmlleftorrightdelimiter\\solidus",
105 [doublebar] = "\\mmlleftorrightdelimiter\\Vert",
106 ["("] = "\\mmlleftdelimiter(",
107 [")"] = "\\mmlrightdelimiter)",
108 ["["] = "\\mmlleftdelimiter[",
109 ["]"] = "\\mmlrightdelimiter]",
110
111
112 ["#"] = "\\mmlchar{35}",
113 ["$"] = "\\mmlchar{36}",
114 ["%"] = "\\mmlchar{37}",
115 ["&"] = "\\mmlchar{38}",
116 ["^"] = "\\mmlchar{94}{}",
117 ["_"] = "\\mmlchar{95}{}",
118 ["~"] = "\\mmlchar{126}",
119 [" "] = "",
120 ["°"] = "^\\circ",
121
122
123 [utfchar(0xF1026)] = "\\mmlchar{38}",
124 [utfchar(0x02061)] = "",
125
126
127}
128
129local simpleoperatorremapper = utf.remapper(o_replacements)
130
131
132
133local i_replacements = {
134 ["sin"] = "\\sin",
135 ["cos"] = "\\cos",
136 ["abs"] = "\\abs",
137 ["arg"] = "\\arg",
138 ["codomain"] = "\\codomain",
139 ["curl"] = "\\curl",
140 ["determinant"] = "\\det",
141 ["divergence"] = "\\div",
142 ["domain"] = "\\domain",
143 ["gcd"] = "\\gcd",
144 ["grad"] = "\\grad",
145 ["identity"] = "\\id",
146 ["image"] = "\\image",
147 ["lcm"] = "\\lcm",
148 ["lim"] = "\\lim",
149 ["max"] = "\\max",
150 ["median"] = "\\median",
151 ["min"] = "\\min",
152 ["mode"] = "\\mode",
153 ["mod"] = "\\mod",
154 ["polar"] = "\\Polar",
155 ["exp"] = "\\exp",
156 ["ln"] = "\\ln",
157 ["log"] = "\\log",
158 ["sin"] = "\\sin",
159 ["arcsin"] = "\\arcsin",
160 ["sinh"] = "\\sinh",
161 ["arcsinh"] = "\\arcsinh",
162 ["cos"] = "\\cos",
163 ["arccos"] = "\\arccos",
164 ["cosh"] = "\\cosh",
165 ["arccosh"] = "\\arccosh",
166 ["tan"] = "\\tan",
167 ["arctan"] = "\\arctan",
168 ["tanh"] = "\\tanh",
169 ["arctanh"] = "\\arctanh",
170 ["cot"] = "\\cot",
171 ["arccot"] = "\\arccot",
172 ["coth"] = "\\coth",
173 ["arccoth"] = "\\arccoth",
174 ["csc"] = "\\csc",
175 ["arccsc"] = "\\arccsc",
176 ["csch"] = "\\csch",
177 ["arccsch"] = "\\arccsch",
178 ["sec"] = "\\sec",
179 ["arcsec"] = "\\arcsec",
180 ["sech"] = "\\sech",
181 ["arcsech"] = "\\arcsech",
182 [" "] = "",
183
184 ["false"] = "{\\mathrm false}",
185 ["notanumber"] = "{\\mathrm NaN}",
186 ["otherwise"] = "{\\mathrm otherwise}",
187 ["true"] = "{\\mathrm true}",
188 ["declare"] = "{\\mathrm declare}",
189 ["as"] = "{\\mathrm as}",
190
191}
192
193
194
195
196local csymbols = {
197 arith1 = {
198 lcm = "lcm",
199 big_lcm = "lcm",
200 gcd = "gcd",
201 big_gcd = "big_gcd",
202 plus = "plus",
203 unary_minus = "minus",
204 minus = "minus",
205 times = "times",
206 divide = "divide",
207 power = "power",
208 abs = "abs",
209 root = "root",
210 sum = "sum",
211 product = "product",
212 },
213 fns = {
214 domain = "domain",
215 range = "codomain",
216 image = "image",
217 identity = "ident",
218
219
220 inverse = "inverse",
221 left_compose = "compose",
222 lambda = "labmda",
223 },
224 linalg1 = {
225 vectorproduct = "vectorproduct",
226 scalarproduct = "scalarproduct",
227 outerproduct = "outerproduct",
228 transpose = "transpose",
229 determinant = "determinant",
230 vector_selector = "selector",
231
232 },
233 logic1 = {
234 equivalent = "equivalent",
235 ["not"] = "not",
236 ["and"] = "and",
237
238 ["xor"] = "xor",
239
240 ["or"] = "or",
241
242 implies = "implies",
243 ["true"] = "true",
244 ["false"] = "false",
245 },
246 nums1 = {
247
248 rational = "rational",
249 inifinity = "infinity",
250 e = "expenonentiale",
251 i = "imaginaryi",
252 pi = "pi",
253 gamma = "gamma",
254 NaN = "NaN",
255 },
256 relation1 = {
257 eq = "eq",
258 lt = "lt",
259 gt = "gt",
260 neq = "neq",
261 leq = "leq",
262 geq = "geq",
263 approx = "approx",
264 },
265 set1 = {
266 cartesian_product = "cartesianproduct",
267 empty_set = "emptyset",
268 map = "map",
269 size = "card",
270
271 set = "set",
272 intersect = "intersect",
273
274 union = "union",
275
276 setdiff = "setdiff",
277 subset = "subset",
278 ["in"] = "in",
279 notin = "notin",
280 prsubset = "prsubset",
281 notsubset = "notsubset",
282 notprsubset = "notprsubset",
283 },
284 veccalc1 = {
285 divergence = "divergence",
286 grad = "grad",
287 curl = "curl",
288 laplacian = "laplacian",
289 Laplacian = "laplacian",
290 },
291 calculus1 = {
292 diff = "diff",
293
294 partialdiff = "partialdiff",
295 int = "int",
296
297 },
298 integer1 = {
299 factorof = "factorof",
300 factorial = "factorial",
301 quotient = "quotient",
302 remainder = "rem",
303 },
304 linalg2 = {
305 vector = "vector",
306 matrix = "matrix",
307 matrixrow = "matrixrow",
308 },
309 mathmkeys = {
310
311
312
313 },
314 rounding1 = {
315 ceiling = "ceiling",
316 floor = "floor",
317
318
319 },
320 setname1 = {
321 P = "primes",
322 N = "naturalnumbers",
323 Z = "integers",
324 rationals = "rationals",
325 R = "reals",
326 complexes = "complexes",
327 },
328 complex1 = {
329
330 real = "real",
331 imaginary = "imaginary",
332
333 argument = "arg",
334 conjugate = "conjugate",
335 },
336 interval1 = {
337
338 interval = "interval",
339 interval_oo = { tag = "interval", closure = "open" },
340 interval_cc = { tag = "interval", closure = "closed" },
341 interval_oc = { tag = "interval", closure = "open-closed" },
342 interval_co = { tag = "interval", closure = "closed-open" },
343 },
344 linalg3 = {
345
346
347
348 },
349 minmax1 = {
350 min = "min",
351
352 max = "max",
353
354 },
355 piece1 = {
356 piecewise = "piecewise",
357 piece = "piece",
358 otherwise = "otherwise",
359 },
360 error1 = {
361
362
363
364 },
365 limit1 = {
366
367
368
369
370
371 tendsto = "tendsto",
372 },
373 list1 = {
374
375
376
377 },
378 multiset1 = {
379 size = { tag = "card", type = "multiset" },
380 cartesian_product = { tag = "cartesianproduct", type = "multiset" },
381 empty_set = { tag = "emptyset", type = "multiset" },
382
383 intersect = { tag = "intersect", type = "multiset" },
384
385 union = { tag = "union", type = "multiset" },
386
387 setdiff = { tag = "setdiff", type = "multiset" },
388 subset = { tag = "subset", type = "multiset" },
389 ["in"] = { tag = "in", type = "multiset" },
390 notin = { tag = "notin", type = "multiset" },
391 prsubset = { tag = "prsubset", type = "multiset" },
392 notsubset = { tag = "notsubset", type = "multiset" },
393 notprsubset = { tag = "notprsubset", type = "multiset" },
394 },
395 quant1 = {
396 forall = "forall",
397 exists = "exists",
398 },
399 s_dist = {
400
401
402
403
404 },
405 s_data = {
406 mean = "mean",
407 sdev = "sdev",
408 variance = "vriance",
409 mode = "mode",
410 median = "median",
411 moment = "moment",
412 },
413 transc1 = {
414 log = "log",
415 ln = "ln",
416 exp = "exp",
417 sin = "sin",
418 cos = "cos",
419 tan = "tan",
420 sec = "sec",
421 csc = "csc",
422 cot = "cot",
423 sinh = "sinh",
424 cosh = "cosh",
425 tanh = "tanh",
426 sech = "sech",
427 csch = "cscs",
428 coth = "coth",
429 arcsin = "arcsin",
430 arccos = "arccos",
431 arctan = "arctan",
432 arcsec = "arcsec",
433 arcscs = "arccsc",
434 arccot = "arccot",
435 arcsinh = "arcsinh",
436 arccosh = "arccosh",
437 arctanh = "arstanh",
438 arcsech = "arcsech",
439 arccsch = "arccsch",
440 arccoth = "arccoth",
441 },
442}
443
444function xml.functions.remapmmlcsymbol(e)
445 local at = e.at
446 local cd = at.cd
447 if cd then
448 cd = csymbols[cd]
449 if cd then
450 local tx = e.dt[1]
451 if tx and tx ~= "" then
452 local tg = cd[tx]
453 if tg then
454 at.cd = nil
455 at.cdbase = nil
456 e.dt = { }
457 if type(tg) == "table" then
458 for k, v in next, tg do
459 if k == "tag" then
460 e.tg = v
461 else
462 at[k] = v
463 end
464 end
465 else
466 e.tg = tg
467 end
468 end
469 end
470 end
471 end
472end
473
474function xml.functions.remapmmlbind(e)
475 e.tg = "apply"
476end
477
478function xml.functions.remapopenmath(e)
479 local tg = e.tg
480 if tg == "OMOBJ" then
481 e.tg = "math"
482 elseif tg == "OMA" then
483 e.tg = "apply"
484 elseif tg == "OMB" then
485 e.tg = "apply"
486 elseif tg == "OMS" then
487 local at = e.at
488 e.tg = "csymbol"
489 e.dt = { at.name or "unknown" }
490 at.name = nil
491 elseif tg == "OMV" then
492 local at = e.at
493 e.tg = "ci"
494 e.dt = { at.name or "unknown" }
495 at.name = nil
496 elseif tg == "OMI" then
497 e.tg = "ci"
498 end
499 e.rn = "mml"
500end
501
502function mathml.checked_operator(str)
503 context(simpleoperatorremapper(str))
504end
505
506function mathml.stripped(str)
507 context(strip(str))
508end
509
510local p_entity = (P("&") * ((1-P(";"))^0) * P(";"))
511local p_utfchar = lpegpatterns.utf8character
512local p_spacing = lpegpatterns.whitespace^1
513
514local p_mn = Cs((p_entity/"" + p_spacing/utfchar(0x205F) + p_utfchar/n_replacements)^0)
515local p_strip = Cs((p_entity/"" + p_utfchar )^0)
516local p_mi = Cs((p_entity/"" + p_utfchar/i_replacements)^0)
517
518function mathml.mn(id)
519
520
521 ctx_mn(lpegmatch(p_mn,xmlcontent(getid(id)) or ""))
522end
523
524function mathml.mo(id)
525 local str = lpegmatch(p_strip,xmlcontent(getid(id)) or "")
526 context(simpleoperatorremapper(str) or str)
527end
528
529function mathml.mi(id)
530
531 local e = getid(id)
532 local str = e.dt
533 if type(str) == "table" then
534 local n = #str
535 if n == 0 then
536
537 elseif n == 1 then
538 local first = str[1]
539 if type(first) == "string" then
540
541
542
543
544
545 local str = lpegmatch(p_strip,first)
546 local rep = i_replacements[str] or lpegmatch(p_mi,str)
547 context(rep)
548
549 else
550 ctx_xmlflush(id)
551 end
552 else
553 ctx_xmlflush(id)
554 end
555 else
556 ctx_xmlflush(id)
557 end
558end
559
560function mathml.mfenced(id)
561 id = getid(id)
562 local at = id.at
563 local left = at.open or "("
564 local right = at.close or ")"
565 local separators = at.separators or ","
566 local l = l_replacements[left]
567 local r = r_replacements[right]
568 ctx_enabledelimiter()
569 if l then
570 context(l_replacements[left] or o_replacements[left] or "")
571 else
572 context(o_replacements["@l"])
573 context(left)
574 end
575 ctx_disabledelimiter()
576 local collected = lxmlfilter(id,"/*")
577 if collected then
578 local n = #collected
579 if n == 0 then
580
581 elseif n == 1 then
582 xmlsprint(collected[1])
583 else
584 local t = utfsplit(separators,true)
585 for i=1,n do
586 xmlsprint(collected[i])
587 if i < n then
588 local m = t[i] or t[#t] or ""
589 if m == "|" then
590 m = "\\enabledelimiter\\middle|\\relax\\disabledelimiter"
591 elseif m == doublebar then
592 m = "\\enabledelimiter\\middle|\\relax\\disabledelimiter"
593 elseif m == "{" then
594 m = "\\{"
595 elseif m == "}" then
596 m = "\\}"
597 end
598 context(m)
599 end
600 end
601 end
602 end
603 ctx_enabledelimiter()
604 if r then
605 context(r_replacements[right] or o_replacements[right] or "")
606 else
607 context(right)
608 context(o_replacements["@r"])
609 end
610 ctx_disabledelimiter()
611end
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655function mathml.mmultiscripts(id)
656 local prescripts = false
657 local subscripts = true
658 local firstdone = false
659 for e in lxmlcollected(id,"/*") do
660 if firstdone then
661 xmlsprint(e.dt)
662 firstdone = true
663 else
664 local tag = e.tg
665 if tag == "none" then
666 subscripts = not subscripts
667 elseif tag == "prescripts" then
668 prescripts = true
669 subscripts = true
670 elseif subscripts then
671 if prescripts then
672 context("\\subprescript{")
673 xmlsprint(e.dt)
674 context("}")
675 end
676 subscripts = false
677 else
678 if prescripts then
679 context("\\superprescript{")
680 xmlsprint(e.dt)
681 context("}")
682 end
683 subscripts = true
684 end
685 end
686 end
687 local prescripts = false
688 local subscripts = true
689 local firstdone = false
690 for e in lxmlcollected(id,"/*") do
691 if firstdone then
692 firstdone = true
693 else
694 local tag = e.tg
695 if tag == "none" then
696 subscripts = not subscripts
697 elseif tag == "prescripts" then
698 prescripts = true
699 subscripts = true
700 elseif subscripts then
701 if not prescripts then
702 context("\\subscript{")
703 xmlsprint(e.dt)
704 context("}")
705 end
706 subscripts = false
707 else
708 if not prescripts then
709 context("\\superscript{")
710 xmlsprint(e.dt)
711 context("}")
712 end
713 subscripts = true
714 end
715 end
716 end
717end
718
719local columnalignments = {
720 left = "flushleft",
721 right = "flushright",
722 center = "middle",
723}
724
725local rowalignments = {
726 top = "high",
727 bottom = "low",
728 center = "lohi",
729 baseline = "top",
730 axis = "lohi",
731}
732
733local frametypes = {
734 none = "off",
735 solid = "on",
736 dashed = "on",
737}
738
739
740
741function mathml.mcolumn(root)
742 root = getid(root)
743 local matrix, numbers = { }, 0
744 local function collect(m,e)
745 local tag = e.tg
746 if tag == "mi" or tag == "mn" or tag == "mo" or tag == "mtext" then
747 local str = xmltext(e)
748 str = lpegmatch(p_strip,str)
749 for s in utfcharacters(str) do
750 m[#m+1] = { tag, s }
751 end
752 if tag == "mn" then
753 local n = utflen(str)
754 if n > numbers then
755 numbers = n
756 end
757 end
758 elseif tag == "mspace" or tag == "mline" then
759 local str = e.at.spacing or ""
760 for s in utfcharacters(str) do
761 m[#m+1] = { tag, s }
762 end
763
764
765 end
766 end
767 for e in lxmlcollected(root,"/*") do
768 local m = { }
769 matrix[#matrix+1] = m
770 if e.tg == "mrow" then
771
772 for e in lxmlcollected(e,"/*") do
773 collect(m,e)
774 end
775 else
776 collect(m,e)
777 end
778 end
779 ctx_halign()
780 ctx_bgroup()
781 context([[\hss\startimath\alignmark\stopimath\aligntab\startimath\alignmark\stopimath\cr]])
782 for i=1,#matrix do
783 local m = matrix[i]
784 local mline = true
785 for j=1,#m do
786 if m[j][1] ~= "mline" then
787 mline = false
788 break
789 end
790 end
791 if mline then
792 ctx_noalign([[\obeydepth\nointerlineskip]])
793 end
794 for j=1,#m do
795 local mm = m[j]
796 local tag, chr = mm[1], mm[2]
797 if tag == "mline" then
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825 chr = "\\hrulefill"
826 elseif tag == "mspace" then
827 chr = "\\mmlmcolumndigitspace"
828 end
829 if j == numbers + 1 then
830 context("\\aligntab")
831 end
832 local nchr = n_replacements[chr]
833 context(nchr or chr)
834 end
835 ctx_crcr()
836 end
837 ctx_egroup()
838end
839
840local spacesplitter = lpeg.tsplitat(" ")
841
842function mathml.mtable(root)
843
844 root = getid(root)
845 local at = root.at
846 local rowalign = at.rowalign
847 local columnalign = at.columnalign
848 local frame = at.frame
849 local rowaligns = rowalign and lpegmatch(spacesplitter,rowalign)
850 local columnaligns = columnalign and lpegmatch(spacesplitter,columnalign)
851 local frames = frame and lpegmatch(spacesplitter,frame)
852 local framespacing = at.framespacing or "0pt"
853 local framespacing = at.framespacing or "-\\ruledlinewidth"
854
855 ctx_bTABLE { frame = frametypes[frame or "none"] or "off", offset = framespacing, background = "" }
856 for e in lxmlcollected(root,"/(mml:mtr|mml:mlabeledtr)") do
857 ctx_bTR()
858 local at = e.at
859 local col = 0
860 local rfr = at.frame or (frames and frames [#frames])
861 local rra = at.rowalign or (rowaligns and rowaligns [#rowaligns])
862 local rca = at.columnalign or (columnaligns and columnaligns[#columnaligns])
863 local ignorelabel = e.tg == "mlabeledtr"
864 for e in lxmlcollected(e,"/mml:mtd") do
865 col = col + 1
866 if ignorelabel and col == 1 then
867
868 else
869 local at = e.at
870 local rowspan = at.rowspan or 1
871 local columnspan = at.columnspan or 1
872 local cra = rowalignments [at.rowalign or (rowaligns and rowaligns [col]) or rra or "center"] or "lohi"
873 local cca = columnalignments[at.columnalign or (columnaligns and columnaligns[col]) or rca or "center"] or "middle"
874 local cfr = frametypes [at.frame or (frames and frames [col]) or rfr or "none" ] or "off"
875 ctx_bTD { align = formatters["{%s,%s}"](cra,cca), frame = cfr, nx = columnspan, ny = rowspan }
876 if xmlempty(e,".") then
877
878 else
879 ctx_startimath()
880
881 xmlcprint(e)
882
883 ctx_stopimath()
884 end
885 ctx_eTD()
886 end
887 end
888
889
890
891
892
893 ctx_eTR()
894 end
895 ctx_eTABLE()
896end
897
898function mathml.csymbol(root)
899 root = getid(root)
900 local at = root.at
901 local encoding = at.encoding or ""
902 local hash = url.hashed(lower(at.definitionUrl or ""))
903 local full = hash.original or ""
904 local base = hash.path or ""
905 local text = strip(xmltext(root) or "")
906 ctx_mmlapplycsymbol(full,base,encoding,text)
907end
908
909local p = lpeg.Cs(((1-lpegpatterns.whitespace)^1 / "mml:enclose:%0" + (lpegpatterns.whitespace^1)/",")^1)
910
911function mathml.menclosepattern(root)
912 root = getid(root)
913 local a = root.at.notation
914 if a and a ~= "" then
915 context(lpegmatch(p,a))
916 end
917end
918
919function xml.is_element(e,name)
920 return type(e) == "table" and (not name or e.tg == name)
921end
922
923function mathml.cpolar(root)
924 root = getid(root)
925 local dt = root.dt
926 ctx_mathopnolimits("Polar")
927 ctx_left(false,"(")
928 for k=1,#dt do
929 local dk = dt[k]
930 if xml.is_element(dk,"sep") then
931 context(",")
932 else
933 xmlsprint(dk)
934 end
935 end
936 ctx_right(false,")")
937end
938
939
940
941local mathmleq = {
942 [utfchar(0x00AF)] = utfchar(0x203E),
943}
944
945function mathml.extensible(chr)
946 context(mathmleq[chr] or chr)
947end
948
949
950
951local function install(name,action)
952 interfaces.implement {
953 name = name,
954 public = true,
955
956 arguments = "argument",
957 actions = action,
958 }
959end
960
961install("mathml_mi", mathml.mi)
962install("mathml_mo", mathml.mo)
963install("mathml_mn", mathml.mn)
964install("mathml_mfenced", mathml.mfenced)
965install("mathml_mmultiscripts", mathml.mmultiscripts)
966install("mathml_menclosepattern", mathml.menclosepattern)
967install("mathml_mtable", mathml.mtable)
968install("mathml_mcolumn", mathml.mcolumn)
969install("mathml_extensible", mathml.extensible)
970
971install("mathml_csymbol", mathml.csymbol)
972install("mathml_cpolar", mathml.cpolar)
973 |