Class MathML::LaTeX::Parser
In: lib/math_ml/latex.rb
Parent: Object

Methods

Included Modules

LaTeX BuiltinEnvironments BuiltinGroups BuiltinCommands

Classes and Modules

Class MathML::LaTeX::Parser::CircularReferenceCommand

Constants

BUILTIN_MACRO = <<'EOS' \newenvironment{smallmatrix}{\begin{matrix}}{\end{matrix}} \newenvironment{pmatrix}{\left(\begin{matrix}}{\end{matrix}\right)} \newenvironment{bmatrix}{\left[\begin{matrix}}{\end{matrix}\right]} \newenvironment{Bmatrix}{\left\{\begin{matrix}}{\end{matrix}\right\}} \newenvironment{vmatrix}{\left|\begin{matrix}}{\end{matrix}\right|} \newenvironment{Vmatrix}{\left\|\begin{matrix}}{\end{matrix}\right\|} EOS

Attributes

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

Public Class methods

[Source]

     # File lib/math_ml/latex.rb, line 366
366:                         def initialize(opt={})
367:                                 @unsecure_entity = false
368:                                 @entities = Hash.new
369:                                 @commands = Hash.new
370:                                 @symbols = Hash.new
371:                                 @delimiters = Array.new
372:                                 @group_begins = Hash.new
373:                                 @group_ends = Hash.new
374:                                 @macro = Macro.new
375:                                 @macro.parse(BUILTIN_MACRO)
376:                                 @expanded_command = Array.new
377:                                 @expanded_environment = Array.new
378:                                 @symbol_table = opt[:symbol] || MathML::Symbol::Default
379:                                 @symbol_table = MathML::Symbol::MAP[@symbol_table] if @symbol_table.is_a?(::Symbol)
380: 
381:                                 super()
382:                         end

Public Instance methods

[Source]

     # File lib/math_ml/latex.rb, line 415
415:                         def add_commands(*a)
416:                                 if a.size==1 && Hash===a[0]
417:                                         @commands.merge!(a[0])
418:                                 else
419:                                         a.each{|i| @commands[i] = false}
420:                                 end
421:                         end

[Source]

     # File lib/math_ml/latex.rb, line 431
431:                         def add_delimiter(list)
432:                                 @delimiters.concat(list)
433:                         end

[Source]

     # File lib/math_ml/latex.rb, line 384
384:                         def add_entity(list)
385:                                 list.each do |i|
386:                                         @entities[i] = true
387:                                 end
388:                         end

[Source]

     # File lib/math_ml/latex.rb, line 435
435:                         def add_group(begin_name, end_name, method=nil)
436:                                 @group_begins[begin_name] = method
437:                                 @group_ends[end_name] = begin_name
438:                         end

[Source]

     # File lib/math_ml/latex.rb, line 423
423:                         def add_multi_command(m, *a)
424:                                 a.each{|i| @commands[i] = m}
425:                         end

[Source]

     # File lib/math_ml/latex.rb, line 411
411:                         def add_plugin(plugin)
412:                                 self.extend(plugin)
413:                         end

[Source]

     # File lib/math_ml/latex.rb, line 427
427:                         def add_sym_cmd(hash)
428:                                 @symbols.merge!(hash)
429:                         end

[Source]

     # File lib/math_ml/latex.rb, line 390
390:                         def parse(src, displaystyle=false)
391:                                 @ds = displaystyle
392:                                 begin
393:                                         parse_into(src, Math.new(@ds), Font::NORMAL)
394:                                 rescue ParseError => e
395:                                         e.done = src[0...(src.size - e.rest.size)]
396:                                         raise
397:                                 end
398:                         end

[Source]

     # File lib/math_ml/latex.rb, line 400
400:                         def push_container(container, scanner=@scanner, font=@font)
401:                                 data = [@container, @scanner, @font]
402:                                 @container, @scanner, @font = [container, scanner, font]
403:                                 begin
404:                                         yield container
405:                                         container
406:                                 ensure
407:                                         @container, @scanner, @font = data
408:                                 end
409:                         end

Private Instance methods

[Source]

     # File lib/math_ml/latex.rb, line 591
591:                         def entitize(str)
592:                                 MathML.pcstring(str.sub(/^(.*)$/){"&#{$1};"}, true)
593:                         end

