asciimath 1.0.9 → 2.0.3

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 (59) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ci.yml +20 -0
  3. data/AST.adoc +457 -0
  4. data/CHANGELOG.adoc +47 -1
  5. data/Gemfile +5 -0
  6. data/README.adoc +68 -4
  7. data/asciimath.gemspec +3 -6
  8. data/dump_symbol_table.rb +46 -0
  9. data/lib/asciimath.rb +5 -4
  10. data/lib/asciimath/ast.rb +456 -0
  11. data/lib/asciimath/cli.rb +4 -1
  12. data/lib/asciimath/color_table.rb +21 -0
  13. data/lib/asciimath/html.rb +128 -112
  14. data/lib/asciimath/latex.rb +399 -0
  15. data/lib/asciimath/markup.rb +509 -0
  16. data/lib/asciimath/mathml.rb +206 -87
  17. data/lib/asciimath/parser.rb +510 -350
  18. data/lib/asciimath/symbol_table.rb +25 -0
  19. data/lib/asciimath/version.rb +1 -1
  20. data/spec/ast.rb +144 -0
  21. data/spec/customisation_spec.rb +28 -0
  22. data/spec/parser_spec.rb +623 -165
  23. data/spec/schema/mathml2/common/common-attribs.xsd +41 -0
  24. data/spec/schema/mathml2/common/math.xsd +126 -0
  25. data/spec/schema/mathml2/common/xlink-href.xsd +20 -0
  26. data/spec/schema/mathml2/content/arith.xsd +90 -0
  27. data/spec/schema/mathml2/content/calculus.xsd +146 -0
  28. data/spec/schema/mathml2/content/common-attrib.xsd +30 -0
  29. data/spec/schema/mathml2/content/constants.xsd +83 -0
  30. data/spec/schema/mathml2/content/constructs.xsd +260 -0
  31. data/spec/schema/mathml2/content/elementary-functions.xsd +117 -0
  32. data/spec/schema/mathml2/content/functions.xsd +73 -0
  33. data/spec/schema/mathml2/content/linear-algebra.xsd +173 -0
  34. data/spec/schema/mathml2/content/logic.xsd +53 -0
  35. data/spec/schema/mathml2/content/relations.xsd +55 -0
  36. data/spec/schema/mathml2/content/semantics.xsd +85 -0
  37. data/spec/schema/mathml2/content/sets.xsd +236 -0
  38. data/spec/schema/mathml2/content/statistics.xsd +136 -0
  39. data/spec/schema/mathml2/content/tokens.xsd +120 -0
  40. data/spec/schema/mathml2/content/vector-calculus.xsd +88 -0
  41. data/spec/schema/mathml2/mathml2.xsd +59 -0
  42. data/spec/schema/mathml2/presentation/action.xsd +44 -0
  43. data/spec/schema/mathml2/presentation/characters.xsd +37 -0
  44. data/spec/schema/mathml2/presentation/common-attribs.xsd +113 -0
  45. data/spec/schema/mathml2/presentation/common-types.xsd +103 -0
  46. data/spec/schema/mathml2/presentation/error.xsd +40 -0
  47. data/spec/schema/mathml2/presentation/layout.xsd +195 -0
  48. data/spec/schema/mathml2/presentation/scripts.xsd +186 -0
  49. data/spec/schema/mathml2/presentation/space.xsd +52 -0
  50. data/spec/schema/mathml2/presentation/style.xsd +69 -0
  51. data/spec/schema/mathml2/presentation/table.xsd +216 -0
  52. data/spec/schema/mathml2/presentation/tokens.xsd +124 -0
  53. data/spec/schema/mathml3/mathml3-common.xsd +99 -0
  54. data/spec/schema/mathml3/mathml3-content.xsd +684 -0
  55. data/spec/schema/mathml3/mathml3-presentation.xsd +2151 -0
  56. data/spec/schema/mathml3/mathml3-strict-content.xsd +186 -0
  57. data/spec/schema/mathml3/mathml3.xsd +9 -0
  58. metadata +88 -48
  59. data/.travis.yml +0 -18
