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