[Source]

     # File lib/math_ml/latex.rb, line 467
467:                         def parse_any(message = "Syntax error.")
468:                                 raise ParseError.new(message) unless @scanner.scan_any
469:                                 s = @scanner
470:                                 @scanner = Scanner.new(@scanner.matched)
471:                                 begin
472:                                         parse_to_element
473:                                 ensure
474:                                         @scanner = s
475:                                 end
476:                         end

[Source]

     # File lib/math_ml/latex.rb, line 537
537:                         def parse_block
538:                                 os = @scanner
539:                                 @scanner =  Scanner.new(@scanner[1])
540:                                 begin
541:                                         push_container(Row.new) do |r|
542:                                                 r << parse_to_element(true) until @scanner.eos?
543:                                         end
544:                                 rescue ParseError => e
545:                                         e.rest << '}'
546:                                         raise
547:                                 ensure
548:                                         @scanner = os
549:                                 end
550:                         end

[Source]

     # File lib/math_ml/latex.rb, line 512
512:                         def parse_char
513:                                 c = @scanner.matched
514:                                 i = Identifier.new
515:                                 case @font
516:                                 when Font::ROMAN
517:                                         i.extend(Variant).variant = Variant::NORMAL
518:                                 when Font::BOLD
519:                                         i.extend(Variant).variant = Variant::BOLD
520:                                 when Font::BOLD_ITALIC
521:                                         i.extend(Variant).variant = Variant::BOLD_ITALIC
522:                                 when Font::BLACKBOLD
523:                                         c = symbol_table.convert("#{c}opf")
524:                                 when Font::SCRIPT
525:                                         c = symbol_table.convert("#{c}scr")
526:                                 when Font::FRAKTUR
527:                                         c = symbol_table.convert("#{c}fr")
528:                                 end
529:                                 i << c
530:                         end

[Source]

     # File lib/math_ml/latex.rb, line 639
