diff options
Diffstat (limited to 'tex/context/base/x-asciimath.lua')
-rw-r--r-- | tex/context/base/x-asciimath.lua | 1707 |
1 files changed, 1485 insertions, 222 deletions
diff --git a/tex/context/base/x-asciimath.lua b/tex/context/base/x-asciimath.lua index dd438d42e..da46b9b31 100644 --- a/tex/context/base/x-asciimath.lua +++ b/tex/context/base/x-asciimath.lua @@ -5,11 +5,22 @@ if not modules then modules = { } end modules ['x-asciimath'] = { copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files" } + --[[ldx-- -<p>Some backgrounds are discussed in <t>x-asciimath.mkiv</t>.</p> +<p>Some backgrounds are discussed in <t>x-asciimath.mkiv</t>. This is a third version. I first +tried a to make a proper expression parser but it's not that easy. First we have to avoid left +recursion, which is not that trivial (maybe a future version of lpeg will provide that), and +second there is not really a syntax but a mix of expressions and sequences with some fuzzy logic +applied. Most problematic are fractions and we also need to handle incomplete expressions. So, +instead we (sort of) tokenize the string and then do some passes over the result. Yes, it's real +ugly and unsatisfying code mess down here. Don't take this as an example.</p> --ldx]]-- +-- todo: spaces around all elements in cleanup? +-- todo: filter from files listed in tuc file + local trace_mapping = false if trackers then trackers.register("modules.asciimath.mapping", function(v) trace_mapping = v end) end +local trace_detail = false if trackers then trackers.register("modules.asciimath.detail", function(v) trace_detail = v end) end local asciimath = { } local moduledata = moduledata or { } @@ -18,264 +29,1516 @@ moduledata.asciimath = asciimath if not characters then require("char-def") require("char-ini") + require("char-ent") end +local entities = characters.entities or { } + local report_asciimath = logs.reporter("mathematics","asciimath") -local format = string.format -local lpegmatch = lpeg.match +local type, rawget = type, rawget +local lpegmatch, patterns = lpeg.match, lpeg.patterns local S, P, R, C, V, Cc, Ct, Cs = lpeg.S, lpeg.P, lpeg.R, lpeg.C, lpeg.V, lpeg.Cc, lpeg.Ct, lpeg.Cs - -local letter = lpeg.patterns.utf8 -local space = S(" \n\r\t") -local spaces = space^0/"" -local integer = P("-")^-1 * R("09")^1 -local realpart = P("-")^-1 * R("09")^1 * S(".")^1 * R("09")^1 -local number = integer -- so we can support nice formatting if needed -local real = realpart -- so we can support nice formatting if needed -local float = realpart * P("E") * integer -- so we can support nice formatting if needed -local texnic = P("\\") * (R("az","AZ")^1) - -local premapper = Cs ( ( - - P("@") / "\\degrees " + - P("O/") / "\\varnothing " + - P("o+") / "\\oplus " + - P("o.") / "\\ocirc " + - P("!in") / "\\not\\in " + - P("!=") / "\\neq " + - P("**") / "\\star " + - P("*") / "\\cdot " + - P("//") / "\\slash " + - P("/_") / "\\angle " + - P("\\\\") / "\\backslash " + - P("^^^") / "\\wedge " + - P("^^") / "\\wedge " + - P("<<") / "\\left\\langle " + - P(">>") / "\\right\\rangle " + - P("<=") / "\\leq " + - P(">=") / "\\geq " + - P("-<") / "\\precc " + - P(">-") / "\\succ " + - P("~=") / "\\cong " + - P("~~") / "\\approx " + - P("=>") / "\\Rightarrow " + - P("(:") / "\\left\\langle " + - P(":)") / "\\right\\rangle " + - P(":.") / "\\therefore " + - P("~|") / "\\right\\rceil " + - P("_|_") / "\\bot " + - P("_|") / "\\right\\rfloor " + - P("+-") / "\\pm " + - P("|--") / "\\vdash " + - P("|==") / "\\models " + - P("|_") / "\\left\\lfloor " + - P("|~") / "\\left\\lceil " + - P("-:") / "\\div " + - P("_=") / "\\equiv " + - - P("|") / "\\middle\\| " + - - P("dx") / "(dx)" + - P("dy") / "(dy)" + - P("dz") / "(dz)" + - - letter + P(1) - -)^0 ) +local concat, sortedhash, sortedkeys = table.concat, table.sortedhash, table.sortedkeys +local rep, gmatch, gsub, find = string.rep, string.gmatch, string.gsub, string.find +local formatters = string.formatters local reserved = { - ["aleph"] = "\\aleph ", - ["vdots"] = "\\vdots ", - ["ddots"] = "\\ddots ", - ["oint"] = "\\oint ", - ["grad"] = "\\nabla ", - ["prod"] = "\\prod ", - ["prop"] = "\\propto ", - ["sube"] = "\\subseteq ", - ["supe"] = "\\supseteq ", - ["sinh"] = "\\sinh ", - ["cosh"] = "\\cosh ", - ["tanh"] = "\\tanh ", - ["sum"] = "\\sum ", - ["vvv"] = "\\vee ", - ["nnn"] = "\\cap ", - ["uuu"] = "\\cup ", - ["sub"] = "\\subset ", - ["sup"] = "\\supset ", - ["not"] = "\\lnot ", - ["iff"] = "\\Leftrightarrow ", - ["int"] = "\\int ", - ["del"] = "\\partial ", - ["and"] = "\\and ", - ["not"] = "\\not ", - ["sin"] = "\\sin ", - ["cos"] = "\\cos ", - ["tan"] = "\\tan ", - ["csc"] = "\\csc ", - ["sec"] = "\\sec ", - ["cot"] = "\\cot ", - ["log"] = "\\log ", - ["det"] = "\\det ", - ["lim"] = "\\lim ", - ["mod"] = "\\mod ", - ["gcd"] = "\\gcd ", - ["lcm"] = "\\lcm ", - ["min"] = "\\min ", - ["max"] = "\\max ", - ["xx"] = "\\times ", - ["in"] = "\\in ", - ["ox"] = "\\otimes ", - ["vv"] = "\\vee ", - ["nn"] = "\\cap ", - ["uu"] = "\\cup ", - ["oo"] = "\\infty ", - ["ln"] = "\\ln ", - ["or"] = "\\or ", - - ["AA"] = "\\forall ", - ["EE"] = "\\exists ", - ["TT"] = "\\top ", - ["CC"] = "\\Bbb{C}", - ["NN"] = "\\Bbb{N}", - ["QQ"] = "\\Bbb{Q}", - ["RR"] = "\\Bbb{R}", - ["ZZ"] = "\\Bbb{Z}", + -- ["aleph"] = "\\aleph", + -- ["vdots"] = "\\vdots", + -- ["ddots"] = "\\ddots", + -- ["oint"] = "\\oint", + -- ["grad"] = "\\nabla", + ["prod"] = "\\prod", + -- ["prop"] = "\\propto", + -- ["sube"] = "\\subseteq", + -- ["supe"] = "\\supseteq", + ["sinh"] = "\\sinh", + ["cosh"] = "\\cosh", + ["tanh"] = "\\tanh", + ["sum"] = "\\sum", + -- ["vvv"] = "\\vee", + -- ["nnn"] = "\\cap", + -- ["uuu"] = "\\cup", + -- ["sub"] = "\\subset", + -- ["sup"] = "\\supset", + -- ["iff"] = "\\Leftrightarrow", + ["int"] = "\\int", + -- ["del"] = "\\partial", + ["sin"] = "\\sin", + ["cos"] = "\\cos", + ["tan"] = "\\tan", + ["csc"] = "\\csc", + ["sec"] = "\\sec", + ["cot"] = "\\cot", + ["log"] = "\\log", + ["det"] = "\\det", + ["lim"] = "\\lim", + ["mod"] = "\\mod", + ["gcd"] = "\\gcd", + -- ["lcm"] = "\\lcm", -- undefined in context + ["min"] = "\\min", + ["max"] = "\\max", + -- ["xx"] = "\\times", + ["in"] = "\\in", + -- ["ox"] = "\\otimes", + -- ["vv"] = "\\vee", + -- ["nn"] = "\\cap", + -- ["uu"] = "\\cup", + -- ["oo"] = "\\infty", + ["ln"] = "\\ln", + + -- ["not"] = "\\not", + ["and"] = "\\text{and}", + ["or"] = "\\text{or}", + ["if"] = "\\text{if}", + + -- ["AA"] = "\\forall", + -- ["EE"] = "\\exists", + -- ["TT"] = "\\top", + + ["sqrt"] = "\\rootradical{}", + ["root"] = "\\rootradical", + ["frac"] = "\\frac", + ["stackrel"] = "\\stackrel", + -- ["text"] = "\\mathoptext", + -- ["bb"] = "\\bb", + ["hat"] = "\\widehat", + ["overbar"] = "\\overbar", + ["underline"] = "\\underline", + ["vec"] = "\\overrightarrow", + ["dot"] = "\\dot", + ["ddot"] = "\\ddot", + + -- binary operators + + -- ["+"] = "+", + -- ["-"] = "-", + ["*"] = "⋅", + ["**"] = "⋆", + ["//"] = "/", + ["\\"] = "\\", + ["xx"] = "×", + ["times"] = "×", + ["-:"] = "÷", + ["@"] = "∘", + ["o+"] = "⊕", + ["ox"] = "⊗", + ["o."] = "⊙", + ["^^"] = "∧", + ["vv"] = "∨", + ["nn"] = "∩", + ["uu"] = "∪", + + -- big operators + + -- ["sum"] = "∑", + -- ["prod"] = "∏", + ["^^^"] = "⋀", + ["vvv"] = "⋁", + ["nnn"] = "⋂", + ["uuu"] = "⋃", + ["int"] = "∫", + ["oint"] = "∮", + + -- brackets + +-- ["("] = "(, +-- [")"] = "), +-- ["["] = "[, +-- ["]"] = "], +-- ["{"] = "{, +-- ["}"] = "}, +-- ["(:"] = "〈", +-- [":)"] = "〉", + + -- binary relations + + ["="] = "=", + ["!="] = "≠", + ["<"] = "<", + [">"] = ">", + ["<="] = "≤", + [">="] = "≥", + ["-<"] = "≺", + [">-"] = "≻", + ["in"] = "∈", + ["!in"] = "∉", + ["sub"] = "⊂", + ["sup"] = "⊃", + ["sube"] = "⊆", + ["supe"] = "⊇", + ["-="] = "≡", + ["~="] = "≅", + ["~~"] = "≈", + ["prop"] = "∝", + + -- arrows + + ["rarr"] = "→", + ["->"] = "→", + ["larr"] = "←", + ["harr"] = "↔", + ["uarr"] = "↑", + ["darr"] = "↓", + ["rArr"] = "⇒", + ["lArr"] = "⇐", + ["hArr"] = "⇔", + ["|->"] = "↦", + + -- logical + + -- ["and"] = "and", + -- ["or"] = "or", + -- ["if"] = "if", + ["not"] = "¬", + ["=>"] = "⇒", + ["iff"] = "⇔", + ["AA"] = "∀", + ["EE"] = "∃", + ["_|_"] = "⊥", + ["TT"] = "⊤", + ["|--"] = "⊢", + ["|=="] = "⊨", + + -- miscellaneous + + ["del"] = "∂", + ["grad"] = "∇", + ["+-"] = "±", + ["O/"] = "∅", + ["oo"] = "∞", + ["aleph"] = "ℵ", + ["angle"] = "∠", + ["/_"] = "∠", + [":."] = "∴", + ["..."] = "...", -- ldots + ["ldots"] = "...", -- ldots + ["cdots"] = "⋯", + ["vdots"] = "⋮", + ["ddots"] = "⋱", + ["diamond"] = "⋄", + ["square"] = "□", + ["|__"] = "⌊", + ["__|"] = "⌋", + ["|~"] = "⌈", + ["~|"] = "⌉", + + -- more + ["_="] = "≡", + + -- blackboard + + ["CC"] = "ℂ", + ["NN"] = "ℕ", + ["QQ"] = "ℚ", + ["RR"] = "ℝ", + ["ZZ"] = "ℤ", + + -- greek lowercase + + alpha = "α", + beta = "β", + gamma = "γ", + delta = "δ", + epsilon = "ε", + varepsilon = "ɛ", + zeta = "ζ", + eta = "η", + theta = "θ", + vartheta = "ϑ", + iota = "ι", + kappa = "κ", + lambda = "λ", + mu = "μ", + nu = "ν", + xi = "ξ", + pi = "π", + rho = "ρ", + sigma = "σ", + tau = "τ", + upsilon = "υ", + phi = "φ", + varphi = "ϕ", + chi = "χ", + psi = "ψ", + omega = "ω", + + -- greek uppercase + + Gamma = "Γ", + Delta = "Δ", + Theta = "Θ", + Lambda = "Λ", + Xi = "Ξ", + Pi = "Π", + Sigma = "Σ", + Phi = "Φ", + Psi = "Ψ", + Omega = "Ω", + + -- alternatively we could just inject a style switch + following character + + -- blackboard + ["bbb a"] = "𝕒", + ["bbb b"] = "𝕓", + ["bbb c"] = "𝕔", + ["bbb d"] = "𝕕", + ["bbb e"] = "𝕖", + ["bbb f"] = "𝕗", + ["bbb g"] = "𝕘", + ["bbb h"] = "𝕙", + ["bbb i"] = "𝕚", + ["bbb j"] = "𝕛", + ["bbb k"] = "𝕜", + ["bbb l"] = "𝕝", + ["bbb m"] = "𝕞", + ["bbb n"] = "𝕟", + ["bbb o"] = "𝕠", + ["bbb p"] = "𝕡", + ["bbb q"] = "𝕢", + ["bbb r"] = "𝕣", + ["bbb s"] = "𝕤", + ["bbb t"] = "𝕥", + ["bbb u"] = "𝕦", + ["bbb v"] = "𝕧", + ["bbb w"] = "𝕨", + ["bbb x"] = "𝕩", + ["bbb y"] = "𝕪", + ["bbb z"] = "𝕫", + + ["bbb A"] = "𝔸", + ["bbb B"] = "𝔹", + ["bbb C"] = "ℂ", + ["bbb D"] = "𝔻", + ["bbb E"] = "𝔼", + ["bbb F"] = "𝔽", + ["bbb G"] = "𝔾", + ["bbb H"] = "ℍ", + ["bbb I"] = "𝕀", + ["bbb J"] = "𝕁", + ["bbb K"] = "𝕂", + ["bbb L"] = "𝕃", + ["bbb M"] = "𝕄", + ["bbb N"] = "ℕ", + ["bbb O"] = "𝕆", + ["bbb P"] = "ℙ", + ["bbb Q"] = "ℚ", + ["bbb R"] = "ℝ", + ["bbb S"] = "𝕊", + ["bbb T"] = "𝕋", + ["bbb U"] = "𝕌", + ["bbb V"] = "𝕍", + ["bbb W"] = "𝕎", + ["bbb X"] = "𝕏", + ["bbb Y"] = "𝕐", + ["bbb Z"] = "ℤ", + + -- fraktur + + ["fr a"] = "𝔞", + ["fr b"] = "𝔟", + ["fr c"] = "𝔠", + ["fr d"] = "𝔡", + ["fr e"] = "𝔢", + ["fr f"] = "𝔣", + ["fr g"] = "𝔤", + ["fr h"] = "𝔥", + ["fr i"] = "𝔦", + ["fr j"] = "𝔧", + ["fr k"] = "𝔨", + ["fr l"] = "𝔩", + ["fr m"] = "𝔪", + ["fr n"] = "𝔫", + ["fr o"] = "𝔬", + ["fr p"] = "𝔭", + ["fr q"] = "𝔮", + ["fr r"] = "𝔯", + ["fr s"] = "𝔰", + ["fr t"] = "𝔱", + ["fr u"] = "𝔲", + ["fr v"] = "𝔳", + ["fr w"] = "𝔴", + ["fr x"] = "𝔵", + ["fr y"] = "𝔶", + ["fr z"] = "𝔷", + + ["fr A"] = "𝔄", + ["fr B"] = "𝔅", + ["fr C"] = "ℭ", + ["fr D"] = "𝔇", + ["fr E"] = "𝔈", + ["fr F"] = "𝔉", + ["fr G"] = "𝔊", + ["fr H"] = "ℌ", + ["fr I"] = "ℑ", + ["fr J"] = "𝔍", + ["fr K"] = "𝔎", + ["fr L"] = "𝔏", + ["fr M"] = "𝔐", + ["fr N"] = "𝔑", + ["fr O"] = "𝔒", + ["fr P"] = "𝔓", + ["fr Q"] = "𝔔", + ["fr R"] = "ℜ", + ["fr S"] = "𝔖", + ["fr T"] = "𝔗", + ["fr U"] = "𝔘", + ["fr V"] = "𝔙", + ["fr W"] = "𝔚", + ["fr X"] = "𝔛", + ["fr Y"] = "𝔜", + ["fr Z"] = "ℨ", + + -- script + + ["cc a"] = "𝒶", + ["cc b"] = "𝒷", + ["cc c"] = "𝒸", + ["cc d"] = "𝒹", + ["cc e"] = "ℯ", + ["cc f"] = "𝒻", + ["cc g"] = "ℊ", + ["cc h"] = "𝒽", + ["cc i"] = "𝒾", + ["cc j"] = "𝒿", + ["cc k"] = "𝓀", + ["cc l"] = "𝓁", + ["cc m"] = "𝓂", + ["cc n"] = "𝓃", + ["cc o"] = "ℴ", + ["cc p"] = "𝓅", + ["cc q"] = "𝓆", + ["cc r"] = "𝓇", + ["cc s"] = "𝓈", + ["cc t"] = "𝓉", + ["cc u"] = "𝓊", + ["cc v"] = "𝓋", + ["cc w"] = "𝓌", + ["cc x"] = "𝓍", + ["cc y"] = "𝓎", + ["cc z"] = "𝓏", + + ["cc A"] = "𝒜", + ["cc B"] = "ℬ", + ["cc C"] = "𝒞", + ["cc D"] = "𝒟", + ["cc E"] = "ℰ", + ["cc F"] = "ℱ", + ["cc G"] = "𝒢", + ["cc H"] = "ℋ", + ["cc I"] = "ℐ", + ["cc J"] = "𝒥", + ["cc K"] = "𝒦", + ["cc L"] = "ℒ", + ["cc M"] = "ℳ", + ["cc N"] = "𝒩", + ["cc O"] = "𝒪", + ["cc P"] = "𝒫", + ["cc Q"] = "𝒬", + ["cc R"] = "ℛ", + ["cc S"] = "𝒮", + ["cc T"] = "𝒯", + ["cc U"] = "𝒰", + ["cc V"] = "𝒱", + ["cc W"] = "𝒲", + ["cc X"] = "𝒳", + ["cc Y"] = "𝒴", + ["cc Z"] = "𝒵", + + -- bold + + ["bb a"] = "𝒂", + ["bb b"] = "𝒃", + ["bb c"] = "𝒄", + ["bb d"] = "𝒅", + ["bb e"] = "𝒆", + ["bb f"] = "𝒇", + ["bb g"] = "𝒈", + ["bb h"] = "𝒉", + ["bb i"] = "𝒊", + ["bb j"] = "𝒋", + ["bb k"] = "𝒌", + ["bb l"] = "𝒍", + ["bb m"] = "𝒎", + ["bb n"] = "𝒏", + ["bb o"] = "𝒐", + ["bb p"] = "𝒑", + ["bb q"] = "𝒒", + ["bb r"] = "𝒓", + ["bb s"] = "𝒔", + ["bb t"] = "𝒕", + ["bb u"] = "𝒖", + ["bb v"] = "𝒗", + ["bb w"] = "𝒘", + ["bb x"] = "𝒙", + ["bb y"] = "𝒚", + ["bb z"] = "𝒛", + + ["bb A"] = "𝑨", + ["bb B"] = "𝑩", + ["bb C"] = "𝑪", + ["bb D"] = "𝑫", + ["bb E"] = "𝑬", + ["bb F"] = "𝑭", + ["bb G"] = "𝑮", + ["bb H"] = "𝑯", + ["bb I"] = "𝑰", + ["bb J"] = "𝑱", + ["bb K"] = "𝑲", + ["bb L"] = "𝑳", + ["bb M"] = "𝑴", + ["bb N"] = "𝑵", + ["bb O"] = "𝑶", + ["bb P"] = "𝑷", + ["bb Q"] = "𝑸", + ["bb R"] = "𝑹", + ["bb S"] = "𝑺", + ["bb T"] = "𝑻", + ["bb U"] = "𝑼", + ["bb V"] = "𝑽", + ["bb W"] = "𝑾", + ["bb X"] = "𝑿", + ["bb Y"] = "𝒀", + ["bb Z"] = "𝒁", + + -- sans + + ["sf a"] = "𝖺", + ["sf b"] = "𝖻", + ["sf c"] = "𝖼", + ["sf d"] = "𝖽", + ["sf e"] = "𝖾", + ["sf f"] = "𝖿", + ["sf g"] = "𝗀", + ["sf h"] = "𝗁", + ["sf i"] = "𝗂", + ["sf j"] = "𝗃", + ["sf k"] = "𝗄", + ["sf l"] = "𝗅", + ["sf m"] = "𝗆", + ["sf n"] = "𝗇", + ["sf o"] = "𝗈", + ["sf p"] = "𝗉", + ["sf q"] = "𝗊", + ["sf r"] = "𝗋", + ["sf s"] = "𝗌", + ["sf t"] = "𝗍", + ["sf u"] = "𝗎", + ["sf v"] = "𝗏", + ["sf w"] = "𝗐", + ["sf x"] = "𝗑", + ["sf y"] = "𝗒", + ["sf z"] = "𝗓", + + ["sf A"] = "𝖠", + ["sf B"] = "𝖡", + ["sf C"] = "𝖢", + ["sf D"] = "𝖣", + ["sf E"] = "𝖤", + ["sf F"] = "𝖥", + ["sf G"] = "𝖦", + ["sf H"] = "𝖧", + ["sf I"] = "𝖨", + ["sf J"] = "𝖩", + ["sf K"] = "𝖪", + ["sf L"] = "𝖫", + ["sf M"] = "𝖬", + ["sf N"] = "𝖭", + ["sf O"] = "𝖮", + ["sf P"] = "𝖯", + ["sf Q"] = "𝖰", + ["sf R"] = "𝖱", + ["sf S"] = "𝖲", + ["sf T"] = "𝖳", + ["sf U"] = "𝖴", + ["sf V"] = "𝖵", + ["sf W"] = "𝖶", + ["sf X"] = "𝖷", + ["sf Y"] = "𝖸", + ["sf Z"] = "𝖹", + + -- monospace + + ["tt a"] = "𝚊", + ["tt b"] = "𝚋", + ["tt c"] = "𝚌", + ["tt d"] = "𝚍", + ["tt e"] = "𝚎", + ["tt f"] = "𝚏", + ["tt g"] = "𝚐", + ["tt h"] = "𝚑", + ["tt i"] = "𝚒", + ["tt j"] = "𝚓", + ["tt k"] = "𝚔", + ["tt l"] = "𝚕", + ["tt m"] = "𝚖", + ["tt n"] = "𝚗", + ["tt o"] = "𝚘", + ["tt p"] = "𝚙", + ["tt q"] = "𝚚", + ["tt r"] = "𝚛", + ["tt s"] = "𝚜", + ["tt t"] = "𝚝", + ["tt u"] = "𝚞", + ["tt v"] = "𝚟", + ["tt w"] = "𝚠", + ["tt x"] = "𝚡", + ["tt y"] = "𝚢", + ["tt z"] = "𝚣", + + ["tt A"] = "𝙰", + ["tt B"] = "𝙱", + ["tt C"] = "𝙲", + ["tt D"] = "𝙳", + ["tt E"] = "𝙴", + ["tt F"] = "𝙵", + ["tt G"] = "𝙶", + ["tt H"] = "𝙷", + ["tt I"] = "𝙸", + ["tt J"] = "𝙹", + ["tt K"] = "𝙺", + ["tt L"] = "𝙻", + ["tt M"] = "𝙼", + ["tt N"] = "𝙽", + ["tt O"] = "𝙾", + ["tt P"] = "𝙿", + ["tt Q"] = "𝚀", + ["tt R"] = "𝚁", + ["tt S"] = "𝚂", + ["tt T"] = "𝚃", + ["tt U"] = "𝚄", + ["tt V"] = "𝚅", + ["tt W"] = "𝚆", + ["tt X"] = "𝚇", + ["tt Y"] = "𝚈", + ["tt Z"] = "𝚉", + + -- some more undocumented + + ["dx"] = { "d", "x" }, -- "{dx}" "\\left(dx\\right)" + ["dy"] = { "d", "y" }, -- "{dy}" "\\left(dy\\right)" + ["dz"] = { "d", "z" }, -- "{dz}" "\\left(dz\\right)" + + ["atan"] = "\\atan", + ["acos"] = "\\acos", + ["asin"] = "\\asin", + + ["arctan"] = "\\arctan", + ["arccos"] = "\\arccos", + ["arcsin"] = "\\arcsin", + + ["prime"] = "′", + ["'"] = "′", + ["''"] = "″", + ["'''"] = "‴", +} + +local isbinary = { + ["\\frac"] = true, + ["\\root"] = true, + ["\\rootradical"] = true, + ["\\stackrel"] = true, } -table.setmetatableindex(reserved,characters.entities) +local isunary = { + ["\\sqrt"] = true, + ["\\rootradical{}"] = true, + -- ["\\bb"] = true, + ["\\text"] = true, -- mathoptext + ["\\mathoptext"] = true, -- mathoptext + ["\\hat"] = true, -- widehat + ["\\widehat"] = true, -- widehat + ["\\overbar"] = true, -- + ["\\underline"] = true, -- + ["\\vec"] = true, -- overrightarrow + ["\\overrightarrow"] = true, -- overrightarrow + ["\\dot"] = true, -- + ["\\ddot"] = true, -- -local postmapper = Cs ( ( + ["^"] = true, + ["_"] = true, - P("\\mathoptext ") * spaces * (P("\\bgroup ")/"{") * (1-P("\\egroup "))^1 * (P("\\egroup ")/"}") + +} - (P("\\bgroup ")) / "{" + - (P("\\egroup ")) / "}" + +-- local isinfix = { +-- ["\\slash"] = true +-- } - P("\\") * (R("az","AZ")^2) + +local isleft = { + ["\\left\\lparent"] = true, + ["\\left\\lbrace"] = true, + ["\\left\\lbracket"] = true, +} +local isright = { + ["\\right\\rparent"] = true, + ["\\right\\rbrace"] = true, + ["\\right\\rbracket"] = true, +} - (R("AZ","az")^2) / reserved + +local issimplified = { +} - P("{:") / "\\left." + - P(":}") / "\\right." + - P("(") / "\\left(" + - P(")") / "\\right)" + - P("[") / "\\left[" + - P("]") / "\\right]" + - P("{") / "\\left\\{" + - P("}") / "\\right\\}" + +local p_number_base = patterns.cpnumber or patterns.cnumber or patterns.number +local p_number = C(p_number_base) +local p_spaces = patterns.whitespace - letter + P(1) -)^0 ) +----- p_number = Cs((patterns.cpnumber or patterns.cnumber or patterns.number)/function(s) return (gsub(s,",","{,}")) end) -local parser +local sign = P("-")^-1 +local digits = R("09")^1 +local integer = sign * digits +----- real = sign * digits * (S(".,") * digits)^-1 +local real = digits * (S(".,") * digits)^-1 +local float = real * (P("E") * integer)^-1 -local function converted(original,totex) - local ok, result - if trace_mapping then - report_asciimath("original : %s",original) +-- local number = C(float + integer) +local p_number = C(float) + +local p_open = S("{[") * P(":") +local p_close = P(":") * S("]}") + +local p_utf_base = + patterns.utf8character +local p_utf = + C(p_utf_base) + +local p_entity_base = + P("&") * ((1-P(";"))^2) * P(";") +local p_entity = + P("&") * (((1-P(";"))^2) / entities) * P(";") + +-- This is (given the large match): +-- +-- local s = sortedkeys(reserved) +-- local p = P(false) +-- for i=#s,1,-1 do +-- local k = s[i] +-- p = p + P(k) +-- end +-- local p_reserved = p / reserved +-- +-- twice as slow as: + +local k_reserved = sortedkeys(reserved) + +asciimath.keys = { + reserved = k_reserved +} + +local k_reserved_different = { } +local k_reserved_words = { } + +for k, v in sortedhash(reserved) do + if k ~= v then + k_reserved_different[#k_reserved_different+1] = k end - local premapped = lpegmatch(premapper,original) - if premapped then - if trace_mapping then - report_asciimath("prepared : %s",premapped) + if not find(k,"[^a-zA-Z]") then + k_reserved_words[#k_reserved_words+1] = k + end +end + +local p_reserved = + lpeg.utfchartabletopattern(k_reserved_different) / reserved + +-- local p_text = +-- P("text") +-- * p_spaces^0 +-- * Cc("\\mathoptext") +-- * ( -- maybe balanced +-- Cs((P("{") ) * (1-P("}"))^0 * P("}") ) +-- + Cs((P("(")/"{") * (1-P(")"))^0 * (P(")")/"}")) +-- ) +-- + Cc("\\mathoptext") * Cs(Cc("{") * patterns.undouble * Cc("}")) + +local p_text = + P("text") + * p_spaces^0 + * Cc("\\mathoptext") + * ( -- maybe balanced + Cs( P("{") * (1-P("}"))^0 * P("}") ) + + Cs((P("(")/"{") * (1-P(")"))^0 * (P(")")/"}")) + ) + + Cc("\\mathoptext") * Cs(Cc("{") * patterns.undouble * Cc("}")) + +-- either map to \left<utf> or map to \left\name + +local p_left = + P("(:") / "\\left\\langle" + + P("(") / "\\left\\lparent" + + P("[") / "\\left\\lbracket" + + P("{") / "\\left\\lbrace" + + P("<<") / "\\left\\langle" -- why not <: + + P("|_") / "\\left\\lfloor" + + P("|~") / "\\left\\lceil" + + + P("⟨") / "\\left\\langle" + +local p_right = + P(")") / "\\right\\rparent" + + P(":)") / "\\right\\rangle" + + P("]") / "\\right\\rbracket" + + P("}") / "\\right\\rbrace" + + P(">>") / "\\right\\rangle" -- why not :> + + P("~|") / "\\right\\rceil" + + P("_|") / "\\right\\rfloor" + + + P("⟩") / "\\right\\rangle" + +-- special cases + +-- local p_special = +-- C("/") +-- + P("\\ ") * Cc("{}") * p_spaces^0 * C(S("^_")) +-- + P("\\ ") * Cc("\\space") +-- + P("\\\\") * Cc("\\backslash") +-- + P("\\") * (R("az","AZ")^1/entities) +-- + P("|") * Cc("\\|") -- "\\middle\\|" -- maybe always add left / right as in mml ? +-- +-- faster bug also uglier: + +local p_special = + C("/") + + P("|") * Cc("\\|") -- "\\middle\\|" -- maybe always add left / right as in mml ? + + P("\\") * ( + ( + P(" ") * ( + Cc("{}") * p_spaces^0 * C(S("^_")) + + Cc("\\space") + ) + ) + + P("\\") * Cc("\\backslash") + + (R("az","AZ")^1/entities) + ) + +local parser = Ct { "tokenizer", + tokenizer = ( + p_spaces + + p_number + + p_text + + Ct(p_open * V("tokenizer") * p_close) + + Ct(p_left * V("tokenizer") * p_right) + + p_special + + p_reserved + + p_entity + + p_utf - p_close - p_right + )^1, +} + +local function show_state(state,level,t) + state = state + 1 + report_asciimath(table.serialize(t,formatters["stage %s:%s"](level,state))) + return state +end + +local function show_result(str,result) + report_asciimath("input > %s",str) + report_asciimath("result > %s",result) +end + +local function collapse(t,level) + if not t then + return "" + end + local state = 0 + if trace_detail then + if level then + level = level + 1 + else + level = 1 end - local parsed = lpegmatch(parser,premapped) - if parsed then - if trace_mapping then - report_asciimath("parsed : %s",parsed) + state = show_state(state,level,t) + end + -- + local n = #t + if n > 4 and t[3] == "," then + local l1 = t[1] + local r1 = t[n] + if isleft[l1] and isright[r1] then + local l2 = t[2] + local r2 = t[n-1] + if type(l2) == "table" and type(r2) == "table" then + -- we have a matrix + local valid = true + for i=3,n-2,2 do + if t[i] ~= "," then + valid = false + break + end + end + if valid then + for i=2,n-1,2 do + local ti = t[i] + local tl = ti[1] + local tr = ti[#ti] + if isleft[tl] and isright[tr] then + -- ok + else + valid = false + break + end + end + if valid then + t[1] = l1 .. "\\startmatrix" + for i=2,n-1 do + if t[i] == "," then + t[i] = "\\NR" + else + local ti = t[i] + ti[1] = "\\NC" + for i=2,#ti-1 do + if ti[i] == "," then + ti[i] = "\\NC" + end + end + ti[#ti] = nil + end + end + t[n] = "\\NR\\stopmatrix" .. r1 + end + end end - local postmapped = lpegmatch(postmapper,parsed) - if postmapped then - if trace_mapping then - report_asciimath("finalized: %s",postmapped) + end + end + -- + if trace_detail then + state = show_state(state,level,t) + end + -- + local n = #t + local i = 1 + while i < n do + local current = t[i] + if current == "/" and i > 1 then + local tl = t[i-1] + local tr = t[i+1] + if type(tl) == "table" then + if isleft[tl[1]] and isright[tl[#tl]] then + tl[1] = "" -- todo: remove + tl[#tl] = nil + end + end + if type(tr) == "table" then + if isleft[tr[1]] and isright[tr[#tr]] then + tr[1] = "" -- todo: remove + tr[#tr] = nil + end + end + i = i + 2 + elseif current == "," or current == ";" then + t[i] = current .. "\\thinspace" + i = i + 1 + else + i = i + 1 + end + end + -- + if trace_detail then + state = show_state(state,level,t) + end + -- + local n = #t + local i = 1 + if n > 2 then + while i < n do + local current = t[i] + if type(current) == "table" and isleft[t[i-1]] and isright[t[i+1]] then + local c = #current + if c > 2 and isleft[current[1]] and isright[current[c]] then + current[1] = "" + current[c] = nil end - result, ok = postmapped, true + i = i + 3 else - result = "error in postmapping" + i = i + 1 end + end + end + -- + if trace_detail then + state = show_state(state,level,t) + end + -- + local n = #t + local i = 1 + local m = 0 + while i <= n do + m = m + 1 + local current = t[i] + if isbinary[current] then + local one = t[i+1] + local two = t[i+2] + if not one then + t[m] = current .. "{}{}" -- error + break + end + if type(one) == "table" then + if isleft[one[1]] and isright[one[#one]] then + one[1] = "" + one[#one] = nil + end + one = collapse(one,level) + end + if not two then + t[m] = current .. "{" .. one .. "}{}" + break + end + if type(two) == "table" then + if isleft[two[1]] and isright[two[#two]] then + two[1] = "" + two[#two] = nil + end + two = collapse(two,level) + end + t[m] = current .. "{" .. one .. "}{" .. two .. "}" + i = i + 3 + elseif isunary[current] then + local one = t[i+1] + if not one then + m = m + 1 + t[m] = current .. "{}" -- error + break + end + if type(one) == "table" then + if isleft[one[1]] and isright[one[#one]] then + one[1] = "" + one[#one] = nil + end + one = collapse(one,level) + elseif one == "-" and i + 2 <= n then -- or another sign ? or unary ? + local t2 = t[i+2] + if type(t2) == "string" then + one = one .. t2 + i = i + 1 + end + end + t[m] = current .. "{" .. one .. "}" + i = i + 2 + elseif type(current) == "table" then + if current[1] == "\\NC" then + t[m] = collapse(current,level) + else + t[m] = "{" .. collapse(current,level) .. "}" + end + i = i + 1 else - result = "error in mapping" + t[m] = current + i = i + 1 + end + end + if i == n then -- yes? + m = m + 1 + t[m] = t[n] + end + if m < n then + for i=n,m+1,-1 do + t[i] = nil + end + end + -- + if trace_detail then + state = show_state(state,level,t) + end + -- + local n = #t + local m = 0 + local i = 1 + while i < n do + local current = t[i] + if current == "/" and i > 1 then + local tl = t[i-1] + local tr = t[i+1] + -- if type(tl) == "table" then + -- if isleft[tl[1]] and isright[tl[#tl]] then + -- tl[1] = "" + -- tl[#tl] = "" + -- end + -- end + -- if type(tr) == "table" then + -- if isleft[tr[1]] and isright[tr[#tr]] then + -- tr[1] = "" + -- tr[#tr] = "" + -- end + -- end + t[m] = "\\frac{" .. tl .. "}{" .. tr .. "}" + i = i + 2 + else + m = m + 1 + t[m] = current + i = i + 1 + end + end + if i == n then + m = m + 1 + t[m] = t[n] + end + if m < n then + for i=n,m+1,-1 do + t[i] = nil + end + end + -- + if trace_detail then + state = show_state(state,level,t) + end + -- + local n = #t + local m = 0 + local i = 1 + while i < n do + local current = t[i] + if current == "\\slash" and i > 1 then + t[m] = "{\\left(" .. t[i-1] .. "\\middle/" .. t[i+1] .. "\\right)}" + i = i + 2 + else + m = m + 1 + t[m] = current + i = i + 1 + end + end + if i == n then + m = m + 1 + t[m] = t[n] + end + if m < n then + for i=n,m+1,-1 do + t[i] = nil end - else - result = "error in premapping" + end + -- + if trace_detail then + state = show_state(state,level,t) + end + -- + local result = concat(t," ") + -- + return result +end + +-- todo: cache simple ones, say #str < 10, maybe weak + +local ctx_mathematics = context and context.mathematics or report_asciimath +local ctx_type = context and context.type or function() end +local ctx_inleft = context and context.inleft or function() end + +local function convert(str,totex) + local texcode = collapse(lpegmatch(parser,str)) + if trace_mapping then + show_result(str,texcode) end if totex then - if ok then - context.mathematics(result) + ctx_mathematics(texcode) + else + return texcode + end +end + +local n = 0 +local p = ( + (S("{[(") + P("\\left" )) / function() n = n + 1 end + + (S("}])") + P("\\right")) / function() n = n - 1 end + + P(1) +)^0 + +local function invalidtex(str) + n = 0 + local result = lpegmatch(p,str) + if n == 0 then + return false + elseif n < 0 then + return formatters["too many left fences: %s"](-n) + elseif n > 0 then + return formatters["not enough right fences: %s"](n) + end +end + +local collected = { } +local indexed = { } + +-- bonus + +local p_reserved_spaced = + C(lpeg.utfchartabletopattern(k_reserved_words)) / " %1 " + +local p_text = + C(P("text")) / " %1 " + * p_spaces^0 + * ( -- maybe balanced + (P("{") * (1-P("}"))^0 * P("}")) + + (P("(") * (1-P(")"))^0 * P(")")) + ) + + patterns.doublequoted + +local p_expand = Cs((p_text + p_reserved_spaced + p_entity_base + p_utf_base)^0) +local p_compress = patterns.collapser + +local function cleanedup(str) + return lpegmatch(p_compress,lpegmatch(p_expand,str)) or str +end + +-- so far + +function collect(fpattern,element,collected,indexed) + local element = element or "am" + local mpattern = formatters["<%s>(.-)</%s>"](element,element) + local filenames = dir.glob(fpattern) + local wildcard = string.split(fpattern,"*")[1] + if not collected then + collected = { } + indexed = { } + end + for i=1,#filenames do + filename = filenames[i] + local splitname = string.split(filename,wildcard) + local shortname = temp and temp[2] or file.basename(filename) + for s in gmatch(io.loaddata(filename),mpattern) do + local c = cleanedup(s) + local f = collected[c] + if f then + f.count = f.count + 1 + f.files[shortname] = (f.files[shortname] or 0) + 1 + if s ~= c then + f.cleanedup = f.cleanedup + 1 + end + f.dirty[s] = (f.dirty[s] or 0) + 1 + else + local texcode = convert(s) + local message = invalidtex(texcode) + if message then + report_asciimath("%s: %s",message,s) + end + collected[c] = { + count = 1, + files = { [shortname] = 1 }, + texcode = texcode, + message = message, + cleanedup = s ~= c and 1 or 0, + dirty = { [s] = 1 } + } + end + end + end + local n = 0 + for k, v in sortedhash(collected) do + n = n + 1 + v.n= n + indexed[n] = k + end + return collected, indexed +end + +asciimath.convert = convert +asciimath.reserved = reserved +asciimath.collect = collect +asciimath.invalidtex = invalidtex +asciimath.cleanedup = cleanedup + +-- sin(x) = 1 : 3.3 uncached 1.2 cached , so no real gain (better optimize the converter then) + +local function convert(str) + if #str == 1 then + ctx_mathematics(str) + else + local texcode = collapse(lpegmatch(parser,str)) + if trace_mapping then + show_result(str,texcode) + end + if #texcode == 0 then + report_asciimath("error in asciimath: %s",str) else - context.type(result) -- some day monospaced + local message = invalidtex(texcode) + if message then + report_asciimath("%s: %s",message,str) + ctx_type(formatters["<%s>"](message)) + else + ctx_mathematics(texcode) + end end + end +end + +commands.asciimath = convert + +if not context then + +-- trace_mapping = true +-- trace_detail = true + + report_asciimath(cleanedup([[ac+sinx+xsqrtx+sinsqrtx+sinsqrt(x)]])) + report_asciimath(cleanedup([[a "αsinsqrtx" b]])) + report_asciimath(cleanedup([[a "α" b]])) + + convert([[ac+sinx+xsqrtx]]) + convert([[ac+\alpha x+xsqrtx-cc b*pi**psi-3alephx / bb X]]) + convert([[ac+\ ^ x+xsqrtx]]) + convert([[d/dx(x^2+1)]]) + convert([[a "αsinsqrtx" b]]) + convert([[a "α" b]]) + +-- convert([[(1,5 ±sqrt(1,25 ),0 )]]) +-- convert([[1//2]]) +-- convert([[(p)/sqrt(p)]]) +-- convert([[u_tot]]) +-- convert([[u_tot=4,4 L+0,054 T]]) + +-- convert([[ [←;0,2] ]]) +-- convert([[ [←;0,2⟩ ]]) +-- convert([[ ⟨←;0,2 ) ]]) +-- convert([[ ⟨←;0,2 ] ]]) +-- convert([[ ⟨←;0,2⟩ ]]) + +-- convert([[ x^2(x-1/16)=0 ]]) +-- convert([[ y = ax + 3 - 3a ]]) +-- convert([[ y= ((1/4)) ^x ]]) +-- convert([[ x=\ ^ (1/4) log(0 ,002 )= log(0,002) / (log(1/4) ]]) +-- convert([[ x=\ ^glog(y) ]]) +-- convert([[ x^ (-1 1/2) =1/x^ (1 1/2)=1/ (x^1*x^ (1/2)) =1/ (xsqrt(x)) ]]) +-- convert([[ x^2(10 -x)>2 x^2 ]]) +-- convert([[ x^4>x ]]) + + return + +end + +local context = context + +local ctx_typebuffer = context.typebuffer +local ctx_mathematics = context.mathematics +local ctx_color = context.color + +local sequenced = table.sequenced +local assign_buffer = buffers.assign + +asciimath.show = { } + +local collected, indexed, ignored = { }, { }, { } + +local color = { "darkred" } + +function asciimath.show.ignore(n) + if type(n) == "string" then + local c = collected[n] + n = c and c.n + end + if n then + ignored[n] = true + end +end + +function asciimath.show.count(n,showcleanedup) + local v = collected[indexed[n]] + local count = v.count + local cleanedup = v.cleanedup + if not showcleanedup or cleanedup == 0 then + context(count) + elseif count == cleanedup then + ctx_color(color,count) + else + context("%s+",count-cleanedup) + ctx_color(color,cleanedup) + end +end + +local h = { } + +function asciimath.show.nofdirty(n) + local k = indexed[n] + local v = collected[k] + local n = v.cleanedup + h = { } + if n > 0 then + for d, n in sortedhash(v.dirty) do + if d ~= k then + h[#h+1] = { d, n } + end + end + end + context(#h) +end + +function asciimath.show.dirty(m,wrapped) + local d = h[m] + if d then + ctx_inleft(d[2]) + if wrapped then + assign_buffer("am",'"' .. d[1] .. '"') + else + assign_buffer("am",d[1]) + end + ctx_typebuffer { "am" } + end +end + +function asciimath.show.files(n) + context(sequenced(collected[indexed[n]].files," ")) +end + +function asciimath.show.input(n,wrapped) + if wrapped then + assign_buffer("am",'"' .. indexed[n] .. '"') else - return result + assign_buffer("am",indexed[n]) end + ctx_typebuffer { "am" } end -local function onlyconverted(str) - local parsed = lpegmatch(parser,str) - return parsed or str +function asciimath.show.result(n) + local v = collected[indexed[n]] + if ignored[n] then + context("ignored") + elseif v.message then + ctx_color(color, v.message) + else + ctx_mathematics(v.texcode) + end end -local sqrt = P("sqrt") / "\\rootradical \\bgroup \\egroup " -local root = P("root") / "\\rootradical " -local frac = P("frac") / "\\frac " -local stackrel = P("stackrel") / "\\stackrel " -local text = P("text") / "\\mathoptext " -local hat = P("hat") / "\\widehat " -local overbar = P("bar") / "\\overbar " -local underline = P("ul") / "\\underline " -local vec = P("vec") / "\\overrightarrow " -local dot = P("dot") / "\\dot " -local ddot = P("ddot") / "\\ddot " - -local left = S("{(") * P(":") + S("([{") -local right = P(":") * S(")}") + S(")]}") -local leftnorright = 1 - left - right -local singles = sqrt + text + hat + underline + overbar + vec + ddot + dot -local doubles = root + frac + stackrel -local ignoreleft = (left/"") * spaces * spaces -local ignoreright = spaces * (right/"") * spaces -local ignoreslash = spaces * (P("/")/"") * spaces -local comma = P(",") -local nocomma = 1-comma -local anychar = P(1) -local openmatrix = left * spaces * Cc("\\matrix\\bgroup ") -local closematrix = Cc("\\egroup ") * spaces * right -local nextcolumn = spaces * (comma/"&") * spaces -local nextrow = spaces * (comma/"\\cr ") * spaces -local finishrow = Cc("\\cr ") -local opengroup = left/"\\bgroup " -local closegroup = right/"\\egroup " -local somescript = S("^_") * spaces -local beginargument = Cc("\\bgroup ") -local endargument = Cc("\\egroup ") -local macro = P("\\") * R("az","AZ")^1 - -parser = Cs { "main", - - scripts = somescript * V("argument"), - division = Cc("\\frac") * V("argument") * spaces * ignoreslash * spaces * V("argument") - + Cc("\\left.") * V("balanced") * spaces * (P("\\slash ")/"\\middle/") * spaces * V("balanced") * Cc("\\right."), - double = doubles * spaces * V("argument") * spaces * V("argument"), - single = singles * spaces * V("argument"), - macro = macro, - - balanced = opengroup * (C((leftnorright + V("balanced"))^0)/onlyconverted) * closegroup, - argument = V("balanced") + V("token"), - - element = (V("step") + (V("argument") + V("step")) - ignoreright - nextcolumn - comma)^1, - commalist = ignoreleft * V("element") * (nextcolumn * spaces * V("element"))^0 * ignoreright, - matrix = openmatrix * spaces * (V("commalist") * (nextrow * V("commalist"))^0) * finishrow * closematrix, - - token = beginargument * (texnic + float + real + number + letter) * endargument, - - step = V("scripts") + V("division") + V("macro") + V("single") + V("double"), - main = (V("matrix") + V("step") + anychar)^0, +function asciimath.show.load(str,element) + collected, indexed, ignored = { }, { }, { } + local t = utilities.parsers.settings_to_array(str) + for i=1,#t do + asciimath.collect(t[i],element or "am",collected,indexed) + end +end -} +function asciimath.show.max() + context(#indexed) +end + +function asciimath.show.statistics() + local usedfiles = { } + local noffiles = 0 + local nofokay = 0 + local nofbad = 0 + local nofcleanedup = 0 + for k, v in next, collected do + if ignored[v.n] then + nofbad = nofbad + v.count + elseif v.message then + nofbad = nofbad + v.count + else + nofokay = nofokay + v.count + end + nofcleanedup = nofcleanedup + v.cleanedup + for k, v in next, v.files do + local u = usedfiles[k] + if u then + usedfiles[k] = u + 1 + else + noffiles = noffiles + 1 + usedfiles[k] = 1 + end + end + end + context.starttabulate { "|B||" } + context.NC() context("files") context.EQ() context(noffiles) context.NC() context.NR() + context.NC() context("formulas") context.EQ() context(nofokay+nofbad) context.NC() context.NR() + context.NC() context("uniques") context.EQ() context(#indexed) context.NC() context.NR() + context.NC() context("cleanedup") context.EQ() context(nofcleanedup) context.NC() context.NR() + context.NC() context("errors") context.EQ() context(nofbad) context.NC() context.NR() + context.stoptabulate() +end + +function asciimath.show.save(name) + table.save(name ~= "" and name or "dummy.lua",collected) +end + +-- maybe: -asciimath.reserved = reserved -asciimath.convert = converted +-- \backslash \ +-- \times × +-- \divide ÷ +-- \circ ∘ +-- \oplus ⊕ +-- \otimes ⊗ +-- \sum ∑ +-- \prod ∏ +-- \wedge ∧ +-- \bigwedge ⋀ +-- \vee ∨ +-- \bigvee ⋁ +-- \cup ∪ +-- \bigcup ⋃ +-- \cap ∩ +-- \bigcap ⋂ -commands.convert = converted +-- \ne ≠ +-- \le ≤ +-- \leq ≤ +-- \ge ≥ +-- \geq ≥ +-- \prec ≺ +-- \succ ≻ +-- \in ∈ +-- \notin ∉ +-- \subset ⊂ +-- \supset ⊃ +-- \subseteq ⊆ +-- \supseteq ⊇ +-- \equiv ≡ +-- \cong ≅ +-- \approx ≈ +-- \propto ∝ +-- +-- \neg ¬ +-- \implies ⇒ +-- \iff ⇔ +-- \forall ∀ +-- \exists ∃ +-- \bot ⊥ +-- \top ⊤ +-- \vdash ⊢ +-- \models ⊨ +-- +-- \int ∫ +-- \oint ∮ +-- \partial ∂ +-- \nabla ∇ +-- \pm ± +-- \emptyset ∅ +-- \infty ∞ +-- \aleph ℵ +-- \ldots ... +-- \cdots ⋯ +-- \quad +-- \diamond ⋄ +-- \square □ +-- \lfloor ⌊ +-- \rfloor ⌋ +-- \lceiling ⌈ +-- \rceiling ⌉ +-- +-- \sin sin +-- \cos cos +-- \tan tan +-- \csc csc +-- \sec sec +-- \cot cot +-- \sinh sinh +-- \cosh cosh +-- \tanh tanh +-- \log log +-- \ln ln +-- \det det +-- \dim dim +-- \lim lim +-- \mod mod +-- \gcd gcd +-- \lcm lcm +-- +-- \uparrow ↑ +-- \downarrow ↓ +-- \rightarrow → +-- \to → +-- \leftarrow ← +-- \leftrightarrow ↔ +-- \Rightarrow ⇒ +-- \Leftarrow ⇐ +-- \Leftrightarrow ⇔ +-- +-- \mathbf +-- \mathbb +-- \mathcal +-- \mathtt +-- \mathfrak |