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