# class MathML::LaTeX::Parser

### Constants

BUILTIN_MACRO

### Attributes

macro[R]
symbol_table[R]
unsecure_entity[RW]

### Public Class Methods

new(opt = {}) click to toggle source
Calls superclass method `MathML::LaTeX::BuiltinCommands::new`

        # File lib/math_ml/latex.rb
    375 def initialize(opt = {})
    376   @unsecure_entity = false
    377   @entities = {}
    378   @commands = {}
    379   @symbols = {}
    380   @delimiters = []
    381   @group_begins = {}
    382   @group_ends = {}
    383   @macro = Macro.new
    384   @macro.parse(BUILTIN_MACRO)
    385   @expanded_command = []
    386   @expanded_environment = []
    387   @symbol_table = opt[:symbol] || MathML::Symbol::Default
    388   @symbol_table = MathML::Symbol::MAP[@symbol_table] if @symbol_table.is_a?(::Symbol)
    389
    390   super()
    391 end

### Public Instance Methods

add_commands(*a) click to toggle source

        # File lib/math_ml/latex.rb
    426 def add_commands(*a)
    427   if a.size == 1 && a[0].is_a?(Hash)
    428     @commands.merge!(a[0])
    429   else
    430     a.each { |i| @commands[i] = false }
    431   end
    432 end

add_delimiter(list) click to toggle source

        # File lib/math_ml/latex.rb
    442 def add_delimiter(list)
    443   @delimiters.concat(list)
    444 end

add_entity(list) click to toggle source

        # File lib/math_ml/latex.rb
    393 def add_entity(list)
    394   list.each do |i|
    395     @entities[i] = true
    396   end
    397 end

add_group(begin_name, end_name, method = nil) click to toggle source

        # File lib/math_ml/latex.rb
    446 def add_group(begin_name, end_name, method = nil)
    447   @group_begins[begin_name] = method
    448   @group_ends[end_name] = begin_name
    449 end

add_multi_command(m, *a) click to toggle source

        # File lib/math_ml/latex.rb
    434 def add_multi_command(m, *a)
    435   a.each { |i| @commands[i] = m }
    436 end

add_plugin(plugin) click to toggle source

        # File lib/math_ml/latex.rb
    422 def add_plugin(plugin)
    423   extend(plugin)
    424 end

add_sym_cmd(hash) click to toggle source

        # File lib/math_ml/latex.rb
    438 def add_sym_cmd(hash)
    439   @symbols.merge!(hash)
    440 end

parse(src, displaystyle = false) click to toggle source

        # File lib/math_ml/latex.rb
    399 def parse(src, displaystyle = false)
    400   @ds = displaystyle
    401   begin
    402     parse_into(src, Math.new(@ds), Font::NORMAL)
    403   rescue ParseError => e
    404     e.done = src[0...(src.size - e.rest.size)]
    405     raise
    406   end
    407 end

push_container(container, scanner = @scanner, font = @font) { |container| ... } click to toggle source

        # File lib/math_ml/latex.rb
    409 def push_container(container, scanner = @scanner, font = @font)
    410   data = [@container, @scanner, @font]
    411   @container = container
    412   @scanner = scanner
    413   @font = font
    414   begin
    415     yield container
    416     container
    417   ensure
    418     @container, @scanner, @font = data
    419   end
    420 end

### Private Instance Methods

entitize(str) click to toggle source

        # File lib/math_ml/latex.rb
    601 def entitize(str)
    602   MathML.pcstring(str.sub(/^(.*)$/) { "&#{$1};" }, true)
    603 end

parse_any(message = 'Syntax error.') click to toggle source

        # File lib/math_ml/latex.rb
    477 def parse_any(message = 'Syntax error.')
    478   raise ParseError, message unless @scanner.scan_any
    479
    480   s = @scanner
    481   @scanner = Scanner.new(@scanner.matched)
    482   begin
    483     parse_to_element
    484   ensure
    485     @scanner = s
    486   end
    487 end

parse_block() click to toggle source

        # File lib/math_ml/latex.rb
    545 def parse_block
    546   os = @scanner
    547   @scanner = Scanner.new(@scanner[1])
    548   begin
    549     push_container(Row.new) do |r|
    550       r << parse_to_element(true) until @scanner.eos?
    551     end
    552   rescue ParseError => e
    553     e.rest << '}'
    554     raise
    555   ensure
    556     @scanner = os
    557   end
    558 end

