x-asciimath.lua /size: 65 Kb    last modification: 2021-10-28 13:51
1
if
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
--[[ldx-- 10<p>Some backgrounds are discussed in <t>x-asciimath.mkiv</t>. This is a third version. I first 11tried a to make a proper expression parser but it's not that easy. First we have to avoid left 12recursion, which is not that trivial (maybe a future version of lpeg will provide that), and 13second there is not really a syntax but a mix of expressions and sequences with some fuzzy logic 14applied. Most problematic are fractions and we also need to handle incomplete expressions. So, 15instead we (sort of) tokenize the string and then do some passes over the result. Yes, it's real 16ugly and unsatisfying code mess down here. Don't take this as an example.</p> 17--ldx]]
--
18 19
-- todo: spaces around all elements in cleanup?
20
-- todo: filter from files listed in tuc file
21 22
local
trace_mapping
=
false
if
trackers
then
trackers
.
register
(
"
modules.asciimath.mapping
"
,
function
(
v
)
trace_mapping
=
v
end
)
end
23
local
trace_details
=
false
if
trackers
then
trackers
.
register
(
"
modules.asciimath.details
"
,
function
(
v
)
trace_details
=
v
end
)
end
24
local
trace_digits
=
false
if
trackers
then
trackers
.
register
(
"
modules.asciimath.digits
"
,
function
(
v
)
trace_digits
=
v
end
)
end
25 26
local
report_asciimath
=
logs
.
reporter
(
"
mathematics
"
,
"
asciimath
"
)
27 28
local
asciimath
=
{
}
29
local
moduledata
=
moduledata
or
{
}
30
moduledata
.
asciimath
=
asciimath
31 32
if
not
characters
then
33
require
(
"
char-def
"
)
34
require
(
"
char-ini
"
)
35
require
(
"
char-ent
"
)
36
end
37 38
local
next
,
type
=
next
,
type
39
local
concat
,
insert
,
remove
=
table
.
concat
,
table
.
insert
,
table
.
remove
40
local
rep
,
gmatch
,
gsub
,
find
=
string
.
rep
,
string
.
gmatch
,
string
.
gsub
,
string
.
find
41
local
utfchar
,
utfbyte
=
utf
.
char
,
utf
.
byte
42 43
local
lpegmatch
,
patterns
=
lpeg
.
match
,
lpeg
.
patterns
44
local
S
,
P
,
R
,
C
,
V
,
Cc
,
Ct
,
Cs
,
Carg
=
lpeg
.
S
,
lpeg
.
P
,
lpeg
.
R
,
lpeg
.
C
,
lpeg
.
V
,
lpeg
.
Cc
,
lpeg
.
Ct
,
lpeg
.
Cs
,
lpeg
.
Carg
45 46
local
sortedhash
=
table
.
sortedhash
47
local
sortedkeys
=
table
.
sortedkeys
48
local
formatters
=
string
.
formatters
49 50
local
entities
=
characters
.
entities
or
{
}
51 52
local
xmltext
=
xml
.
text
53
local
xmlpure
=
xml
.
pure
54
local
xmlinclusion
=
xml
.
inclusion
55
local
xmlcollected
=
xml
.
collected
56 57
local
lxmlgetid
=
lxml
.
getid
58 59
-- todo: use private unicodes as temporary slots ... easier to compare
60 61
local
s_lparent
=
"
\\left\\lparent
"
62
local
s_lbrace
=
"
\\left\\lbrace
"
63
local
s_lbracket
=
"
\\left\\lbracket
"
64
local
s_langle
=
"
\\left\\langle
"
65
local
s_lfloor
=
"
\\left\\lfloor
"
66
local
s_lceil
=
"
\\left\\lceil
"
67
local
s_left
=
"
\\left.
"
68 69
local
s_rparent
=
"
\\right\\rparent
"
70
local
s_rbrace
=
"
\\right\\rbrace
"
71
local
s_rbracket
=
"
\\right\\rbracket
"
72
local
s_rangle
=
"
\\right\\rangle
"
73
local
s_rfloor
=
"
\\right\\rfloor
"
74
local
s_rceil
=
"
\\right\\rceil
"
75
local
s_right
=
"
\\right.
"
76 77
local
s_mslash
=
"
\\middle/
"
78 79
local
s_lbar
=
"
\\left\\|
"
80
local
s_mbar
=
"
\\middle\\|
"
81
local
s_rbar
=
"
\\right\\|
"
82 83
local
s_lnothing
=
"
\\left .
"
-- space fools checker
84
local
s_rnothing
=
"
\\right .
"
-- space fools checker
85 86
local
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
-- ["atan"] = { false, "\\atan" }, -- extra
110
-- ["acos"] = { false, "\\acos" }, -- extra
111
-- ["asin"] = { false, "\\asin" }, -- extra
112 113
[
"
arctan
"
]
=
{
false
,
"
\\arctan
"
}
,
-- extra
114
[
"
arccos
"
]
=
{
false
,
"
\\arccos
"
}
,
-- extra
115
[
"
arcsin
"
]
=
{
false
,
"
\\arcsin
"
}
,
-- extra
116 117
[
"
arctanh
"
]
=
{
false
,
"
\\arctanh
"
}
,
-- extra
118
[
"
arccosh
"
]
=
{
false
,
"
\\arccosh
"
}
,
-- extra
119
[
"
arcsinh
"
]
=
{
false
,
"
\\arcsinh
"
}
,
-- extra
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
-- ["\\frac"] = { false, "\\frac", "binary" },
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
"
}
,
-- 0x2D9
144
[
"
ddot
"
]
=
{
false
,
"
\\ddot
"
,
"
unary
"
}
,
-- 0xA8
145 146
-- binary operators
147 148
[
"
+
"
]
=
{
true
,
"
+
"
}
,
149
[
"
-
"
]
=
{
true
,
"
-
"
}
,
150
[
"
*
"
]
=
{
true
,
"
"
}
,
151
[
"
**
"
]
=
{
true
,
"
"
}
,
152
[
"
////
"
]
=
{
true
,
"
⁄⁄
"
}
,
-- crap
153
[
"
//
"
]
=
{
true
,
"
"
}
,
-- \slash
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
-- big operators
169 170
[
"
^^^
"
]
=
{
true
,
"
"
}
,
171
[
"
vvv
"
]
=
{
true
,
"
"
}
,
172
[
"
nnn
"
]
=
{
true
,
"
"
}
,
173
[
"
uuu
"
]
=
{
true
,
"
"
}
,
174
[
"
int
"
]
=
{
true
,
"
"
}
,
175
[
"
oint
"
]
=
{
true
,
"
"
}
,
176 177
-- brackets
178 179
[
"
(
"
]
=
{
true
,
"
(
"
}
,
180
[
"
)
"
]
=
{
true
,
"
)
"
}
,
181
[
"
[
"
]
=
{
true
,
"
[
"
}
,
182
[
"
]
"
]
=
{
true
,
"
]
"
}
,
183
[
"
{
"
]
=
{
true
,
"
{
"
}
,
184
[
"
}
"
]
=
{
true
,
"
}
"
}
,
185 186
-- binary relations
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
-- arrows
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
-- logical
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
-- miscellaneous
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
,
"
...
"
}
,
-- ldots
253
[
"
ldots
"
]
=
{
true
,
"
...
"
}
,
-- ldots
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
-- more
265 266
[
"
_=
"
]
=
{
true
,
"
"
}
,
267 268
-- bonus
269 270
[
"
prime
"
]
=
{
true
,
"
"
}
,
-- bonus
271
[
"
'
"
]
=
{
true
,
"
"
}
,
-- bonus
272
[
"
''
"
]
=
{
true
,
"
"
}
,
-- bonus
273
[
"
'''
"
]
=
{
true
,
"
"
}
,
-- bonus
274 275
-- special
276 277
[
"
%
"
]
=
{
false
,
"
\\mathpercent
"
}
,
278
[
"
&
"
]
=
{
false
,
"
\\mathampersand
"
}
,
279
[
"
#
"
]
=
{
false
,
"
\\mathhash
"
}
,
280
[
"
$
"
]
=
{
false
,
"
\\mathdollar
"
}
,
281 282
-- blackboard
283 284
[
"
CC
"
]
=
{
true
,
"
"
}
,
285
[
"
NN
"
]
=
{
true
,
"
"
}
,
286
[
"
QQ
"
]
=
{
true
,
"
"
}
,
287
[
"
RR
"
]
=
{
true
,
"
"
}
,
288
[
"
ZZ
"
]
=
{
true
,
"
"
}
,
289 290
-- greek lowercase
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
-- greek uppercase
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
-- blackboard
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
-- fraktur
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
-- script
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
-- bold
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
-- sans
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
-- monospace
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
-- some more undocumented
669 670
[
"
dx
"
]
=
{
false
,
{
"
d
"
,
"
x
"
}
}
,
-- "{dx}" "\\left(dx\\right)"
671
[
"
dy
"
]
=
{
false
,
{
"
d
"
,
"
y
"
}
}
,
-- "{dy}" "\\left(dy\\right)"
672
[
"
dz
"
]
=
{
false
,
{
"
d
"
,
"
z
"
}
}
,
-- "{dz}" "\\left(dz\\right)"
673 674
-- fences
675 676
[
"
(:
"
]
=
{
true
,
"
(:
"
}
,
677
[
"
{:
"
]
=
{
true
,
"
{:
"
}
,
678
[
"
[:
"
]
=
{
true
,
"
[:
"
}
,
679
[
"
(
"
]
=
{
true
,
"
(
"
}
,
680
[
"
[
"
]
=
{
true
,
"
[
"
}
,
681
[
"
{
"
]
=
{
true
,
"
{
"
}
,
682
[
"
<<
"
]
=
{
true
,
"
"
}
,
-- why not <:
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
,
"
"
}
,
-- why not :>
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
-- a bit special:
717 718
-- ["\\frac"] = { true, "frac" },
719 720
-- now it gets real crazy, only these two:
721 722
[
"
&gt;
"
]
=
{
true
,
"
>
"
}
,
723
[
"
&lt;
"
]
=
{
true
,
"
<
"
}
,
724 725
-- extra:
726 727
-- also, invisible times
728 729
[
"
dd
"
]
=
{
false
,
"
{\\tf d}
"
}
,
730
[
"
ee
"
]
=
{
false
,
"
{\\tf e}
"
}
,
731
[
"
xxx
"
]
=
{
true
,
utfchar
(
0x2063
)
}
,
-- invisible times
732 733
}
734 735
-- a..z A..Z : allemaal op italic alphabet
736
-- en dan default naar upright "upr a"
737 738
for
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
-- reserved["\\" .. name] = char
744
end
745
-- local spec = v.mathspec
746
-- if spec then
747
-- for i=1,#spec do
748
-- local name = spec[i].name
749
-- if name and not reserved[name] then
750
-- reserved[name] = { true, utfchar(k) }
751
-- end
752
-- end
753
-- end
754
end
755 756
reserved
.
P
=
nil
757
reserved
.
S
=
nil
758 759 760
local
isbinary
=
{
761
[
"
\\frac
"
]
=
true
,
762
[
"
\\root
"
]
=
true
,
763
[
"
\\asciimathroot
"
]
=
true
,
764
[
"
\\asciimathstackrel
"
]
=
true
,
765
[
"
\\overset
"
]
=
true
,
766
[
"
\\underset
"
]
=
true
,
767
}
768 769
local
isunary
=
{
-- can be taken from reserved
770
[
"
\\sqrt
"
]
=
true
,
771
[
"
\\asciimathsqrt
"
]
=
true
,
772
[
"
\\text
"
]
=
true
,
-- mathoptext
773
[
"
\\mathoptext
"
]
=
true
,
-- mathoptext
774
[
"
\\asciimathoptext
"
]
=
true
,
-- mathoptext
775
[
"
\\hat
"
]
=
true
,
-- widehat
776
[
"
\\widehat
"
]
=
true
,
-- widehat
777
[
"
\\bar
"
]
=
true
,
--
778
[
"
\\overbar
"
]
=
true
,
--
779
[
"
\\overline
"
]
=
true
,
--
780
[
"
\\underline
"
]
=
true
,
--
781
[
"
\\vec
"
]
=
true
,
-- overrightarrow
782
[
"
\\overrightarrow
"
]
=
true
,
-- overrightarrow
783
[
"
\\dot
"
]
=
true
,
--
784
[
"
\\ddot
"
]
=
true
,
--
785 786
[
"
\\overbrace
"
]
=
true
,
787
[
"
\\underbrace
"
]
=
true
,
788
[
"
\\obrace
"
]
=
true
,
789
[
"
\\ubrace
"
]
=
true
,
790
}
791 792
local
isfunny
=
{
793
[
"
\\sin
"
]
=
true
,
794
}
795 796
local
isinfix
=
{
797
[
"
^
"
]
=
true
,
798
[
"
_
"
]
=
true
,
799
}
800 801
local
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
-- ["\\atan"] = true,
824
-- ["\\acos"] = true,
825
-- ["\\asin"] = true,
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 839
local
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 849
local
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 859
local
issimplified
=
{
860
}
861 862
--
863 864
-- special mess (we have a generic one now but for the moment keep this)
865
-- special mess (we have a generic one now but for the moment keep this)
866 867
local
d_one
=
R
(
"
09
"
)
868
local
d_two
=
d_one
*
d_one
869
local
d_three
=
d_two
*
d_one
870
local
d_four
=
d_three
*
d_one
871
local
d_split
=
P
(
-1
)
+
Carg
(
2
)
*
(
S
(
"
.
"
)
/
"
"
)
872 873
local
d_spaced
=
(
Carg
(
1
)
*
d_three
)
^
1
874 875
local
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 882
local
p_fourbefore
=
d_four
*
d_split
883
local
p_fourafter
=
d_four
*
P
(
-1
)
884 885
local
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 890
local
p_aftercomma
=
p_fourafter
891
+
d_three
*
d_spaced
892
+
d_two
*
d_spaced
893
+
d_one
*
d_spaced
894 895
local
digitized_2
=
Cs
(
896
p_fourbefore
*
(
p_aftercomma
^
0
)
+
897
p_beforecomma
*
(
(
p_aftercomma
+
d_one
^
1
)
^
0
)
898
)
899 900
local
p_fourbefore
=
d_four
*
d_split
901
local
p_fourafter
=
d_four
902
local
d_spaced
=
(
Carg
(
1
)
*
(
d_three
+
d_two
+
d_one
)
)
^
1
903
local
p_aftercomma
=
p_fourafter
*
P
(
-1
)
904
+
d_three
*
d_spaced
*
P
(
1
)
^
0
905
+
d_one
^
1
906 907
-- local digitized_3 = Cs (
908
-- p_fourbefore * p_aftercomma^0 +
909
-- p_beforecomma * p_aftercomma^0
910
-- )
911 912
local
digitized_3
=
Cs
(
(
p_fourbefore
+
p_beforecomma
)
*
p_aftercomma
^
0
)
913 914
local
splitmethods
=
{
915
digitized_1
,
916
digitized_2
,
917
digitized_3
,
918
}
919 920
local
splitmethod
=
nil
921
local
symbolmethod
=
nil
922
local
digitseparator
=
utfchar
(
0x2008
)
923
local
digitsymbol
=
"
.
"
924 925
local
v_yes_digits
=
interfaces
and
interfaces
.
variables
.
yes
or
true
926 927
function
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
-- if separator == true or not interfaces or interfaces.variables.yes then
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
949
end
950 951
local
collected_digits
=
{
}
952
local
collected_filename
=
"
asciimath-digits.lua
"
953 954
function
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
968
end
969 970
-- asciimath.setup { splitmethod = 3, symbol = "," }
971
-- local t = {
972
-- "0.00002",
973
-- "1", "12", "123", "1234", "12345", "123456", "1234567", "12345678", "123456789",
974
-- "1.1",
975
-- "12.12",
976
-- "123.123",
977
-- "1234.123",
978
-- "1234.1234",
979
-- "12345.1234",
980
-- "1234.12345",
981
-- "12345.12345",
982
-- "123456.123456",
983
-- "1234567.1234567",
984
-- "12345678.12345678",
985
-- "123456789.123456789",
986
-- "0.1234",
987
-- "1234.0",
988
-- "1234.00",
989
-- "0.123456789",
990
-- "100.00005",
991
-- "0.80018",
992
-- "10.80018",
993
-- "100.80018",
994
-- "1000.80018",
995
-- "10000.80018",
996
-- }
997
-- for i=1,#t do print(formatters["%-20s : [%s]"](t[i],numbermess(t[i]))) end
998 999
statistics
.
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
1009
end
)
1010 1011
local
p_number_base
=
patterns
.
cpnumber
or
patterns
.
cnumber
or
patterns
.
number
1012
local
p_number
=
C
(
p_number_base
)
1013
----- p_number = p_number_base
1014
local
p_spaces
=
patterns
.
whitespace
1015 1016
local
p_utf_base
=
patterns
.
utf8character
1017
local
p_utf
=
C
(
p_utf_base
)
1018
-- local p_entity = (P("&") * C((1-P(";"))^2) * P(";"))/ entities
1019 1020
-- entities["gt"] = ">"
1021
-- entities["lt"] = "<"
1022
-- entities["amp"] = "&"
1023
-- entities["dquot"] = '"'
1024
-- entities["quot"] = "'"
1025 1026
local
p_onechar
=
p_utf_base
*
P
(
-1
)
1027 1028
----- p_number = Cs((patterns.cpnumber or patterns.cnumber or patterns.number)/function(s) return (gsub(s,",","{,}")) end)
1029 1030
local
sign
=
P
(
"
-
"
)
^
-1
1031
local
digits
=
R
(
"
09
"
)
^
1
1032
local
integer
=
sign
*
digits
1033
local
real
=
digits
*
(
S
(
"
.
"
)
*
digits
)
^
-1
1034
local
float
=
real
*
(
P
(
"
E
"
)
*
integer
)
^
-1
1035 1036
-- local number = C(float + integer)
1037
-- local p_number = C(float)
1038
local
p_number
=
float
/
numbermess
1039 1040
local
k_reserved
=
sortedkeys
(
reserved
)
1041
local
k_commands
=
{
}
1042
local
k_unicode
=
{
}
1043 1044
asciimath
.
keys
=
{
1045
reserved
=
k_reserved
1046
}
1047 1048
local
k_reserved_different
=
{
}
1049
local
k_reserved_words
=
{
}
1050 1051
for
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
-- keep them ... later we remap these
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
-- dirty trick, no real unicode (still needed ?)
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
1070
end
1071 1072
local
p_reserved
=
1073
lpeg
.
utfchartabletopattern
(
k_reserved_different
)
/
k_commands
1074 1075
local
p_unicode
=
1076
-- lpeg.utfchartabletopattern(table.keys(k_unicode)) / k_unicode
1077
lpeg
.
utfchartabletopattern
(
k_unicode
)
/
k_unicode
1078 1079
local
p_texescape
=
patterns
.
texescape
1080 1081
local
function
texescaped
(
s
)
1082
return
lpegmatch
(
p_texescape
,
s
)
or
s
1083
end
1084 1085
local
p_text
=
1086
P
(
"
text
"
)
1087
*
p_spaces
^
0
1088
*
Cc
(
"
\\asciimathoptext
"
)
1089
*
(
-- maybe balanced
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 1095
local
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
-- ["<<"] = s_langle, -- why not <:
1107
-- ["|_"] = s_lfloor,
1108
-- ["|~"] = s_lceil,
1109
-- ["〈"] = s_langle,
1110
-- ["〈"] = s_langle,
1111 1112
-- ["lparent"] = s_lparent,
1113
-- ["lbracket"] = s_lbracket,
1114
-- ["lbrace"] = s_lbrace,
1115
-- ["langle"] = s_langle,
1116
-- ["lfloor"] = s_lfloor,
1117
-- ["lceil"] = s_lceil,
1118
}
1119 1120
local
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
-- [">>"] = s_rangle, -- why not :>
1132
-- ["~|"] = s_rceil,
1133
-- ["_|"] = s_rfloor,
1134
-- ["〉"] = s_rangle,
1135
-- ["〉"] = s_rangle,
1136 1137
-- ["rparent"] = s_rparent,
1138
-- ["rbracket"] = s_rbracket,
1139
-- ["rbrace"] = s_rbrace,
1140
-- ["rangle"] = s_rangle,
1141
-- ["rfloor"] = s_rfloor,
1142
-- ["rceil"] = s_rceil,
1143
}
1144 1145
local
islimits
=
{
1146
[
"
\\sum
"
]
=
true
,
1147
-- ["∑"] = true,
1148
[
"
\\prod
"
]
=
true
,
1149
-- ["∏"] = true,
1150
[
"
\\lim
"
]
=
true
,
1151
}
1152 1153
local
p_left
=
1154
lpeg
.
utfchartabletopattern
(
m_left
)
/
m_left
1155
local
p_right
=
1156
lpeg
.
utfchartabletopattern
(
m_right
)
/
m_right
1157 1158
-- special cases
1159 1160
-- local p_special =
1161
-- C("/")
1162
-- + P("\\ ") * Cc("{}") * p_spaces^0 * C(S("^_"))
1163
-- + P("\\ ") * Cc("\\space")
1164
-- + P("\\\\") * Cc("\\backslash")
1165
-- + P("\\") * (R("az","AZ")^1/entities)
1166
-- + P("|") * Cc("\\|")
1167
--
1168
-- faster bug also uglier:
1169 1170
local
p_special
=
1171
P
(
"
|
"
)
*
Cc
(
"
\\|
"
)
-- s_mbar -- maybe always add left / right as in mml ?
1172
+
P
(
"
\\
"
)
*
(
1173
(
1174
P
(
"
"
)
*
(
1175
Cc
(
"
{}
"
)
*
p_spaces
^
0
*
C
(
S
(
"
^_
"
)
)
1176
+
Cc
(
"
\\space
"
)
1177
)
1178
)
1179
+
P
(
"
\\
"
)
*
Cc
(
"
\\backslash
"
)
1180
-- + (R("az","AZ")^1/entities)
1181
+
C
(
R
(
"
az
"
,
"
AZ
"
)
^
1
)
1182
)
1183 1184
-- open | close :: {: | :}
1185 1186
local
u_parser
=
Cs
(
(
1187
patterns
.
doublequoted
+
1188
P
(
"
text
"
)
*
p_spaces
^
0
*
P
(
"
(
"
)
*
(
1
-
P
(
"
)
"
)
)
^
0
*
P
(
"
)
"
)
+
-- -- todo: balanced
1189
P
(
"
\\frac
"
)
/
"
frac
"
+
-- bah
1190
p_unicode
+
1191
p_utf_base
1192
)
^
0
)
1193 1194
local
a_parser
=
Ct
{
"
tokenizer
"
,
1195
tokenizer
=
(
1196
p_spaces
1197
+
p_number
1198
+
p_text
1199
-- + Ct(p_open * V("tokenizer") * p_close) -- {: (a+b,=,1),(a+b,=,7) :}
1200
-- + Ct(p_open * V("tokenizer") * p_close_right) -- { (a+b,=,1),(a+b,=,7) :}
1201
-- + Ct(p_open_left * V("tokenizer") * p_right) -- {: (a+b,=,1),(a+b,=,7) }
1202
+
Ct
(
p_left
*
V
(
"
tokenizer
"
)
*
p_right
)
-- { (a+b,=,1),(a+b,=,7) }
1203
+
p_special
1204
+
p_reserved
1205
-- + p_utf - p_close - p_right
1206
+
(
p_utf
-
p_right
)
1207
)
^
1
,
1208
}
1209 1210
local
collapse
=
nil
1211
local
serialize
=
table
.
serialize
1212
local
f_state
=
formatters
[
"
level %s : %s : intermediate
"
]
1213 1214
local
function
show_state
(
t
,
level
,
state
)
1215
report_asciimath
(
serialize
(
t
,
f_state
(
level
,
state
)
)
)
1216
end
1217 1218
local
function
show_result
(
original
,
unicoded
,
texcoded
)
1219
report_asciimath
(
"
original > %s
"
,
original
)
1220
report_asciimath
(
"
unicoded > %s
"
,
unicoded
)
1221
report_asciimath
(
"
texcoded > %s
"
,
texcoded
)
1222
end
1223 1224
local
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
-- we have a matrix
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
-- ok
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
1285
end
1286 1287
local
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
-- problem: we can have a proper nesting
1309
local
d
=
false
1310
for
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
1316
end
1317
if
not
d
then
1318
local
tt
=
{
s_lnothing
}
-- space fools final checker
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
-- space fools final checker
1332
m
=
tm
1333
t
=
tt
1334
end
1335
elseif
m
<
n
then
1336
for
i
=
n
,
m
+
1
,
-1
do
1337
t
[
i
]
=
nil
1338
end
1339
end
1340
return
t
1341
end
1342 1343
local
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
]
=
"
"
-- todo: remove
1354
tl
[
#
tl
]
=
nil
1355
end
1356
end
1357
if
type
(
tr
)
=
=
"
table
"
then
1358
if
tn
=
=
"
^
"
then
1359
-- brr 1/(1+x)^2
1360
elseif
isleft
[
tr
[
1
]
]
and
isright
[
tr
[
#
tr
]
]
then
1361
tr
[
1
]
=
"
"
-- todo: remove
1362
tr
[
#
tr
]
=
nil
1363
end
1364
end
1365
i
=
i
+
2
1366
elseif
current
=
=
"
,
"
or
current
=
=
"
;
"
then
1367
-- t[i] = current .. "\\thinspace" -- look sbad in (a,b)
1368
i
=
i
+
1
1369
else
1370
i
=
i
+
1
1371
end
1372
end
1373
return
t
1374
end
1375 1376
local
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
1394
end
1395 1396
local
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
-- t[m] = current .. "\\begingroup" .. one .. "\\endgroup"
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
-- yes?
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
1427
end
1428 1429
local
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
-- m = m + 1
1438
t
[
m
]
=
current
.
.
"
{}
"
-- error
1439
return
t
1440
-- break
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
-- or another sign ? or unary ?
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
-- or another sign ? or unary ?
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
-- yes?
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
1496
end
1497 1498
local
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
.
.
"
{}{}
"
-- error
1508
return
t
1509
-- break
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
.
.
"
}{}
"
1520
return
t
1521
-- break
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
-- yes?
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
1547
end
1548 1549
local
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
)
-- collapse ?
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
1573
end
1574 1575
function
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
-- if type(one) == "table" then
1586
-- if isleft[one[1]] and isright[one[#one]] then
1587
-- remove(one,#one)
1588
-- remove(one,1)
1589
-- end
1590
-- one = collapse(one,level)
1591
-- end
1592
if
second
and
isinfix
[
second
]
then
1593
two
=
t
[
i
+
4
]
1594
-- if type(two) == "table" then
1595
-- if isleft[two[1]] and isright[two[#two]] then
1596
-- remove(two,#two)
1597
-- remove(two,1)
1598
-- end
1599
-- two = collapse(two,level)
1600
-- end
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
-- yes?
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
1632
end
1633 1634
local
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
-- yes?
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
1661
end
1662 1663
local
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
1695
end
1696 1697
local
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
1727
end
1728 1729
local
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
-- \slash
1734
if
i
<
n
and
t
[
i
+
1
]
=
=
"
"
then
1735
-- crap for
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
1763
end
1764 1765
local
function
collapse_result
(
t
)
1766
local
n
=
#
t
1767
if
t
[
1
]
=
=
s_left
and
t
[
n
]
=
=
s_right
then
-- see bar .. space needed there
1768
return
concat
(
t
,
"
"
,
2
,
n
-1
)
1769
else
1770
return
concat
(
t
,
"
"
)
1771
end
1772
end
1773 1774
collapse
=
function
(
t
,
level
)
1775
-- check
1776
if
not
t
then
1777
return
"
"
1778
end
1779
-- tracing
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
-- steps
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
-- done
1803
return
collapse_result
(
t
)
1804
end
1805 1806
-- todo: cache simple ones, say #str < 10, maybe weak
1807 1808
local
context
=
context
1809
local
ctx_mathematics
=
context
and
context
.
mathematics
or
report_asciimath
1810
local
ctx_type
=
context
and
context
.
type
or
function
(
)
end
1811
local
ctx_inleft
=
context
and
context
.
inleft
or
function
(
)
end
1812 1813
local
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
1824
end
1825 1826
local
n
=
0
1827
local
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
-- faster:
1834
--
1835
-- local p = (
1836
-- (S("{[(") + P("\\left" )) * Cc(function() n = n + 1 end)
1837
-- + (S("}])") + P("\\right")) * Cc(function() n = n - 1 end)
1838
-- + p_utf_base
1839
-- )^0
1840 1841
local
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
1851
end
1852 1853
local
collected
=
{
}
1854
local
indexed
=
{
}
1855 1856
-- bonus
1857 1858
local
p_reserved_spaced
=
1859
C
(
lpeg
.
utfchartabletopattern
(
k_reserved_words
)
)
/
"
%1
"
1860 1861
local
p_text
=
1862
C
(
P
(
"
text
"
)
)
/
"
%1
"
1863
*
p_spaces
^
0
1864
*
(
-- maybe balanced
1865
(
P
(
"
{
"
)
*
(
1
-
P
(
"
}
"
)
)
^
0
*
P
(
"
}
"
)
)
1866
+
(
P
(
"
(
"
)
*
(
1
-
P
(
"
)
"
)
)
^
0
*
P
(
"
)
"
)
)
1867
)
1868
+
patterns
.
doublequoted
1869 1870
local
p_expand
=
Cs
(
(
p_text
+
p_reserved_spaced
+
p_utf_base
)
^
0
)
1871
local
p_compress
=
patterns
.
collapser
1872 1873
local
function
cleanedup
(
str
)
1874
return
lpegmatch
(
p_compress
,
lpegmatch
(
p_expand
,
str
)
)
or
str
1875
end
1876 1877
-- so far
1878 1879
local
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
1904
end
1905 1906
local
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
1913
end
1914 1915
function
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
1947
end
1948 1949
function
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
1962
end
1963 1964
asciimath
.
convert
=
convert
1965
asciimath
.
reserved
=
reserved
1966
asciimath
.
collect
=
collect
1967
asciimath
.
filter
=
filter
1968
asciimath
.
invalidtex
=
invalidtex
1969
asciimath
.
cleanedup
=
cleanedup
1970 1971
-- sin(x) = 1 : 3.3 uncached 1.2 cached , so no real gain (better optimize the converter then)
1972 1973
local
uncrapped
=
{
1974
[
"
%
"
]
=
"
\\mathpercent
"
,
1975
[
"
&
"
]
=
"
\\mathampersand
"
,
1976
[
"
#
"
]
=
"
\\mathhash
"
,
1977
[
"
$
"
]
=
"
\\mathdollar
"
,
1978
[
"
^
"
]
=
"
\\Hat{\\enspace}
"
,
-- terrible hack ... tex really does it sbest to turn any ^ into a superscript
1979
[
"
_
"
]
=
"
\\underline{\\enspace}
"
,
1980
}
1981 1982
local
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
2007
end
2008 2009
local
context
=
context
2010 2011
if
not
context
then
2012 2013
-- trace_mapping = true
2014
-- trace_details = true
2015 2016
-- report_asciimath(cleanedup([[ac+sinx+xsqrtx+sinsqrtx+sinsqrt(x)]]))
2017
-- report_asciimath(cleanedup([[a "αsinsqrtx" b]]))
2018
-- convert([[a "αsinsqrtx" b]])
2019
-- report_asciimath(cleanedup([[a "α" b]]))
2020
-- report_asciimath(cleanedup([[//4]]))
2021 2022
-- convert("leq\\leq")
2023
-- convert([[\^{1/5}log]])
2024
-- convert("sqrt")
2025
-- convert("^")
2026 2027
-- convert[[\frac{a}{b}]]
2028
-- convert[[frac{a}{b}]]
2029 2030
-- convert("frac{a}{b}")
2031
-- convert("\\sin{a}{b}")
2032
-- convert("sin{a}{b}")
2033
-- convert("1: rightarrow")
2034
-- convert("2: \\rightarrow")
2035 2036
-- convert("((1,2,3),(4,5,6),(7,8,9))")
2037 2038
-- convert("1/(t+x)^2")
2039 2040
-- convert("AA a > 0 ^^ b > 0 | {:log_g:} a + {:log_g:} b")
2041
-- convert("AA a &gt; 0 ^^ b > 0 | {:log_g:} a + {:log_g:} b")
2042 2043
-- convert("10000,00001")
2044
-- convert("4/18*100text(%)~~22,2")
2045
-- convert("4/18*100text(%)≈22,2")
2046
-- convert("62541/(197,6)≈316,05")
2047 2048
-- convert([[sum x]])
2049
-- convert([[sum^(1)_(2) x]])
2050
-- convert([[lim_(1)^(2) x]])
2051
-- convert([[lim_(1) x]])
2052
-- convert([[lim^(2) x]])
2053 2054
-- convert([[{: rangle]])
2055
-- convert([[\langle\larr]])
2056
-- convert([[langlelarr]])
2057
-- convert([[D_f=[0 ,→〉]])
2058
-- convert([[ac+sinx+xsqrtx]])
2059
-- convert([[ac+\alpha x+xsqrtx-cc b*pi**psi-3alephx / bb X]])
2060
-- convert([[ac+\ ^ x+xsqrtx]])
2061
-- convert([[d/dx(x^2+1)]])
2062
-- convert([[a "αsinsqrtx" b]])
2063
-- convert([[a "α" b]])
2064
-- convert([[//4]])
2065
-- convert([[ {(a+b,=,1),(a+b,=,7)) ]])
2066 2067
-- convert([[ 2/a // 5/b = (2 b) / ( a b) // ( 5 a ) / ( a b ) = (2 b ) / ( 5 a ) ]])
2068
-- convert([[ (2+x)/a // 5/b ]])
2069 2070
-- convert([[ ( 2/a ) // ( 5/b ) = ( (2 b) / ( a b) ) // ( ( 5 a ) / ( a b ) ) = (2 b ) / ( 5 a ) ]])
2071 2072
-- convert([[ (x/y)^3 = x^3/y^3 ]])
2073 2074
-- convert([[ {: (1,2) :} ]])
2075
-- convert([[ {: (a+b,=,1),(a+b,=,7) :} ]])
2076
-- convert([[ { (a+b,=,1),(a+b,=,7) :} ]])
2077
-- convert([[ {: (a+b,=,1),(a+b,=,7) } ]])
2078
-- convert([[ { (a+b,=,1),(a+b,=,7) } ]])
2079 2080
-- convert([[(1,5 ±sqrt(1,25 ),0 )]])
2081
-- convert([[1//2]])
2082
-- convert([[(p)/sqrt(p)]])
2083
-- convert([[u_tot]])
2084
-- convert([[u_tot=4,4 L+0,054 T]])
2085 2086
-- convert([[ [←;0,2] ]])
2087
-- convert([[ [←;0,2⟩ ]])
2088
-- convert([[ ⟨←;0,2 ) ]])
2089
-- convert([[ ⟨←;0,2 ] ]])
2090
-- convert([[ ⟨←;0,2⟩ ]])
2091 2092
-- convert([[ x^2(x-1/16)=0 ]])
2093
-- convert([[ y = ax + 3 - 3a ]])
2094
-- convert([[ y= ((1/4)) ^x ]])
2095
-- convert([[ x=\ ^ (1/4) log(0 ,002 )= log(0,002) / (log(1/4) ]])
2096
-- convert([[ x=\ ^glog(y) ]])
2097
-- convert([[ x^ (-1 1/2) =1/x^ (1 1/2)=1/ (x^1*x^ (1/2)) =1/ (xsqrt(x)) ]])
2098
-- convert([[ x^2(10 -x)&gt;2 x^2 ]])
2099
-- convert([[ x^4&gt;x ]])
2100 2101
return
2102 2103
end
2104 2105
interfaces
.
implement
{
2106
name
=
"
asciimath
"
,
2107
actions
=
convert
,
2108
arguments
=
"
string
"
2109
}
2110 2111
interfaces
.
implement
{
2112
name
=
"
justasciimath
"
,
2113
actions
=
convert
,
2114
arguments
=
{
"
string
"
,
true
}
,
2115
}
2116 2117
interfaces
.
implement
{
2118
name
=
"
xmlasciimath
"
,
2119
actions
=
function
(
id
)
2120
convert
(
xmlpure
(
lxmlgetid
(
id
)
)
)
2121
end
,
2122
arguments
=
"
string
"
2123
}
2124 2125
local
ctx_typebuffer
=
context
.
typebuffer
2126
local
ctx_mathematics
=
context
.
mathematics
2127
local
ctx_color
=
context
.
color
2128 2129
local
sequenced
=
table
.
sequenced
2130
local
assign_buffer
=
buffers
.
assign
2131 2132
local
show
=
{
}
2133
asciimath
.
show
=
show
2134 2135
local
collected
,
indexed
,
ignored
=
{
}
,
{
}
,
{
}
2136 2137
local
color
=
{
"
darkred
"
}
2138 2139
function
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
2147
end
2148 2149
function
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
2161
end
2162 2163
local
h
=
{
}
2164
local
am
=
{
"
am
"
}
2165 2166
function
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
)
2179
end
2180 2181
function
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
2192
end
2193 2194
function
show
.
files
(
n
)
2195
context
(
sequenced
(
collected
[
indexed
[
n
]
]
.
files
,
"
"
)
)
2196
end
2197 2198
function
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
)
2205
end
2206 2207
function
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
2216
end
2217 2218
function
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
2224
end
2225 2226
function
show
.
filter
(
id
,
element
)
2227
collected
,
indexed
,
ignored
=
{
}
,
{
}
,
{
}
2228
asciimath
.
filter
(
lxmlgetid
(
id
)
,
element
or
"
am
"
,
collected
,
indexed
)
2229
end
2230 2231
function
show
.
max
(
)
2232
context
(
#
indexed
)
2233
end
2234 2235
function
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
(
)
2270
end
2271 2272
function
show
.
save
(
name
)
2273
table
.
save
(
name
~
=
"
"
and
name
or
"
dummy.lua
"
,
collected
)
2274
end
2275