@@ -1,8 +1,21 @@
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] || ::AsciiMath::MarkupBuilder.default_display_symbol_table(fix_phi: opts.fetch(:fix_phi, true)))
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
18
+ @escape_non_ascii = opts.fetch(:escape_non_ascii, true)
6
19
  end
7
20
 
8
21
  def to_s
@@ -11,78 +24,166 @@ module AsciiMath
11
24
 
12
25
  def append_expression(expression, attrs = {})
13
26
  math('', attrs) do
14
- append(expression, :single_child => true)
27
+ append(expression, :row => :omit)
15
28
  end
16
29
  end
17
30
 
18
31
  private
19
32
 
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
33
+ def append_row(expressions)
34
+ mrow do
35
+ expressions.each { |e| append(e) }
36
+ end
37
+ end
38
+
39
+ def append_operator(operator)
40
+ mo(operator)
41
+ end
42
+
43
+ def append_identifier(identifier)
44
+ mi(identifier)
45
+ end
46
+
47
+ def append_text(text)
48
+ mtext(text)
49
+ end
50
+
51
+ def append_number(number)
52
+ mn(number)
53
+ end
54
+
55
+ def append_sqrt(expression)
56
+ tag("m#{"sqrt"}") do
57
+ append(expression, :row => @row_mode)
58
+ end
59
+ end
60
+
61
+ def append_cancel(expression)
62
+ tag("menclose", :notation => "updiagonalstrike") do
63
+ append(expression, :row => :omit)
64
+ end
65
+ end
66
+
67
+ def append_root(base, index)
68
+ tag("m#{"root"}") do
69
+ append(base, :row => @row_mode)
70
+ append(index, :row => @row_mode)
71
+ end
72
+ end
73
+
74
+ def append_fraction(numerator, denominator)
75
+ tag("m#{"frac"}") do
76
+ append(numerator, :row => @row_mode)
77
+ append(denominator, :row => @row_mode)
78
+ end
79
+ end
80
+
81
+
82
+ def append_font(style, e)
83
+ tag("mstyle", :mathvariant => style.to_s.gsub('_', '-')) do
84
+ append(e)
85
+ end
86
+ end
87
+
88
+ def append_color(color, e)
89
+ tag("mstyle", :mathcolor => color) do
90
+ append(e)
91
+ end
92
+ end
93
+
94
+ def append_matrix(lparen, rows, rparen)
95
+ fenced(lparen, rparen) do
96
+ mtable do
97
+ rows.each do |row|
98
+ mtr do
99
+ row.each do |col|
100
+ mtd do
101
+ append(col)
83
102
  end
84
103
  end
104
+ end
85
105
  end