parse_char() click to toggle source

        # File lib/math_ml/latex.rb
    520 def parse_char
    521   c = @scanner.matched
    522   i = Identifier.new
    523   case @font
    524   when Font::ROMAN
    525     i.extend(Variant).variant = Variant::NORMAL
    526   when Font::BOLD
    527     i.extend(Variant).variant = Variant::BOLD
    528   when Font::BOLD_ITALIC
    529     i.extend(Variant).variant = Variant::BOLD_ITALIC
    530   when Font::BLACKBOLD
    531     c = symbol_table.convert("#{c}opf")
    532   when Font::SCRIPT
    533     c = symbol_table.convert("#{c}scr")
    534   when Font::FRAKTUR
    535     c = symbol_table.convert("#{c}fr")
    536   end
    537   i << c
    538 end

parse_command() click to toggle source

        # File lib/math_ml/latex.rb
    651 def parse_command
    652   com = @scanner[1]
    653   matched = @scanner.matched
    654   pos = @scanner.pos - matched.size
    655   macro = @macro.commands(com)
    656   if macro
    657     begin
    658       flg = @expanded_command.include?(com)
    659       @expanded_command.push(com)
    660       raise CircularReferenceCommand if flg
    661
    662       option = macro.option && @scanner.scan_option ? @scanner[1] : nil
    663       params = []
    664       (1..macro.num).each do
    665         params << (@scanner.scan_block ? @scanner[1] : @scanner.scan_any)
    666         raise ParseError, 'Need more parameter.' unless params.last
    667       end
    668       r = parse_into(@macro.expand_command(com, params, option), [])
    669       return r
    670     rescue CircularReferenceCommand
    671       if @expanded_command.size > 1
    672         raise
    673       else
    674         @scanner.pos = pos
    675         raise ParseError, 'Circular reference.'
    676       end
    677     rescue ParseError => e
    678       if @expanded_command.size > 1
    679         raise
    680       else
    681         @scanner.pos = pos
    682         raise ParseError, %[Error in macro(#{e.message} "#{e.rest.strip}").]
    683       end
    684     ensure
    685       @expanded_command.pop
    686     end
    687   elsif @commands.key?(com)
    688     m = @commands[com]
    689     m ||= com
    690     return __send__("cmd_#{m}")
    691   end
    692   parse_symbol_command(com)
    693 end

parse_group() click to toggle source

        # File lib/math_ml/latex.rb
    705 def parse_group
    706   font = @font
    707   begin
    708     g = @group_begins[@scanner[1]]
    709     g ||= @scanner[1]
    710     __send__("grp_#{g}")
    711   ensure
    712     @font = font
    713   end
    714 end

parse_into(src, parent, font = nil) click to toggle source

        # File lib/math_ml/latex.rb
    453 def parse_into(src, parent, font = nil)
    454   orig = [@scanner, @container, @font, @ds]
    455   @scanner = Scanner.new(src)
    456   @container = parent
    457   @font = font if font
    458   begin
    459     @container << parse_to_element(true) until @scanner.eos?
    460     @container
    461   rescue BlockNotClosed => e
    462     raise ParseError.new('Block not closed.', @scanner.rest)
    463   rescue NotEnvironment => e
    464     raise ParseError.new('Not environment.', @scanner.rest)
    465   rescue EnvironmentNotEnd => e
    466     raise ParseError.new('Environment not end.', @scanner.rest)
    467   rescue OptionNotClosed => e
    468     raise ParseError.new('Option not closed.', @scanner.rest)
    469   rescue ParseError => e
    470     e.rest += @scanner.rest.to_s
    471     raise
    472   ensure
    473     @scanner, @container, @font, @ds = orig
    474   end
    475 end

parse_mathfont(font) click to toggle source

        # File lib/math_ml/latex.rb
    695 def parse_mathfont(font)
    696   f = @font
    697   @font = font
    698   begin
    699     push_container(Row.new) { |r| r << parse_any }
    700   ensure
    701     @font = f
    702   end
    703 end

parse_num() click to toggle source

        # File lib/math_ml/latex.rb
    514 def parse_num
    515   n = Number.new
    516   n.extend(Variant).variant = Variant::BOLD if @font == Font::BOLD
    517   n << @scanner.matched
    518 end

parse_operator() click to toggle source

        # File lib/math_ml/latex.rb
    540 def parse_operator
    541   o = @scanner.matched
    542   Operator.new.tap { |op| op[:stretchy] = 'false' } << o
    543 end

parse_sub() click to toggle source

        # File lib/math_ml/latex.rb
    560 def parse_sub
    561   e = @container.pop
    562   e ||= None.new
    563   e = SubSup.new(@ds && e.display_style, e) unless e.is_a?(SubSup)
    564   raise ParseError.new('Double subscript.', '_') if e.sub
    565
    566   e.sub = parse_any('Subscript not exist.')
    567   e
    568 end

parse_sup() click to toggle source

        # File lib/math_ml/latex.rb
    570 def parse_sup
    571   e = @container.pop
    572   e ||= None.new
    573   e = SubSup.new(@ds && e.display_style, e) unless e.is_a?(SubSup)
    574   raise ParseError.new('Double superscript.', @scanner[0]) if e.sup
    575
    576   if /'+/=~@scanner[0]
    577     prime = Operator.new
    578     @scanner[0].size.times do
    579       prime << symbol_table.convert('prime')
    580     end
    581     unless @scanner.scan(/\^/)
    582       e.sup = prime
    583       return e
    584     end
    585   end
    586   sup = parse_any('Superscript not exist.')
    587
    588   if prime
    589     unless sup.is_a?(Row)
    590       r = Row.new
    591       r << sup
    592       sup = r
    593     end
    594     sup.contents.insert(0, prime)
    595   end
    596
    597   e.sup = sup
    598   e
    599 end

parse_symbol_command(com, plain = false) click to toggle source

        # File lib/math_ml/latex.rb
    605 def parse_symbol_command(com, plain = false)
    606   unless @symbols.include?(com)
    607     @scanner.pos = @scanner.pos - (com.size + 1)
    608     raise ParseError, 'Undefined command.'
    609   end
    610   data = @symbols[com]
    611   return nil unless data
    612
    613   data, s = data
    614   su = data[0]
    615   el = data[1]
    616   el ||= :o
    617   s ||= com.dup.to_sym
    618   s = com if s.is_a?(String) && s.length == 0
    619
    620   case el
    621   when :I
    622     el = Identifier.new
    623   when :i
    624     el = Identifier.new
    625     el.extend(Variant).variant = Variant::NORMAL unless s.is_a?(String) && s.length > 1
    626   when :o
    627     el = Operator.new
    628     el[:stretchy] = 'false'
    629   when :n
    630     el = Number.new
    631   else
    632     raise ParseError, 'Inner data broken.'
    633   end
    634
    635   case s
    636   when Integer
    637     s = MathML.pcstring("&\#x#{s.to_s(16)};", true)
    638   when ::Symbol
    639     s = symbol_table.convert(s)
    640   else
    641     MathML.pcstring(s, true)
    642   end
    643
    644   return s if plain
    645
    646   el << s
    647   el.as_display_style if su == :u
    648   el
    649 end

parse_to_element(whole_group = false) click to toggle source

        # File lib/math_ml/latex.rb
    489 def parse_to_element(whole_group = false)
    490   if whole_group && @group_begins.has_key?(@scanner.peek_command)
    491     @scanner.scan_command
    492     parse_group
    493   elsif @scanner.scan(RE::NUMERICS)
    494     parse_num
    495   elsif @scanner.scan(RE::ALPHABETS)
    496     parse_char
    497   elsif @scanner.scan(RE::OPERATORS)
    498     parse_operator
    499   elsif @scanner.scan_block
    500     parse_block
    501   elsif @scanner.scan(/_/)
    502     parse_sub
    503   elsif @scanner.scan(/'+|\^/)
    504     parse_sup
    505   elsif @scanner.scan(/~/)
    506     Space.new('1em')
    507   elsif @scanner.scan_command
    508     parse_command
    509   else
    510     raise ParseError, 'Syntax error.'
    511   end
    512 end