asciimath 1.0.9 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +5 -5
  2. data/AST.adoc +457 -0
  3. data/CHANGELOG.adoc +12 -0
  4. data/Gemfile.lock +39 -0
  5. data/README.adoc +27 -3
  6. data/asciimath.gemspec +9 -5
  7. data/lib/asciimath.rb +5 -4
  8. data/lib/asciimath/ast.rb +456 -0
  9. data/lib/asciimath/cli.rb +4 -1
  10. data/lib/asciimath/color_table.rb +21 -0
  11. data/lib/asciimath/html.rb +126 -111
  12. data/lib/asciimath/latex.rb +386 -0
  13. data/lib/asciimath/markup.rb +478 -0
  14. data/lib/asciimath/mathml.rb +189 -87
  15. data/lib/asciimath/parser.rb +498 -343
  16. data/lib/asciimath/symbol_table.rb +25 -0
  17. data/lib/asciimath/version.rb +1 -1
  18. data/spec/ast.rb +144 -0
  19. data/spec/parser_spec.rb +592 -165
  20. data/spec/schema/mathml2/common/common-attribs.xsd +41 -0
  21. data/spec/schema/mathml2/common/math.xsd +126 -0
  22. data/spec/schema/mathml2/common/xlink-href.xsd +20 -0
  23. data/spec/schema/mathml2/content/arith.xsd +90 -0
  24. data/spec/schema/mathml2/content/calculus.xsd +146 -0
  25. data/spec/schema/mathml2/content/common-attrib.xsd +30 -0
  26. data/spec/schema/mathml2/content/constants.xsd +83 -0
  27. data/spec/schema/mathml2/content/constructs.xsd +260 -0
  28. data/spec/schema/mathml2/content/elementary-functions.xsd +117 -0
  29. data/spec/schema/mathml2/content/functions.xsd +73 -0
  30. data/spec/schema/mathml2/content/linear-algebra.xsd +173 -0
  31. data/spec/schema/mathml2/content/logic.xsd +53 -0
  32. data/spec/schema/mathml2/content/relations.xsd +55 -0
  33. data/spec/schema/mathml2/content/semantics.xsd +85 -0
  34. data/spec/schema/mathml2/content/sets.xsd +236 -0
  35. data/spec/schema/mathml2/content/statistics.xsd +136 -0
  36. data/spec/schema/mathml2/content/tokens.xsd +120 -0
  37. data/spec/schema/mathml2/content/vector-calculus.xsd +88 -0
  38. data/spec/schema/mathml2/mathml2.xsd +59 -0
  39. data/spec/schema/mathml2/presentation/action.xsd +44 -0
  40. data/spec/schema/mathml2/presentation/characters.xsd +37 -0
  41. data/spec/schema/mathml2/presentation/common-attribs.xsd +113 -0
  42. data/spec/schema/mathml2/presentation/common-types.xsd +103 -0
  43. data/spec/schema/mathml2/presentation/error.xsd +40 -0
  44. data/spec/schema/mathml2/presentation/layout.xsd +195 -0
  45. data/spec/schema/mathml2/presentation/scripts.xsd +186 -0
  46. data/spec/schema/mathml2/presentation/space.xsd +52 -0
  47. data/spec/schema/mathml2/presentation/style.xsd +69 -0
  48. data/spec/schema/mathml2/presentation/table.xsd +216 -0
  49. data/spec/schema/mathml2/presentation/tokens.xsd +124 -0
  50. data/spec/schema/mathml3/mathml3-common.xsd +99 -0
  51. data/spec/schema/mathml3/mathml3-content.xsd +684 -0
  52. data/spec/schema/mathml3/mathml3-presentation.xsd +2151 -0
  53. data/spec/schema/mathml3/mathml3-strict-content.xsd +186 -0
  54. data/spec/schema/mathml3/mathml3.xsd +9 -0
  55. metadata +102 -10
  56. data/.gitignore +0 -16
  57. data/.travis.yml +0 -18