106
+ end
107
+ end
108
+ end
109
+
110
+ def append_operator_unary(operator, expression)
111
+ mrow do
112
+ mo(operator)
113
+ append(expression, :row => @row_mode)
114
+ end
115
+ end
116
+
117
+ def append_identifier_unary(identifier, expression)
118
+ mrow do
119
+ mi(identifier)
120
+ append(expression, :row => @row_mode)
121
+ end
122
+ end
123
+
124
+ def append_paren(lparen, e, rparen, opts = {})
125
+ fenced(lparen, rparen) do
126
+ append(e, :row => @row_mode)
127
+ end
128
+ end
129
+
130
+ def append_subsup(base, sub, sup)
131
+ if sub && sup
132
+ msubsup do
133
+ append(base, :row => @row_mode)
134
+ append(sub, :row => @row_mode)
135
+ append(sup, :row => @row_mode)
136
+ end
137
+ elsif sub
138
+ msub do
139
+ append(base, :row => @row_mode)
140
+ append(sub, :row => @row_mode)
141
+ end
142
+ elsif sup
143
+ msup do
144
+ append(base, :row => @row_mode)
145
+ append(sup, :row => @row_mode)
146
+ end
147
+ else
148
+ append(base)
149
+ end
150
+ end
151
+
152
+ def append_underover(base, sub, sup)
153
+ attrs = {}
154
+
155
+ sub_row_mode = @row_mode
156
+ if is_accent(sub)
157
+ attrs[:accentunder] = true
158
+ sub_row_mode = :avoid
159
+ end
160
+
161
+ sup_row_mode = @row_mode
162
+ if is_accent(sup)
163
+ attrs[:accent] = true
164
+ sup_row_mode = :avoid
165
+ end
166
+
167
+
168
+
169
+ if sub && sup
170
+ munderover(attrs) do
171
+ append(base, :row => @row_mode)
172
+ append(sub, :row => sub_row_mode)
173
+ append(sup, :row => sup_row_mode)
174
+ end
175
+ elsif sub
176
+ munder(attrs) do
177
+ append(base, :row => @row_mode)
178
+ append(sub, :row => sub_row_mode)
179
+ end
180
+ elsif sup
181
+ mover(attrs) do
182
+ append(base, :row => @row_mode)
183
+ append(sup, :row => sup_row_mode)
184
+ end
185
+ else
186
+ append(base)
86
187
  end
87
188
  end
88
189
 
@@ -90,10 +191,18 @@ module AsciiMath
90
191
  tag(meth, *args, &block)
91
192
  end
92
193
 
93
- def fenced(lparen, rparen, &block)
194
+ def fenced(lparen, rparen)
94
195
  if lparen || rparen
95
- mfenced(:open => lparen || '', :close => rparen || '') do
96
- yield self
196
+ if @fence_mode == :fenced
197
+ mfenced(:open => lparen || '', :close => rparen || '') do
198
+ yield self
199
+ end
200
+ else
201
+ mrow do
202
+ mo(lparen) if lparen
203
+ yield self
204
+ mo(rparen) if rparen
205
+ end
97
206
  end
98
207
  else
99
208
  yield self
@@ -102,41 +211,51 @@ module AsciiMath
102
211
 
103
212
  def tag(tag, *args)
104
213
  attrs = args.last.is_a?(Hash) ? args.pop : {}
105
- text = args.last.is_a?(String) ? args.pop : ''
214
+ text = args.last.is_a?(String) || args.last.is_a?(Symbol) ? args.pop.to_s : ''
106
215
 
107
216
  @mathml << '<' << @prefix << tag.to_s
108
217
 
109
218
  attrs.each_pair do |key, value|
110
- @mathml << ' ' << key.to_s << '="' << value.to_s << '"'
219
+ @mathml << ' ' << key.to_s << '="'
220
+ append_escaped(value.to_s)
221
+ @mathml << '"'
111
222
  end
112
223
 
113
224
 
114
225
  if block_given? || text
115
226
  @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
227
+ append_escaped(text)
129
228
  yield self if block_given?
130
229
  @mathml << '</' << @prefix << tag.to_s << '>'
131
230
  else
132
231
  @mathml << '/>'
133
232
  end
134
233
  end
234
+
235
+ def append_escaped(text)
236
+ text.each_codepoint do |cp|
237
+ if cp == 38
238
+ @mathml << "&amp;"
239
+ elsif cp == 60
240
+ @mathml << "&lt;"
241
+ elsif cp == 62
242
+ @mathml << "&gt;"
243
+ elsif cp > 127 && @escape_non_ascii
244
+ @mathml << "&#x#{cp.to_s(16).upcase};"
245
+ else
246
+ @mathml << cp
247
+ end
248
+ end
249
+ end
135
250
  end
136
251
 
137
252
  class Expression
138
253
  def to_mathml(prefix = "", attrs = {})
139
- MathMLBuilder.new(prefix).append_expression(@parsed_expression, attrs).to_s
254
+ if prefix.is_a? Hash
255
+ attrs = prefix
256
+ prefix = ""
257
+ end
258
+ MathMLBuilder.new(:prefix => prefix).append_expression(ast, attrs).to_s
140
259
  end