639:                         def parse_command
640:                                 com = @scanner[1]
641:                                 matched = @scanner.matched
642:                                 pos = @scanner.pos-matched.size
643:                                 macro = @macro.commands(com)
644:                                 if macro
645:                                         begin
646:                                                 flg = @expanded_command.include?(com)
647:                                                 @expanded_command.push(com)
648:                                                 raise CircularReferenceCommand if flg
649:                                                 option = (macro.option && @scanner.scan_option) ? @scanner[1] : nil
650:                                                 params = Array.new
651:                                                 (1..macro.num).each do
652:                                                         params << (@scanner.scan_block ? @scanner[1] : @scanner.scan_any)
653:                                                         raise ParseError.new("Need more parameter.") unless params.last
654:                                                 end
655:                                                 r = parse_into(@macro.expand_command(com, params, option), Array.new)
656:                                                 return r
657:                                         rescue CircularReferenceCommand
658:                                                 if @expanded_command.size>1
659:                                                         raise
660:                                                 else
661:                                                         @scanner.pos = pos
662:                                                         raise ParseError.new("Circular reference.")
663:                                                 end
664:                                         rescue ParseError => e
665:                                                 if @expanded_command.size>1
666:                                                         raise
667:                                                 else
668:                                                         @scanner.pos = pos
669:                                                         raise ParseError.new(%[Error in macro(#{e.message} "#{e.rest.strip}").])
670:                                                 end
671:                                         ensure
672:                                                 @expanded_command.pop
673:                                         end
674:                                 elsif @commands.key?(com)
675:                                         m = @commands[com]
676:                                         m = com unless m
677:                                         return __send__("cmd_#{m.to_s}")
678:                                 end
679:                                 parse_symbol_command(com)
680:                         end

[Source]

     # File lib/math_ml/latex.rb, line 692
692:                         def parse_group
693:                                 font = @font
694:                                 begin
695:                                         g = @group_begins[@scanner[1]]
696:                                         g = @scanner[1] unless g
697:                                         __send__("grp_#{g.to_s}")
698:                                 ensure
699:                                         @font = font
700:                                 end
701:                         end

[Source]

     # File lib/math_ml/latex.rb, line 441
441:                         def parse_into(src, parent, font=nil)
442:                                 orig = [@scanner, @container, @font, @ds]
443:                                 @scanner = Scanner.new(src)
444:                                 @container = parent
445:                                 @font = font if font
446:                                 begin
447:                                         until @scanner.eos?
448:                                                 @container << parse_to_element(true)
449:                                         end
450:                                         @container
451:                                 rescue BlockNotClosed => e
452:                                         raise  ParseError.new("Block not closed.", @scanner.rest)
453:                                 rescue NotEnvironment => e
454:                                         raise ParseError.new("Not environment.", @scanner.rest)
455:                                 rescue EnvironmentNotEnd => e
456:                                         raise ParseError.new("Environment not end.", @scanner.rest)
457:                                 rescue OptionNotClosed => e
458:                                         raise ParseError.new("Option not closed.", @scanner.rest)
459:                                 rescue ParseError => e
460:                                         e.rest << @scanner.rest.to_s
461:                                         raise
462:                                 ensure
463:                                         @scanner, @container, @font, @ds = orig
464:                                 end
465:                         end

[Source]

     # File lib/math_ml/latex.rb, line 682
682:                         def parse_mathfont(font)
683:                                 f = @font
684:                                 @font = font
685:                                 begin
686:                                         push_container(Row.new){|r| r << parse_any}
687:                                 ensure
688:                                         @font = f
689:                                 end
690:                         end

[Source]

     # File lib/math_ml/latex.rb, line 506
506:                         def parse_num
507:                                 n = Number.new
508:                                 n.extend(Variant).variant = Variant::BOLD if @font==Font::BOLD
509:                                 n << @scanner.matched
510:                         end

[Source]

     # File lib/math_ml/latex.rb, line 532
532:                         def parse_operator
533:                                 o = @scanner.matched
534:                                 Operator.new << o
535:                         end

[Source]

     # File lib/math_ml/latex.rb, line 552
552:                         def parse_sub
553:                                 e = @container.pop
554:                                 e = None.new unless e
555:                                 e = SubSup.new(@ds && e.display_style, e) unless e.is_a?(SubSup)
556:                                 raise ParseError.new("Double subscript.", "_") if e.sub
557:                                 e.sub = parse_any("Subscript not exist.")
558:                                 e
559:                         end

[Source]

     # File lib/math_ml/latex.rb, line 561
561:                         def parse_sup
562:                                 e = @container.pop
563:                                 e = None.new unless e
564:                                 e = SubSup.new(@ds && e.display_style, e) unless e.is_a?(SubSup)
565:                                 raise ParseError.new("Double superscript.", @scanner[0]) if e.sup
566:                                 if /'+/=~@scanner[0]
567:                                         prime = Operator.new
568:                                         @scanner[0].size.times do
569:                                                 prime << symbol_table.convert("prime")
570:                                         end
571:                                         unless @scanner.scan(/\^/)
572:                                                 e.sup = prime
573:                                                 return e
574:                                         end
575:                                 end
576:                                 sup = parse_any("Superscript not exist.")
577: 
578:                                 if prime
579:                                         unless sup.is_a?(Row)
580:                                                 r = Row.new
581:                                                 r << sup
582:                                                 sup = r
583:                                         end
584:                                         sup.contents.insert(0, prime)
585:                                 end
586: 
587:                                 e.sup = sup
588:                                 e
589:                         end

[Source]

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

[Source]

     # File lib/math_ml/latex.rb, line 478
478:                         def parse_to_element(whole_group = false)
479:                                 if whole_group && @group_begins.has_key?(@scanner.peek_command)
480:                                         @scanner.scan_command
481:                                         parse_group
482:                                 else
483:                                         case
484:                                         when @scanner.scan(RE::NUMERICS)
485:                                                 parse_num
486:                                         when @scanner.scan(RE::ALPHABETS)
487:                                                 parse_char
488:                                         when @scanner.scan(RE::OPERATORS)
489:                                                 parse_operator
490:                                         when @scanner.scan_block
491:                                                 parse_block
492:                                         when @scanner.scan(/_/)
493:                                                 parse_sub
494:                                         when @scanner.scan(/'+|\^/)
495:                                                 parse_sup
496:                                         when @scanner.scan(/~/)
497:                                                 Space.new("1em")
498:                                         when @scanner.scan_command
499:                                                 parse_command
500:                                         else
501:                                                 raise ParseError.new('Syntax error.')
502:                                         end
503:                                 end
504:                         end

[Validate]