Class: RDocF95::Fortran95parser

Inherits:
Object
  • Object
show all
Extended by:
ParserFactory
Defined in:
lib/rdoc-f95/parsers/parse_f95.rb

Overview

See rdoc/parsers/parse_f95.rb

Defined Under Namespace

Classes: Fortran95Definition

Constant Summary collapse

COMMENTS_ARE_UPPER =
“false”

Comments are below source code

“true”

Comments are upper source code

false
INTERNAL_ALIAS_MES =

Internal alias message

"Alias for"
EXTERNAL_ALIAS_MES =

External alias message

"Original external subprogram is"
PROVIDED_MODULES_MES =

Provided modules message

"This file provides the following module"
NAMELIST_REPOSITORY_NAME =

Repository of NAMELIST statements

"NAMELIST"
IGNORED_MARKER_REGEXP =

Ignored marker

/^:nodoc:/
DOC_PRIORITY_REGEXP =

Document priority marker

/^:doc\-priority\s+([\-\+]?\d+):\s*/
@@external_aliases =
[]
@@public_methods =
[]

Instance Method Summary collapse

Methods included from ParserFactory

alias_extension, can_parse, parse_files_matching, parser_for

Constructor Details

#initialize(top_level, file_name, body, options, stats) ⇒ Fortran95parser

prepare to parse a Fortran 95 file


633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
# File 'lib/rdoc-f95/parsers/parse_f95.rb', line 633

def initialize(top_level, file_name, body, options, stats)
  @body = body
  @stats = stats
  @file_name  = file_name
  @options = options
  @top_level = top_level
  @progress = $stderr unless options.quiet

  begin
    @options_ignore_case = options.ignore_case
  rescue
    @options_ignore_case = true
  end

end

Instance Method Details

#scanObject

devine code constructs


650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
# File 'lib/rdoc-f95/parsers/parse_f95.rb', line 650

