asciimath 1.0.9 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/AST.adoc +457 -0
- data/CHANGELOG.adoc +12 -0
- data/Gemfile.lock +39 -0
- data/README.adoc +27 -3
- data/asciimath.gemspec +9 -5
- data/lib/asciimath.rb +5 -4
- data/lib/asciimath/ast.rb +456 -0
- data/lib/asciimath/cli.rb +4 -1
- data/lib/asciimath/color_table.rb +21 -0
- data/lib/asciimath/html.rb +126 -111
- data/lib/asciimath/latex.rb +386 -0
- data/lib/asciimath/markup.rb +478 -0
- data/lib/asciimath/mathml.rb +189 -87
- data/lib/asciimath/parser.rb +498 -343
- data/lib/asciimath/symbol_table.rb +25 -0
- data/lib/asciimath/version.rb +1 -1
- data/spec/ast.rb +144 -0
- data/spec/parser_spec.rb +592 -165
- data/spec/schema/mathml2/common/common-attribs.xsd +41 -0
- data/spec/schema/mathml2/common/math.xsd +126 -0
- data/spec/schema/mathml2/common/xlink-href.xsd +20 -0
- data/spec/schema/mathml2/content/arith.xsd +90 -0
- data/spec/schema/mathml2/content/calculus.xsd +146 -0
- data/spec/schema/mathml2/content/common-attrib.xsd +30 -0
- data/spec/schema/mathml2/content/constants.xsd +83 -0
- data/spec/schema/mathml2/content/constructs.xsd +260 -0
- data/spec/schema/mathml2/content/elementary-functions.xsd +117 -0
- data/spec/schema/mathml2/content/functions.xsd +73 -0
- data/spec/schema/mathml2/content/linear-algebra.xsd +173 -0
- data/spec/schema/mathml2/content/logic.xsd +53 -0
- data/spec/schema/mathml2/content/relations.xsd +55 -0
- data/spec/schema/mathml2/content/semantics.xsd +85 -0
- data/spec/schema/mathml2/content/sets.xsd +236 -0
- data/spec/schema/mathml2/content/statistics.xsd +136 -0
- data/spec/schema/mathml2/content/tokens.xsd +120 -0
- data/spec/schema/mathml2/content/vector-calculus.xsd +88 -0
- data/spec/schema/mathml2/mathml2.xsd +59 -0
- data/spec/schema/mathml2/presentation/action.xsd +44 -0
- data/spec/schema/mathml2/presentation/characters.xsd +37 -0
- data/spec/schema/mathml2/presentation/common-attribs.xsd +113 -0
- data/spec/schema/mathml2/presentation/common-types.xsd +103 -0
- data/spec/schema/mathml2/presentation/error.xsd +40 -0
- data/spec/schema/mathml2/presentation/layout.xsd +195 -0
- data/spec/schema/mathml2/presentation/scripts.xsd +186 -0
- data/spec/schema/mathml2/presentation/space.xsd +52 -0
- data/spec/schema/mathml2/presentation/style.xsd +69 -0
- data/spec/schema/mathml2/presentation/table.xsd +216 -0
- data/spec/schema/mathml2/presentation/tokens.xsd +124 -0
- data/spec/schema/mathml3/mathml3-common.xsd +99 -0
- data/spec/schema/mathml3/mathml3-content.xsd +684 -0
- data/spec/schema/mathml3/mathml3-presentation.xsd +2151 -0
- data/spec/schema/mathml3/mathml3-strict-content.xsd +186 -0
- data/spec/schema/mathml3/mathml3.xsd +9 -0
- metadata +102 -10
- data/.gitignore +0 -16
- data/.travis.yml +0 -18
data/lib/asciimath/mathml.rb
CHANGED
@@ -1,8 +1,20 @@
|
|
1
|
+
require_relative 'markup'
|
2
|
+
require_relative 'symbol_table'
|
3
|
+
|
1
4
|
module AsciiMath
|
2
|
-
class MathMLBuilder
|
3
|
-
|
4
|
-
|
5
|
+
class MathMLBuilder < ::AsciiMath::MarkupBuilder
|
6
|
+
|
7
|
+
def initialize(opts = {})
|
8
|
+
super(opts[:symbol_table] || DEFAULT_DISPLAY_SYMBOL_TABLE)
|
9
|
+
@prefix = opts[:prefix] || ''
|
5
10
|
@mathml = ''
|
11
|
+
if opts[:msword]
|
12
|
+
@row_mode = :force
|
13
|
+
@fence_mode = :fenced
|
14
|
+
else
|
15
|
+
@row_mode = :avoid
|
16
|
+
@fence_mode = :row
|
17
|
+
end
|
6
18
|
end
|
7
19
|
|
8
20
|
def to_s
|
@@ -11,78 +23,150 @@ module AsciiMath
|
|
11
23
|
|
12
24
|
def append_expression(expression, attrs = {})
|
13
25
|
math('', attrs) do
|
14
|
-
append(expression, :
|
26
|
+
append(expression, :row => :omit)
|
15
27
|
end
|
16
28
|
end
|
17
29
|
|
18
30
|
private
|
19
31
|
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
32
|
+
def append_row(expressions)
|
33
|
+
mrow do
|
34
|
+
expressions.each { |e| append(e) }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def append_operator(operator)
|
39
|
+
mo(operator)
|
40
|
+
end
|
41
|
+
|
42
|
+
def append_identifier(identifier)
|
43
|
+
mi(identifier)
|
44
|
+
end
|
45
|
+
|
46
|
+
def append_text(text)
|
47
|
+
mtext(text)
|
48
|
+
end
|
49
|
+
|
50
|
+
def append_number(number)
|
51
|
+
mn(number)
|
52
|
+
end
|
53
|
+
|
54
|
+
def append_sqrt(expression)
|
55
|
+
tag("m#{"sqrt"}") do
|
56
|
+
append(expression, :row => @row_mode)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def append_cancel(expression)
|
61
|
+
tag("menclose", :notation => "updiagonalstrike") do
|
62
|
+
append(expression, :row => :omit)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def append_root(base, index)
|
67
|
+
tag("m#{"root"}") do
|
68
|
+
append(base, :row => @row_mode)
|
69
|
+
append(index, :row => @row_mode)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def append_fraction(numerator, denominator)
|
74
|
+
tag("m#{"frac"}") do
|
75
|
+
append(numerator, :row => @row_mode)
|
76
|
+
append(denominator, :row => @row_mode)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
def append_font(style, e)
|
82
|
+
tag("mstyle", :mathvariant => style.to_s.gsub('_', '-')) do
|
83
|
+
append(e)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def append_color(color, e)
|
88
|
+
tag("mstyle", :mathcolor => color) do
|
89
|
+
append(e)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def append_matrix(lparen, rows, rparen)
|
94
|
+
fenced(lparen, rparen) do
|
95
|
+
mtable do
|
96
|
+
rows.each do |row|
|
97
|
+
mtr do
|
98
|
+
row.each do |col|
|
99
|
+
mtd do
|
100
|
+
append(col)
|
83
101
|
end
|
84
102
|
end
|
103
|
+
end
|
85
104
|
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def append_operator_unary(operator, expression)
|
110
|
+
mrow do
|
111
|
+
mo(operator)
|
112
|
+
append(expression, :row => @row_mode)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def append_identifier_unary(identifier, expression)
|
117
|
+
mrow do
|
118
|
+
mi(identifier)
|
119
|
+
append(expression, :row => @row_mode)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def append_paren(lparen, e, rparen, opts = {})
|
124
|
+
fenced(lparen, rparen) do
|
125
|
+
append(e, :row => @row_mode)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def append_subsup(base, sub, sup)
|
130
|
+
if sub && sup
|
131
|
+
msubsup do
|
132
|
+
append(base, :row => @row_mode)
|
133
|
+
append(sub, :row => @row_mode)
|
134
|
+
append(sup, :row => @row_mode)
|
135
|
+
end
|
136
|
+
elsif sub
|
137
|
+
msub do
|
138
|
+
append(base, :row => @row_mode)
|
139
|
+
append(sub, :row => @row_mode)
|
140
|
+
end
|
141
|
+
elsif sup
|
142
|
+
msup do
|
143
|
+
append(base, :row => @row_mode)
|
144
|
+
append(sup, :row => @row_mode)
|
145
|
+
end
|
146
|
+
else
|
147
|
+
append(base)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def append_underover(base, sub, sup)
|
152
|
+
if sub && sup
|
153
|
+
munderover do
|
154
|
+
append(base, :row => @row_mode)
|
155
|
+
append(sub, :row => @row_mode)
|
156
|
+
append(sup, :row => @row_mode)
|
157
|
+
end
|
158
|
+
elsif sub
|
159
|
+
munder do
|
160
|
+
append(base, :row => @row_mode)
|
161
|
+
append(sub, :row => @row_mode)
|
162
|
+
end
|
163
|
+
elsif sup
|
164
|
+
mover do
|
165
|
+
append(base, :row => @row_mode)
|
166
|
+
append(sup, :row => @row_mode)
|
167
|
+
end
|
168
|
+
else
|
169
|
+
append(base)
|
86
170
|
end
|
87
171
|
end
|
88
172
|
|
@@ -90,10 +174,18 @@ module AsciiMath
|
|
90
174
|
tag(meth, *args, &block)
|
91
175
|
end
|
92
176
|
|
93
|
-
def fenced(lparen, rparen
|
177
|
+
def fenced(lparen, rparen)
|
94
178
|
if lparen || rparen
|
95
|
-
|
96
|
-
|
179
|
+
if @fence_mode == :fenced
|
180
|
+
mfenced(:open => lparen || '', :close => rparen || '') do
|
181
|
+
yield self
|
182
|
+
end
|
183
|
+
else
|
184
|
+
mrow do
|
185
|
+
mo(lparen) if lparen
|
186
|
+
yield self
|
187
|
+
mo(rparen) if rparen
|
188
|
+
end
|
97
189
|
end
|
98
190
|
else
|
99
191
|
yield self
|
@@ -102,41 +194,51 @@ module AsciiMath
|
|
102
194
|
|
103
195
|
def tag(tag, *args)
|
104
196
|
attrs = args.last.is_a?(Hash) ? args.pop : {}
|
105
|
-
text = args.last.is_a?(String) ? args.pop : ''
|
197
|
+
text = args.last.is_a?(String) || args.last.is_a?(Symbol) ? args.pop.to_s : ''
|
106
198
|
|
107
199
|
@mathml << '<' << @prefix << tag.to_s
|
108
200
|
|
109
201
|
attrs.each_pair do |key, value|
|
110
|
-
@mathml << ' ' << key.to_s << '="'
|
202
|
+
@mathml << ' ' << key.to_s << '="'
|
203
|
+
append_escaped(value.to_s)
|
204
|
+
@mathml << '"'
|
111
205
|
end
|
112
206
|
|
113
207
|
|
114
208
|
if block_given? || text
|
115
209
|
@mathml << '>'
|
116
|
-
text
|
117
|
-
if cp == 38
|
118
|
-
@mathml << "&"
|
119
|
-
elsif cp == 60
|
120
|
-
@mathml << "<"
|
121
|
-
elsif cp == 62
|
122
|
-
@mathml << ">"
|
123
|
-
elsif cp > 127
|
124
|
-
@mathml << "&#x#{cp.to_s(16).upcase};"
|
125
|
-
else
|
126
|
-
@mathml << cp
|
127
|
-
end
|
128
|
-
end
|
210
|
+
append_escaped(text)
|
129
211
|
yield self if block_given?
|
130
212
|
@mathml << '</' << @prefix << tag.to_s << '>'
|
131
213
|
else
|
132
214
|
@mathml << '/>'
|
133
215
|
end
|
134
216
|
end
|
217
|
+
|
218
|
+
def append_escaped(text)
|
219
|
+
text.each_codepoint do |cp|
|
220
|
+
if cp == 38
|
221
|
+
@mathml << "&"
|
222
|
+
elsif cp == 60
|
223
|
+
@mathml << "<"
|
224
|
+
elsif cp == 62
|
225
|
+
@mathml << ">"
|
226
|
+
elsif cp > 127
|
227
|
+
@mathml << "&#x#{cp.to_s(16).upcase};"
|
228
|
+
else
|
229
|
+
@mathml << cp
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
135
233
|
end
|
136
234
|
|
137
235
|
class Expression
|
138
236
|
def to_mathml(prefix = "", attrs = {})
|
139
|
-
|
237
|
+
if prefix.is_a? Hash
|
238
|
+
attrs = prefix
|
239
|
+
prefix = ""
|
240
|
+
end
|
241
|
+
MathMLBuilder.new(:prefix => prefix).append_expression(ast, attrs).to_s
|
140
242
|
end
|
141
243
|
end
|
142
|
-
end
|
244
|
+
end
|
data/lib/asciimath/parser.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
require 'strscan'
|
2
|
+
require_relative 'ast'
|
3
|
+
require_relative 'color_table'
|
4
|
+
require_relative 'symbol_table'
|
2
5
|
|
3
6
|
# Parser for ASCIIMath expressions.
|
4
7
|
#
|
@@ -33,28 +36,18 @@ module AsciiMath
|
|
33
36
|
# The :type key indicates the semantics of the token. The value for :type will be one
|
34
37
|
# of the following symbols:
|
35
38
|
#
|
36
|
-
# - :
|
39
|
+
# - :symbol a symbolic name or a bit of text without any further semantics
|
37
40
|
# - :text a bit of arbitrary text
|
38
41
|
# - :number a number
|
39
42
|
# - :operator a mathematical operator symbol
|
40
43
|
# - :unary a unary operator (e.g., sqrt, text, ...)
|
41
|
-
# - :font a unary font command (e.g., bb, cc, ...)
|
42
44
|
# - :infix an infix operator (e.g, /, _, ^, ...)
|
43
45
|
# - :binary a binary operator (e.g., frac, root, ...)
|
44
|
-
# - :accent an accent character
|
45
46
|
# - :eof indicates no more tokens are available
|
46
47
|
#
|
47
|
-
# Each token type may also have an :underover modifier. When present and set to true
|
48
|
-
# sub- and superscript expressions associated with the token will be rendered as
|
49
|
-
# under- and overscriptabove and below rather than as sub- or superscript.
|
50
|
-
#
|
51
|
-
# :accent tokens additionally have a :postion value which is set to either :over or :under.
|
52
|
-
# This determines if the accent should be rendered over or under the expression to which
|
53
|
-
# it applies.
|
54
|
-
#
|
55
48
|
class Tokenizer
|
56
49
|
WHITESPACE = /\s+/
|
57
|
-
NUMBER =
|
50
|
+
NUMBER = /[0-9]+(?:\.[0-9]+)?/
|
58
51
|
QUOTED_TEXT = /"[^"]*"/
|
59
52
|
TEX_TEXT = /text\([^)]*\)/
|
60
53
|
|
@@ -66,7 +59,7 @@ module AsciiMath
|
|
66
59
|
@string = StringScanner.new(string)
|
67
60
|
@symbols = symbols
|
68
61
|
lookahead = @symbols.keys.map { |k| k.length }.max
|
69
|
-
@symbol_regexp = /([^\s0-9]{1,#{lookahead}})/
|
62
|
+
@symbol_regexp = /((?:\\[\s0-9]|[^\s0-9]){1,#{lookahead}})/
|
70
63
|
@push_back = nil
|
71
64
|
end
|
72
65
|
|
@@ -86,19 +79,19 @@ module AsciiMath
|
|
86
79
|
return {:value => nil, :type => :eof} if @string.eos?
|
87
80
|
|
88
81
|
case @string.peek(1)
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
82
|
+
when '"'
|
83
|
+
read_quoted_text
|
84
|
+
when 't'
|
85
|
+
case @string.peek(5)
|
86
|
+
when 'text('
|
87
|
+
read_tex_text
|
88
|
+
else
|
89
|
+
read_symbol
|
90
|
+
end
|
91
|
+
when '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
|
92
|
+
read_number || read_symbol
|
95
93
|
else
|
96
94
|
read_symbol
|
97
|
-
end
|
98
|
-
when '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
|
99
|
-
read_number || read_symbol
|
100
|
-
else
|
101
|
-
read_symbol
|
102
95
|
end
|
103
96
|
end
|
104
97
|
|
@@ -173,7 +166,12 @@ module AsciiMath
|
|
173
166
|
s.chop!
|
174
167
|
end
|
175
168
|
@string.pos = position + bytesize(s)
|
176
|
-
@symbols[s]
|
169
|
+
symbol = @symbols[s]
|
170
|
+
if symbol
|
171
|
+
symbol.merge({:text => s})
|
172
|
+
else
|
173
|
+
{:value => s, :type => :identifier}
|
174
|
+
end
|
177
175
|
end
|
178
176
|
end
|
179
177
|
|
@@ -185,7 +183,7 @@ module AsciiMath
|
|
185
183
|
# Returns the matched String or the value returned by the block if one was given
|
186
184
|
def read_value(regexp)
|
187
185
|
s = @string.scan(regexp)
|
188
|
-
if s
|
186
|
+
if s && block_given?
|
189
187
|
yield s
|
190
188
|
else
|
191
189
|
s
|
@@ -200,290 +198,333 @@ module AsciiMath
|
|
200
198
|
end
|
201
199
|
|
202
200
|
class Parser
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
201
|
+
def self.add_default_colors(b)
|
202
|
+
b.add('aqua', 0, 255, 255)
|
203
|
+
b.add('black', 0, 0, 0)
|
204
|
+
b.add('blue', 0, 0, 255)
|
205
|
+
b.add('fuchsia', 255, 0, 255)
|
206
|
+
b.add('gray', 128, 128, 128)
|
207
|
+
b.add('green', 0, 128, 0)
|
208
|
+
b.add('lime', 0, 255, 0)
|
209
|
+
b.add('maroon', 128, 0, 0)
|
210
|
+
b.add('navy', 0, 0, 128)
|
211
|
+
b.add('olive', 128, 128, 0)
|
212
|
+
b.add('purple', 128, 0, 128)
|
213
|
+
b.add('red', 255, 0, 0)
|
214
|
+
b.add('silver', 192, 192, 192)
|
215
|
+
b.add('teal', 0, 128, 128)
|
216
|
+
b.add('white', 255, 255, 255)
|
217
|
+
b.add('yellow', 255, 255, 0)
|
218
|
+
b
|
219
|
+
end
|
220
|
+
|
221
|
+
def self.add_default_parser_symbols(b)
|
222
|
+
# Operation symbols
|
223
|
+
b.add('+', :plus, :symbol)
|
224
|
+
b.add('-', :minus, :symbol)
|
225
|
+
b.add('*', 'cdot', :cdot, :symbol)
|
226
|
+
b.add('**', 'ast', :ast, :symbol)
|
227
|
+
b.add('***', 'star', :star, :symbol)
|
228
|
+
b.add('//', :slash, :symbol)
|
229
|
+
b.add('\\\\', 'backslash', :backslash, :symbol)
|
230
|
+
b.add('setminus', :setminus, :symbol)
|
231
|
+
b.add('xx', 'times', :times, :symbol)
|
232
|
+
b.add('|><', 'ltimes', :ltimes, :symbol)
|
233
|
+
b.add('><|', 'rtimes', :rtimes, :symbol)
|
234
|
+
b.add('|><|', 'bowtie', :bowtie, :symbol)
|
235
|
+
b.add('-:', 'div', 'divide', :div, :symbol)
|
236
|
+
b.add('@', 'circ', :circ, :symbol)
|
237
|
+
b.add('o+', 'oplus', :oplus, :symbol)
|
238
|
+
b.add('ox', 'otimes', :otimes, :symbol)
|
239
|
+
b.add('o.', 'odot', :odot, :symbol)
|
240
|
+
b.add('sum', :sum, :symbol)
|
241
|
+
b.add('prod', :prod, :symbol)
|
242
|
+
b.add('^^', 'wedge', :wedge, :symbol)
|
243
|
+
b.add('^^^', 'bigwedge', :bigwedge, :symbol)
|
244
|
+
b.add('vv', 'vee', :vee, :symbol)
|
245
|
+
b.add('vvv', 'bigvee', :bigvee, :symbol)
|
246
|
+
b.add('nn', 'cap', :cap, :symbol)
|
247
|
+
b.add('nnn', 'bigcap', :bigcap, :symbol)
|
248
|
+
b.add('uu', 'cup', :cup, :symbol)
|
249
|
+
b.add('uuu', 'bigcup', :bigcup, :symbol)
|
250
|
+
|
251
|
+
# Relation symbols
|
252
|
+
b.add('=', :eq, :symbol)
|
253
|
+
b.add('!=', 'ne', :ne, :symbol)
|
254
|
+
b.add(':=', :assign, :symbol)
|
255
|
+
b.add('<', 'lt', :lt, :symbol)
|
256
|
+
b.add('>', 'gt', :gt, :symbol)
|
257
|
+
b.add('<=', 'le', :le, :symbol)
|
258
|
+
b.add('>=', 'ge', :ge, :symbol)
|
259
|
+
b.add('-<', '-lt', 'prec', :prec, :symbol)
|
260
|
+
b.add('>-', 'succ', :succ, :symbol)
|
261
|
+
b.add('-<=', 'preceq', :preceq, :symbol)
|
262
|
+
b.add('>-=', 'succeq', :succeq, :symbol)
|
263
|
+
b.add('in', :in, :symbol)
|
264
|
+
b.add('!in', 'notin', :notin, :symbol)
|
265
|
+
b.add('sub', 'subset', :subset, :symbol)
|
266
|
+
b.add('sup', 'supset', :supset, :symbol)
|
267
|
+
b.add('sube', 'subseteq', :subseteq, :symbol)
|
268
|
+
b.add('supe', 'supseteq', :supseteq, :symbol)
|
269
|
+
b.add('-=', 'equiv', :equiv, :symbol)
|
270
|
+
b.add('~=', 'cong', :cong, :symbol)
|
271
|
+
b.add('~~', 'approx', :approx, :symbol)
|
272
|
+
b.add('prop', 'propto', :propto, :symbol)
|
273
|
+
|
274
|
+
# Logical symbols
|
275
|
+
b.add('and', :and, :symbol)
|
276
|
+
b.add('or', :or, :symbol)
|
277
|
+
b.add('not', 'neg', :not, :symbol)
|
278
|
+
b.add('=>', 'implies', :implies, :symbol)
|
279
|
+
b.add('if', :if, :symbol)
|
280
|
+
b.add('<=>', 'iff', :iff, :symbol)
|
281
|
+
b.add('AA', 'forall', :forall, :symbol)
|
282
|
+
b.add('EE', 'exists', :exists, :symbol)
|
283
|
+
b.add('_|_', 'bot', :bot, :symbol)
|
284
|
+
b.add('TT', 'top', :top, :symbol)
|
285
|
+
b.add('|--', 'vdash', :vdash, :symbol)
|
286
|
+
b.add('|==', 'models', :models, :symbol)
|
287
|
+
|
288
|
+
# Grouping brackets
|
289
|
+
b.add('(', 'left(', :lparen, :lparen)
|
290
|
+
b.add(')', 'right)', :rparen, :rparen)
|
291
|
+
b.add('[', 'left[', :lbracket, :lparen)
|
292
|
+
b.add(']', 'right]', :rbracket, :rparen)
|
293
|
+
b.add('{', :lbrace, :lparen)
|
294
|
+
b.add('}', :rbrace, :rparen)
|
295
|
+
b.add('|', :vbar, :lrparen)
|
296
|
+
b.add(':|:', :vbar, :symbol)
|
297
|
+
b.add('|:', :vbar, :lparen)
|
298
|
+
b.add(':|', :vbar, :rparen)
|
299
|
+
# b.add('||', '||', :lrparen)
|
300
|
+
b.add('(:', '<<', 'langle', :langle, :lparen)
|
301
|
+
b.add(':)', '>>', 'rangle', :rangle, :rparen)
|
302
|
+
b.add('{:', nil, :lparen)
|
303
|
+
b.add(':}', nil, :rparen)
|
304
|
+
|
305
|
+
# Miscellaneous symbols
|
306
|
+
b.add('int', :integral, :symbol)
|
307
|
+
b.add('dx', :dx, :symbol)
|
308
|
+
b.add('dy', :dy, :symbol)
|
309
|
+
b.add('dz', :dz, :symbol)
|
310
|
+
b.add('dt', :dt, :symbol)
|
311
|
+
b.add('oint', :contourintegral, :symbol)
|
312
|
+
b.add('del', 'partial', :partial, :symbol)
|
313
|
+
b.add('grad', 'nabla', :nabla, :symbol)
|
314
|
+
b.add('+-', 'pm', :pm, :symbol)
|
315
|
+
b.add('O/', 'emptyset', :emptyset, :symbol)
|
316
|
+
b.add('oo', 'infty', :infty, :symbol)
|
317
|
+
b.add('aleph', :aleph, :symbol)
|
318
|
+
b.add('...', 'ldots', :ellipsis, :symbol)
|
319
|
+
b.add(':.', 'therefore', :therefore, :symbol)
|
320
|
+
b.add(':\'', 'because', :because, :symbol)
|
321
|
+
b.add('/_', 'angle', :angle, :symbol)
|
322
|
+
b.add('/_\\', 'triangle', :triangle, :symbol)
|
323
|
+
b.add('\'', 'prime', :prime, :symbol)
|
324
|
+
b.add('tilde', :tilde, :unary)
|
325
|
+
b.add('\\ ', :nbsp, :symbol)
|
326
|
+
b.add('frown', :frown, :symbol)
|
327
|
+
b.add('quad', :quad, :symbol)
|
328
|
+
b.add('qquad', :qquad, :symbol)
|
329
|
+
b.add('cdots', :cdots, :symbol)
|
330
|
+
b.add('vdots', :vdots, :symbol)
|
331
|
+
b.add('ddots', :ddots, :symbol)
|
332
|
+
b.add('diamond', :diamond, :symbol)
|
333
|
+
b.add('square', :square, :symbol)
|
334
|
+
b.add('|__', 'lfloor', :lfloor, :symbol)
|
335
|
+
b.add('__|', 'rfloor', :rfloor, :symbol)
|
336
|
+
b.add('|~', 'lceiling', :lceiling, :symbol)
|
337
|
+
b.add('~|', 'rceiling', :rceiling, :symbol)
|
338
|
+
b.add('CC', :dstruck_captial_c, :symbol)
|
339
|
+
b.add('NN', :dstruck_captial_n, :symbol)
|
340
|
+
b.add('QQ', :dstruck_captial_q, :symbol)
|
341
|
+
b.add('RR', :dstruck_captial_r, :symbol)
|
342
|
+
b.add('ZZ', :dstruck_captial_z, :symbol)
|
343
|
+
b.add('f', :f, :symbol)
|
344
|
+
b.add('g', :g, :symbol)
|
345
|
+
|
346
|
+
|
347
|
+
# Standard functions
|
348
|
+
b.add('lim', :lim, :symbol)
|
349
|
+
b.add('Lim', :Lim, :symbol)
|
350
|
+
b.add('min', :min, :symbol)
|
351
|
+
b.add('max', :max, :symbol)
|
352
|
+
b.add('sin', :sin, :symbol)
|
353
|
+
b.add('Sin', :Sin, :symbol)
|
354
|
+
b.add('cos', :cos, :symbol)
|
355
|
+
b.add('Cos', :Cos, :symbol)
|
356
|
+
b.add('tan', :tan, :symbol)
|
357
|
+
b.add('Tan', :Tan, :symbol)
|
358
|
+
b.add('sinh', :sinh, :symbol)
|
359
|
+
b.add('Sinh', :Sinh, :symbol)
|
360
|
+
b.add('cosh', :cosh, :symbol)
|
361
|
+
b.add('Cosh', :Cosh, :symbol)
|
362
|
+
b.add('tanh', :tanh, :symbol)
|
363
|
+
b.add('Tanh', :Tanh, :symbol)
|
364
|
+
b.add('cot', :cot, :symbol)
|
365
|
+
b.add('Cot', :Cot, :symbol)
|
366
|
+
b.add('sec', :sec, :symbol)
|
367
|
+
b.add('Sec', :Sec, :symbol)
|
368
|
+
b.add('csc', :csc, :symbol)
|
369
|
+
b.add('Csc', :Csc, :symbol)
|
370
|
+
b.add('arcsin', :arcsin, :symbol)
|
371
|
+
b.add('arccos', :arccos, :symbol)
|
372
|
+
b.add('arctan', :arctan, :symbol)
|
373
|
+
b.add('coth', :coth, :symbol)
|
374
|
+
b.add('sech', :sech, :symbol)
|
375
|
+
b.add('csch', :csch, :symbol)
|
376
|
+
b.add('exp', :exp, :symbol)
|
377
|
+
b.add('abs', :abs, :unary)
|
378
|
+
b.add('Abs', :abs, :unary)
|
379
|
+
b.add('norm', :norm, :unary)
|
380
|
+
b.add('floor', :floor, :unary)
|
381
|
+
b.add('ceil', :ceil, :unary)
|
382
|
+
b.add('log', :log, :symbol)
|
383
|
+
b.add('Log', :Log, :symbol)
|
384
|
+
b.add('ln', :ln, :symbol)
|
385
|
+
b.add('Ln', :Ln, :symbol)
|
386
|
+
b.add('det', :det, :symbol)
|
387
|
+
b.add('dim', :dim, :symbol)
|
388
|
+
b.add('mod', :mod, :symbol)
|
389
|
+
b.add('gcd', :gcd, :symbol)
|
390
|
+
b.add('lcm', :lcm, :symbol)
|
391
|
+
b.add('lub', :lub, :symbol)
|
392
|
+
b.add('glb', :glb, :symbol)
|
393
|
+
|
394
|
+
# Arrows
|
395
|
+
b.add('uarr', 'uparrow', :uparrow, :symbol)
|
396
|
+
b.add('darr', 'downarrow', :downarrow, :symbol)
|
397
|
+
b.add('rarr', 'rightarrow', :rightarrow, :symbol)
|
398
|
+
b.add('->', 'to', :to, :symbol)
|
399
|
+
b.add('>->', 'rightarrowtail', :rightarrowtail, :symbol)
|
400
|
+
b.add('->>', 'twoheadrightarrow', :twoheadrightarrow, :symbol)
|
401
|
+
b.add('>->>', 'twoheadrightarrowtail', :twoheadrightarrowtail, :symbol)
|
402
|
+
b.add('|->', 'mapsto', :mapsto, :symbol)
|
403
|
+
b.add('larr', 'leftarrow', :leftarrow, :symbol)
|
404
|
+
b.add('harr', 'leftrightarrow', :leftrightarrow, :symbol)
|
405
|
+
b.add('rArr', 'Rightarrow', :Rightarrow, :symbol)
|
406
|
+
b.add('lArr', 'Leftarrow', :Leftarrow, :symbol)
|
407
|
+
b.add('hArr', 'Leftrightarrow', :Leftrightarrow, :symbol)
|
408
|
+
|
409
|
+
# Other
|
410
|
+
b.add('sqrt', :sqrt, :unary)
|
411
|
+
b.add('root', :root, :binary)
|
412
|
+
b.add('frac', :frac, :binary)
|
413
|
+
b.add('/', :frac, :infix)
|
414
|
+
b.add('stackrel', :stackrel, :binary)
|
415
|
+
b.add('overset', :overset, :binary)
|
416
|
+
b.add('underset', :underset, :binary)
|
417
|
+
b.add('color', :color, :binary, :convert_operand1 => ::AsciiMath::Parser.instance_method(:convert_to_color))
|
418
|
+
b.add('_', :sub, :infix)
|
419
|
+
b.add('^', :sup, :infix)
|
420
|
+
b.add('hat', :hat, :unary)
|
421
|
+
b.add('bar', :overline, :unary)
|
422
|
+
b.add('vec', :vec, :unary)
|
423
|
+
b.add('dot', :dot, :unary)
|
424
|
+
b.add('ddot', :ddot, :unary)
|
425
|
+
b.add('overarc', 'overparen', :overarc, :unary)
|
426
|
+
b.add('ul', 'underline', :underline, :unary)
|
427
|
+
b.add('ubrace', 'underbrace', :underbrace, :unary)
|
428
|
+
b.add('obrace', 'overbrace', :overbrace, :unary)
|
429
|
+
b.add('cancel', :cancel, :unary)
|
430
|
+
b.add('bb', :bold, :unary)
|
431
|
+
b.add('bbb', :double_struck, :unary)
|
432
|
+
b.add('ii', :italic, :unary)
|
433
|
+
b.add('bii', :bold_italic, :unary)
|
434
|
+
b.add('cc', :script, :unary)
|
435
|
+
b.add('bcc', :bold_script, :unary)
|
436
|
+
b.add('tt', :monospace, :unary)
|
437
|
+
b.add('fr', :fraktur, :unary)
|
438
|
+
b.add('bfr', :bold_fraktur, :unary)
|
439
|
+
b.add('sf', :sans_serif, :unary)
|
440
|
+
b.add('bsf', :bold_sans_serif, :unary)
|
441
|
+
b.add('sfi', :sans_serif_italic, :unary)
|
442
|
+
b.add('sfbi', :sans_serif_bold_italic, :unary)
|
443
|
+
|
444
|
+
# Greek letters
|
445
|
+
b.add('alpha', :alpha, :symbol)
|
446
|
+
b.add('Alpha', :Alpha, :symbol)
|
447
|
+
b.add('beta', :beta, :symbol)
|
448
|
+
b.add('Beta', :Beta, :symbol)
|
449
|
+
b.add('gamma', :gamma, :symbol)
|
450
|
+
b.add('Gamma', :Gamma, :symbol)
|
451
|
+
b.add('delta', :delta, :symbol)
|
452
|
+
b.add('Delta', :Delta, :symbol)
|
453
|
+
b.add('epsi', 'epsilon', :epsilon, :symbol)
|
454
|
+
b.add('Epsilon', :Epsilon, :symbol)
|
455
|
+
b.add('varepsilon', :varepsilon, :symbol)
|
456
|
+
b.add('zeta', :zeta, :symbol)
|
457
|
+
b.add('Zeta', :Zeta, :symbol)
|
458
|
+
b.add('eta', :eta, :symbol)
|
459
|
+
b.add('Eta', :Eta, :symbol)
|
460
|
+
b.add('theta', :theta, :symbol)
|
461
|
+
b.add('Theta', :Theta, :symbol)
|
462
|
+
b.add('vartheta', :vartheta, :symbol)
|
463
|
+
b.add('iota', :iota, :symbol)
|
464
|
+
b.add('Iota', :Iota, :symbol)
|
465
|
+
b.add('kappa', :kappa, :symbol)
|
466
|
+
b.add('Kappa', :Kappa, :symbol)
|
467
|
+
b.add('lambda', :lambda, :symbol)
|
468
|
+
b.add('Lambda', :Lambda, :symbol)
|
469
|
+
b.add('mu', :mu, :symbol)
|
470
|
+
b.add('Mu', :Mu, :symbol)
|
471
|
+
b.add('nu', :nu, :symbol)
|
472
|
+
b.add('Nu', :Nu, :symbol)
|
473
|
+
b.add('xi', :xi, :symbol)
|
474
|
+
b.add('Xi', :Xi, :symbol)
|
475
|
+
b.add('omicron', :omicron, :symbol)
|
476
|
+
b.add('Omicron', :Omicron, :symbol)
|
477
|
+
b.add('pi', :pi, :symbol)
|
478
|
+
b.add('Pi', :Pi, :symbol)
|
479
|
+
b.add('rho', :rho, :symbol)
|
480
|
+
b.add('Rho', :Rho, :symbol)
|
481
|
+
b.add('sigma', :sigma, :symbol)
|
482
|
+
b.add('Sigma', :Sigma, :symbol)
|
483
|
+
b.add('tau', :tau, :symbol)
|
484
|
+
b.add('Tau', :Tau, :symbol)
|
485
|
+
b.add('upsilon', :upsilon, :symbol)
|
486
|
+
b.add('Upsilon', :Upsilon, :symbol)
|
487
|
+
b.add('phi', :phi, :symbol)
|
488
|
+
b.add('Phi', :Phi, :symbol)
|
489
|
+
b.add('varphi', :varphi, :symbol)
|
490
|
+
b.add('chi', :chi, :symbol)
|
491
|
+
b.add('Chi', :Chi, :symbol)
|
492
|
+
b.add('psi', :psi, :symbol)
|
493
|
+
b.add('Psi', :Psi, :symbol)
|
494
|
+
b.add('omega', :omega, :symbol)
|
495
|
+
b.add('Omega', :Omega, :symbol)
|
496
|
+
|
497
|
+
b
|
498
|
+
end
|
499
|
+
|
500
|
+
def initialize(symbol_table, color_table)
|
501
|
+
@symbol_table = symbol_table
|
502
|
+
@color_table = color_table
|
503
|
+
end
|
458
504
|
|
459
505
|
def parse(input)
|
460
506
|
Expression.new(
|
461
507
|
input,
|
462
|
-
parse_expression(Tokenizer.new(input,
|
508
|
+
parse_expression(Tokenizer.new(input, @symbol_table), 0)
|
463
509
|
)
|
464
510
|
end
|
465
511
|
|
466
512
|
private
|
513
|
+
|
514
|
+
include AsciiMath::AST
|
515
|
+
|
467
516
|
def parse_expression(tok, depth)
|
468
517
|
e = []
|
469
518
|
|
470
|
-
while (s1 =
|
519
|
+
while (s1 = parse_intermediate_expression(tok, depth))
|
471
520
|
t1 = tok.next_token
|
472
521
|
|
473
|
-
if t1[:type] == :infix
|
474
|
-
s2 =
|
475
|
-
|
476
|
-
|
477
|
-
s3 = parse_simple_expression(tok, depth)
|
478
|
-
operator = s1[:underover] ? :underover : :subsup
|
479
|
-
e << {:type => :ternary, :operator => operator, :s1 => s1, :s2 => s2, :s3 => s3}
|
522
|
+
if t1[:type] == :infix && t1[:value] == :frac
|
523
|
+
s2 = parse_intermediate_expression(tok, depth)
|
524
|
+
if s2
|
525
|
+
e << infix(unwrap_paren(s1), symbol(:frac, t1[:text]), unwrap_paren(s2))
|
480
526
|
else
|
481
|
-
|
482
|
-
e << {:type => :binary, :operator => operator, :s1 => s1, :s2 => s2}
|
483
|
-
tok.push_back(t2)
|
484
|
-
if (t2[:type] == :lrparen || t2[:type] == :rparen) && depth > 0
|
485
|
-
break
|
486
|
-
end
|
527
|
+
e << s1
|
487
528
|
end
|
488
529
|
elsif t1[:type] == :eof
|
489
530
|
e << s1
|
@@ -497,7 +538,46 @@ module AsciiMath
|
|
497
538
|
end
|
498
539
|
end
|
499
540
|
|
500
|
-
e
|
541
|
+
expression(*e)
|
542
|
+
end
|
543
|
+
|
544
|
+
def parse_intermediate_expression(tok, depth)
|
545
|
+
s = parse_simple_expression(tok, depth)
|
546
|
+
sub = nil
|
547
|
+
sup = nil
|
548
|
+
|
549
|
+
t1 = tok.next_token
|
550
|
+
case t1[:type]
|
551
|
+
when :infix
|
552
|
+
case t1[:value]
|
553
|
+
when :sub
|
554
|
+
sub = parse_simple_expression(tok, depth)
|
555
|
+
if sub
|
556
|
+
t2 = tok.next_token
|
557
|
+
if t2[:type] == :infix && t2[:value] == :sup
|
558
|
+
sup = parse_simple_expression(tok, depth)
|
559
|
+
else
|
560
|
+
tok.push_back(t2)
|
561
|
+
end
|
562
|
+
end
|
563
|
+
when :sup
|
564
|
+
sup = parse_simple_expression(tok, depth)
|
565
|
+
else
|
566
|
+
tok.push_back(t1)
|
567
|
+
end
|
568
|
+
else
|
569
|
+
tok.push_back(t1)
|
570
|
+
end
|
571
|
+
|
572
|
+
if sub && sup
|
573
|
+
subsup(s, unwrap_paren(sub), unwrap_paren(sup))
|
574
|
+
elsif sub
|
575
|
+
sub(s, unwrap_paren(sub))
|
576
|
+
elsif sup
|
577
|
+
sup(s, unwrap_paren(sup))
|
578
|
+
else
|
579
|
+
s
|
580
|
+
end
|
501
581
|
end
|
502
582
|
|
503
583
|
def parse_simple_expression(tok, depth)
|
@@ -508,7 +588,7 @@ module AsciiMath
|
|
508
588
|
t2 = tok.next_token
|
509
589
|
case t2[:type]
|
510
590
|
when :rparen, :lrparen
|
511
|
-
|
591
|
+
paren(token_to_symbol(t1), nil, token_to_symbol(t2))
|
512
592
|
else
|
513
593
|
tok.push_back(t2)
|
514
594
|
|
@@ -517,43 +597,76 @@ module AsciiMath
|
|
517
597
|
t2 = tok.next_token
|
518
598
|
case t2[:type]
|
519
599
|
when :rparen, :lrparen
|
520
|
-
convert_to_matrix(
|
600
|
+
convert_to_matrix(paren(token_to_symbol(t1), e, token_to_symbol(t2)))
|
521
601
|
else
|
522
602
|
tok.push_back(t2)
|
523
|
-
|
603
|
+
paren(token_to_symbol(t1), e, nil)
|
524
604
|
end
|
525
605
|
end
|
526
|
-
when :
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
606
|
+
when :rparen
|
607
|
+
if depth > 0
|
608
|
+
tok.push_back(t1)
|
609
|
+
nil
|
610
|
+
else
|
611
|
+
token_to_symbol(t1)
|
612
|
+
end
|
613
|
+
when :unary
|
614
|
+
s = unwrap_paren(parse_simple_expression(tok, depth))
|
615
|
+
s = convert_node(s, t1[:convert_operand])
|
616
|
+
unary(token_to_symbol(t1), s)
|
532
617
|
when :binary
|
533
|
-
s1 = parse_simple_expression(tok, depth)
|
534
|
-
s2 = parse_simple_expression(tok, depth)
|
535
|
-
|
618
|
+
s1 = unwrap_paren(parse_simple_expression(tok, depth))
|
619
|
+
s2 = unwrap_paren(parse_simple_expression(tok, depth))
|
620
|
+
|
621
|
+
s1 = convert_node(s1, t1[:convert_operand1])
|
622
|
+
s2 = convert_node(s2, t1[:convert_operand2])
|
623
|
+
|
624
|
+
binary(token_to_symbol(t1), s1, s2)
|
536
625
|
when :eof
|
537
626
|
nil
|
627
|
+
when :number
|
628
|
+
number(t1[:value])
|
629
|
+
when :text
|
630
|
+
text(t1[:value])
|
631
|
+
when :identifier
|
632
|
+
identifier(t1[:value])
|
538
633
|
else
|
539
|
-
|
634
|
+
token_to_symbol(t1)
|
635
|
+
end
|
636
|
+
end
|
637
|
+
|
638
|
+
def token_to_symbol(t1)
|
639
|
+
symbol(t1[:value], t1[:text])
|
640
|
+
end
|
641
|
+
|
642
|
+
def unwrap_paren(node)
|
643
|
+
if node.is_a?(::AsciiMath::AST::Paren)
|
644
|
+
group(node.lparen, node.expression, node.rparen)
|
645
|
+
else
|
646
|
+
node
|
540
647
|
end
|
541
648
|
end
|
542
649
|
|
543
|
-
def convert_to_matrix(
|
544
|
-
return
|
650
|
+
def convert_to_matrix(node)
|
651
|
+
return node unless node.is_a?(::AsciiMath::AST::Paren) && node.expression.is_a?(::AsciiMath::AST::Sequence)
|
545
652
|
|
546
|
-
rows, separators = expression
|
547
|
-
return
|
653
|
+
rows, separators = node.expression.partition.with_index { |obj, i| i.even? }
|
654
|
+
return node unless rows.length > 1 &&
|
548
655
|
rows.length > separators.length &&
|
549
656
|
separators.all? { |item| is_matrix_separator(item) } &&
|
550
|
-
(rows.all? { |item| item
|
551
|
-
rows.all? { |item| item
|
657
|
+
(rows.all? { |item| item.is_a?(::AsciiMath::AST::Paren) && item.lparen == symbol(:lparen, '(') && item.rparen == symbol(:rparen, ')') } ||
|
658
|
+
rows.all? { |item| item.is_a?(::AsciiMath::AST::Paren) && item.lparen == symbol(:lbracket, '[') && item.rparen == symbol(:rbracket, ']') })
|
552
659
|
|
553
660
|
rows = rows.map do |row|
|
554
661
|
chunks = []
|
555
662
|
current_chunk = []
|
556
|
-
|
663
|
+
|
664
|
+
row_content = row.expression
|
665
|
+
unless row_content.is_a?(::AsciiMath::AST::Sequence)
|
666
|
+
row_content = expression(row_content)
|
667
|
+
end
|
668
|
+
|
669
|
+
row_content.each do |item|
|
557
670
|
if is_matrix_separator(item)
|
558
671
|
chunks << current_chunk
|
559
672
|
current_chunk = []
|
@@ -564,46 +677,88 @@ module AsciiMath
|
|
564
677
|
|
565
678
|
chunks << current_chunk
|
566
679
|
|
567
|
-
chunks.map {|c| c.length == 1 ? c[0] : c }.to_a
|
680
|
+
chunks.map { |c| c.length == 1 ? c[0] : expression(*c) }.to_a
|
568
681
|
end
|
569
682
|
|
570
|
-
return
|
683
|
+
return node unless rows.all? { |row| row.length == rows[0].length }
|
571
684
|
|
572
|
-
|
685
|
+
matrix(node.lparen, rows, node.rparen)
|
573
686
|
end
|
574
687
|
|
575
|
-
def is_matrix_separator(
|
576
|
-
|
688
|
+
def is_matrix_separator(node)
|
689
|
+
node.is_a?(Identifier) && node.value == ','
|
577
690
|
end
|
578
691
|
|
579
|
-
def
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
rows.all? { |item| item[:type] == :paren && item[:lparen] == '[' && item[:rparen] == ']' }) &&
|
589
|
-
rows.all? { |item| item[:e].length == rows[0][:e].length } &&
|
590
|
-
rows.all? { |item| matrix_cols?(item[:e]) }
|
692
|
+
def convert_node(node, converter)
|
693
|
+
case converter
|
694
|
+
when nil
|
695
|
+
node
|
696
|
+
when UnboundMethod
|
697
|
+
converter.bind(self).call(node)
|
698
|
+
when Method, Proc
|
699
|
+
converter.call(node)
|
700
|
+
end
|
591
701
|
end
|
592
702
|
|
593
|
-
def
|
594
|
-
|
703
|
+
def convert_to_color(color_expression)
|
704
|
+
s = ""
|
705
|
+
append_color_text(s, color_expression)
|
706
|
+
s
|
595
707
|
|
596
|
-
|
708
|
+
case s
|
709
|
+
when /#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/i
|
710
|
+
color_value = {:r => $1.to_i(16), :g => $2.to_i(16), :b => $3.to_i(16), }
|
711
|
+
when /#([0-9a-f])([0-9a-f])([0-9a-f])/i
|
712
|
+
color_value = {:r => "#{$1}#{$1}".to_i(16), :g => "#{$2}#{$2}".to_i(16), :b => "#{$3}#{$3}".to_i(16), }
|
713
|
+
else
|
714
|
+
color_value = @color_table[s.downcase] || {:r => 0, :g => 0, :b => 0}
|
715
|
+
end
|
597
716
|
|
598
|
-
|
599
|
-
separators.all?(&method(:is_col_separator))
|
717
|
+
color(color_value[:r], color_value[:g], color_value[:b], s)
|
600
718
|
end
|
719
|
+
|
720
|
+
def append_color_text(s, node)
|
721
|
+
case node
|
722
|
+
when ::AsciiMath::AST::Sequence
|
723
|
+
node.each { |n| append_color_text(s, n) }
|
724
|
+
when ::AsciiMath::AST::Number, ::AsciiMath::AST::Identifier, ::AsciiMath::AST::Text
|
725
|
+
s << node.value
|
726
|
+
when ::AsciiMath::AST::Symbol
|
727
|
+
s << node.text
|
728
|
+
when ::AsciiMath::AST::Group
|
729
|
+
append_color_text(s, node.expression)
|
730
|
+
when ::AsciiMath::AST::Paren
|
731
|
+
append_color_text(s, node.lparen)
|
732
|
+
append_color_text(s, node.expression)
|
733
|
+
append_color_text(s, node.rparen)
|
734
|
+
when ::AsciiMath::AST::SubSup
|
735
|
+
append_color_text(s, node.base_expression)
|
736
|
+
append_color_text(s, node.operator)
|
737
|
+
append_color_text(s, node.operand2)
|
738
|
+
when ::AsciiMath::AST::UnaryOp
|
739
|
+
append_color_text(s, node.operator)
|
740
|
+
append_color_text(s, node.operand)
|
741
|
+
when ::AsciiMath::AST::BinaryOp
|
742
|
+
append_color_text(s, node.operator)
|
743
|
+
append_color_text(s, node.operand1)
|
744
|
+
append_color_text(s, node.operand2)
|
745
|
+
when ::AsciiMath::AST::InfixOp
|
746
|
+
append_color_text(s, node.operand1)
|
747
|
+
append_color_text(s, node.operator)
|
748
|
+
append_color_text(s, node.operand2)
|
749
|
+
end
|
750
|
+
end
|
751
|
+
|
752
|
+
DEFAULT_COLOR_TABLE = ::AsciiMath::Parser.add_default_colors(AsciiMath::ColorTableBuilder.new).build
|
753
|
+
DEFAULT_PARSER_SYMBOL_TABLE = ::AsciiMath::Parser.add_default_parser_symbols(AsciiMath::SymbolTableBuilder.new).build
|
601
754
|
end
|
602
755
|
|
603
756
|
class Expression
|
604
|
-
|
757
|
+
attr_accessor :ast
|
758
|
+
|
759
|
+
def initialize(asciimath, ast)
|
605
760
|
@asciimath = asciimath
|
606
|
-
@
|
761
|
+
@ast = ast
|
607
762
|
end
|
608
763
|
|
609
764
|
def to_s
|
@@ -611,7 +766,7 @@ module AsciiMath
|
|
611
766
|
end
|
612
767
|
end
|
613
768
|
|
614
|
-
def self.parse(asciimath)
|
615
|
-
Parser.new.parse(asciimath)
|
769
|
+
def self.parse(asciimath, parser_symbol_table = ::AsciiMath::Parser::DEFAULT_PARSER_SYMBOL_TABLE, parser_color_table = ::AsciiMath::Parser::DEFAULT_COLOR_TABLE)
|
770
|
+
Parser.new(parser_symbol_table, parser_color_table).parse(asciimath)
|
616
771
|
end
|
617
772
|
end
|