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