141
260
  end
142
- end
261
+ 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,335 @@ 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('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
+ b.add('rm', :roman, :unary)
445
+
446
+ # Greek letters
447
+ b.add('alpha', :alpha, :symbol)
448
+ b.add('Alpha', :Alpha, :symbol)
449
+ b.add('beta', :beta, :symbol)
450
+ b.add('Beta', :Beta, :symbol)
451
+ b.add('gamma', :gamma, :symbol)
452
+ b.add('Gamma', :Gamma, :symbol)
453
+ b.add('delta', :delta, :symbol)
454
+ b.add('Delta', :Delta, :symbol)
455
+ b.add('epsi', 'epsilon', :epsilon, :symbol)
456
+ b.add('Epsilon', :Epsilon, :symbol)
457
+ b.add('varepsilon', :varepsilon, :symbol)
458
+ b.add('zeta', :zeta, :symbol)
459
+ b.add('Zeta', :Zeta, :symbol)
460
+ b.add('eta', :eta, :symbol)
461
+ b.add('Eta', :Eta, :symbol)
462
+ b.add('theta', :theta, :symbol)
463
+ b.add('Theta', :Theta, :symbol)
464
+ b.add('vartheta', :vartheta, :symbol)
465
+ b.add('iota', :iota, :symbol)
466
+ b.add('Iota', :Iota, :symbol)
467
+ b.add('kappa', :kappa, :symbol)
468
+ b.add('Kappa', :Kappa, :symbol)
469
+ b.add('lambda', :lambda, :symbol)
470
+ b.add('Lambda', :Lambda, :symbol)
471
+ b.add('mu', :mu, :symbol)
472
+ b.add('Mu', :Mu, :symbol)
473
+ b.add('nu', :nu, :symbol)
474
+ b.add('Nu', :Nu, :symbol)
475
+ b.add('xi', :xi, :symbol)
476
+ b.add('Xi', :Xi, :symbol)
477
+ b.add('omicron', :omicron, :symbol)
478
+ b.add('Omicron', :Omicron, :symbol)
479
+ b.add('pi', :pi, :symbol)
480
+ b.add('Pi', :Pi, :symbol)
481
+ b.add('rho', :rho, :symbol)
482
+ b.add('Rho', :Rho, :symbol)
483
+ b.add('sigma', :sigma, :symbol)
484
+ b.add('Sigma', :Sigma, :symbol)
485
+ b.add('tau', :tau, :symbol)
486
+ b.add('Tau', :Tau, :symbol)
487
+ b.add('upsilon', :upsilon, :symbol)
488
+ b.add('Upsilon', :Upsilon, :symbol)
489
+ b.add('phi', :phi, :symbol)
490
+ b.add('Phi', :Phi, :symbol)
491
+ b.add('varphi', :varphi, :symbol)
492
+ b.add('chi', :chi, :symbol)
493
+ b.add('Chi', :Chi, :symbol)
494
+ b.add('psi', :psi, :symbol)
495
+ b.add('Psi', :Psi, :symbol)
496
+ b.add('omega', :omega, :symbol)
497
+ b.add('Omega', :Omega, :symbol)
498
+
499
+ b
500
+ end
501
+
502
+ def initialize(symbol_table, color_table)
503
+ @symbol_table = symbol_table
504
+ @color_table = color_table
505
+ end
458
506
 
459
507
  def parse(input)
460
508
  Expression.new(
461
509
  input,
462
- parse_expression(Tokenizer.new(input, SYMBOLS), 0)
510
+ parse_expression(Tokenizer.new(input, @symbol_table), 0)
463
511
  )
464
512
  end
465
513
 
466
514
  private
515
+
516
+ include AsciiMath::AST
517
+
467
518
  def parse_expression(tok, depth)
468
519
  e = []
469
520
 
470
- while (s1 = parse_simple_expression(tok, depth))
521
+ while (s1 = parse_intermediate_expression(tok, depth))
471
522
  t1 = tok.next_token
472
523
 
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}
524
+ if t1[:type] == :infix && t1[:value] == :frac
525
+ s2 = parse_intermediate_expression(tok, depth)
526
+ if s2
527
+ e << infix(unwrap_paren(s1), symbol(:frac, t1[:text]), unwrap_paren(s2))
480
528
  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