@@ -1,8 +1,20 @@
1
+ require_relative 'markup'
2
+ require_relative 'symbol_table'
3
+
1
4
  module AsciiMath
2
- class MathMLBuilder
3
- def initialize(prefix)
4
- @prefix = prefix
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, :single_child => true)
26
+ append(expression, :row => :omit)
15
27
  end
16
28
  end
17
29
 
18
30
  private
19
31
 
20
- def append(expression, opts = {})
21
- case expression
22
- when Array
23
- if expression.length <= 1 || opts[:single_child]
24
- expression.each { |e| append(e) }
25
- else
26
- mrow do
27
- expression.each { |e| append(e) }
28
- end
29
- end
30
- when Hash
31
- case expression[:type]
32
- when :operator
33
- mo(expression[:c])
34
- when :identifier
35
- mi(expression[:c])
36
- when :number
37
- mn(expression[:c])
38
- when :text
39
- mtext(expression[:c])
40
- when :paren
41
- if !opts[:strip_paren]
42
- fenced(expression[:lparen], expression[:rparen]) do
43
- append(expression[:e])
44
- end
45
- else
46
- append(expression[:e])
47
- end
48
- when :font
49
- style = expression[:operator]
50
- tag("mstyle", :mathvariant => style.to_s.gsub('_', '-')) do
51
- append(expression[:s], :single_child => true, :strip_paren => true)
52
- end
53
- when :unary
54
- operator = expression[:operator]
55
- tag("m#{operator}") do
56
- append(expression[:s], :single_child => true, :strip_paren => true)
57
- end
58
- when :binary
59
- operator = expression[:operator]
60
- tag("m#{operator}") do
61
- append(expression[:s1], :strip_paren => (operator != :sub && operator != :sup))
62
- append(expression[:s2], :strip_paren => true)
63
- end
64
- when :ternary
65
- operator = expression[:operator]
66
- tag("m#{operator}") do
67
- append(expression[:s1])
68
- append(expression[:s2], :strip_paren => true)
69
- append(expression[:s3], :strip_paren => true)
70
- end
71
- when :matrix
72
- fenced(expression[:lparen], expression[:rparen]) do
73
- mtable do
74
- expression[:rows].each do |row|
75
- mtr do
76
- row.each do |col|
77
- mtd do
78
- append(col)
79
- end
80
- end
81
- end
82
- end
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, &block)
177
+ def fenced(lparen, rparen)
94
178
  if lparen || rparen
