asciimath 1.0.6 → 2.0.1

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/.travis.yml +6 -8
  3. data/AST.adoc +457 -0
  4. data/CHANGELOG.adoc +44 -1
  5. data/README.adoc +66 -3
  6. data/asciimath.gemspec +7 -5
  7. data/dump_symbol_table.rb +46 -0
  8. data/lib/asciimath.rb +5 -4
  9. data/lib/asciimath/ast.rb +456 -0
  10. data/lib/asciimath/cli.rb +4 -1
  11. data/lib/asciimath/color_table.rb +21 -0
  12. data/lib/asciimath/html.rb +148 -119
  13. data/lib/asciimath/latex.rb +400 -0
  14. data/lib/asciimath/markup.rb +479 -0
  15. data/lib/asciimath/mathml.rb +196 -83
  16. data/lib/asciimath/parser.rb +531 -318
  17. data/lib/asciimath/symbol_table.rb +25 -0
  18. data/lib/asciimath/version.rb +1 -1
  19. data/spec/ast.rb +144 -0
  20. data/spec/customisation_spec.rb +28 -0
  21. data/spec/parser_spec.rb +598 -147
  22. data/spec/schema/mathml2/common/common-attribs.xsd +41 -0
  23. data/spec/schema/mathml2/common/math.xsd +126 -0
  24. data/spec/schema/mathml2/common/xlink-href.xsd +20 -0
  25. data/spec/schema/mathml2/content/arith.xsd +90 -0
  26. data/spec/schema/mathml2/content/calculus.xsd +146 -0
  27. data/spec/schema/mathml2/content/common-attrib.xsd +30 -0
  28. data/spec/schema/mathml2/content/constants.xsd +83 -0
  29. data/spec/schema/mathml2/content/constructs.xsd +260 -0
  30. data/spec/schema/mathml2/content/elementary-functions.xsd +117 -0
  31. data/spec/schema/mathml2/content/functions.xsd +73 -0
  32. data/spec/schema/mathml2/content/linear-algebra.xsd +173 -0
  33. data/spec/schema/mathml2/content/logic.xsd +53 -0
  34. data/spec/schema/mathml2/content/relations.xsd +55 -0
  35. data/spec/schema/mathml2/content/semantics.xsd +85 -0
  36. data/spec/schema/mathml2/content/sets.xsd +236 -0
  37. data/spec/schema/mathml2/content/statistics.xsd +136 -0
  38. data/spec/schema/mathml2/content/tokens.xsd +120 -0
  39. data/spec/schema/mathml2/content/vector-calculus.xsd +88 -0
  40. data/spec/schema/mathml2/mathml2.xsd +59 -0
  41. data/spec/schema/mathml2/presentation/action.xsd +44 -0
  42. data/spec/schema/mathml2/presentation/characters.xsd +37 -0
  43. data/spec/schema/mathml2/presentation/common-attribs.xsd +113 -0
  44. data/spec/schema/mathml2/presentation/common-types.xsd +103 -0
  45. data/spec/schema/mathml2/presentation/error.xsd +40 -0
  46. data/spec/schema/mathml2/presentation/layout.xsd +195 -0
  47. data/spec/schema/mathml2/presentation/scripts.xsd +186 -0
  48. data/spec/schema/mathml2/presentation/space.xsd +52 -0
  49. data/spec/schema/mathml2/presentation/style.xsd +69 -0
  50. data/spec/schema/mathml2/presentation/table.xsd +216 -0
  51. data/spec/schema/mathml2/presentation/tokens.xsd +124 -0
  52. data/spec/schema/mathml3/mathml3-common.xsd +99 -0
  53. data/spec/schema/mathml3/mathml3-content.xsd +684 -0
  54. data/spec/schema/mathml3/mathml3-presentation.xsd +2151 -0
  55. data/spec/schema/mathml3/mathml3-strict-content.xsd +186 -0
  56. data/spec/schema/mathml3/mathml3.xsd +9 -0
  57. metadata +108 -11
@@ -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,89 +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
- paren = !opts[:strip_paren]
42
- if paren
43
- if opts[:single_child]
44
- mo(expression[:lparen]) if expression[:lparen]
45
- append(expression[:e], :single_child => true)
46
- mo(expression[:rparen]) if expression[:rparen]
47
- else
48
- mrow do
49
- mo(expression[:lparen]) if expression[:lparen]
50
- append(expression[:e], :single_child => true)
51
- mo(expression[:rparen]) if expression[:rparen]
52
- end
53
- end
54
- else
55
- append(expression[:e])
56
- end
57
- when :font
58
- style = expression[:operator]
59
- tag("mstyle", :mathvariant => style.to_s.gsub('_', '-')) do
60
- append(expression[:s], :single_child => true, :strip_paren => true)
61
- end
62
- when :unary
63
- operator = expression[:operator]
64
- tag("m#{operator}") do
65
- append(expression[:s], :single_child => true, :strip_paren => true)
66
- end
67
- when :binary
68
- operator = expression[:operator]
69
- tag("m#{operator}") do
70
- append(expression[:s1], :strip_paren => (operator != :sub && operator != :sup))
71
- append(expression[:s2], :strip_paren => true)
72
- end
73
- when :ternary
74
- operator = expression[:operator]
75
- tag("m#{operator}") do
76
- append(expression[:s1])
77
- append(expression[:s2], :strip_paren => true)
78
- append(expression[:s3], :strip_paren => true)
79
- end
80
- when :matrix
81
- mrow do
82
- mo(expression[:lparen]) if expression[:lparen]
83
- mtable do
84
- expression[:rows].each do |row|
85
- mtr do
86
- row.each do |col|
87
- mtd do
88
- append(col)
89
- end
90
- end
91
- end
92
- 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)
93
101
  end
94
- mo(expression[:rparen]) if expression[:rparen]
95
102
  end
103
+ end
96
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)
97
170
  end