529
+ e << s1
487
530
  end
488
531
  elsif t1[:type] == :eof
489
532
  e << s1
@@ -497,7 +540,46 @@ module AsciiMath
497
540
  end
498
541
  end
499
542
 
500
- e
543
+ expression(*e)
544
+ end
545
+
546
+ def parse_intermediate_expression(tok, depth)
547
+ s = parse_simple_expression(tok, depth)
548
+ sub = nil
549
+ sup = nil
550
+
551
+ t1 = tok.next_token
552
+ case t1[:type]
553
+ when :infix
554
+ case t1[:value]
555
+ when :sub
556
+ sub = parse_simple_expression(tok, depth)
557
+ if sub
558
+ t2 = tok.next_token
559
+ if t2[:type] == :infix && t2[:value] == :sup
560
+ sup = parse_simple_expression(tok, depth)
561
+ else
562
+ tok.push_back(t2)
563
+ end
564
+ end
565
+ when :sup
566
+ sup = parse_simple_expression(tok, depth)
567
+ else
568
+ tok.push_back(t1)
569
+ end
570
+ else
571
+ tok.push_back(t1)
572
+ end
573
+
574
+ if sub && sup
575
+ subsup(s, unwrap_paren(sub), unwrap_paren(sup))
576
+ elsif sub
577
+ sub(s, unwrap_paren(sub))
578
+ elsif sup
579
+ sup(s, unwrap_paren(sup))
580
+ else
581
+ s
582
+ end
501
583
  end
502
584
 
503
585
  def parse_simple_expression(tok, depth)
@@ -508,7 +590,7 @@ module AsciiMath
508
590
  t2 = tok.next_token
509
591
  case t2[:type]
510
592
  when :rparen, :lrparen
511
- {:type => :paren, :e => nil, :lparen => t1[:value], :rparen => t2[:value]}
593
+ paren(token_to_symbol(t1), nil, token_to_symbol(t2))
512
594
  else
513
595
  tok.push_back(t2)
514
596
 
@@ -517,93 +599,171 @@ module AsciiMath
517
599
  t2 = tok.next_token
518
600
  case t2[:type]
519
601
  when :rparen, :lrparen
520
- convert_to_matrix({:type => :paren, :e => e, :lparen => t1[:value], :rparen => t2[:value]})
602
+ convert_to_matrix(paren(token_to_symbol(t1), e, token_to_symbol(t2)))
521
603
  else
522
604
  tok.push_back(t2)
523
- {:type => :paren, :e => e, :lparen => t1[:value]}
605
+ paren(token_to_symbol(t1), e, nil)
524
606
  end
525
607
  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]}
608
+ when :rparen
609
+ if depth > 0
610
+ tok.push_back(t1)
611
+ nil
612
+ else
613
+ token_to_symbol(t1)
614
+ end
615
+ when :unary
616
+ parse_simple_expression = parse_simple_expression(tok, depth)
617
+ s = unwrap_paren(parse_simple_expression)
618
+ s = identifier('') if s.nil?
619
+ s = convert_node(s, t1[:convert_operand])
620
+ unary(token_to_symbol(t1), s)
532
621
  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]}
622
+ s1 = unwrap_paren(parse_simple_expression(tok, depth))
623
+ s1 = identifier('') if s1.nil?
624
+ s2 = unwrap_paren(parse_simple_expression(tok, depth))
625
+ s2 = identifier('') if s2.nil?
626
+
627
+ s1 = convert_node(s1, t1[:convert_operand1])
628
+ s2 = convert_node(s2, t1[:convert_operand2])
629
+
630
+ binary(token_to_symbol(t1), s1, s2)
536
631
  when :eof
