class AsciiMath::Parser
Constants
- DEFAULT_COLOR_TABLE
- DEFAULT_PARSER_SYMBOL_TABLE
Public Class Methods
add_default_colors(b)
click to toggle source
# File lib/asciimath/parser.rb, line 201 def self.add_default_colors(b) b.add('aqua', 0, 255, 255) b.add('black', 0, 0, 0) b.add('blue', 0, 0, 255) b.add('fuchsia', 255, 0, 255) b.add('gray', 128, 128, 128) b.add('green', 0, 128, 0) b.add('lime', 0, 255, 0) b.add('maroon', 128, 0, 0) b.add('navy', 0, 0, 128) b.add('olive', 128, 128, 0) b.add('purple', 128, 0, 128) b.add('red', 255, 0, 0) b.add('silver', 192, 192, 192) b.add('teal', 0, 128, 128) b.add('white', 255, 255, 255) b.add('yellow', 255, 255, 0) b end
add_default_parser_symbols(b)
click to toggle source
# File lib/asciimath/parser.rb, line 221 def self.add_default_parser_symbols(b) # Operation symbols b.add('+', :plus, :symbol) b.add('-', :minus, :symbol) b.add('*', 'cdot', :cdot, :symbol) b.add('**', 'ast', :ast, :symbol) b.add('***', 'star', :star, :symbol) b.add('//', :slash, :symbol) b.add('\\\\', 'backslash', :backslash, :symbol) b.add('setminus', :setminus, :symbol) b.add('xx', 'times', :times, :symbol) b.add('|><', 'ltimes', :ltimes, :symbol) b.add('><|', 'rtimes', :rtimes, :symbol) b.add('|><|', 'bowtie', :bowtie, :symbol) b.add('-:', 'div', 'divide', :div, :symbol) b.add('@', 'circ', :circ, :symbol) b.add('o+', 'oplus', :oplus, :symbol) b.add('ox', 'otimes', :otimes, :symbol) b.add('o.', 'odot', :odot, :symbol) b.add('sum', :sum, :symbol) b.add('prod', :prod, :symbol) b.add('^^', 'wedge', :wedge, :symbol) b.add('^^^', 'bigwedge', :bigwedge, :symbol) b.add('vv', 'vee', :vee, :symbol) b.add('vvv', 'bigvee', :bigvee, :symbol) b.add('nn', 'cap', :cap, :symbol) b.add('nnn', 'bigcap', :bigcap, :symbol) b.add('uu', 'cup', :cup, :symbol) b.add('uuu', 'bigcup', :bigcup, :symbol) # Relation symbols b.add('=', :eq, :symbol) b.add('!=', 'ne', :ne, :symbol) b.add(':=', :assign, :symbol) b.add('<', 'lt', :lt, :symbol) b.add('>', 'gt', :gt, :symbol) b.add('<=', 'le', :le, :symbol) b.add('>=', 'ge', :ge, :symbol) b.add('-<', '-lt', 'prec', :prec, :symbol) b.add('>-', 'succ', :succ, :symbol) b.add('-<=', 'preceq', :preceq, :symbol) b.add('>-=', 'succeq', :succeq, :symbol) b.add('in', :in, :symbol) b.add('!in', 'notin', :notin, :symbol) b.add('sub', 'subset', :subset, :symbol) b.add('sup', 'supset', :supset, :symbol) b.add('sube', 'subseteq', :subseteq, :symbol) b.add('supe', 'supseteq', :supseteq, :symbol) b.add('-=', 'equiv', :equiv, :symbol) b.add('~=', 'cong', :cong, :symbol) b.add('~~', 'approx', :approx, :symbol) b.add('prop', 'propto', :propto, :symbol) # Logical symbols b.add('and', :and, :symbol) b.add('or', :or, :symbol) b.add('not', 'neg', :not, :symbol) b.add('=>', 'implies', :implies, :symbol) b.add('if', :if, :symbol) b.add('<=>', 'iff', :iff, :symbol) b.add('AA', 'forall', :forall, :symbol) b.add('EE', 'exists', :exists, :symbol) b.add('_|_', 'bot', :bot, :symbol) b.add('TT', 'top', :top, :symbol) b.add('|--', 'vdash', :vdash, :symbol) b.add('|==', 'models', :models, :symbol) # Grouping brackets b.add('(', 'left(', :lparen, :lparen) b.add(')', 'right)', :rparen, :rparen) b.add('[', 'left[', :lbracket, :lparen) b.add(']', 'right]', :rbracket, :rparen) b.add('{', :lbrace, :lparen) b.add('}', :rbrace, :rparen) b.add('|', :vbar, :lrparen) b.add(':|:', :vbar, :symbol) b.add('|:', :vbar, :lparen) b.add(':|', :vbar, :rparen) # b.add('||', '||', :lrparen) b.add('(:', '<<', 'langle', :langle, :lparen) b.add(':)', '>>', 'rangle', :rangle, :rparen) b.add('{:', nil, :lparen) b.add(':}', nil, :rparen) # Miscellaneous symbols b.add('int', :integral, :symbol) b.add('dx', :dx, :symbol) b.add('dy', :dy, :symbol) b.add('dz', :dz, :symbol) b.add('dt', :dt, :symbol) b.add('oint', :contourintegral, :symbol) b.add('del', 'partial', :partial, :symbol) b.add('grad', 'nabla', :nabla, :symbol) b.add('+-', 'pm', :pm, :symbol) b.add('O/', 'emptyset', :emptyset, :symbol) b.add('oo', 'infty', :infty, :symbol) b.add('aleph', :aleph, :symbol) b.add('...', 'ldots', :ellipsis, :symbol) b.add(':.', 'therefore', :therefore, :symbol) b.add(':\'', 'because', :because, :symbol) b.add('/_', 'angle', :angle, :symbol) b.add('/_\\', 'triangle', :triangle, :symbol) b.add('\'', 'prime', :prime, :symbol) b.add('tilde', :tilde, :unary) b.add('\\ ', :nbsp, :symbol) b.add('frown', :frown, :symbol) b.add('quad', :quad, :symbol) b.add('qquad', :qquad, :symbol) b.add('cdots', :cdots, :symbol) b.add('vdots', :vdots, :symbol) b.add('ddots', :ddots, :symbol) b.add('diamond', :diamond, :symbol) b.add('square', :square, :symbol) b.add('|__', 'lfloor', :lfloor, :symbol) b.add('__|', 'rfloor', :rfloor, :symbol) b.add('|~', 'lceiling', :lceiling, :symbol) b.add('~|', 'rceiling', :rceiling, :symbol) b.add('CC', :dstruck_captial_c, :symbol) b.add('NN', :dstruck_captial_n, :symbol) b.add('QQ', :dstruck_captial_q, :symbol) b.add('RR', :dstruck_captial_r, :symbol) b.add('ZZ', :dstruck_captial_z, :symbol) b.add('f', :f, :symbol) b.add('g', :g, :symbol) # Standard functions b.add('lim', :lim, :symbol) b.add('Lim', :Lim, :symbol) b.add('min', :min, :symbol) b.add('max', :max, :symbol) b.add('sin', :sin, :symbol) b.add('Sin', :Sin, :symbol) b.add('cos', :cos, :symbol) b.add('Cos', :Cos, :symbol) b.add('tan', :tan, :symbol) b.add('Tan', :Tan, :symbol) b.add('sinh', :sinh, :symbol) b.add('Sinh', :Sinh, :symbol) b.add('cosh', :cosh, :symbol) b.add('Cosh', :Cosh, :symbol) b.add('tanh', :tanh, :symbol) b.add('Tanh', :Tanh, :symbol) b.add('cot', :cot, :symbol) b.add('Cot', :Cot, :symbol) b.add('sec', :sec, :symbol) b.add('Sec', :Sec, :symbol) b.add('csc', :csc, :symbol) b.add('Csc', :Csc, :symbol) b.add('arcsin', :arcsin, :symbol) b.add('arccos', :arccos, :symbol) b.add('arctan', :arctan, :symbol) b.add('coth', :coth, :symbol) b.add('sech', :sech, :symbol) b.add('csch', :csch, :symbol) b.add('exp', :exp, :symbol) b.add('abs', :abs, :unary) b.add('Abs', :abs, :unary) b.add('norm', :norm, :unary) b.add('floor', :floor, :unary) b.add('ceil', :ceil, :unary) b.add('log', :log, :symbol) b.add('Log', :Log, :symbol) b.add('ln', :ln, :symbol) b.add('Ln', :Ln, :symbol) b.add('det', :det, :symbol) b.add('dim', :dim, :symbol) b.add('ker', :ker, :symbol) b.add('mod', :mod, :symbol) b.add('gcd', :gcd, :symbol) b.add('lcm', :lcm, :symbol) b.add('lub', :lub, :symbol) b.add('glb', :glb, :symbol) # Arrows b.add('uarr', 'uparrow', :uparrow, :symbol) b.add('darr', 'downarrow', :downarrow, :symbol) b.add('rarr', 'rightarrow', :rightarrow, :symbol) b.add('->', 'to', :to, :symbol) b.add('>->', 'rightarrowtail', :rightarrowtail, :symbol) b.add('->>', 'twoheadrightarrow', :twoheadrightarrow, :symbol) b.add('>->>', 'twoheadrightarrowtail', :twoheadrightarrowtail, :symbol) b.add('|->', 'mapsto', :mapsto, :symbol) b.add('larr', 'leftarrow', :leftarrow, :symbol) b.add('harr', 'leftrightarrow', :leftrightarrow, :symbol) b.add('rArr', 'Rightarrow', :Rightarrow, :symbol) b.add('lArr', 'Leftarrow', :Leftarrow, :symbol) b.add('hArr', 'Leftrightarrow', :Leftrightarrow, :symbol) # Other b.add('sqrt', :sqrt, :unary) b.add('root', :root, :binary) b.add('frac', :frac, :binary) b.add('/', :frac, :infix) b.add('stackrel', :stackrel, :binary) b.add('overset', :overset, :binary) b.add('underset', :underset, :binary) b.add('color', :color, :binary, :convert_operand1 => ::AsciiMath::Parser.instance_method(:convert_to_color)) b.add('_', :sub, :infix) b.add('^', :sup, :infix) b.add('hat', :hat, :unary) b.add('bar', :overline, :unary) b.add('vec', :vec, :unary) b.add('dot', :dot, :unary) b.add('ddot', :ddot, :unary) b.add('overarc', 'overparen', :overarc, :unary) b.add('ul', 'underline', :underline, :unary) b.add('ubrace', 'underbrace', :underbrace, :unary) b.add('obrace', 'overbrace', :overbrace, :unary) b.add('cancel', :cancel, :unary) b.add('bb', :bold, :unary) b.add('bbb', :double_struck, :unary) b.add('ii', :italic, :unary) b.add('bii', :bold_italic, :unary) b.add('cc', :script, :unary) b.add('bcc', :bold_script, :unary) b.add('tt', :monospace, :unary) b.add('fr', :fraktur, :unary) b.add('bfr', :bold_fraktur, :unary) b.add('sf', :sans_serif, :unary) b.add('bsf', :bold_sans_serif, :unary) b.add('sfi', :sans_serif_italic, :unary) b.add('sfbi', :sans_serif_bold_italic, :unary) b.add('rm', :roman, :unary) # Greek letters b.add('alpha', :alpha, :symbol) b.add('Alpha', :Alpha, :symbol) b.add('beta', :beta, :symbol) b.add('Beta', :Beta, :symbol) b.add('gamma', :gamma, :symbol) b.add('Gamma', :Gamma, :symbol) b.add('delta', :delta, :symbol) b.add('Delta', :Delta, :symbol) b.add('epsi', 'epsilon', :epsilon, :symbol) b.add('Epsilon', :Epsilon, :symbol) b.add('varepsilon', :varepsilon, :symbol) b.add('zeta', :zeta, :symbol) b.add('Zeta', :Zeta, :symbol) b.add('eta', :eta, :symbol) b.add('Eta', :Eta, :symbol) b.add('theta', :theta, :symbol) b.add('Theta', :Theta, :symbol) b.add('vartheta', :vartheta, :symbol) b.add('iota', :iota, :symbol) b.add('Iota', :Iota, :symbol) b.add('kappa', :kappa, :symbol) b.add('Kappa', :Kappa, :symbol) b.add('lambda', :lambda, :symbol) b.add('Lambda', :Lambda, :symbol) b.add('mu', :mu, :symbol) b.add('Mu', :Mu, :symbol) b.add('nu', :nu, :symbol) b.add('Nu', :Nu, :symbol) b.add('xi', :xi, :symbol) b.add('Xi', :Xi, :symbol) b.add('omicron', :omicron, :symbol) b.add('Omicron', :Omicron, :symbol) b.add('pi', :pi, :symbol) b.add('Pi', :Pi, :symbol) b.add('rho', :rho, :symbol) b.add('Rho', :Rho, :symbol) b.add('sigma', :sigma, :symbol) b.add('Sigma', :Sigma, :symbol) b.add('tau', :tau, :symbol) b.add('Tau', :Tau, :symbol) b.add('upsilon', :upsilon, :symbol) b.add('Upsilon', :Upsilon, :symbol) b.add('phi', :phi, :symbol) b.add('Phi', :Phi, :symbol) b.add('varphi', :varphi, :symbol) b.add('chi', :chi, :symbol) b.add('Chi', :Chi, :symbol) b.add('psi', :psi, :symbol) b.add('Psi', :Psi, :symbol) b.add('omega', :omega, :symbol) b.add('Omega', :Omega, :symbol) b end
new(symbol_table, color_table)
click to toggle source
# File lib/asciimath/parser.rb, line 502 def initialize(symbol_table, color_table) @symbol_table = symbol_table @color_table = color_table end
Public Instance Methods
parse(input)
click to toggle source
# File lib/asciimath/parser.rb, line 507 def parse(input) Expression.new( input, parse_expression(Tokenizer.new(input, @symbol_table), 0) ) end
Private Instance Methods
append_color_text(s, node)
click to toggle source
# File lib/asciimath/parser.rb, line 725 def append_color_text(s, node) case node when ::AsciiMath::AST::Sequence node.each { |n| append_color_text(s, n) } when ::AsciiMath::AST::Number, ::AsciiMath::AST::Identifier, ::AsciiMath::AST::Text s << node.value when ::AsciiMath::AST::Symbol s << node.text when ::AsciiMath::AST::Group append_color_text(s, node.expression) when ::AsciiMath::AST::Paren append_color_text(s, node.lparen) append_color_text(s, node.expression) append_color_text(s, node.rparen) when ::AsciiMath::AST::SubSup append_color_text(s, node.base_expression) append_color_text(s, node.operator) append_color_text(s, node.operand2) when ::AsciiMath::AST::UnaryOp append_color_text(s, node.operator) append_color_text(s, node.operand) when ::AsciiMath::AST::BinaryOp append_color_text(s, node.operator) append_color_text(s, node.operand1) append_color_text(s, node.operand2) when ::AsciiMath::AST::InfixOp append_color_text(s, node.operand1) append_color_text(s, node.operator) append_color_text(s, node.operand2) end end
convert_node(node, converter)
click to toggle source
# File lib/asciimath/parser.rb, line 698 def convert_node(node, converter) case converter when nil node when UnboundMethod converter.bind(self).call(node) when Method, Proc converter.call(node) end end
convert_to_color(color_expression)
click to toggle source
# File lib/asciimath/parser.rb, line 709 def convert_to_color(color_expression) s = "" append_color_text(s, color_expression) case s when /#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/i color_value = {:r => $1.to_i(16), :g => $2.to_i(16), :b => $3.to_i(16), } when /#([0-9a-f])([0-9a-f])([0-9a-f])/i color_value = {:r => "#{$1}#{$1}".to_i(16), :g => "#{$2}#{$2}".to_i(16), :b => "#{$3}#{$3}".to_i(16), } else color_value = @color_table[s.downcase] || {:r => 0, :g => 0, :b => 0} end color(color_value[:r], color_value[:g], color_value[:b], s) end
convert_to_matrix(node)
click to toggle source
# File lib/asciimath/parser.rb, line 656 def convert_to_matrix(node) return node unless node.is_a?(::AsciiMath::AST::Paren) && node.expression.is_a?(::AsciiMath::AST::Sequence) rows, separators = node.expression.partition.with_index { |obj, i| i.even? } return node unless rows.length > 1 && rows.length > separators.length && separators.all? { |item| is_matrix_separator(item) } && (rows.all? { |item| item.is_a?(::AsciiMath::AST::Paren) && item.lparen == symbol(:lparen, '(') && item.rparen == symbol(:rparen, ')') } || rows.all? { |item| item.is_a?(::AsciiMath::AST::Paren) && item.lparen == symbol(:lbracket, '[') && item.rparen == symbol(:rbracket, ']') }) rows = rows.map do |row| chunks = [] current_chunk = [] row_content = row.expression unless row_content.is_a?(::AsciiMath::AST::Sequence) [expression(row_content)] else row_content.each do |item| if is_matrix_separator(item) chunks << current_chunk current_chunk = [] else current_chunk << item end end chunks << current_chunk chunks.map { |c| c.length == 1 ? c[0] : expression(*c) }.to_a end end return node unless rows.all? { |row| row.length == rows[0].length } matrix(node.lparen, rows, node.rparen) end
is_matrix_separator(node)
click to toggle source
# File lib/asciimath/parser.rb, line 694 def is_matrix_separator(node) node.is_a?(Identifier) && node.value == ',' end
parse_expression(tok, depth)
click to toggle source
# File lib/asciimath/parser.rb, line 518 def parse_expression(tok, depth) e = [] while (s1 = parse_intermediate_expression(tok, depth)) t1 = tok.next_token if t1[:type] == :infix && t1[:value] == :frac s2 = parse_intermediate_expression(tok, depth) if s2 e << infix(unwrap_paren(s1), symbol(:frac, t1[:text]), unwrap_paren(s2)) else e << s1 end elsif t1[:type] == :eof e << s1 break else e << s1 tok.push_back(t1) if (t1[:type] == :lrparen || t1[:type] == :rparen) && depth > 0 break end end end expression(*e) end
parse_intermediate_expression(tok, depth)
click to toggle source
# File lib/asciimath/parser.rb, line 546 def parse_intermediate_expression(tok, depth) s = parse_simple_expression(tok, depth) sub = nil sup = nil t1 = tok.next_token case t1[:type] when :infix case t1[:value] when :sub sub = parse_simple_expression(tok, depth) if sub t2 = tok.next_token if t2[:type] == :infix && t2[:value] == :sup sup = parse_simple_expression(tok, depth) else tok.push_back(t2) end end when :sup sup = parse_simple_expression(tok, depth) else tok.push_back(t1) end else tok.push_back(t1) end if sub && sup subsup(s, unwrap_paren(sub), unwrap_paren(sup)) elsif sub sub(s, unwrap_paren(sub)) elsif sup sup(s, unwrap_paren(sup)) else s end end
parse_simple_expression(tok, depth)
click to toggle source
# File lib/asciimath/parser.rb, line 585 def parse_simple_expression(tok, depth) t1 = tok.next_token case t1[:type] when :lparen, :lrparen t2 = tok.next_token case t2[:type] when :rparen, :lrparen paren(token_to_symbol(t1), nil, token_to_symbol(t2)) else tok.push_back(t2) e = parse_expression(tok, depth + 1) t2 = tok.next_token case t2[:type] when :rparen, :lrparen convert_to_matrix(paren(token_to_symbol(t1), e, token_to_symbol(t2))) else tok.push_back(t2) paren(token_to_symbol(t1), e, nil) end end when :rparen if depth > 0 tok.push_back(t1) nil else token_to_symbol(t1) end when :unary parse_simple_expression = parse_simple_expression(tok, depth) s = unwrap_paren(parse_simple_expression) s = identifier('') if s.nil? s = convert_node(s, t1[:convert_operand]) unary(token_to_symbol(t1), s) when :binary s1 = unwrap_paren(parse_simple_expression(tok, depth)) s1 = identifier('') if s1.nil? s2 = unwrap_paren(parse_simple_expression(tok, depth)) s2 = identifier('') if s2.nil? s1 = convert_node(s1, t1[:convert_operand1]) s2 = convert_node(s2, t1[:convert_operand2]) binary(token_to_symbol(t1), s1, s2) when :eof nil when :number number(t1[:value]) when :text text(t1[:value]) when :identifier identifier(t1[:value]) else token_to_symbol(t1) end end
token_to_symbol(t1)
click to toggle source
# File lib/asciimath/parser.rb, line 644 def token_to_symbol(t1) symbol(t1[:value], t1[:text]) end
unwrap_paren(node)
click to toggle source
# File lib/asciimath/parser.rb, line 648 def unwrap_paren(node) if node.is_a?(::AsciiMath::AST::Paren) group(node.lparen, node.expression, node.rparen) else node end end