98
171
  end
99
172
 
@@ -101,31 +174,71 @@ module AsciiMath
101
174
  tag(meth, *args, &block)
102
175
  end
103
176
 
177
+ def fenced(lparen, rparen)
178
+ if lparen || rparen
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
189
+ end
190
+ else
191
+ yield self
192
+ end
193
+ end
194
+
104
195
  def tag(tag, *args)
105
196
  attrs = args.last.is_a?(Hash) ? args.pop : {}
106
- text = args.last.is_a?(String) ? args.pop : ''
197
+ text = args.last.is_a?(String) || args.last.is_a?(Symbol) ? args.pop.to_s : ''
107
198
 
108
199
  @mathml << '<' << @prefix << tag.to_s
109
200
 
110
201
  attrs.each_pair do |key, value|
111
- @mathml << ' ' << key.to_s << '="' << value.to_s << '"'
202
+ @mathml << ' ' << key.to_s << '="'
203
+ append_escaped(value.to_s)
204
+ @mathml << '"'
112
205
  end
113
206
 
114
207
 
115
208
  if block_given? || text
116
209
  @mathml << '>'
117
- @mathml << text
210
+ append_escaped(text)
118
211
  yield self if block_given?
119
212
  @mathml << '</' << @prefix << tag.to_s << '>'
120
213
  else
121
214
  @mathml << '/>'
122
215
  end
123
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
124
233
  end
125
234
 
126
235
  class Expression
127
236
  def to_mathml(prefix = "", attrs = {})
128
- 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
129
242
  end
130
243
  end
131
- 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,29 +36,20 @@ 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
- WHITESPACE = /^\s+/
57
- NUMBER = /-?[0-9]+(?:\.[0-9]+)?/
58
- TEXT = /"[^"]+"/
49
+ WHITESPACE = /\s+/
50
+ NUMBER = /[0-9]+(?:\.[0-9]+)?/
51
+ QUOTED_TEXT = /"[^"]*"/
52
+ TEX_TEXT = /text\([^)]*\)/
59
53
 
60
54
  # Public: Initializes an ASCIIMath tokenizer.
61
55
  #
@@ -65,7 +59,7 @@ module AsciiMath
65
59
  @string = StringScanner.new(string)
66
60
  @symbols = symbols
67
61
  lookahead = @symbols.keys.map { |k| k.length }.max