537
632
  nil
633
+ when :number
634
+ number(t1[:value])
635
+ when :text
636
+ text(t1[:value])
637
+ when :identifier
638
+ identifier(t1[:value])
538
639
  else
539
- {:type => t1[:type], :c => t1[:value], :underover => t1[:underover]}
640
+ token_to_symbol(t1)
641
+ end
642
+ end
643
+
644
+ def token_to_symbol(t1)
645
+ symbol(t1[:value], t1[:text])
646
+ end
647
+
648
+ def unwrap_paren(node)
649
+ if node.is_a?(::AsciiMath::AST::Paren)
650
+ group(node.lparen, node.expression, node.rparen)
651
+ else
652
+ node
540
653
  end
541
654
  end
542
655
 
543
- def convert_to_matrix(expression)
544
- return expression unless expression.is_a?(Hash) && expression[:type] == :paren
656
+ def convert_to_matrix(node)
657
+ return node unless node.is_a?(::AsciiMath::AST::Paren) && node.expression.is_a?(::AsciiMath::AST::Sequence)
545
658
 
546
- rows, separators = expression[:e].partition.with_index { |obj, i| i.even? }
547
- return expression unless rows.length > 1 &&
659
+ rows, separators = node.expression.partition.with_index { |obj, i| i.even? }
660
+ return node unless rows.length > 1 &&
548
661
  rows.length > separators.length &&
549
662
  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] == ']' })
663
+ (rows.all? { |item| item.is_a?(::AsciiMath::AST::Paren) && item.lparen == symbol(:lparen, '(') && item.rparen == symbol(:rparen, ')') } ||
664
+ rows.all? { |item| item.is_a?(::AsciiMath::AST::Paren) && item.lparen == symbol(:lbracket, '[') && item.rparen == symbol(:rbracket, ']') })
552
665
 
553
666
  rows = rows.map do |row|
554
667
  chunks = []
555
668
  current_chunk = []
556
- row[:e].each do |item|
557
- if is_matrix_separator(item)
558
- chunks << current_chunk
559
- current_chunk = []
560
- else
561
- current_chunk << item
669
+
670
+ row_content = row.expression
671
+ unless row_content.is_a?(::AsciiMath::AST::Sequence)
672
+ [expression(row_content)]
673
+ else
674
+ row_content.each do |item|
675
+ if is_matrix_separator(item)
676
+ chunks << current_chunk
677
+ current_chunk = []
678
+ else
679
+ current_chunk << item
680
+ end
562
681
  end
563
- end
564
682
 
565
- chunks << current_chunk
683
+ chunks << current_chunk
566
684
 
567
- chunks.map {|c| c.length == 1 ? c[0] : c }.to_a
685
+ chunks.map { |c| c.length == 1 ? c[0] : expression(*c) }.to_a
686
+ end
568
687
  end
569
688
 
570
- return expression unless rows.all? { |row| row.length == rows[0].length }
689
+ return node unless rows.all? { |row| row.length == rows[0].length }
571
690
 
572
- {:type => :matrix, :rows => rows, :lparen => expression[:lparen], :rparen => expression[:rparen]}
691
+ matrix(node.lparen, rows, node.rparen)
573
692
  end
574
693
 
575
- def is_matrix_separator(item)
576
- item[:type] == :identifier && item[:c] == ','
694
+ def is_matrix_separator(node)
695
+ node.is_a?(Identifier) && node.value == ','
577
696
  end
578
697
 
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]) }
698
+ def convert_node(node, converter)
699
+ case converter
700
+ when nil
701
+ node
702
+ when UnboundMethod
703
+ converter.bind(self).call(node)
704
+ when Method, Proc
705
+ converter.call(node)
706
+ end
591
707
  end
