diff options
31 files changed, 895 insertions, 2784 deletions
diff --git a/context/data/scite/scite-context.properties b/context/data/scite/scite-context.properties index 03aaf383b..739967d3c 100644 --- a/context/data/scite/scite-context.properties +++ b/context/data/scite/scite-context.properties @@ -56,7 +56,7 @@ textwrapper.length=68 file.patterns.tex= file.patterns.latex= -file.patterns.context=*.tex;*.mkii;*.mkiv;*.mkvi; +file.patterns.context=*.tex;*.mkii;*.mkiv;*.mkvi;*.mkix;*.mkxi; open.suffix.$(file.patterns.context)=.tex diff --git a/scripts/context/lua/mtx-context.lua b/scripts/context/lua/mtx-context.lua index f164aadd4..4381840b2 100644 --- a/scripts/context/lua/mtx-context.lua +++ b/scripts/context/lua/mtx-context.lua @@ -1053,6 +1053,8 @@ function scripts.context.touch() touchfiles("mkii") touchfiles("mkiv") touchfiles("mkvi") + touchfiles("mkix") + touchfiles("mkxi") else report("touching needs --expert") end @@ -1061,7 +1063,7 @@ end -- modules local labels = { "title", "comment", "status" } -local cards = { "*.mkvi", "*.mkiv", "*.tex" } +local cards = { "*.mkvi", "*.mkiv", "*.mkxi", "*.mkix", "*.tex" } function scripts.context.modules(pattern) local list = { } @@ -1086,7 +1088,7 @@ function scripts.context.modules(pattern) if not done[base] then done[base] = true local suffix = file.suffix(base) - if suffix == "tex" or suffix == "mkiv" or suffix == "mkvi" then + if suffix == "tex" or suffix == "mkiv" or suffix == "mkvi" or suffix == "mkix" or suffix == "mkxi" then local prefix = match(base,"^([xmst])%-") if prefix then v = resolvers.findfile(base) -- so that files on my dev path are seen diff --git a/scripts/context/lua/mtxrun.lua b/scripts/context/lua/mtxrun.lua index a299e3a2b..829c3f11d 100644 --- a/scripts/context/lua/mtxrun.lua +++ b/scripts/context/lua/mtxrun.lua @@ -169,6 +169,14 @@ string.unquote = string.unquoted string.itself = function(s) return s end +-- also handy (see utf variant) + +local pattern = Ct(C(1)^0) + +function string.totable(str) + return lpegmatch(pattern,str) +end + end -- of closure @@ -4132,7 +4140,7 @@ if not modules then modules = { } end modules ['l-unicode'] = { local concat = table.concat local type = type -local P, C, R, Cs = lpeg.P, lpeg.C, lpeg.R, lpeg.Cs +local P, C, R, Cs, Ct = lpeg.P, lpeg.C, lpeg.R, lpeg.Cs, lpeg.Ct local lpegmatch, patterns = lpeg.match, lpeg.patterns local utftype = patterns.utftype local char, byte, find, bytepairs, utfvalues, format = string.char, string.byte, string.find, string.bytepairs, string.utfvalues, string.format @@ -4573,6 +4581,14 @@ function unicode.xstring(s) return format("0x%05X",type(s) == "number" and s or utfbyte(s)) end +-- + +local pattern = Ct(C(patterns.utf8char)^0) + +function utf.totable(str) + return lpegmatch(pattern,str) +end + end -- of closure @@ -4788,14 +4804,6 @@ function tables.encapsulate(core,capsule,protect) end end -local escaped = Cs ( ( - P('\\' ) + - P('"' )/'\\"' + - P('\n')/'\\n' + - P('\r')/'\\r' + - 1 -)^0 ) - local function serialize(t,r,outer) -- no mixes r[#r+1] = "{" local n = #t @@ -4837,7 +4845,19 @@ local function serialize(t,r,outer) -- no mixes end function table.fastserialize(t,prefix) - return concat(serialize(t,{ prefix },true)) + return concat(serialize(t,{ prefix or "return" },true)) +end + +function table.deserialize(str) + local code = loadstring(str) + if not code then + return + end + code = code() + if not code then + return + end + return code end -- inspect(table.fastserialize { a = 1, b = { 4, { 5, 6 } }, c = { d = 7, e = 'f"g\nh' } }) @@ -4857,6 +4877,45 @@ function table.load(filename) end end +local function slowdrop(t) + local r = { } + local l = { } + for i=1,#t do + local ti = t[i] + local j = 0 + for k, v in next, ti do + j = j + 1 + l[j] = format("%s=%q",k,v) + end + r[i] = format(" {%s},\n",concat(l)) + end + return format("return {\n%s}",concat(r)) +end + +local function fastdrop(t) + local r = { "return {\n" } + for i=1,#t do + local ti = t[i] + r[#r+1] = " {" + for k, v in next, ti do + r[#r+1] = format("%s=%q",k,v) + end + r[#r+1] = "},\n" + end + r[#r+1] = "}" + return concat(r) +end + +function table.drop(t,slow) + if #t == 0 then + return "return { }" + elseif slow == true then + return slowdrop(t) -- less memory + else + return fastdrop(t) -- some 15% faster + end +end + end -- of closure @@ -9944,12 +10003,12 @@ xml.selection = selection -- new method, simple handle -- generic function finalizer (independant namespace) -local function dofunction(collected,fnc) +local function dofunction(collected,fnc,...) if collected then local f = functions[fnc] if f then for c=1,#collected do - f(collected[c]) + f(collected[c],...) end else report_lpath("unknown function '%s'",fnc) @@ -15763,7 +15822,10 @@ if not modules then modules = { } end modules ['data-lua'] = { -- on the developments (the loaders must not trigger kpse); we could -- of course use a more extensive lib path spec -local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end) +local trace_libraries = false + +trackers.register("resolvers.libraries", function(v) trace_libraries = v end) +trackers.register("resolvers.locating", function(v) trace_libraries = v end) local report_libraries = logs.reporter("resolvers","libraries") @@ -15772,7 +15834,8 @@ local unpack = unpack or table.unpack local resolvers, package = resolvers, package -local libformats = { 'luatexlibs', 'tex', 'texmfscripts', 'othertextfiles' } -- 'luainputs' +-- local libformats = { 'luatexlibs', 'tex', 'texmfscripts', 'othertextfiles' } +local libformats = { 'lua', 'tex' } local clibformats = { 'lib' } local _path_, libpaths, _cpath_, clibpaths @@ -15796,7 +15859,7 @@ end local function thepath(...) local t = { ... } t[#t+1] = "?.lua" local path = file.join(unpack(t)) - if trace_locating then + if trace_libraries then report_libraries("! appending '%s' to 'package.path'",path) end return path @@ -15818,11 +15881,11 @@ local function loaded(libpaths,name,simple) for i=1,#libpaths do -- package.path, might become option local libpath = libpaths[i] local resolved = gsub(libpath,"%?",simple) - if trace_locating then -- more detail + if trace_libraries then -- more detail report_libraries("! checking for '%s' on 'package.path': '%s' => '%s'",simple,libpath,resolved) end if file.is_readable(resolved) then - if trace_locating then + if trace_libraries then report_libraries("! lib '%s' located via 'package.path': '%s'",name,resolved) end return loadfile(resolved) @@ -15833,22 +15896,22 @@ end package.loaders[2] = function(name) -- was [#package.loaders+1] if file.suffix(name) == "" then name = file.addsuffix(name,"lua") -- maybe a list - if trace_locating then -- mode detail + if trace_libraries then -- mode detail report_libraries("! locating '%s' with forced suffix",name) end else - if trace_locating then -- mode detail + if trace_libraries then -- mode detail report_libraries("! locating '%s'",name) end end for i=1,#libformats do local format = libformats[i] local resolved = resolvers.findfile(name,format) or "" - if trace_locating then -- mode detail + if trace_libraries then -- mode detail report_libraries("! checking for '%s' using 'libformat path': '%s'",name,format) end if resolved ~= "" then - if trace_locating then + if trace_libraries then report_libraries("! lib '%s' located via environment: '%s'",name,resolved) end return loadfile(resolved) @@ -15871,11 +15934,11 @@ package.loaders[2] = function(name) -- was [#package.loaders+1] for p=1,#paths do local path = paths[p] local resolved = file.join(path,libname) - if trace_locating then -- mode detail + if trace_libraries then -- mode detail report_libraries("! checking for '%s' using 'clibformat path': '%s'",libname,path) end if file.is_readable(resolved) then - if trace_locating then + if trace_libraries then report_libraries("! lib '%s' located via 'clibformat': '%s'",libname,resolved) end return package.loadlib(resolved,name) @@ -15885,11 +15948,11 @@ package.loaders[2] = function(name) -- was [#package.loaders+1] for i=1,#clibpaths do -- package.path, might become option local libpath = clibpaths[i] local resolved = gsub(libpath,"?",simple) - if trace_locating then -- more detail + if trace_libraries then -- more detail report_libraries("! checking for '%s' on 'package.cpath': '%s'",simple,libpath) end if file.is_readable(resolved) then - if trace_locating then + if trace_libraries then report_libraries("! lib '%s' located via 'package.cpath': '%s'",name,resolved) end return package.loadlib(resolved,name) @@ -15901,12 +15964,12 @@ package.loaders[2] = function(name) -- was [#package.loaders+1] end local resolved = resolvers.findfile(file.basename(name),'luatexlibs') or "" if resolved ~= "" then - if trace_locating then + if trace_libraries then report_libraries("! lib '%s' located by basename via environment: '%s'",name,resolved) end return loadfile(resolved) end - if trace_locating then + if trace_libraries then report_libraries('? unable to locate lib: %s',name) end -- return "unable to locate " .. name @@ -15925,6 +15988,7 @@ package.obsolete.append_libpath = appendtolibpath -- will become obsolete package.obsolete.prepend_libpath = prependtolibpath -- will become obsolete + end -- of closure do -- create closure to overcome 200 locals limit @@ -16446,6 +16510,8 @@ local report_template = logs.reporter("template") local format = string.format local P, C, Cs, Carg, lpegmatch = lpeg.P, lpeg.C, lpeg.Cs, lpeg.Carg, lpeg.match +-- todo: make installable template.new + local replacer local function replacekey(k,t) @@ -16459,40 +16525,59 @@ local function replacekey(k,t) if trace_template then report_template("setting key %q to value %q",k,v) end - -- return v return lpegmatch(replacer,v,1,t) -- recursive end end ------ leftmarker = P("<!-- ") / "" ------ rightmarker = P(" --!>") / "" +local sqlescape = lpeg.replacer { + { "'", "''" }, + { "\\", "\\\\" }, + { "\r\n", "\\n" }, + { "\r", "\\n" }, + -- { "\t", "\\t" }, +} + +local escapers = { + lua = function(s) + return format("%q",s) + end, + sql = function(s) + return lpegmatch(sqlescape,s) + end, +} + +local function replacekeyunquoted(s,t,how) -- ".. \" " + local escaper = how and escapers[how] or escapers.lua + return escaper(replacekey(s,t)) +end local single = P("%") -- test %test% test : resolves test local double = P("%%") -- test 10%% test : %% becomes % local lquoted = P("%[") -- test %[test]" test : resolves test with escaped "'s local rquoted = P("]%") -- -local escape = double / "%%" -local nosingle = single / "" -local nodouble = double / "" -local nolquoted = lquoted / "" -local norquoted = rquoted / "" +local escape = double / '%%' +local nosingle = single / '' +local nodouble = double / '' +local nolquoted = lquoted / '' +local norquoted = rquoted / '' local key = nosingle * (C((1-nosingle)^1 * Carg(1))/replacekey) * nosingle -local unquoted = nolquoted * ((C((1 - norquoted)^1) * Carg(1))/function(s,t) return format("%q",replacekey(s,t)) end) * norquoted +local unquoted = nolquoted * ((C((1 - norquoted)^1) * Carg(1) * Carg(2))/replacekeyunquoted) * norquoted local any = P(1) replacer = Cs((unquoted + escape + key + any)^0) -local function replace(str,mapping) +local function replace(str,mapping,how) if mapping then - return lpegmatch(replacer,str,1,mapping) or str + return lpegmatch(replacer,str,1,mapping,how or "lua") or str else return str end end --- print(replace("test %[x]% test",{ x = [[a "x" a]] })) +-- print(replace("test '%[x]%' test",{ x = [[a 'x' a]] })) +-- print(replace("test '%[x]%' test",{ x = [[a 'x' a]] },'sql')) templates.replace = replace diff --git a/scripts/context/stubs/mswin/mtxrun.lua b/scripts/context/stubs/mswin/mtxrun.lua index a299e3a2b..829c3f11d 100644 --- a/scripts/context/stubs/mswin/mtxrun.lua +++ b/scripts/context/stubs/mswin/mtxrun.lua @@ -169,6 +169,14 @@ string.unquote = string.unquoted string.itself = function(s) return s end +-- also handy (see utf variant) + +local pattern = Ct(C(1)^0) + +function string.totable(str) + return lpegmatch(pattern,str) +end + end -- of closure @@ -4132,7 +4140,7 @@ if not modules then modules = { } end modules ['l-unicode'] = { local concat = table.concat local type = type -local P, C, R, Cs = lpeg.P, lpeg.C, lpeg.R, lpeg.Cs +local P, C, R, Cs, Ct = lpeg.P, lpeg.C, lpeg.R, lpeg.Cs, lpeg.Ct local lpegmatch, patterns = lpeg.match, lpeg.patterns local utftype = patterns.utftype local char, byte, find, bytepairs, utfvalues, format = string.char, string.byte, string.find, string.bytepairs, string.utfvalues, string.format @@ -4573,6 +4581,14 @@ function unicode.xstring(s) return format("0x%05X",type(s) == "number" and s or utfbyte(s)) end +-- + +local pattern = Ct(C(patterns.utf8char)^0) + +function utf.totable(str) + return lpegmatch(pattern,str) +end + end -- of closure @@ -4788,14 +4804,6 @@ function tables.encapsulate(core,capsule,protect) end end -local escaped = Cs ( ( - P('\\' ) + - P('"' )/'\\"' + - P('\n')/'\\n' + - P('\r')/'\\r' + - 1 -)^0 ) - local function serialize(t,r,outer) -- no mixes r[#r+1] = "{" local n = #t @@ -4837,7 +4845,19 @@ local function serialize(t,r,outer) -- no mixes end function table.fastserialize(t,prefix) - return concat(serialize(t,{ prefix },true)) + return concat(serialize(t,{ prefix or "return" },true)) +end + +function table.deserialize(str) + local code = loadstring(str) + if not code then + return + end + code = code() + if not code then + return + end + return code end -- inspect(table.fastserialize { a = 1, b = { 4, { 5, 6 } }, c = { d = 7, e = 'f"g\nh' } }) @@ -4857,6 +4877,45 @@ function table.load(filename) end end +local function slowdrop(t) + local r = { } + local l = { } + for i=1,#t do + local ti = t[i] + local j = 0 + for k, v in next, ti do + j = j + 1 + l[j] = format("%s=%q",k,v) + end + r[i] = format(" {%s},\n",concat(l)) + end + return format("return {\n%s}",concat(r)) +end + +local function fastdrop(t) + local r = { "return {\n" } + for i=1,#t do + local ti = t[i] + r[#r+1] = " {" + for k, v in next, ti do + r[#r+1] = format("%s=%q",k,v) + end + r[#r+1] = "},\n" + end + r[#r+1] = "}" + return concat(r) +end + +function table.drop(t,slow) + if #t == 0 then + return "return { }" + elseif slow == true then + return slowdrop(t) -- less memory + else + return fastdrop(t) -- some 15% faster + end +end + end -- of closure @@ -9944,12 +10003,12 @@ xml.selection = selection -- new method, simple handle -- generic function finalizer (independant namespace) -local function dofunction(collected,fnc) +local function dofunction(collected,fnc,...) if collected then local f = functions[fnc] if f then for c=1,#collected do - f(collected[c]) + f(collected[c],...) end else report_lpath("unknown function '%s'",fnc) @@ -15763,7 +15822,10 @@ if not modules then modules = { } end modules ['data-lua'] = { -- on the developments (the loaders must not trigger kpse); we could -- of course use a more extensive lib path spec -local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end) +local trace_libraries = false + +trackers.register("resolvers.libraries", function(v) trace_libraries = v end) +trackers.register("resolvers.locating", function(v) trace_libraries = v end) local report_libraries = logs.reporter("resolvers","libraries") @@ -15772,7 +15834,8 @@ local unpack = unpack or table.unpack local resolvers, package = resolvers, package -local libformats = { 'luatexlibs', 'tex', 'texmfscripts', 'othertextfiles' } -- 'luainputs' +-- local libformats = { 'luatexlibs', 'tex', 'texmfscripts', 'othertextfiles' } +local libformats = { 'lua', 'tex' } local clibformats = { 'lib' } local _path_, libpaths, _cpath_, clibpaths @@ -15796,7 +15859,7 @@ end local function thepath(...) local t = { ... } t[#t+1] = "?.lua" local path = file.join(unpack(t)) - if trace_locating then + if trace_libraries then report_libraries("! appending '%s' to 'package.path'",path) end return path @@ -15818,11 +15881,11 @@ local function loaded(libpaths,name,simple) for i=1,#libpaths do -- package.path, might become option local libpath = libpaths[i] local resolved = gsub(libpath,"%?",simple) - if trace_locating then -- more detail + if trace_libraries then -- more detail report_libraries("! checking for '%s' on 'package.path': '%s' => '%s'",simple,libpath,resolved) end if file.is_readable(resolved) then - if trace_locating then + if trace_libraries then report_libraries("! lib '%s' located via 'package.path': '%s'",name,resolved) end return loadfile(resolved) @@ -15833,22 +15896,22 @@ end package.loaders[2] = function(name) -- was [#package.loaders+1] if file.suffix(name) == "" then name = file.addsuffix(name,"lua") -- maybe a list - if trace_locating then -- mode detail + if trace_libraries then -- mode detail report_libraries("! locating '%s' with forced suffix",name) end else - if trace_locating then -- mode detail + if trace_libraries then -- mode detail report_libraries("! locating '%s'",name) end end for i=1,#libformats do local format = libformats[i] local resolved = resolvers.findfile(name,format) or "" - if trace_locating then -- mode detail + if trace_libraries then -- mode detail report_libraries("! checking for '%s' using 'libformat path': '%s'",name,format) end if resolved ~= "" then - if trace_locating then + if trace_libraries then report_libraries("! lib '%s' located via environment: '%s'",name,resolved) end return loadfile(resolved) @@ -15871,11 +15934,11 @@ package.loaders[2] = function(name) -- was [#package.loaders+1] for p=1,#paths do local path = paths[p] local resolved = file.join(path,libname) - if trace_locating then -- mode detail + if trace_libraries then -- mode detail report_libraries("! checking for '%s' using 'clibformat path': '%s'",libname,path) end if file.is_readable(resolved) then - if trace_locating then + if trace_libraries then report_libraries("! lib '%s' located via 'clibformat': '%s'",libname,resolved) end return package.loadlib(resolved,name) @@ -15885,11 +15948,11 @@ package.loaders[2] = function(name) -- was [#package.loaders+1] for i=1,#clibpaths do -- package.path, might become option local libpath = clibpaths[i] local resolved = gsub(libpath,"?",simple) - if trace_locating then -- more detail + if trace_libraries then -- more detail report_libraries("! checking for '%s' on 'package.cpath': '%s'",simple,libpath) end if file.is_readable(resolved) then - if trace_locating then + if trace_libraries then report_libraries("! lib '%s' located via 'package.cpath': '%s'",name,resolved) end return package.loadlib(resolved,name) @@ -15901,12 +15964,12 @@ package.loaders[2] = function(name) -- was [#package.loaders+1] end local resolved = resolvers.findfile(file.basename(name),'luatexlibs') or "" if resolved ~= "" then - if trace_locating then + if trace_libraries then report_libraries("! lib '%s' located by basename via environment: '%s'",name,resolved) end return loadfile(resolved) end - if trace_locating then + if trace_libraries then report_libraries('? unable to locate lib: %s',name) end -- return "unable to locate " .. name @@ -15925,6 +15988,7 @@ package.obsolete.append_libpath = appendtolibpath -- will become obsolete package.obsolete.prepend_libpath = prependtolibpath -- will become obsolete + end -- of closure do -- create closure to overcome 200 locals limit @@ -16446,6 +16510,8 @@ local report_template = logs.reporter("template") local format = string.format local P, C, Cs, Carg, lpegmatch = lpeg.P, lpeg.C, lpeg.Cs, lpeg.Carg, lpeg.match +-- todo: make installable template.new + local replacer local function replacekey(k,t) @@ -16459,40 +16525,59 @@ local function replacekey(k,t) if trace_template then report_template("setting key %q to value %q",k,v) end - -- return v return lpegmatch(replacer,v,1,t) -- recursive end end ------ leftmarker = P("<!-- ") / "" ------ rightmarker = P(" --!>") / "" +local sqlescape = lpeg.replacer { + { "'", "''" }, + { "\\", "\\\\" }, + { "\r\n", "\\n" }, + { "\r", "\\n" }, + -- { "\t", "\\t" }, +} + +local escapers = { + lua = function(s) + return format("%q",s) + end, + sql = function(s) + return lpegmatch(sqlescape,s) + end, +} + +local function replacekeyunquoted(s,t,how) -- ".. \" " + local escaper = how and escapers[how] or escapers.lua + return escaper(replacekey(s,t)) +end local single = P("%") -- test %test% test : resolves test local double = P("%%") -- test 10%% test : %% becomes % local lquoted = P("%[") -- test %[test]" test : resolves test with escaped "'s local rquoted = P("]%") -- -local escape = double / "%%" -local nosingle = single / "" -local nodouble = double / "" -local nolquoted = lquoted / "" -local norquoted = rquoted / "" +local escape = double / '%%' +local nosingle = single / '' +local nodouble = double / '' +local nolquoted = lquoted / '' +local norquoted = rquoted / '' local key = nosingle * (C((1-nosingle)^1 * Carg(1))/replacekey) * nosingle -local unquoted = nolquoted * ((C((1 - norquoted)^1) * Carg(1))/function(s,t) return format("%q",replacekey(s,t)) end) * norquoted +local unquoted = nolquoted * ((C((1 - norquoted)^1) * Carg(1) * Carg(2))/replacekeyunquoted) * norquoted local any = P(1) replacer = Cs((unquoted + escape + key + any)^0) -local function replace(str,mapping) +local function replace(str,mapping,how) if mapping then - return lpegmatch(replacer,str,1,mapping) or str + return lpegmatch(replacer,str,1,mapping,how or "lua") or str else return str end end --- print(replace("test %[x]% test",{ x = [[a "x" a]] })) +-- print(replace("test '%[x]%' test",{ x = [[a 'x' a]] })) +-- print(replace("test '%[x]%' test",{ x = [[a 'x' a]] },'sql')) templates.replace = replace diff --git a/scripts/context/stubs/unix/mtxrun b/scripts/context/stubs/unix/mtxrun index a299e3a2b..829c3f11d 100644 --- a/scripts/context/stubs/unix/mtxrun +++ b/scripts/context/stubs/unix/mtxrun @@ -169,6 +169,14 @@ string.unquote = string.unquoted string.itself = function(s) return s end +-- also handy (see utf variant) + +local pattern = Ct(C(1)^0) + +function string.totable(str) + return lpegmatch(pattern,str) +end + end -- of closure @@ -4132,7 +4140,7 @@ if not modules then modules = { } end modules ['l-unicode'] = { local concat = table.concat local type = type -local P, C, R, Cs = lpeg.P, lpeg.C, lpeg.R, lpeg.Cs +local P, C, R, Cs, Ct = lpeg.P, lpeg.C, lpeg.R, lpeg.Cs, lpeg.Ct local lpegmatch, patterns = lpeg.match, lpeg.patterns local utftype = patterns.utftype local char, byte, find, bytepairs, utfvalues, format = string.char, string.byte, string.find, string.bytepairs, string.utfvalues, string.format @@ -4573,6 +4581,14 @@ function unicode.xstring(s) return format("0x%05X",type(s) == "number" and s or utfbyte(s)) end +-- + +local pattern = Ct(C(patterns.utf8char)^0) + +function utf.totable(str) + return lpegmatch(pattern,str) +end + end -- of closure @@ -4788,14 +4804,6 @@ function tables.encapsulate(core,capsule,protect) end end -local escaped = Cs ( ( - P('\\' ) + - P('"' )/'\\"' + - P('\n')/'\\n' + - P('\r')/'\\r' + - 1 -)^0 ) - local function serialize(t,r,outer) -- no mixes r[#r+1] = "{" local n = #t @@ -4837,7 +4845,19 @@ local function serialize(t,r,outer) -- no mixes end function table.fastserialize(t,prefix) - return concat(serialize(t,{ prefix },true)) + return concat(serialize(t,{ prefix or "return" },true)) +end + +function table.deserialize(str) + local code = loadstring(str) + if not code then + return + end + code = code() + if not code then + return + end + return code end -- inspect(table.fastserialize { a = 1, b = { 4, { 5, 6 } }, c = { d = 7, e = 'f"g\nh' } }) @@ -4857,6 +4877,45 @@ function table.load(filename) end end +local function slowdrop(t) + local r = { } + local l = { } + for i=1,#t do + local ti = t[i] + local j = 0 + for k, v in next, ti do + j = j + 1 + l[j] = format("%s=%q",k,v) + end + r[i] = format(" {%s},\n",concat(l)) + end + return format("return {\n%s}",concat(r)) +end + +local function fastdrop(t) + local r = { "return {\n" } + for i=1,#t do + local ti = t[i] + r[#r+1] = " {" + for k, v in next, ti do + r[#r+1] = format("%s=%q",k,v) + end + r[#r+1] = "},\n" + end + r[#r+1] = "}" + return concat(r) +end + +function table.drop(t,slow) + if #t == 0 then + return "return { }" + elseif slow == true then + return slowdrop(t) -- less memory + else + return fastdrop(t) -- some 15% faster + end +end + end -- of closure @@ -9944,12 +10003,12 @@ xml.selection = selection -- new method, simple handle -- generic function finalizer (independant namespace) -local function dofunction(collected,fnc) +local function dofunction(collected,fnc,...) if collected then local f = functions[fnc] if f then for c=1,#collected do - f(collected[c]) + f(collected[c],...) end else report_lpath("unknown function '%s'",fnc) @@ -15763,7 +15822,10 @@ if not modules then modules = { } end modules ['data-lua'] = { -- on the developments (the loaders must not trigger kpse); we could -- of course use a more extensive lib path spec -local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end) +local trace_libraries = false + +trackers.register("resolvers.libraries", function(v) trace_libraries = v end) +trackers.register("resolvers.locating", function(v) trace_libraries = v end) local report_libraries = logs.reporter("resolvers","libraries") @@ -15772,7 +15834,8 @@ local unpack = unpack or table.unpack local resolvers, package = resolvers, package -local libformats = { 'luatexlibs', 'tex', 'texmfscripts', 'othertextfiles' } -- 'luainputs' +-- local libformats = { 'luatexlibs', 'tex', 'texmfscripts', 'othertextfiles' } +local libformats = { 'lua', 'tex' } local clibformats = { 'lib' } local _path_, libpaths, _cpath_, clibpaths @@ -15796,7 +15859,7 @@ end local function thepath(...) local t = { ... } t[#t+1] = "?.lua" local path = file.join(unpack(t)) - if trace_locating then + if trace_libraries then report_libraries("! appending '%s' to 'package.path'",path) end return path @@ -15818,11 +15881,11 @@ local function loaded(libpaths,name,simple) for i=1,#libpaths do -- package.path, might become option local libpath = libpaths[i] local resolved = gsub(libpath,"%?",simple) - if trace_locating then -- more detail + if trace_libraries then -- more detail report_libraries("! checking for '%s' on 'package.path': '%s' => '%s'",simple,libpath,resolved) end if file.is_readable(resolved) then - if trace_locating then + if trace_libraries then report_libraries("! lib '%s' located via 'package.path': '%s'",name,resolved) end return loadfile(resolved) @@ -15833,22 +15896,22 @@ end package.loaders[2] = function(name) -- was [#package.loaders+1] if file.suffix(name) == "" then name = file.addsuffix(name,"lua") -- maybe a list - if trace_locating then -- mode detail + if trace_libraries then -- mode detail report_libraries("! locating '%s' with forced suffix",name) end else - if trace_locating then -- mode detail + if trace_libraries then -- mode detail report_libraries("! locating '%s'",name) end end for i=1,#libformats do local format = libformats[i] local resolved = resolvers.findfile(name,format) or "" - if trace_locating then -- mode detail + if trace_libraries then -- mode detail report_libraries("! checking for '%s' using 'libformat path': '%s'",name,format) end if resolved ~= "" then - if trace_locating then + if trace_libraries then report_libraries("! lib '%s' located via environment: '%s'",name,resolved) end return loadfile(resolved) @@ -15871,11 +15934,11 @@ package.loaders[2] = function(name) -- was [#package.loaders+1] for p=1,#paths do local path = paths[p] local resolved = file.join(path,libname) - if trace_locating then -- mode detail + if trace_libraries then -- mode detail report_libraries("! checking for '%s' using 'clibformat path': '%s'",libname,path) end if file.is_readable(resolved) then - if trace_locating then + if trace_libraries then report_libraries("! lib '%s' located via 'clibformat': '%s'",libname,resolved) end return package.loadlib(resolved,name) @@ -15885,11 +15948,11 @@ package.loaders[2] = function(name) -- was [#package.loaders+1] for i=1,#clibpaths do -- package.path, might become option local libpath = clibpaths[i] local resolved = gsub(libpath,"?",simple) - if trace_locating then -- more detail + if trace_libraries then -- more detail report_libraries("! checking for '%s' on 'package.cpath': '%s'",simple,libpath) end if file.is_readable(resolved) then - if trace_locating then + if trace_libraries then report_libraries("! lib '%s' located via 'package.cpath': '%s'",name,resolved) end return package.loadlib(resolved,name) @@ -15901,12 +15964,12 @@ package.loaders[2] = function(name) -- was [#package.loaders+1] end local resolved = resolvers.findfile(file.basename(name),'luatexlibs') or "" if resolved ~= "" then - if trace_locating then + if trace_libraries then report_libraries("! lib '%s' located by basename via environment: '%s'",name,resolved) end return loadfile(resolved) end - if trace_locating then + if trace_libraries then report_libraries('? unable to locate lib: %s',name) end -- return "unable to locate " .. name @@ -15925,6 +15988,7 @@ package.obsolete.append_libpath = appendtolibpath -- will become obsolete package.obsolete.prepend_libpath = prependtolibpath -- will become obsolete + end -- of closure do -- create closure to overcome 200 locals limit @@ -16446,6 +16510,8 @@ local report_template = logs.reporter("template") local format = string.format local P, C, Cs, Carg, lpegmatch = lpeg.P, lpeg.C, lpeg.Cs, lpeg.Carg, lpeg.match +-- todo: make installable template.new + local replacer local function replacekey(k,t) @@ -16459,40 +16525,59 @@ local function replacekey(k,t) if trace_template then report_template("setting key %q to value %q",k,v) end - -- return v return lpegmatch(replacer,v,1,t) -- recursive end end ------ leftmarker = P("<!-- ") / "" ------ rightmarker = P(" --!>") / "" +local sqlescape = lpeg.replacer { + { "'", "''" }, + { "\\", "\\\\" }, + { "\r\n", "\\n" }, + { "\r", "\\n" }, + -- { "\t", "\\t" }, +} + +local escapers = { + lua = function(s) + return format("%q",s) + end, + sql = function(s) + return lpegmatch(sqlescape,s) + end, +} + +local function replacekeyunquoted(s,t,how) -- ".. \" " + local escaper = how and escapers[how] or escapers.lua + return escaper(replacekey(s,t)) +end local single = P("%") -- test %test% test : resolves test local double = P("%%") -- test 10%% test : %% becomes % local lquoted = P("%[") -- test %[test]" test : resolves test with escaped "'s local rquoted = P("]%") -- -local escape = double / "%%" -local nosingle = single / "" -local nodouble = double / "" -local nolquoted = lquoted / "" -local norquoted = rquoted / "" +local escape = double / '%%' +local nosingle = single / '' +local nodouble = double / '' +local nolquoted = lquoted / '' +local norquoted = rquoted / '' local key = nosingle * (C((1-nosingle)^1 * Carg(1))/replacekey) * nosingle -local unquoted = nolquoted * ((C((1 - norquoted)^1) * Carg(1))/function(s,t) return format("%q",replacekey(s,t)) end) * norquoted +local unquoted = nolquoted * ((C((1 - norquoted)^1) * Carg(1) * Carg(2))/replacekeyunquoted) * norquoted local any = P(1) replacer = Cs((unquoted + escape + key + any)^0) -local function replace(str,mapping) +local function replace(str,mapping,how) if mapping then - return lpegmatch(replacer,str,1,mapping) or str + return lpegmatch(replacer,str,1,mapping,how or "lua") or str else return str end end --- print(replace("test %[x]% test",{ x = [[a "x" a]] })) +-- print(replace("test '%[x]%' test",{ x = [[a 'x' a]] })) +-- print(replace("test '%[x]%' test",{ x = [[a 'x' a]] },'sql')) templates.replace = replace diff --git a/tex/context/base/cont-new.mkii b/tex/context/base/cont-new.mkii index 386f7e557..e92106c05 100644 --- a/tex/context/base/cont-new.mkii +++ b/tex/context/base/cont-new.mkii @@ -11,7 +11,7 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\newcontextversion{2012.09.06 23:03} +\newcontextversion{2012.09.10 00:57} %D This file is loaded at runtime, thereby providing an %D excellent place for hacks, patches, extensions and new diff --git a/tex/context/base/cont-new.mkiv b/tex/context/base/cont-new.mkiv index 3b53d7d5d..b5125f072 100644 --- a/tex/context/base/cont-new.mkiv +++ b/tex/context/base/cont-new.mkiv @@ -11,7 +11,7 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\newcontextversion{2012.09.06 23:03} +\newcontextversion{2012.09.10 00:57} %D This file is loaded at runtime, thereby providing an excellent place for %D hacks, patches, extensions and new features. diff --git a/tex/context/base/context-version.pdf b/tex/context/base/context-version.pdf Binary files differindex 5642abc09..50e2e7800 100644 --- a/tex/context/base/context-version.pdf +++ b/tex/context/base/context-version.pdf diff --git a/tex/context/base/context-version.png b/tex/context/base/context-version.png Binary files differindex 648fc8263..c4afeadb1 100644 --- a/tex/context/base/context-version.png +++ b/tex/context/base/context-version.png diff --git a/tex/context/base/context.mkii b/tex/context/base/context.mkii index 8b40e2a7c..4d6937ead 100644 --- a/tex/context/base/context.mkii +++ b/tex/context/base/context.mkii @@ -20,7 +20,7 @@ %D your styles an modules. \edef\contextformat {\jobname} -\edef\contextversion{2012.09.06 23:03} +\edef\contextversion{2012.09.10 00:57} %D For those who want to use this: diff --git a/tex/context/base/context.mkiv b/tex/context/base/context.mkiv index 5c81ac2e7..7bd9bb409 100644 --- a/tex/context/base/context.mkiv +++ b/tex/context/base/context.mkiv @@ -25,7 +25,7 @@ %D up and the dependencies are more consistent. \edef\contextformat {\jobname} -\edef\contextversion{2012.09.06 23:03} +\edef\contextversion{2012.09.10 00:57} %D For those who want to use this: @@ -145,7 +145,7 @@ \loadmarkfile{attr-eff} \loadmarkfile{trac-tex} -\loadmarkfile{trac-deb} +\loadmarkfile{trac-deb} % will move up \loadmarkfile{trac-ctx} % maybe move up %loadmarkfile{blob-ini} % not to be used, we only use a helper diff --git a/tex/context/base/data-lua.lua b/tex/context/base/data-lua.lua index 906a611ee..ab762f3d4 100644 --- a/tex/context/base/data-lua.lua +++ b/tex/context/base/data-lua.lua @@ -10,7 +10,10 @@ if not modules then modules = { } end modules ['data-lua'] = { -- on the developments (the loaders must not trigger kpse); we could -- of course use a more extensive lib path spec -local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end) +local trace_libraries = false + +trackers.register("resolvers.libraries", function(v) trace_libraries = v end) +trackers.register("resolvers.locating", function(v) trace_libraries = v end) local report_libraries = logs.reporter("resolvers","libraries") @@ -19,7 +22,8 @@ local unpack = unpack or table.unpack local resolvers, package = resolvers, package -local libformats = { 'luatexlibs', 'tex', 'texmfscripts', 'othertextfiles' } -- 'luainputs' +-- local libformats = { 'luatexlibs', 'tex', 'texmfscripts', 'othertextfiles' } +local libformats = { 'lua', 'tex' } local clibformats = { 'lib' } local _path_, libpaths, _cpath_, clibpaths @@ -43,7 +47,7 @@ end local function thepath(...) local t = { ... } t[#t+1] = "?.lua" local path = file.join(unpack(t)) - if trace_locating then + if trace_libraries then report_libraries("! appending '%s' to 'package.path'",path) end return path @@ -65,11 +69,11 @@ local function loaded(libpaths,name,simple) for i=1,#libpaths do -- package.path, might become option local libpath = libpaths[i] local resolved = gsub(libpath,"%?",simple) - if trace_locating then -- more detail + if trace_libraries then -- more detail report_libraries("! checking for '%s' on 'package.path': '%s' => '%s'",simple,libpath,resolved) end if file.is_readable(resolved) then - if trace_locating then + if trace_libraries then report_libraries("! lib '%s' located via 'package.path': '%s'",name,resolved) end return loadfile(resolved) @@ -80,22 +84,22 @@ end package.loaders[2] = function(name) -- was [#package.loaders+1] if file.suffix(name) == "" then name = file.addsuffix(name,"lua") -- maybe a list - if trace_locating then -- mode detail + if trace_libraries then -- mode detail report_libraries("! locating '%s' with forced suffix",name) end else - if trace_locating then -- mode detail + if trace_libraries then -- mode detail report_libraries("! locating '%s'",name) end end for i=1,#libformats do local format = libformats[i] local resolved = resolvers.findfile(name,format) or "" - if trace_locating then -- mode detail + if trace_libraries then -- mode detail report_libraries("! checking for '%s' using 'libformat path': '%s'",name,format) end if resolved ~= "" then - if trace_locating then + if trace_libraries then report_libraries("! lib '%s' located via environment: '%s'",name,resolved) end return loadfile(resolved) @@ -118,11 +122,11 @@ package.loaders[2] = function(name) -- was [#package.loaders+1] for p=1,#paths do local path = paths[p] local resolved = file.join(path,libname) - if trace_locating then -- mode detail + if trace_libraries then -- mode detail report_libraries("! checking for '%s' using 'clibformat path': '%s'",libname,path) end if file.is_readable(resolved) then - if trace_locating then + if trace_libraries then report_libraries("! lib '%s' located via 'clibformat': '%s'",libname,resolved) end return package.loadlib(resolved,name) @@ -132,11 +136,11 @@ package.loaders[2] = function(name) -- was [#package.loaders+1] for i=1,#clibpaths do -- package.path, might become option local libpath = clibpaths[i] local resolved = gsub(libpath,"?",simple) - if trace_locating then -- more detail + if trace_libraries then -- more detail report_libraries("! checking for '%s' on 'package.cpath': '%s'",simple,libpath) end if file.is_readable(resolved) then - if trace_locating then + if trace_libraries then report_libraries("! lib '%s' located via 'package.cpath': '%s'",name,resolved) end return package.loadlib(resolved,name) @@ -148,12 +152,12 @@ package.loaders[2] = function(name) -- was [#package.loaders+1] end local resolved = resolvers.findfile(file.basename(name),'luatexlibs') or "" if resolved ~= "" then - if trace_locating then + if trace_libraries then report_libraries("! lib '%s' located by basename via environment: '%s'",name,resolved) end return loadfile(resolved) end - if trace_locating then + if trace_libraries then report_libraries('? unable to locate lib: %s',name) end -- return "unable to locate " .. name @@ -170,3 +174,4 @@ package.prepend_libpath = prependtolibpath -- will become obsolete package.obsolete.append_libpath = appendtolibpath -- will become obsolete package.obsolete.prepend_libpath = prependtolibpath -- will become obsolete + diff --git a/tex/context/base/file-job.lua b/tex/context/base/file-job.lua index 168300767..0705b8e5a 100644 --- a/tex/context/base/file-job.lua +++ b/tex/context/base/file-job.lua @@ -718,6 +718,7 @@ end document = document or { arguments = allocate(), files = allocate(), + variables = allocate(), -- for templates options = { commandline = { environments = allocate(), diff --git a/tex/context/base/l-string.lua b/tex/context/base/l-string.lua index cdfa9b051..03616aa19 100644 --- a/tex/context/base/l-string.lua +++ b/tex/context/base/l-string.lua @@ -125,3 +125,11 @@ string.unquote = string.unquoted -- handy fallback string.itself = function(s) return s end + +-- also handy (see utf variant) + +local pattern = Ct(C(1)^0) + +function string.totable(str) + return lpegmatch(pattern,str) +end diff --git a/tex/context/base/l-unicode.lua b/tex/context/base/l-unicode.lua index 6447fb040..cbcec8329 100644 --- a/tex/context/base/l-unicode.lua +++ b/tex/context/base/l-unicode.lua @@ -12,7 +12,7 @@ if not modules then modules = { } end modules ['l-unicode'] = { local concat = table.concat local type = type -local P, C, R, Cs = lpeg.P, lpeg.C, lpeg.R, lpeg.Cs +local P, C, R, Cs, Ct = lpeg.P, lpeg.C, lpeg.R, lpeg.Cs, lpeg.Ct local lpegmatch, patterns = lpeg.match, lpeg.patterns local utftype = patterns.utftype local char, byte, find, bytepairs, utfvalues, format = string.char, string.byte, string.find, string.bytepairs, string.utfvalues, string.format @@ -579,3 +579,11 @@ end function unicode.xstring(s) return format("0x%05X",type(s) == "number" and s or utfbyte(s)) end + +-- + +local pattern = Ct(C(patterns.utf8char)^0) + +function utf.totable(str) + return lpegmatch(pattern,str) +end diff --git a/tex/context/base/luat-lib.mkiv b/tex/context/base/luat-lib.mkiv index 2eba44931..6ca0ac05a 100644 --- a/tex/context/base/luat-lib.mkiv +++ b/tex/context/base/luat-lib.mkiv @@ -69,6 +69,7 @@ \registerctxluafile{luat-exe}{1.001} \registerctxluafile{luat-iop}{1.001} \registerctxluafile{luat-bwc}{1.001} +\registerctxluafile{trac-lmx}{1.001} % might become l-lmx or luat-lmx \registerctxluafile{luat-mac}{1.001} \registerctxluafile{lxml-tab}{1.001} diff --git a/tex/context/base/luat-mac.lua b/tex/context/base/luat-mac.lua index f8f87a25a..199332bba 100644 --- a/tex/context/base/luat-mac.lua +++ b/tex/context/base/luat-mac.lua @@ -20,6 +20,8 @@ local lpegmatch, patterns = lpeg.match, lpeg.patterns local insert, remove = table.insert, table.remove local rep, sub = string.rep, string.sub local setmetatable = setmetatable +local filesuffix = file.suffix +local convertlmxstring = lmx.convertstring local pushtarget, poptarget = logs.pushtarget, logs.poptarget @@ -199,18 +201,91 @@ function macros.version(data) return lpegmatch(checker,data) end +-- function macros.processmkvi(str,filename) +-- if filename and filesuffix(filename) == "mkvi" or lpegmatch(checker,str) == "mkvi" then +-- local oldsize = #str +-- str = lpegmatch(parser,str,1,true) or str +-- pushtarget("log") +-- report_macros("processed mkvi file %q, delta %s",filename,oldsize-#str) +-- poptarget("log") +-- end +-- return str +-- end +-- +-- utilities.sequencers.appendaction(resolvers.openers.helpers.textfileactions,"system","resolvers.macros.processmkvi") + +-- the document variables hack is temporary + +local processors = { } + +function processors.mkvi(str,filename) + local oldsize = #str + str = lpegmatch(parser,str,1,true) or str + pushtarget("log") + report_macros("processed mkvi file %q, delta %s",filename,oldsize-#str) + poptarget("log") + return str +end + +function processors.mkix(str,filename) -- we could intercept earlier so that caching works better + if not document then -- because now we hash the string as well as the + document = { } + end + if not document.variables then + document.variables = { } + end + local oldsize = #str + str = convertlmxstring(str,document.variables,false) or str + pushtarget("log") + report_macros("processed mkix file %q, delta %s",filename,oldsize-#str) + poptarget("log") + return str +end + +function processors.mkxi(str,filename) + if not document then + document = { } + end + if not document.variables then + document.variables = { } + end + local oldsize = #str + str = convertlmxstring(str,document.variables,false) or str + str = lpegmatch(parser,str,1,true) or str + pushtarget("log") + report_macros("processed mkxi file %q, delta %s",filename,oldsize-#str) + poptarget("log") + return str +end + +function macros.processmk(str,filename) + if filename then + local suffix = filesuffix(filename) + local processor = processors[suffix] or processors[lpegmatch(checker,str)] + if processor then + str = processor(str,filename) + end + end + return str +end + +utilities.sequencers.appendaction(resolvers.openers.helpers.textfileactions,"system","resolvers.macros.processmk") + function macros.processmkvi(str,filename) - if (filename and file.suffix(filename) == "mkvi") or lpegmatch(checker,str) == "mkvi" then - local result = lpegmatch(parser,str,1,true) or str + if filename and filesuffix(filename) == "mkvi" or lpegmatch(checker,str) == "mkvi" then + local oldsize = #str + str = lpegmatch(parser,str,1,true) or str pushtarget("log") - report_macros("processed file '%s', delta %s",filename,#str-#result) + report_macros("processed mkvi file %q, delta %s",filename,oldsize-#str) poptarget("log") - return result - else - return str end + return str end +utilities.sequencers.appendaction(resolvers.openers.helpers.textfileactions,"system","resolvers.macros.processmkvi") + +-- bonus + if resolvers.schemes then local function handler(protocol,name,cachename) @@ -218,7 +293,7 @@ if resolvers.schemes then local path = hashed.path if path and path ~= "" then local str = resolvers.loadtexfile(path) - if file.suffix(path) == "mkvi" or lpegmatch(checker,str) == "mkvi" then + if filesuffix(path) == "mkvi" or lpegmatch(checker,str) == "mkvi" then -- already done automatically io.savedata(cachename,str) else @@ -234,9 +309,6 @@ if resolvers.schemes then resolvers.schemes.install('mkvi',handler,1) -- this will cache ! - utilities.sequencers.appendaction(resolvers.openers.helpers.textfileactions,"system","resolvers.macros.processmkvi") - -- utilities.sequencers.disableaction(resolvers.openers.helpers.textfileactions,"resolvers.macros.processmkvi") - end -- print(macros.preprocessed( diff --git a/tex/context/base/lxml-lpt.lua b/tex/context/base/lxml-lpt.lua index 426e07b15..a2926f03b 100644 --- a/tex/context/base/lxml-lpt.lua +++ b/tex/context/base/lxml-lpt.lua @@ -1205,12 +1205,12 @@ xml.selection = selection -- new method, simple handle -- generic function finalizer (independant namespace) -local function dofunction(collected,fnc) +local function dofunction(collected,fnc,...) if collected then local f = functions[fnc] if f then for c=1,#collected do - f(collected[c]) + f(collected[c],...) end else report_lpath("unknown function '%s'",fnc) diff --git a/tex/context/base/s-abr-01.tex b/tex/context/base/s-abr-01.tex index cf2ade8a0..4033560a6 100644 --- a/tex/context/base/s-abr-01.tex +++ b/tex/context/base/s-abr-01.tex @@ -24,6 +24,8 @@ \logo [MKIII] {MkIII} % joke \logo [MKIV] {MkIV} \logo [MKVI] {MkVI} +\logo [MKIX] {MkIX} +\logo [MKXI] {MkXI} \logo [MPII] {MpII} \logo [MPIV] {MpIV} @@ -145,6 +147,7 @@ \logo [LUAJIT] {LuaJIT} \logo [LUATEX] {Lua\TeX} \logo [LUATOOLS] {luatools} +\logo [LMX] {lmx} \logo [MACOSX] {MacOSX} \logo [MACROTEX] {Macro\TeX} \logo [MAKEMPY] {MakeMPY} diff --git a/tex/context/base/sort-lan.lua b/tex/context/base/sort-lan.lua index 84cd7aa49..d2fa276d7 100644 --- a/tex/context/base/sort-lan.lua +++ b/tex/context/base/sort-lan.lua @@ -7,6 +7,9 @@ if not modules then modules = { } end modules ['sort-lan'] = { dataonly = true, } +-- todo: look into uts#10 (2012) ... some experiments ... something +-- to finish in winter. + -- Many vectors were supplied by Wolfgang Schuster and Philipp -- Gesang. However this is a quite adapted and reformatted variant -- so it needs some checking. Other users provides tables and diff --git a/tex/context/base/status-files.pdf b/tex/context/base/status-files.pdf Binary files differindex ca09992dd..b5c7464c8 100644 --- a/tex/context/base/status-files.pdf +++ b/tex/context/base/status-files.pdf diff --git a/tex/context/base/status-lua.pdf b/tex/context/base/status-lua.pdf Binary files differindex 8aa2791d6..51523908b 100644 --- a/tex/context/base/status-lua.pdf +++ b/tex/context/base/status-lua.pdf diff --git a/tex/context/base/status-mkiv.lua b/tex/context/base/status-mkiv.lua index 6690e7be6..f8c6c692b 100644 --- a/tex/context/base/status-mkiv.lua +++ b/tex/context/base/status-mkiv.lua @@ -2556,11 +2556,6 @@ return { }, { category = "lua", - filename = "bibl-tst", - status = "todo", - }, - { - category = "lua", filename = "blob-ini", status = "todo", }, @@ -4481,7 +4476,7 @@ return { category = "lua", comment = "will be redone and extended", filename = "trac-lmx", - loading = "trac-lmx", + loading = "luat-lib", status = "pending", }, { diff --git a/tex/context/base/trac-deb.mkiv b/tex/context/base/trac-deb.mkiv index 10e462a31..fe5dd02dc 100644 --- a/tex/context/base/trac-deb.mkiv +++ b/tex/context/base/trac-deb.mkiv @@ -13,7 +13,7 @@ \writestatus{loading}{ConTeXt Tracing Macros / Debugger} -\registerctxluafile{trac-lmx}{1.001} +%registerctxluafile{trac-lmx}{1.001} \registerctxluafile{trac-deb}{1.001} \unexpanded\def\breakpoint{\showdebuginfo\wait} diff --git a/tex/context/base/trac-lmx.lua b/tex/context/base/trac-lmx.lua index e83fdce7f..b39c8ca54 100644 --- a/tex/context/base/trac-lmx.lua +++ b/tex/context/base/trac-lmx.lua @@ -26,6 +26,9 @@ local report_error = logs.reporter("lmx","error") lmx = lmx or { } local lmx = lmx +-- This will change: we will just pass the global defaults as argument, but then we need +-- to rewrite some older code or come up with an ugly trick. + local lmxvariables = { ['title-default'] = 'ConTeXt LMX File', ['color-background-green'] = '#4F6F6F', @@ -370,10 +373,6 @@ local luacodecss = beginluacss * (1-endluacss)^1 * endluacss --- local othercode = Cc(" p[==[") --- * (1-beginluaxml-beginluacss)^1 --- * Cc("]==] ") - local othercode = (1-beginluaxml-beginluacss)^1 / " p[==[%0]==] " local include = ((beginembedxml * P("lmx-include") * whitespace) / "") @@ -416,7 +415,7 @@ local function wrapper(converter,defaults,variables) end end -function lmxnew(data,defaults) +function lmxnew(data,defaults,nocache) -- todo: use defaults in calling routines data = data or "" local known = cache[data] if not known then @@ -441,7 +440,7 @@ function lmxnew(data,defaults) variables = defaults, converter = converter, } - if cache_templates then + if cache_templates and nocache ~= false then cache[data] = known end elseif variables then @@ -472,23 +471,23 @@ lmx.result = lmxresult local loadedfiles = { } -function lmx.convertstring(templatestring,variables) - return lmxresult(lmxnew(templatestring),variables) +function lmx.convertstring(templatestring,variables,nocache) + return lmxresult(lmxnew(templatestring,nil,nocache),variables) end -function lmx.convertfile(templatefile,variables) +function lmx.convertfile(templatefile,variables,nocache) if trace_variables then -- will become templates report_lmx("converting file: %s",templatefile) end local converter = loadedfiles[templatefile] if not converter then - converter = lmxnew(loadedfile(templatefile)) + converter = lmxnew(loadedfile(templatefile),nil,nocache) loadedfiles[templatefile] = converter end return lmxresult(converter,variables) end -function lmxconvert(templatefile,resultfile,variables) -- or (templatefile,variables) +function lmxconvert(templatefile,resultfile,variables,nocache) -- or (templatefile,variables) if trace_variables then -- will become templates report_lmx("converting file: %s",templatefile) end @@ -497,7 +496,7 @@ function lmxconvert(templatefile,resultfile,variables) -- or (templatefile,varia end local converter = loadedfiles[templatefile] if not converter then - converter = lmxnew(loadedfile(templatefile)) + converter = lmxnew(loadedfile(templatefile),nil,nocache) if cache_files then loadedfiles[templatefile] = converter end diff --git a/tex/context/base/util-sql.lua b/tex/context/base/util-sql.lua index 798ef44af..aeee7c09b 100644 --- a/tex/context/base/util-sql.lua +++ b/tex/context/base/util-sql.lua @@ -6,30 +6,44 @@ if not modules then modules = { } end modules ['util-sql'] = { license = "see context related readme files" } --- Of course we could use a library but we don't want another depedency and --- there is a bit of flux in these libraries. Also, we want the data back in --- a way that we like. - --- Todo: buffer templates when files. +-- Of course we could use a library but we don't want another depedency and there is +-- a bit of flux in these libraries. Also, we want the data back in a way that we +-- like. +-- +-- This is the first of set of sql related modules that are providing functionality +-- for a web based framework that we use for typesetting (related) services. We're +-- talking of session management, job ticket processing, storage, (xml) file processing +-- and dealing with data from databases (often ambitiously called database publishing). +-- +-- There is no generic solution for such services, but from our perspective, as we use +-- context in a regular tds tree (the standard distribution) it makes sense to put shared +-- code in the context distribution. That way we don't need to reinvent wheels every time. local format = string.format +local random = math.random local rawset, setmetatable, loadstring, type = rawset, setmetatable, loadstring, type local P, S, V, C, Cs, Ct, Cc, Cg, Cf, patterns, lpegmatch = lpeg.P, lpeg.S, lpeg.V, lpeg.C, lpeg.Cs, lpeg.Ct, lpeg.Cc, lpeg.Cg, lpeg.Cf, lpeg.patterns, lpeg.match local concat = table.concat -local osclock = os.clock or os.time -local fastserialize = table.fastserialize -local lpegmatch = lpeg.match +local osuuid = os.uuid +local osclock = os.clock or os.time -local trace_sql = false trackers.register("sql.trace",function(v) trace_sql = v end) -local report_state = logs.reporter("sql") +local trace_sql = false trackers.register("sql.trace", function(v) trace_sql = v end) +local trace_queries = false trackers.register("sql.queries",function(v) trace_queries = v end) +local report_state = logs.reporter("sql") -utilities.sql = utilities.sql or { } -local sql = utilities.sql +utilities.sql = utilities.sql or { } +local sql = utilities.sql local replacetemplate = utilities.templates.replace local loadtemplate = utilities.templates.load +local methods = { } +sql.methods = methods + +sql.serialize = table.fastserialize +sql.deserialize = table.deserialize + local defaults = { __index = { resultfile = "result.dat", @@ -44,22 +58,21 @@ local defaults = { __index = }, } -local engine = "mysql" - -local runners = { -- --defaults-extra-file="%inifile" - mysql = [[mysql --user="%username%" --password="%password%" --host="%host%" --port=%port% --database="%database%" < "%queryfile%" > "%resultfile%"]], -} - -sql.runners = runners - -- Experiments with an p/action demonstrated that there is not much gain. We could do a runtime -- capture but creating all the small tables is not faster and it doesn't work well anyway. local separator = P("\t") local newline = patterns.newline -local entry = C((1-separator-newline)^0) -- C 10% faster than Cs local empty = Cc("") +local entry = C((1-separator-newline)^0) -- C 10% faster than Cs + +local unescaped = P("\\n") / "\n" + + P("\\t") / "\t" + + P("\\\\") / "\\" + +local entry = Cs((unescaped + (1-separator-newline))^0) -- C 10% faster than Cs but Cs needed due to nesting + local getfirst = Ct( entry * (separator * (entry+empty))^0) + newline local skipfirst = (1-newline)^1 * newline local getfirstline = C((1-newline)^0) @@ -157,16 +170,39 @@ local function validspecification(specification) return true end -local function dataprepared(specification) - local query = false - if specification.template then - query = replacetemplate(specification.template,specification.variables) - elseif specification.templatefile then - query = loadtemplate(specification.templatefile,specification.variables) +local function preparetemplate(specification) + local template = specification.template + if template then + local query = replacetemplate(template,specification.variables,'sql') + if not query then + report_state("error in template: %s",template) + elseif trace_queries then + report_state("query from template: %s",query) + end + return query + end + local templatefile = specification.templatefile + if templatefile then + local query = loadtemplate(templatefile,specification.variables,'sql') + if not query then + report_state("error in template file %q",templatefile) + elseif trace_queries then + report_state("query from template file %q: %s",templatefile,query) + end + return query end + report_state("no query template or templatefile") +end + + +local function dataprepared(specification) + local query = preparetemplate(specification) if query then io.savedata(specification.queryfile,query) os.remove(specification.resultfile) + if trace_queries then + report_state("query: %s",query) + end return true else -- maybe push an error @@ -175,17 +211,17 @@ local function dataprepared(specification) end end -local function datafetched(specification) - local command = replacetemplate(runners[engine],specification) +local function datafetched(specification,runner) + local command = replacetemplate(runner,specification) if trace_sql then local t = osclock() report_state("command: %s",command) - os.execute(command) + local okay = os.execute(command) report_state("fetchtime: %.3f sec",osclock()-t) -- not okay under linux + return okay == 0 else - os.execute(command) + return os.execute(command) == 0 end - return true end local function dataloaded(specification) @@ -215,66 +251,100 @@ end sql.splitdata = splitdata -local methods = { } -sql.methods = methods - -- todo: new, etc -local function fetch(specification) +local function execute(specification) if trace_sql then - report_state("fetching") + report_state("executing") end if not validspecification(specification) then - report("error in specification") + report_state("error in specification") return end if not dataprepared(specification) then - report("error in preparation") + report_state("error in preparation") return end - if not datafetched(specification) then - report("error in fetching") + if not datafetched(specification,methods.client.runner) then + report_state("error in fetching, query: %s",string.collapsespaces(io.loaddata(specification.queryfile))) return end local data = dataloaded(specification) --- local data = datafetched(specification) if not data then - report("error in loading") + report_state("error in loading") return end local data, keys = dataconverted(data) if not data then - report("error in converting") + report_state("error in converting") return end return data, keys end --- local function reuse(specification) --- if trace_sql then --- report_state("reusing") --- end --- if not validspecification(specification) then --- report("error in specification") --- return --- end --- local data = dataloaded(specification) --- if not data then --- report("error in loading") --- return --- end --- local data, keys = dataconverted(data) --- if not data then --- report("error in converting") --- return --- end --- return data, keys --- end - -sql.fetch = fetch - methods.client = { - fetch = fetch, + runner = [[mysql --batch --user="%username%" --password="%password%" --host="%host%" --port=%port% --database="%database%" < "%queryfile%" > "%resultfile%"]], + execute = execute, + serialize = serialize, + deserialize = deserialize, +} + +local function dataloaded(specification) + if trace_sql then + local t = osclock() + local data = table.load(specification.resultfile) + report_state("loadtime: %.3f sec",osclock()-t) + return data + else + return table.load(specification.resultfile) + end +end + +local function dataconverted(data) + if trace_sql then + local data, keys = data.data, data.keys + report_state("keys: %s ",#keys) + report_state("entries: %s ",#data) + return data, keys + else + return data.data, data.keys + end +end + +local function execute(specification) + if trace_sql then + report_state("executing") + end + if not validspecification(specification) then + report_state("error in specification") + return + end + if not dataprepared(specification) then + report_state("error in preparation") + return + end + if not datafetched(specification,methods.lmxsql.runner) then + report_state("error in fetching, query: %s",string.collapsespaces(io.loaddata(specification.queryfile))) + return + end + local data = dataloaded(specification) + if not data then + report_state("error in loading") + return + end + local data, keys = dataconverted(data) + if not data then + report_state("error in converting") + return + end + return data, keys +end + +methods.lmxsql = { + runner = [[lmx-sql %host% %port% "%username%" "%password%" "%database%" "%queryfile%" "%resultfile%"]], + execute = execute, + serialize = serialize, + deserialize = deserialize, } local mysql = nil @@ -294,17 +364,7 @@ local function validspecification(specification) return true end -local function dataprepared(specification) - local query = false - if specification.template then - query = replacetemplate(specification.template,specification.variables) - elseif specification.templatefile then - query = loadtemplate(specification.templatefile,specification.variables) - end - if query then - return query - end -end +local dataprepared = preparetemplate local function connect(session,specification) return session:connect( @@ -317,9 +377,17 @@ local function connect(session,specification) end local whitespace = patterns.whitespace^0 -local quoted = patterns.quoted local separator = P(";") -local query = whitespace * Cs((quoted + 1 - separator)^1 * Cc(";")) * whitespace +local escaped = patterns.escaped +local dquote = patterns.dquote +local squote = patterns.squote +local dsquote = squote * squote +---- quoted = patterns.quoted +local quoted = dquote * (escaped + (1-dquote))^0 * dquote + + squote * (escaped + dsquote + (1-squote))^0 * squote +local query = whitespace + * Cs((quoted + 1 - separator)^1 * Cc(";")) + * whitespace local splitter = Ct(query * (separator * query)^0) local function datafetched(specification,query) @@ -348,7 +416,9 @@ local function datafetched(specification,query) for i=1,#query do local q = query[i] result, message = connection:execute(q) --- io.savedata("e:/tmp/oeps.sql",q) + if message then + report_state("error in query: %s",string.collapsespaces(q)) + end end if not result and id then if session then @@ -361,7 +431,11 @@ local function datafetched(specification,query) connection = connect(session,specification) cache[id] = { session = session, connection = connection } for i=1,#query do - result, message = connection:execute(query[i]) + local q = query[i] + result, message = connection:execute(q) + if message then + report_state("error in query: %s",string.collapsespaces(q)) + end end end local data, keys @@ -397,7 +471,7 @@ local function datafetched(specification,query) return data, keys end -local function fetch(specification) +local function execute(specification) if not mysql then local lib = require("luasql.mysql") if lib then @@ -407,31 +481,49 @@ local function fetch(specification) end end if trace_sql then - report_state("fetching") + report_state("executing") end if not validspecification(specification) then - report("error in specification") + report_state("error in specification") return end local query = dataprepared(specification) if not query then - report("error in preparation") + report_state("error in preparation") return end local data, keys = datafetched(specification,query) if not data then - report("error in fetching") + report_state("error in fetching") return end return data, keys end methods.library = { - fetch = fetch, + runner = function() end, -- never called + execute = execute, + serialize = serialize, + deserialize = deserialize, } -- -- -- +local currentmethod + +function sql.setmethod(method) + local m = methods[method] + if m then + currentmethod = method + sql.execute = m.execute + return m + else + return methods[currentmethod] + end +end + +sql.setmethod("client") + -- local data = utilities.sql.prepare { -- templatefile = "test.sql", -- variables = { }, @@ -466,93 +558,42 @@ methods.library = { -- presets = "...", -- } --- -- -- - -local e_pattern = lpeg.replacer { { '\\"','\\\\""' }, {'"','""'}, {'\\\n', "\\n" }, {'\\\r', "\\r" }, {'\t', " " } } -local u_pattern = lpeg.replacer { { '\\\\','\\' } } -local u_pattern = lpeg.replacer { { '\\\\','\\' }, { "\n","\\n" } } - --- library: - -function methods.library.serialize(t) - local str = fastserialize(t,"return") - local escaped = lpegmatch(e_pattern,str) - return escaped -end - -function methods.library.deserialize(str) - local unescaped = lpegmatch(u_pattern,str) - if not unescaped then - return - end - local code = loadstring(unescaped) - if not code then - return - end - code = code() - if not code then - return - end - return code -end - --- client - -local e_pattern = lpeg.replacer { { '\\"','\\\\""' }, {'"','""'}, {'\\\n', "\\n" }, {'\\\r', "\\r" } } -local u_pattern = lpeg.replacer { { '\\\\','\\' } } - -function methods.client.serialize(t) - return lpegmatch(e_pattern,fastserialize(t,"return")) -end - -function methods.client.deserialize(str) - local unescaped = lpegmatch(u_pattern,str) - if not unescaped then - return - end - local code = loadstring(unescaped) - if not code then - return - end - code = code() - if not code then - return - end - return code -end - -sql.serialize = methods.client.serialize -sql.deserialize = methods.client.deserialize - -function sql.escape(str) - return lpegmatch(e_pattern,str) -end - -function sql.unescape(str) - return lpegmatch(u_pattern,str) -end - --- local s = sql.serialize { a = 1, b = { 4, { 5, 6 } }, c = { d = 7, e = 'f"g\nh' } } --- local u = sql.unescape(s) --- local t = sql.deserialize(s) --- inspect(s) --- inspect(u) --- inspect(t) +sql.tokens = { + length = 42, + new = function() + return format("%s+%05x",osuuid(),random(1,0xFFFFF)) -- 36 + 1 + 5 = 42 + end, +} -- -- -- if tex and tex.systemmodes then - function sql.prepare(specification) + local droptable = table.drop + local threshold = 16 * 1024 -- use slower but less memory hungry variant + + function sql.prepare(specification,tag) + -- could go into tuc if needed + -- todo: serialize per column + local filename = format("%s-sql-result-%s.tuc",tex.jobname,tag or "last") if tex.systemmodes["first"] then - return sql.fetch(specification) + local data, keys = sql.execute(specification) + if not data then + data = { } + end + if not keys then + keys = { } + end + io.savedata(filename,droptable({ data = data, keys = keys },#keys*#data>threshold)) + return data, keys else - return sql.reuse(specification) + local result = table.load(filename) + return result.data, result.keys end end else - sql.prepare = sql.fetch + sql.prepare = sql.execute end diff --git a/tex/context/base/util-tab.lua b/tex/context/base/util-tab.lua index d45b58f6f..f0977743b 100644 --- a/tex/context/base/util-tab.lua +++ b/tex/context/base/util-tab.lua @@ -168,14 +168,6 @@ function tables.encapsulate(core,capsule,protect) end end -local escaped = Cs ( ( - P('\\' ) + - P('"' )/'\\"' + - P('\n')/'\\n' + - P('\r')/'\\r' + - 1 -)^0 ) - local function serialize(t,r,outer) -- no mixes r[#r+1] = "{" local n = #t @@ -217,7 +209,19 @@ local function serialize(t,r,outer) -- no mixes end function table.fastserialize(t,prefix) - return concat(serialize(t,{ prefix },true)) + return concat(serialize(t,{ prefix or "return" },true)) +end + +function table.deserialize(str) + local code = loadstring(str) + if not code then + return + end + code = code() + if not code then + return + end + return code end -- inspect(table.fastserialize { a = 1, b = { 4, { 5, 6 } }, c = { d = 7, e = 'f"g\nh' } }) @@ -236,3 +240,42 @@ function table.load(filename) end end end + +local function slowdrop(t) + local r = { } + local l = { } + for i=1,#t do + local ti = t[i] + local j = 0 + for k, v in next, ti do + j = j + 1 + l[j] = format("%s=%q",k,v) + end + r[i] = format(" {%s},\n",concat(l)) + end + return format("return {\n%s}",concat(r)) +end + +local function fastdrop(t) + local r = { "return {\n" } + for i=1,#t do + local ti = t[i] + r[#r+1] = " {" + for k, v in next, ti do + r[#r+1] = format("%s=%q",k,v) + end + r[#r+1] = "},\n" + end + r[#r+1] = "}" + return concat(r) +end + +function table.drop(t,slow) + if #t == 0 then + return "return { }" + elseif slow == true then + return slowdrop(t) -- less memory + else + return fastdrop(t) -- some 15% faster + end +end diff --git a/tex/context/base/util-tpl.lua b/tex/context/base/util-tpl.lua index 2a728d373..f6648b224 100644 --- a/tex/context/base/util-tpl.lua +++ b/tex/context/base/util-tpl.lua @@ -20,6 +20,8 @@ local report_template = logs.reporter("template") local format = string.format local P, C, Cs, Carg, lpegmatch = lpeg.P, lpeg.C, lpeg.Cs, lpeg.Carg, lpeg.match +-- todo: make installable template.new + local replacer local function replacekey(k,t) @@ -33,40 +35,59 @@ local function replacekey(k,t) if trace_template then report_template("setting key %q to value %q",k,v) end - -- return v return lpegmatch(replacer,v,1,t) -- recursive end end ------ leftmarker = P("<!-- ") / "" ------ rightmarker = P(" --!>") / "" +local sqlescape = lpeg.replacer { + { "'", "''" }, + { "\\", "\\\\" }, + { "\r\n", "\\n" }, + { "\r", "\\n" }, + -- { "\t", "\\t" }, +} + +local escapers = { + lua = function(s) + return format("%q",s) + end, + sql = function(s) + return lpegmatch(sqlescape,s) + end, +} + +local function replacekeyunquoted(s,t,how) -- ".. \" " + local escaper = how and escapers[how] or escapers.lua + return escaper(replacekey(s,t)) +end local single = P("%") -- test %test% test : resolves test local double = P("%%") -- test 10%% test : %% becomes % local lquoted = P("%[") -- test %[test]" test : resolves test with escaped "'s local rquoted = P("]%") -- -local escape = double / "%%" -local nosingle = single / "" -local nodouble = double / "" -local nolquoted = lquoted / "" -local norquoted = rquoted / "" +local escape = double / '%%' +local nosingle = single / '' +local nodouble = double / '' +local nolquoted = lquoted / '' +local norquoted = rquoted / '' local key = nosingle * (C((1-nosingle)^1 * Carg(1))/replacekey) * nosingle -local unquoted = nolquoted * ((C((1 - norquoted)^1) * Carg(1))/function(s,t) return format("%q",replacekey(s,t)) end) * norquoted +local unquoted = nolquoted * ((C((1 - norquoted)^1) * Carg(1) * Carg(2))/replacekeyunquoted) * norquoted local any = P(1) replacer = Cs((unquoted + escape + key + any)^0) -local function replace(str,mapping) +local function replace(str,mapping,how) if mapping then - return lpegmatch(replacer,str,1,mapping) or str + return lpegmatch(replacer,str,1,mapping,how or "lua") or str else return str end end --- print(replace("test %[x]% test",{ x = [[a "x" a]] })) +-- print(replace("test '%[x]%' test",{ x = [[a 'x' a]] })) +-- print(replace("test '%[x]%' test",{ x = [[a 'x' a]] },'sql')) templates.replace = replace diff --git a/tex/context/base/x-mathml.mkiv b/tex/context/base/x-mathml.mkiv deleted file mode 100644 index 2fb5fb58a..000000000 --- a/tex/context/base/x-mathml.mkiv +++ /dev/null @@ -1,2425 +0,0 @@ -%D \module -%D [ file=x-mathml, -%D version=2008.05.29, -%D title=\CONTEXT\ XML Modules, -%D subtitle=Loading \MATHML\ Filters, -%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 module is under construction and will be cleaned up. We use a funny mix of -% xml, tex and lua. I could rewrite the lot but it also shows how context evolves. -% -% no m:text strip (needs checking, maybe nbsp is mandate -% -% todo: more will be moved to lua (less hassle) -% todo: move left/right to the lua end - -\writestatus{loading}{ConTeXt XML Macros / MathML Renderer} - -\unprotect - -\usemodule[x][calcmath] -%usemodule[x][asciimath] - -\startmodule [mathml] - -\registerctxluafile{x-mathml}{} - -\def\ctxmodulemathml#1{\directlua\zerocount{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} - -\unexpanded\def\MMLhack - {\let\MMLpar\par - \let\par\relax - \everyvbox{\let\par\MMLpar}} - -\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} - -\startxmlsetups mml:math - \begingroup - \xmlval {mml:math:dir} {\xmlatt{#1}{dir}} {} - \xmlval {mml:math:display} {\xmlatt{#1}{display}} { - \xmlval {mml:math:mode} {\xmlatt{#1}{mode}} { - \automathematics - } - } - { - \MMLhack\xmlflush{#1} - } - \endgroup -\stopxmlsetups - -\startxmlsetups mml:imath - \inlinemathematics{\MMLhack\xmlflush{#1}} -\stopxmlsetups - -\startxmlsetups mml:dmath - \displaymathematics{\MMLhack\xmlflush{#1}} -\stopxmlsetups - -%D First we define some general formula elements. - -\startxmlsetups mml:formula - \edef\mmlformulalabel {\xmlatt{#1}{label}\xmlatt{#1}{id}} - \edef\mmlformulasublabel{\xmlatt{#1}{sublabel}\xmlatt{#1}{id}} - \doifsomething\mmlformulalabel{\placeformula[\mmlformulalabel]{\mmlformulasublabel}} - \startformula\MMLhack\xmlfirst{#1}{/mml:math}\stopformula -\stopxmlsetups - -\setfalse\mmlignoredelimiter -\settrue \mmlsomeleftdelimiter - -\def\MMLleftorright - {\ifconditional\mmlsomeleftdelimiter - \setfalse\mmlsomeleftdelimiter\expandafter\MMLleft - \else - \settrue \mmlsomeleftdelimiter\expandafter\MMLright - \fi} - -\ifx\MMLleft \undefined \let\MMLleft \firstofoneargument \fi -\ifx\MMLright \undefined \let\MMLright \firstofoneargument \fi -\ifx\MMLmiddle\undefined \let\MMLmiddle\firstofoneargument \fi - -\def\mmlleftdelimiter #1{\ifconditional\mmlignoredelimiter#1\else\normalordelimiter{#1}{\MMLleft #1}\fi} -\def\mmlrightdelimiter #1{\ifconditional\mmlignoredelimiter#1\else\normalordelimiter{#1}{\MMLright #1}\fi} -\def\mmlmiddledelimiter #1{\ifconditional\mmlignoredelimiter#1\else\normalordelimiter{#1}{\MMLmiddle #1}\fi} -\def\mmlleftorrightdelimiter#1{\ifconditional\mmlignoredelimiter#1\else\normalordelimiter{#1}{\MMLleftorright#1}\fi} - -\def\mmlchar#1{\char#1 } % used in lua code - -% \newcount\delimiternesting \appendtoks \delimiternesting\zerocount \to \everymathematics - -% \def\mmlleftdelimiter #1{\ifconditional\mmlignoredelimiter#1\else\normalordelimiter{#1}{% -% \advance\delimiternesting\plusone \MMLleft #1}\fi} -% \def\mmlrightdelimiter #1{\ifconditional\mmlignoredelimiter#1\else\normalordelimiter{#1}{% -% \advance\delimiternesting\plusone \MMLright#1}\fi} -% \def\mmlmiddledelimiter#1{\ifconditional\mmlignoredelimiter#1\else\normalordelimiter{#1}{% -% \ifcase\delimiternesting\MMLleft\else\MMLmiddle\fi#1}\fi} - -%D Remark: from now on this is a module and no longer an xtag -%D filter. There is an intermediate cleaner module but it has -%D some namespace limitations. Here we do it the \MKIV\ way. - -\def\widevec#1% - {\vbox{\mathsurround\zeropoint\ialign{##\crcr - \rightarrowfill\crcr\noalign{\nointerlineskip}% - \startimath\hfil\displaystyle{#1}\hfil\stopimath\crcr}}} - -%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 -%D rendering, there are probably a lot of omissions and -%D misinterpretations. At least I learned some bits and -%D pieces of math rendering. -%D -%D The main complications were not so much the math, but to -%D find the most efficient way to handle elements without -%D spacing beging messed up. The first implementation was -%D aimed at getting reasonable output, this second -%D implementation is already better in terms of handling -%D nesting, and I will definitely need a third one that has -%D more efficient and less ugly code. -%D -%D The \TEX\ part is not that complicated and once the -%D preprocessor was okay, the rest way just a lot of keying -%D and testing. It all comes down to gobbling, redefining, -%D and not so much to parsing. -%D -%D The second implementation expanded the whole math sequence -%D into an internal \TEX\ representation. This is a rather clean -%D and fast process. Filtering and testing takes place by -%D redefining teh internal representation macros. -%D -%D The third implementation may look a bit more messy in some -%D respects. This is because in \TEX\ it's not that trivial to -%D implement a tree handler. We use a stack for the \type {apply} -%D element and other sequential content. Occasionally we need to -%D peek into child elements which involves messy code. This -%D implementation is closer to the normal \XML\ handling in -%D \CONTEXT. - -%D We start with the parent elements and the option handler. - -\def\xmlmathmldirective#1{\dosetvalue{MML#1}} - -%def\xmlmathmldirective#1#2#3{[#1][#2][#3]\dosetvalue{MML#1}{#2}{#3}} - -%D In the styles, options can be set with: - -\unexpanded\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 -%D \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 Special features: - - \newtoks \@@postponedMMLactions \setfalse \somepostponedMMLactions - - \def\postponeMMLactions#1% - {\global\settrue\somepostponedMMLactions - \global\@@postponedMMLactions\expandafter{\the\@@postponedMMLactions#1}} - - \def\postponedMMLactions - {\global\setfalse\somepostponedMMLactions - \@EA\global\@EA\@@postponedMMLactions\@EA\emptytoks - \the\@@postponedMMLactions} - -%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 -%D get problems with 1/2(1+2) and alike (todo: ask taco). -%D -%D 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 -%D version 3 the following definitions may be sub optimal or -%D 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 \else - \ifx\mmlapplyopentoken\empty - \def\mmlapplyopentoken {(} - \def\mmlapplyclosetoken{)} - \fi - \fi - \advance\mmlapplydepth\plusone - \begingroup - \ifx\mmlapplyopentoken\empty - \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}{/*/name()}} - \doifsetupselse {mml:apply:mml:\mmlapplyaction} { - \xmlsetup{#1}{mml:apply:mml:\mmlapplyaction} - } { -% \MMLdoL - \xmlsetup{#1}{mml:\xmlfilter{#1}{/*/name()}} -% \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}}% was xmlcontent - \doifsetupselse{mmc:fn:\mmlfnci} { % was mmc:fn:... - \xmlsetup{#1}{mmc:fn:\mmlfnci} % \MMLdoL/MMLdoR to be handled in plugin - } { - \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} { % first - \edef\mmlfnci{\xmltext{#1}{/mml:ci}}% was xmlcontent - \doifsetupselse{mmc:fn:\mmlfnci} { % was mmc:fn:... - \xmlsetup{#1}{mmc:fn:\mmlfnci} % \MMLdoL/MMLdoR to be handled in plugin - } { - \MMLcreset - \mmlfirst{#1} - } - } { - \xmldoifelse {#1} {/mml:apply} { % first - \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} { % first - \edef\mmlfnci{\xmltext{#1}{/mml:ci}}% was xmlcontent - \doifsetupselse{mmc:fn:\mmlfnci} { % was mmc:fn:... - \xmlsetup{#1}{mmc:fn:\mmlfnci} % \MMLdoL/MMLdoR to be handled in plugin - } { - \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 -%D the open math 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} { -% {\mr #4} - \text{#4} - } { - \doifsetupselse {mml:csymbol:#1} { - % full url - \directsetup{mml:csymbol:#1} - } { - % somename (fallback) - \doifsetupselse {mml:csymbol:#2} { - \directsetup{mml:csymbol:#2} - } { - \xmlval{mmc:cs}{#3}{}% todo - } - } - } -\stoptexdefinition - -\startxmlsetups mml:csymbol - \ctxmodulemathml{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 - \widevec{\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\else - \ifnum\mmlintegerbase= 8 #2\else - \ifnum\mmlintegerbase=10 #3\else - \ifnum\mmlintegerbase=16 #4\else - \mmlintegerbase \fi\fi\fi\fi} - -\startxmlsetups mml:cn:polar - \xmlsetup{#1}{mml:cn:polar:\MMLpolaralternative} -\stopxmlsetups - -\startxmlsetups mml:cn:polar:a - \ctxmodulemathml{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 - \ifx\first\empty - \mmlfloatstring - \else\ifx\last\empty - \mmlfloatstring - \else - \first - \doifelse \MMLfloatsymbol {dot} \cdot \times - 10\normalsuperscript{\last} - \fi \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} { - \frac - {\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]/name()}} -\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 - \frac{\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 slso 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 - \doifinsetelse\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}{/*/name()}} - \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) - \frac { - 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} { - \frac { - {\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}} - \ifx\mmldegree\empty - % 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} { - \frac { - {\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}} - \ifx \mmlintervalfrom \empty \else - \def\mmlsumprodlower{\normalsubscript{\xmldoif{#1}{/mml:bvar}{\xmlfirst{#1}{/mml:bvar}{=}}\mmlintervalfrom}} - \fi - \ifx \mmlintervalto \empty \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','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{\xmlflush{#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{\O} \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 - \ifx\MMLpowerelement\empty - \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 -% -% there are some rough edges that need to be sorted out - -% helpers - -\xmlmapvalue {mml} {normal} {\tf} -\xmlmapvalue {mml} {double-struck} {\bf} -\xmlmapvalue {mml} {italic} {\it} -\xmlmapvalue {mml} {fraktur} {\bf} -\xmlmapvalue {mml} {script} {\tf} -\xmlmapvalue {mml} {bold} {\bf} -\xmlmapvalue {mml} {bold-italic} {\bi} -\xmlmapvalue {mml} {bold-fraktur} {\bf} -\xmlmapvalue {mml} {bold-script} {\bf} -\xmlmapvalue {mml} {sans-serif} {\ss} -\xmlmapvalue {mml} {bold-sans-serif} {\ss\bf} -\xmlmapvalue {mml} {sans-serif-italic} {\ss\it} -\xmlmapvalue {mml} {sans-serif-bold-italic} {\ss\bi} -\xmlmapvalue {mml} {monospace} {\tt} - -% todo: displaystyle=true/false (or whatever else shows up) - -\starttexdefinition setmmlmathstyle #1 - \xmlval {mml} {\xmlatt{#1}{mathvariant}} \empty % was: \mmmr -\stoptexdefinition - -\starttexdefinition applymmlmathcolor #1#2 - \edef\mmlmathcolor{\xmlatt{#1}{mathcolor}} - \ifx \mmlmathcolor \empty - #2 - \else - \color[\mmlmathcolor]{#2} - \fi -\stoptexdefinition - -% todo: textbackgrounds - -\starttexdefinition applymmlmathbackground #1#2 - \edef\mmlmathbackground{\xmlatt{#1}{mathbackground}} - \ifx \mmlmathbackground \empty - #2 - \else - \backgroundline[\mmlmathbackground]{#2} - \fi -\stoptexdefinition - -\newsignal\mmltextsignal % not used - -\starttexdefinition applymmlsometext #1#2 - \applymmlmathbackground {#1} { - \applymmlmathcolor {#1} { - \setmmlmathstyle {#1} - #2 - } - } -\stoptexdefinition - -% probably bugged: - -\starttexdefinition doMMLfiller #1 - \pushmacro\doMMLfiller - \let\doMMLfiller\gobbleoneargument - \gdef\dodoMMLfiller{% where used - \disablefiller - \mathematics{#1} - } - \hbox { - \def\normalorfiller##1##2{ - \gdef\dodoMMLfiller{\enablefiller#1}% - \let\normalorfiller\gobbletwoarguments - } - \mathematics{#1} - } - \popmacro\doMMLfiller -\stoptexdefinition - -% setups - -\startxmlsetups mml:mi % todo: mathvariant mathsize mathcolor mathbackground - \ctxmodulemathml{mi("#1")} -\stopxmlsetups - -\startxmlsetups mml:mn % todo: mathvariant mathsize mathcolor mathbackground -% \begingroup -% \mr - \ctxmodulemathml{mn("#1")}% no \hbox, would be ok for . , but spoils rest -% \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 - \doif {\xmlatt{#1}{maxsize}} {1} {\settrue\mmlignoredelimiter} - \doif {\xmlatt{#1}{stretchy}} {false} {\settrue\mmlignoredelimiter} - \ctxmodulemathml{mo("#1")} - \setfalse\mmlignoredelimiter -\stopxmlsetups - -\startxmlsetups mml:mfenced % {} around separator is needed for spacing - \def\MMLleft {\left }% weird - \def\MMLright {\right} - \def\MMLmiddle{\middle} - \ctxmodulemathml{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{\ctxmodulemathml{menclosepattern("#1")}} - \ifx\mmlmenclosenotation\empty - \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|} - } { - \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 - {\startimath - \expanded{\doifinsetelse {mml:enclose:longdiv} {\mmlmenclosenotation}} { - \overline{\left)\strut\xmlflush{#1}\right.} - } { - \expanded{\doifinsetelse {mml:enclose:actuarial} {\mmlmenclosenotation}} { - \overline{\left.\strut\xmlflush{#1}\right|} - } { - \expanded{\doifinsetelse {mml:enclose:radical} {\mmlmenclosenotation}} { - \sqrt{\xmlflush{#1}} - } { - \xmlflush{#1} - } - } - } - \stopimath} - } - } - } - } - \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}} - \ifx\mmlfraclinethickness\empty - \doifelse{\xmlatt{#1}{bevelled}}{true} { - \left.\mmlfirst{#1}\middle/\mmlsecond{#1}\right.% \thinspace\middle/\thinspace - } { - \frac{\mmlfirst{#1}}{\mmlsecond{#1}} - } - \else - \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 - \edef\mmllquote{\xmlatt{#1}{lquote}} - \edef\mmlrquote{\xmlatt{#1}{rquote}} - \ifx\mmllquote\empty\symbol[leftquotation]\else\mmllquote\fi - \applymmlsometext{#1}{\xmlflush{#1}} - \ifx\mmlrquote\empty\symbol[rightquotation]\else\mmlrquote\fi - } -\stopxmlsetups - -\startxmlsetups mml:mstyle - \begingroup - \setmmlmathstyle{#1} - \xmlflush{#1} - \endgroup -\stopxmlsetups - -\setupMMLappearance[text][\c!alternative=\v!b] % a=normal, b=keep spaces - -\startxmlsetups mml:mtext - \text { - \applymmlsometext{#1}{ - \doifelse \MMLtextalternative \v!a { - %\ctxmodulemathml{stripped(\!!bs\xmlflush{#1}\!!es)} - \ignorespaces - \xmlflush{#1} - \removeunwantedspaces - } { - \xmlflush{#1} - } - } - } -\stopxmlsetups - -\startxmlsetups mml:merror - \hbox{\startimath\displaystyle\xmlflush{#1}\stopimath} -\stopxmlsetups - -\startxmlsetups mml:mphantom -% \phantom{\ignorespaces{}\xmlflush{#1}\unskip} % watch spacing {} hack -% \phantom{\mathstyle{\ignorespaces{}\xmlflush{#1}\unskip}}% - \phantom{\triggermathstyle\normalmathstyle\ignorespaces\xmlflush{#1}\removeunwantedspaces} -% \mktriggereffect\v!hidden -% \ignorespaces{}\xmlflush{#1}\unskip % no attributes in math yet -% \mktriggereffect\v!normal -\stopxmlsetups - -\startxmlsetups mml:mpadded % todo - \xmlflush{#1} -\stopxmlsetups - -% mrow / option: no fenced - -\startxmlsetups mml:maction - \xmlflush{#1} -\stopxmlsetups - -% \startxmlsetups mml:mrow -% \begingroup -% \edef\nofmmlrows{\xmlcount{#1}{/mml:mo}}% -% \ifnum\nofmmlrows=\plustwo -% \xmldoifelse {#1} {/mml:mo[position()==1 or position()==\nofmmlrows]} {% we need a {} -% \def\MMLleft {\left } -% \def\MMLright {\right} -% \def\MMLmiddle{\middle} -% \enabledelimiter -% \checkdelimiters{\xmlall{#1}{/mml:mo}} -% \fakeleftdelimiter -% \xmlflush{#1} -% \fakerightdelimiter -% \disabledelimiter -% } { -% \xmlflush{#1} -% } -% \else -% \xmlflush{#1} -% \fi -% \endgroup -% \stopxmlsetups -% -% fails on { ... so we need - -\startxmlsetups mml:mrow - \begingroup - \xmldoifelse {#1} {/mml:mo[first() or last()]} {% we need a {} - \def\MMLleft {\left } - \def\MMLright {\right} - \def\MMLmiddle{\middle} - \enabledelimiter - \checkdelimiters{\xmlall{#1}{/mml:mo}} - \fakeleftdelimiter - \xmlflush{#1} - \fakerightdelimiter - \disabledelimiter - } { - \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 - -\startxmlsetups mml:msub - \edef\mmlnucleus{\xmlraw{#1}{/mml:*[1]}} - \doifelse {\utfmathclass\mmlnucleus} {limop} { - \mmlfirst{#1} \normalsubscript{\mmlsecond{#1}} - } { - \doifelse\MMLscriptsalternative\v!a { - {\mmlfirst{#1}}\normalsubscript{\mmlsecond{#1}} - } { - \mmlfirst{#1} \normalsubscript{\mmlsecond{#1}} - } - } -\stopxmlsetups - -\startxmlsetups mml:msup - \edef\mmlnucleus{\xmlraw{#1}{/mml:*[1]}} - \doifelse {\utfmathclass\mmlnucleus} {limop} { - \mmlfirst{#1} \normalsuperscript{\mmlsecond{#1}} - } { - \doifelse\MMLscriptsalternative\v!a { - {\mmlfirst{#1}}\normalsuperscript{\mmlsecond{#1}} - } { - \mmlfirst{#1} \normalsuperscript{\mmlsecond{#1}} - } - } -\stopxmlsetups - -\startxmlsetups mml:msubsup - \edef\mmlnucleus{\xmlraw{#1}{/mml:*[1]}} - \doifelse {\utfmathclass\mmlnucleus} {limop} { - \mmlfirst{#1}\normalsubscript{\mmlsecond{#1}}\normalsuperscript{\mmlthird{#1}} - } { - \doifelse\MMLscriptsalternative\v!a { - {\mmlfirst{#1}}\normalsubscript{\mmlsecond{#1}}\normalsuperscript{\mmlthird{#1}} - } { - \mmlfirst{#1}\normalsubscript{\mmlsecond{#1}}\normalsuperscript{\mmlthird{#1}} - } - } -\stopxmlsetups - -\def\mmlexecuteifdefined#1% - {\ifx#1\empty - \expandafter\secondoftwoarguments - \else\ifcsname#1\endcsname - \doubleexpandafter\firstoftwoarguments - \else - \doubleexpandafter\secondoftwoarguments - \fi\fi - {\csname#1\endcsname}} - -\startxmlsetups mml:mover -% \mathop { - \edef\mmlovertoken{\xmlraw{#1}{/mml:*[2]}} - \doifelseutfmathaccent\mmlovertoken { - \edef\mmlovercommand{\utfmathcommand\mmlovertoken} - \mmlexecuteifdefined\mmlovercommand\mathematics{\mmlfirst{#1}} - } { - \edef\mmlbasetoken{\xmlraw{#1}{/mml:*[1]}} - \edef\mmlbasecommand{\utfmathfiller\mmlbasetoken} - \edef\mmlovercommand{\utfmathfiller\mmlovertoken} -% todo: proper math mode/size - \vbox { - \mathsurround\zeropoint \ialign { -% \hss##\hss -\hss$##$\hss - \crcr - \noalign{\kern3\onepoint}% -% \mmlexecuteifdefined\mmlovercommand{\mathematics{\mmlsecond{#1}}} -\mmlexecuteifdefined\mmlovercommand{\mmlsecond{#1}} - \crcr - \noalign{\kern3\onepoint\nointerlineskip}% -% \mmlexecuteifdefined\mmlbasecommand{\mathematics{\mmlfirst{#1}}} -\mmlexecuteifdefined\mmlbasecommand{\mmlfirst{#1}} - \crcr - } - } - } -% } -% \limits % spoils spacing -\stopxmlsetups - -% messy: <munder><mo>(</mo><mo>_</mo></munder> - -\startxmlsetups mml:munder -% \mathop { - \edef\mmlundertoken{\xmlraw{#1}{/mml:*[2]}} - \doifelseutfmathaccent\mmlundertoken { - \edef\mmlundercommand{\utfmathcommand\mmlundertoken} - \mmlexecuteifdefined\mmlundercommand\mathematics{\mmlfirst{#1}} - } { - \edef\mmlbasetoken {\xmlraw{#1}{/mml:*[1]}} - \edef\mmlbasecommand {\utfmathfiller\mmlbasetoken} - \edef\mmlundercommand{\utfmathfiller\mmlundertoken} -% todo: proper math mode/size - \vtop { - \mathsurround\zeropoint \ialign { -% \hss##\hss -\hss$##$\hss - \crcr -% \mmlexecuteifdefined\mmlbasecommand {\mathematics{\mmlfirst{#1}}} -\mmlexecuteifdefined\mmlbasecommand {\mmlfirst{#1}} - \crcr - \noalign{\kern3\onepoint\nointerlineskip}% -% \mmlexecuteifdefined\mmlundercommand{\mathematics{\mmlsecond{#1}}} -\mmlexecuteifdefined\mmlundercommand{\mmlsecond{#1}} - \crcr - \noalign{\kern3\onepoint} - } - } - } -% } -% \limits % spoils spacing -\stopxmlsetups - -\startxmlsetups mml:munderover - \edef\mmlbasetoken{\xmlraw{#1}{/mml:*[1]}} - \edef\mmlbasecommand{\utfmathcommand\mmlbasetoken} - \mmlexecuteifdefined\mmlbasecommand{\mathematics{\mmlfirst{#1}}}\normalsubscript{\mmlsecond{#1}}\normalsuperscript{\mmlthird{#1}} -\stopxmlsetups - -% tables (mml:mtable, mml:mtr, mml:mlabledtr, mml:mtd) - -\startxmlsetups mml:mtable % some more attributes need to be supported - \vcenter{\ctxmodulemathml{mtable("#1")}} -\stopxmlsetups - -\startxmlsetups mml:mcolumn - \ctxmodulemathml{mcolumn("#1")} -\stopxmlsetups - -\def\mmlsetfakewidth#1{\setbox\scratchbox\hbox{#1}\scratchdimen\wd\scratchbox} - -\def\mmlmcolumndigitspace {\mmlsetfakewidth {0}\kern\scratchdimen} -\def\mmlmcolumndigitrule {\mmlsetfakewidth {0}\vrule width \scratchdimen height .2pt depth .2pt\relax} -\def\mmlmcolumnsymbolrule {\mmlsetfakewidth{\times}\vrule width \scratchdimen height .2pt depth .2pt\relax} -\def\mmlmcolumnpunctuationrule{\mmlsetfakewidth {.}\vrule width \scratchdimen height .2pt depth .2pt\relax} - -\startxmlsetups mml:mspace - \begingroup - \edef\mmlspacetext{\xmlatt{#1}{spacing}} - \ifx\mmlspacetext\empty - \!!widtha \xmlattdef{#1}{width} \!!zeropoint % must be string - \!!heighta\xmlattdef{#1}{height}\!!zeropoint - \!!deptha \xmlattdef{#1}{depth} \!!zeropoint - \ifdim\!!heighta=\zeropoint - \ifdim\!!deptha=\zeropoint\else - \hbox{\vrule\s!depth\!!deptha\s!height\zeropoint\s!width\zeropoint}% - \fi - \else - \hbox{\vrule\s!depth\zeropoint\s!height\!!heighta\s!width\zeropoint}% - \fi - \ifdim\!!widtha=\zeropoint\else - \hskip\!!widtha - \fi - \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} -% \ifx\mmllinewidth\empty -% \!!deptha.5\linewidth -% \else -% \!!deptha.5\dimexpr\mmllinewidth\relax -% \fi -% \!!heighta\!!deptha -% \ifx\mmllinetext\empty -% \ifx\mmllinelength\empty -% \!!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}} - \ifx \mmlglyphfontfamily \empty - \hbox{\tttf[no fontfamily specified for \mmlglyphalt]} - \else\ifx\mmlglyphindex\empty - \hbox{\tttf[no index specified for \mmlglyphalt]} - \else - \hbox{\getglyph\mmlglyphfontfamily\mmlglyphindex} - \fi\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 - \ctxmodulemathml{mmultiscripts("#1")} -\stopxmlsetups - -% goodie - -\definebuffer[mml] - -\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> - -% \startmoduletestsection -% -% \def\xflushXMLstackwith#1#2#3#4% num bgroup egroup whatever -% {\dostepwiserecurse{#1}\XMLstacklevel\plusone -% {#2\relax -% \ifnum\recurselevel>#1\relax#4\fi -% \getXMLstackdata\recurselevel -% #3}} -% -% \def\xflushXMLstackfrom#1#2#3% -% {\dostepwiserecurse{#1}\XMLstacklevel\plusone -% {#2\getXMLstackdata\recurselevel#3}} -% -% \startxmlsetups mml:minus -% \doif \MMLsignreduction \v!yes { -% \setMMLcreset{fn,\MMLcfunctionlist} -% } -% \ifcase\XMLstacklevel -% \or -% % self -% \or -% -\getXMLstackdata\plustwo -% \else -% \dostepwiserecurse \plustwo \XMLstacklevel \plusone { -% \begingroup -% \doifelse {\getXMLstackname\recurselevel} {apply} { -% \ifnum\recurselevel=\plustwo -% \begingroup -% \dodoifelseMMCfunctioninapply \recurselevel {minus} { -% \ifnum\XMLstacklevel>\plustwo -% \endgroup -% \else -% \endgroup -% \MMLcreset -% \fi -% } { -% \endgroup -% } -% \else -% \doifelseMMCfunctioninapply \recurselevel {\MMLcfunctionlist,\MMLcconstructlist} { -% \MMLcreset -% } { -% } -% \fi -% } { -% } -% \getXMLstackdata\recurselevel -% \ifnum\recurselevel<\XMLstacklevel\relax -% - -% \fi -% \endgroup -% } -% \fi -% \stopxmlsetups -% -% \stopmoduletestsection diff --git a/tex/context/base/x-xfdf.mkiv b/tex/context/base/x-xfdf.mkiv new file mode 100644 index 000000000..c4ca0c427 --- /dev/null +++ b/tex/context/base/x-xfdf.mkiv @@ -0,0 +1,71 @@ +%D \module +%D [ file=x-xfdf, +%D version=2011.09.07, +%D title=\CONTEXT\ XML Modules, +%D subtitle=\XFDF, +%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 is a revival of using \XFDF, but now in a more \MKIV-ish way. We +%D supported it long ago already in \MKII\ but never used it at a large +%D scale (not that much user interest anyway). + +\startmodule[xfdf] + +% see xfdf-001.xfdf and xfdf-001.tex + +% %D Possible speedup but hardly worth the trouble. +% +% \startluacode +% +% local hashes = { } table.setmetatableindex(hashes,function(t,k) local v = { } t[k] = v return v end) +% +% function xml.functions.xfdf_collect_values(root) +% local hash = hashes[root] +% for c in xml.collected(root,"/xfdf/fields/field/value") do +% hash[xml.parent(c).at.name] = c +% end +% end +% +% function xml.functions.xfdf_get_values(root,name) +% return hashes[root][name] +% end +% +% function lxml.xfdf_get_values(root,name) +% xml.sprint(hashes[lxml.id(root)][name]) +% end +% +% \stopluacode +% +% \def\xfdfvalue#1#2% +% {\ctxlua{lxml.xfdf_get_values("#1","#2")}} + +\startxmlsetups xfdf:define + \xmlsetsetup{#1}{*}{xfdf:*} + % \xmlfilter {#1}{./function(xfdf_collect_values)} +\stopxmlsetups + +\xmlregisterns{xfdf}{http://ns.adobe.com/xfdf/} + +\xmlregisterdocumentsetup{xfdf}{xfdf:define} + +\startxmlsetups xfdf:value + \xmlflush{#1} +\stopxmlsetups + +\def\xfdfload #1#2{\xmlloadonly{#1}{#2}{xfdf}} +\def\xfdfvalue#1#2{\xmlfirst{#1}{/xfdf/fields/field[@name='#2']/value}} + +% \startxmlsetups xfdf:b +% \bold{\xmlflush{#1}} +% \stopxmlsetups + +% \xfdfload {whatever}{xfdf-001.xfdf} +% \xfdfvalue{whatever}{somefield} + +\stopmodule diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua index 1140ff916..4700859ff 100644 --- a/tex/generic/context/luatex/luatex-fonts-merged.lua +++ b/tex/generic/context/luatex/luatex-fonts-merged.lua @@ -1,6 +1,6 @@ -- merged file : luatex-fonts-merged.lua -- parent file : luatex-fonts.lua --- merge date : 09/06/12 23:03:51 +-- merge date : 09/10/12 00:57:08 do -- begin closure to overcome local limits and interference @@ -132,6 +132,14 @@ string.unquote = string.unquoted string.itself = function(s) return s end +-- also handy (see utf variant) + +local pattern = Ct(C(1)^0) + +function string.totable(str) + return lpegmatch(pattern,str) +end + end -- closure do -- begin closure to overcome local limits and interference |