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.
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