95
- mfenced(:open => lparen || '', :close => rparen || '') do
96
- yield self
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 << '="' << value.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.each_codepoint do |cp|
117
- if cp == 38
118
- @mathml << "&amp;"
119
- elsif cp == 60
120
- @mathml << "&lt;"
121
- elsif cp == 62
122
- @mathml << "&gt;"
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 << "&amp;"
222
+ elsif cp == 60
223
+ @mathml << "&lt;"
224
+ elsif cp == 62
225
+ @mathml << "&gt;"
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
- MathMLBuilder.new(prefix).append_expression(@parsed_expression, attrs).to_s
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
@@ -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
- # - :identifier a symbolic name or a bit of text without any further semantics
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 = /-?[0-9]+(?:\.[0-9]+)?/
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
- when '"'
90
- read_quoted_text
91
- when 't'
92
- case @string.peek(5)
93
- when 'text('
94
- read_tex_text
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] || {:value => s, :type => :identifier}
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
- SYMBOLS = {
204
- # Operation symbols
205
- '+' => {:value => '+', :type => :operator},
206
- '-' => {:value => "\u2212", :type => :operator},
207
- '*' => {:value => "\u22C5", :type => :operator},
208
- '**' => {:value => "\u002A", :type => :operator},
209
- '***' => {:value => "\u22C6", :type => :operator},
210
- '//' => {:value => '/', :type => :operator},
211
- '\\\\' => {:value => '\\', :type => :operator},
212
- 'xx' => {:value => "\u00D7", :type => :operator},
213
- '-:' => {:value => "\u00F7", :type => :operator},
214
- '|><' => {:value => "\u22C9", :type => :operator},
215
- '><|' => {:value => "\u22CA", :type => :operator},
216
- '|><|' => {:value => "\u22C8", :type => :operator},
217
- '@' => {:value => "\u26AC", :type => :operator},
218
- 'o+' => {:value => "\u2295", :type => :operator},
219
- 'ox' => {:value => "\u2297", :type => :operator},
220
- 'o.' => {:value => "\u2299", :type => :operator},
221
- 'sum' => {:value => "\u2211", :type => :operator, :underover => true},
222
- 'prod' => {:value => "\u220F", :type => :operator, :underover => true},
223
- '^^' => {:value => "\u2227", :type => :operator},
224
- '^^^' => {:value => "\u22C0", :type => :operator, :underover => true},
225
- 'vv' => {:value => "\u2228", :type => :operator},
226
- 'vvv' => {:value => "\u22C1", :type => :operator, :underover => true},
227
- 'nn' => {:value => "\u2229", :type => :operator},
228
- 'nnn' => {:value => "\u22C2", :type => :operator, :underover => true},
229
- 'uu' => {:value => "\u222A", :type => :operator},
230
- 'uuu' => {:value => "\u22C3", :type => :operator, :underover => true},
231
-
232
- # Relation symbols
233
- '=' => {:value => '=', :type => :operator},
234
- '!=' => {:value => "\u2260", :type => :operator},
235
- ':=' => {:value => ':=', :type => :operator},
236
- '<' => {:value => "\u003C", :type => :operator},
237
- 'lt' => {:value => "\u003C", :type => :operator},
238
- '>' => {:value => "\u003E", :type => :operator},
239
- 'gt' => {:value => "\u003E", :type => :operator},
240
- '<=' => {:value => "\u2264", :type => :operator},
241
- 'le' => {:value => "\u2264", :type => :operator},
242
- '>=' => {:value => "\u2265", :type => :operator},
243
- 'ge' => {:value => "\u2265", :type => :operator},
244
- '-<' => {:value => "\u227A", :type => :operator},
245
- '>-' => {:value => "\u227B", :type => :operator},
246
- '-<=' => {:value => "\u2AAF", :type => :operator},
247
- '>-=' => {:value => "\u2AB0", :type => :operator},
248
- 'in' => {:value => "\u2208", :type => :operator},
249
- '!in' => {:value => "\u2209", :type => :operator},
250
- 'sub' => {:value => "\u2282", :type => :operator},
251
- 'sup' => {:value => "\u2283", :type => :operator},
252
- 'sube' => {:value => "\u2286", :type => :operator},
253
- 'supe' => {:value => "\u2287", :type => :operator},
254
- '-=' => {:value => "\u2261", :type => :operator},
255
- '~=' => {:value => "\u2245", :type => :operator},
256
- '~~' => {:value => "\u2248", :type => :operator},
257
- 'prop' => {:value => "\u221D", :type => :operator},
258
-
259
- # Logical symbols
260
- 'and' => {:value => 'and', :type => :text},
261
- 'or' => {:value => 'or', :type => :text},
262
- 'not' => {:value => "\u00AC", :type => :operator},
263
- '=>' => {:value => "\u21D2", :type => :operator},
264
- 'if' => {:value => 'if', :type => :operator},
265
- '<=>' => {:value => "\u21D4", :type => :operator},
266
- 'AA' => {:value => "\u2200", :type => :operator},
267
- 'EE' => {:value => "\u2203", :type => :operator},
268
- '_|_' => {:value => "\u22A5", :type => :operator},
269
- 'TT' => {:value => "\u22A4", :type => :operator},
270
- '|--' => {:value => "\u22A2", :type => :operator},
271
- '|==' => {:value => "\u22A8", :type => :operator},
272
-
273
- # Grouping brackets
274
- '(' => {:value => '(', :type => :lparen},
275
- ')' => {:value => ')', :type => :rparen},
276
- '[' => {:value => '[', :type => :lparen},
277
- ']' => {:value => ']', :type => :rparen},
278
- '{' => {:value => '{', :type => :lparen},
279
- '}' => {:value => '}', :type => :rparen},
280
- '(:' => {:value => "\u2329", :type => :lparen},
281
- ':)' => {:value => "\u232A", :type => :rparen},
282
- '<<' => {:value => "\u2329", :type => :lparen},
283
- '>>' => {:value => "\u232A", :type => :rparen},
284
- '|' => {:value => '|', :type => :lrparen},
285
- '||' => {:value => '||', :type => :lrparen},
286
- '{:' => {:value => nil, :type => :lparen},
287
- ':}' => {:value => nil, :type => :rparen},
288
-
289
- # Miscellaneous symbols
290
- 'int' => {:value => "\u222B", :type => :operator},
291
- 'dx' => {:value => 'dx', :type => :identifier},
292
- 'dy' => {:value => 'dy', :type => :identifier},
293
- 'dz' => {:value => 'dz', :type => :identifier},
294
- 'dt' => {:value => 'dt', :type => :identifier},
295
- 'oint' => {:value => "\u222E", :type => :operator},
296
- 'del' => {:value => "\u2202", :type => :operator},
297
- 'grad' => {:value => "\u2207", :type => :operator},
298
- '+-' => {:value => "\u00B1", :type => :operator},
299
- 'O/' => {:value => "\u2205", :type => :operator},
300
- 'oo' => {:value => "\u221E", :type => :operator},
301
- 'aleph' => {:value => "\u2135", :type => :operator},
302
- '...' => {:value => '...', :type => :operator},
303
- ':.' => {:value => "\u2234", :type => :operator},
304
- '/_' => {:value => "\u2220", :type => :operator},
305
- '\\ ' => {:value => "\u00A0", :type => :operator},
306
- 'quad' => {:value => '\u00A0\u00A0', :type => :operator},
307
- 'qquad' => {:value => '\u00A0\u00A0\u00A0\u00A0', :type => :operator},
308
- 'cdots' => {:value => "\u22EF", :type => :operator},
309
- 'vdots' => {:value => "\u22EE", :type => :operator},
310
- 'ddots' => {:value => "\u22F1", :type => :operator},
311
- 'diamond' => {:value => "\u22C4", :type => :operator},
312
- 'square' => {:value => "\u25A1", :type => :operator},
313
- '|__' => {:value => "\u230A", :type => :operator},
314
- '__|' => {:value => "\u230B", :type => :operator},
315
- '|~' => {:value => "\u2308", :type => :operator},
316
- '~|' => {:value => "\u2309", :type => :operator},
317
- 'CC' => {:value => "\u2102", :type => :operator},
318
- 'NN' => {:value => "\u2115", :type => :operator},
319
- 'QQ' => {:value => "\u211A", :type => :operator},
320
- 'RR' => {:value => "\u211D", :type => :operator},
321
- 'ZZ' => {:value => "\u2124", :type => :operator},
322
-
323
- 'lim' => {:value => 'lim', :type => :operator, :underover => true},
324
- 'Lim' => {:value => 'Lim', :type => :operator, :underover => true},
325
-
326
- # Standard functions
327
- 'sin' => {:value => 'sin', :type => :identifier},
328
- 'cos' => {:value => 'cos', :type => :identifier},
329
- 'tan' => {:value => 'tan', :type => :identifier},
330
- 'sec' => {:value => 'sec', :type => :identifier},
331
- 'csc' => {:value => 'csc', :type => :identifier},
332
- 'cot' => {:value => 'cot', :type => :identifier},
333
- 'arcsin' => {:value => 'arcsin', :type => :identifier},
334
- 'arccos' => {:value => 'arccos', :type => :identifier},
335
- 'arctan' => {:value => 'arctan', :type => :identifier},
336
- 'sinh' => {:value => 'sinh', :type => :identifier},
337
- 'cosh' => {:value => 'cosh', :type => :identifier},
338
- 'tanh' => {:value => 'tanh', :type => :identifier},
339
- 'sech' => {:value => 'sech', :type => :identifier},
340
- 'csch' => {:value => 'csch', :type => :identifier},
341
- 'coth' => {:value => 'coth', :type => :identifier},
342
- 'exp' => {:value => 'exp', :type => :identifier},
343
- 'log' => {:value => 'log', :type => :identifier},
344
- 'ln' => {:value => 'ln', :type => :identifier},
345
- 'det' => {:value => 'det', :type => :identifier},
346
- 'dim' => {:value => 'dim', :type => :identifier},
347
- 'mod' => {:value => 'mod', :type => :identifier},
348
- 'gcd' => {:value => 'gcd', :type => :identifier},
349
- 'lcm' => {:value => 'lcm', :type => :identifier},
350
- 'lub' => {:value => 'lub', :type => :identifier},
351
- 'glb' => {:value => 'glb', :type => :identifier},
352
- 'min' => {:value => 'min', :type => :identifier, :underover => true},
353
- 'max' => {:value => 'max', :type => :identifier, :underover => true},
354
- 'f' => {:value => 'f', :type => :identifier},
355
- 'g' => {:value => 'g', :type => :identifier},
356
-
357
- # Accents
358
- 'hat' => {:value => "\u005E", :type => :accent, :position => :over},
359
- 'bar' => {:value => "\u00AF", :type => :accent, :position => :over},
360
- 'ul' => {:value => '_', :type => :accent, :position => :under},
361
- 'vec' => {:value => "\u2192", :type => :accent, :position => :over},
362
- 'dot' => {:value => '.', :type => :accent, :position => :over},
363
- 'ddot' => {:value => '..', :type => :accent, :position => :over},
364
- 'obrace' => {:value => "\u23DE", :type => :accent, :position => :over},
365
- 'ubrace' => {:value => "\u23DF", :type => :accent, :position => :under},
366
-
367
- # Arrows
368
- 'uarr' => {:value => "\u2191", :type => :operator},
369
- 'darr' => {:value => "\u2193", :type => :operator},
370
- 'rarr' => {:value => "\u2192", :type => :operator},
371
- '->' => {:value => "\u2192", :type => :operator},
372
- '>->' => {:value => "\u21A3", :type => :operator},
373
- '->>' => {:value => "\u21A0", :type => :operator},
374
- '>->>' => {:value => "\u2916", :type => :operator},
375
- '|->' => {:value => "\u21A6", :type => :operator},
376
- 'larr' => {:value => "\u2190", :type => :operator},
377
- 'harr' => {:value => "\u2194", :type => :operator},
378
- 'rArr' => {:value => "\u21D2", :type => :operator},
379
- 'lArr' => {:value => "\u21D0", :type => :operator},
380
- 'hArr' => {:value => "\u21D4", :type => :operator},
381
-
382
- # Other
383
- 'sqrt' => {:value => :sqrt, :type => :unary},
384
- 'text' => {:value => :text, :type => :unary},
385
- 'bb' => {:value => :bold, :type => :font},
386
- 'bbb' => {:value => :double_struck, :type => :font},
387
- 'ii' => {:value => :italic, :type => :font},
388
- 'bii' => {:value => :bold_italic, :type => :font},
389
- 'cc' => {:value => :script, :type => :font},
390
- 'bcc' => {:value => :bold_script, :type => :font},
391
- 'tt' => {:value => :monospace, :type => :font},
392
- 'fr' => {:value => :fraktur, :type => :font},
393
- 'bfr' => {:value => :bold_fraktur, :type => :font},
394
- 'sf' => {:value => :sans_serif, :type => :font},
395
- 'bsf' => {:value => :bold_sans_serif, :type => :font},
396
- 'sfi' => {:value => :sans_serif_italic, :type => :font},
397
- 'sfbi' => {:value => :sans_serif_bold_italic, :type => :font},
398
- 'frac' => {:value => :frac, :type => :binary},
399
- 'root' => {:value => :root, :type => :binary},
400
- 'stackrel' => {:value => :over, :type => :binary},
401
- '/' => {:value => :frac, :type => :infix},
402
- '_' => {:value => :sub, :type => :infix},
403
- '^' => {:value => :sup, :type => :infix},
404
-
405
- # Greek letters
406
- 'alpha' => {:value => "\u03b1", :type => :identifier},
407
- 'Alpha' => {:value => "\u0391", :type => :identifier},
408
- 'beta' => {:value => "\u03b2", :type => :identifier},
409
- 'Beta' => {:value => "\u0392", :type => :identifier},
410
- 'gamma' => {:value => "\u03b3", :type => :identifier},
411
- 'Gamma' => {:value => "\u0393", :type => :operator},
412
- 'delta' => {:value => "\u03b4", :type => :identifier},
413
- 'Delta' => {:value => "\u0394", :type => :operator},
414
- 'epsilon' => {:value => "\u03b5", :type => :identifier},
415
- 'Epsilon' => {:value => "\u0395", :type => :identifier},
416
- 'varepsilon' => {:value => "\u025b", :type => :identifier},
417
- 'zeta' => {:value => "\u03b6", :type => :identifier},
418
- 'Zeta' => {:value => "\u0396", :type => :identifier},
419
- 'eta' => {:value => "\u03b7", :type => :identifier},
420
- 'Eta' => {:value => "\u0397", :type => :identifier},
421
- 'theta' => {:value => "\u03b8", :type => :identifier},
422
- 'Theta' => {:value => "\u0398", :type => :operator},
423
- 'vartheta' => {:value => "\u03d1", :type => :identifier},
424
- 'iota' => {:value => "\u03b9", :type => :identifier},
425
- 'Iota' => {:value => "\u0399", :type => :identifier},
426
- 'kappa' => {:value => "\u03ba", :type => :identifier},
427
- 'Kappa' => {:value => "\u039a", :type => :identifier},
428
- 'lambda' => {:value => "\u03bb", :type => :identifier},
429
- 'Lambda' => {:value => "\u039b", :type => :operator},
430
- 'mu' => {:value => "\u03bc", :type => :identifier},
431
- 'Mu' => {:value => "\u039c", :type => :identifier},
432
- 'nu' => {:value => "\u03bd", :type => :identifier},
433
- 'Nu' => {:value => "\u039d", :type => :identifier},
434
- 'xi' => {:value => "\u03be", :type => :identifier},
435
- 'Xi' => {:value => "\u039e", :type => :operator},
436
- 'omicron' => {:value => "\u03bf", :type => :identifier},
437
- 'Omicron' => {:value => "\u039f", :type => :identifier},
438
- 'pi' => {:value => "\u03c0", :type => :identifier},
439
- 'Pi' => {:value => "\u03a0", :type => :operator},
440
- 'rho' => {:value => "\u03c1", :type => :identifier},
441
- 'Rho' => {:value => "\u03a1", :type => :identifier},
442
- 'sigma' => {:value => "\u03c3", :type => :identifier},
443
- 'Sigma' => {:value => "\u03a3", :type => :operator},
444
- 'tau' => {:value => "\u03c4", :type => :identifier},
445
- 'Tau' => {:value => "\u03a4", :type => :identifier},
446
- 'upsilon' => {:value => "\u03c5", :type => :identifier},
447
- 'Upsilon' => {:value => "\u03a5", :type => :identifier},
448
- 'phi' => {:value => "\u03c6", :type => :identifier},
449
- 'Phi' => {:value => "\u03a6", :type => :identifier},
450
- 'varphi' => {:value => "\u03d5", :type => :identifier},
451
- 'chi' => {:value => '\u03b3c7', :type => :identifier},
452
- 'Chi' => {:value => '\u0393a7', :type => :identifier},
453
- 'psi' => {:value => "\u03c8", :type => :identifier},
454
- 'Psi' => {:value => "\u03a8", :type => :identifier},
455
- 'omega' => {:value => "\u03c9", :type => :identifier},
456
- 'Omega' => {:value => "\u03a9", :type => :operator},
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, SYMBOLS), 0)
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 = parse_simple_expression(tok, depth))
519
+ while (s1 = parse_intermediate_expression(tok, depth))
471
520
  t1 = tok.next_token
