diff options
Diffstat (limited to 'tex/context/base/x-mathml.lua')
-rw-r--r-- | tex/context/base/x-mathml.lua | 1658 |
1 files changed, 829 insertions, 829 deletions
diff --git a/tex/context/base/x-mathml.lua b/tex/context/base/x-mathml.lua index 31483bbea..676b9a7c6 100644 --- a/tex/context/base/x-mathml.lua +++ b/tex/context/base/x-mathml.lua @@ -1,829 +1,829 @@ -if not modules then modules = { } end modules ['x-mathml'] = { - version = 1.001, - comment = "companion to x-mathml.mkiv", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - --- This needs an upgrade to the latest greatest mechanisms. - -local type, next = type, next -local format, lower, find, gsub = string.format, string.lower, string.find, string.gsub -local strip = string.strip -local xmlsprint, xmlcprint, xmltext, xmlcontent = xml.sprint, xml.cprint, xml.text, xml.content -local getid = lxml.getid -local utfchar, utfcharacters, utfvalues = utf.char, utf.characters, utf.values -local lpegmatch = lpeg.match - -local mathml = { } -moduledata.mathml = mathml -lxml.mathml = mathml -- for the moment - --- an alternative is to remap to private codes, where we can have --- different properties .. to be done; this will move and become --- generic; we can then make the private ones active in math mode - --- todo: handle opening/closing mo's here ... presentation mml is such a mess ... - -characters.registerentities() - -local doublebar = utfchar(0x2016) - -local n_replacements = { --- [" "] = utfchar(0x2002), -- "&textspace;" -> tricky, no &; in mkiv - ["."] = "{.}", - [","] = "{,}", - [" "] = "", -} - -local l_replacements = { -- in main table - ["|"] = "\\mmlleftdelimiter\\vert", - ["{"] = "\\mmlleftdelimiter\\lbrace", - ["("] = "\\mmlleftdelimiter(", - ["["] = "\\mmlleftdelimiter[", - ["<"] = "\\mmlleftdelimiter<", - [doublebar] = "\\mmlleftdelimiter\\Vert", -} -local r_replacements = { -- in main table - ["|"] = "\\mmlrightdelimiter\\vert", - ["}"] = "\\mmlrightdelimiter\\rbrace", - [")"] = "\\mmlrightdelimiter)", - ["]"] = "\\mmlrightdelimiter]", - [">"] = "\\mmlrightdelimiter>", - [doublebar] = "\\mmlrightdelimiter\\Vert", -} - --- todo: play with asciimode and avoid mmlchar - -local o_replacements = { -- in main table - ["@l"] = "\\mmlleftdelimiter.", - ["@r"] = "\\mmlrightdelimiter.", - ["{"] = "\\mmlleftdelimiter \\lbrace", - ["}"] = "\\mmlrightdelimiter\\rbrace", - ["|"] = "\\mmlleftorrightdelimiter\\vert", - [doublebar] = "\\mmlleftorrightdelimiter\\Vert", - ["("] = "\\mmlleftdelimiter(", - [")"] = "\\mmlrightdelimiter)", - ["["] = "\\mmlleftdelimiter[", - ["]"] = "\\mmlrightdelimiter]", - -- ["<"] = "\\mmlleftdelimiter<", - -- [">"] = "\\mmlrightdelimiter>", - ["#"] = "\\mmlchar{35}", - ["$"] = "\\mmlchar{36}", -- $ - ["%"] = "\\mmlchar{37}", - ["&"] = "\\mmlchar{38}", - ["^"] = "\\mmlchar{94}{}", -- strange, sometimes luatex math sees the char instead of \char - ["_"] = "\\mmlchar{95}{}", -- so we need the {} - ["~"] = "\\mmlchar{126}", - [" "] = "", - ["°"] = "^\\circ", -- hack - - -- [utfchar(0xF103C)] = "\\mmlleftdelimiter<", - [utfchar(0xF1026)] = "\\mmlchar{38}", - -- [utfchar(0xF103E)] = "\\mmlleftdelimiter>", - -} - -local simpleoperatorremapper = utf.remapper(o_replacements) - ---~ languages.data.labels.functions - -local i_replacements = { - ["sin"] = "\\mathopnolimits{sin}", - ["cos"] = "\\mathopnolimits{cos}", - ["abs"] = "\\mathopnolimits{abs}", - ["arg"] = "\\mathopnolimits{arg}", - ["codomain"] = "\\mathopnolimits{codomain}", - ["curl"] = "\\mathopnolimits{curl}", - ["determinant"] = "\\mathopnolimits{det}", - ["divergence"] = "\\mathopnolimits{div}", - ["domain"] = "\\mathopnolimits{domain}", - ["gcd"] = "\\mathopnolimits{gcd}", - ["grad"] = "\\mathopnolimits{grad}", - ["identity"] = "\\mathopnolimits{id}", - ["image"] = "\\mathopnolimits{image}", - ["lcm"] = "\\mathopnolimits{lcm}", - ["lim"] = "\\mathopnolimits{lim}", - ["max"] = "\\mathopnolimits{max}", - ["median"] = "\\mathopnolimits{median}", - ["min"] = "\\mathopnolimits{min}", - ["mode"] = "\\mathopnolimits{mode}", - ["mod"] = "\\mathopnolimits{mod}", - ["polar"] = "\\mathopnolimits{Polar}", - ["exp"] = "\\mathopnolimits{exp}", - ["ln"] = "\\mathopnolimits{ln}", - ["log"] = "\\mathopnolimits{log}", - ["sin"] = "\\mathopnolimits{sin}", - ["arcsin"] = "\\mathopnolimits{arcsin}", - ["sinh"] = "\\mathopnolimits{sinh}", - ["arcsinh"] = "\\mathopnolimits{arcsinh}", - ["cos"] = "\\mathopnolimits{cos}", - ["arccos"] = "\\mathopnolimits{arccos}", - ["cosh"] = "\\mathopnolimits{cosh}", - ["arccosh"] = "\\mathopnolimits{arccosh}", - ["tan"] = "\\mathopnolimits{tan}", - ["arctan"] = "\\mathopnolimits{arctan}", - ["tanh"] = "\\mathopnolimits{tanh}", - ["arctanh"] = "\\mathopnolimits{arctanh}", - ["cot"] = "\\mathopnolimits{cot}", - ["arccot"] = "\\mathopnolimits{arccot}", - ["coth"] = "\\mathopnolimits{coth}", - ["arccoth"] = "\\mathopnolimits{arccoth}", - ["csc"] = "\\mathopnolimits{csc}", - ["arccsc"] = "\\mathopnolimits{arccsc}", - ["csch"] = "\\mathopnolimits{csch}", - ["arccsch"] = "\\mathopnolimits{arccsch}", - ["sec"] = "\\mathopnolimits{sec}", - ["arcsec"] = "\\mathopnolimits{arcsec}", - ["sech"] = "\\mathopnolimits{sech}", - ["arcsech"] = "\\mathopnolimits{arcsech}", - [" "] = "", - - ["false"] = "{\\mr false}", - ["notanumber"] = "{\\mr NaN}", - ["otherwise"] = "{\\mr otherwise}", - ["true"] = "{\\mr true}", - ["declare"] = "{\\mr declare}", - ["as"] = "{\\mr as}", -} - --- we could use a metatable or when accessing fallback on the --- key but at least we now have an overview - -local csymbols = { - arith1 = { - lcm = "lcm", - big_lcm = "lcm", - gcd = "gcd", - big_gcd = "big_gcd", - plus = "plus", - unary_minus = "minus", - minus = "minus", - times = "times", - divide = "divide", - power = "power", - abs = "abs", - root = "root", - sum = "sum", - product = "product", - }, - fns = { - domain = "domain", - range = "codomain", - image = "image", - identity = "ident", - -- left_inverse = "", - -- right_inverse = "", - inverse = "inverse", - left_compose = "compose", - lambda = "labmda", - }, - linalg1 = { - vectorproduct = "vectorproduct", - scalarproduct = "scalarproduct", - outerproduct = "outerproduct", - transpose = "transpose", - determinant = "determinant", - vector_selector = "selector", - -- matrix_selector = "matrix_selector", - }, - logic1 = { - equivalent = "equivalent", - ["not"] = "not", - ["and"] = "and", - -- big_and = "", - ["xor"] = "xor", - -- big_xor = "", - ["or"] = "or", - -- big-or = "", - implies = "implies", - ["true"] = "true", - ["false"] = "false", - }, - nums1 = { - -- based_integer = "based_integer" - rational = "rational", - inifinity = "infinity", - e = "expenonentiale", - i = "imaginaryi", - pi = "pi", - gamma = "gamma", - NaN = "NaN", - }, - relation1 = { - eq = "eq", - lt = "lt", - gt = "gt", - neq = "neq", - leq = "leq", - geq = "geq", - approx = "approx", - }, - set1 = { - cartesian_product = "cartesianproduct", - empty_set = "emptyset", - map = "map", - size = "card", - -- suchthat = "suchthat", - set = "set", - intersect = "intersect", - -- big_intersect = "", - union = "union", - -- big_union = "", - setdiff = "setdiff", - subset = "subset", - ["in"] = "in", - notin = "notin", - prsubset = "prsubset", - notsubset = "notsubset", - notprsubset = "notprsubset", - }, - veccalc1 = { - divergence = "divergence", - grad = "grad", - curl = "curl", - laplacian = "laplacian", - Laplacian = "laplacian", - }, - calculus1 = { - diff = "diff", - -- nthdiff = "", - partialdiff = "partialdiff", - int = "int", - -- defint = "defint", - }, - integer1 = { - factorof = "factorof", - factorial = "factorial", - quotient = "quotient", - remainder = "rem", - }, - linalg2 = { - vector = "vector", - matrix = "matrix", - matrixrow = "matrixrow", - }, - mathmkeys = { - -- equiv = "", - -- contentequiv = "", - -- contentequiv_strict = "", - }, - rounding1 = { - ceiling = "ceiling", - floor = "floor", - -- trunc = "trunc", - -- round = "round", - }, - setname1 = { - P = "primes", - N = "naturalnumbers", - Z = "integers", - rationals = "rationals", - R = "reals", - complexes = "complexes", - }, - complex1 = { - -- complex_cartesian = "complex_cartesian", -- ci ? - real = "real", - imaginary = "imaginary", - -- complex_polar = "complex_polar", -- ci ? - argument = "arg", - conjugate = "conjugate", - }, - interval1 = { -- not an apply - -- integer_interval = "integer_interval", - interval = "interval", - interval_oo = { tag = "interval", closure = "open" }, - interval_cc = { tag = "interval", closure = "closed" }, - interval_oc = { tag = "interval", closure = "open-closed" }, - interval_co = { tag = "interval", closure = "closed-open" }, - }, - linalg3 = { - -- vector = "vector.column", - -- matrixcolumn = "matrixcolumn", - -- matrix = "matrix.column", - }, - minmax1 = { - min = "min", - -- big_min = "", - max = "max", - -- big_max = "", - }, - piece1 = { - piecewise = "piecewise", - piece = "piece", - otherwise = "otherwise", - }, - error1 = { - -- unhandled_symbol = "", - -- unexpected_symbol = "", - -- unsupported_CD = "", - }, - limit1 = { - -- limit = "limit", - -- both_sides = "both_sides", - -- above = "above", - -- below = "below", - -- null = "null", - tendsto = "tendsto", - }, - list1 = { - -- map = "", - -- suchthat = "", - -- list = "list", - }, - multiset1 = { - size = { tag = "card", type = "multiset" }, - cartesian_product = { tag = "cartesianproduct", type = "multiset" }, - empty_set = { tag = "emptyset", type = "multiset" }, - -- multi_set = { tag = "multiset", type = "multiset" }, - intersect = { tag = "intersect", type = "multiset" }, - -- big_intersect = "", - union = { tag = "union", type = "multiset" }, - -- big_union = "", - setdiff = { tag = "setdiff", type = "multiset" }, - subset = { tag = "subset", type = "multiset" }, - ["in"] = { tag = "in", type = "multiset" }, - notin = { tag = "notin", type = "multiset" }, - prsubset = { tag = "prsubset", type = "multiset" }, - notsubset = { tag = "notsubset", type = "multiset" }, - notprsubset = { tag = "notprsubset", type = "multiset" }, - }, - quant1 = { - forall = "forall", - exists = "exists", - }, - s_dist = { - -- mean = "mean.dist", - -- sdev = "sdev.dist", - -- variance = "variance.dist", - -- moment = "moment.dist", - }, - s_data = { - mean = "mean", - sdev = "sdev", - variance = "vriance", - mode = "mode", - median = "median", - moment = "moment", - }, - transc1 = { - log = "log", - ln = "ln", - exp = "exp", - sin = "sin", - cos = "cos", - tan = "tan", - sec = "sec", - csc = "csc", - cot = "cot", - sinh = "sinh", - cosh = "cosh", - tanh = "tanh", - sech = "sech", - csch = "cscs", - coth = "coth", - arcsin = "arcsin", - arccos = "arccos", - arctan = "arctan", - arcsec = "arcsec", - arcscs = "arccsc", - arccot = "arccot", - arcsinh = "arcsinh", - arccosh = "arccosh", - arctanh = "arstanh", - arcsech = "arcsech", - arccsch = "arccsch", - arccoth = "arccoth", - }, -} - -function xml.functions.remapmmlcsymbol(e) - local at = e.at - local cd = at.cd - if cd then - cd = csymbols[cd] - if cd then - local tx = e.dt[1] - if tx and tx ~= "" then - local tg = cd[tx] - if tg then - at.cd = nil - at.cdbase = nil - e.dt = { } - if type(tg) == "table" then - for k, v in next, tg do - if k == "tag" then - e.tg = v - else - at[k] = v - end - end - else - e.tg = tg - end - end - end - end - end -end - -function xml.functions.remapmmlbind(e) - e.tg = "apply" -end - -function xml.functions.remapopenmath(e) - local tg = e.tg - if tg == "OMOBJ" then - e.tg = "math" - elseif tg == "OMA" then - e.tg = "apply" - elseif tg == "OMB" then - e.tg = "apply" - elseif tg == "OMS" then - local at = e.at - e.tg = "csymbol" - e.dt = { at.name or "unknown" } - at.name = nil - elseif tg == "OMV" then - local at = e.at - e.tg = "ci" - e.dt = { at.name or "unknown" } - at.name = nil - elseif tg == "OMI" then - e.tg = "ci" - end - e.rn = "mml" -end - -function mathml.checked_operator(str) - context(simpleoperatorremapper(str)) -end - -function mathml.stripped(str) - context(strip(str)) -end - -function mathml.mn(id,pattern) - -- maybe at some point we need to interpret the number, but - -- currently we assume an upright font - local str = xmlcontent(getid(id)) or "" - local rep = gsub(str,"&.-;","") - local rep = gsub(rep,"(%s+)",utfchar(0x205F)) -- medspace e.g.: twenty one (nbsp is not seen) - local rep = gsub(rep,".",n_replacements) - context.mn(rep) -end - -function mathml.mo(id) - local str = xmlcontent(getid(id)) or "" - local rep = gsub(str,"&.-;","") -- todo - context(simpleoperatorremapper(rep)) -end - -function mathml.mi(id) - -- we need to strip comments etc .. todo when reading in tree - local e = getid(id) - local str = e.dt - if type(str) == "string" then - local n = #str - if n == 0 then - -- nothing to do - elseif n == 1 then - local str = gsub(str[1],"&.-;","") -- bah - local rep = i_replacements[str] - if not rep then - rep = gsub(str,".",i_replacements) - end - context(rep) - -- context.mi(rep) - else - context.xmlflush(id) -- xmlsprint or so - end - else - context.xmlflush(id) -- xmlsprint or so - end -end - -function mathml.mfenced(id) -- multiple separators - id = getid(id) - local left, right, separators = id.at.open or "(", id.at.close or ")", id.at.separators or "," - local l, r = l_replacements[left], r_replacements[right] - context.enabledelimiter() - if l then - context(l_replacements[left] or o_replacements[left] or "") - else - context(o_replacements["@l"]) - context(left) - end - context.disabledelimiter() - local collected = lxml.filter(id,"/*") -- check the * - if collected then - local n = #collected - if n == 0 then - -- skip - elseif n == 1 then - xmlsprint(collected[1]) -- to be checked - else - local t = utf.split(separators,true) - for i=1,n do - xmlsprint(collected[i]) -- to be checked - if i < n then - local m = t[i] or t[#t] or "" - if m == "|" then - m = "\\enabledelimiter\\middle|\\relax\\disabledelimiter" - elseif m == doublebar then - m = "\\enabledelimiter\\middle|\\relax\\disabledelimiter" - elseif m == "{" then - m = "\\{" - elseif m == "}" then - m = "\\}" - end - context(m) - end - end - end - end - context.enabledelimiter() - if r then - context(r_replacements[right] or o_replacements[right] or "") - else - context(right) - context(o_replacements["@r"]) - end - context.disabledelimiter() -end - ---~ local function flush(e,tag,toggle) ---~ if toggle then ---~ context("^{") ---~ else ---~ context("_{") ---~ end ---~ if tag == "none" then ---~ context("{}") ---~ else ---~ xmlsprint(e.dt) ---~ end ---~ if not toggle then ---~ context("}") ---~ else ---~ context("}{}") ---~ end ---~ return not toggle ---~ end - -local function flush(e,tag,toggle) - if tag == "none" then - -- if not toggle then - context("{}") -- {} starts a new ^_ set - -- end - elseif toggle then - context("^{") - xmlsprint(e.dt) - context("}{}") -- {} starts a new ^_ set - else - context("_{") - xmlsprint(e.dt) - context("}") - end - return not toggle -end - -function mathml.mmultiscripts(id) - local done, toggle = false, false - for e in lxml.collected(id,"/*") do - local tag = e.tg - if tag == "mprescripts" then - context("{}") - done = true - elseif done then - toggle = flush(e,tag,toggle) - end - end - local done, toggle = false, false - for e in lxml.collected(id,"/*") do - local tag = e.tg - if tag == "mprescripts" then - break - elseif done then - toggle = flush(e,tag,toggle) - else - xmlsprint(e.dt) - done = true - end - end -end - -local columnalignments = { - left = "flushleft", - right = "flushright", - center = "middle", -} - -local rowalignments = { - top = "high", - bottom = "low", - center = "lohi", - baseline = "top", - axis = "lohi", -} - -local frametypes = { - none = "off", - solid = "on", - dashed = "on", -} - --- crazy element ... should be a proper structure instead of such a mess - -function mathml.mcolumn(root) - root = getid(root) - local matrix, numbers = { }, 0 - local function collect(m,e) - local tag = e.tg - if tag == "mi" or tag == "mn" or tag == "mo" or tag == "mtext" then - local str = xmltext(e) - str = gsub(str,"&.-;","") - for s in utfcharacters(str) do - m[#m+1] = { tag, s } - end - if tag == "mn" then - local n = utf.len(str) - if n > numbers then - numbers = n - end - end - elseif tag == "mspace" or tag == "mline" then - local str = e.at.spacing or "" - for s in utfcharacters(str) do - m[#m+1] = { tag, s } - end - -- elseif tag == "mline" then - -- m[#m+1] = { tag, e } - end - end - for e in lxml.collected(root,"/*") do - local m = { } - matrix[#matrix+1] = m - if e.tg == "mrow" then - -- only one level - for e in lxml.collected(e,"/*") do - collect(m,e) - end - else - collect(m,e) - end - end - context.halign() - context.bgroup() - context([[\hss\startimath\alignmark\stopimath\aligntab\startimath\alignmark\stopimath\cr]]) - for i=1,#matrix do - local m = matrix[i] - local mline = true - for j=1,#m do - if m[j][1] ~= "mline" then - mline = false - break - end - end - if mline then - context.noalign([[\obeydepth\nointerlineskip]]) - end - for j=1,#m do - local mm = m[j] - local tag, chr = mm[1], mm[2] - if tag == "mline" then - -- This code is under construction ... I need some real motivation - -- to deal with this kind of crap. ---~ local n, p = true, true ---~ for c=1,#matrix do ---~ local mc = matrix[c][j] ---~ if mc then ---~ mc = mc[2] ---~ if type(mc) ~= "string" then ---~ n, p = false, false ---~ break ---~ elseif find(mc,"^[%d ]$") then -- rangecheck is faster ---~ -- digit ---~ elseif not find(mc,"^[%.%,]$") then -- rangecheck is faster ---~ -- punctuation ---~ else ---~ n = false ---~ break ---~ end ---~ end ---~ end ---~ if n then ---~ chr = "\\mmlmcolumndigitrule" ---~ elseif p then ---~ chr = "\\mmlmcolumnpunctuationrule" ---~ else ---~ chr = "\\mmlmcolumnsymbolrule" -- should be widest char ---~ end - chr = "\\hrulefill" - elseif tag == "mspace" then - chr = "\\mmlmcolumndigitspace" -- utfchar(0x2007) - end - if j == numbers + 1 then - context("\\aligntab") - end - local nchr = n_replacements[chr] - context(nchr or chr) - end - context.crcr() - end - context.egroup() -end - -local spacesplitter = lpeg.tsplitat(" ") - -function mathml.mtable(root) - -- todo: align, rowspacing, columnspacing, rowlines, columnlines - root = getid(root) - local at = root.at - local rowalign = at.rowalign - local columnalign = at.columnalign - local frame = at.frame - local rowaligns = rowalign and lpegmatch(spacesplitter,rowalign) - local columnaligns = columnalign and lpegmatch(spacesplitter,columnalign) - local frames = frame and lpegmatch(spacesplitter,frame) - local framespacing = at.framespacing or "0pt" - local framespacing = at.framespacing or "-\\ruledlinewidth" -- make this an option - - context.bTABLE { frame = frametypes[frame or "none"] or "off", offset = framespacing } - for e in lxml.collected(root,"/(mml:mtr|mml:mlabeledtr)") do - context.bTR() - local at = e.at - local col = 0 - local rfr = at.frame or (frames and frames [#frames]) - local rra = at.rowalign or (rowaligns and rowaligns [#rowaligns]) - local rca = at.columnalign or (columnaligns and columnaligns[#columnaligns]) - local ignorelabel = e.tg == "mlabeledtr" - for e in lxml.collected(e,"/mml:mtd") do -- nested we can use xml.collected - col = col + 1 - if ignorelabel and col == 1 then - -- get rid of label, should happen at the document level - else - local at = e.at - local rowspan, columnspan = at.rowspan or 1, at.columnspan or 1 - local cra = rowalignments [at.rowalign or (rowaligns and rowaligns [col]) or rra or "center"] or "lohi" - local cca = columnalignments[at.columnalign or (columnaligns and columnaligns[col]) or rca or "center"] or "middle" - local cfr = frametypes [at.frame or (frames and frames [col]) or rfr or "none" ] or "off" - context.bTD { align = format("{%s,%s}",cra,cca), frame = cfr, nx = columnspan, ny = rowspan } - context.startimath() - context.ignorespaces() - xmlcprint(e) - context.stopimath() - context.removeunwantedspaces() - context.eTD() - end - end - -- if e.tg == "mlabeledtr" then - -- context.bTD() - -- xmlcprint(xml.first(e,"/!mml:mtd")) - -- context.eTD() - -- end - context.eTR() - end - context.eTABLE() -end - -function mathml.csymbol(root) - root = getid(root) - local at = root.at - local encoding = at.encoding or "" - local hash = url.hashed(lower(at.definitionUrl or "")) - local full = hash.original or "" - local base = hash.path or "" - local text = strip(xmltext(root) or "") - context.mmlapplycsymbol(full,base,encoding,text) -end - -function mathml.menclosepattern(root) - root = getid(root) - local a = root.at.notation - if a and a ~= "" then - context("mml:enclose:",(gsub(a," +",",mml:enclose:"))) - end -end - -function xml.is_element(e,name) - return type(e) == "table" and (not name or e.tg == name) -end - -function mathml.cpolar_a(root) - root = getid(root) - local dt = root.dt - context.mathopnolimits("Polar") - context.left(false,"(") - for k=1,#dt do - local dk = dt[k] - if xml.is_element(dk,"sep") then - context(",") - else - xmlsprint(dk) - end - end - context.right(false,")") -end +if not modules then modules = { } end modules ['x-mathml'] = {
+ version = 1.001,
+ comment = "companion to x-mathml.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- This needs an upgrade to the latest greatest mechanisms.
+
+local type, next = type, next
+local format, lower, find, gsub = string.format, string.lower, string.find, string.gsub
+local strip = string.strip
+local xmlsprint, xmlcprint, xmltext, xmlcontent = xml.sprint, xml.cprint, xml.text, xml.content
+local getid = lxml.getid
+local utfchar, utfcharacters, utfvalues = utf.char, utf.characters, utf.values
+local lpegmatch = lpeg.match
+
+local mathml = { }
+moduledata.mathml = mathml
+lxml.mathml = mathml -- for the moment
+
+-- an alternative is to remap to private codes, where we can have
+-- different properties .. to be done; this will move and become
+-- generic; we can then make the private ones active in math mode
+
+-- todo: handle opening/closing mo's here ... presentation mml is such a mess ...
+
+characters.registerentities()
+
+local doublebar = utfchar(0x2016)
+
+local n_replacements = {
+-- [" "] = utfchar(0x2002), -- "&textspace;" -> tricky, no &; in mkiv
+ ["."] = "{.}",
+ [","] = "{,}",
+ [" "] = "",
+}
+
+local l_replacements = { -- in main table
+ ["|"] = "\\mmlleftdelimiter\\vert",
+ ["{"] = "\\mmlleftdelimiter\\lbrace",
+ ["("] = "\\mmlleftdelimiter(",
+ ["["] = "\\mmlleftdelimiter[",
+ ["<"] = "\\mmlleftdelimiter<",
+ [doublebar] = "\\mmlleftdelimiter\\Vert",
+}
+local r_replacements = { -- in main table
+ ["|"] = "\\mmlrightdelimiter\\vert",
+ ["}"] = "\\mmlrightdelimiter\\rbrace",
+ [")"] = "\\mmlrightdelimiter)",
+ ["]"] = "\\mmlrightdelimiter]",
+ [">"] = "\\mmlrightdelimiter>",
+ [doublebar] = "\\mmlrightdelimiter\\Vert",
+}
+
+-- todo: play with asciimode and avoid mmlchar
+
+local o_replacements = { -- in main table
+ ["@l"] = "\\mmlleftdelimiter.",
+ ["@r"] = "\\mmlrightdelimiter.",
+ ["{"] = "\\mmlleftdelimiter \\lbrace",
+ ["}"] = "\\mmlrightdelimiter\\rbrace",
+ ["|"] = "\\mmlleftorrightdelimiter\\vert",
+ [doublebar] = "\\mmlleftorrightdelimiter\\Vert",
+ ["("] = "\\mmlleftdelimiter(",
+ [")"] = "\\mmlrightdelimiter)",
+ ["["] = "\\mmlleftdelimiter[",
+ ["]"] = "\\mmlrightdelimiter]",
+ -- ["<"] = "\\mmlleftdelimiter<",
+ -- [">"] = "\\mmlrightdelimiter>",
+ ["#"] = "\\mmlchar{35}",
+ ["$"] = "\\mmlchar{36}", -- $
+ ["%"] = "\\mmlchar{37}",
+ ["&"] = "\\mmlchar{38}",
+ ["^"] = "\\mmlchar{94}{}", -- strange, sometimes luatex math sees the char instead of \char
+ ["_"] = "\\mmlchar{95}{}", -- so we need the {}
+ ["~"] = "\\mmlchar{126}",
+ [" "] = "",
+ ["°"] = "^\\circ", -- hack
+
+ -- [utfchar(0xF103C)] = "\\mmlleftdelimiter<",
+ [utfchar(0xF1026)] = "\\mmlchar{38}",
+ -- [utfchar(0xF103E)] = "\\mmlleftdelimiter>",
+
+}
+
+local simpleoperatorremapper = utf.remapper(o_replacements)
+
+--~ languages.data.labels.functions
+
+local i_replacements = {
+ ["sin"] = "\\mathopnolimits{sin}",
+ ["cos"] = "\\mathopnolimits{cos}",
+ ["abs"] = "\\mathopnolimits{abs}",
+ ["arg"] = "\\mathopnolimits{arg}",
+ ["codomain"] = "\\mathopnolimits{codomain}",
+ ["curl"] = "\\mathopnolimits{curl}",
+ ["determinant"] = "\\mathopnolimits{det}",
+ ["divergence"] = "\\mathopnolimits{div}",
+ ["domain"] = "\\mathopnolimits{domain}",
+ ["gcd"] = "\\mathopnolimits{gcd}",
+ ["grad"] = "\\mathopnolimits{grad}",
+ ["identity"] = "\\mathopnolimits{id}",
+ ["image"] = "\\mathopnolimits{image}",
+ ["lcm"] = "\\mathopnolimits{lcm}",
+ ["lim"] = "\\mathopnolimits{lim}",
+ ["max"] = "\\mathopnolimits{max}",
+ ["median"] = "\\mathopnolimits{median}",
+ ["min"] = "\\mathopnolimits{min}",
+ ["mode"] = "\\mathopnolimits{mode}",
+ ["mod"] = "\\mathopnolimits{mod}",
+ ["polar"] = "\\mathopnolimits{Polar}",
+ ["exp"] = "\\mathopnolimits{exp}",
+ ["ln"] = "\\mathopnolimits{ln}",
+ ["log"] = "\\mathopnolimits{log}",
+ ["sin"] = "\\mathopnolimits{sin}",
+ ["arcsin"] = "\\mathopnolimits{arcsin}",
+ ["sinh"] = "\\mathopnolimits{sinh}",
+ ["arcsinh"] = "\\mathopnolimits{arcsinh}",
+ ["cos"] = "\\mathopnolimits{cos}",
+ ["arccos"] = "\\mathopnolimits{arccos}",
+ ["cosh"] = "\\mathopnolimits{cosh}",
+ ["arccosh"] = "\\mathopnolimits{arccosh}",
+ ["tan"] = "\\mathopnolimits{tan}",
+ ["arctan"] = "\\mathopnolimits{arctan}",
+ ["tanh"] = "\\mathopnolimits{tanh}",
+ ["arctanh"] = "\\mathopnolimits{arctanh}",
+ ["cot"] = "\\mathopnolimits{cot}",
+ ["arccot"] = "\\mathopnolimits{arccot}",
+ ["coth"] = "\\mathopnolimits{coth}",
+ ["arccoth"] = "\\mathopnolimits{arccoth}",
+ ["csc"] = "\\mathopnolimits{csc}",
+ ["arccsc"] = "\\mathopnolimits{arccsc}",
+ ["csch"] = "\\mathopnolimits{csch}",
+ ["arccsch"] = "\\mathopnolimits{arccsch}",
+ ["sec"] = "\\mathopnolimits{sec}",
+ ["arcsec"] = "\\mathopnolimits{arcsec}",
+ ["sech"] = "\\mathopnolimits{sech}",
+ ["arcsech"] = "\\mathopnolimits{arcsech}",
+ [" "] = "",
+
+ ["false"] = "{\\mr false}",
+ ["notanumber"] = "{\\mr NaN}",
+ ["otherwise"] = "{\\mr otherwise}",
+ ["true"] = "{\\mr true}",
+ ["declare"] = "{\\mr declare}",
+ ["as"] = "{\\mr as}",
+}
+
+-- we could use a metatable or when accessing fallback on the
+-- key but at least we now have an overview
+
+local csymbols = {
+ arith1 = {
+ lcm = "lcm",
+ big_lcm = "lcm",
+ gcd = "gcd",
+ big_gcd = "big_gcd",
+ plus = "plus",
+ unary_minus = "minus",
+ minus = "minus",
+ times = "times",
+ divide = "divide",
+ power = "power",
+ abs = "abs",
+ root = "root",
+ sum = "sum",
+ product = "product",
+ },
+ fns = {
+ domain = "domain",
+ range = "codomain",
+ image = "image",
+ identity = "ident",
+ -- left_inverse = "",
+ -- right_inverse = "",
+ inverse = "inverse",
+ left_compose = "compose",
+ lambda = "labmda",
+ },
+ linalg1 = {
+ vectorproduct = "vectorproduct",
+ scalarproduct = "scalarproduct",
+ outerproduct = "outerproduct",
+ transpose = "transpose",
+ determinant = "determinant",
+ vector_selector = "selector",
+ -- matrix_selector = "matrix_selector",
+ },
+ logic1 = {
+ equivalent = "equivalent",
+ ["not"] = "not",
+ ["and"] = "and",
+ -- big_and = "",
+ ["xor"] = "xor",
+ -- big_xor = "",
+ ["or"] = "or",
+ -- big-or = "",
+ implies = "implies",
+ ["true"] = "true",
+ ["false"] = "false",
+ },
+ nums1 = {
+ -- based_integer = "based_integer"
+ rational = "rational",
+ inifinity = "infinity",
+ e = "expenonentiale",
+ i = "imaginaryi",
+ pi = "pi",
+ gamma = "gamma",
+ NaN = "NaN",
+ },
+ relation1 = {
+ eq = "eq",
+ lt = "lt",
+ gt = "gt",
+ neq = "neq",
+ leq = "leq",
+ geq = "geq",
+ approx = "approx",
+ },
+ set1 = {
+ cartesian_product = "cartesianproduct",
+ empty_set = "emptyset",
+ map = "map",
+ size = "card",
+ -- suchthat = "suchthat",
+ set = "set",
+ intersect = "intersect",
+ -- big_intersect = "",
+ union = "union",
+ -- big_union = "",
+ setdiff = "setdiff",
+ subset = "subset",
+ ["in"] = "in",
+ notin = "notin",
+ prsubset = "prsubset",
+ notsubset = "notsubset",
+ notprsubset = "notprsubset",
+ },
+ veccalc1 = {
+ divergence = "divergence",
+ grad = "grad",
+ curl = "curl",
+ laplacian = "laplacian",
+ Laplacian = "laplacian",
+ },
+ calculus1 = {
+ diff = "diff",
+ -- nthdiff = "",
+ partialdiff = "partialdiff",
+ int = "int",
+ -- defint = "defint",
+ },
+ integer1 = {
+ factorof = "factorof",
+ factorial = "factorial",
+ quotient = "quotient",
+ remainder = "rem",
+ },
+ linalg2 = {
+ vector = "vector",
+ matrix = "matrix",
+ matrixrow = "matrixrow",
+ },
+ mathmkeys = {
+ -- equiv = "",
+ -- contentequiv = "",
+ -- contentequiv_strict = "",
+ },
+ rounding1 = {
+ ceiling = "ceiling",
+ floor = "floor",
+ -- trunc = "trunc",
+ -- round = "round",
+ },
+ setname1 = {
+ P = "primes",
+ N = "naturalnumbers",
+ Z = "integers",
+ rationals = "rationals",
+ R = "reals",
+ complexes = "complexes",
+ },
+ complex1 = {
+ -- complex_cartesian = "complex_cartesian", -- ci ?
+ real = "real",
+ imaginary = "imaginary",
+ -- complex_polar = "complex_polar", -- ci ?
+ argument = "arg",
+ conjugate = "conjugate",
+ },
+ interval1 = { -- not an apply
+ -- integer_interval = "integer_interval",
+ interval = "interval",
+ interval_oo = { tag = "interval", closure = "open" },
+ interval_cc = { tag = "interval", closure = "closed" },
+ interval_oc = { tag = "interval", closure = "open-closed" },
+ interval_co = { tag = "interval", closure = "closed-open" },
+ },
+ linalg3 = {
+ -- vector = "vector.column",
+ -- matrixcolumn = "matrixcolumn",
+ -- matrix = "matrix.column",
+ },
+ minmax1 = {
+ min = "min",
+ -- big_min = "",
+ max = "max",
+ -- big_max = "",
+ },
+ piece1 = {
+ piecewise = "piecewise",
+ piece = "piece",
+ otherwise = "otherwise",
+ },
+ error1 = {
+ -- unhandled_symbol = "",
+ -- unexpected_symbol = "",
+ -- unsupported_CD = "",
+ },
+ limit1 = {
+ -- limit = "limit",
+ -- both_sides = "both_sides",
+ -- above = "above",
+ -- below = "below",
+ -- null = "null",
+ tendsto = "tendsto",
+ },
+ list1 = {
+ -- map = "",
+ -- suchthat = "",
+ -- list = "list",
+ },
+ multiset1 = {
+ size = { tag = "card", type = "multiset" },
+ cartesian_product = { tag = "cartesianproduct", type = "multiset" },
+ empty_set = { tag = "emptyset", type = "multiset" },
+ -- multi_set = { tag = "multiset", type = "multiset" },
+ intersect = { tag = "intersect", type = "multiset" },
+ -- big_intersect = "",
+ union = { tag = "union", type = "multiset" },
+ -- big_union = "",
+ setdiff = { tag = "setdiff", type = "multiset" },
+ subset = { tag = "subset", type = "multiset" },
+ ["in"] = { tag = "in", type = "multiset" },
+ notin = { tag = "notin", type = "multiset" },
+ prsubset = { tag = "prsubset", type = "multiset" },
+ notsubset = { tag = "notsubset", type = "multiset" },
+ notprsubset = { tag = "notprsubset", type = "multiset" },
+ },
+ quant1 = {
+ forall = "forall",
+ exists = "exists",
+ },
+ s_dist = {
+ -- mean = "mean.dist",
+ -- sdev = "sdev.dist",
+ -- variance = "variance.dist",
+ -- moment = "moment.dist",
+ },
+ s_data = {
+ mean = "mean",
+ sdev = "sdev",
+ variance = "vriance",
+ mode = "mode",
+ median = "median",
+ moment = "moment",
+ },
+ transc1 = {
+ log = "log",
+ ln = "ln",
+ exp = "exp",
+ sin = "sin",
+ cos = "cos",
+ tan = "tan",
+ sec = "sec",
+ csc = "csc",
+ cot = "cot",
+ sinh = "sinh",
+ cosh = "cosh",
+ tanh = "tanh",
+ sech = "sech",
+ csch = "cscs",
+ coth = "coth",
+ arcsin = "arcsin",
+ arccos = "arccos",
+ arctan = "arctan",
+ arcsec = "arcsec",
+ arcscs = "arccsc",
+ arccot = "arccot",
+ arcsinh = "arcsinh",
+ arccosh = "arccosh",
+ arctanh = "arstanh",
+ arcsech = "arcsech",
+ arccsch = "arccsch",
+ arccoth = "arccoth",
+ },
+}
+
+function xml.functions.remapmmlcsymbol(e)
+ local at = e.at
+ local cd = at.cd
+ if cd then
+ cd = csymbols[cd]
+ if cd then
+ local tx = e.dt[1]
+ if tx and tx ~= "" then
+ local tg = cd[tx]
+ if tg then
+ at.cd = nil
+ at.cdbase = nil
+ e.dt = { }
+ if type(tg) == "table" then
+ for k, v in next, tg do
+ if k == "tag" then
+ e.tg = v
+ else
+ at[k] = v
+ end
+ end
+ else
+ e.tg = tg
+ end
+ end
+ end
+ end
+ end
+end
+
+function xml.functions.remapmmlbind(e)
+ e.tg = "apply"
+end
+
+function xml.functions.remapopenmath(e)
+ local tg = e.tg
+ if tg == "OMOBJ" then
+ e.tg = "math"
+ elseif tg == "OMA" then
+ e.tg = "apply"
+ elseif tg == "OMB" then
+ e.tg = "apply"
+ elseif tg == "OMS" then
+ local at = e.at
+ e.tg = "csymbol"
+ e.dt = { at.name or "unknown" }
+ at.name = nil
+ elseif tg == "OMV" then
+ local at = e.at
+ e.tg = "ci"
+ e.dt = { at.name or "unknown" }
+ at.name = nil
+ elseif tg == "OMI" then
+ e.tg = "ci"
+ end
+ e.rn = "mml"
+end
+
+function mathml.checked_operator(str)
+ context(simpleoperatorremapper(str))
+end
+
+function mathml.stripped(str)
+ context(strip(str))
+end
+
+function mathml.mn(id,pattern)
+ -- maybe at some point we need to interpret the number, but
+ -- currently we assume an upright font
+ local str = xmlcontent(getid(id)) or ""
+ local rep = gsub(str,"&.-;","")
+ local rep = gsub(rep,"(%s+)",utfchar(0x205F)) -- medspace e.g.: twenty one (nbsp is not seen)
+ local rep = gsub(rep,".",n_replacements)
+ context.mn(rep)
+end
+
+function mathml.mo(id)
+ local str = xmlcontent(getid(id)) or ""
+ local rep = gsub(str,"&.-;","") -- todo
+ context(simpleoperatorremapper(rep))
+end
+
+function mathml.mi(id)
+ -- we need to strip comments etc .. todo when reading in tree
+ local e = getid(id)
+ local str = e.dt
+ if type(str) == "string" then
+ local n = #str
+ if n == 0 then
+ -- nothing to do
+ elseif n == 1 then
+ local str = gsub(str[1],"&.-;","") -- bah
+ local rep = i_replacements[str]
+ if not rep then
+ rep = gsub(str,".",i_replacements)
+ end
+ context(rep)
+ -- context.mi(rep)
+ else
+ context.xmlflush(id) -- xmlsprint or so
+ end
+ else
+ context.xmlflush(id) -- xmlsprint or so
+ end
+end
+
+function mathml.mfenced(id) -- multiple separators
+ id = getid(id)
+ local left, right, separators = id.at.open or "(", id.at.close or ")", id.at.separators or ","
+ local l, r = l_replacements[left], r_replacements[right]
+ context.enabledelimiter()
+ if l then
+ context(l_replacements[left] or o_replacements[left] or "")
+ else
+ context(o_replacements["@l"])
+ context(left)
+ end
+ context.disabledelimiter()
+ local collected = lxml.filter(id,"/*") -- check the *
+ if collected then
+ local n = #collected
+ if n == 0 then
+ -- skip
+ elseif n == 1 then
+ xmlsprint(collected[1]) -- to be checked
+ else
+ local t = utf.split(separators,true)
+ for i=1,n do
+ xmlsprint(collected[i]) -- to be checked
+ if i < n then
+ local m = t[i] or t[#t] or ""
+ if m == "|" then
+ m = "\\enabledelimiter\\middle|\\relax\\disabledelimiter"
+ elseif m == doublebar then
+ m = "\\enabledelimiter\\middle|\\relax\\disabledelimiter"
+ elseif m == "{" then
+ m = "\\{"
+ elseif m == "}" then
+ m = "\\}"
+ end
+ context(m)
+ end
+ end
+ end
+ end
+ context.enabledelimiter()
+ if r then
+ context(r_replacements[right] or o_replacements[right] or "")
+ else
+ context(right)
+ context(o_replacements["@r"])
+ end
+ context.disabledelimiter()
+end
+
+--~ local function flush(e,tag,toggle)
+--~ if toggle then
+--~ context("^{")
+--~ else
+--~ context("_{")
+--~ end
+--~ if tag == "none" then
+--~ context("{}")
+--~ else
+--~ xmlsprint(e.dt)
+--~ end
+--~ if not toggle then
+--~ context("}")
+--~ else
+--~ context("}{}")
+--~ end
+--~ return not toggle
+--~ end
+
+local function flush(e,tag,toggle)
+ if tag == "none" then
+ -- if not toggle then
+ context("{}") -- {} starts a new ^_ set
+ -- end
+ elseif toggle then
+ context("^{")
+ xmlsprint(e.dt)
+ context("}{}") -- {} starts a new ^_ set
+ else
+ context("_{")
+ xmlsprint(e.dt)
+ context("}")
+ end
+ return not toggle
+end
+
+function mathml.mmultiscripts(id)
+ local done, toggle = false, false
+ for e in lxml.collected(id,"/*") do
+ local tag = e.tg
+ if tag == "mprescripts" then
+ context("{}")
+ done = true
+ elseif done then
+ toggle = flush(e,tag,toggle)
+ end
+ end
+ local done, toggle = false, false
+ for e in lxml.collected(id,"/*") do
+ local tag = e.tg
+ if tag == "mprescripts" then
+ break
+ elseif done then
+ toggle = flush(e,tag,toggle)
+ else
+ xmlsprint(e.dt)
+ done = true
+ end
+ end
+end
+
+local columnalignments = {
+ left = "flushleft",
+ right = "flushright",
+ center = "middle",
+}
+
+local rowalignments = {
+ top = "high",
+ bottom = "low",
+ center = "lohi",
+ baseline = "top",
+ axis = "lohi",
+}
+
+local frametypes = {
+ none = "off",
+ solid = "on",
+ dashed = "on",
+}
+
+-- crazy element ... should be a proper structure instead of such a mess
+
+function mathml.mcolumn(root)
+ root = getid(root)
+ local matrix, numbers = { }, 0
+ local function collect(m,e)
+ local tag = e.tg
+ if tag == "mi" or tag == "mn" or tag == "mo" or tag == "mtext" then
+ local str = xmltext(e)
+ str = gsub(str,"&.-;","")
+ for s in utfcharacters(str) do
+ m[#m+1] = { tag, s }
+ end
+ if tag == "mn" then
+ local n = utf.len(str)
+ if n > numbers then
+ numbers = n
+ end
+ end
+ elseif tag == "mspace" or tag == "mline" then
+ local str = e.at.spacing or ""
+ for s in utfcharacters(str) do
+ m[#m+1] = { tag, s }
+ end
+ -- elseif tag == "mline" then
+ -- m[#m+1] = { tag, e }
+ end
+ end
+ for e in lxml.collected(root,"/*") do
+ local m = { }
+ matrix[#matrix+1] = m
+ if e.tg == "mrow" then
+ -- only one level
+ for e in lxml.collected(e,"/*") do
+ collect(m,e)
+ end
+ else
+ collect(m,e)
+ end
+ end
+ context.halign()
+ context.bgroup()
+ context([[\hss\startimath\alignmark\stopimath\aligntab\startimath\alignmark\stopimath\cr]])
+ for i=1,#matrix do
+ local m = matrix[i]
+ local mline = true
+ for j=1,#m do
+ if m[j][1] ~= "mline" then
+ mline = false
+ break
+ end
+ end
+ if mline then
+ context.noalign([[\obeydepth\nointerlineskip]])
+ end
+ for j=1,#m do
+ local mm = m[j]
+ local tag, chr = mm[1], mm[2]
+ if tag == "mline" then
+ -- This code is under construction ... I need some real motivation
+ -- to deal with this kind of crap.
+--~ local n, p = true, true
+--~ for c=1,#matrix do
+--~ local mc = matrix[c][j]
+--~ if mc then
+--~ mc = mc[2]
+--~ if type(mc) ~= "string" then
+--~ n, p = false, false
+--~ break
+--~ elseif find(mc,"^[%d ]$") then -- rangecheck is faster
+--~ -- digit
+--~ elseif not find(mc,"^[%.%,]$") then -- rangecheck is faster
+--~ -- punctuation
+--~ else
+--~ n = false
+--~ break
+--~ end
+--~ end
+--~ end
+--~ if n then
+--~ chr = "\\mmlmcolumndigitrule"
+--~ elseif p then
+--~ chr = "\\mmlmcolumnpunctuationrule"
+--~ else
+--~ chr = "\\mmlmcolumnsymbolrule" -- should be widest char
+--~ end
+ chr = "\\hrulefill"
+ elseif tag == "mspace" then
+ chr = "\\mmlmcolumndigitspace" -- utfchar(0x2007)
+ end
+ if j == numbers + 1 then
+ context("\\aligntab")
+ end
+ local nchr = n_replacements[chr]
+ context(nchr or chr)
+ end
+ context.crcr()
+ end
+ context.egroup()
+end
+
+local spacesplitter = lpeg.tsplitat(" ")
+
+function mathml.mtable(root)
+ -- todo: align, rowspacing, columnspacing, rowlines, columnlines
+ root = getid(root)
+ local at = root.at
+ local rowalign = at.rowalign
+ local columnalign = at.columnalign
+ local frame = at.frame
+ local rowaligns = rowalign and lpegmatch(spacesplitter,rowalign)
+ local columnaligns = columnalign and lpegmatch(spacesplitter,columnalign)
+ local frames = frame and lpegmatch(spacesplitter,frame)
+ local framespacing = at.framespacing or "0pt"
+ local framespacing = at.framespacing or "-\\ruledlinewidth" -- make this an option
+
+ context.bTABLE { frame = frametypes[frame or "none"] or "off", offset = framespacing }
+ for e in lxml.collected(root,"/(mml:mtr|mml:mlabeledtr)") do
+ context.bTR()
+ local at = e.at
+ local col = 0
+ local rfr = at.frame or (frames and frames [#frames])
+ local rra = at.rowalign or (rowaligns and rowaligns [#rowaligns])
+ local rca = at.columnalign or (columnaligns and columnaligns[#columnaligns])
+ local ignorelabel = e.tg == "mlabeledtr"
+ for e in lxml.collected(e,"/mml:mtd") do -- nested we can use xml.collected
+ col = col + 1
+ if ignorelabel and col == 1 then
+ -- get rid of label, should happen at the document level
+ else
+ local at = e.at
+ local rowspan, columnspan = at.rowspan or 1, at.columnspan or 1
+ local cra = rowalignments [at.rowalign or (rowaligns and rowaligns [col]) or rra or "center"] or "lohi"
+ local cca = columnalignments[at.columnalign or (columnaligns and columnaligns[col]) or rca or "center"] or "middle"
+ local cfr = frametypes [at.frame or (frames and frames [col]) or rfr or "none" ] or "off"
+ context.bTD { align = format("{%s,%s}",cra,cca), frame = cfr, nx = columnspan, ny = rowspan }
+ context.startimath()
+ context.ignorespaces()
+ xmlcprint(e)
+ context.stopimath()
+ context.removeunwantedspaces()
+ context.eTD()
+ end
+ end
+ -- if e.tg == "mlabeledtr" then
+ -- context.bTD()
+ -- xmlcprint(xml.first(e,"/!mml:mtd"))
+ -- context.eTD()
+ -- end
+ context.eTR()
+ end
+ context.eTABLE()
+end
+
+function mathml.csymbol(root)
+ root = getid(root)
+ local at = root.at
+ local encoding = at.encoding or ""
+ local hash = url.hashed(lower(at.definitionUrl or ""))
+ local full = hash.original or ""
+ local base = hash.path or ""
+ local text = strip(xmltext(root) or "")
+ context.mmlapplycsymbol(full,base,encoding,text)
+end
+
+function mathml.menclosepattern(root)
+ root = getid(root)
+ local a = root.at.notation
+ if a and a ~= "" then
+ context("mml:enclose:",(gsub(a," +",",mml:enclose:")))
+ end
+end
+
+function xml.is_element(e,name)
+ return type(e) == "table" and (not name or e.tg == name)
+end
+
+function mathml.cpolar_a(root)
+ root = getid(root)
+ local dt = root.dt
+ context.mathopnolimits("Polar")
+ context.left(false,"(")
+ for k=1,#dt do
+ local dk = dt[k]
+ if xml.is_element(dk,"sep") then
+ context(",")
+ else
+ xmlsprint(dk)
+ end
+ end
+ context.right(false,")")
+end
|