592
708
 
593
- def matrix_cols?(expression)
594
- return false unless expression.is_a?(Array)
709
+ def convert_to_color(color_expression)
710
+ s = ""
711
+ append_color_text(s, color_expression)
595
712
 
596
- cols, separators = expression.partition.with_index { |obj, i| i.even? }
713
+ case s
714
+ when /#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/i
715
+ color_value = {:r => $1.to_i(16), :g => $2.to_i(16), :b => $3.to_i(16), }
716
+ when /#([0-9a-f])([0-9a-f])([0-9a-f])/i
717
+ color_value = {:r => "#{$1}#{$1}".to_i(16), :g => "#{$2}#{$2}".to_i(16), :b => "#{$3}#{$3}".to_i(16), }
718
+ else
719
+ color_value = @color_table[s.downcase] || {:r => 0, :g => 0, :b => 0}
720
+ end
597
721
 
598
- cols.all? { |item| item[:type] != :identifier || item[:c] != ',' } &&
599
- separators.all?(&method(:is_col_separator))
722
+ color(color_value[:r], color_value[:g], color_value[:b], s)
600
723
  end
724
+
725
+ def append_color_text(s, node)
726
+ case node
727
+ when ::AsciiMath::AST::Sequence
728
+ node.each { |n| append_color_text(s, n) }
729
+ when ::AsciiMath::AST::Number, ::AsciiMath::AST::Identifier, ::AsciiMath::AST::Text
730
+ s << node.value
731
+ when ::AsciiMath::AST::Symbol
732
+ s << node.text
733
+ when ::AsciiMath::AST::Group
734
+ append_color_text(s, node.expression)
735
+ when ::AsciiMath::AST::Paren
736
+ append_color_text(s, node.lparen)
737
+ append_color_text(s, node.expression)
738
+ append_color_text(s, node.rparen)
739
+ when ::AsciiMath::AST::SubSup
740
+ append_color_text(s, node.base_expression)
741
+ append_color_text(s, node.operator)
742
+ append_color_text(s, node.operand2)
743
+ when ::AsciiMath::AST::UnaryOp
744
+ append_color_text(s, node.operator)
745
+ append_color_text(s, node.operand)
746
+ when ::AsciiMath::AST::BinaryOp
747
+ append_color_text(s, node.operator)
748
+ append_color_text(s, node.operand1)
749
+ append_color_text(s, node.operand2)
750
+ when ::AsciiMath::AST::InfixOp
751
+ append_color_text(s, node.operand1)
752
+ append_color_text(s, node.operator)
753
+ append_color_text(s, node.operand2)
754
+ end
755
+ end
756
+
757
+ DEFAULT_COLOR_TABLE = ::AsciiMath::Parser.add_default_colors(AsciiMath::ColorTableBuilder.new).build
758
+ DEFAULT_PARSER_SYMBOL_TABLE = ::AsciiMath::Parser.add_default_parser_symbols(AsciiMath::SymbolTableBuilder.new).build
601
759
  end
602
760
 
603
761
  class Expression
604
- def initialize(asciimath, parsed_expression)
762
+ attr_accessor :ast
763
+
764
+ def initialize(asciimath, ast)
605
765
  @asciimath = asciimath
606
- @parsed_expression = parsed_expression
766
+ @ast = ast
607
767
  end
608
768
 
609
769
  def to_s
@@ -611,7 +771,7 @@ module AsciiMath
611
771
  end
612
772
  end
613
773
 
614
- def self.parse(asciimath)
615
- Parser.new.parse(asciimath)
774
+ def self.parse(asciimath, parser_symbol_table = ::AsciiMath::Parser::DEFAULT_PARSER_SYMBOL_TABLE, parser_color_table = ::AsciiMath::Parser::DEFAULT_COLOR_TABLE)
775
+ Parser.new(parser_symbol_table, parser_color_table).parse(asciimath)
616
776
  end
617
777
  end