def scan

  # remove private comment
  remaining_code = remove_private_comments(@body)

  # continuation lines are united to one line
  remaining_code = united_to_one_line(remaining_code)

  # semicolons are replaced to line feed
  remaining_code = semicolon_to_linefeed(remaining_code)

  # collect comment for file entity
  whole_comment, remaining_code = collect_first_comment(remaining_code)
  @top_level.comment = whole_comment

  # String "remaining_code" is converted to Array "remaining_lines"
  remaining_lines = remaining_code.split("\n")

  # "module" or "program" parts are parsed (new)
  #
  level_depth = 0
  block_searching_flag = nil
  block_searching_lines = []
  pre_comment = []
  module_program_trailing = ""
  module_program_name = ""
  other_block_level_depth = 0
  other_block_searching_flag = nil
  remaining_lines.collect!{|line|
    if !block_searching_flag && !other_block_searching_flag
      if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i
        block_searching_flag = :module
        block_searching_lines << line
        module_program_name = $1
        module_program_trailing = find_comments($2)
        next false
      elsif line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i ||
             line =~ /^\s*?\w/ && !block_start?(line)
        block_searching_flag = :program
        block_searching_lines << line
        module_program_name = $1 || ""
        module_program_trailing = find_comments($2)
        next false

      elsif block_start?(line)
        other_block_searching_flag = true
        next line

      elsif line =~ /^\s*?!\s?(.*)/
        pre_comment << line
        next line
      else
        pre_comment = []
        next line
      end
    elsif other_block_searching_flag
      other_block_level_depth += 1 if block_start?(line)
      other_block_level_depth -= 1 if block_end?(line)
      if other_block_level_depth < 0
        other_block_level_depth = 0
        other_block_searching_flag = nil
      end
      next line
    end

    block_searching_lines << line
    level_depth += 1 if block_start?(line)
    level_depth -= 1 if block_end?(line)
    if level_depth >= 0
      next false
    end

    # "module_program_code" is formatted.
    # ":nodoc:" flag is checked.
    #
    module_program_code = block_searching_lines.join("\n")
    module_program_code = remove_empty_head_lines(module_program_code)
    if module_program_trailing =~ IGNORED_MARKER_REGEXP
      # next loop to search next block
      level_depth = 0
      block_searching_flag = false
      block_searching_lines = []
      pre_comment = []
      next false
    end

    # NormalClass is created, and added to @top_level
    #
    if block_searching_flag == :module
      module_name = module_program_name
      module_code = module_program_code
      module_trailing = module_program_trailing
      progress "m"
      @stats.num_modules += 1
      f9x_module = @top_level.add_module NormalClass, module_name
      f9x_module.record_location @top_level

      #
      # Add provided modules information to @top_level comment
      #
      provided_modules = []
      provided_mes_line_num = nil
      top_level_comment_lines = []
      line_num = 0
      @top_level.comment.split("\n").each{|line|
        top_level_comment_lines << line
        line_num += 1
        next if line.empty?
        if !provided_mes_line_num && /^\s?#{PROVIDED_MODULES_MES}/ =~ line
          provided_mes_line_num = line_num
          next
        end
        if provided_mes_line_num
          if /^\s?\*\s+<b>(\w+)<\/b>/ =~ line
            provided_modules << $1
          else
            provided_mes_line_num = nil
          end
        end
      }
      line_num = 0
      if provided_mes_line_num
        top_level_comment_lines.collect!{ |line|
          line_num += 1
          if line_num < provided_mes_line_num
            line
          else
            nil
          end
        }
        top_level_comment_lines.delete_if{|line| !line }
      end
      top_level_comment_lines << "\n" + PROVIDED_MODULES_MES + "."
      if provided_mes_line_num
        top_level_comment_lines[-1].sub!(/\.$/, '')
        top_level_comment_lines[-1] << "s."
      end
      provided_modules.each{ |mod|
        top_level_comment_lines << "* <b>" + mod + "</b>"
      }
      top_level_comment_lines << "* <b>" + module_name + "</b>"
      @top_level.comment = top_level_comment_lines.join("\n")

      #
      # Information about the module is parsed
      #
      f9x_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) +
        "\n" + module_trailing : module_trailing + "\n" +
        find_comments(module_code.sub(/^.*$\n/i, ''))
      f9x_module.comment = f9x_comment
      parse_program_or_module(f9x_module, module_code)

      TopLevel.all_files.each do |name, toplevel|
        if toplevel.include_includes?(module_name, @options_ignore_case)
          if !toplevel.include_requires?(@file_name, @options_ignore_case)
            toplevel.add_require(Require.new(@file_name, ""))
          end
        end
        toplevel.each_classmodule{|m|
          if m.include_includes?(module_name, @options_ignore_case)
            if !m.include_requires?(@file_name, @options_ignore_case)
              m.add_require(Require.new(@file_name, ""))
            end
          end
        }
      end

      namelist_comment = 
        find_namelists(f9x_module, before_contains(module_code))
      f9x_module.comment << namelist_comment if namelist_comment

    elsif block_searching_flag == :program
      program_name = module_program_name
      program_name = "main_program" if program_name.empty?
      program_code = module_program_code
      program_trailing = module_program_trailing
      program_priority, program_trailing = doc_priority_from_trailing(program_trailing)

      program_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) + 
        "\n" + program_trailing : program_trailing + "\n" + 
        find_comments(program_code.sub(/^.*$\n/i, ''))

      progress "p"
      @stats.num_methods += 1
      f9x_mainprogram = AnyMethod.new("main_program", program_name)
      f9x_mainprogram.singleton = false
      f9x_mainprogram.comment = "<b><em> Main Program </em></b> :: <tt></tt>\n"
      f9x_mainprogram.comment << program_comment
      f9x_mainprogram.params = ""
      f9x_mainprogram.set_priority(program_priority) if program_priority

      # For output source code
      f9x_mainprogram.start_collecting_tokens
      f9x_mainprogram.add_token Token.new(1,1).set_text(program_code)

      @top_level.add_method f9x_mainprogram
      parse_program_or_module(@top_level, program_code, :private)

      namelist_comment = find_namelists(f9x_mainprogram, program_code)
      f9x_mainprogram.comment << namelist_comment if namelist_comment
    end

    # next loop to search next block
    level_depth = 0
    block_searching_flag = false
    block_searching_lines = []
    pre_comment = []
    next false
  }

  remaining_lines.delete_if{ |line|
    line == false
  }

  # External subprograms and functions are parsed
  #
  parse_program_or_module(@top_level, remaining_lines.join("\n"),
                          :public, true)

  @top_level
end