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