summaryrefslogtreecommitdiff
path: root/tex/context/base/x-asciimath.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/x-asciimath.lua')
-rw-r--r--tex/context/base/x-asciimath.lua2279
1 files changed, 2054 insertions, 225 deletions
diff --git a/tex/context/base/x-asciimath.lua b/tex/context/base/x-asciimath.lua
index 992c37eae..51f401e66 100644
--- a/tex/context/base/x-asciimath.lua
+++ b/tex/context/base/x-asciimath.lua
@@ -7,266 +7,2095 @@ if not modules then modules = { } end modules ['x-asciimath'] = {
}
--[[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]]--
-local trace_mapping = false if trackers then trackers.register("modules.asciimath.mapping", function(v) trace_mapping = v end) end
+-- todo: spaces around all elements in cleanup?
+-- todo: filter from files listed in tuc file
-local asciimath = { }
-local moduledata = moduledata or { }
-moduledata.asciimath = asciimath
+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 trace_digits = false if trackers then trackers.register("modules.asciimath.digits", function(v) trace_digits = v end) end
local report_asciimath = logs.reporter("mathematics","asciimath")
-local format = string.format
-local lpegmatch = lpeg.match
-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)
+local asciimath = { }
+local moduledata = moduledata or { }
+moduledata.asciimath = asciimath
-)^0 )
+if not characters then
+ require("char-def")
+ require("char-ini")
+ require("char-ent")
+end
+
+local type, rawget = type, rawget
+local concat, insert, remove = table.concat, table.insert, table.remove
+local rep, gmatch, gsub, find = string.rep, string.gmatch, string.gsub, string.find
+local utfchar, utfbyte = utf.char, utf.byte
+
+local lpegmatch, patterns = lpeg.match, lpeg.patterns
+local S, P, R, C, V, Cc, Ct, Cs, Carg = lpeg.S, lpeg.P, lpeg.R, lpeg.C, lpeg.V, lpeg.Cc, lpeg.Ct, lpeg.Cs, lpeg.Carg
+
+local sortedhash = table.sortedhash
+local sortedkeys = table.sortedkeys
+local formatters = string.formatters
+
+local entities = characters.entities or { }
+
+local xmltext = xml.text
+local xmlinclusion = xml.inclusion
+local xmlcollected = xml.collected
+
+-- todo: use private unicodes as temporary slots ... easier to compare
+
+local s_lparent = "\\left\\lparent"
+local s_lbrace = "\\left\\lbrace"
+local s_lbracket = "\\left\\lbracket"
+local s_langle = "\\left\\langle"
+local s_lfloor = "\\left\\lfloor"
+local s_lceil = "\\left\\lceil"
+local s_left = "\\left."
+
+local s_rparent = "\\right\\rparent"
+local s_rbrace = "\\right\\rbrace"
+local s_rbracket = "\\right\\rbracket"
+local s_rangle = "\\right\\rangle"
+local s_rfloor = "\\right\\rfloor"
+local s_rceil = "\\right\\rceil"
+local s_right = "\\right."
+
+local s_mslash = "\\middle/"
+
+local s_lbar = "\\left\\|"
+local s_mbar = "\\middle\\|"
+local s_rbar = "\\right\\|"
+
+local s_lnothing = "\\left ." -- space fools checker
+local s_rnothing = "\\right ." -- space fools checker
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}",
+ ["prod"] = { false, "\\prod" },
+ ["sinh"] = { false, "\\sinh" },
+ ["cosh"] = { false, "\\cosh" },
+ ["tanh"] = { false, "\\tanh" },
+ ["sum"] = { false, "\\sum" },
+ ["int"] = { false, "\\int" },
+ ["sin"] = { false, "\\sin" },
+ ["cos"] = { false, "\\cos" },
+ ["tan"] = { false, "\\tan" },
+ ["csc"] = { false, "\\csc" },
+ ["sec"] = { false, "\\sec" },
+ ["cot"] = { false, "\\cot" },
+ ["log"] = { false, "\\log" },
+ ["det"] = { false, "\\det" },
+ ["lim"] = { false, "\\lim" },
+ ["mod"] = { false, "\\mod" },
+ ["gcd"] = { false, "\\gcd" },
+ ["min"] = { false, "\\min" },
+ ["max"] = { false, "\\max" },
+ ["ln"] = { false, "\\ln" },
+
+ ["atan"] = { false, "\\atan" }, -- extra
+ ["acos"] = { false, "\\acos" }, -- extra
+ ["asin"] = { false, "\\asin" }, -- extra
+ -- extra
+ ["arctan"] = { false, "\\arctan" }, -- extra
+ ["arccos"] = { false, "\\arccos" }, -- extra
+ ["arcsin"] = { false, "\\arcsin" }, -- extra
+
+ ["and"] = { false, "\\text{and}" },
+ ["or"] = { false, "\\text{or}" },
+ ["if"] = { false, "\\text{if}" },
+
+ ["sqrt"] = { false, "\\asciimathsqrt", "unary" },
+ ["root"] = { false, "\\asciimathroot", "binary" },
+ ["frac"] = { false, "\\frac", "binary" },
+ ["stackrel"] = { false, "\\asciimathstackrel", "binary" },
+ ["hat"] = { false, "\\widehat", "unary" },
+ ["bar"] = { false, "\\overbar", "unary" },
+ ["overbar"] = { false, "\\overbar", "unary" },
+ ["underline"] = { false, "\\underline", "unary" },
+ ["ul"] = { false, "\\underline", "unary" },
+ ["vec"] = { false, "\\overrightarrow", "unary" },
+ ["dot"] = { false, "\\dot", "unary" }, -- 0x2D9
+ ["ddot"] = { false, "\\ddot", "unary" }, -- 0xA8
+
+ -- binary operators
+
+ ["+"] = { true, "+" },
+ ["-"] = { true, "-" },
+ ["*"] = { true, "⋅" },
+ ["**"] = { true, "⋆" },
+ ["//"] = { true, "⁄" }, -- \slash
+ ["\\"] = { true, "\\" },
+ ["xx"] = { true, "×" },
+ ["times"] = { true, "×" },
+ ["-:"] = { true, "÷" },
+ ["@"] = { true, "∘" },
+ ["circ"] = { true, "∘" },
+ ["o+"] = { true, "⊕" },
+ ["ox"] = { true, "⊗" },
+ ["o."] = { true, "⊙" },
+ ["^^"] = { true, "∧" },
+ ["vv"] = { true, "∨" },
+ ["nn"] = { true, "∩" },
+ ["uu"] = { true, "∪" },
+
+ -- big operators
+
+ ["^^^"] = { true, "⋀" },
+ ["vvv"] = { true, "⋁" },
+ ["nnn"] = { true, "⋂" },
+ ["uuu"] = { true, "⋃" },
+ ["int"] = { true, "∫" },
+ ["oint"] = { true, "∮" },
+
+ -- brackets
+
+ ["("] = { true, "(" },
+ [")"] = { true, ")" },
+ ["["] = { true, "[" },
+ ["]"] = { true, "]" },
+ ["{"] = { true, "{" },
+ ["}"] = { true, "}" },
+
+ -- binary relations
+
+ ["="] = { true, "=" },
+ ["eq"] = { true, "=" },
+ ["!="] = { true, "≠" },
+ ["ne"] = { true, "≠" },
+ ["neq"] = { true, "≠" },
+ ["<"] = { true, "<" },
+ ["lt"] = { true, "<" },
+ [">"] = { true, ">" },
+ ["gt"] = { true, ">" },
+ ["<="] = { true, "≤" },
+ ["le"] = { true, "≤" },
+ ["leq"] = { true, "≤" },
+ [">="] = { true, "≥" },
+ ["ge"] = { true, "≥" },
+ ["geq"] = { true, "≥" },
+ ["-<"] = { true, "≺" },
+ [">-"] = { true, "≻" },
+ ["in"] = { true, "∈" },
+ ["!in"] = { true, "∉" },
+ ["sub"] = { true, "⊂" },
+ ["sup"] = { true, "⊃" },
+ ["sube"] = { true, "⊆" },
+ ["supe"] = { true, "⊇" },
+ ["-="] = { true, "≡" },
+ ["~="] = { true, "≅" },
+ ["~~"] = { true, "≈" },
+ ["prop"] = { true, "∝" },
+
+ -- arrows
+
+ ["rarr"] = { true, "→" },
+ ["->"] = { true, "→" },
+ ["larr"] = { true, "←" },
+ ["harr"] = { true, "↔" },
+ ["uarr"] = { true, "↑" },
+ ["darr"] = { true, "↓" },
+ ["rArr"] = { true, "⇒" },
+ ["lArr"] = { true, "⇐" },
+ ["hArr"] = { true, "⇔" },
+ ["|->"] = { true, "↦" },
+
+ -- logical
+
+ ["not"] = { true, "¬" },
+ ["=>"] = { true, "⇒" },
+ ["iff"] = { true, "⇔" },
+ ["AA"] = { true, "∀" },
+ ["EE"] = { true, "∃" },
+ ["_|_"] = { true, "⊥" },
+ ["TT"] = { true, "⊤" },
+ ["|--"] = { true, "⊢" },
+ ["|=="] = { true, "⊨" },
+
+ -- miscellaneous
+
+ ["del"] = { true, "∂" },
+ ["grad"] = { true, "∇" },
+ ["+-"] = { true, "±" },
+ ["O/"] = { true, "∅" },
+ ["oo"] = { true, "∞" },
+ ["aleph"] = { true, "ℵ" },
+ ["angle"] = { true, "∠" },
+ ["/_"] = { true, "∠" },
+ [":."] = { true, "∴" },
+ ["..."] = { true, "..." }, -- ldots
+ ["ldots"] = { true, "..." }, -- ldots
+ ["cdots"] = { true, "⋯" },
+ ["vdots"] = { true, "⋮" },
+ ["ddots"] = { true, "⋱" },
+ ["diamond"] = { true, "⋄" },
+ ["square"] = { true, "□" },
+ ["|__"] = { true, "⌊" },
+ ["__|"] = { true, "⌋" },
+ ["|~"] = { true, "⌈" },
+ ["~|"] = { true, "⌉" },
+
+ -- more
+
+ ["_="] = { true, "≡" },
+
+ -- bonus
+
+ ["prime"] = { true, "′" }, -- bonus
+ ["'"] = { true, "′" }, -- bonus
+ ["''"] = { true, "″" }, -- bonus
+ ["'''"] = { true, "‴" }, -- bonus
+
+ -- special
+
+ ["%"] = { false, "\\mathpercent" },
+ ["&"] = { false, "\\mathampersand" },
+ ["#"] = { false, "\\mathhash" },
+ ["$"] = { false, "\\mathdollar" },
+
+ -- blackboard
+
+ ["CC"] = { true, "ℂ" },
+ ["NN"] = { true, "ℕ" },
+ ["QQ"] = { true, "ℚ" },
+ ["RR"] = { true, "ℝ" },
+ ["ZZ"] = { true, "ℤ" },
+
+ -- greek lowercase
+
+ ["alpha"] = { true, "α" },
+ ["beta"] = { true, "β" },
+ ["gamma"] = { true, "γ" },
+ ["delta"] = { true, "δ" },
+ ["epsilon"] = { true, "ε" },
+ ["varepsilon"] = { true, "ɛ" },
+ ["zeta"] = { true, "ζ" },
+ ["eta"] = { true, "η" },
+ ["theta"] = { true, "θ" },
+ ["vartheta"] = { true, "ϑ" },
+ ["iota"] = { true, "ι" },
+ ["kappa"] = { true, "κ" },
+ ["lambda"] = { true, "λ" },
+ ["mu"] = { true, "μ" },
+ ["nu"] = { true, "ν" },
+ ["xi"] = { true, "ξ" },
+ ["pi"] = { true, "π" },
+ ["rho"] = { true, "ρ" },
+ ["sigma"] = { true, "σ" },
+ ["tau"] = { true, "τ" },
+ ["upsilon"] = { true, "υ" },
+ ["phi"] = { true, "φ" },
+ ["varphi"] = { true, "ϕ" },
+ ["chi"] = { true, "χ" },
+ ["psi"] = { true, "ψ" },
+ ["omega"] = { true, "ω" },
+
+ -- greek uppercase
+
+ ["Gamma"] = { true, "Γ" },
+ ["Delta"] = { true, "Δ" },
+ ["Theta"] = { true, "Θ" },
+ ["Lambda"] = { true, "Λ" },
+ ["Xi"] = { true, "Ξ" },
+ ["Pi"] = { true, "Π" },
+ ["Sigma"] = { true, "Σ" },
+ ["Phi"] = { true, "Φ" },
+ ["Psi"] = { true, "Ψ" },
+ ["Omega"] = { true, "Ω" },
+
+ -- blackboard
+
+ ["bbb a"] = { true, "𝕒" },
+ ["bbb b"] = { true, "𝕓" },
+ ["bbb c"] = { true, "𝕔" },
+ ["bbb d"] = { true, "𝕕" },
+ ["bbb e"] = { true, "𝕖" },
+ ["bbb f"] = { true, "𝕗" },
+ ["bbb g"] = { true, "𝕘" },
+ ["bbb h"] = { true, "𝕙" },
+ ["bbb i"] = { true, "𝕚" },
+ ["bbb j"] = { true, "𝕛" },
+ ["bbb k"] = { true, "𝕜" },
+ ["bbb l"] = { true, "𝕝" },
+ ["bbb m"] = { true, "𝕞" },
+ ["bbb n"] = { true, "𝕟" },
+ ["bbb o"] = { true, "𝕠" },
+ ["bbb p"] = { true, "𝕡" },
+ ["bbb q"] = { true, "𝕢" },
+ ["bbb r"] = { true, "𝕣" },
+ ["bbb s"] = { true, "𝕤" },
+ ["bbb t"] = { true, "𝕥" },
+ ["bbb u"] = { true, "𝕦" },
+ ["bbb v"] = { true, "𝕧" },
+ ["bbb w"] = { true, "𝕨" },
+ ["bbb x"] = { true, "𝕩" },
+ ["bbb y"] = { true, "𝕪" },
+ ["bbb z"] = { true, "𝕫" },
+
+ ["bbb A"] = { true, "𝔸" },
+ ["bbb B"] = { true, "𝔹" },
+ ["bbb C"] = { true, "ℂ" },
+ ["bbb D"] = { true, "𝔻" },
+ ["bbb E"] = { true, "𝔼" },
+ ["bbb F"] = { true, "𝔽" },
+ ["bbb G"] = { true, "𝔾" },
+ ["bbb H"] = { true, "ℍ" },
+ ["bbb I"] = { true, "𝕀" },
+ ["bbb J"] = { true, "𝕁" },
+ ["bbb K"] = { true, "𝕂" },
+ ["bbb L"] = { true, "𝕃" },
+ ["bbb M"] = { true, "𝕄" },
+ ["bbb N"] = { true, "ℕ" },
+ ["bbb O"] = { true, "𝕆" },
+ ["bbb P"] = { true, "ℙ" },
+ ["bbb Q"] = { true, "ℚ" },
+ ["bbb R"] = { true, "ℝ" },
+ ["bbb S"] = { true, "𝕊" },
+ ["bbb T"] = { true, "𝕋" },
+ ["bbb U"] = { true, "𝕌" },
+ ["bbb V"] = { true, "𝕍" },
+ ["bbb W"] = { true, "𝕎" },
+ ["bbb X"] = { true, "𝕏" },
+ ["bbb Y"] = { true, "𝕐" },
+ ["bbb Z"] = { true, "ℤ" },
+
+ -- fraktur
+
+ ["fr a"] = { true, "𝔞" },
+ ["fr b"] = { true, "𝔟" },
+ ["fr c"] = { true, "𝔠" },
+ ["fr d"] = { true, "𝔡" },
+ ["fr e"] = { true, "𝔢" },
+ ["fr f"] = { true, "𝔣" },
+ ["fr g"] = { true, "𝔤" },
+ ["fr h"] = { true, "𝔥" },
+ ["fr i"] = { true, "𝔦" },
+ ["fr j"] = { true, "𝔧" },
+ ["fr k"] = { true, "𝔨" },
+ ["fr l"] = { true, "𝔩" },
+ ["fr m"] = { true, "𝔪" },
+ ["fr n"] = { true, "𝔫" },
+ ["fr o"] = { true, "𝔬" },
+ ["fr p"] = { true, "𝔭" },
+ ["fr q"] = { true, "𝔮" },
+ ["fr r"] = { true, "𝔯" },
+ ["fr s"] = { true, "𝔰" },
+ ["fr t"] = { true, "𝔱" },
+ ["fr u"] = { true, "𝔲" },
+ ["fr v"] = { true, "𝔳" },
+ ["fr w"] = { true, "𝔴" },
+ ["fr x"] = { true, "𝔵" },
+ ["fr y"] = { true, "𝔶" },
+ ["fr z"] = { true, "𝔷" },
+
+ ["fr A"] = { true, "𝔄" },
+ ["fr B"] = { true, "𝔅" },
+ ["fr C"] = { true, "ℭ" },
+ ["fr D"] = { true, "𝔇" },
+ ["fr E"] = { true, "𝔈" },
+ ["fr F"] = { true, "𝔉" },
+ ["fr G"] = { true, "𝔊" },
+ ["fr H"] = { true, "ℌ" },
+ ["fr I"] = { true, "ℑ" },
+ ["fr J"] = { true, "𝔍" },
+ ["fr K"] = { true, "𝔎" },
+ ["fr L"] = { true, "𝔏" },
+ ["fr M"] = { true, "𝔐" },
+ ["fr N"] = { true, "𝔑" },
+ ["fr O"] = { true, "𝔒" },
+ ["fr P"] = { true, "𝔓" },
+ ["fr Q"] = { true, "𝔔" },
+ ["fr R"] = { true, "ℜ" },
+ ["fr S"] = { true, "𝔖" },
+ ["fr T"] = { true, "𝔗" },
+ ["fr U"] = { true, "𝔘" },
+ ["fr V"] = { true, "𝔙" },
+ ["fr W"] = { true, "𝔚" },
+ ["fr X"] = { true, "𝔛" },
+ ["fr Y"] = { true, "𝔜" },
+ ["fr Z"] = { true, "ℨ" },
+
+ -- script
+
+ ["cc a"] = { true, "𝒶" },
+ ["cc b"] = { true, "𝒷" },
+ ["cc c"] = { true, "𝒸" },
+ ["cc d"] = { true, "𝒹" },
+ ["cc e"] = { true, "ℯ" },
+ ["cc f"] = { true, "𝒻" },
+ ["cc g"] = { true, "ℊ" },
+ ["cc h"] = { true, "𝒽" },
+ ["cc i"] = { true, "𝒾" },
+ ["cc j"] = { true, "𝒿" },
+ ["cc k"] = { true, "𝓀" },
+ ["cc l"] = { true, "𝓁" },
+ ["cc m"] = { true, "𝓂" },
+ ["cc n"] = { true, "𝓃" },
+ ["cc o"] = { true, "ℴ" },
+ ["cc p"] = { true, "𝓅" },
+ ["cc q"] = { true, "𝓆" },
+ ["cc r"] = { true, "𝓇" },
+ ["cc s"] = { true, "𝓈" },
+ ["cc t"] = { true, "𝓉" },
+ ["cc u"] = { true, "𝓊" },
+ ["cc v"] = { true, "𝓋" },
+ ["cc w"] = { true, "𝓌" },
+ ["cc x"] = { true, "𝓍" },
+ ["cc y"] = { true, "𝓎" },
+ ["cc z"] = { true, "𝓏" },
+
+ ["cc A"] = { true, "𝒜" },
+ ["cc B"] = { true, "ℬ" },
+ ["cc C"] = { true, "𝒞" },
+ ["cc D"] = { true, "𝒟" },
+ ["cc E"] = { true, "ℰ" },
+ ["cc F"] = { true, "ℱ" },
+ ["cc G"] = { true, "𝒢" },
+ ["cc H"] = { true, "ℋ" },
+ ["cc I"] = { true, "ℐ" },
+ ["cc J"] = { true, "𝒥" },
+ ["cc K"] = { true, "𝒦" },
+ ["cc L"] = { true, "ℒ" },
+ ["cc M"] = { true, "ℳ" },
+ ["cc N"] = { true, "𝒩" },
+ ["cc O"] = { true, "𝒪" },
+ ["cc P"] = { true, "𝒫" },
+ ["cc Q"] = { true, "𝒬" },
+ ["cc R"] = { true, "ℛ" },
+ ["cc S"] = { true, "𝒮" },
+ ["cc T"] = { true, "𝒯" },
+ ["cc U"] = { true, "𝒰" },
+ ["cc V"] = { true, "𝒱" },
+ ["cc W"] = { true, "𝒲" },
+ ["cc X"] = { true, "𝒳" },
+ ["cc Y"] = { true, "𝒴" },
+ ["cc Z"] = { true, "𝒵" },
+
+ -- bold
+
+ ["bb a"] = { true, "𝒂" },
+ ["bb b"] = { true, "𝒃" },
+ ["bb c"] = { true, "𝒄" },
+ ["bb d"] = { true, "𝒅" },
+ ["bb e"] = { true, "𝒆" },
+ ["bb f"] = { true, "𝒇" },
+ ["bb g"] = { true, "𝒈" },
+ ["bb h"] = { true, "𝒉" },
+ ["bb i"] = { true, "𝒊" },
+ ["bb j"] = { true, "𝒋" },
+ ["bb k"] = { true, "𝒌" },
+ ["bb l"] = { true, "𝒍" },
+ ["bb m"] = { true, "𝒎" },
+ ["bb n"] = { true, "𝒏" },
+ ["bb o"] = { true, "𝒐" },
+ ["bb p"] = { true, "𝒑" },
+ ["bb q"] = { true, "𝒒" },
+ ["bb r"] = { true, "𝒓" },
+ ["bb s"] = { true, "𝒔" },
+ ["bb t"] = { true, "𝒕" },
+ ["bb u"] = { true, "𝒖" },
+ ["bb v"] = { true, "𝒗" },
+ ["bb w"] = { true, "𝒘" },
+ ["bb x"] = { true, "𝒙" },
+ ["bb y"] = { true, "𝒚" },
+ ["bb z"] = { true, "𝒛" },
+
+ ["bb A"] = { true, "𝑨" },
+ ["bb B"] = { true, "𝑩" },
+ ["bb C"] = { true, "𝑪" },
+ ["bb D"] = { true, "𝑫" },
+ ["bb E"] = { true, "𝑬" },
+ ["bb F"] = { true, "𝑭" },
+ ["bb G"] = { true, "𝑮" },
+ ["bb H"] = { true, "𝑯" },
+ ["bb I"] = { true, "𝑰" },
+ ["bb J"] = { true, "𝑱" },
+ ["bb K"] = { true, "𝑲" },
+ ["bb L"] = { true, "𝑳" },
+ ["bb M"] = { true, "𝑴" },
+ ["bb N"] = { true, "𝑵" },
+ ["bb O"] = { true, "𝑶" },
+ ["bb P"] = { true, "𝑷" },
+ ["bb Q"] = { true, "𝑸" },
+ ["bb R"] = { true, "𝑹" },
+ ["bb S"] = { true, "𝑺" },
+ ["bb T"] = { true, "𝑻" },
+ ["bb U"] = { true, "𝑼" },
+ ["bb V"] = { true, "𝑽" },
+ ["bb W"] = { true, "𝑾" },
+ ["bb X"] = { true, "𝑿" },
+ ["bb Y"] = { true, "𝒀" },
+ ["bb Z"] = { true, "𝒁" },
+
+ -- sans
+
+ ["sf a"] = { true, "𝖺" },
+ ["sf b"] = { true, "𝖻" },
+ ["sf c"] = { true, "𝖼" },
+ ["sf d"] = { true, "𝖽" },
+ ["sf e"] = { true, "𝖾" },
+ ["sf f"] = { true, "𝖿" },
+ ["sf g"] = { true, "𝗀" },
+ ["sf h"] = { true, "𝗁" },
+ ["sf i"] = { true, "𝗂" },
+ ["sf j"] = { true, "𝗃" },
+ ["sf k"] = { true, "𝗄" },
+ ["sf l"] = { true, "𝗅" },
+ ["sf m"] = { true, "𝗆" },
+ ["sf n"] = { true, "𝗇" },
+ ["sf o"] = { true, "𝗈" },
+ ["sf p"] = { true, "𝗉" },
+ ["sf q"] = { true, "𝗊" },
+ ["sf r"] = { true, "𝗋" },
+ ["sf s"] = { true, "𝗌" },
+ ["sf t"] = { true, "𝗍" },
+ ["sf u"] = { true, "𝗎" },
+ ["sf v"] = { true, "𝗏" },
+ ["sf w"] = { true, "𝗐" },
+ ["sf x"] = { true, "𝗑" },
+ ["sf y"] = { true, "𝗒" },
+ ["sf z"] = { true, "𝗓" },
+
+ ["sf A"] = { true, "𝖠" },
+ ["sf B"] = { true, "𝖡" },
+ ["sf C"] = { true, "𝖢" },
+ ["sf D"] = { true, "𝖣" },
+ ["sf E"] = { true, "𝖤" },
+ ["sf F"] = { true, "𝖥" },
+ ["sf G"] = { true, "𝖦" },
+ ["sf H"] = { true, "𝖧" },
+ ["sf I"] = { true, "𝖨" },
+ ["sf J"] = { true, "𝖩" },
+ ["sf K"] = { true, "𝖪" },
+ ["sf L"] = { true, "𝖫" },
+ ["sf M"] = { true, "𝖬" },
+ ["sf N"] = { true, "𝖭" },
+ ["sf O"] = { true, "𝖮" },
+ ["sf P"] = { true, "𝖯" },
+ ["sf Q"] = { true, "𝖰" },
+ ["sf R"] = { true, "𝖱" },
+ ["sf S"] = { true, "𝖲" },
+ ["sf T"] = { true, "𝖳" },
+ ["sf U"] = { true, "𝖴" },
+ ["sf V"] = { true, "𝖵" },
+ ["sf W"] = { true, "𝖶" },
+ ["sf X"] = { true, "𝖷" },
+ ["sf Y"] = { true, "𝖸" },
+ ["sf Z"] = { true, "𝖹" },
+
+ -- monospace
+
+ ["tt a"] = { true, "𝚊" },
+ ["tt b"] = { true, "𝚋" },
+ ["tt c"] = { true, "𝚌" },
+ ["tt d"] = { true, "𝚍" },
+ ["tt e"] = { true, "𝚎" },
+ ["tt f"] = { true, "𝚏" },
+ ["tt g"] = { true, "𝚐" },
+ ["tt h"] = { true, "𝚑" },
+ ["tt i"] = { true, "𝚒" },
+ ["tt j"] = { true, "𝚓" },
+ ["tt k"] = { true, "𝚔" },
+ ["tt l"] = { true, "𝚕" },
+ ["tt m"] = { true, "𝚖" },
+ ["tt n"] = { true, "𝚗" },
+ ["tt o"] = { true, "𝚘" },
+ ["tt p"] = { true, "𝚙" },
+ ["tt q"] = { true, "𝚚" },
+ ["tt r"] = { true, "𝚛" },
+ ["tt s"] = { true, "𝚜" },
+ ["tt t"] = { true, "𝚝" },
+ ["tt u"] = { true, "𝚞" },
+ ["tt v"] = { true, "𝚟" },
+ ["tt w"] = { true, "𝚠" },
+ ["tt x"] = { true, "𝚡" },
+ ["tt y"] = { true, "𝚢" },
+ ["tt z"] = { true, "𝚣" },
+
+ ["tt A"] = { true, "𝙰" },
+ ["tt B"] = { true, "𝙱" },
+ ["tt C"] = { true, "𝙲" },
+ ["tt D"] = { true, "𝙳" },
+ ["tt E"] = { true, "𝙴" },
+ ["tt F"] = { true, "𝙵" },
+ ["tt G"] = { true, "𝙶" },
+ ["tt H"] = { true, "𝙷" },
+ ["tt I"] = { true, "𝙸" },
+ ["tt J"] = { true, "𝙹" },
+ ["tt K"] = { true, "𝙺" },
+ ["tt L"] = { true, "𝙻" },
+ ["tt M"] = { true, "𝙼" },
+ ["tt N"] = { true, "𝙽" },
+ ["tt O"] = { true, "𝙾" },
+ ["tt P"] = { true, "𝙿" },
+ ["tt Q"] = { true, "𝚀" },
+ ["tt R"] = { true, "𝚁" },
+ ["tt S"] = { true, "𝚂" },
+ ["tt T"] = { true, "𝚃" },
+ ["tt U"] = { true, "𝚄" },
+ ["tt V"] = { true, "𝚅" },
+ ["tt W"] = { true, "𝚆" },
+ ["tt X"] = { true, "𝚇" },
+ ["tt Y"] = { true, "𝚈" },
+ ["tt Z"] = { true, "𝚉" },
+
+ -- some more undocumented
+
+ ["dx"] = { false, { "d", "x" } }, -- "{dx}" "\\left(dx\\right)"
+ ["dy"] = { false, { "d", "y" } }, -- "{dy}" "\\left(dy\\right)"
+ ["dz"] = { false, { "d", "z" } }, -- "{dz}" "\\left(dz\\right)"
+
+ -- fences
+
+ ["(:"] = { true, "(:" },
+ ["{:"] = { true, "{:" },
+ ["[:"] = { true, "[:" },
+ ["("] = { true, "(" },
+ ["["] = { true, "[" },
+ ["{"] = { true, "{" },
+ ["<<"] = { true, "⟨" }, -- why not <:
+ ["|_"] = { true, "⌊" },
+ ["|~"] = { true, "⌈" },
+ ["⟨"] = { true, "⟨" },
+ ["〈"] = { true, "⟨" },
+ ["〈"] = { true, "⟨" },
+
+ [":)"] = { true, ":)" },
+ [":}"] = { true, ":}" },
+ [":]"] = { true, ":]" },
+ [")"] = { true, ")" },
+ ["]"] = { true, "]" },
+ ["}"] = { true, "}" },
+ [">>"] = { true, "⟩" }, -- why not :>
+ ["~|"] = { true, "⌉" },
+ ["_|"] = { true, "⌋" },
+ ["⟩"] = { true, "⟩" },
+ ["〉"] = { true, "⟩" },
+ ["〉"] = { true, "⟩" },
+
+ ["lparent"] = { true, "(" },
+ ["lbracket"] = { true, "[" },
+ ["lbrace"] = { true, "{" },
+ ["langle"] = { true, "⟨" },
+ ["lfloor"] = { true, "⌊" },
+ ["lceil"] = { true, "⌈" },
+
+ ["rparent"] = { true, ")" },
+ ["rbracket"] = { true, "]" },
+ ["rbrace"] = { true, "}" },
+ ["rangle"] = { true, "⟩" },
+ ["rfloor"] = { true, "⌋" },
+ ["rceil"] = { true, "⌉" },
+
+ -- a bit special:
+
+ ["\\frac"] = { true, "frac" },
+
+ -- now it gets real crazy, only these two:
+
+ ["&gt;"] = { true, ">" },
+ ["&lt;"] = { true, "<" },
+
+}
+
+for k, v in next, characters.data do
+ local name = v.mathname
+ if name and not reserved[name] then
+ reserved[name] = { true, utfchar(k) }
+ end
+ local spec = v.mathspec
+ -- if spec then
+ -- for i=1,#spec do
+ -- local name = spec[i].name
+ -- if name and not reserved[name] then
+ -- reserved[name] = { true, utfchar(k) }
+ -- end
+ -- end
+ -- end
+end
+
+reserved.P = nil
+reserved.S = nil
+
+local isbinary = {
+ ["\\frac"] = true,
+ ["\\root"] = true,
+ ["\\asciimathroot"] = true,
+ ["\\asciimathstackrel"] = true,
}
-table.setmetatableindex(reserved,characters.entities)
+local isunary = {
+ ["\\sqrt"] = true,
+ ["\\asciimathsqrt"] = true,
+ ["\\text"] = true, -- mathoptext
+ ["\\mathoptext"] = true, -- mathoptext
+ ["\\asciimathoptext"] = true, -- mathoptext
+ ["\\hat"] = true, -- widehat
+ ["\\widehat"] = true, -- widehat
+ ["\\bar"] = true, --
+ ["\\overbar"] = true, --
+ ["\\underline"] = true, --
+ ["\\vec"] = true, -- overrightarrow
+ ["\\overrightarrow"] = true, -- overrightarrow
+ ["\\dot"] = true, --
+ ["\\ddot"] = true, --
-local postmapper = Cs ( (
+}
+
+local isfunny = {
+ ["\\sin"] = true,
+}
+
+local isinfix = {
+ ["^"] = true,
+ ["_"] = true,
+}
+
+local isleft = {
+ [s_lparent] = true,
+ [s_lbrace] = true,
+ [s_lbracket] = true,
+ [s_langle] = true,
+ [s_lfloor] = true,
+ [s_lceil] = true,
+ [s_left] = true,
+}
+
+local isright = {
+ [s_rparent] = true,
+ [s_rbrace] = true,
+ [s_rbracket] = true,
+ [s_rangle] = true,
+ [s_rfloor] = true,
+ [s_rceil] = true,
+ [s_right] = true,
+}
+
+local issimplified = {
+}
+
+--
+
+-- special mess
- P("\\mathoptext ") * spaces * (P("\\bgroup ")/"{") * (1-P("\\egroup "))^1 * (P("\\egroup ")/"}") +
+local d_one = R("09")
+local d_two = d_one * d_one
+local d_three = d_two * d_one
+local d_four = d_three * d_one
+local d_split = P(-1) + P(",")
- (P("\\bgroup ")) / "{" +
- (P("\\egroup ")) / "}" +
+local d_spaced = (Carg(1) * d_three)^1
- P("\\") * (R("az","AZ")^2) +
+local digitized_1 = Cs ( (
+ d_three * d_spaced * d_split +
+ d_two * d_spaced * d_split +
+ d_one * d_spaced * d_split +
+ P(1)
+ )^1 )
- (R("AZ","az")^2) / reserved +
+local p_fourbefore = d_four * d_split
+local p_fourafter = d_four * P(-1)
- P("{:") / "\\left." +
- P(":}") / "\\right." +
- P("(") / "\\left(" +
- P(")") / "\\right)" +
- P("[") / "\\left[" +
- P("]") / "\\right]" +
- P("{") / "\\left\\{" +
- P("}") / "\\right\\}" +
+local p_beforecomma = d_three * d_spaced * d_split
+ + d_two * d_spaced * d_split
+ + d_one * d_spaced * d_split
+ + d_one * d_split
+
+local p_aftercomma = p_fourafter
+ + d_three * d_spaced
+ + d_two * d_spaced
+ + d_one * d_spaced
+
+local digitized_2 = Cs (
+ p_fourbefore * (p_aftercomma^0) +
+ p_beforecomma * ((p_aftercomma + d_one^1)^0)
+ )
+
+local p_fourbefore = d_four * d_split
+local p_fourafter = d_four
+local d_spaced = (Carg(1) * (d_three + d_two + d_one))^1
+local p_aftercomma = p_fourafter * P(-1)
+ + d_three * d_spaced * P(1)^0
+ + d_one^1
+
+-- local digitized_3 = Cs (
+-- p_fourbefore * p_aftercomma^0 +
+-- p_beforecomma * p_aftercomma^0
+-- )
+
+local digitized_3 = Cs((p_fourbefore + p_beforecomma) * p_aftercomma^0)
+
+local splitmethods = {
+ digitized_1,
+ digitized_2,
+ digitized_3,
+}
+
+local splitmethod = nil
+
+function asciimath.setup(settings)
+ splitmethod = splitmethods[tonumber(settings.splitmethod) or 0]
+ if splitmethod then
+ local separator = settings.separator
+ if separator == true or not interfaces or interfaces.variables.yes then
+ digitseparator = utfchar(0x2008)
+ elseif type(separator) == "string" and separator ~= "" then
+ digitseparator = separator
+ else
+ splitmethod = nil
+ end
+ end
+end
- letter + P(1)
+local collected_digits = { }
+local collected_filename = "asciimath-digits.lua"
+
+function numbermess(s)
+ if splitmethod then
+ local d = lpegmatch(splitmethod,s,1,digitseparator)
+ if d then
+ if trace_digits and s ~= d then
+ collected_digits[s] = d
+ end
+ return d
+ end
+ end
+ return s
+end
+
+-- asciimath.setup { splitmethod = 3 }
+-- local t = {
+-- "1", "12", "123", "1234", "12345", "123456", "1234567", "12345678", "123456789",
+-- "1,1",
+-- "12,12",
+-- "123,123",
+-- "1234,123",
+-- "1234,1234",
+-- "12345,1234",
+-- "1234,12345",
+-- "12345,12345",
+-- "123456,123456",
+-- "1234567,1234567",
+-- "12345678,12345678",
+-- "123456789,123456789",
+-- "0,1234",
+-- "1234,0",
+-- "1234,00",
+-- "0,123456789",
+-- }
+-- for i=1,#t do print(formatters["%-20s : [%s]"](t[i],numbermess(t[i]))) end
+
+statistics.register("asciimath",function()
+ if trace_digits then
+ local n = table.count(collected_digits)
+ if n > 0 then
+ table.save(collected_filename,collected_digits)
+ return string.format("%s digit conversions saved in %s",n,collected_filename)
+ else
+ os.remove(collected_filename)
+ end
+ end
+end)
+
+local p_number_base = patterns.cpnumber or patterns.cnumber or patterns.number
+local p_number = C(p_number_base)
+----- p_number = p_number_base
+local p_spaces = patterns.whitespace
+
+local p_utf_base = patterns.utf8character
+local p_utf = C(p_utf_base)
+-- local p_entity = (P("&") * C((1-P(";"))^2) * P(";"))/ entities
+
+-- entities["gt"] = ">"
+-- entities["lt"] = "<"
+-- entities["amp"] = "&"
+-- entities["dquot"] = '"'
+-- entities["quot"] = "'"
+
+local p_onechar = p_utf_base * P(-1)
+
+----- p_number = Cs((patterns.cpnumber or patterns.cnumber or patterns.number)/function(s) return (gsub(s,",","{,}")) end)
+
+local sign = P("-")^-1
+local digits = R("09")^1
+local integer = sign * digits
+local real = digits * (S(".") * digits)^-1
+local float = real * (P("E") * integer)^-1
+
+-- local number = C(float + integer)
+-- local p_number = C(float)
+local p_number = float / numbermess
+
+local k_reserved = sortedkeys(reserved)
+local k_commands = { }
+local k_unicode = { }
+
+asciimath.keys = {
+ reserved = k_reserved
+}
+
+local k_reserved_different = { }
+local k_reserved_words = { }
+
+for k, v in sortedhash(reserved) do
+ local replacement = v[2]
+ if v[1] then
+ k_unicode[k] = replacement
+ else
+ k_unicode[k] = k -- keep them ... later we remap these
+ if k ~= replacement then
+ k_reserved_different[#k_reserved_different+1] = k
+ end
+ end
+ if not find(k,"[^[a-zA-Z]+$]") then
+ k_unicode["\\"..k] = k -- dirty trick, no real unicode
+ end
+ if not find(k,"[^a-zA-Z]") then
+ k_reserved_words[#k_reserved_words+1] = k
+ end
+ k_commands[k] = replacement
+end
+
+local p_reserved =
+ lpeg.utfchartabletopattern(k_reserved_different) / k_commands
+
+local p_unicode =
+ lpeg.utfchartabletopattern(table.keys(k_unicode)) / k_unicode
+
+-- inspect(k_reserved_different)
+
+local p_texescape = patterns.texescape
+
+local function texescaped(s)
+ return lpegmatch(p_texescape,s)
+end
+
+local p_text =
+ P("text")
+ * p_spaces^0
+ * Cc("\\asciimathoptext")
+ * ( -- maybe balanced
+ Cs( P("{") * ((1-P("}"))^0/texescaped) * P("}") )
+ + Cs((P("(")/"{") * ((1-P(")"))^0/texescaped) * (P(")")/"}"))
+ )
+ + Cc("\\asciimathoptext") * Cs(Cc("{") * (patterns.undouble/texescaped) * Cc("}"))
+
+local m_left = {
+ ["(:"] = s_langle,
+ ["{:"] = s_left,
+ ["[:"] = s_left,
+ ["("] = s_lparent,
+ ["["] = s_lbracket,
+ ["{"] = s_lbrace,
+ ["⟨"] = s_langle,
+ ["⌈"] = s_lceil,
+ ["⌊"] = s_lfloor,
+
+ -- ["<<"] = s_langle, -- why not <:
+ -- ["|_"] = s_lfloor,
+ -- ["|~"] = s_lceil,
+ -- ["〈"] = s_langle,
+ -- ["〈"] = s_langle,
+
+ -- ["lparent"] = s_lparent,
+ -- ["lbracket"] = s_lbracket,
+ -- ["lbrace"] = s_lbrace,
+ -- ["langle"] = s_langle,
+ -- ["lfloor"] = s_lfloor,
+ -- ["lceil"] = s_lceil,
+}
+
+local m_right = {
+ [":)"] = s_rangle,
+ [":}"] = s_right,
+ [":]"] = s_right,
+ [")"] = s_rparent,
+ ["]"] = s_rbracket,
+ ["}"] = s_rbrace,
+ ["⟩"] = s_rangle,
+ ["⌉"] = s_rceil,
+ ["⌋"] = s_rfloor,
+
+ -- [">>"] = s_rangle, -- why not :>
+ -- ["~|"] = s_rceil,
+ -- ["_|"] = s_rfloor,
+ -- ["〉"] = s_rangle,
+ -- ["〉"] = s_rangle,
+
+ -- ["rparent"] = s_rparent,
+ -- ["rbracket"] = s_rbracket,
+ -- ["rbrace"] = s_rbrace,
+ -- ["rangle"] = s_rangle,
+ -- ["rfloor"] = s_rfloor,
+ -- ["rceil"] = s_rceil,
+}
+
+local islimits = {
+ ["\\sum"] = true,
+ -- ["∑"] = true,
+ ["\\prod"] = true,
+ -- ["∏"] = true,
+ ["\\lim"] = true,
+}
+
+local p_left =
+ lpeg.utfchartabletopattern(m_left) / m_left
+local p_right =
+ lpeg.utfchartabletopattern(m_right) / m_right
+
+-- 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("\\|")
+--
+-- faster bug also uglier:
+
+local p_special =
+ P("|") * Cc("\\|") -- s_mbar -- 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)
+ + C(R("az","AZ")^1)
+ )
+
+-- open | close :: {: | :}
+
+local u_parser = Cs ( (
+ patterns.doublequoted +
+ P("text") * p_spaces^0 * P("(") * (1-P(")"))^0 * P(")") + -- -- todo: balanced
+ p_unicode +
+ p_utf_base
)^0 )
-local parser
+local a_parser = Ct { "tokenizer",
+ tokenizer = (
+ p_spaces
+ + p_number
+ + p_text
+ -- + Ct(p_open * V("tokenizer") * p_close) -- {: (a+b,=,1),(a+b,=,7) :}
+ -- + Ct(p_open * V("tokenizer") * p_close_right) -- { (a+b,=,1),(a+b,=,7) :}
+ -- + Ct(p_open_left * V("tokenizer") * p_right) -- {: (a+b,=,1),(a+b,=,7) }
+ + Ct(p_left * V("tokenizer") * p_right) -- { (a+b,=,1),(a+b,=,7) }
+ + p_special
+ + p_reserved
+ -- + p_utf - p_close - p_right
+ + (p_utf - p_right)
+ )^1,
+}
-local function converted(original,totex)
- local ok, result
- if trace_mapping then
- report_asciimath("original : %s",original)
+local collapse = nil
+local serialize = table.serialize
+local f_state = formatters["level %s : %s : intermediate"]
+
+local function show_state(t,level,state)
+ report_asciimath(serialize(t,f_state(level,state)))
+end
+
+local function show_result(original,unicoded,texcoded)
+ report_asciimath("original > %s",original)
+ report_asciimath("unicoded > %s",unicoded)
+ report_asciimath("texcoded > %s",texcoded)
+end
+
+local function collapse_matrices(t)
+ 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
+ local omit = l1 == s_left and r1 == s_right
+ if omit then
+ t[1] = "\\startmatrix"
+ else
+ t[1] = l1 .. "\\startmatrix"
+ end
+ 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
+ if omit then
+ t[n] = "\\NR\\stopmatrix"
+ else
+ t[n] = "\\NR\\stopmatrix" .. r1
+ end
+ end
+ end
+ end
+ end
+ end
+ return t
+end
+
+local function collapse_bars(t)
+ local n, i, l, m = #t, 1, false, 0
+ while i <= n do
+ local current = t[i]
+ if current == "\\|" then
+ if l then
+ m = m + 1
+ t[l] = s_lbar
+ t[i] = s_rbar
+ t[m] = { unpack(t,l,i) }
+ l = false
+ else
+ l = i
+ end
+ elseif not l then
+ m = m + 1
+ t[m] = current
+ end
+ i = i + 1
end
- local premapped = lpegmatch(premapper,original)
- if premapped then
- if trace_mapping then
- report_asciimath("prepared : %s",premapped)
+ if l then
+ local tt = { s_lnothing } -- space fools final checker
+ local tm = 1
+ for i=1,m do
+ tm = tm + 1
+ tt[tm] = t[i]
end
- local parsed = lpegmatch(parser,premapped)
- if parsed then
- if trace_mapping then
- report_asciimath("parsed : %s",parsed)
+ tm = tm + 1
+ tt[tm] = s_mbar
+ for i=l+1,n do
+ tm = tm + 1
+ tt[tm] = t[i]
+ end
+ tm = tm + 1
+ tt[tm] = s_rnothing -- space fools final checker
+ m = tm
+ t = tt
+ elseif m < n then
+ for i=n,m+1,-1 do
+ t[i] = nil
+ end
+ end
+ return t
+end
+
+local function collapse_pairs(t)
+ local n, i = #t, 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]
+ local tn = t[i+2]
+ 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 tn == "^" then
+ -- brr 1/(1+x)^2
+ elseif 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" -- look sbad in (a,b)
+ i = i + 1
+ else
+ i = i + 1
+ end
+ end
+ return t
+end
+
+local function collapse_parentheses(t)
+ local n, i = #t, 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
+ remove(current,c)
+ remove(current,1)
+ end
+ i = i + 3
+ else
+ i = i + 1
+ end
+ end
+ end
+ return t
+end
+
+local function collapse_signs(t)
+ local n, m, i = #t, 0, 1
+ while i <= n do
+ m = m + 1
+ local current = t[i]
+ if isunary[current] then
+ local one = t[i+1]
+ if not one then
+-- m = m + 1
+ t[m] = current .. "{}" -- error
+return t
+-- break
+ end
+ if type(one) == "table" then
+ if isleft[one[1]] and isright[one[#one]] then
+ remove(one,#one)
+ remove(one,1)
+ 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 i + 2 <= n and isfunny[current] then
+ local one = t[i+1]
+ if isinfix[one] then
+ local two = t[i+2]
+ if two == "-" then -- or another sign ? or unary ?
+ local three = t[i+3]
+ if three then
+ if type(three) == "table" then
+ three = collapse(three,level)
+ end
+ t[m] = current .. one .. "{" .. two .. three .. "}"
+ i = i + 4
+ else
+ t[m] = current
+ i = i + 1
+ end
+ else
+ t[m] = current
+ i = i + 1
+ end
+ else
+ t[m] = current
+ i = i + 1
+ end
+ else
+ 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
+ return t
+end
+
+local function collapse_binaries(t)
+ local n, m, i = #t, 0, 1
+ 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
+return t
+-- break
+ end
+ if type(one) == "table" then
+ if isleft[one[1]] and isright[one[#one]] then
+ remove(one,#one)
+ remove(one,1)
+ end
+ one = collapse(one,level)
+ end
+ if not two then
+ t[m] = current .. "{" .. one .. "}{}"
+return t
+-- break
+ end
+ if type(two) == "table" then
+ if isleft[two[1]] and isright[two[#two]] then
+ remove(two,#two)
+ remove(two,1)
+ end
+ two = collapse(two,level)
+ end
+ t[m] = current .. "{" .. one .. "}{" .. two .. "}"
+ i = i + 3
+ else
+ 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
+ return t
+end
+
+local function collapse_infixes_1(t)
+ local n, i = #t, 1
+ while i <= n do
+ local current = t[i]
+ if isinfix[current] then
+ local what = t[i+1]
+ if what then
+ if type(what) == "table" then
+ local f, l = what[1], what[#what]
+ if isleft[f] and isright[l] then
+ remove(what,#what)
+ remove(what,1)
+ end
+ t[i+1] = collapse(what,level) -- collapse ?
+ end
+ i = i + 2
+ else
+ break
end
- local postmapped = lpegmatch(postmapper,parsed)
- if postmapped then
- if trace_mapping then
- report_asciimath("finalized: %s",postmapped)
+ else
+ i = i + 1
+ end
+ end
+ return t
+end
+
+function collapse_limits(t)
+ local n, m, i = #t, 0, 1
+ while i <= n do
+ m = m + 1
+ local current = t[i]
+ if islimits[current] then
+ local one, two, first, second = nil, nil, t[i+1], t[i+3]
+ if first and isinfix[first] then
+ one = t[i+2]
+ if one then
+ -- if type(one) == "table" then
+ -- if isleft[one[1]] and isright[one[#one]] then
+ -- remove(one,#one)
+ -- remove(one,1)
+ -- end
+ -- one = collapse(one,level)
+ -- end
+ if second and isinfix[second] then
+ two = t[i+4]
+ -- if type(two) == "table" then
+ -- if isleft[two[1]] and isright[two[#two]] then
+ -- remove(two,#two)
+ -- remove(two,1)
+ -- end
+ -- two = collapse(two,level)
+ -- end
+ end
+ if two then
+ t[m] = current .. "\\limits" .. first .. "{" .. one .. "}" .. second .. "{" .. two .. "}"
+ i = i + 5
+ else
+ t[m] = current .. "\\limits" .. first .. "{" .. one .. "}"
+ i = i + 3
+ end
+ else
+ t[m] = current
+ i = i + 1
end
- result, ok = postmapped, true
else
- result = "error in postmapping"
+ t[m] = current
+ i = i + 1
+ end
+ else
+ 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
+ return t
+end
+
+local function collapse_tables(t)
+ local n, m, i = #t, 0, 1
+ while i <= n do
+ m = m + 1
+ local current = t[i]
+ if 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
+ 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
+ return t
+end
+
+local function collapse_infixes_2(t)
+ local n, m, i = #t, 0, 1
+ while i < n do
+ local current = t[i]
+ if isinfix[current] and i > 1 then
+ local tl = t[i-1]
+ local tr = t[i+1]
+ local ti = t[i+2]
+ local tn = t[i+3]
+ if ti and tn and isinfix[ti] then
+ t[m] = tl .. current .. "{" .. tr .. "}" .. ti .. "{" .. tn .. "}"
+ i = i + 4
+ else
+ t[m] = tl .. current .. "{" .. tr .. "}"
+ i = i + 2
+ end
+ 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
+ return t
+end
+
+local function collapse_fractions_1(t)
+ local n, m, i = #t, 0, 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]
+ t[m] = "\\frac{" .. tl .. "}{" .. tr .. "}"
+ i = i + 2
+ if i < n then
+ m = m + 1
+ t[m] = t[i]
+ i = i + 1
end
else
- result = "error in mapping"
+ 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
+ return t
+end
+
+local function collapse_fractions_2(t)
+ local n, m, i = #t, 0, 1
+ while i < n do
+ local current = t[i]
+ if current == "⁄" and i > 1 then -- \slash
+ t[m] = "{" .. s_left .. t[i-1] .. s_mslash .. t[i+1] .. s_right .. "}"
+ i = i + 2
+ if i < n then
+ m = m + 1
+ t[m] = t[i]
+ i = i + 1
+ end
+ 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
+ return t
+end
+
+local function collapse_result(t)
+ local n = #t
+ if t[1] == s_left and t[n] == s_right then -- see bar .. space needed there
+ return concat(t," ",2,n-1)
else
- result = "error in premapping"
+ return concat(t," ")
end
- if totex then
- if ok then
- context.mathematics(result)
+end
+
+collapse = function(t,level)
+ -- check
+ if not t then
+ return ""
+ end
+ -- tracing
+ if trace_detail then
+ if level then
+ level = level + 1
else
- context.type(result) -- some day monospaced
+ level = 1
+ end
+ show_state(t,level,"parsed")
+ end
+ -- steps
+ t = collapse_matrices (t) if trace_detail then show_state(t,level,"matrices") end
+ t = collapse_bars (t) if trace_detail then show_state(t,level,"bars") end
+ t = collapse_pairs (t) if trace_detail then show_state(t,level,"pairs") end
+ t = collapse_parentheses(t) if trace_detail then show_state(t,level,"parentheses") end
+ t = collapse_signs (t) if trace_detail then show_state(t,level,"signs") end
+ t = collapse_binaries (t) if trace_detail then show_state(t,level,"binaries") end
+ t = collapse_infixes_1 (t) if trace_detail then show_state(t,level,"infixes (1)") end
+ t = collapse_limits (t) if trace_detail then show_state(t,level,"limits") end
+ t = collapse_tables (t) if trace_detail then show_state(t,level,"tables") end
+ t = collapse_infixes_2 (t) if trace_detail then show_state(t,level,"infixes (2)") end
+ t = collapse_fractions_1(t) if trace_detail then show_state(t,level,"fractions (1)") end
+ t = collapse_fractions_2(t) if trace_detail then show_state(t,level,"fractions (2)") end
+ -- done
+ return collapse_result(t)
+end
+
+-- todo: cache simple ones, say #str < 10, maybe weak
+
+local context = context
+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 unicoded = lpegmatch(u_parser,str) or str
+ local texcoded = collapse(lpegmatch(a_parser,unicoded))
+ if trace_mapping then
+ show_result(str,unicoded,texcoded)
+ end
+ if totex then
+ ctx_mathematics(texcoded)
+ else
+ return texcoded
+ end
+end
+
+local n = 0
+local p = (
+ (S("{[(") + P("\\left" )) / function() n = n + 1 end
+ + (S("}])") + P("\\right")) / function() n = n - 1 end
+ + p_utf_base
+)^0
+
+local function invalidtex(str)
+ n = 0
+ 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_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
+
+local function register(s,cleanedup,collected,shortname)
+ 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
- return result
- end
-end
-
-local function onlyconverted(str)
- local parsed = lpegmatch(parser,str)
- return parsed or str
-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 = P("(:") + P("{:") + P("(") + P("[") + P("{")
-local right = P(":)") + P(":}") + P(")") + P("]") + P("}")
-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 ")
-
-parser = Cs { "main",
-
- scripts = somescript * V("argument"),
- division = Cc("\\frac") * V("argument") * spaces * ignoreslash * spaces * V("argument"),
- double = doubles * spaces * V("argument") * spaces * V("argument"),
- single = singles * spaces * V("argument"),
-
- 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("single") + V("double"),
- main = (V("matrix") + V("step") + anychar)^0,
+ local texcoded = convert(s)
+ local message = invalidtex(texcoded)
+ if message then
+ report_asciimath("%s: %s : %s",message,s,texcoded)
+ end
+ collected[c] = {
+ count = 1,
+ files = { [shortname] = 1 },
+ texcoded = texcoded,
+ message = message,
+ cleanedup = s ~= c and 1 or 0,
+ dirty = { [s] = 1 }
+ }
+ end
+end
-}
+local function wrapup(collected,indexed)
+ local n = 0
+ for k, v in sortedhash(collected) do
+ n = n + 1
+ v.n= n
+ indexed[n] = k
+ end
+end
+function collect(fpattern,element,collected,indexed)
+ local element = element or "am"
+ local mpattern = formatters["<%s>(.-)</%s>"](element,element)
+ local filenames = resolvers.findtexfile(fpattern)
+ if filenames and filenames ~= "" then
+ filenames = { filenames }
+ else
+ filenames = dir.glob(fpattern)
+ end
+ local cfpattern = gsub(fpattern,"^%./",lfs.currentdir())
+ local cfpattern = gsub(cfpattern,"\\","/")
+ local wildcard = string.split(cfpattern,"*")[1]
+ if not collected then
+ collected = { }
+ indexed = { }
+ end
+ for i=1,#filenames do
+ filename = gsub(filenames[i],"\\","/")
+ local splitname = (wildcard and wildcard ~= "" and string.split(filename,wildcard)[2]) or filename
+ local shortname = gsub(splitname or file.basename(filename),"^%./","")
+ if shortname == "" then
+ shortname = filename
+ end
+ local fullname = resolvers.findtexfile(filename) or filename
+ if fullname ~= "" then
+ for s in gmatch(io.loaddata(fullname),mpattern) do
+ register(s,cleanedup,collected,shortname)
+ end
+ end
+ end
+ wrapup(collected,indexed)
+ return collected, indexed
+end
+
+function filter(root,pattern,collected,indexed)
+ if not pattern or pattern == "" then
+ pattern = "am"
+ end
+ if not collected then
+ collected = { }
+ indexed = { }
+ end
+ for c in xmlcollected(root,pattern) do
+ register(xmltext(c),cleanedup,collected,xmlinclusion(c) or "" )
+ end
+ wrapup(collected,indexed)
+ return collected, indexed
+end
+
+asciimath.convert = convert
asciimath.reserved = reserved
-asciimath.convert = converted
+asciimath.collect = collect
+asciimath.filter = filter
+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 uncrapped = {
+ ["%"] = "\\mathpercent",
+ ["&"] = "\\mathampersand",
+ ["#"] = "\\mathhash",
+ ["$"] = "\\mathdollar",
+ ["^"] = "\\Hat{\\enspace}", -- terrible hack ... tex really does it sbest to turn any ^ into a superscript
+ ["_"] = "\\underline{\\enspace}",
+}
+
+local function convert(str,nowrap)
+ if #str > 0 then
+ local unicoded = lpegmatch(u_parser,str) or str
+ if lpegmatch(p_onechar,unicoded) then
+ ctx_mathematics(uncrapped[unicoded] or unicoded)
+ else
+ local texcoded = collapse(lpegmatch(a_parser,unicoded))
+ if trace_mapping then
+ show_result(str,unicoded,texcoded)
+ end
+ if #texcoded == 0 then
+ report_asciimath("error in asciimath: %s",str)
+ else
+ local message = invalidtex(texcoded)
+ if message then
+ report_asciimath("%s: %s : %s",message,str,texcoded)
+ ctx_type(formatters["<%s>"](message))
+ elseif nowrap then
+ context(texcoded)
+ else
+ ctx_mathematics(texcoded)
+ end
+ end
+ end
+ end
+end
+
+
+local context = context
+
+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]]))
+-- report_asciimath(cleanedup([[//4]]))
+
+-- convert([[\^{1/5}log]])
+-- convert("sqrt")
+-- convert("^")
+
+-- convert("\\frac{a}{b}")
+-- convert("frac{a}{b}")
+-- convert("\\sin{a}{b}")
+-- convert("sin{a}{b}")
+-- convert("1: rightarrow")
+-- convert("2: \\rightarrow")
+
+-- convert("((1,2,3),(4,5,6),(7,8,9))")
+
+-- convert("1/(t+x)^2")
+
+-- convert("AA a > 0 ^^ b > 0 | {:log_g:} a + {:log_g:} b")
+-- convert("AA a &gt; 0 ^^ b > 0 | {:log_g:} a + {:log_g:} b")
+
+-- convert("10000,00001")
+-- convert("4/18*100text(%)~~22,2")
+-- convert("4/18*100text(%)≈22,2")
+-- convert("62541/(197,6)≈316,05")
+
+-- convert([[sum x]])
+-- convert([[sum^(1)_(2) x]])
+-- convert([[lim_(1)^(2) x]])
+-- convert([[lim_(1) x]])
+-- convert([[lim^(2) x]])
+
+-- convert([[{: rangle]])
+-- convert([[\langle\larr]])
+-- convert([[langlelarr]])
+-- convert([[D_f=[0 ,→〉]])
+-- 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([[//4]])
+-- convert([[ {(a+b,=,1),(a+b,=,7)) ]])
+
+-- convert([[ 2/a // 5/b = (2 b) / ( a b) // ( 5 a ) / ( a b ) = (2 b ) / ( 5 a ) ]])
+-- convert([[ (2+x)/a // 5/b ]])
+
+-- convert([[ ( 2/a ) // ( 5/b ) = ( (2 b) / ( a b) ) // ( ( 5 a ) / ( a b ) ) = (2 b ) / ( 5 a ) ]])
+
+-- convert([[ (x/y)^3 = x^3/y^3 ]])
+
+-- convert([[ {: (1,2) :} ]])
+-- convert([[ {: (a+b,=,1),(a+b,=,7) :} ]])
+-- convert([[ { (a+b,=,1),(a+b,=,7) :} ]])
+-- convert([[ {: (a+b,=,1),(a+b,=,7) } ]])
+-- convert([[ { (a+b,=,1),(a+b,=,7) } ]])
+
+-- 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)&gt;2 x^2 ]])
+-- convert([[ x^4&gt;x ]])
+
+ return
+
+end
+
+interfaces.implement {
+ name = "asciimath",
+ actions = convert,
+ arguments = "string"
+}
+
+interfaces.implement {
+ name = "justasciimath",
+ actions = convert,
+ arguments = { "string", true },
+}
+
+local ctx_typebuffer = context.typebuffer
+local ctx_mathematics = context.mathematics
+local ctx_color = context.color
+
+local sequenced = table.sequenced
+local assign_buffer = buffers.assign
+
+local show = { }
+asciimath.show = show
+
+local collected, indexed, ignored = { }, { }, { }
+
+local color = { "darkred" }
+
+function 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 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 = { }
+local am = { "am" }
+
+function 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 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 show.files(n)
+ context(sequenced(collected[indexed[n]].files," "))
+end
+
+function show.input(n,wrapped)
+ if wrapped then
+ assign_buffer("am",'"' .. indexed[n] .. '"')
+ else
+ assign_buffer("am",indexed[n])
+ end
+ ctx_typebuffer(am)
+end
+
+function 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.texcoded)
+ end
+end
+
+function 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 show.filter(id,element)
+ collected, indexed, ignored = { }, { }, { }
+ asciimath.filter(lxml.getid(id),element or "am",collected,indexed)
+end
+
+function show.max()
+ context(#indexed)
+end
+
+function 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
+ local NC = context.NC
+ local NR = context.NR
+ local EQ = context.EQ
+ context.starttabulate { "|B||" }
+ NC() context("files") EQ() context(noffiles) NC() NR()
+ NC() context("formulas") EQ() context(nofokay+nofbad) NC() NR()
+ NC() context("uniques") EQ() context(#indexed) NC() NR()
+ NC() context("cleanedup") EQ() context(nofcleanedup) NC() NR()
+ NC() context("errors") EQ() context(nofbad) NC() NR()
+ context.stoptabulate()
+end
+
+function show.save(name)
+ table.save(name ~= "" and name or "dummy.lua",collected)
+end