472
521
 
473
- if t1[:type] == :infix
474
- s2 = parse_simple_expression(tok, depth)
475
- t2 = tok.next_token
476
- if t1[:value] == :sub && t2[:value] == :sup
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
- operator = s1[:underover] ? (t1[:value] == :sub ? :under : :over) : t1[:value]
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
- {:type => :paren, :e => nil, :lparen => t1[:value], :rparen => t2[:value]}
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({:type => :paren, :e => e, :lparen => t1[:value], :rparen => t2[:value]})
600
+ convert_to_matrix(paren(token_to_symbol(t1), e, token_to_symbol(t2)))
521
601
  else
522
602
  tok.push_back(t2)
523
- {:type => :paren, :e => e, :lparen => t1[:value]}
603
+ paren(token_to_symbol(t1), e, nil)
524
604
  end
525
605
  end
526
- when :accent
527
- s = parse_simple_expression(tok, depth)
528
- {:type => :binary, :s1 => s, :s2 => {:type => :operator, :c => t1[:value]}, :operator => t1[:position]}
529
- when :unary, :font
530
- s = parse_simple_expression(tok, depth)
531
- {:type => t1[:type], :s => s, :operator => t1[:value]}
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
- {:type => :binary, :s1 => s1, :s2 => s2, :operator => t1[:value]}
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
- {:type => t1[:type], :c => t1[:value], :underover => t1[:underover]}
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(expression)
544
- return expression unless expression.is_a?(Hash) && expression[:type] == :paren
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[:e].partition.with_index { |obj, i| i.even? }
547
- return expression unless rows.length > 1 &&
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[:type] == :paren && item[:lparen] == '(' && item[:rparen] == ')' } ||
551
- rows.all? { |item| item[:type] == :paren && item[:lparen] == '[' && item[:rparen] == ']' })
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
- row[:e].each do |item|
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 expression unless rows.all? { |row| row.length == rows[0].length }
683
+ return node unless rows.all? { |row| row.length == rows[0].length }
571
684
 
