diff options
author | Hans Hagen <pragma@wxs.nl> | 2021-06-07 08:17:45 +0200 |
---|---|---|
committer | Context Git Mirror Bot <phg@phi-gamma.net> | 2021-06-07 08:17:45 +0200 |
commit | e3a0d092848f3f128742ffe478334651ab18e8dc (patch) | |
tree | d4ab51ab52cd72d343fe5d72b9e11adf81642460 /tex/context/modules/mkxl | |
parent | 75be509021abdcd01f7d5caf35d026647042322a (diff) | |
download | context-e3a0d092848f3f128742ffe478334651ab18e8dc.tar.gz |
2021-06-07 08:07:00
Diffstat (limited to 'tex/context/modules/mkxl')
-rw-r--r-- | tex/context/modules/mkxl/m-system-readers.mkxl | 148 | ||||
-rw-r--r-- | tex/context/modules/mkxl/m-timing.mkxl | 113 | ||||
-rw-r--r-- | tex/context/modules/mkxl/s-languages-goodies.lmt | 99 | ||||
-rw-r--r-- | tex/context/modules/mkxl/s-languages-goodies.mkxl | 144 | ||||
-rw-r--r-- | tex/context/modules/mkxl/s-system-macros.mkxl | 330 | ||||
-rw-r--r-- | tex/context/modules/mkxl/s-system-tokens.mkxl | 84 | ||||
-rw-r--r-- | tex/context/modules/mkxl/x-mathml.lmt | 910 | ||||
-rw-r--r-- | tex/context/modules/mkxl/x-mathml.mkxl | 2448 |
8 files changed, 4276 insertions, 0 deletions
diff --git a/tex/context/modules/mkxl/m-system-readers.mkxl b/tex/context/modules/mkxl/m-system-readers.mkxl new file mode 100644 index 000000000..0f2d3275e --- /dev/null +++ b/tex/context/modules/mkxl/m-system-readers.mkxl @@ -0,0 +1,148 @@ +%D \module +%D [ file=m-system-readers, +%D version=2021.02.13, +%D title=\CONTEXT\ Modules, +%D subtitle=Reading from files, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] + +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\startmodule[system-readers] + +% \unprotect +% +% \installcorenamespace {markedlines} +% +% \permanent\protected\def\startmarkedlines[#1]% +% {\edef\scratchstring{#1}% +% \scratchcounter\numexpr\inputlineno+\plusone\relax +% \gobbleuntilandfinalize\stopmarkedlines} +% +% \permanent\protected\def\stopmarkedlines +% {\edefcsname\??markedlines\scratchstring\endcsname +% {{\the\scratchcounter}{\the\numexpr\inputlineno+\minusone\relax}}} +% +% \protected\def\firstmarkedline#1% +% {\numexpr +% \ifcsname\??markedlines#1\endcsname +% \normalexpanded{\noexpand\firstoftwoarguments\lastnamedcs}% +% \else +% \zerocount +% \fi +% \relax} +% +% \protected\def\lastmarkedline#1% +% {\numexpr +% \ifcsname\??markedlines#1\endcsname +% \normalexpanded{\noexpand\secondoftwoarguments\lastnamedcs}% +% \else +% \zerocount +% \fi +% \relax} +% +% \protected\def\markedlines#1% +% {\ifcsname\??markedlines\scratchstring\endcsname\lastnamedcs\else{0}{0}\fi} +% +% \protect + +\startluacode + + local createtoken = tokens.create + local gobbletoken = tokens.gobble + local integer_value = tokens.values.integer + + local marked = { } + + interfaces.implement { + name = "startmarkedlines", + public = true, + protected = true, + arguments = "optional", + actions = function(tag) + local start = status.readstate.linenumber + 1 + gobbletoken(createtoken("startmarkedlines"),createtoken("stopmarkedlines")) + local state = status.readstate + marked[tag] = { state.filename, start, state.linenumber - 1 } + end + } + + + interfaces.implement { + name = "markedfilename", + public = true, + -- usage = "value", + arguments = "string", + actions = function(tag) + local m = marked[tag] + -- return m and m[1] or "" + context(m and m[1] or "") + end + } + + interfaces.implement { + name = "firstmarkedline", + public = true, + usage = "value", + arguments = "string", + actions = function(tag) + local m = marked[tag] + return integer_value, m and m[2] or 0 + end + } + + interfaces.implement { + name = "lastmarkedline", + public = true, + usage = "value", + arguments = "string", + actions = function(tag) + local m = marked[tag] + return integer_value, m and m[3] or 0 + end + } + +\stopluacode + +\continueifinputfile{m-system-readers.mkxl} + +\starttext + +\startmarkedlines[test] +SOME LINE 1 +SOME LINE 2 +SOME LINE 3 +SOME LINE 4 +\stopmarkedlines + +\startmarkedlines[more] +SOME MORE 1 +SOME MORE 2 +SOME MORE 3 +SOME MORE 4 +\stopmarkedlines + +\begingroup + \newlocalread\myreada + \immediate\openin\myreada {\markedfilename{test}} + \dostepwiserecurse{\lastmarkedline{test}}{\firstmarkedline{test}}{-1}{ + \readline\myreada line #1 to \scratchstring #1 : \scratchstring \par + } + \immediate\closein\myreada +\endgroup + +\blank + +\begingroup + \newlocalread\myreada + \immediate\openin\myreada {\markedfilename{more}} + \dostepwiserecurse{\firstmarkedline{more}}{\lastmarkedline{more}}{1}{ + \read \myreada line #1 to \scratchstring #1 : \scratchstring \par + } + \immediate\closein\myreada +\endgroup + +\stoptext diff --git a/tex/context/modules/mkxl/m-timing.mkxl b/tex/context/modules/mkxl/m-timing.mkxl new file mode 100644 index 000000000..3edfd14e2 --- /dev/null +++ b/tex/context/modules/mkxl/m-timing.mkxl @@ -0,0 +1,113 @@ +%D \module +%D [ file=m-timing, +%D version=2007.12.23, +%D title=\CONTEXT\ Modules, +%D subtitle=Timing, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +%D Todo: adapt to latest metafun magic. + +\ifdefined\ShowNamedUsage \endinput \fi + +%D Written at the end of 2007, this module is dedicated to Taco. Reaching this +%D point in \LUATEX\ was a non trivial effort. By visualizing a bit what happens +%D when pages come out of \LUATEX, you may get an idea what is involved. It took +%D much time an dedication to reach this point in the development. Add to that +%D those daily Skype intense discussion, testing and debugging moments. Time flies +%D but progress is impressive. The motto of this module could be: what you see +%D is what you get. An there is much more to come \unknown. + +% \usemodule[timing] +% \setupcolors[state=start] +% \starttext +% \dorecurse{200}{\input tufte \par} \ShowUsage{} +% \stoptext + +\definecolor[usage:line] [darkred] +\definecolor[usage:time] [darkblue] +\definecolor[usage:frame][darkgray] + +\ctxloadluafile{trac-tim.lmt} + +\startluacode +local progress = moduledata.progress + +function progress.show(filename,names,other) + if not filename or filename == "" then + filename = progress.defaultfilename or "" + end + for n, name in pairs(progress.names(filename)) do + if string.find(name,names) and name ~= other and name ~= "variables: lasttime" then + context.ShowNamedUsage(filename,name or "",other or "") + end + end +end +\stopluacode + +\startnotmode[no-timing] + \appendtoks\ctxlua{moduledata.progress.store()}\to\everystarttext + \appendtoks\ctxlua{moduledata.progress.store()}\to\everyshipout + \ctxlua{luatex.registerstopactions(function() moduledata.progress.save() end)} +\stopnotmode + +\permanent\protected\def\ShowNamedUsage#1#2#3% + {\setbox\scratchbox\vbox\bgroup + \startMPcode{doublefun} + begingroup ; save p, q, b, h, w ; + path p, q, b ; numeric h, w ; + p := \cldcontext{moduledata.progress.path("#1","#2")} ; + % p := p shifted -llcorner p ; + if bbwidth(p) > 0 : + h := 100 ; w := 2 * h ; + w := \the\textwidth-3pt ; % correct for pen + p := p xstretched w ; + b := boundingbox (llcorner p -- llcorner p shifted (w,h)) ; + pickup pencircle scaled 3pt ; linecap := butt ; + draw b withcolor \MPcolor{usage:frame} ; + draw p withcolor \MPcolor{usage:line} ; + if ("#3" <> "") and ("#3" <> "#2") : + q := \cldcontext{moduledata.progress.path("#1","#3")} ; + % q := q shifted -llcorner q ; + if bbwidth(q) > 1 : + q := q xstretched w ; + pickup pencircle scaled 1.5pt ; linecap := butt ; + draw q withcolor \MPcolor{usage:time} ; + fi ; + fi ; + fi ; + endgroup ; + \stopMPcode + \egroup + \scratchdimen\wd\scratchbox + \ifdim\scratchdimen>\zeropoint + \startlinecorrection[blank] + \box\scratchbox \endgraf + \hbox to \scratchdimen\bgroup + \tttf\strut\detokenize{#2}\hss + \scratchcounter =\cldcontext{moduledata.progress.set("#1","\detokenize{#2}")}\relax + \scratchcounterone =\cldcontext{moduledata.progress.bot("#1","\detokenize{#2}")}\relax + \scratchcountertwo =\cldcontext{moduledata.progress.top("#1","\detokenize{#2}")}\relax + \scratchcounterthree=\numexpr\scratchcountertwo-\scratchcounterone\relax + \ifnum\scratchcounter >\zerocount set:\the\scratchcounter \quad\fi + \ifnum\scratchcounterthree>\zerocount inc:\the\scratchcounterthree\quad\fi + \ifnum\scratchcounterone >\zerocount min:\the\scratchcounterone \quad\fi + \ifnum\scratchcountertwo >\zerocount max:\the\scratchcountertwo \quad\fi + pages:\cldcontext{moduledata.progress.pages("#1")}% + \egroup + \stoplinecorrection + \fi} + +\permanent\protected\def\LoadUsage #1{\ctxlua{moduledata.progress.convert("#1")}} +\permanent\protected\def\ShowUsage #1{\ctxlua{moduledata.progress.show("#1",".*", "variables: elapsed")}} +\permanent\protected\def\ShowMemoryUsage #1{\ctxlua{moduledata.progress.show("#1","memory:.*","variables: elapsed")}} +\permanent\protected\def\ShowNodeUsage #1{\ctxlua{moduledata.progress.show("#1","nodes:.*", "variables: elapsed")}} +\permanent\protected\def\ShowFilteredUsage#1#2{\ctxlua{moduledata.progress.show("#1","#2", "variables: elapsed")}} +\permanent\protected\def\ShowSimpleUsage #1#2{\ctxlua{moduledata.progress.show("#1","#2")}} + +\endinput diff --git a/tex/context/modules/mkxl/s-languages-goodies.lmt b/tex/context/modules/mkxl/s-languages-goodies.lmt new file mode 100644 index 000000000..7256fd35d --- /dev/null +++ b/tex/context/modules/mkxl/s-languages-goodies.lmt @@ -0,0 +1,99 @@ +if not modules then modules = { } end modules ['s-languages-goodies'] = { + version = 1.001, + comment = "companion to s-languages-goodies.mkxl", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +moduledata.languages = moduledata.languages or { } +moduledata.languages.goodies = moduledata.languages.goodies or { } + +function moduledata.languages.goodies.show(specification) + specification = interfaces.checkedspecification(specification) + local filename = specification.file + if filename and filename ~= "" then + local list = table.load(resolvers.findfile(filename)) + if list then + list = list.options + if list then + for i=1,#list do + local l = list[i] + local w = l.words + if w then + local pre = l.prefixes + local suf = l.suffixes + context.startsubject { title = table.concat(table.sortedkeys(l.patterns)," ") } + context(languages.strippedgoodiewords(w)) + if pre then + context.blank() + context.bold("prefixes: ") + context(languages.strippedgoodiewords(pre)) + end + if suf then + context.blank() + context.bold("suffixes: ") + context(languages.strippedgoodiewords(suf)) + end + context.stopsubject() + end + end + end + end + end +end + +local lpegmatch = lpeg.match + +moduledata.languages.goodies.ligaturehandlers = { } + +function moduledata.languages.goodies.ligatures(specification) + + specification = interfaces.checkedspecification(specification) + local language = specification.language + local filename = specification.file + + if not language then + elseif moduledata.languages.goodies.ligaturehandlers[language] then + else + -- fb ff ffb fff ffh ffi ffj ffk ffl fft fi fk fl ft + local list = specification.list or "ff fi fl ffi fff ffl" + local hash = table.tohash(lpeg.split(" ",list)) -- also strip + local pattern = (1-lpeg.utfchartabletopattern(hash))^1 * lpeg.P(-1) + local checked = { } + + moduledata.languages.goodies.ligaturehandlers[language] = function(original) + if not checked[original] and not lpegmatch(pattern,original) then + checked[original] = true + end + return original + end + + languages.installhandler(language,"moduledata.languages.goodies.ligaturehandlers." .. language .. "") + + statistics.register(string.formatters["'% t' ligatures checked for language %a"](table.sortedkeys(hash), language), function() + return next(checked) and table.concat(table.sortedkeys(checked)," ") or nil + end) + + local applied = languages.appliedoptions[language] + + trackers.enable("languages.applied") + + if applied then + statistics.register(string.formatters["options applied for language %a"](language), function() + return next(applied) and table.concat(table.sortedkeys(applied)," ") or nil + end) + statistics.register(string.formatters["missed ligatures for language %a"](language), function() + for k, v in next, applied do + checked[k] = nil + end + for k, v in next, hash do + checked[k] = nil + end + return next(checked) and table.concat(table.sortedkeys(checked)," ") or nil + end) + end + + end + +end diff --git a/tex/context/modules/mkxl/s-languages-goodies.mkxl b/tex/context/modules/mkxl/s-languages-goodies.mkxl new file mode 100644 index 000000000..3ced071be --- /dev/null +++ b/tex/context/modules/mkxl/s-languages-goodies.mkxl @@ -0,0 +1,144 @@ +%D \module +%D [ file=s-languages-goodies, +%D version=2021.25.03, +%D title=\CONTEXT\ Style File, +%D subtitle=Language Goodies, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\startmodule[languages-goodies] + +\registerctxluafile{s-languages-goodies}{autosuffix} + +\installmodulecommandluasingle \showlanguagegoodies {moduledata.languages.goodies.show} +\installmodulecommandluasingle \showlanguageligatures {moduledata.languages.goodies.ligatures} + +\stopmodule + +\continueifinputfile{s-languages-goodies.mkxl} + +% Beware, for now this file is a playground so what gets rendered +% can differ per upload. + +\usemodule[art-01] + +% \setupbodyfont[libertine] + +\setuplanguage[de][goodies={lang-de.llg}] +\setuplanguage[en][goodies={lang-en.llg}] + +\mainlanguage[de] + +% \setupalign[stretch,verytolerant,flushleft] \dontcomplain + +% \startlanguageoptions[de] +% Zapf|innovation +% \stoplanguageoptions + +% \tracinghyphenation3 \tracingonline2 + +\starttext + + \start +% \setupalign[stretch,verytolerant,flushleft,nothyphenated] \dontcomplain + +% \showlanguageligatures[language=de,list=ff fi fl fk ft fb ffi ffl fff ffk fft ffb ffh ffj] +% \showlanguageligatures[language=en,list=ff fi fl fk ft fb ffi ffl fff ffk fft ffb ffh ffj] + +% \starttitle[title={DE}] +% \start \de \showlanguagegoodies [file={lang-de.llg}] \stop +% \stoptitle + +% \starttitle[title={EN}] +% \start \en \showlanguagegoodies[file={lang-en.llg}] \stop +% \stoptitle + + \page + + \stop + + % oeps effe + % nonexistentffitestcase + % nonexistentffltestcase + + \enabletrackers[languages.goodies,languages.applied] + + \start \de \dontcomplain + +% general + +% 0 : ignore +% 1 : invisible % {}{}{} +% 2 : no break % {}{}{}[9] +% 3 : pre % {-}{}{} +% 4 : pre replace % {-}{}{-} +% 5 : post % {}{-}{} +% 6 : post replace % {}{-}{-} +% 7 : pre post % {-}{-}{} +% 8 : pre post replace % {-}{-}{-} + +% \codedef\hccode +% \codedef\hycode + +% \hccode"002D = "2010 \hycode"002D = "0 % hyphen minus +% \hccode"00AD = "0000 \hycode"00AD = "1 % soft hyphen +% \hccode"2010 = "2010 \hycode"2010 = "0 % hyphen +% \hccode"2011 = "2010 \hycode"2011 = "2 % non breaking hyphen +% \hccode"2012 = "2012 \hycode"2012 = "0 % figure dash +% \hccode"2013 = "2013 \hycode"2013 = "0 % en dash +% \hccode"2014 = "2014 \hycode"2014 = "0 % em dash + + +% \permanent\protected\def\cwm{\discretionary preword postword{-}{}{-}} +% \tracingonline2 \tracinghyphenation2 + +% One can map to exhyphenchar and use a pre/post for that one but if +% really needed \hbcode (before=pre) and \hacode (after=post) can be +% introduced. Maybe only settable runtime via lua. + +\hccode"002D = "002D +\hccode"2010 = "2010 +\hccode"2013 = "2013 +\hccode"2014 = "2014 + +% Offline\cwm Anwendungen\par +% {\hsize 1mm Offline\cwm Anwendungen\par} +% Offline-Anwendungen\par +% Offline{\char"2010}Anwendungen\par +% {\hsize 1mm Offline-Anwendungen\par} +% {\hsize 1mm Offline{\char"2010}Anwendungen\par} +% {\hsize 1mm Offline{\endash}Anwendungen\par} +% {\hsize 1mm Offline{\emdash}Anwendungen\par} + {\hsize 3mm \emdash Offline-Anwendungen\emdash\par} + {\hsize 3mm \emdash\wordboundary Offline-Anwendungen\wordboundary\emdash\par} + {\hsize 3mm \quotation{Offline-Anwendungen}\par} + {\hsize 3mm „Offline-Anwendungen“\par} + {\hsize 3mm -Offline-Anwendungen-\par} + +% OfflineAnwendungen\par +% {\hsize 1mm OfflineAnwendungen\par} +% Offline\par +% {\hsize 1mm Offline\par} + + +% \hyphenationmode\bitwiseflip\hyphenationmode-\forcehandlerhyphenationmodecode + +% \de \dontcomplain + +% \startexceptions[de] +% multi-cul-ti{-}{}{-}word{-}{}{-}boun-daries +% \stopexceptions + +% {multiculti-word-boundaries\par} +% {multicultiwordboundaries\par} +% {\hsize 1mm multicultiwordboundaries\par} +% {\hsize 1mm multiculti-word-boundaries\par} +% {\hsize 1mm multiwordboundaries\par} + + \stop +\stoptext diff --git a/tex/context/modules/mkxl/s-system-macros.mkxl b/tex/context/modules/mkxl/s-system-macros.mkxl new file mode 100644 index 000000000..605859000 --- /dev/null +++ b/tex/context/modules/mkxl/s-system-macros.mkxl @@ -0,0 +1,330 @@ +%D \module +%D [ file=s-system-tokens.mkxl, +%D version=2020.06.02, +%D title=\CONTEXT\ Style File, +%D subtitle=System Tokens Checking, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +%D This file is for Wolfgang and Hans and it's used in the transition from \MKIV\ +%D to the more robust \LMTX. + +% todo: \permanent\protected\let\select\directselect : same value (add ref) +% +% todo: when mutable, remove immutable, decide on how immutable it really is +% +% todo: just for the fun of it we can compare the table generated here to mkiv but it +% needs the same hash exposure as we use in luametatex so i'll do that after all lmtx +% macros are checked (maybe i need to backport some more but it has a low priority) +% +% todo: do we need something similar for lua functions etc (problem: performance hit) +% +% todo: and how about metapost ... i need a mp.hashtokens in order to do that and I also +% need to think about protection there (tricky as we use an avl hash there) +% +% public undefined : SmallCaps scitebuffer sciteinlinebuffer +% single todos : \ \- \\ \_ + +\enablemode[texmacros] +\enablemode[metapostmacros] +% \enablemode[notmarked] +\enablemode[everything] + +\startmodule[system-macros] + +\continueifinputfile{s-system-macros.mkxl} + +% \usemodule[article-basic] \setuplayout[tight] \setupbodyfont[7pt,tt] +\usemodule[article-basic] \setuplayout[tight] \setupbodyfont[5pt,tt] + +\setupbackgrounds[page][background=color,backgroundcolor=darkgray] \setupcolors[textcolor=white] + +\setuppapersize + [A4,landscape] + [A4,landscape] + +\starttext + +\startluacode + + if tex.modes.texmacros then + + local context = context + local ctx_NC = context.NC + local ctx_NR = context.NR + local ctx_bold = context.bold + local ctx_verb = context.verbatim + + local find = string.find + local gsub = string.gsub + local create = tokens.create + + local crap = "[$>%|%&%#" .. string.char(0xEF) .. "]" + + local basefile = resolvers.findfile("context.mkxl") + local swapnames = { } + + local pattern = file.join(file.pathpart(basefile),"/*.mk*") + local filenames = dir.glob(pattern) + for i=1,#filenames do + swapnames[file.basename(filenames[i])] = true + end + + local pattern = file.join(file.pathpart(basefile),"/*.l**") + local filenames = dir.glob(pattern) + for i=1,#filenames do + swapnames[file.basename(filenames[i])] = true + end + + local hashnames = table.setmetatableindex(function(t,k) + local s = file.suffix(k) + local v = k + if s == "mkiv" then + local n = file.replacesuffix(k,"mkxl") + if swapnames[n] then + v = n + end + elseif s == "mkvi" then + local n = file.replacesuffix(k,"mklx") + if swapnames[n] then + v = n + end + elseif s == "lua" then + local n = file.replacesuffix(k,"lmt") + if swapnames[n] then + v = n + end + end + t[k] = v + return v + end) + + require("mtx-interface") + + local data = scripts.interface.editor("data") + local files = data and data.common and data.common.filenames or { } + local macros = { } + local flagged = 0 + local total = 0 + local list = tex.hashtokens() + local all = not tex.modes.notmarked + local everything = tex.modes.everything + + local fmtname = resolvers.locateformat("cont-en.fmt") + if fmtname then + local logname = file.replacesuffix(fmtname,"log") + for filename in string.gmatch(io.loaddata(logname),"fullname=(%S+)") do + local s = file.suffix(filename) + local b = file.basename(filename) + if s ~= "lua" and s ~= "lmt" then + local d = io.loaddata(filename) + for m in string.gmatch(d,"\n[\\a-z]*[exg]*def\\([a-zA-Z_]+)") do + macros[m] = b + end + for m in string.gmatch(d,"\n[\\a-z]*[g]*let\\([a-zA-Z_]+)") do + macros[m] = b + end + end + end + end + + table.sort(list) + + local function show(visible, check) + -- context.starttabulate { "|l|l|l|lj2|l|l|l|l|l|l|l|l|" } + context.starttabulate { "|l|l|l|lj2|l|l|l|l|l|l|l|l|" } + for i=1,#list do + local k = list[i] + if check(k) then + local v = create(k) + local mutable = v.mutable and "mutable" + local immutable = v.immutable and "immutable" + local frozen = v.frozen and "frozen" + local permanent = v.permanent and "permanent" + local primitive = v.primitive and "primitive" + local instance = v.instance and "instance" + local dealtwith = mutable or immutable or mutable or frozen or permanent or primitive -- beware: we can have combinations + local whatever = find(k,"^[a-z][a-z][a-z]+_") + local cscommand = gsub(v.cmdname or "","_"," ") + local undefined = cscommand == "undefined cs" + local marked = (dealtwith and "+") or (whatever and "-") or (instance and "!") + if everything or ((all or not marked) and not find(k,"^[pvm]_") and not find(k,"^![tT]")) then + local parameters = v.parameters + local noaligned = v.noaligned and "noaligned" + local filename = files[k] or macros[k] + local csname = context.escape(k) + if undefined then + marked = "?" + end + ctx_NC() if marked then context(marked) end + ctx_NC() if primitive then ctx_bold(csname) else + ctx_verb(csname) end + ctx_NC() if parameters then context(parameters > 0 and parameters or "-") end + ctx_NC() if undefined then context.red(false) end + context(cscommand) + ctx_NC() if primitive then context(primitive) end + ctx_NC() if permanent then context(permanent) end + ctx_NC() if immutable then context(immutable) end + ctx_NC() if frozen then context(frozen) end + ctx_NC() if mutable then context(mutable) end + ctx_NC() if instance then context(instance) end + ctx_NC() if noaligned then context(noaligned) end + ctx_NC() if filename then context(hashnames[filename]) end + ctx_NC() ctx_NR() + end + if visible then + total = total + 1 + if dealtwith then + flagged = flagged + 1 + end + end + end + end + context.stoptabulate() + end + + context.starttitle { title = "Public \\TEX\\ commands" } + show(true, function(k) return find(k,"^[a-zA-Z]+$") end) + context.stoptitle() + + context.starttitle { title = "Private \\TEX\\ commands" } + show(false, function(k) return not find(k,"^[a-zA-Z]+$") and not find(k,crap) end) + context.stoptitle() + + tokens.setters.macro("NumberOfVisible", total) + tokens.setters.macro("NumberOfFlagged", flagged) + + end + +\stopluacode + +\startmode[texmacros] + + \page + + \starttabulate[|c|l|] + \HL + \NC \type {+} \NC mutable, immutable, frozen, permanent, primitive \NC \NR + \NC \type {-} \NC protected by obscurity (underscores) \NC \NR + \NC \type {!} \NC instance (can be frozen) \NC \NR + \NC \type {0-9} \NC the number of arguments (argument grabbing can be delegated) \NC \NR + \HL + \stoptabulate + + \start \hsize 15cm \veryraggedright + Often frozen commands are redefined on demand and they can be overloaded. Mutable + doesn't mean that a user can change it without consequences, for instance the + \type {\current...} ones. Primitives come with the engine, permanent macros are + the core of \CONTEXT. Noaligned macros are special and dealt deep down when + scanning for alignment specific primitives. + \par \stop + + \starttabulate[||r|] + \BC number of visible macros \NC \NumberOfVisible \NC \NR + \BC number of flagged macros \NC \NumberOfFlagged \NC \NR + \stoptabulate + +\stopmode + +\page + +\startluacode + + if tex.modes.metapostmacros then + + local context = context + -- local ctx_NC = context.NC + -- local ctx_NR = context.NR + -- local ctx_bold = context.bold + + local find = string.find + local gsub = string.gsub + local create = tokens.create + + context.starttitle { title = "\\METAFUN\\ commands" } + + metapost.simple("prestine") + + local mptotal = 0 + local codes = metapost.codes + local types = metapost.types + local parameters = metapost.knownparameters + local procodes = mplib.propertycodes + local everything = tex.modes.everything + + context.startcolumns { n = 5, distance = "1em" } + context.nohyphens(false) + context.obeyspaces(false) + local t = metapost.gethashentries("prestine",true) -- prestine:1 + if t then + table.sort(t,function(a,b) return a[3] < b[3] end) + mptotal = #t + for i=1,mptotal do + local ti = t[i] + local code = codes[ti[1]] + local property = procodes[ti[2]] + local name = ti[3] + local vtype = ti[4] + local vardef = vtype and types[vtype] == "unsuffixedmacro" + context.bgroup() + -- context("%-15s\\quad",vardef and "(vardef) tag" or code) + context("%s %-15s\\quad",parameters[name] and "+" or "\\nbsp",vardef and "(vardef) tag" or code) + if property == "primitive" then + context.bf(false) + context.blue(false) + elseif property == "permanent" then + context.bf(false) + context.lightgreen(false) + elseif property == "immutable" then + context.bf(false) + context.lightcyan(false) + elseif property == "mutable" then + context.bf(false) + context.lightmagenta(false) + elseif everything or not find(name,"^%a+_") then + -- todo: + if vardef then + context.bf(false) + context.lightred(false) + end + end + context.verbatim(name) + context.egroup() + context.par() + end + end + context.stopcolumns() + + context.stoptitle() + + tokens.setters.macro("NumberOfMetafun", mptotal) + + end +\stopluacode + +\startmode [metapostmacros] + + \page + + \starttabulate[|c|l|] + \HL + \NC \type {-3} \NC \bf \lightmagenta mutable \NC \NR + \NC \type {1} \NC \bf \blue primitive \NC \NR + \NC \type {2} \NC \bf \lightgreen permanent \NC \NR + \NC \type {3} \NC \bf \lightcyan immutable \NC \NR + \NC \type {+} \NC \bf (also) used as key \NC \NR + \HL + \stoptabulate + + \starttabulate[||r|] + \BC number of metafun entries \NC \NumberOfMetafun \NC \NR + \stoptabulate + +\stopmode + +\stopmodule diff --git a/tex/context/modules/mkxl/s-system-tokens.mkxl b/tex/context/modules/mkxl/s-system-tokens.mkxl new file mode 100644 index 000000000..b83a4f47b --- /dev/null +++ b/tex/context/modules/mkxl/s-system-tokens.mkxl @@ -0,0 +1,84 @@ +%D \module +%D [ file=s-system-tokens.mkxl, +%D version=2020.06.02, +%D title=\CONTEXT\ Style File, +%D subtitle=System Tokens Checking, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\startmodule[system-tokens] + +\registerctxluafile{s-system-tokens}{} + +\permanent\protected\def\showsystemtokens{\ctxlua{moduledata.system.tokens.showlist()}} % can be public implementor + +\stopmodule + +\continueifinputfile{s-system-tokens.mkxl} + +\usemodule[article-basic] + +\setuppapersize[A4,landscape] + +\setuplayout[tight] + +\setupbodyfont[8pt] + +\starttext + + \showsystemtokens + + Some tokens cannot be created yet because they are more complex but eventually the creator will + deal with them. The indices are sometimes the same as internal but in most cases nicely start + at zero. When they start at another value, then there is an internal token or state that is not + user accessible. You always need to use symbolic constants as the numbers can change. + + The first column is a classifier (which is experimental and categories might change when we feel + the need). + + \startcolumns[n=5] + \starttabulate[|T||] + \NC 0 \NC unused \NC \NR + \NC 1 \NC regular \NC \NR + \NC 2 \NC character \NC \NR + \NC 3 \NC register \NC \NR + \NC 4 \NC internal \NC \NR + \NC 5 \NC reference \NC \NR + \NC 6 \NC data \NC \NR + \NC 7 \NC token \NC \NR + \NC 8 \NC node \NC \NR + \stoptabulate + \stopcolumns + + \page + + Here is a typeset table of \type {\startframed} using \type {\luatokentable\startframed}: + + \luatokentable\startframed + + which calls \type {\pack_framed_start_framed} where \type {\luatokentable\pack_framed_start_framed} gives: + + + \unprotect + \luatokentable\pack_framed_start_framed + \protect + + So you can guess what generates this: + + \unprotect + \luatokentable\pack_framed_start_framed_nop + \protect + + And this: + + \unprotect + \luatokentable\pack_framed_start_framed_yes + \protect + +\stoptext + diff --git a/tex/context/modules/mkxl/x-mathml.lmt b/tex/context/modules/mkxl/x-mathml.lmt new file mode 100644 index 000000000..ba05c002e --- /dev/null +++ b/tex/context/modules/mkxl/x-mathml.lmt @@ -0,0 +1,910 @@ +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. But ... it +-- probably doesn't pay back as no mathml support ever did. + +local type, next = type, next +local formatters, lower, find, gsub, match = string.formatters, string.lower, string.find, string.gsub, string.match +local strip = string.strip +local xmlsprint, xmlcprint, xmltext, xmlcontent, xmlempty = xml.sprint, xml.cprint, xml.text, xml.content, xml.empty +local lxmlcollected, lxmlfilter = lxml.collected, lxml.filter +local getid = lxml.getid +local utfchar, utfcharacters, utfsplit, utflen = utf.char, utf.characters, utf.split, utf.len +local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns +local P, Cs = lpeg.P, lpeg.Cs + +local mathml = { } +moduledata.mathml = mathml +lxml.mathml = mathml -- for the moment + +local context = context + +local ctx_enabledelimiter = context.enabledelimiter +local ctx_disabledelimiter = context.disabledelimiter +local ctx_xmlflush = context.xmlflush -- better xmlsprint + +local ctx_halign = context.halign +local ctx_noalign = context.noalign +local ctx_bgroup = context.bgroup +local ctx_egroup = context.egroup +local ctx_crcr = context.crcr + +local ctx_bTABLE = context.bTABLE +local ctx_eTABLE = context.eTABLE +local ctx_bTR = context.bTR +local ctx_eTR = context.eTR +local ctx_bTD = context.bTD +local ctx_eTD = context.eTD + +local ctx_mn = context.mn +local ctx_mi = context.mi +local ctx_mo = context.mo +local ctx_startimath = context.startimath +local ctx_ignorespaces = context.ignorespaces +local ctx_removeunwantedspaces = context.removeunwantedspaces +local ctx_stopimath = context.stopimath + +local ctx_mmlapplycsymbol = context.mmlapplycsymbol + +local ctx_mathopnolimits = context.mathopnolimits +local ctx_left = context.left +local ctx_right = context.right + +-- 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 + +-- we can use the proper names now! todo + +local o_replacements = { -- in main table + ["@l"] = "\\mmlleftdelimiter.", + ["@r"] = "\\mmlrightdelimiter.", + ["{"] = "\\mmlleftdelimiter \\lbrace", + ["}"] = "\\mmlrightdelimiter\\rbrace", + ["|"] = "\\mmlleftorrightdelimiter\\vert", + -- ["."] = "\\mmlleftorrightdelimiter.", + ["/"] = "\\mmlleftorrightdelimiter\\solidus", + [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 so we + ["_"] = "\\mmlchar{95}{}", -- need the {} ... has to do with active mess feedback into scanner + ["~"] = "\\mmlchar{126}", + [" "] = "", + ["°"] = "^\\circ", -- hack + + -- [utfchar(0xF103C)] = "\\mmlleftdelimiter<", + [utfchar(0xF1026)] = "\\mmlchar{38}", + [utfchar(0x02061)] = "", -- function applicator sometimes shows up in font + -- [utfchar(0xF103E)] = "\\mmlleftdelimiter>", + -- [utfchar(0x000AF)] = '\\mmlchar{"203E}', -- 0x203E +} + +local simpleoperatorremapper = utf.remapper(o_replacements) + +--~ languages.data.labels.functions + +local i_replacements = { + ["sin"] = "\\sin", + ["cos"] = "\\cos", + ["abs"] = "\\abs", + ["arg"] = "\\arg", + ["codomain"] = "\\codomain", + ["curl"] = "\\curl", + ["determinant"] = "\\det", + ["divergence"] = "\\div", + ["domain"] = "\\domain", + ["gcd"] = "\\gcd", + ["grad"] = "\\grad", + ["identity"] = "\\id", + ["image"] = "\\image", + ["lcm"] = "\\lcm", + ["lim"] = "\\lim", + ["max"] = "\\max", + ["median"] = "\\median", + ["min"] = "\\min", + ["mode"] = "\\mode", + ["mod"] = "\\mod", + ["polar"] = "\\Polar", + ["exp"] = "\\exp", + ["ln"] = "\\ln", + ["log"] = "\\log", + ["sin"] = "\\sin", + ["arcsin"] = "\\arcsin", + ["sinh"] = "\\sinh", + ["arcsinh"] = "\\arcsinh", + ["cos"] = "\\cos", + ["arccos"] = "\\arccos", + ["cosh"] = "\\cosh", + ["arccosh"] = "\\arccosh", + ["tan"] = "\\tan", + ["arctan"] = "\\arctan", + ["tanh"] = "\\tanh", + ["arctanh"] = "\\arctanh", + ["cot"] = "\\cot", + ["arccot"] = "\\arccot", + ["coth"] = "\\coth", + ["arccoth"] = "\\arccoth", + ["csc"] = "\\csc", + ["arccsc"] = "\\arccsc", + ["csch"] = "\\csch", + ["arccsch"] = "\\arccsch", + ["sec"] = "\\sec", + ["arcsec"] = "\\arcsec", + ["sech"] = "\\sech", + ["arcsech"] = "\\arcsech", + [" "] = "", + + ["false"] = "{\\mathrm false}", + ["notanumber"] = "{\\mathrm NaN}", + ["otherwise"] = "{\\mathrm otherwise}", + ["true"] = "{\\mathrm true}", + ["declare"] = "{\\mathrm declare}", + ["as"] = "{\\mathrm 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 + +local p_entity = (P("&") * ((1-P(";"))^0) * P(";")) +local p_utfchar = lpegpatterns.utf8character +local p_spacing = lpegpatterns.whitespace^1 + +local p_mn = Cs((p_entity/"" + p_spacing/utfchar(0x205F) + p_utfchar/n_replacements)^0) +local p_strip = Cs((p_entity/"" + p_utfchar )^0) +local p_mi = Cs((p_entity/"" + p_utfchar/i_replacements)^0) + +function mathml.mn(id) + -- maybe at some point we need to interpret the number, but + -- currently we assume an upright font + ctx_mn(lpegmatch(p_mn,xmlcontent(getid(id)) or "")) +end + +function mathml.mo(id) + local str = lpegmatch(p_strip,xmlcontent(getid(id)) or "") + context(simpleoperatorremapper(str) or str) +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) == "table" then + local n = #str + if n == 0 then + -- nothing to do + elseif n == 1 then + local first = str[1] + if type(first) == "string" then + -- local str = gsub(first,"&.-;","") -- bah + -- local rep = i_replacements[str] + -- if not rep then + -- rep = gsub(str,".",i_replacements) + -- end + local str = lpegmatch(p_strip,first) + local rep = i_replacements[str] or lpegmatch(p_mi,str) + context(rep) + -- ctx_mi(rep) + else + ctx_xmlflush(id) -- xmlsprint or so + end + else + ctx_xmlflush(id) -- xmlsprint or so + end + else + ctx_xmlflush(id) -- xmlsprint or so + end +end + +function mathml.mfenced(id) -- multiple separators + id = getid(id) + local at = id.at + local left = at.open or "(" + local right = at.close or ")" + local separators = at.separators or "," + local l = l_replacements[left] + local r = r_replacements[right] + ctx_enabledelimiter() + if l then + context(l_replacements[left] or o_replacements[left] or "") + else + context(o_replacements["@l"]) + context(left) + end + ctx_disabledelimiter() + local collected = lxmlfilter(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 = utfsplit(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 + ctx_enabledelimiter() + if r then + context(r_replacements[right] or o_replacements[right] or "") + else + context(right) + context(o_replacements["@r"]) + end + ctx_disabledelimiter() +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 lxmlcollected(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 lxmlcollected(id,"/*") do + local tag = e.tg + if tag == "mprescripts" then + break + elseif done then + toggle = flush(e,tag,toggle) + else + xmlsprint(e) + 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 = lpegmatch(p_strip,str) + for s in utfcharacters(str) do + m[#m+1] = { tag, s } + end + if tag == "mn" then + local n = utflen(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 lxmlcollected(root,"/*") do + local m = { } + matrix[#matrix+1] = m + if e.tg == "mrow" then + -- only one level + for e in lxmlcollected(e,"/*") do + collect(m,e) + end + else + collect(m,e) + end + end + ctx_halign() + ctx_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 + ctx_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 + ctx_crcr() + end + ctx_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 + + ctx_bTABLE { frame = frametypes[frame or "none"] or "off", offset = framespacing, background = "" } -- todo: use xtables and definextable + for e in lxmlcollected(root,"/(mml:mtr|mml:mlabeledtr)") do + ctx_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 lxmlcollected(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 = at.rowspan or 1 + local columnspan = 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" + ctx_bTD { align = formatters["{%s,%s}"](cra,cca), frame = cfr, nx = columnspan, ny = rowspan } + if xmlempty(e,".") then + -- nothing, else hsize max + else + ctx_startimath() + -- ctx_ignorespaces() + xmlcprint(e) + -- ctx_removeunwantedspaces() + ctx_stopimath() + end + ctx_eTD() + end + end + -- if e.tg == "mlabeledtr" then + -- ctx_bTD() + -- xmlcprint(xml.first(e,"/!mml:mtd")) + -- ctx_eTD() + -- end + ctx_eTR() + end + ctx_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 "") + ctx_mmlapplycsymbol(full,base,encoding,text) +end + +local p = lpeg.Cs(((1-lpegpatterns.whitespace)^1 / "mml:enclose:%0" + (lpegpatterns.whitespace^1)/",")^1) + +function mathml.menclosepattern(root) + root = getid(root) + local a = root.at.notation + if a and a ~= "" then + context(lpegmatch(p,a)) + 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 + ctx_mathopnolimits("Polar") + ctx_left(false,"(") + for k=1,#dt do + local dk = dt[k] + if xml.is_element(dk,"sep") then + context(",") + else + xmlsprint(dk) + end + end + ctx_right(false,")") +end + +-- crap .. maybe in char-def a mathml overload + +local mathmleq = { + [utfchar(0x00AF)] = utfchar(0x203E), +} + +function mathml.extensible(chr) + context(mathmleq[chr] or chr) +end + +-- + +local function install(name,action) + interfaces.implement { + name = name, + public = true, + -- protected = true, -- some definitely not ! + arguments = "argument", + actions = action, + } +end + +install("mathml_mi", mathml.mi) +install("mathml_mo", mathml.mo) +install("mathml_mn", mathml.mn) +install("mathml_mfenced", mathml.mfenced) +install("mathml_mmultiscripts", mathml.mmultiscripts) +install("mathml_menclosepattern", mathml.menclosepattern) +install("mathml_mtable", mathml.mtable) +install("mathml_mcolumn", mathml.mcolumn) +install("mathml_extensible", mathml.extensible) + +install("mathml_csymbol", mathml.csymbol) +install("mathml_cpolar_a", mathml.cpolar_a) + +install("mathml_cpolar_extensible", mathml.cpolar_extensible) diff --git a/tex/context/modules/mkxl/x-mathml.mkxl b/tex/context/modules/mkxl/x-mathml.mkxl new file mode 100644 index 000000000..fbfc17883 --- /dev/null +++ b/tex/context/modules/mkxl/x-mathml.mkxl @@ -0,0 +1,2448 @@ +%D \module +%D [ file=x-mathml, +%D version=2008.05.29, (evolved from pre 2000 code) +%D title=\CONTEXT\ XML Modules, +%D subtitle=\MATHML, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +% \xmlfilter{#1}{/*/name()} -> \xmltag + +% This implementation looks like a hack ... this is because we deal with all weird +% cases we ran into, including abuse that was supposed to render ok (even if it +% didn't in other renderers) .. it was simply expected to work that way. It is also +% the product of stepwise adaptation to what we run into. And that in turn is often +% determined by the tools that were used to produce the \XML. Even worse is the +% cycling between coding that happens in projects: from content\ \MATHML\ to +% OpenMath to asciimath to presentation \MATHML\ to \unknown\ which all depends on +% what tools are available to render in a browser (where first \MATHML\ was hardly +% supported, then became accepted, then was taken over by mathjax, then merged with +% other input methods and who knopws what comes next in these days where technologies +% are shortlived and the next best thing is already waiting around the corner. +% +% So, consider this module to be under constant construction and clean up. We still +% use a funny mix of xml, tex and lua. I could rewrite the lot but it also shows +% how context evolves. I might end up with a lua-only implementation some day, but +% I must find a real good reason to spend time on it as so far it never paid back. +% As far as I can tell, publishers have never shown much (real) interest anyway or +% at least I haven't met one who cared to invest in it. If they run into \MATHML\ +% they just expect it to be supported. +% +% This variant is adapted to \LMTX\ and might evolve with upcoming variations of +% the standard. As with \SVG\ and probably other \XML\ definitions that target a +% specific domain, \MATHML\ is now more just something for browsers and \HTML\ +% usage (although support fluctuates). It's getting less generic (or at least we +% see no more structural elements showing up) and with \CSS\ becoming the +% recomended way to control local optimizations it indeed looks like only browsers +% are the target, unless we can just ignore all that. Limitations of renderers, +% specific usage, application determined \XML\ ... where will it end. All we can do +% is follow and try to keep up, but maybe the more web it becomes, the less \TEX\ +% users need to care (read: can stick to \TEX\ coding). +% +% See the \MKII\ and \MKIV\ files for a history and the hacks we had to use in +% the past. + +\writestatus{loading}{ConTeXt XML Macros / MathML Renderer} + +\unprotect + +\usemodule[x][calcmath] +%usemodule[x][asciimath] + +\startmodule [mathml] + +\registerctxluafile{x-mathml}{autosuffix} + +\setupxml[\c!entities=\v!yes] % load big entities table + +\def\ctxmodulemathml#1{\ctxlua{moduledata.mathml.#1}} + +\startxmlsetups xml:mml:define + \xmlsetsetup{#1} {(formula|subformula)} {mml:formula} + \xmlfilter {#1} {omt:*/function(remapopenmath)} + \xmlfilter {#1} {mml:bind/function(remapmmlbind)} + \xmlfilter {#1} {mml:csymbol/function(remapmmlcsymbol)} + \xmlsetsetup{#1} {mml:*} {mml:*} + \xmlsetsetup{#1} {mml:apply/mml:apply/mml:inverse/../..} {mml:apply:inverse} + \xmlstrip {#1} {(mml:mi|mml:mo|mml:mn|mml:csymbol)} +\stopxmlsetups + +\xmlregisterns{omt}{openmath} +\xmlregisterns{mml}{mathml} + +\xmlregistersetup{xml:mml:define} + +\xmlmapvalue {mml:math:mode} {display} {\displaymathematics} % we had this already +\xmlmapvalue {mml:math:mode} {inline} {\inlinemathematics } + +\xmlmapvalue {mml:math:display} {block} {\displaymathematics} % before this showed up +\xmlmapvalue {mml:math:display} {inline} {\inlinemathematics } + +\xmlmapvalue {mml:math:dir} {ltr} {\setfalse\c_math_right_to_left\math_basics_synchronize_direction} +\xmlmapvalue {mml:math:dir} {rtl} {\settrue \c_math_right_to_left\math_basics_synchronize_direction} + +\edef\mmlconstantone {1} +\edef\mmlconstantfalse{false} + +\startxmlsetups mml:math + \begingroup + \enableautofences + \enableautofencemode + \xmlval {mml:math:dir} {\xmlatt{#1}{dir}} {} + \xmlval {mml:math:display} {\xmlatt{#1}{display}} { + \xmlval {mml:math:mode} {\xmlatt{#1}{mode}} { + \automathematics + } + } + { + \xmlflush{#1} + } + \endgroup +\stopxmlsetups + +\startxmlsetups mml:imath + \inlinemathematics { + \enableautofences + \enableautofencemode + \xmlflush{#1} + } +\stopxmlsetups + +\startxmlsetups mml:dmath + \displaymathematics { + \enableautofences + \enableautofencemode + \xmlflush{#1} + } +\stopxmlsetups + +%D First we define some general formula elements. + +\startxmlsetups mml:formula + \edef\mmlformulaid {\xmlatt{#1}{id}} + \edef\mmlformulalabel {\xmlatt{#1}{label}\mmlformulaid} + \edef\mmlformulasublabel{\xmlatt{#1}{sublabel}\mmlformulaid} + \doifsomething\mmlformulalabel{\placeformula[\mmlformulalabel]{\mmlformulasublabel}} + \startformula + \xmlfirst{#1}{/mml:math} + \stopformula +\stopxmlsetups + + +\setfalse\mmlignoredelimiter % alternatively we could turn it on/off inside the start/stop and ignore \left\right\middle otherwise + +\let\mmlleftdelimiter \autofenceopen +\let\mmlmiddledelimiter \autofencemiddle +\let\mmlrightdelimiter \autofenceclose +\let\mmlleftorrightdelimiter\autofenceboth + +\def\mmlchar#1{\char#1 } % used in lua code + +%D The rendering macros: + +\def\MMLrm{\mr} + +\def\MMLseparator#1{\removeunwantedspaces{#1}\ignorespaces} % nils space after separator +\def\MMLseparator#1{,} % todo, for europe we need to block the space + +%D Since I only had the draft of MathML 2 and later 3 as example of rendering, there +%D are probably a lot of omissions and misinterpretations. At least I learned some +%D bits and pieces of math rendering. +%D +%D The main complications were not so much the math, but to find the most efficient +%D way to handle elements without spacing beging messed up. The first implementation +%D was aimed at getting reasonable output, this second implementation is already +%D better in terms of handling nesting, and I will definitely need a third one that +%D has more efficient and less ugly code. +%D +%D The \TEX\ part is not that complicated and once the preprocessor was okay, the +%D rest way just a lot of keying and testing. It all comes down to gobbling, +%D redefining, and not so much to parsing. +%D +%D The second implementation expanded the whole math sequence into an internal \TEX\ +%D representation. This is a rather clean and fast process. Filtering and testing +%D takes place by redefining the internal representation macros. +%D +%D The third implementation may look a bit more messy in some respects. This is +%D because in \TEX\ it's not that trivial to implement a tree handler. We use a +%D stack for the \type {apply} element and other sequential content. Occasionally we +%D need to peek into child elements which involves messy code. This implementation +%D is closer to the normal \XML\ handling in \CONTEXT. +%D +%D This fourth variant just improves on the third. It uses some tricks available in +%D \LUAMETATEX\ where we have extended the math machinery. + +%D We start with the parent elements and the option handler. + +\protected\def\xmlmathmldirective#1{\dosetvalue{MML#1}} + +\xmlinstalldirective{mathml}{xmlmathmldirective} + +%D In the styles, options can be set with: + +\protected\def\setupMMLappearance[#1]{\dodoubleargument\getparameters[MML#1]} % no @@ because passed to lua + +%D We will apply inner math to all bits and pieces made up by an \type {apply}. + +\def\MMLmathinner + {\ifinner + \expandafter\firstofoneargument + \else + \expandafter\mathinner + \fi} + +%D Auxiliary MathML macros: (to be generalized) + +\def\mmlfirst #1{\xmlelement{#1}{1}} % we can move these inline if needed +\def\mmlsecond #1{\xmlelement{#1}{2}} +\def\mmlthird #1{\xmlelement{#1}{3}} +\def\mmlprelast#1{\xmlelement{#1}{-2}} +\def\mmllast #1{\xmlelement{#1}{-1}} + +\starttexdefinition doifelsemmlfunction #1 + \xmldoifelse {#1} {/mml:fn} { + \firstoftwoarguments + } { + \xmldoifelse {#1} {/mml:apply/mml:fn} { + \firstoftwoarguments + } { + \xmldoifelse {#1} {/mml:ci[@type=='fn']} { + \firstoftwoarguments + } { + \secondoftwoarguments + } + } + } +\stoptexdefinition + +%D A couple of lists: + +\convertargument + mml:times|mml:divide|mml:power|% + mml:lt|mml:gt|mml:eq|mml:leq|mml:geq|% + mml:in|mml:inverse|% + mml:fn|% + mml:floor|mml:ceiling|% + mml:mean|% + mml:selector|% + mml:abs|mml:int|mml:limit|mml:sum|mml:product|% + mml:outerproduct|mml:innerproduct|mml:scalarproduct% +\to \MMLcmainresetlist + +\convertargument + mml:sin|mml:arcsin|mml:sinh|mml:arcsinh|% + mml:cos|mml:arccos|mml:cosh|mml:arccosh|% + mml:tan|mml:arctan|mml:tanh|mml:arctanh|% + mml:cot|mml:arccot|mml:coth|mml:arccoth|% + mml:csc|mml:arccsc|mml:csch|mml:arccsch|% + mml:sec|mml:arcsec|mml:sech|mml:arcsech|% + mml:ln|mml:exp|mml:log|% + mml:abs|mml:int|mml:limit|mml:sum|mml:product|% + mml:fn% +\to \MMLcfunctionlist + +\convertargument + mml:sin|mml:arcsin|mml:sinh|mml:arcsinh|% + mml:cos|mml:arccos|mml:cosh|mml:arccosh|% + mml:tan|mml:arctan|mml:tanh|mml:arctanh|% + mml:cot|mml:arccot|mml:coth|mml:arccoth|% + mml:csc|mml:arccsc|mml:csch|mml:arccsch|% + mml:sec|mml:arcsec|mml:sech|mml:arcsech|% + mml:ln|mml:exp|mml:log|% + mml:abs% +\to \MMLcpurefunctionlist + +\convertargument + mml:diff|mml:partialdiff|mml:root% +\to \MMLcconstructlist + +%D We use inner and grouping (begin/end and no b/e) else we get problems with +%D 1/2(1+2) and alike. The problem with apply is that we need to take care of +%D several situations, like: +%D +%D \starttyping +%D <apply> <.../> ... +%D <apply> <fn> ... +%D <apply> <apply> <ci> ... +%D <apply> <apply> <fn> <ci> ... +%D \stoptyping +%D +%D Because we translated version 2 of this renderer into version 3 the following +%D definitions may be sub optimal or more complex than actually needed. + +%D We will more more to lua ... + +% simple version + +\newcount\@MMLlevel \def\MMLcreset{\@MMLlevel\zerocount} + +\let\MMLctempresetlist\empty \def\setMMLcreset{\edef\MMLctempresetlist} + +\let\MMLdoL\donothing +\let\MMLdoR\donothing + +\newcount\mmlapplydepth \def\MMLcreset{\mmlapplydepth\zerocount} + +\startxmlsetups mml:apply + \MMLmathinner { + % \xmldoif {#1} {/(\MMLcmainresetlist\string|\MMLctempresetlist)} { + % \MMLcreset + % } + \edef\mmlapplyopentoken {\xmlatt{#1}{open}} + \edef\mmlapplyclosetoken{\xmlatt{#1}{close}} + \ifcase\mmlapplydepth + \orelse\ifempty\mmlapplyopentoken + \def\mmlapplyopentoken {(} + \def\mmlapplyclosetoken{)} + \fi + \advance\mmlapplydepth\plusone + \begingroup + \ifempty\mmlapplyopentoken + \let\MMLdoL\donothing + \let\MMLdoR\donothing + \else + \edef\MMLdoL{\noexpand\left \mmlapplyopentoken } + \edef\MMLdoR{\noexpand\right\mmlapplyclosetoken} + \fi + \let\MMLctempresetlist\empty + \xmldoifelse {#1} {/mml:apply} { +% % <apply> <apply> ... </apply> <ci> .. </ci> </apply> +% \xmldoifelse {#1} {/mml:apply(mml:plus|mml:minus)} {% [a] +% % yet incomplete and rather untested +% % <apply> <apply> <minus/> <tan/> <cos/> </apply> <ci>x</ci> </apply> + } {% [b] +% \MMLcreset + } +% \MMLdoL +% \mmlfirst{#1} +% \ifconditional\somepostponedMMLactions +% \postponedMMLactions +% \else +% \left(\MMLcreset\mmlsecond{#1}\right) +% \fi +% \MMLdoR +% } { + \edef\mmlapplyaction{\xmlfilter{#1}{/*/tag()}} + \doifelsesetups {mml:apply:mml:\mmlapplyaction} { + \xmlsetup{#1}{mml:apply:mml:\mmlapplyaction} + } { +% \MMLdoL + \xmlsetup{#1}{mml:\mmlapplyaction} +% \MMLdoR + } +% } + \endgroup + \advance\mmlapplydepth\minusone + } +\stopxmlsetups + +\startxmlsetups mml:apply:mml:apply + \xmlflush{#1} + \xmlall{#1}{../[position()>1]} +\stopxmlsetups + +\startxmlsetups mml:apply:mml:fn + \xmldoifelse {#1} {/mml:fn/mml:ci} { + \edef\mmlfnci{\xmlstripped{#1}{/mml:fn/mml:ci}} + \doifelsesetups{mmc:fn:\mmlfnci} { + \xmlsetup{#1}{mmc:fn:\mmlfnci} + } { + \MMLcreset + \MMLdoL + \mmlfirst{#1} + \ifnum\xmlcount{#1}{/*}>\plusone + \negthinspace % not enough + \left(\MMLcreset\xmlconcatrange{#1}{/*}{2}{}{\MMLseparator,}\right) + \fi + \MMLdoR + } + } { + \MMLcreset + \MMLdoL + \xmlall{#1}{/*} + \MMLdoR + } +\stopxmlsetups + +\startxmlsetups mml:apply:mml:csymbol + \xmlsetup{#1}{mml:csymbol}% \MMLdoL/MMLdoR to be handled in plugin +\stopxmlsetups + +\startxmlsetups mml:apply:mml:ci + \xmlfirst{#1}{/mml:ci} + \ifnum\xmlcount{#1}{/*}>\plusone + \left(\MMLcreset\xmlconcatrange{#1}{/*}{2}{}{\MMLseparator,}\right) + \fi +\stopxmlsetups + +% reln + +\startxmlsetups mml:reln + \writestatus{XML}{MathML element "reln" is obsolete} +\stopxmlsetups + +% fn + +% plusminus ± + +\startxmlsetups mmc:fn:\utfchar{"00B1} + \MMLdoL + \xmlconcat{#1}{/[position()>1]}{\utfchar{"00B1}} + \MMLdoR +\stopxmlsetups + +% minusplus + +\startxmlsetups mmc:fn:\utfchar{"2213} + \MMLdoL + \xmlconcat{#1}{/[position()>1]}{\utfchar{"2213}} + \MMLdoR +\stopxmlsetups + +\startxmlsetups mmc:fn + \begingroup + \edef\mmlnoffn{\xmlcount{#1}{/*}} + \ifnum\mmlnoffn>\plustwo + \def\MMCfnleft {\left(} + \def\MMCfnright{\right)} + \else + \let\MMCfnleft \relax + \let\MMCfnright\relax + \fi + \xmldoifelse {#1} {/mml:ci} { + \edef\mmlfnci{\xmltext{#1}{/mml:ci}} + \doifelsesetups{mmc:fn:\mmlfnci} { + \xmlsetup{#1}{mmc:fn:\mmlfnci} + } { + \MMLcreset + \mmlfirst{#1} + } + } { + \xmldoifelse {#1} {/mml:apply} { + \xmldoifelse {#1} {/(mml:plus\string|mml:minus)} { + \left(\mmlfirst{#1}\right) + } { + \mmlfirst{#1} + } + \ifnum\mmlnoffn>\plusone + \left(\xmlall{#1}{/!mml:apply}\right) + \fi + } { + \MMLcreset + \negthinspace + \MMCfnleft + \ifnum\mmlnoffn=\plustwo,\fi + \xmlconcat{#1}{/*}{2}{}{\MMLseparator,} + \MMCfnright + } + } + \endgroup +\stopxmlsetups + +\startxmlsetups mmc:fn:apply % where used? + \xmldoifelse {#1} {/mml:ci} { + \edef\mmlfnci{\xmltext{#1}{/mml:ci}} + \doifelsesetups{mmc:fn:\mmlfnci} { + \xmlsetup{#1}{mmc:fn:\mmlfnci} + } { + \MMLcreset + \mmlfirst{#1} + \ifnum\xmlcount{#1}{/*}>\plusone + \negthinspace + \left(\MMLcreset\xmlconcat{#1}{2}{}{\MMLseparator,}\right) + \fi + } + } { + \endgroup + \MMLcreset + \mmlfirst{#1} + } +\stopxmlsetups + +%D The next definition provide a kind of plug-in mechanism (see the open math +%D extension module). + +% http://www.publishers.com/somename +% +% called at the lua end + +\starttexdefinition mmlapplycsymbol #1#2#3#4 + % #1=full url, #2=name, #3=encoding, #4=text + \doifelse {#3} {text} { + \text{#4} + } { + \doifelsesetups {mml:csymbol:#1} { + % full url + \fastsetup{mml:csymbol:#1} + } { + % somename (fallback) + \doifelsesetups {mml:csymbol:#2} { + \fastsetup{mml:csymbol:#2} + } { + \xmlval{mmc:cs}{#3}{}% todo + } + } + } +\stoptexdefinition + +\startxmlsetups mml:csymbol + \mathml_csymbol{#1} +\stopxmlsetups + +\startxmlsetups mml:csymbol:cdots + \cdots +\stopxmlsetups + +% \startxmlsetups mml:csymbol:<url> \stopxmlsetups + +%D Alternative b will convert periods into comma's: + +\setupMMLappearance[cn] [\c!alternative=\v!a] +\setupMMLappearance[polar] [\c!alternative=\v!a] % a|b|c +\setupMMLappearance[float] [\c!symbol=\v!no] % \v!yes|dot +\setupMMLappearance[enotation][\c!symbol=\v!no] % \v!yes|dot +\setupMMLappearance[base] [\c!symbol=\v!numbers] % digits|characters|text|no + +\startxmlsetups mml:cs \xmlcommand{#1}{/}{mml:cs:\xmlattdef{#1}{type}{default}} \stopxmlsetups +\startxmlsetups mml:ci \xmlcommand{#1}{/}{mml:ci:\xmlattdef{#1}{type}{default}} \stopxmlsetups +\startxmlsetups mml:cn \xmlcommand{#1}{/}{mml:cn:\xmlattdef{#1}{type}{default}} \stopxmlsetups + +% helpers cn / todo: \mn{...} + +\startxmlsetups mml:cn:default + \mathopnolimits{\xmlflush{#1}} +\stopxmlsetups + +% helpers ci + +\startxmlsetups mml:ci:default + \xmlflush{#1} +\stopxmlsetups + +\startxmlsetups mml:ci:set + {\blackboard{\xmlflush{#1}}} % todo +\stopxmlsetups + +\startxmlsetups mml:ci:vector + \overrightarrow{\xmlflush{#1}} +\stopxmlsetups + +\startxmlsetups mml:ci:matrix + {\bi\xmlflush{#1}} +\stopxmlsetups + +\startxmlsetups mml:ci:function + \xmlflush{#1}% \negthinspace +\stopxmlsetups + +\startxmlsetups mml:ci:fn + \xmlsetup{#1}{mml:ci:function} +\stopxmlsetups + +\startxmlsetups mml:ci:complex-cartesian + \xmlsetup{#1}{mml:cn:complex} +\stopxmlsetups + +\startxmlsetups mml:ci:complex + \xmlsetup{#1}{mml:cn:complex} +\stopxmlsetups + +\startxmlsetups mml:ci:complex-polar + \xmlsetup{#1}{mml:cn:polar} +\stopxmlsetups + +\startxmlsetups mml:ci:polar + \xmlsetup{#1}{mml:cn:polar} +\stopxmlsetups + +% helpers ci + +\startxmlsetups mml:cn:default + \xmlflush{#1} +\stopxmlsetups + +\startxmlsetups mml:cn:integer + \edef\mmlintegerbase{\xmlattdef{#1}{base}{}} + \ifx\mmlintegerbase\empty + \xmlflush{#1} + \else + \doifelse \MMLbasesymbol \v!no { + \MMLcCNbasedata{\xmlflush{#1}} + } { + \MMLcCNbasedata{\xmlflush{#1}}\normalsubscript{ + \hbox {\startimath + \mr + \scriptscriptstyle + \processaction + [\MMLbasesymbol] + [\v!characters=>\MMLcCNbasestring BODH, + \v!text=>\MMLcCNbasestring{BIN}{OCT}{DEC}{HEX}, + \s!unknown=>\mmlintegerbase] + \stopimath} + } + } + \fi +\stopxmlsetups + +\def\MMLcCNbasedata#1% + {\ifnum\mmlintegerbase>10 \relax{\mr#1}\else#1\fi} + +\def\MMLcCNbasestring#1#2#3#4% + {\ifnum\mmlintegerbase= 2 #1\orelse + \ifnum\mmlintegerbase= 8 #2\orelse + \ifnum\mmlintegerbase=10 #3\orelse + \ifnum\mmlintegerbase=16 #4\else + \mmlintegerbase \fi} + +\startxmlsetups mml:cn:polar + \xmlsetup{#1}{mml:cn:polar:\MMLpolaralternative} +\stopxmlsetups + +\startxmlsetups mml:cn:polar:a + \mathml_cpolar_a{#1} +\stopxmlsetups + +\startxmlsetups mml:cn:polar:b + {\mr e}\normalsuperscript{\xmlsnippet{#1}{1}+\xmlsnippet{#1}{3}\thinspace{\mr i}} +\stopxmlsetups + +\startxmlsetups mml:cn:polar:c + \exp\left(\xmlsnippet{#1}{1}+\xmlsnippet{#1}{3}\thinspace{\mr i}\right) +\stopxmlsetups + +\startxmlsetups mml:cn:complex-polar + \xmlsetup{#1}{mml:cn:polar} +\stopxmlsetups + +\startxmlsetups mml:cn:complex % todo ( ) + \left(\xmlsnippet{#1}{1} + \xmlsnippet{#1}{3}\thinspace{\mr i}\right) +\stopxmlsetups + +\startxmlsetups mml:cn:complex-cartesian + \xmlsetup{#1}{mml:cn:complex} +\stopxmlsetups + +\startxmlsetups mml:cn:float + \doifelse \MMLfloatsymbol \v!no { + % make sure that e shows up ok + \mathopnolimits{\xmlflush{#1}} + } { + % we should ignore \entities ! + \edef\mmlfloatstring{\xmlflush{#1}} + \splitstring\mmlfloatstring\at e\to\first\and\last + \ifempty\first + \mmlfloatstring + \orelse\ifempty\last + \mmlfloatstring + \else + \first + \doifelse \MMLfloatsymbol {dot} \cdot \times + 10\normalsuperscript{\last} + \fi + } +\stopxmlsetups + +\startxmlsetups mml:cn:real + \xmlsetup{#1}{mml:cn:float} +\stopxmlsetups + +\startxmlsetups mml:cn:e-notation + \doifelse \MMLenotationsymbol \v!no { + \xmlsnippet{#1}{1} + \unskip\mathopnolimits{e}\ignorespaces + \xmlsnippet{#1}{3} + } { + \xmlsnippet{#1}{1} + \doifelse \MMLenotationsymbol {dot} \cdot + \times10\normalsuperscript{\xmlsnippet{#1}{3}} + } +\stopxmlsetups + +\startxmlsetups mml:cn:logical + \mathopnolimits{\xmlflush{#1}} +\stopxmlsetups + +\startxmlsetups mml:cn:rational + \xmldoifelse {#1} {/mml:sep} { + \mmlfrac + {\xmlsnippet{#1}{1}} + {\xmlsnippet{#1}{3}} + } { + \xmlflush{#1} + } +\stopxmlsetups + +% interval + +\setupMMLappearance[interval][\c!alternative=\v!a,\c!separator={,}] + +% when empty element, then it's an apply + +\startxmlsetups mml:interval + \doifelse {\xmltag{#1}} {apply} { + % #1 == apply + \let\mmlintervalfirst \mmlsecond + \let\mmlintervalsecond\mmlthird + \xmlsetup{#1}{mml:interval:\xmlattributedef{#1}{/mml:interval}{closure}{closed}} + } { + % #1 == interval + \let\mmlintervalfirst \mmlfirst + \let\mmlintervalsecond\mmlsecond + \xmlsetup{#1}{mml:interval:\xmlattdef{#1}{closure}{closed}} + } +\stopxmlsetups + +\startxmlsetups mml:interval:closed + \left[\mmlintervalfirst{#1}\MMLseparator\MMLintervalseparator\mmlintervalsecond{#1}\right] +\stopxmlsetups + +\startxmlsetups mml:interval:open-closed + \doifelse \MMLintervalalternative \v!b { + \left<\mmlintervalfirst{#1}\MMLseparator\MMLintervalseparator\mmlintervalsecond{#1}\right] + } { + \left(\mmlintervalfirst{#1}\MMLseparator\MMLintervalseparator\mmlintervalsecond{#1}\right] + } +\stopxmlsetups + +\startxmlsetups mml:interval:closed-open + \doifelse \MMLintervalalternative \v!b { + \left[\mmlintervalfirst{#1}\MMLseparator\MMLintervalseparator\mmlintervalsecond{#1}\right> + } { + \left[\mmlintervalfirst{#1}\MMLseparator\MMLintervalseparator\mmlintervalsecond{#1}\right) + } +\stopxmlsetups + +\startxmlsetups mml:interval:open + \doifelse \MMLintervalalternative \v!b { + \left<\mmlintervalfirst{#1}\MMLseparator\MMLintervalseparator\mmlintervalsecond{#1}\right> + } { + \left(\mmlintervalfirst{#1}\MMLseparator\MMLintervalseparator\mmlintervalsecond{#1}\right) + } +\stopxmlsetups + +% inverse + +\setfalse\xmlinversefunction + +\startxmlsetups mml:apply:inverse + \settrue\xmlinversefunction + \xmlsetup{#1}{mml:\xmlfilter{#1}{/mml:apply/*[2]/tag()}} +\stopxmlsetups + +% condition + +% maybe a fast \xmlnonfirst + +% instead of the following we could do \xmlcontent{#1}{/mml:bvar} etc + +\startxmlsetups mml:bvar \xmlflush{#1} \stopxmlsetups +\startxmlsetups mml:lowlimit \xmlflush{#1} \stopxmlsetups +\startxmlsetups mml:uplimit \xmlflush{#1} \stopxmlsetups +\startxmlsetups mml:degree \xmlflush{#1} \stopxmlsetups +\startxmlsetups mml:logbase \xmlflush{#1} \stopxmlsetups +\startxmlsetups mml:fn \xmlflush{#1} \stopxmlsetups + +\startxmlsetups mml:condition +% \xmldoif {#1} {/mml:bvar} { +% \xmlfirst{#1}{/mml:bvar}\mid +% } + \xmlall{#1}{/!(mml:condition\string|mml:bvar)} +\stopxmlsetups + +% declare + +\setupMMLappearance[declare][\c!state=\v!start] + +\startxmlsetups mml:declare + \doif \MMLdeclarestate \v!start { + \mathopnolimits{declare} + \mmlfirst{#1} + \ifnum\xmlcount{#1}{/*}>\plusone + \thickspace + \mathopnolimits{as} + \thickspace + \fi + \mmlsecond{#1} + } +\stopxmlsetups + +% lambda + +\setupMMLappearance[lambda][\c!alternative=b] + +\startxmlsetups mml:lambda + \begingroup + \doifelse \MMLlambdaalternative \v!a { + \lambda\left(\xmlconcat{#1}{/!mml:lambda}{\MMLseparator,}\right) + } { + \ifnum\xmlcount{#1}{/mml:bvar}>\plusone + \left(\xmlconcat{#1}{/mml:bvar}{\MMLseparator,}\right) + \else + \xmlfirst{#1}{/mml:bvar} + \fi + \mapsto + \MMLcreset + \xmlall{#1}{/!(mml:bvar|mml:lambda)} + } + \endgroup +\stopxmlsetups + +% compose + +\startxmlsetups mml:compose + \begingroup + \MMLcreset +% \let\MMLcCIfunction\firstofoneargument % brrr ? ? ? + \doifelsemmlfunction {#1} { + \left(\xmlconcat{#1}{/!mml:compose}{\circ}\right) + } { + \xmlconcat{#1}{/!mml:compose}{\circ} + } + \endgroup +\stopxmlsetups + +\startxmlsetups mml:image + \mathopnolimits{image} \left( {\mr\xmlfilter{#1}{/!mml:image/tag()}} \right) +\stopxmlsetups + +\setupMMLappearance[piece][\c!separator=] + +\startxmlsetups mml:piecewise + \processaction + [\MMLpieceseparator] + [ \v!yes=>\def\theMMLpieceseparator{,&}, + \v!no=>\def\theMMLpieceseparator{&}, + \s!default=>\def\theMMLpieceseparator{&}, + \s!unknown=>\def\theMMLpieceseparator{\,\,\hbox{\MMLpieceseparator}\,\,}] + \cases{\xmlflush{#1}} +\stopxmlsetups + +\startxmlsetups mml:piece + \mmlfirst{#1}\theMMLpieceseparator\mathematics{\mmlsecond{#1}}\crcr +\stopxmlsetups + +\startxmlsetups mml:otherwise +% \xmlflush{#1}\MMLcPIECEseparator&{\mr otherwise}\crcr + \xmlflush{#1}&{\mr otherwise}\crcr +\stopxmlsetups + +% end of piece + +\startxmlsetups mml:quotient + \lfloor\mmlsecond{#1}/\mmlthird{#1}\rfloor +\stopxmlsetups + +\startxmlsetups mml:factorial + \xmlall{#1}{/!factorial}! +\stopxmlsetups + +\setupMMLappearance [divide] [\c!level=\!!maxcard,\c!alternative=\v!a] + +\newcount\mmldividelevel + +\startxmlsetups mml:divide + \advance\mmldividelevel\plusone + \doifelse \MMLdividealternative \v!b { + \mmlsecond{#1}/\mmlthird{#1} + } { + \ifnum \mmldividelevel > \MMLdividelevel \relax % threshold + \mmlsecond{#1}/\mmlthird{#1} + \else + \MMLcreset + \mmlfrac{\MMLcreset\mmlsecond{#1}}{\MMLcreset\mmlthird{#1}} + \fi + } + \advance\mmldividelevel\minusone +\stopxmlsetups + +% min max + +\startxmlsetups mml:min \mathopnolimits{min} \xmlsetup{#1}{mml:minmax} \stopxmlsetups +\startxmlsetups mml:max \mathopnolimits{max} \xmlsetup{#1}{mml:minmax} \stopxmlsetups + +\startxmlsetups mml:minmax + \xmldoif {#1} {/mml:bvar} { + {}\normalsubscript{\xmlfirst{#1}{/mml:bvar}} + } + \left\{ + \xmlconcat{#1}{/!(mml:bvar\string|mml:max\string|mml:min)}{\MMLseparator,} + \right\} +\stopxmlsetups + +% minus plus + +\setupMMLappearance [plus] [\c!alternative=\v!a] % b = no sign -> 3 1/4 +\setupMMLappearance [sign] [\c!reduction=\v!yes] + +% alternative b -> geen sign + +% branch needed, else (a-b) + (c-d) goes wrong +% reset check in case of (-x) + 37 +% reset check in case of (-x) + 37 + +\newcount\mmlpluscounter + +\startxmlsetups mml:plus + \doifelse \MMLsignreduction \v!yes { + \MMLdoL + \xmlsetup{#1}{mml:plus:reset} + \xmlcommand{#1}{/!mml:plus}{mml:plus:body} + \MMLdoR + } { + \ifnum\xmlcount{#1}{/!mml:plus}=\plusone + +\xmlfirst{#1}{/!mml:plus} + \else + \MMLdoL + \xmlconcat{#1}{/!mml:plus}{+} + \MMLdoR + \fi + } +\stopxmlsetups + +\startxmlsetups mml:plus:reset + \mmlpluscounter\zerocount +\stopxmlsetups + +\startxmlsetups mml:plus:body + \advance\mmlpluscounter\plusone + \ifnum\mmlpluscounter>\plusone + \xmldoifelse{#1}{/mml:minus} { + \ifnum\xmlcount{#1}{/!mml:minus}>\plusone + + + \fi + } { + \doifelse {\xmlatt{#1}{type}} {rational} { + % fraction + } { + + + } + } + \fi + \xmldirect{#1} +\stopxmlsetups + +\newcount\mmlminuscounter + +\startsetups mml:minus + \doifelse \MMLsignreduction \v!yes { + \ifnum\xmlcount{#1}{/!mml:minus}=\plusone + -\xmlfirst{#1}{/!mml:minus} + \else + \MMLdoL + \xmlsetup{#1}{mml:minus:reset} + \xmlcommand{#1}{/!mml:minus}{mml:minus:body} + \MMLdoR + \fi + } { + \left( % \MMLdoL + \ifnum\xmlcount{#1}{/!mml:minus}=\plusone + -\xmlfirst{#1}{/!mml:minus} + \else + \xmlsetup{#1}{mml:minus:reset} + \xmlcommand{#1}{/!mml:minus}{mml:minus:body} + \fi + \right) % \MMLdoR + } +\stopsetups + +\startxmlsetups mml:minus:reset + \mmlminuscounter\zerocount +\stopxmlsetups + +\startxmlsetups mml:minus:body + % we can also use concat here + \advance\mmlminuscounter\plusone + \ifnum\mmlminuscounter>\plusone + - + \fi + \xmldirect{#1} +\stopxmlsetups + +% power + +\setupMMLappearance[power][\c!reduction=\v!yes] + +\let\MMLpowerelement\empty + +\startxmlsetups mml:power + \xmldoifelse {#1} {/mml:apply} { + \doifelse \MMLpowerreduction \v!yes { + \xmldoifelse {#1} {/mml:apply/(\MMLcfunctionlist)} { + \gdef\MMLpowerelement{\mmlthird{#1}}% postpone, no xdef + \MMLcreset\mmlsecond{#1} + } { + \left(\MMLcreset\mmlsecond{#1}\right)\normalsuperscript{\MMLcreset\mmlthird{#1}} + } + } { + \left(\MMLcreset\mmlsecond{#1}\right)\normalsuperscript{\MMLcreset\mmlthird{#1}} + } + } { + \mmlsecond{#1}\normalsuperscript{\MMLcreset\mmlthird{#1}} + } +\stopxmlsetups + +% rem + +\startxmlsetups mml:rem + \xmlconcat{#1}{/!mml:rem}{\mathopnolimits{mod}} +\stopxmlsetups + +\setupMMLappearance [times] [\c!symbol=\v!no,\c!auto=\v!yes] % new, auto catches cn cn cn + +\startxmlsetups mml:times + \setMMLcreset{\MMLcfunctionlist\string|\MMLcconstructlist}% + \doifelse\MMLtimesauto\v!no { + \let\MMLtimes@@symbol\MMLtimessymbol + } { + \xmldoifelse {#1} {/mml:cn[name(1) == 'mml:cn']} {% name(1) is next one + \doifelseinset\MMLtimessymbol{\v!yes,\v!no} { + \let\MMLtimes@@symbol\v!yes + } { + \let\MMLtimes@@symbol\MMLtimessymbol + } + } { + \let\MMLtimes@@symbol\MMLtimessymbol + } + } + \doifelse\MMLtimes@@symbol\v!yes { + \xmlconcat{#1}{/!mml:times}{\times} + } { + \doifelse\MMLtimes@@symbol{dot} { + \xmlconcat{#1}{/!mml:times}{\cdot} + } { + \doifelse\MMLtimes@@symbol{times} { + \xmlconcat{#1}{/!mml:times}{\times} + } { + \xmlall{#1}{/!mml:times} + } + } + } +\stopxmlsetups + +\setupMMLappearance[root][\c!symbol=\v!yes] + +\startxmlsetups mml:root + \xmldoifelse {#1} {/mml:degree} { + \root + \doifnot\MMLrootsymbol\v!no{\MMLcreset\xmltext{#1}{/mml:degree}} + \of + } { + \sqrt + } + {\MMLcreset\xmlall{#1}{/!(mml:degree\string|mml:root)}} +\stopxmlsetups + +% gcd + +\startxmlsetups mml:gcd + \begingroup + \gcd\left(\MMLcreset\xmlconcat{#1}{/!mml:gcd}{\MMLseparator,}\right) + \endgroup +\stopxmlsetups + +% and or xor implies, not + +\startxmlsetups mml:and \xmlconcat{#1}{/!mml:and} {\wedge} \stopxmlsetups +\startxmlsetups mml:or \xmlconcat{#1}{/!mml:or} {\vee} \stopxmlsetups +\startxmlsetups mml:xor \xmlconcat{#1}{/!mml:xor} {\mathopnolimits{xor}} \stopxmlsetups +\startxmlsetups mml:implies \xmlconcat{#1}{/!mml:implies}{\Rightarrow} \stopxmlsetups +\startxmlsetups mml:not \neg \xmlall {#1}{/!mml:not} \stopxmlsetups + +% forall exists + +%D We need to shift left below rotated A. + +\startxmlsetups mml:forall + \forall \negthinspace \xmlsetup{#1}{mml:forallexists} +\stopxmlsetups + +\startxmlsetups mml:exists + \exists \xmlsetup{#1}{mml:forallexists} +\stopxmlsetups + +\def\mmlforallexistslist{mml:bvar\string|mml:forall\string|mml:exists\string|mml:condition} + +\startxmlsetups mml:forallexists + \normalsubscript{\xmlconcat{#1}{/mml:bvar}{\MMLseparator,}} + \xmldoifelse {#1} {/mml:condition} { + \thickspace + \begingroup + \xmlfirst{#1}{/mml:condition} + \endgroup + \ifcase\xmlcount{#1}{/!(\mmlforallexistslist)}\relax + % nothing + \or + % == snelle volgende + \left\vert + \MMLcreset \medspace \xmlconcat{#1}{/!(\mmlforallexistslist)}{} + \right. + \else + % special case + \left\vert + \matrix { + \xmlconcat{#1}{/!(\mmlforallexistslist)}{\hfill\crcr} + } + \right. + \fi + } { + :\xmlfirst{#1}{/!(\mmlforallexistslist)} + } +\stopxmlsetups + +\startxmlsetups mml:abs + \left\vert \MMLcreset\xmlall{#1}{/!mml:abs} \right\vert +\stopxmlsetups + +\startxmlsetups mml:conjugate % watch extra {} + {\overline{\MMLcreset\xmlall{#1}{/!mml:conjugate}}} +\stopxmlsetups + +\startxmlsetups mml:arg + \mathopnolimits{arg} \left( \MMLcreset\xmlall{#1}{/!mml:arg} \right) +\stopxmlsetups + +\startxmlsetups mml:real + \Re \left( \MMLcreset \xmlall{#1}{/!mml:real} \right) +\stopxmlsetups + +\startxmlsetups mml:imaginary + \Im \ left( \MMLcreset \xmlall{#1}{/!mml:imaginary} \right) +\stopxmlsetups + +\startxmlsetups mml:lcm + \mathopnolimits{lcm} \left( \xmlconcat{#1}{/!mml:lcm}{\MMLseparator,} \right) +\stopxmlsetups + +\startxmlsetups mml:floor + \lfloor \xmlall{#1}{/!mml:floor} \rfloor +\stopxmlsetups + +\startxmlsetups mml:ceiling + \lceiling \xmlall{#1}{/!mml:ceiling} \rceiling +\stopxmlsetups + +% relations + +% apply attr or eq + +\setupMMLappearance[relation][\c!align=\v!no] + +\xmlmapvalue {mml:relation} {eq} {=} +\xmlmapvalue {mml:relation} {neq} {\neq} +\xmlmapvalue {mml:relation} {gt} {>} +\xmlmapvalue {mml:relation} {lt} {<} +\xmlmapvalue {mml:relation} {geq} {\geq} +\xmlmapvalue {mml:relation} {leq} {\leq} +\xmlmapvalue {mml:relation} {equivalent} {\equiv} +\xmlmapvalue {mml:relation} {approx} {\approx} +\xmlmapvalue {mml:relation} {factorof} {\mid} + +\startxmlsetups mml:eq \xmlsetup{#1}{mml:relation} \stopxmlsetups +\startxmlsetups mml:neq \xmlsetup{#1}{mml:relation} \stopxmlsetups +\startxmlsetups mml:gt \xmlsetup{#1}{mml:relation} \stopxmlsetups +\startxmlsetups mml:lt \xmlsetup{#1}{mml:relation} \stopxmlsetups +\startxmlsetups mml:geq \xmlsetup{#1}{mml:relation} \stopxmlsetups +\startxmlsetups mml:leq \xmlsetup{#1}{mml:relation} \stopxmlsetups +\startxmlsetups mml:equivalent \xmlsetup{#1}{mml:relation} \stopxmlsetups +\startxmlsetups mml:approx \xmlsetup{#1}{mml:relation} \stopxmlsetups +\startxmlsetups mml:factorof \xmlsetup{#1}{mml:relation} \stopxmlsetups + +\startxmlsetups mml:relation + \edef\mmlapplyaction{\xmlfilter{#1}{/*/tag()}} + \MMLcreset \xmlsetup{#1}{mml:relation:\xmlattdef{#1}{align}{\MMLrelationalign}} +\stopxmlsetups + +\startxmlsetups mml:relation:default + \xmlconcatrange{#1}{/*}{2}{}{\xmlval{mml:relation}{\mmlapplyaction}{[\mmlapplyaction]}} +\stopxmlsetups +\startxmlsetups mml:relation:last + \eqalign { + \xmlconcatrange{#1}{/*}{2}{-2}{&\xmlval{mml:relation}{\mmlapplyaction}{[\mmlapplyaction]}\crcr} + \mmlprelast{#1}&\xmlval{mml:relation}{\mmlapplyaction}{[\mmlapplyaction]}{}\mmllast{#1} + } +\stopxmlsetups +\startxmlsetups mml:relation:first + \eqalign { + \mmlsecond{#1}\xmlval{mml:relation}{\mmlapplyaction}{[\mmlapplyaction]}{} + &\xmlconcatrange{#1}{/*}{3}{}{\crcr\xmlval{mml:relation}{\mmlapplyaction}{[\mmlapplyaction]}{}&} + } +\stopxmlsetups +\startxmlsetups mml:relation:left + \eqalign { + \xmlconcatrange{#1}{/*}{2}{}{&\xmlval{mml:relation}{\mmlapplyaction}{[\mmlapplyaction]}\crcr} + } +\stopxmlsetups +\startxmlsetups mml:relation:right + \eqalign { + &\xmlconcatrange{#1}{/*}{2}{}{\crcr\xmlval{mml:relation}{\mmlapplyaction}{[\mmlapplyaction]}{}&} + } +\stopxmlsetups +\startxmlsetups mml:relation:no + \xmlsetup{#1}{mml:relation:default} +\stopxmlsetups +\startxmlsetups mml:relation:yes + \xmlsetup{#1}{mml:relation:left} +\stopxmlsetups + +% personal goody: + +\edef\MMLcmainresetlist{\MMLcmainresetlist\string|becomes} + +\xmlmapvalue {mml:relation} {mml:becomes} {:=} + +\startxmlsetups mml:becomes \xmlsetup{#1}{mml:relation} \stopxmlsetups + +% calculus and vector calculus + +\startxmlsetups mml:domainofapplication + \xmlall{#1}{/!mml:domainofapplication} +\stopxmlsetups + +\setupMMLappearance[int][\c!location=\v!top] + +\def\doMMLlimits#1{\doifelsevalue{MML#1\c!location}\v!top\limits\nolimits} + +\startxmlsetups mml:int + \MMLcreset + \xmldoifelse {#1} {/mml:domainofapplication} { + \int \doMMLlimits{int}\normalsubscript{\xmlfirst{#1}{/mml:domainofapplication}}\relax + } { + \xmldoifelse {#1} {/mml:condition} { + \int \doMMLlimits{int}\normalsubscript{\xmlfirst{#1}{/mml:condition}}\relax + } { + \xmldoifelse {#1} {/mml:lowlimit} { + \int \doMMLlimits{int}\normalsubscript{\xmlfirst{#1}{/mml:lowlimit}}\normalsuperscript{\xmlfirst{#1}{/mml:uplimit}} + } { + % funny, why do we have lowlimit/uplimit then + \xmldoifelse {#1} {/mml:apply/mml:interval} { + \int \doMMLlimits{int}\normalsubscript{\xmlindex{#1}{/mml:apply}{2}}\normalsuperscript{\xmlindex{#1}{/mml:apply}{3}} + } { + \int + } + } + } + } + \MMLcreset + \xmldoifelse {#1} {/mml:apply} { + \doifelsemmlfunction {#1} { % todo test + \xmlfirst{#1}{/mml:apply} + } { + % if there are too many () now, we need to be more clever + \left( \xmlfirst{#1}{/mml:apply} \right) + } + } { + \xmlfirst{#1}{/mml:ci} + } + \xmldoifelse {#1} {/mml:bvar} { + \thinspace {\mr d} \xmlfirst{#1}{/mml:bvar} + } { + % nothing + } +\stopxmlsetups + +\setupMMLappearance[diff][\c!location=\v!top,\c!alternative=\v!a] + +\startxmlsetups mml:diff + \MMLcreset + \doifelse \MMLdiffalternative \v!a { + \xmldoifelse {#1} {/mml:lambda} { + % a special case (mathadore/openmath) + \mmlfrac { + d + \normalsuperscript + {\xmlfirst{#1}{/mml:bvar}\xmlfirst{#1}{/mml:cn}} + {\xmlfirst{#1}{/mml:lambda}\xmlfirst{#1}{/mml:ci}} + } { + d + {\xmlfirst{#1}{/mml:bvar}\xmlfirst{#1}{/mml:ci}} + \normalsuperscript + {\xmlfirst{#1}{/mml:bvar}\xmlfirst{#1}{/mml:cn}} + } + } { + \xmldoifelse {#1} {/mml:bvar} { + \mmlfrac { + {\mr d}{ + \xmldoifelse {#1} {/mml:degree} { + \normalsuperscript{\xmlconcat{#1}{/mml:degree}\empty} + } { + \xmldoif {#1} {/mml:bvar/mml:degree} { + \normalsuperscript{\xmlconcat{#1}{/mml:bvar/mml:degree}+} + } + } + } + \doif \MMLdifflocation \v!top { + \xmldoifelse {#1} {/mml:ci} { + \xmlfirst{#1}{/mml:ci} + } { + \MMLcreset + \ifnum\xmlcount{#1}{/mml:apply/*}>\plustwo % hack + \left(\xmlfirst{#1}{/mml:apply}\right) + \else + \xmlfirst{#1}{/mml:apply} + \fi + } + } + } { + {\mr d} + \xmlfirst{#1}{/mml:bvar/!mml:degree} + \xmldoif {#1} {/mml:bvar/mml:degree} { + \normalsuperscript{\xmlfirst{#1}{/mml:bvar/mml:degree}} + } + } + \doifnot \MMLdifflocation \v!top { + \left(\MMLcreset\xmlfirst{#1}{/(mml:apply\string|mml:ci)}\right) + } + } { + % beware, the second {} is needed for the superscript + \xmlconcatrange{#1}{/*}{2}{}{}\normalsuperscript\prime + } + } + } { + \MMLcreset + \xmlfirst{#1}{/(mml:apply\string|mml:ci)} + % there can be problems with nested diff's: \normalsuperscript\normalsuperscript{} error + % so we add an empty group here + {}\normalsuperscript + { + \xmldoifelse {#1} {/mml:degree} { + \edef\mmldegree{\xmlfirst{#1}{/mml:degree/mml:cn}} + \ifempty\mmldegree + % what to do here + \else + \dorecurse\mmldegree\prime + \fi + } { + \prime + } + } + } +\stopxmlsetups + +\startxmlsetups mml:partialdiff + \xmldoifelse {#1} {/mml:list} { + {\mr D}\normalsubscript{ + \begingroup + \setfalse\mmllistdelimiters + \xmlall{#1}{/mml:list} + \endgroup + } + \xmlfirst{#1}{/(mml:apply\string|mml:reln\string|mml:ci\string|mml:cn)} + } { + \xmldoifelse {#1} {/mml:bvar} { + \mmlfrac { + {\mr d}\normalsuperscript{ + \xmldoifelse {#1} {/mml:degree} { + \xmlconcat{#1}{/mml:degree}\empty + } { + \xmlconcat{#1}{/mml:bvar/mml:degree}+ + } + } + \MMLcreset + \xmlfirst{#1}{/(mml:apply\string|mml:reln\string|mml:ci\string|mml:cn)} + } { + \xmldoif {#1}{/mml:bvar/!mml:degree} { + \xmlfirst{#1}{/mml:bvar/!mml:degree} \, + } + {\mr d}\xmlfirst{#1}{/(mml:apply\string|mml:reln\string|mml:ci\string|mml:cn)} + \xmldoif {#1} {/mml:bvar/mml:degree} { + \normalsuperscript{\xmlfirst{#1}{/mml:bvar/mml:degree}} + } + } + } { + \xmlfirst{#1}{/(mml:apply\string|mml:reln\string|mml:ci\string|mml:cn)} + } + } +\stopxmlsetups + +\startxmlsetups mml:divergence \mathopnolimits{div} \xmlall{#1}{/!mml:divergence} \stopxmlsetups +\startxmlsetups mml:grad \mathopnolimits{grad} \xmlall{#1}{/!mml:grad} \stopxmlsetups +\startxmlsetups mml:curl \mathopnolimits{curl} \xmlall{#1}{/!mml:curl} \stopxmlsetups +\startxmlsetups mml:laplacian \nabla\normalsuperscript2 \xmlall{#1}{/!mml:laplacian} \stopxmlsetups +\startxmlsetups mml:ident \mathopnolimits{identity} \xmlall{#1}{/!mml:ident} \stopxmlsetups + +\setupMMLappearance[domain] [symbol=] +\setupMMLappearance[codomain][symbol=] + +\startxmlsetups mml:domain + \doifelsenothing \MMLdomainsymbol { + \mathopnolimits{domain}\MMLcreset\xmlall{#1}{/!mml:domain} + } { + \MMLdomainsymbol\normalsubscript{\xmlall{#1}{/!mml:domain}} + } +\stopxmlsetups + +\startxmlsetups mml:codomain + \doifelsenothing \MMLcodomainsymbol { + \mathopnolimits{codomain}\MMLcreset\xmlall{#1}{/!mml:codomain} + } { + \MMLcodomainsymbol\normalsubscript{\xmlall{#1}{/!mml:codomain}} + } +\stopxmlsetups + +% theory of sets + +\startxmlsetups mml:set + \left\{ + \xmldoifelse {#1} {/mml:condition} { + \xmlfirst{#1}{/mml:bvar}\,\middle\vert\,\xmlfirst{#1}{/mml:condition} + } { + \xmlconcat{#1}{/!mml:set}{\MMLseparator,} + } + \right\} + \relax % needed +\stopxmlsetups + +\settrue\mmllistdelimiters + +\startxmlsetups mml:list + \begingroup + \ifconditional\mmllistdelimiters\left [\fi + \begingroup + \settrue\mmllistdelimiters + \xmlconcat{#1}{/!mml:list}{\MMLseparator,} + \endgroup + \ifconditional\mmllistdelimiters\right]\fi + \endgroup +\stopxmlsetups + +\startxmlsetups mml:union \mmlsecond{#1} \cup \mmlthird{#1} \stopxmlsetups +\startxmlsetups mml:intersect \mmlsecond{#1} \cap \mmlthird{#1} \stopxmlsetups +\startxmlsetups mml:in \mmlsecond{#1} \in \mmlthird{#1} \stopxmlsetups +\startxmlsetups mml:notin \mmlsecond{#1} {\not\in} \mmlthird{#1} \stopxmlsetups +\startxmlsetups mml:subset \mmlsecond{#1} \subset \mmlthird{#1} \stopxmlsetups +\startxmlsetups mml:prsubset \mmlsecond{#1} \subseteq \mmlthird{#1} \stopxmlsetups +\startxmlsetups mml:notsubset \mmlsecond{#1} {\not\subset} \mmlthird{#1} \stopxmlsetups +\startxmlsetups mml:notprsubset \mmlsecond{#1} {\not\subseteq} \mmlthird{#1} \stopxmlsetups +\startxmlsetups mml:setdiff \mmlsecond{#1} \setminus \mmlthird{#1} \stopxmlsetups + +\startxmlsetups mml:card + \left\vert \xmlall{#1}{/!mml:card} \right\vert +\stopxmlsetups + +\startxmlsetups mml:cartesianproduct + \xmlconcat{#1}{/!mml:cartesianproduct}{\times} +\stopxmlsetups + +% sequences and series + +\setupMMLappearance[sum] [\c!location=\v!top] +\setupMMLappearance[product][\c!location=\v!top] + +\xmlmapvalue {mml:sumprod} {sum} {\sum} +\xmlmapvalue {mml:sumprod} {product} {\prod} + +\startxmlsetups mml:sum \edef\mmlsumprodname{sum} \xmlsetup{#1}{mml:sumprod} \stopxmlsetups +\startxmlsetups mml:product \edef\mmlsumprodname{product} \xmlsetup{#1}{mml:sumprod} \stopxmlsetups + +\def\mmlstackedsubscripts#1% + {\vbox + {\baselineskip\zeropoint % hack, taco vragen + \halign{\startimath\scriptstyle\hss\alignmark\alignmark\hss\stopimath\cr#1\crcr}}} + +% unfinished + +\startxmlsetups mml:sumprod + \begingroup + \xmldoifelse {#1} {/(mml:condition\string|mml:bvar\string|mml:lowlimit)} { + \def\mmlsumprodlower{ + \normalsubscript{ + \xmldoifelse {#1} {/mml:condition} { + \mmlstackedsubscripts{\xmlconcat{#1}{/mml:condition}{\crcr}} + } { + \xmldoif {#1} {/mml:bvar} { + \xmlfirst{#1}{/mml:bvar} + \xmldoif{#1}{/mml:lowlimit}{=} + } + \xmlfirst{#1}{/mml:lowlimit} + } + } + } + } { + \let\mmlsumprodlower\empty + } + \xmldoifelse {#1} {/mml:uplimit} { + \def\mmlsumprodupper{\normalsuperscript{\xmlfirst{#1}{/mml:uplimit}}} + } { + \let\mmlsumprodupper\empty + } + \xmldoif {#1} {/mml:interval} { % open math converter gives this + \edef\mmlintervalfrom{\xmlindex{#1}{/mml:interval}{1}} + \edef\mmlintervalto {\xmlindex{#1}{/mml:interval}{2}} + \ifempty\mmlintervalfrom \else + \def\mmlsumprodlower{\normalsubscript{\xmldoif{#1}{/mml:bvar}{\xmlfirst{#1}{/mml:bvar}{=}}\mmlintervalfrom}} + \fi + \ifempty\mmlintervalto \else + \def\mmlsumprodupper{\normalsuperscript{\mmlintervalto}} + \fi + } + \MMLcreset + \xmlval{mml:sumprod}{\mmlsumprodname}{}\doMMLlimits\mmlsumprodname\mmlsumprodupper\mmlsumprodlower + \MMLcreset + \xmldoifelse {#1} {/mml:lambda/mml:apply} { + \xmlfirst{#1}{/mml:lambda/mml:apply}% a bit of open math conversion mess + } { + \xmlfirst{#1}{/(mml:apply\string|mml:lambda\string|mml:ci)}% + } + \endgroup +\stopxmlsetups + +\setupMMLappearance[limit][\c!location=\v!top] + +\startxmlsetups mml:limit + \MMLcreset \lim + \doMMLlimits {limit}\normalsubscript{ + \MMLcreset + \xmldoifelse {#1} {/mml:condition} { + \xmlfirst{#1}{/mml:condition} + } { + \xmldoif {#1} {/mml:bvar} { + \xmlfirst{#1}{/mml:bvar}\rightarrow + } + \xmlfirst{#1}{/mml:lowlimit} + } + } + \begingroup + % a bit of open math conversion mess, lambda needed for openmath, ok? + \MMLcreset + \xmlfirst{#1}{/mml:lambda/mml:apply} + \xmlfirst{#1}{/(mml:apply\string|mml:lambda)} + \endgroup +\stopxmlsetups + +% consider a faster index + +\startxmlsetups mml:tendsto + \MMLcreset \mmlsecond{#1} + \xmlval {mml:tendsto:type} {\xmlattdef{#1}{type}{default}} {\rightarrow} + \MMLcreset \mmlthird{#1} +\stopxmlsetups + +\xmlmapvalue {mml:tendsto:type} {above} {\downarrow} +\xmlmapvalue {mml:tendsto:type} {below} {\uparrow} +\xmlmapvalue {mml:tendsto:type} {default} {\rightarrow} + +% elementary classical functions + +\setupMMLappearance[log][\c!location=\v!right] + +\startxmlsetups mml:exp +% {\mr e}\normalsuperscript{\xmlfirst{#1}{/mml:apply\string|mml:reln\string|mml:ci\string|mml:cn}} + {\mr e}\normalsuperscript{\xmlfirst{#1}{/!mml:exp}} +\stopxmlsetups + +\startxmlsetups mml:log + \xmldoifelse {#1} {/mml:logbase} { + \doifelse \MMLloglocation \v!left { + \mathop { + {}\normalsuperscript{\xmlfirst{#1}{/mml:logbase}}\negthinspace\mathopnolimits{log} + } + } { + \mathopnolimits{log}\normalsubscript{\xmlfirst{#1}{/mml:logbase}} + } +% \MMLcreset + \xmlfirst{#1}{/(mml:apply\string|mml:reln\string|mml:ci\string|mml:cn)} +% \xmlsetup{#1}{mml:function} % todo, we start elsewhere +% \mmlthird{#1} + } { + \mathopnolimits{log} +% \MMLcreset +% \xmlsetup{#1}{mml:function} % todo, we start elsewhere + \xmlfirst{#1}{/(mml:apply\string|mml:reln\string|mml:ci\string|mml:cn)} +% \mmlsecond{#1} + } +\stopxmlsetups + +\startxmlsetups mml:ln + \mathopnolimits{ln} + \xmlsetup{#1}{mml:function} +\stopxmlsetups + +% statistics + +\startxmlsetups mml:mean \overline {\mmlsecond{#1}} \stopxmlsetups +\startxmlsetups mml:sdev \sigma \left(\MMLcreset\mmlsecond{#1}\right) \stopxmlsetups +\startxmlsetups mml:variance \sigma \left(\MMLcreset\mmlsecond{#1}\right)\normalsuperscript2 \stopxmlsetups +\startxmlsetups mml:median \mathopnolimits{median}\left(\MMLcreset\mmlsecond{#1}\right) \stopxmlsetups +\startxmlsetups mml:mode \mathopnolimits{mode} \left(\MMLcreset\mmlsecond{#1}\right) \stopxmlsetups + +% moments + +\startxmlsetups mml:moment + \left\langle + \xmlfirst{#1}{/(mml:apply\string|mml:reln\string|mml:ci\string|mml:cn)}\normalsuperscript{\xmlfirst{#1}{/mml:degree}} + \right\rangle + \xmldoif {#1} {mml:momentabout} { + \normalsubscript{\xmlfirst{#1}{mml:momentabout}} + } +\stopxmlsetups + +% linear algebra + +\setupMMLappearance [vector] [\c!direction=\v!horizontal,\c!separator={,}] + +\startxmlsetups mml:vector + \begingroup + \ifnum\xmlcount{#1}{/*}>\plusone + \doifelse\MMLvectordirection\v!horizontal { + \left(\xmlconcat{#1}{/*}{\MMLseparator\MMLvectorseparator}\right) + } { + \MMLcreset\left(\matrix{\xmlconcat{#1}{/*}{\MMLseparator\MMLvectorseparator}}\right) + } + \else + \overrightarrow{\charhtstrut\mmlfirst{#1}} + \fi + \endgroup +\stopxmlsetups + +\settrue\MMCdelmatrix % ( ) when true + +\startxmlsetups mml:matrix + \begingroup + \MMLcreset + \ifconditional\MMCdelmatrix + \left(\matrix{\xmlcommand{#1}{/mml:matrixrow}{mml:matrixrow:do}}\right) + \else + \settrue\MMCdelmatrix + \matrix{\xmlcommand{#1}{/mml:matrixrow}{mml:matrixrow:do}} + \fi + \endgroup +\stopxmlsetups + +\startxmlsetups mml:matrixrow + \begingroup + \MMLcreset + \left(\xmlsetup{#1}{mml:matrixrow:do}\right) + \endgroup +\stopxmlsetups + +\startxmlsetups mml:matrixrow:do + \xmlconcat{#1}{/*}{&}\crcr +\stopxmlsetups + +\startxmlsetups mml:determinant + \begingroup + \setfalse\MMCdelmatrix + \left|\mmlsecond{#1}\right| + \endgroup +\stopxmlsetups + +\startxmlsetups mml:transpose + \mmlsecond{#1}\normalsuperscript{\mathopnolimits{T}} +\stopxmlsetups + +\startxmlsetups mml:selector + \MMLmathinner{\mmlsecond{#1}\normalsubscript{\MMLcreset\xmlconcatrange{#1}{/*}{3}{}{\MMLseparator,}}} +\stopxmlsetups + +\startxmlsetups mml:vectorproduct \mmlsecond{#1}\times \mmlthird{#1} \stopxmlsetups +\startxmlsetups mml:scalarproduct \mmlsecond{#1}\cdot \mmlthird{#1} \stopxmlsetups +\startxmlsetups mml:outerproduct \mmlsecond{#1}\otimes\mmlthird{#1} \stopxmlsetups + +% semantic mapping elements + +\setupMMLappearance[semantics][\c!state=\v!start] + +\startxmlsetups mml:semantics + \doifelse\MMLsemanticsstate\v!start { + \xmlall{#1}{/mml:annotation} + } { + \xmlall{#1}{/!mml:annotation} + } +\stopxmlsetups + +\startxmlsetups mml:annotation + \xmldoifelse {#1} {.[oneof(@encoding,'TeX','tex','application/x-tex','TEX','ConTeXt','context','CONTEXT','ctx')]} { + \xmlflushcontext{#1} + } { + \xmldoifelse {#1} {.[oneof(@encoding,'calcmath','cm')]} { + \expanded{\calcmath{\xmlflush{#1}}} + } { + \xmldoifelse {#1} {.[oneof(@encoding,'asciimath','am')]} { + \ifdefined\asciimath + \expanded{\asciimath{\xmlflushpure{#1}}} + \else + \hbox{\tt no am loaded} + \fi + } { + \xmlall{#1}{../!mml:annotation} + } + } + } +\stopxmlsetups + +\startxmlsetups mml:annotation-xml + % maybe diagnostics +\stopxmlsetups + +% misc + +\startxmlsetups mml:integers \integers \stopxmlsetups +\startxmlsetups mml:reals \reals \stopxmlsetups +\startxmlsetups mml:rationals \rationals \stopxmlsetups +\startxmlsetups mml:naturalnumbers \naturalnumbers \stopxmlsetups +\startxmlsetups mml:complexes \complexes \stopxmlsetups +\startxmlsetups mml:primes \primes \stopxmlsetups +\startxmlsetups mml:exponentiale \mathopnolimits{e} \stopxmlsetups +\startxmlsetups mml:imaginaryi \mathopnolimits{i} \stopxmlsetups +\startxmlsetups mml:notanumber \mathopnolimits{NaN} \stopxmlsetups +\startxmlsetups mml:true \mathopnolimits{true} \stopxmlsetups +\startxmlsetups mml:false \mathopnolimits{false} \stopxmlsetups +\startxmlsetups mml:emptyset \mathopnolimits{Ø} \stopxmlsetups +\startxmlsetups mml:pi \pi \stopxmlsetups +\startxmlsetups mml:eulergamma \gamma \stopxmlsetups +\startxmlsetups mml:infinity \infty \stopxmlsetups + +% gonio functions + +\setupMMLappearance[function][\c!reduction=\v!yes] + +% todo: \mfunction which adapts itself when registered as command + +% todo: \def\mmlcfunction#1#2{\mathopnolimits{#2}\xmlsetup{#1}{mml:function}} + +\startxmlsetups mml:sin \mathcommand {sin}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:sinh \mathcommand {sinh}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:cos \mathcommand {cos}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:cosh \mathcommand {cosh}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:tan \mathcommand {tan}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:tanh \mathcommand {tanh}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:cot \mathcommand {cot}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:coth \mathcommand {coth}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:csc \mathcommand {csc}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:csch \mathcommand {csch}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:sec \mathcommand {sec}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:sech \mathcommand {sech}\xmlsetup{#1}{mml:function} \stopxmlsetups + +\startxmlsetups mml:arcsin \mathcommand {arcsin}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:arcsinh \mathcommand{arcsinh}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:arccos \mathcommand {arccos}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:arccosh \mathcommand{arccosh}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:arctan \mathcommand {arctan}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:arctanh \mathcommand{arctanh}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:arccot \mathcommand {arccot}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:arccoth \mathcommand{arccoth}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:arccsc \mathcommand {arccsc}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:arccsch \mathcommand{arccsch}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:arcsec \mathcommand {arcsec}\xmlsetup{#1}{mml:function} \stopxmlsetups +\startxmlsetups mml:arcsech \mathcommand{arcsech}\xmlsetup{#1}{mml:function} \stopxmlsetups + +\startxmlsetups mml:function + \ifempty\MMLpowerelement + \ifconditional\xmlinversefunction\normalsuperscript{-1}\fi + \setfalse\xmlinversefunction + \else + \normalsuperscript{\ifconditional\xmlinversefunction-\fi\MMLpowerelement} + \setfalse\xmlinversefunction + \glet\MMLpowerelement\empty + \fi + \xmlsetup{#1}{mml:function:argument} +\stopxmlsetups + +\startxmlsetups mml:function:argument + \doifelse \MMLfunctionreduction \v!yes { + \xmldoifelse {#1} {/mml:apply} { + \xmldoifelse {#1} {/mml:apply/(\MMLcfunctionlist\string|mml:divide)} + \donefalse + \donetrue + } { + \donefalse + } + } { + \donetrue + } + % beware, we still flush from 2 up + \ifdone + \left( + \MMLcreset + \xmlall{#1}{/[position()>1]}% \xmlconcatrange{#1}{/*}{2}{}\empty + \right) + \else + \MMLcreset + \xmlall{#1}{/[position()>1]} + \fi +\stopxmlsetups + +% PRESENTATION MATHML + +% helpers: maybe we can need a setting for the uprights + +\xmlmapvalue {mml:s} {normal} {\mathupright} % {\mathtf} +\xmlmapvalue {mml:s} {double-struck} {\mathblackboard} +\xmlmapvalue {mml:s} {italic} {\mathit} +\xmlmapvalue {mml:s} {fraktur} {\mathfraktur} +\xmlmapvalue {mml:s} {script} {\mathscript} +\xmlmapvalue {mml:s} {bold} {\mb} % {\mathbf} +\xmlmapvalue {mml:s} {bold-italic} {\mathbi} +\xmlmapvalue {mml:s} {bold-fraktur} {\mathfraktur\mathbf} +\xmlmapvalue {mml:s} {bold-script} {\mathscript\mathbf} +\xmlmapvalue {mml:s} {sans-serif} {\mathss} +\xmlmapvalue {mml:s} {bold-sans-serif} {\mathss\mathbf} +\xmlmapvalue {mml:s} {sans-serif-italic} {\mathss\mathit} +\xmlmapvalue {mml:s} {sans-serif-bold-italic} {\mathss\mathbi} +\xmlmapvalue {mml:s} {monospace} {\mathtt} + +\xmlmapvalue {mml:l} {-} {\let\mmlfrac\tfrac} + \let\mmlfrac\frac +\xmlmapvalue {mml:l} {+} {\let\mmlfrac\sfrac} + +\xmlmapvalue {mml:d} {true} {\displaystyle} +\xmlmapvalue {mml:d} {false} {\textstyle} % or whatever + +\starttexdefinition setmmlmathstyle #1 + \ifxmlattempty{#1}{displaystyle}\else + \xmlval{mml:d}\xmllastatt\empty + \fi + \ifxmlattempty{#1}{mathvariant}\else + \xmlval{mml:s}\xmllastatt\empty + \fi +\stoptexdefinition + +\starttexdefinition setmmlscriptlevel #1 + \ifxmlattempty{#1}{scriptlevel} + \let\mmlfrac\frac + \else + \xmlval{mml:l}\xmllastatt{\let\mmlfrac\frac} + \fi +\stoptexdefinition + +\starttexdefinition setmmlmathcolor #1 + \ifxmlattempty{#1}{mathcolor}\else + \directcolor[\xmllastatt] + \fi +\stoptexdefinition + +\starttexdefinition setmmlmathproperties #1 + % \ifxmlatt{#1}{displaystyle}\empty\else + \ifxmlattempty{#1}{displaystyle}\else + \xmlval{mml:d}\xmllastatt\empty + \fi + \ifxmlattempty{#1}{mathvariant}\else + \xmlval{mml:s}\xmllastatt\empty + \fi + \ifxmlattempty{#1}{scriptlevel} + \let\mmlfrac\frac + \else + \xmlval{mml:l}\xmllastatt{\let\mmlfrac\frac} + \fi + \ifxmlattempty{#1}{mathcolor}\else + \directcolor[\xmllastatt] + \fi +\stoptexdefinition + +% todo: textbackgrounds / todo: can be combined with new grouping + +\starttexdefinition applymmlmathbackground #1#2 + \ifxmlattempty{#1}{mathbackground} + #2 + \else + \backgroundline[\xmllastatt]{#2} + \fi +\stoptexdefinition + +\starttexdefinition applymmlsometext #1#2 + \begingroup + \applymmlmathbackground {#1} { + \setmmlmathcolor {#1} + \setmmlmathstyle {#1} + #2 + } + \endgroup +\stoptexdefinition + +% setups + +\startxmlsetups mml:mi % todo: mathsize (unlikely) mathcolor (easy) mathbackground (easy) + \begingroup + \pushmathstyle % still needed ? + \setmmlmathproperties{#1} + \mathml_mi{#1} + \popmathstyle % still needed ? + \endgroup +\stopxmlsetups + +\startxmlsetups mml:mn + \begingroup + \setmmlmathcolor{#1} + \mathml_mn{#1} + \endgroup +\stopxmlsetups + +% <m:mo>-</m:mo><m:mn>2</m:mn> and <m:mn>1</m:mn><m:mo>-</m:mo><m:mn>2</m:mn> +% +% spacing between - and 2 is taken care of by tex itself + +\startxmlsetups mml:mo + \begingroup + \setmmlmathcolor{#1} + \ifxmlatt{#1}{maxsize}{1} + \settrue\mmlignoredelimiter + \orelse\ifxmlatt{#1}{stretchy}{false} + \settrue\mmlignoredelimiter + \fi + \ifxmlattempty{#1}{lspace}\else + \hskip\xmllastatt\relax % todo: check for dimension + \fi + \mathml_mo{#1} + \ifxmlattempty{#1}{rspace}\else + \hskip\xmllastatt\relax % todo: check for dimension + \fi + \endgroup +\stopxmlsetups + +\startxmlsetups mml:mfenced % {} around separator is needed for spacing + \mathml_mfenced{#1} +\stopxmlsetups + +\defineoverlay [mml:enclose:box] [\useMPgraphic{mml:enclose:box}] +\defineoverlay [mml:enclose:roundedbox] [\useMPgraphic{mml:enclose:roundedbox}] +\defineoverlay [mml:enclose:circle] [\useMPgraphic{mml:enclose:circle}] +\defineoverlay [mml:enclose:left] [\useMPgraphic{mml:enclose:left}] +\defineoverlay [mml:enclose:right] [\useMPgraphic{mml:enclose:right}] +\defineoverlay [mml:enclose:top] [\useMPgraphic{mml:enclose:top}] +\defineoverlay [mml:enclose:bottom] [\useMPgraphic{mml:enclose:bottom}] +\defineoverlay [mml:enclose:updiagonalstrike] [\useMPgraphic{mml:enclose:updiagonalstrike}] +\defineoverlay [mml:enclose:downdiagonalstrike] [\useMPgraphic{mml:enclose:downdiagonalstrike}] +\defineoverlay [mml:enclose:horizontalstrike] [\useMPgraphic{mml:enclose:horizontalstrike}] +\defineoverlay [mml:enclose:verticalstrike] [\useMPgraphic{mml:enclose:verticalstrike}] + +\startuseMPgraphic{mml:enclose:box} + draw OverlayBox withpen pencircle scaled (ExHeight/10) ; +\stopuseMPgraphic +\startuseMPgraphic{mml:enclose:roundedbox} + draw OverlayBox cornered .5ExHeight withpen pencircle scaled (ExHeight/10) ; +\stopuseMPgraphic +\startuseMPgraphic{mml:enclose:circle} + draw fullcircle xysized(bbwidth(OverlayBox),bbheight(OverlayBox)) withpen pencircle scaled (ExHeight/10) ; +\stopuseMPgraphic +\startuseMPgraphic{mml:enclose:left} + draw leftboundary OverlayBox withpen pencircle scaled (ExHeight/10) ; + setbounds currentpicture to OverlayBox ; +\stopuseMPgraphic +\startuseMPgraphic{mml:enclose:right} + draw rightboundary OverlayBox withpen pencircle scaled (ExHeight/10) ; + setbounds currentpicture to OverlayBox ; +\stopuseMPgraphic +\startuseMPgraphic{mml:enclose:top} + draw topboundary OverlayBox withpen pencircle scaled (ExHeight/10) ; + setbounds currentpicture to OverlayBox ; +\stopuseMPgraphic +\startuseMPgraphic{mml:enclose:bottom} + draw bottomboundary OverlayBox withpen pencircle scaled (ExHeight/10) ; + setbounds currentpicture to OverlayBox ; +\stopuseMPgraphic +\startuseMPgraphic{mml:enclose:updiagonalstrike} + path p ; p := OverlayBox enlarged -.25ExHeight ; + draw llcorner p -- urcorner p withpen pencircle scaled (ExHeight/10) ; + setbounds currentpicture to OverlayBox ; +\stopuseMPgraphic +\startuseMPgraphic{mml:enclose:downdiagonalstrike} + path p ; p := OverlayBox enlarged -.25ExHeight ; + draw ulcorner p -- lrcorner p withpen pencircle scaled (ExHeight/10) ; + setbounds currentpicture to OverlayBox ; +\stopuseMPgraphic +\startuseMPgraphic{mml:enclose:horizontalstrike} + path p ; p := OverlayBox enlarged -.25ExHeight ; + draw .5[llcorner p,ulcorner p] -- .5[lrcorner p,urcorner p] withpen pencircle scaled (ExHeight/10) ; + setbounds currentpicture to OverlayBox ; +\stopuseMPgraphic +\startuseMPgraphic{mml:enclose:verticalstrike} + path p ; p := OverlayBox enlarged -.25ExHeight ; + draw .5[llcorner p,lrcorner p] -- .5[ulcorner p,urcorner p] withpen pencircle scaled (ExHeight/10) ; + setbounds currentpicture to OverlayBox ; +\stopuseMPgraphic + +\startxmlsetups mml:menclose + \edef\mmlmenclosenotation{\mathml_menclosepattern{#1}} + \ifempty\mmlmenclosenotation + \xmlflush{#1} + \else + \doifelse \mmlmenclosenotation {mml:enclose:longdiv} { + \overline{\left)\strut\xmlflush{#1}\right.} + } { + \doifelse \mmlmenclosenotation {mml:enclose:actuarial} { + \overline{\left.\strut\xmlflush{#1}\right\vert} + } { + \doifelse \mmlmenclosenotation {mml:enclose:radical} { + \sqrt{\xmlflush{#1}} + } { + % todo: no framed when longdiv, actuarial or radical ? spec ? + \vcenter { + \framed + [frame=off,strut=no,background={\mmlmenclosenotation}] % offset is kind of undefined + { + \startpickupmath + \expanded{\doifelseinset {mml:enclose:longdiv} {\mmlmenclosenotation}} { + \overline{\left)\strut\xmlflush{#1}\right.} + } { + \expanded{\doifelseinset {mml:enclose:actuarial} {\mmlmenclosenotation}} { + \overline{\left.\strut\xmlflush{#1}\right\vert} + } { + \expanded{\doifelseinset {mml:enclose:radical} {\mmlmenclosenotation}} { + \sqrt{\xmlflush{#1}} + } { + \expanded{\doifelseinset {mml:enclose:rule} {\mmlmenclosenotation}} { + \overline{\strut\xmlflush{#1}} + } { + \xmlflush{#1} + } + } + } + } + \stoppickupmath + } + } + } + } + } + \fi +\stopxmlsetups + +\xmlmapvalue {mml:mfrac:linethickness} {thin} {.2pt} +\xmlmapvalue {mml:mfrac:linethickness} {medium} {.4pt} +\xmlmapvalue {mml:mfrac:linethickness} {thick} {.8pt} +\xmlmapvalue {mml:mfrac:linethickness} {0} {0pt} + +\startxmlsetups mml:mfrac % dodo: handle linethickness in lua + unit + \begingroup + \edef\mmlfraclinethickness{\xmlatt{#1}{linethickness}} + \ifempty\mmlfraclinethickness + \doifelse{\xmlatt{#1}{bevelled}}{true} { + \left.\mmlfirst{#1}\middle/\mmlsecond{#1}\right.% \thinspace\middle/\thinspace + } { + \mmlfrac{\mmlfirst{#1}}{\mmlsecond{#1}} + } + \else % use \ifchknum + \doifelse {\xmlval{mml:mfrac:linethickness}{\mmlfraclinethickness}{}} {} { + \scratchdimen\xmlval{mml:mfrac:linethickness}\mmlfraclinethickness{.4pt} + } { + % probably not yet ok + \setdimensionwithunit\scratchdimen\mmlfraclinethickness{pt} + } + { + {\mmlfirst{#1}} + \above\scratchdimen + {\mmlsecond{#1}} + } + \fi + \endgroup +\stopxmlsetups + +\startxmlsetups mml:ms + \hbox { + \tf % else encoding problems + \ifxmlattempty{#1}{lquote}\symbol[leftquotation]\else\xmllastatt\fi + \applymmlsometext{#1}{\xmlflush{#1}} + \ifxmlattempty{#1}{rquote}\symbol[rightquotation]\else\xmllastatt\fi + } +\stopxmlsetups + +\startxmlsetups mml:mstyle + \begingroup + \pushmathstyle + \setmmlmathstyle{#1} + \setmmlscriptlevel{#1} + \xmlflush{#1} + \popmathstyle + \endgroup +\stopxmlsetups + +\setupMMLappearance[text][\c!alternative=\v!b] % a=normal, b=keep spaces + +\startxmlsetups mml:mtext + \text { + \applymmlsometext{#1}{ + \ifcstok{\MMLtextalternative}\v!a + \ignorespaces + \xmlflush{#1} + \removeunwantedspaces + \else + \xmlflush{#1} + \fi + } + } +\stopxmlsetups + +\startxmlsetups mml:merror + \hbox{\startimath\displaystyle\xmlflush{#1}\stopimath} +\stopxmlsetups + +\startxmlsetups mml:mphantom + \phantom{\triggermathstyle\normalmathstyle\ignorespaces\xmlflush{#1}\removeunwantedspaces} +\stopxmlsetups + +\startxmlsetups mml:mpadded % todo + \xmlflush{#1} +\stopxmlsetups + +% mrow / option: no fenced + +\startxmlsetups mml:maction + \xmlflush{#1} +\stopxmlsetups + +\startxmlsetups mml:mrow + \begingroup + \xmlflush{#1} + \endgroup +\stopxmlsetups + +\startxmlsetups mml:msqrt + \sqrt{\xmlflush{#1}} +\stopxmlsetups + +\startxmlsetups mml:mroot + \root{\mmlsecond{#1}}\of{\mmlfirst{#1}} +\stopxmlsetups + +\setupMMLappearance[scripts][\c!alternative=\v!a] % {} rond base + +% brrr no { } when limop .. todo: better in lua +% speed up with ifx and setups or just in lua + +\let\mmlnucleus\relax + +% maybe make helper +% \iftok{\utfmathclass{\xmlraw{#1}{/mml:*[1]}}}{limop} +% \ifcstok{\utfmathclass{\xmlraw{#1}{/mml:*[1]}}}\s!limop + +\startxmlsetups mml:msub + \iftok{\utfmathclass{\xmlraw{#1}{/mml:*[1]}}}{limop} + \mmlfirst{#1} + \normalsubscript{\mmlsecond{#1}} + \orelse\ifcstok{\MMLscriptsalternative}\v!a + {\mmlfirst{#1}} + \normalsubscript{\mmlsecond{#1}} + \else + \mmlfirst{#1} + \normalsubscript{\mmlsecond{#1}} + \fi +\stopxmlsetups + +\startxmlsetups mml:msup + \iftok{\utfmathclass{\xmlraw{#1}{/mml:*[1]}}}{limop} + \mmlfirst{#1} + \normalsuperscript{\mmlsecond{#1}} + \orelse\ifcstok{\MMLscriptsalternative}\v!a + {\mmlfirst{#1}} + \normalsuperscript{\mmlsecond{#1}} + \else + \mmlfirst{#1} + \normalsuperscript{\mmlsecond{#1}} + \fi +\stopxmlsetups + +% use mathclass number + +\startxmlsetups mml:msubsup + \iftok{\utfmathclass{\xmlraw{#1}{/mml:*[1]}}}{limop} + \mmlfirst{#1} + \normalsubscript{\mmlsecond{#1}} + \normalsuperscript{\mmlthird{#1}} + \orelse\ifcstok{\MMLscriptsalternative}\v!a + {\mmlfirst{#1}} + \normalsubscript{\mmlsecond{#1}} + \normalsuperscript{\mmlthird {#1}} + \else + \mmlfirst{#1} + \normalsubscript{\mmlsecond{#1}} + \normalsuperscript{\mmlthird {#1}} + \fi +\stopxmlsetups + +% helpers + +\protected\def\mmlexecutecommand#1% + {\ifcsname#1\endcsname + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments + \fi + \lastnamedcs} + +\let\mmlextensible\mathml_extensible + +\definemathtriplet [\v!mathematics] [mmlovertriplet] % or will we use a special instance +\definemathtriplet [\v!mathematics] [mmlundertriplet] % or will we use a special instance +\definemathtriplet [\v!mathematics] [mmldoubletriplet] % or will we use a special instance + +% common to munder/mover/munderover : will become core helper (speed up too) + +\starttexdefinition protected mmlfencedfirst #1 + \xmlelement{#1}{1} +\stoptexdefinition +\starttexdefinition protected mmlfencedsecond #1 + \xmlelement{#1}{2} +\stoptexdefinition +\starttexdefinition protected mmlfencedthird #1 + \xmlelement{#1}{3} +\stoptexdefinition + +% mover + +\starttexdefinition protected mmloverabove #1 + \mmlexecutecommand{\utfmathfiller\mmlovertoken} {\mmlfencedsecond{#1}} \relax +\stoptexdefinition +\starttexdefinition protected mmloverbase #1 + \mmlexecutecommand{\utfmathfiller\mmlbasetoken} {\mmlfencedfirst{#1}} \relax +\stoptexdefinition +\starttexdefinition protected mmloverbasefiller #1 + \mmlexecutecommand{e\utfmathcommandfiller\mmlbasetoken} \relax {\mmlfencedsecond{#1}} {} +\stoptexdefinition +\starttexdefinition protected mmloveraccent #1 + \mmlexecutecommand{\utfmathcommandabove\mmlovertoken} \relax {\mmlfencedfirst{#1}} +\stoptexdefinition + +\starttexdefinition protected mmlovertext #1 + \mmlovertriplet {\mmloverbase{#1}} {\mmloverabove{#1}} {} +\stoptexdefinition +\starttexdefinition protected mmloveraccentchecker #1 + \edef\mmlovertoken{\mmlextensible{\xmlraw{#1}{/mml:*[2]}}}% /text() + \doifelseutfmathabove\mmlovertoken \mmloveraccent \mmlovertext {#1} +\stoptexdefinition + +\startxmlsetups mml:mover + \edef\mmlbasetoken{\mmlextensible{\xmlraw{#1}{/mml:*[1]}}}% /text() + \doifelseutfmathlimop\mmlbasetoken + {\mmllimopover{#1}} + {\doifelseutfmathfiller\mmlbasetoken \mmloverbasefiller \mmloveraccentchecker {#1}} +\stopxmlsetups + +\starttexdefinition mmllimopover #1 + \mmlbasetoken\normalsuperscript{\mmlfencedsecond{#1}} +\stoptexdefinition + +% munder + +\starttexdefinition protected mmlunderbelow #1 + \mmlexecutecommand{\utfmathfiller\mmlundertoken} {\mmlfencedsecond{#1}} \relax +\stoptexdefinition +\starttexdefinition protected mmlunderbase #1 + \mmlexecutecommand{\utfmathfiller\mmlbasetoken} {\mmlfencedfirst{#1}} \relax +\stoptexdefinition +\starttexdefinition protected mmlunderbasefiller #1 + \mmlexecutecommand{e\utfmathcommandfiller\mmlbasetoken} \relax {} {\mmlfencedsecond{#1}} +\stoptexdefinition +\starttexdefinition protected mmlunderaccent #1 + \mmlexecutecommand{\utfmathcommandbelow\mmlundertoken} \relax {\mmlfencedfirst{#1}} +\stoptexdefinition + +\starttexdefinition protected mmlundertext #1 + \mmlundertriplet {\mmlunderbase{#1}} {} {\mmlunderbelow{#1}} +\stoptexdefinition +\starttexdefinition protected mmlunderaccentchecker #1 + \edef\mmlundertoken{\mmlextensible{\xmlraw{#1}{/mml:*[2]}}}% /text() + \doifelseutfmathbelow\mmlundertoken \mmlunderaccent \mmlundertext {#1} +\stoptexdefinition + +\startxmlsetups mml:munder + \edef\mmlbasetoken{\mmlextensible{\xmlraw{#1}{/mml:*[1]}}}% /text() + \doifelseutfmathlimop\mmlbasetoken + {\mmllimopunder{#1}} + {\doifelseutfmathfiller\mmlbasetoken \mmlunderbasefiller \mmlunderaccentchecker {#1}} +\stopxmlsetups + +\starttexdefinition mmllimopunder #1 + \mmlbasetoken\normalsubscript{\mmlfencedsecond{#1}} +\stoptexdefinition + +% munderover + +\starttexdefinition protected mmlunderoveraccentcheckerUO #1 + \edef\mmlundercommand{\utfmathcommandbelow\mmlundertoken} + \edef\mmlovercommand {\utfmathcommandabove\mmlovertoken} + \edef\mmlbasecommand {\mmlovercommand\mmlundercommand} + \ifcsname\mmlbasecommand\endcsname + \lastnamedcs {\mmlfencedfirst{#1}} + \orelse\ifcsname\mmlundercommand\endcsname + \ifcsname\mmlovercommand\endcsname + \lastnamedcs {\csname\mmlundercommand\endcsname{\mmlfencedfirst{#1}}} + \else + \mmldoubletriplet {\csname\mmlundercommand\endcsname{\mmlfencedfirst{#1}}} {\mmlfencedthird{#1}\mmlfencedthird{#1}} {} + \fi + \orelse\ifcsname\mmlovercommand\endcsname + \mmldoubletriplet {\csname\mmlovercommand\endcsname{\mmlfencedfirst{#1}}} {} {\mmlfencedsecond{#1}} + \else + \mmlunderoveraccentcheckerTT {#1} + \fi +\stoptexdefinition +\starttexdefinition protected mmlunderoveraccentcheckerUT #1 + \edef\mmlundercommand{\utfmathcommandbelow\mmlundertoken} + \edef\mmlbasecommand {\mmlundercommand text} + \ifcsname\mmlbasecommand\endcsname + \lastnamedcs {\mmlfencedfirst{#1}} {\mmlfencedthird{#1}} + \orelse\ifcsname\mmlundercommand\endcsname + \mmldoubletriplet {\csname\mmlundercommand\endcsname{\mmlfencedfirst{#1}}} {\mmlfencedthird{#1}} {} + \else + \mmlunderoveraccentcheckerTT {#1} + \fi +\stoptexdefinition +\starttexdefinition protected mmlunderoveraccentcheckerOT #1 + \edef\mmlovercommand{\utfmathcommandabove\mmlovertoken} + \edef\mmlbasecommand{\mmlovercommand text} + \ifcsname\mmlbasecommand\endcsname + \lastnamedcs {\mmlfencedfirst{#1}} {\mmlfencedsecond{#1}} + \orelse\ifcsname\mmlovercommand\endcsname + \mmldoubletriplet {\csname\mmlovercommand\endcsname{\mmlfencedfirst{#1}}} {} {\mmlfencedsecond{#1}} + \else + \mmlunderoveraccentcheckerTT {#1} + \fi +\stoptexdefinition +\starttexdefinition protected mmlunderoveraccentcheckerTT #1 + \mmldoubletriplet {\mmlfencedfirst{#1}} {\mmlfencedthird{#1}} {\mmlfencedsecond{#1}} \relax +\stoptexdefinition +\starttexdefinition protected mmlunderoveraccentchecker #1 + \edef\mmlundertoken{\mmlextensible{\xmlraw{#1}{/mml:*[2]}}}% /text() + \edef\mmlovertoken {\mmlextensible{\xmlraw{#1}{/mml:*[3]}}}% /text() + \doifelseutfmathbelow\mmlundertoken { + \doifelseutfmathabove\mmlovertoken \mmlunderoveraccentcheckerUO \mmlunderoveraccentcheckerUT {#1} + } { + \doifelseutfmathabove\mmlovertoken \mmlunderoveraccentcheckerOT \mmlunderoveraccentcheckerTT {#1} + } +\stoptexdefinition + +\starttexdefinition protected mmlunderoverbasefiller #1 + \mmlexecutecommand{e\utfmathcommandfiller\mmlbasetoken} \relax {\mmlfencedthird{#1}} {\mmlfencedsecond{#1}} +\stoptexdefinition + +\startxmlsetups mml:munderover + \edef\mmlbasetoken{\mmlextensible{\xmlraw{#1}{/mml:*[1]}}}% /text() + \doifelseutfmathlimop\mmlbasetoken + {\mmllimopunderover{#1}} + {\doifelseutfmathfiller\mmlbasetoken \mmlunderoverbasefiller \mmlunderoveraccentchecker {#1}} +\stopxmlsetups + +\starttexdefinition mmllimopunderover #1 + \mmlbasetoken\normalsuperscript{\mmlfencedthird{#1}}\normalsubscript{\mmlfencedsecond{#1}} +\stoptexdefinition + +% tables (mml:mtable, mml:mtr, mml:mlabledtr, mml:mtd) + +\startxmlsetups mml:mtable % some more attributes need to be supported + \vcenter { + \hbox {% needed because otherwise positions make the vcenter wide + \mathml_mtable{#1} + } + } +\stopxmlsetups + +\startxmlsetups mml:mcolumn + \vbox{\mathml_mcolumn{#1}}% needs checking +\stopxmlsetups + +\def\mmlsetfakewidth#1{\setbox\scratchbox\hbox{#1}\scratchdimen\wd\scratchbox} + +\def\mmlmcolumndigitspace {\mmlsetfakewidth {0}\kern\scratchdimen} +\def\mmlmcolumndigitrule {\mmlsetfakewidth {0}\vrule \s!width \scratchdimen \s!height .2\points \s!depth .2\points\relax} +\def\mmlmcolumnsymbolrule {\mmlsetfakewidth{\times}\vrule \s!width \scratchdimen \s!height .2\points \s!depth .2\points\relax} +\def\mmlmcolumnpunctuationrule{\mmlsetfakewidth {.}\vrule \s!width \scratchdimen \s!height .2\points \s!depth .2\points\relax} + +\setupMMLappearance[mspace][\c!option=] % \v!test + +\startxmlsetups mml:mspace + \begingroup + \edef\mmlspacetext{\xmlatt{#1}{spacing}} + \ifempty\mmlspacetext + \scratchwidth \xmlattdef{#1}{width} \!!zeropoint % must be string + \scratchheight\xmlattdef{#1}{height}\!!zeropoint + \scratchdepth \xmlattdef{#1}{depth} \!!zeropoint + \ifdim\scratchheight=\zeropoint + \ifdim\scratchdepth=\zeropoint\else + \novrule\s!depth\scratchdepth\s!height\zeropoint\s!width\zeropoint + \fi + \else + \novrule\s!depth\zeropoint\s!height\scratchheight\s!width\zeropoint + \fi + \ifdim\scratchwidth=\zeropoint + \orelse\ifx\MMLmspaceoption\v!test + \hbox to \scratchwidth{\showstruts\strut\hss\lower2\exheight\hbox{\infofont\xmlattdef{#1}{width}}\hss\strut} + \else + \hskip\scratchwidth + \fi + \orelse\ifx\MMLmspaceoption\v!test + \hbox{\showstruts\strut\phantom{\triggermathstyle\normalmathstyle\mmlspacetext}\strut} + \else + \phantom{\triggermathstyle\normalmathstyle\mmlspacetext} + \fi + \endgroup +\stopxmlsetups + +% later we can do a better job by manipulating node lists + +% \startxmlsetups mml:mline +% % new, rather undefined, we need to capture a few keywords +% \edef\mmllinewidth {\xmlatt{#1}{linethickness}} +% \edef\mmllinetext {\xmlatt{#1}{spacing}} +% \edef\mmllinelength{\xmlattdef{#1}{length}\!!zeropoint} +% \ifempty\mmllinewidth +% \!!deptha.5\linewidth +% \else +% \!!deptha.5\dimexpr\mmllinewidth\relax +% \fi +% \!!heighta\!!deptha +% \ifempty\mmllinetext +% \ifempty\mmllinelength +% \!!widtha\zeropoint +% \else +% \!!widtha\mmllinelength +% \fi +% \else +% \setbox\scratchbox\hbox{\mathematics{\mathstyle{\mmllinetext}}}% not ok +% \!!widtha\wd\scratchbox +% \fi +% \hbox{\vrule\s!width\!!widtha\s!depth\!!deptha\s!height\!!heighta} +% \stopxmlsetups + +\startxmlsetups mml:mglyph % probably never ok (hbox is needed in order to switch to normal font) + \begingroup + \edef\mmlglyphfontfamily{\xmlatt {#1}{fontfamily}} + \edef\mmlglyphalt {\xmlattdef{#1}{alt}{unknown}} + \edef\mmlglyphindex {\xmlatt {#1}{index}} + \ifempty\mmlglyphfontfamily + \hbox{\tttf[no fontfamily specified for \mmlglyphalt]} + \orelse\ifempty\mmlglyphindex + \hbox{\tttf[no index specified for \mmlglyphalt]} + \else + \hbox{\getglyph\mmlglyphfontfamily\mmlglyphindex} + \fi + \endgroup +\stopxmlsetups + +\startxmlsetups mml:maligngroup \stopxmlsetups % will be done when needed +\startxmlsetups mml:malignmark \stopxmlsetups % will be done when needed + +\startxmlsetups mml:none \stopxmlsetups +\startxmlsetups mml:mprescripts \stopxmlsetups + +\startxmlsetups mml:mmultiscripts + \mathml_mmultiscripts{#1} +\stopxmlsetups + +% goodie + +\definebuffer[mml] + +\permanent\protected\def\stopmml{\xmlprocessbuffer{@mml@}{\thedefinedbuffer{mml}}{}} + +\stopmodule + +\protect \endinput + +% TODO: +% +% <apply><divide/> +% <apply><minus/> +% <apply><minus/><ci>b</ci></apply> +% <apply><minus/><ci>b</ci></apply> +% <apply><root/> <ci>a</ci></apply> +% </apply> +% <apply><minus/> +% <apply><minus/><ci>b</ci><ci>b</ci></apply> +% <apply><minus/><ci>b</ci></apply> +% <apply><root/> <ci>a</ci></apply> +% </apply> +% </apply> |