68
- @symbol_regexp = /([^\s0-9]{1,#{lookahead}})/
62
+ @symbol_regexp = /((?:\\[\s0-9]|[^\s0-9]){1,#{lookahead}})/
69
63
  @push_back = nil
70
64
  end
71
65
 
@@ -86,11 +80,18 @@ module AsciiMath
86
80
 
87
81
  case @string.peek(1)
88
82
  when '"'
89
- read_text
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
90
91
  when '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
91
- read_number() || read_symbol
92
+ read_number || read_symbol
92
93
  else
93
- read_symbol()
94
+ read_symbol
94
95
  end
95
96
  end
96
97
 
@@ -109,12 +110,22 @@ module AsciiMath
109
110
  #
110
111
  # Returns the text token or nil if a text token could not be matched at
111
112
  # the current position
112
- def read_text
113
- read_value(TEXT) do |text|
113
+ def read_quoted_text
114
+ read_value(QUOTED_TEXT) do |text|
114
115
  {:value => text[1..-2], :type => :text}
115
116
  end
116
117
  end
117
118
 
119
+ # Private: Reads a text token from the input string
120
+ #
121
+ # Returns the text token or nil if a text token could not be matched at
122
+ # the current position
123
+ def read_tex_text
124
+ read_value(TEX_TEXT) do |text|
125
+ {:value => text[5..-2], :type => :text}
126
+ end
127
+ end
128
+
118
129
  # Private: Reads a number token from the input string
119
130
  #
120
131
  # Returns the number token or nil if a number token could not be matched at
@@ -155,7 +166,12 @@ module AsciiMath
155
166
  s.chop!
156
167
  end
157
168
  @string.pos = position + bytesize(s)
158
- @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
159
175
  end
160
176
  end
161
177
 
@@ -167,7 +183,7 @@ module AsciiMath
167
183
  # Returns the matched String or the value returned by the block if one was given
168
184
  def read_value(regexp)
169
185
  s = @string.scan(regexp)
170
- if s
186
+ if s && block_given?
171
187
  yield s
172
188
  else
173
189
  s
@@ -182,277 +198,334 @@ module AsciiMath
182
198
  end
183
199
 
184
200
  class Parser
185
- SYMBOLS = {
186
- # Operation symbols
187
- '+' => {:value => '+', :type => :operator},
188
- '-' => {:value => '&#x2212;', :type => :operator},
189
- '*' => {:value => '&#x22C5;', :type => :operator},
190
- '**' => {:value => '&#x22C6;', :type => :operator},
191
- '//' => {:value => '/', :type => :operator},
192
- '\\\\' => {:value => '\\', :type => :operator},
193
- 'xx' => {:value => '&#x00D7;', :type => :operator},
194
- '-:' => {:value => '&#x00F7;', :type => :operator},
195
- '@' => {:value => '&#x26AC;', :type => :operator},
196
- 'o+' => {:value => '&#x2295;', :type => :operator},
197
- 'ox' => {:value => '&#x2297;', :type => :operator},
198
- 'o.' => {:value => '&#x2299;', :type => :operator},
199
- 'sum' => {:value => '&#x2211;', :type => :operator, :underover => true},
200
- 'prod' => {:value => '&#x220F;', :type => :operator, :underover => true},
201
- '^^' => {:value => '&#x2227;', :type => :operator},
202
- '^^^' => {:value => '&#x22C0;', :type => :operator, :underover => true},
203
- 'vv' => {:value => '&#x2228;', :type => :operator},
204
- 'vvv' => {:value => '&#x22C1;', :type => :operator, :underover => true},
205
- 'nn' => {:value => '&#x2229;', :type => :operator},
206
- 'nnn' => {:value => '&#x22C2;', :type => :operator, :underover => true},
207
- 'uu' => {:value => '&#x222A;', :type => :operator},
208
- 'uuu' => {:value => '&#x22C3;', :type => :operator, :underover => true},
209
-
210
- # Relation symbols
211
- '=' => {:value => '=', :type => :operator},
212
- '!=' => {:value => '&#x2260;', :type => :operator},
213
- ':=' => {:value => ':=', :type => :operator},
214
- '<' => {:value => '&#x003C;', :type => :operator},
215
- 'lt' => {:value => '&#x003C;', :type => :operator},
216
- '>' => {:value => '&#x003E;', :type => :operator},
217
- 'gt' => {:value => '&#x003E;', :type => :operator},
218
- '<=' => {:value => '&#x2264;', :type => :operator},
219
- 'lt=' => {:value => '&#x2264;', :type => :operator},
220
- '>=' => {:value => '&#x2265;', :type => :operator},
221
- 'geq' => {:value => '&#x2265;', :type => :operator},
222
- '-<' => {:value => '&#x227A;', :type => :operator},
223
- '-lt' => {:value => '&#x227A;', :type => :operator},
224
- '>-' => {:value => '&#x227B;', :type => :operator},
225
- '-<=' => {:value => '&#x2AAF;', :type => :operator},
226
- '>-=' => {:value => '&#x2AB0;', :type => :operator},
227
- 'in' => {:value => '&#x2208;', :type => :operator},
228
- '!in' => {:value => '&#x2209;', :type => :operator},
229
- 'sub' => {:value => '&#x2282;', :type => :operator},
230
- 'sup' => {:value => '&#x2283;', :type => :operator},
231
- 'sube' => {:value => '&#x2286;', :type => :operator},
232
- 'supe' => {:value => '&#x2287;', :type => :operator},
233
- '-=' => {:value => '&#x2261;', :type => :operator},
234
- '~=' => {:value => '&#x2245;', :type => :operator},
235
- '~~' => {:value => '&#x2248;', :type => :operator},
236
- 'prop' => {:value => '&#x221D;', :type => :operator},
237
-
238
- # Logical symbols
239
- 'and' => {:value => 'and', :type => :text},
240
- 'or' => {:value => 'or', :type => :text},
241
- 'not' => {:value => '&#x00AC;', :type => :operator},
242
- '=>' => {:value => '&#x21D2;', :type => :operator},
243
- 'if' => {:value => 'if', :type => :operator},
244
- '<=>' => {:value => '&#x21D4;', :type => :operator},
245
- 'AA' => {:value => '&#x2200;', :type => :operator},
246
- 'EE' => {:value => '&#x2203;', :type => :operator},
247
- '_|_' => {:value => '&#x22A5;', :type => :operator},
248
- 'TT' => {:value => '&#x22A4;', :type => :operator},
249
- '|--' => {:value => '&#x22A2;', :type => :operator},
250
- '|==' => {:value => '&#x22A8;', :type => :operator},
251
-
252
- # Grouping brackets
253
- '(' => {:value => '(', :type => :lparen},
254
- ')' => {:value => ')', :type => :rparen},
255
- '[' => {:value => '[', :type => :lparen},
256
- ']' => {:value => ']', :type => :rparen},
257
- '{' => {:value => '{', :type => :lparen},
258
- '}' => {:value => '}', :type => :rparen},
259
- '|' => {:value => '|', :type => :lrparen},
260
- '||' => {:value => '||', :type => :lrparen},
261
- '(:' => {:value => '&#x2329;', :type => :lparen},
262
- ':)' => {:value => '&#x232A;', :type => :rparen},
263
- '<<' => {:value => '&#x2329;', :type => :lparen},
264
- '>>' => {:value => '&#x232A;', :type => :rparen},
265
- '{:' => {:value => nil, :type => :lparen},
266
- ':}' => {:value => nil, :type => :rparen},
267
-
268
- # Miscellaneous symbols
269
- 'int' => {:value => '&#x222B;', :type => :operator},
270
- 'dx' => {:value => 'dx', :type => :identifier},
271
- 'dy' => {:value => 'dy', :type => :identifier},
272
- 'dz' => {:value => 'dz', :type => :identifier},
273
- 'dt' => {:value => 'dt', :type => :identifier},
274
- 'oint' => {:value => '&#x222E;', :type => :operator},
275
- 'del' => {:value => '&#x2202;', :type => :operator},
276
- 'grad' => {:value => '&#x2207;', :type => :operator},
277
- '+-' => {:value => '&#x00B1;', :type => :operator},
278
- 'O/' => {:value => '&#x2205;', :type => :operator},
279
- 'oo' => {:value => '&#x221E;', :type => :operator},
280
- 'aleph' => {:value => '&#x2135;', :type => :operator},
281
- '...' => {:value => '...', :type => :operator},
282
- ':.' => {:value => '&#x2234;', :type => :operator},
283
- '/_' => {:value => '&#x2220;', :type => :operator},
284
- '\\ ' => {:value => '&#x00A0;', :type => :operator},
285
- 'quad' => {:value => '\u00A0\u00A0', :type => :operator},
286
- 'qquad' => {:value => '\u00A0\u00A0\u00A0\u00A0', :type => :operator},
287
- 'cdots' => {:value => '&#x22EF;', :type => :operator},
288
- 'vdots' => {:value => '&#x22EE;', :type => :operator},
289
- 'ddots' => {:value => '&#x22F1;', :type => :operator},
290
- 'diamond' => {:value => '&#x22C4;', :type => :operator},
291
- 'square' => {:value => '&#x25A1;', :type => :operator},
292
- '|__' => {:value => '&#x230A;', :type => :operator},
293
- '__|' => {:value => '&#x230B;', :type => :operator},
294
- '|~' => {:value => '&#x2308;', :type => :operator},
295
- '~|' => {:value => '&#x2309;', :type => :operator},
296
- 'CC' => {:value => '&#x2102;', :type => :operator},
297
- 'NN' => {:value => '&#x2115;', :type => :operator},
298
- 'QQ' => {:value => '&#x211A;', :type => :operator},
299
- 'RR' => {:value => '&#x211D;', :type => :operator},
300
- 'ZZ' => {:value => '&#x2124;', :type => :operator},
301
- 'f' => {:value => 'f', :type => :identifier},
302
- 'g' => {:value => 'g', :type => :identifier},
303
-
304
- # Standard functions
305
- 'lim' => {:value => 'lim', :type => :operator, :underover => true},
306
- 'Lim' => {:value => 'Lim', :type => :operator, :underover => true},
307
- 'sin' => {:value => 'sin', :type => :operator},
308
- 'cos' => {:value => 'cos', :type => :operator},
309
- 'tan' => {:value => 'tan', :type => :operator},
310
- 'sinh' => {:value => 'sinh', :type => :operator},
311
- 'cosh' => {:value => 'cosh', :type => :operator},
312
- 'tanh' => {:value => 'tanh', :type => :operator},
313
- 'cot' => {:value => 'cot', :type => :operator},
314
- 'sec' => {:value => 'sec', :type => :operator},
315
- 'csc' => {:value => 'csc', :type => :operator},
316
- 'log' => {:value => 'log', :type => :operator},
317
- 'ln' => {:value => 'ln', :type => :operator},
318
- 'det' => {:value => 'det', :type => :operator},
319
- 'dim' => {:value => 'dim', :type => :operator},
320
- 'mod' => {:value => 'mod', :type => :operator},
321
- 'gcd' => {:value => 'gcd', :type => :operator},
322
- 'lcm' => {:value => 'lcm', :type => :operator},
323
- 'lub' => {:value => 'lub', :type => :operator},
324
- 'glb' => {:value => 'glb', :type => :operator},
325
- 'min' => {:value => 'min', :type => :operator, :underover => true},
326
- 'max' => {:value => 'max', :type => :operator, :underover => true},
327
-
328
- # Accents
329
- 'hat' => {:value => '&#x005E;', :type => :accent, :position => :over},
330
- 'bar' => {:value => '&#x00AF;', :type => :accent, :position => :over},
331
- 'ul' => {:value => '_', :type => :accent, :position => :under},
332
- 'vec' => {:value => '&#x2192;', :type => :accent, :position => :over},
333
- 'dot' => {:value => '.', :type => :accent, :position => :over},
334
- 'ddot' => {:value => '..', :type => :accent, :position => :over},
335
-
336
- # Arrows
337
- 'uarr' => {:value => '&#x2191;', :type => :operator},
338
- 'darr' => {:value => '&#x2193;', :type => :operator},
339
- 'rarr' => {:value => '&#x2192;', :type => :operator},
340
- '->' => {:value => '&#x2192;', :type => :operator},
341
- '>->' => {:value => '&#x21A3;', :type => :operator},
342
- '->>' => {:value => '&#x21A0;', :type => :operator},
343
- '>->>' => {:value => '&#x2916;', :type => :operator},
344
- '|->' => {:value => '&#x21A6;', :type => :operator},
345
- 'larr' => {:value => '&#x2190;', :type => :operator},
346
- 'harr' => {:value => '&#x2194;', :type => :operator},
347
- 'rArr' => {:value => '&#x21D2;', :type => :operator},
348
- 'lArr' => {:value => '&#x21D0;', :type => :operator},
349
- 'hArr' => {:value => '&#x21D4;', :type => :operator},
350
-
351
- # Other
352
- 'sqrt' => {:value => :sqrt, :type => :unary},
353
- 'text' => {:value => :text, :type => :unary},
354
- 'bb' => {:value => :bold, :type => :font},
355
- 'bbb' => {:value => :double_struck, :type => :font},
356
- 'ii' => {:value => :italic, :type => :font},
357
- 'bii' => {:value => :bold_italic, :type => :font},
358
- 'cc' => {:value => :script, :type => :font},
359
- 'bcc' => {:value => :bold_script, :type => :font},
360
- 'tt' => {:value => :monospace, :type => :font},
361
- 'fr' => {:value => :fraktur, :type => :font},
362
- 'bfr' => {:value => :bold_fraktur, :type => :font},
363
- 'sf' => {:value => :sans_serif, :type => :font},
364
- 'bsf' => {:value => :bold_sans_serif, :type => :font},
365
- 'sfi' => {:value => :sans_serif_italic, :type => :font},
366
- 'sfbi' => {:value => :sans_serif_bold_italic, :type => :font},
367
- 'frac' => {:value => :frac, :type => :binary},
368
- 'root' => {:value => :root, :type => :binary},
369
- 'stackrel' => {:value => :over, :type => :binary},
370
- '/' => {:value => :frac, :type => :infix},
371
- '_' => {:value => :sub, :type => :infix},
372
- '^' => {:value => :sup, :type => :infix},
373
-
374
- # Greek letters
375
- 'alpha' => {:value => '&#x03b1;', :type => :identifier},
376
- 'Alpha' => {:value => '&#x0391;', :type => :identifier},
377
- 'beta' => {:value => '&#x03b2;', :type => :identifier},
378
- 'Beta' => {:value => '&#x0392;', :type => :identifier},
379
- 'gamma' => {:value => '&#x03b3;', :type => :identifier},
380
- 'Gamma' => {:value => '&#x0393;', :type => :operator},
381
- 'delta' => {:value => '&#x03b4;', :type => :identifier},
382
- 'Delta' => {:value => '&#x0394;', :type => :operator},
383
- 'epsilon' => {:value => '&#x03b5;', :type => :identifier},
384
- 'Epsilon' => {:value => '&#x0395;', :type => :identifier},
385
- 'varepsilon' => {:value => '&#x025b;', :type => :identifier},
386
- 'zeta' => {:value => '&#x03b6;', :type => :identifier},
387
- 'Zeta' => {:value => '&#x0396;', :type => :identifier},
388
- 'eta' => {:value => '&#x03b7;', :type => :identifier},
389
- 'Eta' => {:value => '&#x0397;', :type => :identifier},
390
- 'theta' => {:value => '&#x03b8;', :type => :identifier},
391
- 'Theta' => {:value => '&#x0398;', :type => :operator},
392
- 'vartheta' => {:value => '&#x03d1;', :type => :identifier},
393
- 'iota' => {:value => '&#x03b9;', :type => :identifier},
394
- 'Iota' => {:value => '&#x0399;', :type => :identifier},
395
- 'kappa' => {:value => '&#x03ba;', :type => :identifier},
396
- 'Kappa' => {:value => '&#x039a;', :type => :identifier},
397
- 'lambda' => {:value => '&#x03bb;', :type => :identifier},
398
- 'Lambda' => {:value => '&#x039b;', :type => :operator},
399
- 'mu' => {:value => '&#x03bc;', :type => :identifier},
400
- 'Mu' => {:value => '&#x039c;', :type => :identifier},
401
- 'nu' => {:value => '&#x03bd;', :type => :identifier},
402
- 'Nu' => {:value => '&#x039d;', :type => :identifier},
403
- 'xi' => {:value => '&#x03be;', :type => :identifier},
404
- 'Xi' => {:value => '&#x039e;', :type => :operator},
405
- 'omicron' => {:value => '&#x03bf;', :type => :identifier},
406
- 'Omicron' => {:value => '&#x039f;', :type => :identifier},
407
- 'pi' => {:value => '&#x03c0;', :type => :identifier},
408
- 'Pi' => {:value => '&#x03a0;', :type => :operator},
409
- 'rho' => {:value => '&#x03c1;', :type => :identifier},
410
- 'Rho' => {:value => '&#x03a1;', :type => :identifier},
411
- 'sigma' => {:value => '&#x03c3;', :type => :identifier},
412
- 'Sigma' => {:value => '&#x03a3;', :type => :operator},
413
- 'tau' => {:value => '&#x03c4;', :type => :identifier},
414
- 'Tau' => {:value => '&#x03a4;', :type => :identifier},
415
- 'upsilon' => {:value => '&#x03c5;', :type => :identifier},
416
- 'Upsilon' => {:value => '&#x03a5;', :type => :identifier},
417
- 'phi' => {:value => '&#x03c6;', :type => :identifier},
418
- 'Phi' => {:value => '&#x03a6;', :type => :identifier},
419
- 'varphi' => {:value => '&#x03d5;', :type => :identifier},
420
- 'chi' => {:value => '\u03b3c7', :type => :identifier},
421
- 'Chi' => {:value => '\u0393a7', :type => :identifier},
422
- 'psi' => {:value => '&#x03c8;', :type => :identifier},
423
- 'Psi' => {:value => '&#x03a8;', :type => :identifier},
424
- 'omega' => {:value => '&#x03c9;', :type => :identifier},
425
- 'Omega' => {:value => '&#x03a9;', :type => :operator},
426
- }
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('ker', :ker, :symbol)
389
+ b.add('mod', :mod, :symbol)
390
+ b.add('gcd', :gcd, :symbol)
391
+ b.add('lcm', :lcm, :symbol)
392
+ b.add('lub', :lub, :symbol)
393
+ b.add('glb', :glb, :symbol)
394
+
395
+ # Arrows
396
+ b.add('uarr', 'uparrow', :uparrow, :symbol)
397
+ b.add('darr', 'downarrow', :downarrow, :symbol)
398
+ b.add('rarr', 'rightarrow', :rightarrow, :symbol)
399
+ b.add('->', 'to', :to, :symbol)
400
+ b.add('>->', 'rightarrowtail', :rightarrowtail, :symbol)
401
+ b.add('->>', 'twoheadrightarrow', :twoheadrightarrow, :symbol)
402
+ b.add('>->>', 'twoheadrightarrowtail', :twoheadrightarrowtail, :symbol)
403
+ b.add('|->', 'mapsto', :mapsto, :symbol)
404
+ b.add('larr', 'leftarrow', :leftarrow, :symbol)
405
+ b.add('harr', 'leftrightarrow', :leftrightarrow, :symbol)
406
+ b.add('rArr', 'Rightarrow', :Rightarrow, :symbol)
407
+ b.add('lArr', 'Leftarrow', :Leftarrow, :symbol)
408
+ b.add('hArr', 'Leftrightarrow', :Leftrightarrow, :symbol)
409
+
410
+ # Other
411
+ b.add('sqrt', :sqrt, :unary)
412
+ b.add('root', :root, :binary)
413
+ b.add('frac', :frac, :binary)
414
+ b.add('/', :frac, :infix)
415
+ b.add('stackrel', :stackrel, :binary)
416
+ b.add('overset', :overset, :binary)
417
+ b.add('underset', :underset, :binary)
418
+ b.add('color', :color, :binary, :convert_operand1 => ::AsciiMath::Parser.instance_method(:convert_to_color))
419
+ b.add('_', :sub, :infix)
420
+ b.add('^', :sup, :infix)
421
+ b.add('hat', :hat, :unary)
422
+ b.add('bar', :overline, :unary)
423
+ b.add('vec', :vec, :unary)
424
+ b.add('dot', :dot, :unary)
425
+ b.add('ddot', :ddot, :unary)
426
+ b.add('overarc', 'overparen', :overarc, :unary)
427
+ b.add('ul', 'underline', :underline, :unary)
428
+ b.add('ubrace', 'underbrace', :underbrace, :unary)
429
+ b.add('obrace', 'overbrace', :overbrace, :unary)
430
+ b.add('cancel', :cancel, :unary)
431
+ b.add('bb', :bold, :unary)
432
+ b.add('bbb', :double_struck, :unary)
433
+ b.add('ii', :italic, :unary)
434
+ b.add('bii', :bold_italic, :unary)
435
+ b.add('cc', :script, :unary)
436
+ b.add('bcc', :bold_script, :unary)
437
+ b.add('tt', :monospace, :unary)
438
+ b.add('fr', :fraktur, :unary)
439
+ b.add('bfr', :bold_fraktur, :unary)
440
+ b.add('sf', :sans_serif, :unary)
441
+ b.add('bsf', :bold_sans_serif, :unary)
442
+ b.add('sfi', :sans_serif_italic, :unary)
443
+ b.add('sfbi', :sans_serif_bold_italic, :unary)
444
+
445
+ # Greek letters
446
+ b.add('alpha', :alpha, :symbol)
447
+ b.add('Alpha', :Alpha, :symbol)
448
+ b.add('beta', :beta, :symbol)
449
+ b.add('Beta', :Beta, :symbol)
450
+ b.add('gamma', :gamma, :symbol)
451
+ b.add('Gamma', :Gamma, :symbol)
452
+ b.add('delta', :delta, :symbol)
453
+ b.add('Delta', :Delta, :symbol)
454
+ b.add('epsi', 'epsilon', :epsilon, :symbol)
455
+ b.add('Epsilon', :Epsilon, :symbol)
456
+ b.add('varepsilon', :varepsilon, :symbol)
457
+ b.add('zeta', :zeta, :symbol)
458
+ b.add('Zeta', :Zeta, :symbol)
459
+ b.add('eta', :eta, :symbol)
460
+ b.add('Eta', :Eta, :symbol)
461
+ b.add('theta', :theta, :symbol)
462
+ b.add('Theta', :Theta, :symbol)
463
+ b.add('vartheta', :vartheta, :symbol)
464
+ b.add('iota', :iota, :symbol)
465
+ b.add('Iota', :Iota, :symbol)
466
+ b.add('kappa', :kappa, :symbol)
467
+ b.add('Kappa', :Kappa, :symbol)
468
+ b.add('lambda', :lambda, :symbol)
469
+ b.add('Lambda', :Lambda, :symbol)
470
+ b.add('mu', :mu, :symbol)
471
+ b.add('Mu', :Mu, :symbol)
472
+ b.add('nu', :nu, :symbol)
473
+ b.add('Nu', :Nu, :symbol)
474
+ b.add('xi', :xi, :symbol)
475
+ b.add('Xi', :Xi, :symbol)
476
+ b.add('omicron', :omicron, :symbol)
477
+ b.add('Omicron', :Omicron, :symbol)
478
+ b.add('pi', :pi, :symbol)
479
+ b.add('Pi', :Pi, :symbol)
480
+ b.add('rho', :rho, :symbol)
481
+ b.add('Rho', :Rho, :symbol)
482
+ b.add('sigma', :sigma, :symbol)
483
+ b.add('Sigma', :Sigma, :symbol)
484
+ b.add('tau', :tau, :symbol)
485
+ b.add('Tau', :Tau, :symbol)
486
+ b.add('upsilon', :upsilon, :symbol)
487
+ b.add('Upsilon', :Upsilon, :symbol)
488
+ b.add('phi', :phi, :symbol)
489
+ b.add('Phi', :Phi, :symbol)
490
+ b.add('varphi', :varphi, :symbol)
491
+ b.add('chi', :chi, :symbol)
492
+ b.add('Chi', :Chi, :symbol)
493
+ b.add('psi', :psi, :symbol)
494
+ b.add('Psi', :Psi, :symbol)
495
+ b.add('omega', :omega, :symbol)
496
+ b.add('Omega', :Omega, :symbol)
497
+
498
+ b
499
+ end
500
+
501
+ def initialize(symbol_table, color_table)
502
+ @symbol_table = symbol_table
503
+ @color_table = color_table
504
+ end
427
505
 
428
506
  def parse(input)
429
507
  Expression.new(
430
508
  input,
431
- parse_expression(Tokenizer.new(input, SYMBOLS), 0)
509
+ parse_expression(Tokenizer.new(input, @symbol_table), 0)
432
510
  )
433
511
  end
434
512
 
435
513
  private
514
+
515
+ include AsciiMath::AST
516
+
436
517
  def parse_expression(tok, depth)
437
518
  e = []
438
519
 
439
- while (s1 = parse_simple_expression(tok, depth))
520
+ while (s1 = parse_intermediate_expression(tok, depth))
440
521
  t1 = tok.next_token
441
522
 
442
- if t1[:type] == :infix
443
- s2 = parse_simple_expression(tok, depth)
444
- t2 = tok.next_token
445
- if t1[:value] == :sub && t2[:value] == :sup
446
- s3 = parse_simple_expression(tok, depth)
447
- operator = s1[:underover] ? :underover : :subsup
448
- e << {:type => :ternary, :operator => operator, :s1 => s1, :s2 => s2, :s3 => s3}
523
+ if t1[:type] == :infix && t1[:value] == :frac
524
+ s2 = parse_intermediate_expression(tok, depth)
525
+ if s2
526
+ e << infix(unwrap_paren(s1), symbol(:frac, t1[:text]), unwrap_paren(s2))
449
527
  else
450
- operator = s1[:underover] ? (t1[:value] == :sub ? :under : :over) : t1[:value]
451
- e << {:type => :binary, :operator => operator, :s1 => s1, :s2 => s2}
452
- tok.push_back(t2)
453
- if (t2[:type] == :lrparen || t2[:type] == :rparen) && depth > 0
454
- break
455
- end
528
+ e << s1
456
529
  end
457
530
  elsif t1[:type] == :eof
458
531
  e << s1
@@ -466,7 +539,46 @@ module AsciiMath
466
539
  end
467
540
  end
468
541
 
469
- e
542
+ expression(*e)
543
+ end
544
+
545
+ def parse_intermediate_expression(tok, depth)
546
+ s = parse_simple_expression(tok, depth)
547
+ sub = nil
548
+ sup = nil
549
+
550
+ t1 = tok.next_token
551
+ case t1[:type]
552
+ when :infix
553
+ case t1[:value]
554
+ when :sub
555
+ sub = parse_simple_expression(tok, depth)
556
+ if sub
557
+ t2 = tok.next_token
558
+ if t2[:type] == :infix && t2[:value] == :sup
559
+ sup = parse_simple_expression(tok, depth)
560
+ else
561
+ tok.push_back(t2)
562
+ end
563
+ end
564
+ when :sup
565
+ sup = parse_simple_expression(tok, depth)
566
+ else
567
+ tok.push_back(t1)
568
+ end
569
+ else
570
+ tok.push_back(t1)
571
+ end
572
+
573
+ if sub && sup
574
+ subsup(s, unwrap_paren(sub), unwrap_paren(sup))
575
+ elsif sub
576
+ sub(s, unwrap_paren(sub))
577
+ elsif sup
578
+ sup(s, unwrap_paren(sup))
579
+ else
580
+ s
581
+ end
470
582
  end
471
583
 
472
584
  def parse_simple_expression(tok, depth)
@@ -477,7 +589,7 @@ module AsciiMath
477
589
  t2 = tok.next_token
478
590
  case t2[:type]
479
591
  when :rparen, :lrparen
480
- {:type => :paren, :e => nil, :lparen => t1[:value], :rparen => t2[:value]}
592
+ paren(token_to_symbol(t1), nil, token_to_symbol(t2))
481
593
  else
482
594
  tok.push_back(t2)
483
595
 
@@ -486,67 +598,168 @@ module AsciiMath
486
598
  t2 = tok.next_token
487
599
  case t2[:type]
488
600
  when :rparen, :lrparen
489
- convert_to_matrix({:type => :paren, :e => e, :lparen => t1[:value], :rparen => t2[:value]})
601
+ convert_to_matrix(paren(token_to_symbol(t1), e, token_to_symbol(t2)))
490
602
  else
491
603
  tok.push_back(t2)
492
- {:type => :paren, :e => e, :lparen => t1[:value]}
604
+ paren(token_to_symbol(t1), e, nil)
493
605
  end
494
606
  end
495
- when :accent
496
- s = parse_simple_expression(tok, depth)
497
- {:type => :binary, :s1 => s, :s2 => {:type => :operator, :c => t1[:value]}, :operator => t1[:position]}
498
- when :unary, :font
499
- s = parse_simple_expression(tok, depth)
500
- {:type => t1[:type], :s => s, :operator => t1[:value]}
607
+ when :rparen
608
+ if depth > 0
609
+ tok.push_back(t1)
610
+ nil
611
+ else
612
+ token_to_symbol(t1)
613
+ end
614
+ when :unary
615
+ s = unwrap_paren(parse_simple_expression(tok, depth))
616
+ s = convert_node(s, t1[:convert_operand])
617
+ unary(token_to_symbol(t1), s)
501
618
  when :binary
502
- s1 = parse_simple_expression(tok, depth)
503
- s2 = parse_simple_expression(tok, depth)
504
- {:type => :binary, :s1 => s1, :s2 => s2, :operator => t1[:value]}
619
+ s1 = unwrap_paren(parse_simple_expression(tok, depth))
620
+ s2 = unwrap_paren(parse_simple_expression(tok, depth))
621
+
622
+ s1 = convert_node(s1, t1[:convert_operand1])
623
+ s2 = convert_node(s2, t1[:convert_operand2])
624
+
625
+ binary(token_to_symbol(t1), s1, s2)
505
626
  when :eof
506
627
  nil
628
+ when :number
629
+ number(t1[:value])
630
+ when :text
631
+ text(t1[:value])
632
+ when :identifier
633
+ identifier(t1[:value])
507
634
  else
508
- {:type => t1[:type], :c => t1[:value], :underover => t1[:underover]}
635
+ token_to_symbol(t1)
509
636
  end
510
637
  end
511
638
 
512
- def convert_to_matrix(expression)
513
- return expression unless matrix? expression
639
+ def token_to_symbol(t1)
640
+ symbol(t1[:value], t1[:text])
641
+ end
514
642
 
515
- rows = expression[:e].select.with_index { |obj, i| i.even? }.map do |row|
516
- row[:e].select.with_index { |obj, i| i.even? }
643
+ def unwrap_paren(node)
644
+ if node.is_a?(::AsciiMath::AST::Paren)
645
+ group(node.lparen, node.expression, node.rparen)
646
+ else
647
+ node
517
648
  end
518
-
519
- {:type => :matrix, :rows => rows, :lparen => expression[:lparen], :rparen => expression[:rparen]}
520
649
  end
521
650
 
522
- def matrix?(expression)
523
- return false unless expression.is_a?(Hash) && expression[:type] == :paren
524
-
525
- rows, separators = expression[:e].partition.with_index { |obj, i| i.even? }
651
+ def convert_to_matrix(node)
652
+ return node unless node.is_a?(::AsciiMath::AST::Paren) && node.expression.is_a?(::AsciiMath::AST::Sequence)
526
653
 
527
- rows.length > 1 &&
654
+ rows, separators = node.expression.partition.with_index { |obj, i| i.even? }
655
+ return node unless rows.length > 1 &&
528
656
  rows.length > separators.length &&
529
- separators.all? { |item| item[:type] == :identifier && item[:c] == ',' } &&
530
- (rows.all? { |item| item[:type] == :paren && item[:lparen] == '(' && item[:rparen] == ')' } ||
531
- rows.all? { |item| item[:type] == :paren && item[:lparen] == '[' && item[:rparen] == ']' }) &&
532
- rows.all? { |item| item[:e].length == rows[0][:e].length } &&
533
- rows.all? { |item| matrix_cols?(item[:e]) }
657
+ separators.all? { |item| is_matrix_separator(item) } &&
658
+ (rows.all? { |item| item.is_a?(::AsciiMath::AST::Paren) && item.lparen == symbol(:lparen, '(') && item.rparen == symbol(:rparen, ')') } ||
659
+ rows.all? { |item| item.is_a?(::AsciiMath::AST::Paren) && item.lparen == symbol(:lbracket, '[') && item.rparen == symbol(:rbracket, ']') })
660
+
661
+ rows = rows.map do |row|
662
+ chunks = []
663
+ current_chunk = []
664
+
665
+ row_content = row.expression
666
+ unless row_content.is_a?(::AsciiMath::AST::Sequence)
667
+ [expression(row_content)]
668
+ else
669
+ row_content.each do |item|
670
+ if is_matrix_separator(item)
671
+ chunks << current_chunk
672
+ current_chunk = []
673
+ else
674
+ current_chunk << item
675
+ end
676
+ end
677
+
678
+ chunks << current_chunk
679
+
680
+ chunks.map { |c| c.length == 1 ? c[0] : expression(*c) }.to_a
681
+ end
682
+ end
683
+
684
+ return node unless rows.all? { |row| row.length == rows[0].length }
685
+
686
+ matrix(node.lparen, rows, node.rparen)
534
687
  end
535
688
 
536
- def matrix_cols?(expression)
537
- return false unless expression.is_a?(Array)
689
+ def is_matrix_separator(node)
690
+ node.is_a?(Identifier) && node.value == ','
691
+ end
692
+
693
+ def convert_node(node, converter)
694
+ case converter
695
+ when nil
696
+ node
697
+ when UnboundMethod
698
+ converter.bind(self).call(node)
699
+ when Method, Proc
700
+ converter.call(node)
701
+ end
702
+ end
538
703
 
539
- cols, separators = expression.partition.with_index { |obj, i| i.even? }
704
+ def convert_to_color(color_expression)
705
+ s = ""
706
+ append_color_text(s, color_expression)
707
+ s
540
708
 
541
- cols.all? { |item| item[:type] != :identifier || item[:c] != ',' } &&
542
- separators.all? { |item| item[:type] == :identifier && item[:c] == ',' }
709
+ case s
710
+ when /#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/i
711
+ color_value = {:r => $1.to_i(16), :g => $2.to_i(16), :b => $3.to_i(16), }
712
+ when /#([0-9a-f])([0-9a-f])([0-9a-f])/i
713
+ color_value = {:r => "#{$1}#{$1}".to_i(16), :g => "#{$2}#{$2}".to_i(16), :b => "#{$3}#{$3}".to_i(16), }
714
+ else
715
+ color_value = @color_table[s.downcase] || {:r => 0, :g => 0, :b => 0}
716
+ end
717
+
718
+ color(color_value[:r], color_value[:g], color_value[:b], s)
719
+ end
720
+
721
+ def append_color_text(s, node)
722
+ case node
723
+ when ::AsciiMath::AST::Sequence
724
+ node.each { |n| append_color_text(s, n) }
725
+ when ::AsciiMath::AST::Number, ::AsciiMath::AST::Identifier, ::AsciiMath::AST::Text
726
+ s << node.value
727
+ when ::AsciiMath::AST::Symbol
728
+ s << node.text
729
+ when ::AsciiMath::AST::Group
730
+ append_color_text(s, node.expression)
731
+ when ::AsciiMath::AST::Paren
732
+ append_color_text(s, node.lparen)
733
+ append_color_text(s, node.expression)
734
+ append_color_text(s, node.rparen)
735
+ when ::AsciiMath::AST::SubSup
736
+ append_color_text(s, node.base_expression)
737
+ append_color_text(s, node.operator)
738
+ append_color_text(s, node.operand2)
739
+ when ::AsciiMath::AST::UnaryOp
740
+ append_color_text(s, node.operator)
741
+ append_color_text(s, node.operand)
742
+ when ::AsciiMath::AST::BinaryOp
743
+ append_color_text(s, node.operator)
744
+ append_color_text(s, node.operand1)
745
+ append_color_text(s, node.operand2)
746
+ when ::AsciiMath::AST::InfixOp
747
+ append_color_text(s, node.operand1)
748
+ append_color_text(s, node.operator)
749
+ append_color_text(s, node.operand2)
750
+ end
543
751
  end
752
+
753
+ DEFAULT_COLOR_TABLE = ::AsciiMath::Parser.add_default_colors(AsciiMath::ColorTableBuilder.new).build
754
+ DEFAULT_PARSER_SYMBOL_TABLE = ::AsciiMath::Parser.add_default_parser_symbols(AsciiMath::SymbolTableBuilder.new).build
544
755
  end
545
756
 
546
757
  class Expression
547
- def initialize(asciimath, parsed_expression)
758
+ attr_accessor :ast
759
+
760
+ def initialize(asciimath, ast)
548
761
  @asciimath = asciimath
549
- @parsed_expression = parsed_expression
762
+ @ast = ast
550
763
  end
551
764
 
552
765
  def to_s
@@ -554,7 +767,7 @@ module AsciiMath
554
767
  end
555
768
  end
556
769
 
557
- def self.parse(asciimath)
558
- Parser.new.parse(asciimath)
770
+ def self.parse(asciimath, parser_symbol_table = ::AsciiMath::Parser::DEFAULT_PARSER_SYMBOL_TABLE, parser_color_table = ::AsciiMath::Parser::DEFAULT_COLOR_TABLE)
771
+ Parser.new(parser_symbol_table, parser_color_table).parse(asciimath)
559
772
  end
560
773
  end