572
- {:type => :matrix, :rows => rows, :lparen => expression[:lparen], :rparen => expression[:rparen]}
685
+ matrix(node.lparen, rows, node.rparen)
573
686
  end
574
687
 
575
- def is_matrix_separator(item)
576
- item[:type] == :identifier && item[:c] == ','
688
+ def is_matrix_separator(node)
689
+ node.is_a?(Identifier) && node.value == ','
577
690
  end
578
691
 
579
- def matrix?(expression)
580
- return false unless expression.is_a?(Hash) && expression[:type] == :paren
581
-
582
- rows, separators = expression[:e].partition.with_index { |obj, i| i.even? }
583
-
584
- rows.length > 1 &&
585
- rows.length > separators.length &&
586
- separators.all?(&method(:is_matrix_separator)) &&
587
- (rows.all? { |item| item[:type] == :paren && item[:lparen] == '(' && item[:rparen] == ')' } ||
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 matrix_cols?(expression)
594
- return false unless expression.is_a?(Array)
703
+ def convert_to_color(color_expression)
704
+ s = ""
705
+ append_color_text(s, color_expression)
706
+ s
595
707
 
596
- cols, separators = expression.partition.with_index { |obj, i| i.even? }
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
- cols.all? { |item| item[:type] != :identifier || item[:c] != ',' } &&
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
- def initialize(asciimath, parsed_expression)
757
+ attr_accessor :ast
758
+
759
+ def initialize(asciimath, ast)
605
760
  @asciimath = asciimath
606
- @parsed_expression = parsed_expression
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