asciimath 1.0.6 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +5 -5
  2. data/.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