1if not modules then modules = { } end modules ['x-asciimath'] = {
2 version = 1.001,
3 comment = "companion to x-asciimath.mkiv",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files"
7}
8
9
10
11
12
13
14
15
16
17
18
19
20
21local trace_mapping = false if trackers then trackers.register("modules.asciimath.mapping", function(v) trace_mapping = v end) end
22local trace_details = false if trackers then trackers.register("modules.asciimath.details", function(v) trace_details = v end) end
23local trace_digits = false if trackers then trackers.register("modules.asciimath.digits", function(v) trace_digits = v end) end
24
25local report_asciimath = logs.reporter("mathematics","asciimath")
26
27local asciimath = asciimath or { }
28local moduledata = moduledata or { }
29moduledata.asciimath = asciimath
30
31if not characters then
32 require("char-def")
33 require("char-ini")
34 require("char-ent")
35end
36
37local next, type = next, type
38local concat, insert, remove = table.concat, table.insert, table.remove
39local rep, gmatch, gsub, find = string.rep, string.gmatch, string.gsub, string.find
40local utfchar, utfbyte = utf.char, utf.byte
41
42local lpegmatch, patterns = lpeg.match, lpeg.patterns
43local 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
44
45local sortedhash = table.sortedhash
46local sortedkeys = table.sortedkeys
47local formatters = string.formatters
48
49local entities = characters.entities or { }
50
51local xmltext = xml.text
52local xmlpure = xml.pure
53local xmlinclusion = xml.inclusion
54local xmlcollected = xml.collected
55
56local lxmlgetid = lxml.getid
57
58
59
60local s_lparent = "\\left\\lparent"
61local s_lbrace = "\\left\\lbrace"
62local s_lbracket = "\\left\\lbracket"
63local s_langle = "\\left\\langle"
64local s_lfloor = "\\left\\lfloor"
65local s_lceil = "\\left\\lceil"
66local s_left = "\\left."
67
68local s_rparent = "\\right\\rparent"
69local s_rbrace = "\\right\\rbrace"
70local s_rbracket = "\\right\\rbracket"
71local s_rangle = "\\right\\rangle"
72local s_rfloor = "\\right\\rfloor"
73local s_rceil = "\\right\\rceil"
74local s_right = "\\right."
75
76
77
78local s_lbar = "\\left\\|"
79local s_mbar = "\\middle\\|"
80local s_rbar = "\\right\\|"
81
82local s_lnothing = "\\left ."
83local s_rnothing = "\\right ."
84
85local reserved = {
86
87 ["prod"] = { false, "\\prod" },
88 ["sinh"] = { false, "\\sinh" },
89 ["cosh"] = { false, "\\cosh" },
90 ["tanh"] = { false, "\\tanh" },
91 ["sum"] = { false, "\\sum" },
92 ["int"] = { false, "\\int" },
93 ["sin"] = { false, "\\sin" },
94 ["cos"] = { false, "\\cos" },
95 ["tan"] = { false, "\\tan" },
96 ["csc"] = { false, "\\csc" },
97 ["sec"] = { false, "\\sec" },
98 ["cot"] = { false, "\\cot" },
99 ["log"] = { false, "\\log" },
100 ["det"] = { false, "\\det" },
101 ["lim"] = { false, "\\lim" },
102 ["mod"] = { false, "\\mod" },
103 ["gcd"] = { false, "\\gcd" },
104 ["min"] = { false, "\\min" },
105 ["max"] = { false, "\\max" },
106 ["ln"] = { false, "\\ln" },
107
108
109
110
111
112 ["arctan"] = { false, "\\arctan" },
113 ["arccos"] = { false, "\\arccos" },
114 ["arcsin"] = { false, "\\arcsin" },
115
116 ["arctanh"] = { false, "\\arctanh" },
117 ["arccosh"] = { false, "\\arccosh" },
118 ["arcsinh"] = { false, "\\arcsinh" },
119
120 ["and"] = { false, "\\text{and}" },
121 ["or"] = { false, "\\text{or}" },
122 ["if"] = { false, "\\text{if}" },
123
124 ["sqrt"] = { false, "\\asciimathsqrt", "unary" },
125 ["root"] = { false, "\\asciimathroot", "binary" },
126
127 ["frac"] = { false, "\\frac", "binary" },
128 ["stackrel"] = { false, "\\asciimathstackrel", "binary" },
129 ["hat"] = { false, "\\widehat", "unary" },
130 ["bar"] = { false, "\\overline", "unary" },
131 ["overbar"] = { false, "\\overline", "unary" },
132 ["overline"] = { false, "\\overline", "unary" },
133 ["underline"] = { false, "\\underline", "unary" },
134 ["overbrace"] = { false, "\\overbrace", "unary" },
135 ["underbrace"]= { false, "\\underbrace", "unary" },
136 ["overset"] = { false, "\\overset", "unary" },
137 ["underset"] = { false, "\\underset", "unary" },
138 ["obrace"] = { false, "\\overbrace", "unary" },
139 ["ubrace"] = { false, "\\underbrace", "unary" },
140 ["ul"] = { false, "\\underline", "unary" },
141 ["vec"] = { false, "\\overrightarrow", "unary" },
142 ["dot"] = { false, "\\dot", "unary" },
143 ["ddot"] = { false, "\\ddot", "unary" },
144
145
146
147 ["+"] = { true, "+" },
148 ["-"] = { true, "-" },
149 ["*"] = { true, "⋅" },
150 ["**"] = { true, "⋆" },
151 ["////"] = { true, "⁄⁄" },
152 ["//"] = { true, "⁄" },
153 ["\\"] = { true, "\\" },
154 ["xx"] = { true, "×" },
155 ["times"] = { true, "×" },
156 ["-:"] = { true, "÷" },
157 ["@"] = { true, "∘" },
158 ["circ"] = { true, "∘" },
159 ["o+"] = { true, "⊕" },
160 ["ox"] = { true, "⊗" },
161 ["o."] = { true, "⊙" },
162 ["^^"] = { true, "∧" },
163 ["vv"] = { true, "∨" },
164 ["nn"] = { true, "∩" },
165 ["uu"] = { true, "∪" },
166
167
168
169 ["^^^"] = { true, "⋀" },
170 ["vvv"] = { true, "⋁" },
171 ["nnn"] = { true, "⋂" },
172 ["uuu"] = { true, "⋃" },
173 ["int"] = { true, "∫" },
174 ["oint"] = { true, "∮" },
175
176
177
178 ["("] = { true, "(" },
179 [")"] = { true, ")" },
180 ["["] = { true, "[" },
181 ["]"] = { true, "]" },
182 ["{"] = { true, "{" },
183 ["}"] = { true, "}" },
184
185
186
187 ["="] = { true, "=" },
188 ["eq"] = { true, "=" },
189 ["!="] = { true, "≠" },
190 ["ne"] = { true, "≠" },
191 ["neq"] = { true, "≠" },
192 ["<"] = { true, "<" },
193 ["lt"] = { true, "<" },
194 [">"] = { true, ">" },
195 ["gt"] = { true, ">" },
196 ["<="] = { true, "≤" },
197 ["le"] = { true, "≤" },
198 ["leq"] = { true, "≤" },
199 [">="] = { true, "≥" },
200 ["ge"] = { true, "≥" },
201 ["geq"] = { true, "≥" },
202 ["-<"] = { true, "≺" },
203 [">-"] = { true, "≻" },
204 ["in"] = { true, "∈" },
205 ["!in"] = { true, "∉" },
206 ["sub"] = { true, "⊂" },
207 ["sup"] = { true, "⊃" },
208 ["sube"] = { true, "⊆" },
209 ["supe"] = { true, "⊇" },
210 ["-="] = { true, "≡" },
211 ["~="] = { true, "≅" },
212 ["~~"] = { true, "≈" },
213 ["prop"] = { true, "∝" },
214
215
216
217 ["rarr"] = { true, "→" },
218 ["->"] = { true, "→" },
219 ["larr"] = { true, "←" },
220 ["harr"] = { true, "↔" },
221 ["uarr"] = { true, "↑" },
222 ["darr"] = { true, "↓" },
223 ["rArr"] = { true, "⇒" },
224 ["lArr"] = { true, "⇐" },
225 ["hArr"] = { true, "⇔" },
226 ["|->"] = { true, "↦" },
227
228
229
230 ["not"] = { true, "¬" },
231 ["=>"] = { true, "⇒" },
232 ["iff"] = { true, "⇔" },
233 ["AA"] = { true, "∀" },
234 ["EE"] = { true, "∃" },
235 ["_|_"] = { true, "⊥" },
236 ["TT"] = { true, "⊤" },
237 ["|--"] = { true, "⊢" },
238 ["|=="] = { true, "⊨" },
239
240
241
242 ["del"] = { true, "∂" },
243 ["grad"] = { true, "∇" },
244 ["+-"] = { true, "±" },
245 ["O/"] = { true, "∅" },
246 ["oo"] = { true, "∞" },
247 ["aleph"] = { true, "ℵ" },
248 ["angle"] = { true, "∠" },
249 ["/_"] = { true, "∠" },
250 [":."] = { true, "∴" },
251 ["..."] = { true, "..." },
252 ["ldots"] = { true, "..." },
253 ["cdots"] = { true, "⋯" },
254 ["vdots"] = { true, "⋮" },
255 ["ddots"] = { true, "⋱" },
256 ["diamond"] = { true, "⋄" },
257 ["square"] = { true, "□" },
258 ["|__"] = { true, "⌊" },
259 ["__|"] = { true, "⌋" },
260 ["|~"] = { true, "⌈" },
261 ["~|"] = { true, "⌉" },
262
263
264
265 ["_="] = { true, "≡" },
266
267
268
269 ["prime"] = { true, "′" },
270 ["'"] = { true, "′" },
271 ["''"] = { true, "″" },
272 ["'''"] = { true, "‴" },
273
274
275
276 ["%"] = { false, "\\mathpercent" },
277 ["&"] = { false, "\\mathampersand" },
278 ["#"] = { false, "\\mathhash" },
279 ["$"] = { false, "\\mathdollar" },
280
281
282
283 ["CC"] = { true, "ℂ" },
284 ["NN"] = { true, "ℕ" },
285 ["QQ"] = { true, "ℚ" },
286 ["RR"] = { true, "ℝ" },
287 ["ZZ"] = { true, "ℤ" },
288
289
290
291 ["alpha"] = { true, "α" },
292 ["beta"] = { true, "β" },
293 ["gamma"] = { true, "γ" },
294 ["delta"] = { true, "δ" },
295 ["epsilon"] = { true, "ε" },
296 ["varepsilon"] = { true, "ɛ" },
297 ["zeta"] = { true, "ζ" },
298 ["eta"] = { true, "η" },
299 ["theta"] = { true, "θ" },
300 ["vartheta"] = { true, "ϑ" },
301 ["iota"] = { true, "ι" },
302 ["kappa"] = { true, "κ" },
303 ["lambda"] = { true, "λ" },
304 ["mu"] = { true, "μ" },
305 ["nu"] = { true, "ν" },
306 ["xi"] = { true, "ξ" },
307 ["pi"] = { true, "π" },
308 ["rho"] = { true, "ρ" },
309 ["sigma"] = { true, "σ" },
310 ["tau"] = { true, "τ" },
311 ["upsilon"] = { true, "υ" },
312 ["phi"] = { true, "ϕ" },
313 ["varphi"] = { true, "φ" },
314 ["chi"] = { true, "χ" },
315 ["psi"] = { true, "ψ" },
316 ["omega"] = { true, "ω" },
317
318
319
320 ["Gamma"] = { true, "Γ" },
321 ["Delta"] = { true, "Δ" },
322 ["Theta"] = { true, "Θ" },
323 ["Lambda"] = { true, "Λ" },
324 ["Xi"] = { true, "Ξ" },
325 ["Pi"] = { true, "Π" },
326 ["Sigma"] = { true, "Σ" },
327 ["Phi"] = { true, "Φ" },
328 ["Psi"] = { true, "Ψ" },
329 ["Omega"] = { true, "Ω" },
330
331
332
333 ["bbb a"] = { true, "𝕒" },
334 ["bbb b"] = { true, "𝕓" },
335 ["bbb c"] = { true, "𝕔" },
336 ["bbb d"] = { true, "𝕕" },
337 ["bbb e"] = { true, "𝕖" },
338 ["bbb f"] = { true, "𝕗" },
339 ["bbb g"] = { true, "𝕘" },
340 ["bbb h"] = { true, "𝕙" },
341 ["bbb i"] = { true, "𝕚" },
342 ["bbb j"] = { true, "𝕛" },
343 ["bbb k"] = { true, "𝕜" },
344 ["bbb l"] = { true, "𝕝" },
345 ["bbb m"] = { true, "𝕞" },
346 ["bbb n"] = { true, "𝕟" },
347 ["bbb o"] = { true, "𝕠" },
348 ["bbb p"] = { true, "𝕡" },
349 ["bbb q"] = { true, "𝕢" },
350 ["bbb r"] = { true, "𝕣" },
351 ["bbb s"] = { true, "𝕤" },
352 ["bbb t"] = { true, "𝕥" },
353 ["bbb u"] = { true, "𝕦" },
354 ["bbb v"] = { true, "𝕧" },
355 ["bbb w"] = { true, "𝕨" },
356 ["bbb x"] = { true, "𝕩" },
357 ["bbb y"] = { true, "𝕪" },
358 ["bbb z"] = { true, "𝕫" },
359
360 ["bbb A"] = { true, "𝔸" },
361 ["bbb B"] = { true, "𝔹" },
362 ["bbb C"] = { true, "ℂ" },
363 ["bbb D"] = { true, "𝔻" },
364 ["bbb E"] = { true, "𝔼" },
365 ["bbb F"] = { true, "𝔽" },
366 ["bbb G"] = { true, "𝔾" },
367 ["bbb H"] = { true, "ℍ" },
368 ["bbb I"] = { true, "𝕀" },
369 ["bbb J"] = { true, "𝕁" },
370 ["bbb K"] = { true, "𝕂" },
371 ["bbb L"] = { true, "𝕃" },
372 ["bbb M"] = { true, "𝕄" },
373 ["bbb N"] = { true, "ℕ" },
374 ["bbb O"] = { true, "𝕆" },
375 ["bbb P"] = { true, "ℙ" },
376 ["bbb Q"] = { true, "ℚ" },
377 ["bbb R"] = { true, "ℝ" },
378 ["bbb S"] = { true, "𝕊" },
379 ["bbb T"] = { true, "𝕋" },
380 ["bbb U"] = { true, "𝕌" },
381 ["bbb V"] = { true, "𝕍" },
382 ["bbb W"] = { true, "𝕎" },
383 ["bbb X"] = { true, "𝕏" },
384 ["bbb Y"] = { true, "𝕐" },
385 ["bbb Z"] = { true, "ℤ" },
386
387
388
389 ["fr a"] = { true, "𝔞" },
390 ["fr b"] = { true, "𝔟" },
391 ["fr c"] = { true, "𝔠" },
392 ["fr d"] = { true, "𝔡" },
393 ["fr e"] = { true, "𝔢" },
394 ["fr f"] = { true, "𝔣" },
395 ["fr g"] = { true, "𝔤" },
396 ["fr h"] = { true, "𝔥" },
397 ["fr i"] = { true, "𝔦" },
398 ["fr j"] = { true, "𝔧" },
399 ["fr k"] = { true, "𝔨" },
400 ["fr l"] = { true, "𝔩" },
401 ["fr m"] = { true, "𝔪" },
402 ["fr n"] = { true, "𝔫" },
403 ["fr o"] = { true, "𝔬" },
404 ["fr p"] = { true, "𝔭" },
405 ["fr q"] = { true, "𝔮" },
406 ["fr r"] = { true, "𝔯" },
407 ["fr s"] = { true, "𝔰" },
408 ["fr t"] = { true, "𝔱" },
409 ["fr u"] = { true, "𝔲" },
410 ["fr v"] = { true, "𝔳" },
411 ["fr w"] = { true, "𝔴" },
412 ["fr x"] = { true, "𝔵" },
413 ["fr y"] = { true, "𝔶" },
414 ["fr z"] = { true, "𝔷" },
415
416 ["fr A"] = { true, "𝔄" },
417 ["fr B"] = { true, "𝔅" },
418 ["fr C"] = { true, "ℭ" },
419 ["fr D"] = { true, "𝔇" },
420 ["fr E"] = { true, "𝔈" },
421 ["fr F"] = { true, "𝔉" },
422 ["fr G"] = { true, "𝔊" },
423 ["fr H"] = { true, "ℌ" },
424 ["fr I"] = { true, "ℑ" },
425 ["fr J"] = { true, "𝔍" },
426 ["fr K"] = { true, "𝔎" },
427 ["fr L"] = { true, "𝔏" },
428 ["fr M"] = { true, "𝔐" },
429 ["fr N"] = { true, "𝔑" },
430 ["fr O"] = { true, "𝔒" },
431 ["fr P"] = { true, "𝔓" },
432 ["fr Q"] = { true, "𝔔" },
433 ["fr R"] = { true, "ℜ" },
434 ["fr S"] = { true, "𝔖" },
435 ["fr T"] = { true, "𝔗" },
436 ["fr U"] = { true, "𝔘" },
437 ["fr V"] = { true, "𝔙" },
438 ["fr W"] = { true, "𝔚" },
439 ["fr X"] = { true, "𝔛" },
440 ["fr Y"] = { true, "𝔜" },
441 ["fr Z"] = { true, "ℨ" },
442
443
444
445 ["cc a"] = { true, "𝒶" },
446 ["cc b"] = { true, "𝒷" },
447 ["cc c"] = { true, "𝒸" },
448 ["cc d"] = { true, "𝒹" },
449 ["cc e"] = { true, "ℯ" },
450 ["cc f"] = { true, "𝒻" },
451 ["cc g"] = { true, "ℊ" },
452 ["cc h"] = { true, "𝒽" },
453 ["cc i"] = { true, "𝒾" },
454 ["cc j"] = { true, "𝒿" },
455 ["cc k"] = { true, "𝓀" },
456 ["cc l"] = { true, "𝓁" },
457 ["cc m"] = { true, "𝓂" },
458 ["cc n"] = { true, "𝓃" },
459 ["cc o"] = { true, "ℴ" },
460 ["cc p"] = { true, "𝓅" },
461 ["cc q"] = { true, "𝓆" },
462 ["cc r"] = { true, "𝓇" },
463 ["cc s"] = { true, "𝓈" },
464 ["cc t"] = { true, "𝓉" },
465 ["cc u"] = { true, "𝓊" },
466 ["cc v"] = { true, "𝓋" },
467 ["cc w"] = { true, "𝓌" },
468 ["cc x"] = { true, "𝓍" },
469 ["cc y"] = { true, "𝓎" },
470 ["cc z"] = { true, "𝓏" },
471
472 ["cc A"] = { true, "𝒜" },
473 ["cc B"] = { true, "ℬ" },
474 ["cc C"] = { true, "𝒞" },
475 ["cc D"] = { true, "𝒟" },
476 ["cc E"] = { true, "ℰ" },
477 ["cc F"] = { true, "ℱ" },
478 ["cc G"] = { true, "𝒢" },
479 ["cc H"] = { true, "ℋ" },
480 ["cc I"] = { true, "ℐ" },
481 ["cc J"] = { true, "𝒥" },
482 ["cc K"] = { true, "𝒦" },
483 ["cc L"] = { true, "ℒ" },
484 ["cc M"] = { true, "ℳ" },
485 ["cc N"] = { true, "𝒩" },
486 ["cc O"] = { true, "𝒪" },
487 ["cc P"] = { true, "𝒫" },
488 ["cc Q"] = { true, "𝒬" },
489 ["cc R"] = { true, "ℛ" },
490 ["cc S"] = { true, "𝒮" },
491 ["cc T"] = { true, "𝒯" },
492 ["cc U"] = { true, "𝒰" },
493 ["cc V"] = { true, "𝒱" },
494 ["cc W"] = { true, "𝒲" },
495 ["cc X"] = { true, "𝒳" },
496 ["cc Y"] = { true, "𝒴" },
497 ["cc Z"] = { true, "𝒵" },
498
499
500
501 ["bb a"] = { true, "𝒂" },
502 ["bb b"] = { true, "𝒃" },
503 ["bb c"] = { true, "𝒄" },
504 ["bb d"] = { true, "𝒅" },
505 ["bb e"] = { true, "𝒆" },
506 ["bb f"] = { true, "𝒇" },
507 ["bb g"] = { true, "𝒈" },
508 ["bb h"] = { true, "𝒉" },
509 ["bb i"] = { true, "𝒊" },
510 ["bb j"] = { true, "𝒋" },
511 ["bb k"] = { true, "𝒌" },
512 ["bb l"] = { true, "𝒍" },
513 ["bb m"] = { true, "𝒎" },
514 ["bb n"] = { true, "𝒏" },
515 ["bb o"] = { true, "𝒐" },
516 ["bb p"] = { true, "𝒑" },
517 ["bb q"] = { true, "𝒒" },
518 ["bb r"] = { true, "𝒓" },
519 ["bb s"] = { true, "𝒔" },
520 ["bb t"] = { true, "𝒕" },
521 ["bb u"] = { true, "𝒖" },
522 ["bb v"] = { true, "𝒗" },
523 ["bb w"] = { true, "𝒘" },
524 ["bb x"] = { true, "𝒙" },
525 ["bb y"] = { true, "𝒚" },
526 ["bb z"] = { true, "𝒛" },
527
528 ["bb A"] = { true, "𝑨" },
529 ["bb B"] = { true, "𝑩" },
530 ["bb C"] = { true, "𝑪" },
531 ["bb D"] = { true, "𝑫" },
532 ["bb E"] = { true, "𝑬" },
533 ["bb F"] = { true, "𝑭" },
534 ["bb G"] = { true, "𝑮" },
535 ["bb H"] = { true, "𝑯" },
536 ["bb I"] = { true, "𝑰" },
537 ["bb J"] = { true, "𝑱" },
538 ["bb K"] = { true, "𝑲" },
539 ["bb L"] = { true, "𝑳" },
540 ["bb M"] = { true, "𝑴" },
541 ["bb N"] = { true, "𝑵" },
542 ["bb O"] = { true, "𝑶" },
543 ["bb P"] = { true, "𝑷" },
544 ["bb Q"] = { true, "𝑸" },
545 ["bb R"] = { true, "𝑹" },
546 ["bb S"] = { true, "𝑺" },
547 ["bb T"] = { true, "𝑻" },
548 ["bb U"] = { true, "𝑼" },
549 ["bb V"] = { true, "𝑽" },
550 ["bb W"] = { true, "𝑾" },
551 ["bb X"] = { true, "𝑿" },
552 ["bb Y"] = { true, "𝒀" },
553 ["bb Z"] = { true, "𝒁" },
554
555
556
557 ["sf a"] = { true, "𝖺" },
558 ["sf b"] = { true, "𝖻" },
559 ["sf c"] = { true, "𝖼" },
560 ["sf d"] = { true, "𝖽" },
561 ["sf e"] = { true, "𝖾" },
562 ["sf f"] = { true, "𝖿" },
563 ["sf g"] = { true, "𝗀" },
564 ["sf h"] = { true, "𝗁" },
565 ["sf i"] = { true, "𝗂" },
566 ["sf j"] = { true, "𝗃" },
567 ["sf k"] = { true, "𝗄" },
568 ["sf l"] = { true, "𝗅" },
569 ["sf m"] = { true, "𝗆" },
570 ["sf n"] = { true, "𝗇" },
571 ["sf o"] = { true, "𝗈" },
572 ["sf p"] = { true, "𝗉" },
573 ["sf q"] = { true, "𝗊" },
574 ["sf r"] = { true, "𝗋" },
575 ["sf s"] = { true, "𝗌" },
576 ["sf t"] = { true, "𝗍" },
577 ["sf u"] = { true, "𝗎" },
578 ["sf v"] = { true, "𝗏" },
579 ["sf w"] = { true, "𝗐" },
580 ["sf x"] = { true, "𝗑" },
581 ["sf y"] = { true, "𝗒" },
582 ["sf z"] = { true, "𝗓" },
583
584 ["sf A"] = { true, "𝖠" },
585 ["sf B"] = { true, "𝖡" },
586 ["sf C"] = { true, "𝖢" },
587 ["sf D"] = { true, "𝖣" },
588 ["sf E"] = { true, "𝖤" },
589 ["sf F"] = { true, "𝖥" },
590 ["sf G"] = { true, "𝖦" },
591 ["sf H"] = { true, "𝖧" },
592 ["sf I"] = { true, "𝖨" },
593 ["sf J"] = { true, "𝖩" },
594 ["sf K"] = { true, "𝖪" },
595 ["sf L"] = { true, "𝖫" },
596 ["sf M"] = { true, "𝖬" },
597 ["sf N"] = { true, "𝖭" },
598 ["sf O"] = { true, "𝖮" },
599 ["sf P"] = { true, "𝖯" },
600 ["sf Q"] = { true, "𝖰" },
601 ["sf R"] = { true, "𝖱" },
602 ["sf S"] = { true, "𝖲" },
603 ["sf T"] = { true, "𝖳" },
604 ["sf U"] = { true, "𝖴" },
605 ["sf V"] = { true, "𝖵" },
606 ["sf W"] = { true, "𝖶" },
607 ["sf X"] = { true, "𝖷" },
608 ["sf Y"] = { true, "𝖸" },
609 ["sf Z"] = { true, "𝖹" },
610
611
612
613 ["tt a"] = { true, "𝚊" },
614 ["tt b"] = { true, "𝚋" },
615 ["tt c"] = { true, "𝚌" },
616 ["tt d"] = { true, "𝚍" },
617 ["tt e"] = { true, "𝚎" },
618 ["tt f"] = { true, "𝚏" },
619 ["tt g"] = { true, "𝚐" },
620 ["tt h"] = { true, "𝚑" },
621 ["tt i"] = { true, "𝚒" },
622 ["tt j"] = { true, "𝚓" },
623 ["tt k"] = { true, "𝚔" },
624 ["tt l"] = { true, "𝚕" },
625 ["tt m"] = { true, "𝚖" },
626 ["tt n"] = { true, "𝚗" },
627 ["tt o"] = { true, "𝚘" },
628 ["tt p"] = { true, "𝚙" },
629 ["tt q"] = { true, "𝚚" },
630 ["tt r"] = { true, "𝚛" },
631 ["tt s"] = { true, "𝚜" },
632 ["tt t"] = { true, "𝚝" },
633 ["tt u"] = { true, "𝚞" },
634 ["tt v"] = { true, "𝚟" },
635 ["tt w"] = { true, "𝚠" },
636 ["tt x"] = { true, "𝚡" },
637 ["tt y"] = { true, "𝚢" },
638 ["tt z"] = { true, "𝚣" },
639
640 ["tt A"] = { true, "𝙰" },
641 ["tt B"] = { true, "𝙱" },
642 ["tt C"] = { true, "𝙲" },
643 ["tt D"] = { true, "𝙳" },
644 ["tt E"] = { true, "𝙴" },
645 ["tt F"] = { true, "𝙵" },
646 ["tt G"] = { true, "𝙶" },
647 ["tt H"] = { true, "𝙷" },
648 ["tt I"] = { true, "𝙸" },
649 ["tt J"] = { true, "𝙹" },
650 ["tt K"] = { true, "𝙺" },
651 ["tt L"] = { true, "𝙻" },
652 ["tt M"] = { true, "𝙼" },
653 ["tt N"] = { true, "𝙽" },
654 ["tt O"] = { true, "𝙾" },
655 ["tt P"] = { true, "𝙿" },
656 ["tt Q"] = { true, "𝚀" },
657 ["tt R"] = { true, "𝚁" },
658 ["tt S"] = { true, "𝚂" },
659 ["tt T"] = { true, "𝚃" },
660 ["tt U"] = { true, "𝚄" },
661 ["tt V"] = { true, "𝚅" },
662 ["tt W"] = { true, "𝚆" },
663 ["tt X"] = { true, "𝚇" },
664 ["tt Y"] = { true, "𝚈" },
665 ["tt Z"] = { true, "𝚉" },
666
667
668
669 ["dx"] = { false, { "d", "x" } },
670 ["dy"] = { false, { "d", "y" } },
671 ["dz"] = { false, { "d", "z" } },
672
673
674
675 ["(:"] = { true, "(:" },
676 ["{:"] = { true, "{:" },
677 ["[:"] = { true, "[:" },
678 ["("] = { true, "(" },
679 ["["] = { true, "[" },
680 ["{"] = { true, "{" },
681 ["<<"] = { true, "⟨" },
682 ["|_"] = { true, "⌊" },
683 ["|~"] = { true, "⌈" },
684 ["⟨"] = { true, "⟨" },
685 ["〈"] = { true, "⟨" },
686 ["〈"] = { true, "⟨" },
687
688 [":)"] = { true, ":)" },
689 [":}"] = { true, ":}" },
690 [":]"] = { true, ":]" },
691 [")"] = { true, ")" },
692 ["]"] = { true, "]" },
693 ["}"] = { true, "}" },
694 [">>"] = { true, "⟩" },
695 ["~|"] = { true, "⌉" },
696 ["_|"] = { true, "⌋" },
697 ["⟩"] = { true, "⟩" },
698 ["〉"] = { true, "⟩" },
699 ["〉"] = { true, "⟩" },
700
701 ["lparent"] = { true, "(" },
702 ["lbracket"] = { true, "[" },
703 ["lbrace"] = { true, "{" },
704 ["langle"] = { true, "⟨" },
705 ["lfloor"] = { true, "⌊" },
706 ["lceil"] = { true, "⌈" },
707
708 ["rparent"] = { true, ")" },
709 ["rbracket"] = { true, "]" },
710 ["rbrace"] = { true, "}" },
711 ["rangle"] = { true, "⟩" },
712 ["rfloor"] = { true, "⌋" },
713 ["rceil"] = { true, "⌉" },
714
715
716
717
718
719
720
721 [">"] = { true, ">" },
722 ["<"] = { true, "<" },
723
724
725
726
727
728 ["dd"] = { false, "{\\tf d}" },
729 ["ee"] = { false, "{\\tf e}" },
730 ["xxx"] = { true, utfchar(0x2063) },
731
732}
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751local extras = asciimath.extras
752if extras then
753 for k, v in next, extras do
754 if not reserved[k] then
755 reserved[k] = v
756 end
757 end
758end
759
760
761
762
763for k, v in next, characters.data do
764 local name = v.mathname
765 if name and not reserved[name] then
766 local char = { true, utfchar(k) }
767 reserved[ name] = char
768
769 end
770
771
772
773
774
775
776
777
778
779end
780
781reserved.P = nil
782reserved.S = nil
783
784
785local isbinary = {
786 ["\\frac"] = true,
787 ["\\root"] = true,
788 ["\\asciimathroot"] = true,
789 ["\\asciimathstackrel"] = true,
790 ["\\overset"] = true,
791 ["\\underset"] = true,
792}
793
794local isunary = {
795 ["\\sqrt"] = true,
796 ["\\asciimathsqrt"] = true,
797 ["\\text"] = true,
798 ["\\mathoptext"] = true,
799 ["\\asciimathoptext"] = true,
800 ["\\hat"] = true,
801 ["\\widehat"] = true,
802 ["\\bar"] = true,
803 ["\\overbar"] = true,
804 ["\\overline"] = true,
805 ["\\underline"] = true,
806 ["\\vec"] = true,
807 ["\\overrightarrow"] = true,
808 ["\\dot"] = true,
809 ["\\ddot"] = true,
810
811 ["\\overbrace"] = true,
812 ["\\underbrace"] = true,
813 ["\\obrace"] = true,
814 ["\\ubrace"] = true,
815}
816
817local isfunny = {
818 ["\\sin"] = true,
819}
820
821local isinfix = {
822 ["^"] = true,
823 ["_"] = true,
824}
825
826local isstupid = {
827 ["\\prod"] = true,
828 ["\\sinh"] = true,
829 ["\\cosh"] = true,
830 ["\\tanh"] = true,
831 ["\\sum"] = true,
832 ["\\int"] = true,
833 ["\\sin"] = true,
834 ["\\cos"] = true,
835 ["\\tan"] = true,
836 ["\\csc"] = true,
837 ["\\sec"] = true,
838 ["\\cot"] = true,
839 ["\\log"] = true,
840 ["\\det"] = true,
841 ["\\lim"] = true,
842 ["\\mod"] = true,
843 ["\\gcd"] = true,
844 ["\\min"] = true,
845 ["\\max"] = true,
846 ["\\ln"] = true,
847
848
849
850
851
852 ["\\arctan"] = true,
853 ["\\arccos"] = true,
854 ["\\arcsin"] = true,
855
856 ["\\arctanh"] = true,
857 ["\\arccosh"] = true,
858 ["\\arcsinh"] = true,
859
860 ["f"] = true,
861 ["g"] = true,
862}
863
864local isleft = {
865 [s_lparent] = true,
866 [s_lbrace] = true,
867 [s_lbracket] = true,
868 [s_langle] = true,
869 [s_lfloor] = true,
870 [s_lceil] = true,
871 [s_left] = true,
872}
873
874local isright = {
875 [s_rparent] = true,
876 [s_rbrace] = true,
877 [s_rbracket] = true,
878 [s_rangle] = true,
879 [s_rfloor] = true,
880 [s_rceil] = true,
881 [s_right] = true,
882}
883
884local issimplified = {
885}
886
887
888
889
890
891
892local d_one = R("09")
893local d_two = d_one * d_one
894local d_three = d_two * d_one
895local d_four = d_three * d_one
896local d_split = P(-1) + Carg(2) * (S(".") /"")
897
898local d_spaced = (Carg(1) * d_three)^1
899
900local digitized_1 = Cs ( (
901 d_three * d_spaced * d_split +
902 d_two * d_spaced * d_split +
903 d_one * d_spaced * d_split +
904 P(1)
905 )^1 )
906
907local p_fourbefore = d_four * d_split
908local p_fourafter = d_four * P(-1)
909
910local p_beforecomma = d_three * d_spaced^0 * d_split
911 + d_two * d_spaced^0 * d_split
912 + d_one * d_spaced^0 * d_split
913 + d_one * d_split
914
915local p_aftercomma = p_fourafter
916 + d_three * d_spaced
917 + d_two * d_spaced
918 + d_one * d_spaced
919
920local digitized_2 = Cs (
921 p_fourbefore * (p_aftercomma^0) +
922 p_beforecomma * ((p_aftercomma + d_one^1)^0)
923 )
924
925local p_fourbefore = d_four * d_split
926local p_fourafter = d_four
927local d_spaced = (Carg(1) * (d_three + d_two + d_one))^1
928local p_aftercomma = p_fourafter * P(-1)
929 + d_three * d_spaced * P(1)^0
930 + d_one^1
931
932
933
934
935
936
937local digitized_3 = Cs((p_fourbefore + p_beforecomma) * p_aftercomma^0)
938
939local splitmethods = {
940 digitized_1,
941 digitized_2,
942 digitized_3,
943}
944
945local splitmethod = nil
946local symbolmethod = nil
947local digitseparator = utfchar(0x2008)
948local digitsymbol = "."
949
950local v_yes_digits = interfaces and interfaces.variables.yes or true
951
952function asciimath.setup(settings)
953 splitmethod = splitmethods[tonumber(settings.splitmethod) or 0]
954 if splitmethod then
955 digitsymbol = settings.symbol
956 if not digitsymbol or digitsymbol == "" then
957 digitsymbol = "."
958 end
959 local separator = settings.separator
960
961 if separator == true or separator == nil or separator == v_yes_digits then
962 digitseparator = utfchar(0x2008)
963 elseif type(separator) == "string" and separator ~= "" then
964 digitseparator = separator
965 else
966 splitmethod = nil
967 end
968 if digitsymbol ~= "." then
969 symbolmethod = lpeg.replacer(".",digitsymbol)
970 else
971 symbolmethod = nil
972 end
973 end
974end
975
976local collected_digits = { }
977local collected_filename = "asciimath-digits.lua"
978
979function numbermess(s)
980 if splitmethod then
981 local d = lpegmatch(splitmethod,s,1,digitseparator,digitsymbol)
982 if not d and symbolmethod then
983 d = lpegmatch(symbolmethod,s)
984 end
985 if d then
986 if trace_digits and s ~= d then
987 collected_digits[s] = d
988 end
989 return d
990 end
991 end
992 return s
993end
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024statistics.register("asciimath",function()
1025 if trace_digits then
1026 local n = table.count(collected_digits)
1027 if n > 0 then
1028 table.save(collected_filename,collected_digits)
1029 return string.format("%s digit conversions saved in %s",n,collected_filename)
1030 else
1031 os.remove(collected_filename)
1032 end
1033 end
1034end)
1035
1036local p_number_base = patterns.cpnumber or patterns.cnumber or patterns.number
1037local p_number = C(p_number_base)
1038
1039local p_spaces = patterns.whitespace
1040
1041local p_utf_base = patterns.utf8character
1042local p_utf = C(p_utf_base)
1043
1044
1045
1046
1047
1048
1049
1050
1051local p_onechar = p_utf_base * P(-1)
1052
1053
1054
1055local sign = P("-")^-1
1056local digits = R("09")^1
1057local integer = sign * digits
1058local real = digits * (S(".") * digits)^-1
1059local float = real * (P("E") * integer)^-1
1060
1061
1062
1063local p_number = float / numbermess
1064
1065local k_reserved = sortedkeys(reserved)
1066local k_commands = { }
1067local k_unicode = { }
1068
1069asciimath.keys = {
1070 reserved = k_reserved
1071}
1072
1073local k_reserved_different = { }
1074local k_reserved_words = { }
1075
1076for k, v in sortedhash(reserved) do
1077 local replacement = v[2]
1078 if v[1] then
1079 k_unicode[k] = replacement
1080 else
1081 k_unicode[k] = k
1082 if k ~= replacement then
1083 k_reserved_different[#k_reserved_different+1] = k
1084 end
1085 end
1086 if find(k,"^[a-zA-Z]+$") then
1087 k_unicode["\\"..k] = replacement
1088 else
1089 k_unicode["\\"..k] = k
1090 end
1091 if not find(k,"[^a-zA-Z]") then
1092 k_reserved_words[#k_reserved_words+1] = k
1093 end
1094 k_commands[k] = replacement
1095end
1096
1097local p_reserved =
1098 lpeg.utfchartabletopattern(k_reserved_different) / k_commands
1099
1100local p_unicode =
1101
1102 lpeg.utfchartabletopattern(k_unicode) / k_unicode
1103
1104local p_texescape = patterns.texescape
1105
1106local function texescaped(s)
1107 return lpegmatch(p_texescape,s) or s
1108end
1109
1110local p_text =
1111 P("text")
1112 * p_spaces^0
1113 * Cc("\\asciimathoptext")
1114 * (
1115 Cs( P("{") * ((1-P("}"))^0/texescaped) * P("}") )
1116 + Cs((P("(")/"{") * ((1-P(")"))^0/texescaped) * (P(")")/"}"))
1117 )
1118 + Cc("\\asciimathoptext") * Cs(Cc("{") * (C(patterns.undouble)/texescaped) * Cc("}"))
1119
1120local m_left = {
1121 ["(:"] = s_langle,
1122 ["{:"] = s_left,
1123 ["[:"] = s_left,
1124 ["("] = s_lparent,
1125 ["["] = s_lbracket,
1126 ["{"] = s_lbrace,
1127 ["⟨"] = s_langle,
1128 ["⌈"] = s_lceil,
1129 ["⌊"] = s_lfloor,
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143}
1144
1145local m_right = {
1146 [":)"] = s_rangle,
1147 [":}"] = s_right,
1148 [":]"] = s_right,
1149 [")"] = s_rparent,
1150 ["]"] = s_rbracket,
1151 ["}"] = s_rbrace,
1152 ["⟩"] = s_rangle,
1153 ["⌉"] = s_rceil,
1154 ["⌋"] = s_rfloor,
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168}
1169
1170local islimits = {
1171 ["\\sum"] = true,
1172
1173 ["\\prod"] = true,
1174
1175 ["\\lim"] = true,
1176}
1177
1178local p_left =
1179 lpeg.utfchartabletopattern(m_left) / m_left
1180local p_right =
1181 lpeg.utfchartabletopattern(m_right) / m_right
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195local p_special =
1196 P("|") * Cc("\\|")
1197 + P("\\") * (
1198 (
1199 P(" ") * (
1200 Cc("{}") * p_spaces^0 * C(S("^_"))
1201 + Cc("\\space")
1202 )
1203 )
1204 + P("\\") * Cc("\\backslash")
1205
1206 + C(R("az","AZ")^1)
1207 )
1208
1209
1210
1211local u_parser = Cs ( (
1212 patterns.doublequoted +
1213 P("text") * p_spaces^0 * P("(") * (1-P(")"))^0 * P(")") +
1214 P("\\frac") / "frac" +
1215 p_unicode +
1216 p_utf_base
1217)^0 )
1218
1219local a_parser = Ct { "tokenizer",
1220 tokenizer = (
1221 p_spaces
1222 + p_number
1223 + p_text
1224
1225
1226
1227 + Ct(p_left * V("tokenizer") * p_right)
1228 + p_special
1229 + p_reserved
1230
1231 + (p_utf - p_right)
1232 )^1,
1233}
1234
1235local collapse = nil
1236local serialize = table.serialize
1237local f_state = formatters["level %s : %s : intermediate"]
1238
1239local function show_state(t,level,state)
1240 report_asciimath(serialize(t,f_state(level,state)))
1241end
1242
1243local function show_result(original,unicoded,texcoded)
1244 report_asciimath("original > %s",original)
1245 report_asciimath("unicoded > %s",unicoded)
1246 report_asciimath("texcoded > %s",texcoded)
1247end
1248
1249local function collapse_matrices(t)
1250 local n = #t
1251 if n > 4 and t[3] == "," then
1252 local l1 = t[1]
1253 local r1 = t[n]
1254 if isleft[l1] and isright[r1] then
1255 local l2 = t[2]
1256 local r2 = t[n-1]
1257 if type(l2) == "table" and type(r2) == "table" then
1258
1259 local valid = true
1260 for i=3,n-2,2 do
1261 if t[i] ~= "," then
1262 valid = false
1263 break
1264 end
1265 end
1266 if valid then
1267 for i=2,n-1,2 do
1268 local ti = t[i]
1269 local tl = ti[1]
1270 local tr = ti[#ti]
1271 if isleft[tl] and isright[tr] then
1272
1273 else
1274 valid = false
1275 break
1276 end
1277 end
1278 if valid then
1279 local omit = l1 == s_left and r1 == s_right
1280 if omit then
1281 t[1] = "\\startmatrix"
1282 else
1283 t[1] = l1 .. "\\startmatrix"
1284 end
1285 for i=2,n-1 do
1286 if t[i] == "," then
1287 t[i] = "\\NR"
1288 else
1289 local ti = t[i]
1290 ti[1] = "\\NC"
1291 for i=2,#ti-1 do
1292 if ti[i] == "," then
1293 ti[i] = "\\NC"
1294 end
1295 end
1296 ti[#ti] = nil
1297 end
1298 end
1299 if omit then
1300 t[n] = "\\NR\\stopmatrix"
1301 else
1302 t[n] = "\\NR\\stopmatrix" .. r1
1303 end
1304 end
1305 end
1306 end
1307 end
1308 end
1309 return t
1310end
1311
1312local function collapse_bars(t)
1313 local n, i, l, m = #t, 1, false, 0
1314 while i <= n do
1315 local current = t[i]
1316 if current == "\\|" then
1317 if l then
1318 m = m + 1
1319 t[l] = s_lbar
1320 t[i] = s_rbar
1321 t[m] = { unpack(t,l,i) }
1322 l = false
1323 else
1324 l = i
1325 end
1326 elseif not l then
1327 m = m + 1
1328 t[m] = current
1329 end
1330 i = i + 1
1331 end
1332 if l then
1333
1334local d = false
1335for i=1,m do
1336 local ti = t[i]
1337 if type(ti) == "string" and find(ti,"\\left",1,true) then
1338 d = true
1339 break
1340 end
1341end
1342if not d then
1343 local tt = { s_lnothing }
1344 local tm = 1
1345 for i=1,m do
1346 tm = tm + 1
1347 tt[tm] = t[i]
1348 end
1349 tm = tm + 1
1350 tt[tm] = s_mbar
1351 for i=l+1,n do
1352 tm = tm + 1
1353 tt[tm] = t[i]
1354 end
1355 tm = tm + 1
1356 tt[tm] = s_rnothing
1357 m = tm
1358 t = tt
1359end
1360 elseif m < n then
1361 for i=n,m+1,-1 do
1362 t[i] = nil
1363 end
1364 end
1365 return t
1366end
1367
1368local function collapse_pairs(t)
1369 local n, i = #t, 1
1370 while i < n do
1371 local current = t[i]
1372 if current == "/" and i > 1 then
1373 local tl = t[i-1]
1374 local tr = t[i+1]
1375 local tn = t[i+2]
1376 if type(tl) == "table" then
1377 if isleft[tl[1]] and isright[tl[#tl]] then
1378 tl[1] = ""
1379 tl[#tl] = nil
1380 end
1381 end
1382 if type(tr) == "table" then
1383 if tn == "^" then
1384
1385 elseif isleft[tr[1]] and isright[tr[#tr]] then
1386 tr[1] = ""
1387 tr[#tr] = nil
1388 end
1389 end
1390 i = i + 2
1391 elseif current == "," or current == ";" then
1392
1393 i = i + 1
1394 else
1395 i = i + 1
1396 end
1397 end
1398 return t
1399end
1400
1401local function collapse_parentheses(t)
1402 local n, i = #t, 1
1403 if n > 2 then
1404 while i < n do
1405 local current = t[i]
1406 if type(current) == "table" and isleft[t[i-1]] and isright[t[i+1]] then
1407 local c = #current
1408 if c > 2 and isleft[current[1]] and isright[current[c]] then
1409 remove(current,c)
1410 remove(current,1)
1411 end
1412 i = i + 3
1413 else
1414 i = i + 1
1415 end
1416 end
1417 end
1418 return t
1419end
1420
1421local function collapse_stupids(t)
1422 local n, m, i = #t, 0, 1
1423 while i <= n do
1424 m = m + 1
1425 local current = t[i]
1426 if isstupid[current] then
1427 local one = t[i+1]
1428 if type(one) == "table" then
1429 one = collapse(one,level)
1430 t[m] = current .. "{" .. one .. "}"
1431
1432 i = i + 2
1433 else
1434 t[m] = current
1435 i = i + 1
1436 end
1437 else
1438 t[m] = current
1439 i = i + 1
1440 end
1441 end
1442 if i == n then
1443 m = m + 1
1444 t[m] = t[n]
1445 end
1446 if m < n then
1447 for i=n,m+1,-1 do
1448 t[i] = nil
1449 end
1450 end
1451 return t
1452end
1453
1454local function collapse_signs(t)
1455 local n, m, i = #t, 0, 1
1456 while i <= n do
1457 m = m + 1
1458 local current = t[i]
1459 if isunary[current] then
1460 local one = t[i+1]
1461 if not one then
1462
1463 t[m] = current .. "{}"
1464 return t
1465
1466 end
1467 if type(one) == "table" then
1468 if isleft[one[1]] and isright[one[#one]] then
1469 remove(one,#one)
1470 remove(one,1)
1471 end
1472 one = collapse(one,level)
1473 elseif one == "-" and i + 2 <= n then
1474 local t2 = t[i+2]
1475 if type(t2) == "string" then
1476 one = one .. t2
1477 i = i + 1
1478 end
1479 end
1480 t[m] = current .. "{" .. one .. "}"
1481 i = i + 2
1482 elseif i + 2 <= n and isfunny[current] then
1483 local one = t[i+1]
1484 if isinfix[one] then
1485 local two = t[i+2]
1486 if two == "-" then
1487 local three = t[i+3]
1488 if three then
1489 if type(three) == "table" then
1490 three = collapse(three,level)
1491 end
1492 t[m] = current .. one .. "{" .. two .. three .. "}"
1493 i = i + 4
1494 else
1495 t[m] = current
1496 i = i + 1
1497 end
1498 else
1499 t[m] = current
1500 i = i + 1
1501 end
1502 else
1503 t[m] = current
1504 i = i + 1
1505 end
1506 else
1507 t[m] = current
1508 i = i + 1
1509 end
1510 end
1511 if i == n then
1512 m = m + 1
1513 t[m] = t[n]
1514 end
1515 if m < n then
1516 for i=n,m+1,-1 do
1517 t[i] = nil
1518 end
1519 end
1520 return t
1521end
1522
1523local function collapse_binaries(t)
1524 local n, m, i = #t, 0, 1
1525 while i <= n do
1526 m = m + 1
1527 local current = t[i]
1528 if isbinary[current] then
1529 local one = t[i+1]
1530 local two = t[i+2]
1531 if not one then
1532 t[m] = current .. "{}{}"
1533return t
1534
1535 end
1536 if type(one) == "table" then
1537 if isleft[one[1]] and isright[one[#one]] then
1538 remove(one,#one)
1539 remove(one,1)
1540 end
1541 one = collapse(one,level)
1542 end
1543 if not two then
1544 t[m] = current .. "{" .. one .. "}{}"
1545return t
1546
1547 end
1548 if type(two) == "table" then
1549 if isleft[two[1]] and isright[two[#two]] then
1550 remove(two,#two)
1551 remove(two,1)
1552 end
1553 two = collapse(two,level)
1554 end
1555 t[m] = current .. "{" .. one .. "}{" .. two .. "}"
1556 i = i + 3
1557 else
1558 t[m] = current
1559 i = i + 1
1560 end
1561 end
1562 if i == n then
1563 m = m + 1
1564 t[m] = t[n]
1565 end
1566 if m < n then
1567 for i=n,m+1,-1 do
1568 t[i] = nil
1569 end
1570 end
1571 return t
1572end
1573
1574local function collapse_infixes_1(t)
1575 local n, i = #t, 1
1576 while i <= n do
1577 local current = t[i]
1578 if isinfix[current] then
1579 local what = t[i+1]
1580 if what then
1581 if type(what) == "table" then
1582 local f, l = what[1], what[#what]
1583 if isleft[f] and isright[l] then
1584 remove(what,#what)
1585 remove(what,1)
1586 end
1587 t[i+1] = collapse(what,level)
1588 end
1589 i = i + 2
1590 else
1591 break
1592 end
1593 else
1594 i = i + 1
1595 end
1596 end
1597 return t
1598end
1599
1600function collapse_limits(t)
1601 local n, m, i = #t, 0, 1
1602 while i <= n do
1603 m = m + 1
1604 local current = t[i]
1605 if islimits[current] then
1606 local one, two, first, second = nil, nil, t[i+1], t[i+3]
1607 if first and isinfix[first] then
1608 one = t[i+2]
1609 if one then
1610
1611
1612
1613
1614
1615
1616
1617 if second and isinfix[second] then
1618 two = t[i+4]
1619
1620
1621
1622
1623
1624
1625
1626 end
1627 if two then
1628 t[m] = current .. "\\limits" .. first .. "{" .. one .. "}" .. second .. "{" .. two .. "}"
1629 i = i + 5
1630 else
1631 t[m] = current .. "\\limits" .. first .. "{" .. one .. "}"
1632 i = i + 3
1633 end
1634 else
1635 t[m] = current
1636 i = i + 1
1637 end
1638 else
1639 t[m] = current
1640 i = i + 1
1641 end
1642 else
1643 t[m] = current
1644 i = i + 1
1645 end
1646 end
1647 if i == n then
1648 m = m + 1
1649 t[m] = t[n]
1650 end
1651 if m < n then
1652 for i=n,m+1,-1 do
1653 t[i] = nil
1654 end
1655 end
1656 return t
1657end
1658
1659local function collapse_tables(t)
1660 local n, m, i = #t, 0, 1
1661 while i <= n do
1662 m = m + 1
1663 local current = t[i]
1664 if type(current) == "table" then
1665 if current[1] == "\\NC" then
1666 t[m] = collapse(current,level)
1667 else
1668 t[m] = "{" .. collapse(current,level) .. "}"
1669 end
1670 i = i + 1
1671 else
1672 t[m] = current
1673 i = i + 1
1674 end
1675 end
1676 if i == n then
1677 m = m + 1
1678 t[m] = t[n]
1679 end
1680 if m < n then
1681 for i=n,m+1,-1 do
1682 t[i] = nil
1683 end
1684 end
1685 return t
1686end
1687
1688local function collapse_infixes_2(t)
1689 local n, m, i = #t, 0, 1
1690 while i < n do
1691 local current = t[i]
1692 if isinfix[current] and i > 1 then
1693 local tl = t[i-1]
1694 local tr = t[i+1]
1695 local ti = t[i+2]
1696 local tn = t[i+3]
1697 if ti and tn and isinfix[ti] then
1698 t[m] = tl .. current .. "{" .. tr .. "}" .. ti .. "{" .. tn .. "}"
1699 i = i + 4
1700 else
1701 t[m] = tl .. current .. "{" .. tr .. "}"
1702 i = i + 2
1703 end
1704 else
1705 m = m + 1
1706 t[m] = current
1707 i = i + 1
1708 end
1709 end
1710 if i == n then
1711 m = m + 1
1712 t[m] = t[n]
1713 end
1714 if m < n then
1715 for i=n,m+1,-1 do
1716 t[i] = nil
1717 end
1718 end
1719 return t
1720end
1721
1722local function collapse_fractions_1(t)
1723 local n, m, i = #t, 0, 1
1724 while i < n do
1725 local current = t[i]
1726 if current == "/" and i > 1 then
1727 local tl = t[i-1]
1728 local tr = t[i+1]
1729 t[m] = "\\frac{" .. tl .. "}{" .. tr .. "}"
1730 i = i + 2
1731 if i < n then
1732 m = m + 1
1733 t[m] = t[i]
1734 i = i + 1
1735 end
1736 else
1737 m = m + 1
1738 t[m] = current
1739 i = i + 1
1740 end
1741 end
1742 if i == n then
1743 m = m + 1
1744 t[m] = t[n]
1745 end
1746 if m < n then
1747 for i=n,m+1,-1 do
1748 t[i] = nil
1749 end
1750 end
1751 return t
1752end
1753
1754local function collapse_fractions_2(t)
1755 local n, m, i = #t, 0, 1
1756 while i < n do
1757 local current = t[i]
1758 if current == "⁄" and i > 1 then
1759 if i < n and t[i+1] == "⁄" then
1760
1761
1762
1763 t[m] = "\\hfrac{" .. t[i-1] .. "}{" .. t[i+2] .. "}"
1764 i = i + 3
1765 else
1766
1767
1768 t[m] = "\\hfrac{" .. t[i-1] .. "}{" .. t[i+1] .. "}"
1769 i = i + 2
1770 end
1771 if i < n then
1772 m = m + 1
1773 t[m] = t[i]
1774 i = i + 1
1775 end
1776 else
1777 m = m + 1
1778 t[m] = current
1779 i = i + 1
1780 end
1781 end
1782 if i == n then
1783 m = m + 1
1784 t[m] = t[n]
1785 end
1786 if m < n then
1787 for i=n,m+1,-1 do
1788 t[i] = nil
1789 end
1790 end
1791 return t
1792end
1793
1794local function collapse_result(t)
1795 local n = #t
1796 if t[1] == s_left and t[n] == s_right then
1797 return concat(t," ",2,n-1)
1798 else
1799 return concat(t," ")
1800 end
1801end
1802
1803collapse = function(t,level)
1804
1805 if not t then
1806 return ""
1807 end
1808
1809 if trace_details then
1810 if level then
1811 level = level + 1
1812 else
1813 level = 1
1814 end
1815 show_state(t,level,"parsed")
1816 end
1817
1818 t = collapse_matrices (t) if trace_details then show_state(t,level,"matrices") end
1819 t = collapse_bars (t) if trace_details then show_state(t,level,"bars") end
1820 t = collapse_stupids (t) if trace_details then show_state(t,level,"stupids") end
1821 t = collapse_pairs (t) if trace_details then show_state(t,level,"pairs") end
1822 t = collapse_parentheses(t) if trace_details then show_state(t,level,"parentheses") end
1823 t = collapse_signs (t) if trace_details then show_state(t,level,"signs") end
1824 t = collapse_binaries (t) if trace_details then show_state(t,level,"binaries") end
1825 t = collapse_infixes_1 (t) if trace_details then show_state(t,level,"infixes (1)") end
1826 t = collapse_limits (t) if trace_details then show_state(t,level,"limits") end
1827 t = collapse_tables (t) if trace_details then show_state(t,level,"tables") end
1828 t = collapse_infixes_2 (t) if trace_details then show_state(t,level,"infixes (2)") end
1829 t = collapse_fractions_1(t) if trace_details then show_state(t,level,"fractions (1)") end
1830 t = collapse_fractions_2(t) if trace_details then show_state(t,level,"fractions (2)") end
1831
1832 return collapse_result(t)
1833end
1834
1835
1836
1837local context = context
1838local ctx_mathematics = context and context.mathematics or report_asciimath
1839local ctx_type = context and context.type or function() end
1840local ctx_inleft = context and context.inleft or function() end
1841
1842local function convert(str,totex)
1843 local unicoded = lpegmatch(u_parser,str) or str
1844 local texcoded = collapse(lpegmatch(a_parser,unicoded))
1845 if trace_mapping then
1846 show_result(str,unicoded,texcoded)
1847 end
1848 if totex then
1849 ctx_mathematics(texcoded)
1850 else
1851 return texcoded
1852 end
1853end
1854
1855local n = 0
1856local p = (
1857 (S("{[(") + P("\\left" )) / function() n = n + 1 end
1858 + (S("}])") + P("\\right")) / function() n = n - 1 end
1859 + p_utf_base
1860)^0
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870local function invalidtex(str)
1871 n = 0
1872 lpegmatch(p,str)
1873 if n == 0 then
1874 return false
1875 elseif n < 0 then
1876 return formatters["too many left fences: %s"](-n)
1877 elseif n > 0 then
1878 return formatters["not enough right fences: %s"](n)
1879 end
1880end
1881
1882local collected = { }
1883local indexed = { }
1884
1885
1886
1887local p_reserved_spaced =
1888 C(lpeg.utfchartabletopattern(k_reserved_words)) / " %1 "
1889
1890local p_text =
1891 C(P("text")) / " %1 "
1892 * p_spaces^0
1893 * (
1894 (P("{") * (1-P("}"))^0 * P("}"))
1895 + (P("(") * (1-P(")"))^0 * P(")"))
1896 )
1897 + patterns.doublequoted
1898
1899local p_expand = Cs((p_text + p_reserved_spaced + p_utf_base)^0)
1900local p_compress = patterns.collapser
1901
1902local function cleanedup(str)
1903 return lpegmatch(p_compress,lpegmatch(p_expand,str)) or str
1904end
1905
1906
1907
1908local function register(s,cleanedup,collected,shortname)
1909 local c = cleanedup(s)
1910 local f = collected[c]
1911 if f then
1912 f.count = f.count + 1
1913 f.files[shortname] = (f.files[shortname] or 0) + 1
1914 if s ~= c then
1915 f.cleanedup = f.cleanedup + 1
1916 end
1917 f.dirty[s] = (f.dirty[s] or 0) + 1
1918 else
1919 local texcoded = convert(s)
1920 local message = invalidtex(texcoded)
1921 if message then
1922 report_asciimath("%s: %s : %s",message,s,texcoded)
1923 end
1924 collected[c] = {
1925 count = 1,
1926 files = { [shortname] = 1 },
1927 texcoded = texcoded,
1928 message = message,
1929 cleanedup = s ~= c and 1 or 0,
1930 dirty = { [s] = 1 }
1931 }
1932 end
1933end
1934
1935local function wrapup(collected,indexed)
1936 local n = 0
1937 for k, v in sortedhash(collected) do
1938 n = n + 1
1939 v.n= n
1940 indexed[n] = k
1941 end
1942end
1943
1944function collect(fpattern,element,collected,indexed)
1945 local element = element or "am"
1946 local mpattern = formatters["<%s>(.-)</%s>"](element,element)
1947 local filenames = resolvers.findtexfile(fpattern)
1948 if filenames and filenames ~= "" then
1949 filenames = { filenames }
1950 else
1951 filenames = dir.glob(fpattern)
1952 end
1953 local cfpattern = gsub(fpattern,"^%./",lfs.currentdir())
1954 local cfpattern = gsub(cfpattern,"\\","/")
1955 local wildcard = string.split(cfpattern,"*")[1]
1956 if not collected then
1957 collected = { }
1958 indexed = { }
1959 end
1960 for i=1,#filenames do
1961 filename = gsub(filenames[i],"\\","/")
1962 local splitname = (wildcard and wildcard ~= "" and string.split(filename,wildcard)[2]) or filename
1963 local shortname = gsub(splitname or file.basename(filename),"^%./","")
1964 if shortname == "" then
1965 shortname = filename
1966 end
1967 local fullname = resolvers.findtexfile(filename) or filename
1968 if fullname ~= "" then
1969 for s in gmatch(io.loaddata(fullname),mpattern) do
1970 register(s,cleanedup,collected,shortname)
1971 end
1972 end
1973 end
1974 wrapup(collected,indexed)
1975 return collected, indexed
1976end
1977
1978function filter(root,pattern,collected,indexed)
1979 if not pattern or pattern == "" then
1980 pattern = "am"
1981 end
1982 if not collected then
1983 collected = { }
1984 indexed = { }
1985 end
1986 for c in xmlcollected(root,pattern) do
1987 register(xmltext(c),cleanedup,collected,xmlinclusion(c) or "" )
1988 end
1989 wrapup(collected,indexed)
1990 return collected, indexed
1991end
1992
1993asciimath.convert = convert
1994asciimath.reserved = reserved
1995asciimath.collect = collect
1996asciimath.filter = filter
1997asciimath.invalidtex = invalidtex
1998asciimath.cleanedup = cleanedup
1999
2000
2001
2002local uncrapped = {
2003 ["%"] = "\\mathpercent",
2004 ["&"] = "\\mathampersand",
2005 ["#"] = "\\mathhash",
2006 ["$"] = "\\mathdollar",
2007 ["^"] = "\\Hat{\\enspace}",
2008 ["_"] = "\\underline{\\enspace}",
2009}
2010
2011local function convert(str,nowrap)
2012 if str ~= "" then
2013 local unicoded = lpegmatch(u_parser,str) or str
2014 if lpegmatch(p_onechar,unicoded) then
2015 ctx_mathematics(uncrapped[unicoded] or unicoded)
2016 else
2017 local texcoded = collapse(lpegmatch(a_parser,unicoded))
2018 if trace_mapping then
2019 show_result(str,unicoded,texcoded)
2020 end
2021 if #texcoded == 0 then
2022 report_asciimath("error in asciimath: %s",str)
2023 else
2024 local message = invalidtex(texcoded)
2025 if message then
2026 report_asciimath("%s: %s : %s",message,str,texcoded)
2027 ctx_type(formatters["<%s>"](message))
2028 elseif nowrap then
2029 context(texcoded)
2030 else
2031 ctx_mathematics(texcoded)
2032 end
2033 end
2034 end
2035 end
2036end
2037
2038local context = context
2039
2040if not context then
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130 return
2131
2132end
2133
2134interfaces.implement {
2135 name = "asciimath",
2136 actions = convert,
2137 arguments = "string"
2138}
2139
2140interfaces.implement {
2141 name = "texasciimath",
2142 actions = convert,
2143 arguments = { "string", true },
2144}
2145
2146interfaces.implement {
2147 name = "xmlasciimath",
2148 actions = function(id)
2149 convert(xmlpure(lxmlgetid(id)))
2150 end,
2151 arguments = "string"
2152}
2153
2154local ctx_typebuffer = context.typebuffer
2155local ctx_mathematics = context.mathematics
2156local ctx_color = context.color
2157
2158local sequenced = table.sequenced
2159local assign_buffer = buffers.assign
2160
2161local show = { }
2162asciimath.show = show
2163
2164local collected, indexed, ignored = { }, { }, { }
2165
2166local color = { "darkred" }
2167
2168function show.ignore(n)
2169 if type(n) == "string" then
2170 local c = collected[n]
2171 n = c and c.n
2172 end
2173 if n then
2174 ignored[n] = true
2175 end
2176end
2177
2178function show.count(n,showcleanedup)
2179 local v = collected[indexed[n]]
2180 local count = v.count
2181 local cleanedup = v.cleanedup
2182 if not showcleanedup or cleanedup == 0 then
2183 context(count)
2184 elseif count == cleanedup then
2185 ctx_color(color,count)
2186 else
2187 context("%s+",count-cleanedup)
2188 ctx_color(color,cleanedup)
2189 end
2190end
2191
2192local h = { }
2193local am = { "am" }
2194
2195function show.nofdirty(n)
2196 local k = indexed[n]
2197 local v = collected[k]
2198 local n = v.cleanedup
2199 h = { }
2200 if n > 0 then
2201 for d, n in sortedhash(v.dirty) do
2202 if d ~= k then
2203 h[#h+1] = { d, n }
2204 end
2205 end
2206 end
2207 context(#h)
2208end
2209
2210function show.dirty(m,wrapped)
2211 local d = h[m]
2212 if d then
2213 ctx_inleft(d[2])
2214 if wrapped then
2215 assign_buffer("am",'"' .. d[1] .. '"')
2216 else
2217 assign_buffer("am",d[1])
2218 end
2219 ctx_typebuffer(am)
2220 end
2221end
2222
2223function show.files(n)
2224 context(sequenced(collected[indexed[n]].files," "))
2225end
2226
2227function show.input(n,wrapped)
2228 if wrapped then
2229 assign_buffer("am",'"' .. indexed[n] .. '"')
2230 else
2231 assign_buffer("am",indexed[n])
2232 end
2233 ctx_typebuffer(am)
2234end
2235
2236function show.result(n)
2237 local v = collected[indexed[n]]
2238 if ignored[n] then
2239 context("ignored")
2240 elseif v.message then
2241 ctx_color(color, v.message)
2242 else
2243 ctx_mathematics(v.texcoded)
2244 end
2245end
2246
2247function show.load(str,element)
2248 collected, indexed, ignored = { }, { }, { }
2249 local t = utilities.parsers.settings_to_array(str)
2250 for i=1,#t do
2251 asciimath.collect(t[i],element or "am",collected,indexed)
2252 end
2253end
2254
2255function show.filter(id,element)
2256 collected, indexed, ignored = { }, { }, { }
2257 asciimath.filter(lxmlgetid(id),element or "am",collected,indexed)
2258end
2259
2260function show.max()
2261 context(#indexed)
2262end
2263
2264function show.statistics()
2265 local usedfiles = { }
2266 local noffiles = 0
2267 local nofokay = 0
2268 local nofbad = 0
2269 local nofcleanedup = 0
2270 for k, v in next, collected do
2271 if ignored[v.n] then
2272 nofbad = nofbad + v.count
2273 elseif v.message then
2274 nofbad = nofbad + v.count
2275 else
2276 nofokay = nofokay + v.count
2277 end
2278 nofcleanedup = nofcleanedup + v.cleanedup
2279 for k, v in next, v.files do
2280 local u = usedfiles[k]
2281 if u then
2282 usedfiles[k] = u + 1
2283 else
2284 noffiles = noffiles + 1
2285 usedfiles[k] = 1
2286 end
2287 end
2288 end
2289 local NC = context.NC
2290 local NR = context.NR
2291 local EQ = context.EQ
2292 context.starttabulate { "|B||" }
2293 NC() context("files") EQ() context(noffiles) NC() NR()
2294 NC() context("formulas") EQ() context(nofokay+nofbad) NC() NR()
2295 NC() context("uniques") EQ() context(#indexed) NC() NR()
2296 NC() context("cleanedup") EQ() context(nofcleanedup) NC() NR()
2297 NC() context("errors") EQ() context(nofbad) NC() NR()
2298 context.stoptabulate()
2299end
2300
2301function show.save(name)
2302 table.save(name ~= "" and name or "dummy.lua",collected)
2303end
2304 |