Class RDoc::Fortran95parser
In: parsers/parse_f95.rb
Parent: Object

See rdoc/parsers/parse_f95.rb

Methods

Classes and Modules

Class RDoc::Fortran95parser::Fortran95Definition

Constants

COMMENTS_ARE_UPPER = false  
"false":Comments are below source code
"true" :Comments are upper source code
INTERNAL_ALIAS_MES = "Alias for"   Internal alias message
EXTERNAL_ALIAS_MES = "Original external subprogram is"   External alias message
PROVIDED_MODULES_MES = "This file provides following module"   Provided modules message
NAMELIST_REPOSITORY_NAME = "NAMELIST"   Repository of NAMELIST statements
IGNORED_MARKER_REGEXP = /^:nodoc:/   Ignored marker
DOC_PRIORITY_REGEXP = /^:doc\-priority\s+([\-\+]?\d+):\s*/   Document priority marker

Public Class methods

prepare to parse a Fortran 95 file

[Source]

     # File parsers/parse_f95.rb, line 819
819:     def initialize(top_level, file_name, body, options, stats)
820:       @body = body
821:       @stats = stats
822:       @file_name  = file_name
823:       @options = options
824:       @top_level = top_level
825:       @progress = $stderr unless options.quiet
826: 
827:       begin
828:         @options_ignore_case = options.ignore_case
829:       rescue
830:         @options_ignore_case = true
831:       end
832: 
833:     end

Public Instance methods

Return lines before "contains" statement in modules. "interface", "type" statements are removed.

[Source]

      # File parsers/parse_f95.rb, line 1767
1767:     def before_contains(code)
1768:       level_depth = 0
1769:       before_contains_lines = []
1770:       before_contains_code = nil
1771:       before_contains_flag = nil
1772:       code.split("\n").each{ |line|
1773:         if !before_contains_flag
1774:           if line =~ /^\s*?module\s+\w+\s*?(!.*?)?$/i
1775:             before_contains_flag = true
1776:           end
1777:         else
1778:           break if line =~ /^\s*?contains\s*?(!.*?)?$/i
1779:           level_depth += 1 if block_start?(line)
1780:           level_depth -= 1 if block_end?(line)
1781:           break if level_depth < 0
1782:           before_contains_lines << line
1783:         end
1784: 
1785:       }
1786:       before_contains_code = before_contains_lines.join("\n")
1787:       if before_contains_code
1788:         before_contains_code.gsub!(/^\s*?interface\s+.*?\s+end\s+interface.*?$/im, "")
1789:         before_contains_code.gsub!(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
1790:       end
1791: 
1792:       before_contains_code
1793:     end

Which "line" is end of block (module, program, block data, subroutine, function) statement ?

[Source]

      # File parsers/parse_f95.rb, line 2435
2435:     def block_end?(line)
2436:       return nil if !line
2437: 
2438:       if line =~ /^\s*?end\s*?(!.*?)?$/i                 ||
2439:           line =~ /^\s*?end\s+module(\s+\w+)?\s*?(!.*?)?$/i       ||
2440:           line =~ /^\s*?end\s+program(\s+\w+)?\s*?(!.*?)?$/i      ||
2441:           line =~ /^\s*?end\s+block\s+data(\s+\w+)?\s*?(!.*?)?$/i  ||
2442:           line =~ /^\s*?end\s+subroutine(\s+\w+)?\s*?(!.*?)?$/i   ||
2443:           line =~ /^\s*?end\s+function(\s+\w+)?\s*?(!.*?)?$/i
2444:         return true
2445:       end
2446: 
2447:       return nil
2448:     end

Which "line" is start of block (module, program, block data, subroutine, function) statement ?

[Source]

      # File parsers/parse_f95.rb, line 2399
2399:     def block_start?(line)
2400:       return nil if !line
2401: 
2402:       if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i    ||
2403:           line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i  ||
2404:           line =~ /^\s*?block\s+data(\s+\w+)?\s*?(!.*?)?$/i     ||
2405:           line =~ \
2406:                   /^\s*?
2407:                    (recursive|pure|elemental)?\s*?
2408:                    subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
2409:                   /ix ||
2410:           line =~ \
2411:                   /^\s*?
2412:                    (recursive|pure|elemental)?\s*?
2413:                    (
2414:                        character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
2415:                      | type\s*?\([\w\s]+?\)\s+
2416:                      | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
2417:                      | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
2418:                      | double\s+precision\s+
2419:                      | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
2420:                      | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
2421:                    )?
2422:                    function\s+(\w+)\s*?
2423:                    (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
2424:                   /ix
2425:         return true
2426:       end
2427: 
2428:       return nil
2429:     end

Check external aliases

subname というサブルーチン名, または関数名を持つファイルを 探査し, 存在する場合にはそのファイル内へメソッドを追加する.

[Source]

      # File parsers/parse_f95.rb, line 2154
2154:     def check_external_aliases(subname, params, comment, test=nil)
2155:       @@external_aliases.each{ |alias_item|
2156:         if subname == alias_item["old_name"] ||
2157:                     subname.upcase == alias_item["old_name"].upcase &&
2158:                             @options_ignore_case
2159: 
2160:           new_meth = initialize_external_method(alias_item["new_name"], 
2161:                                                 subname, params, @file_name, 
2162:                                                 comment)
2163:           new_meth.visibility = alias_item["visibility"]
2164:           new_meth.set_priority(alias_item["doc_priority"]) if alias_item["doc_priority"]
2165: 
2166:           progress "e"
2167:           @stats.num_methods += 1
2168:           alias_item["file_or_module"].add_method(new_meth)
2169: 
2170:           if !alias_item["file_or_module"].include_requires?(@file_name, @options_ignore_case)
2171:             alias_item["file_or_module"].add_require(Require.new(@file_name, ""))
2172:           end
2173:         end
2174:       }
2175:     end

Check public_methods

use したモジュールからそのまま引き継いで public として 公開する場合のチェックを行う. subname というサブルーチン名, または関数名を持つファイルを 探査し, 存在する場合にはそのファイル内へメソッドを追加する.

[Source]

      # File parsers/parse_f95.rb, line 2185
2185:     def check_public_methods(method, parent)
2186:       return if !method || !parent
2187:       @@public_methods.each{ |alias_item|
2188:         parent_is_used_module = nil
2189:         alias_item["used_modules"].each{ |used_module|
2190:           if used_module == parent ||
2191:               used_module.upcase == parent.upcase &&
2192:               @options_ignore_case
2193:             parent_is_used_module = true
2194:           end
2195:         }
2196:         next if !parent_is_used_module
2197: 
2198:         if method.name == alias_item["name"] ||
2199:             method.name.upcase == alias_item["name"].upcase &&
2200:             @options_ignore_case
2201: 
2202:           new_meth = initialize_public_method(method, parent)
2203:           if alias_item["local_name"]
2204:             new_meth.name = alias_item["local_name"]
2205:           end
2206: 
2207:           progress "e"
2208:           @stats.num_methods += 1
2209:           alias_item["file_or_module"].add_method new_meth
2210:         end
2211:       }
2212:     end

Collect comment for file entity

[Source]

      # File parsers/parse_f95.rb, line 1798
1798:     def collect_first_comment(body)
1799:       comment = ""
1800:       not_comment = ""
1801:       comment_start = false
1802:       comment_end   = false
1803:       body.split("\n").each{ |line|
1804:         if comment_end
1805:           not_comment << line
1806:           not_comment << "\n"
1807:         elsif /^\s*?!\s?(.*)$/i =~ line
1808:           comment_start = true
1809:           comment << $1
1810:           comment << "\n"
1811:         elsif /^\s*?$/i =~ line
1812:           comment_end = true if comment_start && COMMENTS_ARE_UPPER
1813:         else
1814:           comment_end = true
1815:           not_comment << line
1816:           not_comment << "\n"
1817:         end
1818:       }
1819:       return comment, not_comment
1820:     end

Comment out checker

[Source]

      # File parsers/parse_f95.rb, line 2326
2326:     def comment_out?(line)
2327:       return nil unless line
2328:       commentout = false
2329:       squote = false ; dquote = false
2330:       line.split("").each { |char|
2331:         if !(squote) && !(dquote)
2332:           case char
2333:           when "!" ; commentout = true ; break
2334:           when "\""; dquote = true
2335:           when "\'"; squote = true
2336:           else next
2337:           end
2338:         elsif squote
2339:           case char
2340:           when "\'"; squote = false
2341:           else next
2342:           end
2343:         elsif dquote
2344:           case char
2345:           when "\""; dquote = false
2346:           else next
2347:           end
2348:         end
2349:       }
2350:       return commentout
2351:     end

Continuous line checker

[Source]

      # File parsers/parse_f95.rb, line 2312
2312:     def continuous_line?(line)
2313:       continuous = false
2314:       if /&\s*?(!.*)?$/ =~ line
2315:         continuous = true
2316:         if comment_out?($~.pre_match)
2317:           continuous = false
2318:         end
2319:       end
2320:       return continuous
2321:     end

Parse string argument "text", and Return Array of Fortran95Definition object

[Source]

      # File parsers/parse_f95.rb, line 2577
2577:     def definition_info(text)
2578:       return nil unless text
2579:       lines = "#{text}"
2580:       defs = Array.new
2581:       comment = ""
2582:       trailing_comment = ""
2583:       under_comment_valid = false
2584:       lines.split("\n").each{ |line|
2585:         if /^\s*?!\s?(.*)/ =~ line
2586:           if COMMENTS_ARE_UPPER
2587:             comment << remove_header_marker($1)
2588:             comment << "\n"
2589:           elsif defs[-1] && under_comment_valid
2590:             defs[-1].comment << "\n"
2591:             defs[-1].comment << remove_header_marker($1)
2592:           end
2593:           next
2594:         elsif /^\s*?$/ =~ line
2595:           comment = ""
2596:           under_comment_valid = false
2597:           next
2598:         end
2599:         type = ""
2600:         characters = ""
2601:         if line =~ /^\s*?
2602:                     (
2603:                         character\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2604:                       | type\s*?\([\w\s]+?\)[\s\,]*
2605:                       | integer\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2606:                       | real\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2607:                       | double\s+precision[\s\,]*
2608:                       | logical\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2609:                       | complex\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2610:                     )
2611:                     (.*?::)?
2612:                     (.+)$
2613:                    /ix
2614:           characters = $8
2615:           type = $1
2616:           type << $7.gsub(/::/, '').gsub(/^\s*?\,/, '') if $7
2617:         else
2618:           under_comment_valid = false
2619:           next
2620:         end
2621:         squote = false ; dquote = false ; bracket = 0
2622:         iniflag = false; commentflag = false
2623:         varname = "" ; arraysuffix = "" ; inivalue = ""
2624:         start_pos = defs.size
2625:         characters.split("").each { |char|
2626:           if !(squote) && !(dquote) && bracket <= 0 && !(iniflag) && !(commentflag)
2627:             case char
2628:             when "!" ; commentflag = true
2629:             when "(" ; bracket += 1       ; arraysuffix = char
2630:             when "\""; dquote = true
2631:             when "\'"; squote = true
2632:             when "=" ; iniflag = true     ; inivalue << char
2633:             when ","
2634:               defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2635:               varname = "" ; arraysuffix = "" ; inivalue = ""
2636:               under_comment_valid = true
2637:             when " " ; next
2638:             else     ; varname << char
2639:             end
2640:           elsif commentflag
2641:             comment << remove_header_marker(char)
2642:             trailing_comment << remove_header_marker(char)
2643:           elsif iniflag
2644:             if dquote
2645:               case char
2646:               when "\"" ; dquote = false ; inivalue << char
2647:               else      ; inivalue << char
2648:               end
2649:             elsif squote
2650:               case char
2651:               when "\'" ; squote = false ; inivalue << char
2652:               else      ; inivalue << char
2653:               end
2654:             elsif bracket > 0
2655:               case char
2656:               when "(" ; bracket += 1 ; inivalue << char
2657:               when ")" ; bracket -= 1 ; inivalue << char
2658:               else     ; inivalue << char
2659:               end
2660:             else
2661:               case char
2662:               when ","
2663:                 defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2664:                 varname = "" ; arraysuffix = "" ; inivalue = ""
2665:                 iniflag = false
2666:                 under_comment_valid = true
2667:               when "(" ; bracket += 1 ; inivalue << char
2668:               when "\""; dquote = true  ; inivalue << char
2669:               when "\'"; squote = true  ; inivalue << char
2670:               when "!" ; commentflag = true
2671:               else     ; inivalue << char
2672:               end
2673:             end
2674:           elsif !(squote) && !(dquote) && bracket > 0
2675:             case char
2676:             when "(" ; bracket += 1 ; arraysuffix << char
2677:             when ")" ; bracket -= 1 ; arraysuffix << char
2678:             else     ; arraysuffix << char
2679:             end
2680:           elsif squote
2681:             case char
2682:             when "\'"; squote = false ; inivalue << char
2683:             else     ; inivalue << char
2684:             end
2685:           elsif dquote
2686:             case char
2687:             when "\""; dquote = false ; inivalue << char
2688:             else     ; inivalue << char
2689:             end
2690:           end
2691:         }
2692:         defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2693:         if trailing_comment =~ IGNORED_MARKER_REGEXP
2694:           defs[start_pos..-1].collect!{ |defitem|
2695:             defitem.nodoc = true
2696:           }
2697:         end
2698:         if trailing_comment =~ DOC_PRIORITY_REGEXP
2699:           doc_priority = $1.to_i
2700:           defs[start_pos..-1].collect!{ |defitem|
2701:             defitem.doc_priority = doc_priority
2702:             defitem.comment.sub!(DOC_PRIORITY_REGEXP, '')
2703:           }
2704:         end
2705:         varname = "" ; arraysuffix = "" ; inivalue = ""
2706:         comment = ""
2707:         under_comment_valid = true
2708:         trailing_comment = ""
2709:       }
2710:       return defs
2711:     end

[Source]

      # File parsers/parse_f95.rb, line 1747
1747:     def doc_priority_from_trailing(trailing)
1748:       prefix = ''
1749:       if trailing =~ /^(\s*!)(.*)$/
1750:         prefix = $1
1751:         trailing = $2
1752:       end
1753:       if trailing =~ DOC_PRIORITY_REGEXP
1754:         priority = $1.to_i
1755:         trailing.sub!(DOC_PRIORITY_REGEXP, '')
1756:       else
1757:         priority = false
1758:       end
1759:       trailing = prefix + trailing
1760:       return priority, trailing
1761:     end

Return comments of definitions of arguments

If "all" argument is true, information of all arguments are returned. If "modified_params" is true, list of arguments are decorated, for exameple, optional arguments are parenthetic as "[arg]".

[Source]

      # File parsers/parse_f95.rb, line 1829
1829:     def find_arguments(args, text, all=nil, indent=nil, modified_params=nil)
1830:       return unless args || all
1831:       indent = "" unless indent
1832:       args = ["all"] if all
1833:       params = "" if modified_params
1834:       comma = ""
1835:       return unless text
1836:       args_rdocforms = "\n"
1837:       remaining_lines = "#{text}"
1838:       definitions = definition_info(remaining_lines)
1839:       args.each{ |arg|
1840:         arg.strip!
1841:         arg.chomp!
1842:         definitions.each { |defitem|
1843:           if arg == defitem.varname.strip.chomp || all
1844:             args_rdocforms << "\n\#{indent}<b><tt>\#{defitem.varname.chomp.strip}\#{defitem.arraysuffix}  </tt></b>  <tt> \#{defitem.inivalue}</tt> ::\n\#{indent}   <tt>\#{defitem.types.chomp.strip}</tt>\n"
1845:             if !defitem.comment.chomp.strip.empty?
1846:               comment = ""
1847:               defitem.comment.split("\n").each{ |line|
1848:                 comment << "       " + line + "\n"
1849:               }
1850:               args_rdocforms << "\n\#{indent}   <tt></tt> ::\n\#{indent}       <tt></tt>\n\#{indent}       \#{comment.chomp.strip}\n"
1851:             end
1852: 
1853:             if modified_params
1854:               if defitem.include_attr?("optional")
1855:                 params << "#{comma}[#{arg}]"
1856:               else
1857:                 params << "#{comma}#{arg}"
1858:               end
1859:               comma = ", "
1860:             end
1861:           end
1862:         }
1863:       }
1864:       if modified_params
1865:         return args_rdocforms, params
1866:       else
1867:         return args_rdocforms
1868:       end
1869:     end

Comments just after module or subprogram, or arguments are returnd. If "COMMENTS_ARE_UPPER" is true, comments just before modules or subprograms are returnd

[Source]

      # File parsers/parse_f95.rb, line 1972
1972:     def find_comments text
1973:       return "" unless text
1974:       lines = text.split("\n")
1975:       lines.reverse! if COMMENTS_ARE_UPPER
1976:       comment_block = Array.new
1977:       lines.each do |line|
1978:         break if line =~ /^\s*?\w/ || line =~ /^\s*?$/
1979:         if COMMENTS_ARE_UPPER
1980:           comment_block.unshift line.sub(/^\s*?!\s?/,"")
1981:         else
1982:           comment_block.push line.sub(/^\s*?!\s?/,"")
1983:         end
1984:       end
1985:       nice_lines = comment_block.join("\n").split "\n\s*?\n"
1986:       nice_lines[0] ||= ""
1987:       nice_lines.shift
1988:     end

Add namelist information to Repository (dummy module of each @top_level) of NAMELIST statements. And return comments about namelist group names

[Source]

      # File parsers/parse_f95.rb, line 1887
1887:     def find_namelists(container, text, before_contains=nil)
1888:       return nil if !text
1889:       top_level = find_toplevel(container)
1890: 
1891:       if text =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)(!.*?)?$/i
1892:         if top_level.include_includes?(NAMELIST_REPOSITORY_NAME)
1893:           namelist_module = 
1894:             top_level.find_module_named(NAMELIST_REPOSITORY_NAME)
1895:         else
1896:           namelist_module = 
1897:             top_level.add_module NormalClass, NAMELIST_REPOSITORY_NAME
1898:           namelist_module.record_location top_level
1899:           namelist_module.comment = "This is not a module but a repository of NAMELIST group names declared\nin all Fortran 90/95 files\n"
1900:         end
1901:       else
1902:         return ""
1903:       end
1904: 
1905:       nml_group_name_lists = []
1906:       lines = "#{text}"
1907:       before_contains = "" if !before_contains
1908:       while lines =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)(!.*?)?$/i
1909:         lines = $~.post_match
1910:         pre_match = $~.pre_match ; post_match = $~.post_match
1911:         nml_group_name = $1
1912:         trailing_comment = $3 || ""
1913:         nml_vars_list  = $2.split(",")
1914:         nml_comment = COMMENTS_ARE_UPPER ? 
1915:             find_comments(pre_match.sub(/\n$/, '')) :
1916:             find_comments(trailing_comment + post_match)
1917:         if lines.split("\n")[0] =~ /^\//i
1918:           lines = "namelist " + lines
1919:         end
1920: 
1921:         nml_meth = AnyMethod.new("NAMELIST", nml_group_name)
1922:         nml_meth.singleton = false
1923:         nml_meth.params    = "( " + nml_vars_list.join(", ") + " )"
1924:         nml_meth.comment   = "<b><em> NAMELIST </em></b> :: <tt></tt>\n"
1925:         nml_meth.comment   << find_arguments(nml_vars_list, "#{text}" + "\n" + before_contains)
1926:         nml_meth.comment   << "\n" + nml_comment if nml_comment
1927:         if container.parent.parent
1928:           parent_object = container.parent.name
1929:         else
1930:           parent_object = container.parent.file_relative_name
1931:         end
1932:         nml_meth.comment   << "\n\nThis namelist group name is input/output in "
1933:         nml_meth.comment   << parent_object + "#" + container.name
1934: 
1935:         progress "n"
1936:         @stats.num_methods += 1
1937:         namelist_module.add_method nml_meth
1938: 
1939:         nml_group_name_lists << NAMELIST_REPOSITORY_NAME + "#" + nml_group_name
1940:       end
1941: 
1942:       if !nml_group_name_lists.empty?
1943:         comments_in_procedures = "\n\nThis procedure input/output "
1944:         comments_in_procedures << nml_group_name_lists.join(", ") + " . "
1945:       else
1946:         comments_in_procedures = ""
1947:       end
1948: 
1949:       comments_in_procedures
1950:     end

Return toplevel class of container

[Source]

      # File parsers/parse_f95.rb, line 1959
1959:     def find_toplevel(container)
1960:       top_level = container
1961:       while top_level.parent
1962:         top_level = top_level.parent
1963:       end
1964:       top_level
1965:     end

Find visibility

[Source]

      # File parsers/parse_f95.rb, line 2135
2135:     def find_visibility(container, subname, visibility_info)
2136:       return nil if !subname || !visibility_info
2137:       visibility_info.each{ |info|
2138:         if info["name"] == subname ||
2139:             @options_ignore_case && info["name"].upcase == subname.upcase
2140:           if info["parent"] == container.name
2141:             return info["visibility"]
2142:           end
2143:         end
2144:       }
2145:       return nil
2146:     end

Create method for external alias

If argument "internal" is true, file is ignored.

[Source]

      # File parsers/parse_f95.rb, line 2017
2017:     def initialize_external_method(new, old, params, file, comment, token=nil,
2018:                                    internal=nil, nolink=nil)
2019:       return nil unless new || old
2020: 
2021:       if internal
2022:         external_alias_header = "#{INTERNAL_ALIAS_MES} "
2023:         external_alias_text   = external_alias_header + old 
2024:       elsif file
2025:         external_alias_header = "#{EXTERNAL_ALIAS_MES} "
2026:         external_alias_text   = external_alias_header + file + "#" + old
2027:       else
2028:         return nil
2029:       end
2030:       external_meth = AnyMethod.new(external_alias_text, new)
2031:       external_meth.singleton    = false
2032:       external_meth.params       = params
2033:       external_comment = remove_trailing_alias(comment) + "\n\n" if comment
2034:       external_meth.comment = external_comment || ""
2035:       if nolink && token
2036:         external_meth.start_collecting_tokens
2037:         external_meth.add_token Token.new(1,1).set_text(token)
2038:       else
2039:         external_meth.comment << external_alias_text
2040:       end
2041: 
2042:       return external_meth
2043:     end

Create method for internal alias

[Source]

      # File parsers/parse_f95.rb, line 2000
2000:     def initialize_public_method(method, parent)
2001:       return if !method || !parent
2002: 
2003:       new_meth = AnyMethod.new("External Alias for module", method.name)
2004:       new_meth.singleton    = method.singleton
2005:       new_meth.params       = method.params.clone
2006:       new_meth.comment      = remove_trailing_alias(method.comment.clone)
2007:       new_meth.comment      << "\n\n#{EXTERNAL_ALIAS_MES} #{parent.strip.chomp}\##{method.name}"
2008: 
2009:       return new_meth
2010:     end

[Source]

      # File parsers/parse_f95.rb, line 1063
1063:     def parse_program_or_module(container, code,
1064:                                 visibility=:public, external=nil)
1065:       return unless container
1066:       return unless code
1067:       remaining_lines = code.split("\n")
1068:       remaining_code = "#{code}"
1069: 
1070:       #
1071:       # Parse variables before "contains" in module
1072:       #
1073:       # namelist 変数の定義に使われたり, これ自体が定数, 変数
1074:       # 提供されるのに利用される. (変数や定数として利用される場合,
1075:       # これもメソッドとして提供する.
1076:       #
1077:       before_contains_code = before_contains(remaining_code)
1078: 
1079:       #
1080:       # Parse global "use"
1081:       #
1082:       use_check_code = "#{before_contains_code}"
1083:       cascaded_modules_list = []
1084:       while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i
1085:         use_check_code = $~.pre_match
1086:         use_check_code << $~.post_match
1087:         used_mod_name = $1.strip.chomp
1088:         used_list = $2 || ""
1089:         used_trailing = $3 || ""
1090:         next if used_trailing.sub(/^!/, '') =~ IGNORED_MARKER_REGEXP
1091:         if !container.include_includes?(used_mod_name, @options_ignore_case)
1092:           progress "."
1093:           container.add_include Include.new(used_mod_name, "")
1094:         end
1095:         if ! (used_list =~ /\,\s*?only\s*?:/i )
1096:           cascaded_modules_list << "\#" + used_mod_name
1097:         end
1098:       end
1099: 
1100:       #
1101:       # Parse public and private, and store information.
1102:       # This information is used when "add_method" and
1103:       # "set_visibility_for" are called.
1104:       #
1105:       visibility_default, visibility_info = 
1106:                 parse_visibility(remaining_lines.join("\n"), visibility, container)
1107:       @@public_methods.concat visibility_info
1108:       if visibility_default == :public
1109:         if !cascaded_modules_list.empty?
1110:           cascaded_modules = 
1111:             Attr.new("Cascaded Modules",
1112:                      "Imported modules all of whose components are published again",
1113:                      "",
1114:                      cascaded_modules_list.join(", "))
1115:           container.add_attribute(cascaded_modules)
1116:         end
1117:       end
1118: 
1119:       #
1120:       # Check rename elements
1121:       #
1122:       use_check_code = "#{before_contains_code}"
1123:       while use_check_code =~ /^\s*?use\s+(\w+)\s*?\,(.+)$/i
1124:         use_check_code = $~.pre_match
1125:         use_check_code << $~.post_match
1126:         used_mod_name = $1.strip.chomp
1127:         used_elements = $2.sub(/\s*?only\s*?:\s*?/i, '')
1128:         used_elements.split(",").each{ |used|
1129:           if /\s*?(\w+)\s*?=>\s*?(\w+)\s*?/ =~ used
1130:             local = $1
1131:             org = $2
1132:             @@public_methods.collect!{ |pub_meth|
1133:               if local == pub_meth["name"] ||
1134:                   local.upcase == pub_meth["name"].upcase &&
1135:                   @options_ignore_case
1136:                 pub_meth["name"] = org
1137:                 pub_meth["local_name"] = local
1138:               end
1139:               pub_meth
1140:             }
1141:           end
1142:         }
1143:       end
1144: 
1145:       #
1146:       # Parse private "use"
1147:       #
1148:       use_check_code = remaining_lines.join("\n")
1149:       while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i
1150:         use_check_code = $~.pre_match
1151:         use_check_code << $~.post_match
1152:         used_mod_name = $1.strip.chomp
1153:         used_trailing = $3 || ""
1154:         next if used_trailing.sub(/^!/, '') =~ IGNORED_MARKER_REGEXP
1155:         if !container.include_includes?(used_mod_name, @options_ignore_case)
1156:           progress "."
1157:           container.add_include Include.new(used_mod_name, "")
1158:         end
1159:       end
1160: 
1161:       container.each_includes{ |inc|
1162:         TopLevel.all_files.each do |name, toplevel|
1163:           indicated_mod = toplevel.find_symbol(inc.name,
1164:                                                nil, @options_ignore_case)
1165:           if indicated_mod
1166:             indicated_name = indicated_mod.parent.file_relative_name
1167:             if !container.include_requires?(indicated_name, @options_ignore_case)
1168:               container.add_require(Require.new(indicated_name, ""))
1169:             end
1170:             break
1171:           end
1172:         end
1173:       }
1174: 
1175:       #
1176:       # Parse derived types definitions
1177:       #
1178:       derived_types_comment = ""
1179:       remaining_code = remaining_lines.join("\n")
1180:       while remaining_code =~ /^\s*?
1181:                                     type[\s\,]+(public|private)?\s*?(::)?\s*?
1182:                                     (\w+)\s*?(!.*?)?$
1183:                                     (.*?)
1184:                                     ^\s*?end\s+type.*?$
1185:                               /imx
1186:         remaining_code = $~.pre_match
1187:         remaining_code << $~.post_match
1188:         typename = $3.chomp.strip
1189:         type_elements = $5 || ""
1190:         type_code = remove_empty_head_lines($&)
1191:         type_trailing = find_comments($4)
1192:         type_visibility = $1
1193:         pre_match = $~.pre_match
1194:         next if type_trailing =~ IGNORED_MARKER_REGEXP
1195:         type_priority, type_trailing = doc_priority_from_trailing(type_trailing)
1196:         type_comment = COMMENTS_ARE_UPPER ? 
1197:           find_comments(pre_match) + "\n" + type_trailing :
1198:             type_trailing + "\n" + find_comments(type_code.sub(/^.*$\n/i, ''))
1199:         type_element_visibility_public = true
1200:         type_code.split("\n").each{ |line|
1201:           if /^\s*?private\s*?$/ =~ line
1202:             type_element_visibility_public = nil
1203:             break
1204:           end
1205:         } if type_code
1206: 
1207:         args_comment = ""
1208:         type_args_info = nil
1209: 
1210:         if @options.show_all
1211:           args_comment = find_arguments(nil, type_code, true)
1212:         else
1213:           type_public_args_list = []
1214:           type_args_info = definition_info(type_code)
1215:           type_args_info.each{ |arg|
1216:             arg_is_public = type_element_visibility_public
1217:             arg_is_public = true if arg.include_attr?("public")
1218:             arg_is_public = nil if arg.include_attr?("private")
1219:             type_public_args_list << arg.varname if arg_is_public
1220:           }
1221:           args_comment = find_arguments(type_public_args_list, type_code)
1222:         end
1223: 
1224:         type = AnyMethod.new("type #{typename}", typename)
1225:         type.singleton = false
1226:         type.params = ""
1227:         type.comment = "<b><em> Derived Type </em></b> :: <tt></tt>\n"
1228:         type.comment << args_comment if args_comment
1229:         type.comment << type_comment if type_comment
1230:         type.set_priority(type_priority) if type_priority
1231:         progress "t"
1232:         @stats.num_methods += 1
1233:         container.add_method type
1234: 
1235:         set_visibility(container, typename, visibility_default, @@public_methods)
1236: 
1237:         if type_visibility
1238:           type_visibility.gsub!(/\s/,'')
1239:           type_visibility.gsub!(/\,/,'')
1240:           type_visibility.gsub!(/:/,'')
1241:           type_visibility.downcase!
1242:           if type_visibility == "public"
1243:             container.set_visibility_for([typename], :public)
1244:           elsif type_visibility == "private"
1245:             container.set_visibility_for([typename], :private)
1246:           end
1247:         end
1248: 
1249:         check_public_methods(type, container.name)
1250: 
1251:         if @options.show_all
1252:           derived_types_comment << ", " unless derived_types_comment.empty?
1253:           derived_types_comment << typename
1254:         else
1255:           if type.visibility == :public
1256:           derived_types_comment << ", " unless derived_types_comment.empty?
1257:           derived_types_comment << typename
1258:           end
1259:         end
1260: 
1261:       end
1262: 
1263:       if !derived_types_comment.empty?
1264:         derived_types_table = 
1265:           Attr.new("Derived Types", "Derived_Types", "", 
1266:                    derived_types_comment)
1267:         container.add_attribute(derived_types_table)
1268:       end
1269: 
1270:       #
1271:       # move interface scope
1272:       #
1273:       interface_code = ""
1274:       while remaining_code =~ /^\s*?
1275:                                    interface(
1276:                                               \s+\w+                      |
1277:                                               \s+operator\s*?\(.*?\)       |
1278:                                               \s+assignment\s*?\(\s*?=\s*?\)
1279:                                             )?\s*?$
1280:                                    (.*?)
1281:                                    ^\s*?end\s+interface.*?$
1282:                               /imx
1283:         interface_code << remove_empty_head_lines($&) + "\n"
1284:         remaining_code = $~.pre_match
1285:         remaining_code << $~.post_match
1286:       end
1287: 
1288:       #
1289:       # Parse global constants or variables in modules
1290:       #
1291:       const_var_defs = definition_info(before_contains_code)
1292:       const_var_defs.each{|defitem|
1293:         next if defitem.nodoc
1294:         const_or_var_type = "Variable"
1295:         const_or_var_progress = "v"
1296:         if defitem.include_attr?("parameter")
1297:           const_or_var_type = "Constant"
1298:           const_or_var_progress = "c"
1299:         end
1300:         const_or_var = AnyMethod.new(const_or_var_type, defitem.varname)
1301:         const_or_var.set_priority(defitem.doc_priority) if defitem.doc_priority
1302:         const_or_var.singleton = false
1303:         const_or_var.params = ""
1304:         self_comment = find_arguments([defitem.varname], before_contains_code)
1305:         const_or_var.comment = "<b><em>" + const_or_var_type + "</em></b> :: <tt></tt>\n"
1306:         const_or_var.comment << self_comment if self_comment
1307:         progress const_or_var_progress
1308:         @stats.num_methods += 1
1309:         container.add_method const_or_var
1310: 
1311:         set_visibility(container, defitem.varname, visibility_default, @@public_methods)
1312: 
1313:         if defitem.include_attr?("public")
1314:           container.set_visibility_for([defitem.varname], :public)
1315:         elsif defitem.include_attr?("private")
1316:           container.set_visibility_for([defitem.varname], :private)
1317:         end
1318: 
1319:         check_public_methods(const_or_var, container.name)
1320: 
1321:       } if const_var_defs
1322: 
1323:       remaining_lines = remaining_code.split("\n")
1324: 
1325:       # "subroutine" or "function" parts are parsed (new)
1326:       #
1327:       level_depth = 0
1328:       block_searching_flag = nil
1329:       block_searching_lines = []
1330:       pre_comment = []
1331:       procedure_trailing = ""
1332:       procedure_name = ""
1333:       procedure_params = ""
1334:       procedure_prefix = ""
1335:       procedure_result_arg = ""
1336:       procedure_type = ""
1337:       contains_lines = []
1338:       contains_flag = nil
1339:       remaining_lines.collect!{|line|
1340:         if !block_searching_flag
1341:           # subroutine
1342:           if line =~ /^\s*?
1343:                            (recursive|pure|elemental)?\s*?
1344:                            subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
1345:                      /ix
1346:             block_searching_flag = :subroutine
1347:             block_searching_lines << line
1348: 
1349:             procedure_name = $2.chomp.strip
1350:             procedure_params = $3 || ""
1351:             procedure_prefix = $1 || ""
1352:             procedure_trailing = $4 || "!"
1353:             next false
1354: 
1355:           # function
1356:           elsif line =~ /^\s*?
1357:                          (recursive|pure|elemental)?\s*?
1358:                          (
1359:                              character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1360:                            | type\s*?\([\w\s]+?\)\s+
1361:                            | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1362:                            | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1363:                            | double\s+precision\s+
1364:                            | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1365:                            | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1366:                          )?
1367:                          function\s+(\w+)\s*?
1368:                          (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
1369:                         /ix
1370:             block_searching_flag = :function
1371:             block_searching_lines << line
1372: 
1373:             procedure_prefix = $1 || ""
1374:             procedure_type = $2 ? $2.chomp.strip : nil
1375:             procedure_name = $8.chomp.strip
1376:             procedure_params = $9 || ""
1377:             procedure_result_arg = $11 ? $11.chomp.strip : procedure_name
1378:             procedure_trailing = $12 || "!"
1379:             next false
1380:           elsif line =~ /^\s*?!\s?(.*)/
1381:             pre_comment << line
1382:             next line
1383:           else
1384:             pre_comment = []
1385:             next line
1386:           end
1387:         end
1388:         contains_flag = true if line =~ /^\s*?contains\s*?(!.*?)?$/
1389:         block_searching_lines << line
1390:         contains_lines << line if contains_flag
1391: 
1392:         level_depth += 1 if block_start?(line)
1393:         level_depth -= 1 if block_end?(line)
1394:         if level_depth >= 0
1395:           next false
1396:         end
1397: 
1398:         # "procedure_code" is formatted.
1399:         # ":nodoc:" flag is checked.
1400:         #
1401:         procedure_code = block_searching_lines.join("\n")
1402:         procedure_code = remove_empty_head_lines(procedure_code)
1403:         if procedure_trailing.sub(/^!/, '') =~ IGNORED_MARKER_REGEXP
1404:           # next loop to search next block
1405:           level_depth = 0
1406:           block_searching_flag = nil
1407:           block_searching_lines = []
1408:           pre_comment = []
1409:           procedure_trailing = ""
1410:           procedure_name = ""
1411:           procedure_params = ""
1412:           procedure_prefix = ""
1413:           procedure_result_arg = ""
1414:           procedure_type = ""
1415:           contains_lines = []
1416:           contains_flag = nil
1417:           next false
1418:         end
1419: 
1420:         # AnyMethod is created, and added to container
1421:         #
1422:         subroutine_function = nil
1423:         if block_searching_flag == :subroutine
1424:           subroutine_prefix   = procedure_prefix
1425:           subroutine_name     = procedure_name
1426:           subroutine_params   = procedure_params
1427:           subroutine_trailing = procedure_trailing
1428:           subroutine_code     = procedure_code
1429:           subroutine_priority, subroutine_trailing = doc_priority_from_trailing(subroutine_trailing)
1430: 
1431:           subroutine_comment = COMMENTS_ARE_UPPER ? 
1432:             pre_comment.join("\n") + "\n" + subroutine_trailing : 
1433:               subroutine_trailing + "\n" + subroutine_code.sub(/^.*$\n/i, '')
1434:           subroutine = AnyMethod.new("subroutine", subroutine_name)
1435:           parse_subprogram(subroutine, subroutine_params,
1436:                            subroutine_comment, subroutine_code,
1437:                            before_contains_code, nil, subroutine_prefix)
1438:           subroutine.set_priority(subroutine_priority) if subroutine_priority
1439:           progress "s"
1440:           @stats.num_methods += 1
1441:           container.add_method subroutine
1442:           subroutine_function = subroutine
1443: 
1444:           namelist_comment = 
1445:             find_namelists(subroutine, subroutine_code, before_contains_code)
1446:           subroutine.comment << namelist_comment if namelist_comment
1447: 
1448:         elsif block_searching_flag == :function
1449:           function_prefix     = procedure_prefix
1450:           function_type       = procedure_type
1451:           function_name       = procedure_name
1452:           function_params_org = procedure_params
1453:           function_result_arg = procedure_result_arg
1454:           function_trailing   = procedure_trailing
1455:           function_code_org   = procedure_code
1456:           function_priority, function_trailing = doc_priority_from_trailing(function_trailing)
1457: 
1458:           function_comment = COMMENTS_ARE_UPPER ?
1459:             pre_comment.join("\n") + "\n" + function_trailing :
1460:               function_trailing + "\n " + function_code_org.sub(/^.*$\n/i, '')
1461: 
1462:           function_code = "#{function_code_org}"
1463:           if function_type
1464:             function_code << "\n" + function_type + " :: " + function_result_arg
1465:           end
1466: 
1467:           function_params =
1468:             function_params_org.sub(/^\(/, "\(#{function_result_arg}, ")
1469: 
1470:           function = AnyMethod.new("function", function_name)
1471:           parse_subprogram(function, function_params,
1472:                            function_comment, function_code,
1473:                            before_contains_code, true, function_prefix)
1474:           function.set_priority(function_priority) if function_priority
1475: 
1476:           # Specific modification due to function
1477:           function.params.sub!(/\(\s*?#{function_result_arg}\s*?,\s*?/, "\( ")
1478:           function.params << " result(" + function_result_arg + ")"
1479:           function.start_collecting_tokens
1480:           function.add_token Token.new(1,1).set_text(function_code_org)
1481: 
1482:           progress "f"
1483:           @stats.num_methods += 1
1484:           container.add_method function
1485:           subroutine_function = function
1486: 
1487:           namelist_comment = 
1488:             find_namelists(function, function_code, before_contains_code)
1489:           function.comment << namelist_comment if namelist_comment
1490: 
1491:         end
1492: 
1493:         # The visibility of procedure is specified
1494:         #
1495:         set_visibility(container, procedure_name, 
1496:                        visibility_default, @@public_methods)
1497: 
1498:         # The alias for this procedure from external modules
1499:         #
1500:         check_external_aliases(procedure_name,
1501:                                subroutine_function.params,
1502:                                subroutine_function.comment, subroutine_function) if external
1503:         check_public_methods(subroutine_function, container.name)
1504: 
1505: 
1506:         # contains_lines are parsed as private procedures
1507:         if contains_flag
1508:           parse_program_or_module(container,
1509:                                   contains_lines.join("\n"), :private)
1510:         end
1511: 
1512:         # next loop to search next block
1513:         level_depth = 0
1514:         block_searching_flag = nil
1515:         block_searching_lines = []
1516:         pre_comment = []
1517:         procedure_trailing = ""
1518:         procedure_name = ""
1519:         procedure_params = ""
1520:         procedure_prefix = ""
1521:         procedure_result_arg = ""
1522:         contains_lines = []
1523:         contains_flag = nil
1524:         next false
1525:       } # End of remaining_lines.collect!{|line|
1526: 
1527:       # Array remains_lines is converted to String remains_code again
1528:       #
1529:       remaining_code = remaining_lines.join("\n")
1530: 
1531:       #
1532:       # Parse interface
1533:       #
1534:       interface_scope = false
1535:       generic_name = ""
1536:       interface_code.split("\n").each{ |line|
1537:         if /^\s*?
1538:                  interface(
1539:                             \s+\w+|
1540:                             \s+operator\s*?\(.*?\)|
1541:                             \s+assignment\s*?\(\s*?=\s*?\)
1542:                           )?
1543:                  \s*?(!.*?)?$
1544:            /ix =~ line
1545:           generic_name = $1 ? $1.strip.chomp : nil
1546:           interface_trailing = $2 || "!"
1547:           interface_scope = true
1548:           interface_scope = false if interface_trailing.sub(/^!/, '') =~ IGNORED_MARKER_REGEXP
1549: #          if generic_name =~ /operator\s*?\((.*?)\)/i
1550: #            operator_name = $1
1551: #            if operator_name && !operator_name.empty?
1552: #              generic_name = "#{operator_name}"
1553: #            end
1554: #          end
1555: #          if generic_name =~ /assignment\s*?\((.*?)\)/i
1556: #            assignment_name = $1
1557: #            if assignment_name && !assignment_name.empty?
1558: #              generic_name = "#{assignment_name}"
1559: #            end
1560: #          end
1561:         end
1562:         if /^\s*?end\s+interface/i =~ line
1563:           interface_scope = false
1564:           generic_name = nil
1565:         end
1566:         # internal alias
1567:         if interface_scope && /^\s*?module\s+procedure\s+(.*?)(!.*?)?$/i =~ line
1568:           procedures = $1.strip.chomp
1569:           procedures_trailing = $2 || "!"
1570:           next if procedures_trailing.sub(/^!/, '') =~ IGNORED_MARKER_REGEXP
1571:           procedures_priority, procedures_trailing = doc_priority_from_trailing(procedures_trailing)
1572: 
1573:           procedures.split(",").each{ |proc|
1574:             proc.strip!
1575:             proc.chomp!
1576:             next if generic_name == proc || !generic_name
1577:             old_meth = container.find_symbol(proc, nil, @options_ignore_case)
1578:             next if !old_meth
1579:             nolink = old_meth.visibility == :private ? true : nil
1580:             nolink = nil if @options.show_all
1581:             new_meth = 
1582:                initialize_external_method(generic_name, proc, 
1583:                                           old_meth.params, nil, 
1584:                                           old_meth.comment, 
1585:                                           old_meth.clone.token_stream[0].text, 
1586:                                           true, nolink)
1587:             new_meth.singleton = old_meth.singleton
1588:             new_meth.set_priority(procedures_priority) if procedures_priority
1589: 
1590:             progress "i"
1591:             @stats.num_methods += 1
1592:             container.add_method new_meth
1593: 
1594:             set_visibility(container, generic_name, visibility_default, @@public_methods)
1595: 
1596:             check_public_methods(new_meth, container.name)
1597: 
1598:           }
1599:         end
1600: 
1601:         # external aliases
1602:         if interface_scope
1603:           # subroutine
1604:           proc = nil
1605:           params = nil
1606:           procedures_trailing = nil
1607:           if line =~ /^\s*?
1608:                            (recursive|pure|elemental)?\s*?
1609:                            subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
1610:                      /ix
1611:             proc = $2.chomp.strip
1612:             proc_name = generic_name || proc
1613:             params = $3 || ""
1614:             procedures_trailing = $4 || "!"
1615: 
1616:           # function
1617:           elsif line =~ /^\s*?
1618:                          (recursive|pure|elemental)?\s*?
1619:                          (
1620:                              character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1621:                            | type\s*?\([\w\s]+?\)\s+
1622:                            | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1623:                            | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1624:                            | double\s+precision\s+
1625:                            | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1626:                            | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1627:                          )?
1628:                          function\s+(\w+)\s*?
1629:                          (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
1630:                         /ix
1631:             proc = $8.chomp.strip
1632:             proc_name = generic_name || proc
1633:             params = $9 || ""
1634:             procedures_trailing = $12 || "!"
1635:           else
1636:             next
1637:           end
1638:           next if procedures_trailing.sub(/^!/, '') =~ IGNORED_MARKER_REGEXP
1639:           procedures_priority, procedures_trailing = doc_priority_from_trailing(procedures_trailing)
1640:           indicated_method = nil
1641:           indicated_file   = nil
1642:           TopLevel.all_files.each do |name, toplevel|
1643:             indicated_method = toplevel.find_local_symbol(proc, @options_ignore_case)
1644:             indicated_file = name
1645:             break if indicated_method
1646:           end
1647: 
1648:           if indicated_method
1649:             external_method = 
1650:               initialize_external_method(proc_name, proc, 
1651:                                          indicated_method.params, 
1652:                                          indicated_file, 
1653:                                          indicated_method.comment)
1654:             external_method.set_priority(procedures_priority) if procedures_priority
1655: 
1656:             progress "e"
1657:             @stats.num_methods += 1
1658:             container.add_method external_method
1659:             set_visibility(container, proc_name, visibility_default, @@public_methods)
1660:             if !container.include_requires?(indicated_file, @options_ignore_case)
1661:               container.add_require(Require.new(indicated_file, ""))
1662:             end
1663:             check_public_methods(external_method, container.name)
1664: 
1665:           else
1666:             @@external_aliases << {
1667:               "new_name"  => proc_name,
1668:               "old_name"  => proc,
1669:               "file_or_module" => container,
1670:               "visibility" => find_visibility(container, proc_name, @@public_methods) || visibility_default,
1671:               "doc_priority" => procedures_priority
1672:             }
1673:           end
1674:         end
1675: 
1676:       } if interface_code # End of interface_code.split("\n").each ...
1677: 
1678:       #
1679:       # Already imported methods are removed from @@public_methods.
1680:       # Remainders are assumed to be imported from other modules.
1681:       #
1682:       # 既に参照済みのメソッドは @@public_methods から取り除く.
1683:       # 残りは外部モジュールからの参照と仮定する.
1684:       #
1685:       @@public_methods.delete_if{ |method| method["entity_is_discovered"]}
1686: 
1687:       @@public_methods.each{ |pub_meth|
1688:         next unless pub_meth["file_or_module"].name == container.name
1689:         pub_meth["used_modules"].each{ |used_mod|
1690:           TopLevel.all_classes_and_modules.each{ |modules|
1691:             if modules.name == used_mod ||
1692:                 modules.name.upcase == used_mod.upcase &&
1693:                 @options_ignore_case
1694:               modules.method_list.each{ |meth|
1695:                 if meth.name == pub_meth["name"] ||
1696:                     meth.name.upcase == pub_meth["name"].upcase &&
1697:                     @options_ignore_case
1698:                   new_meth = initialize_public_method(meth,
1699:                                                       modules.name)
1700:                   if pub_meth["local_name"]
1701:                     new_meth.name = pub_meth["local_name"]
1702:                   end
1703:                   progress "e"
1704:                   @stats.num_methods += 1
1705:                   container.add_method new_meth
1706:                 end
1707:               }
1708:             end
1709:           }
1710:         }
1711:       }
1712: 
1713:       container
1714:     end

Parse arguments, comment, code of subroutine and function. Return AnyMethod object.

[Source]

      # File parsers/parse_f95.rb, line 1720
1720:     def parse_subprogram(subprogram, params, comment, code, 
1721:                          before_contains=nil, function=nil, prefix=nil)
1722:       subprogram.singleton = false
1723:       prefix = "" if !prefix
1724:       arguments = params.sub(/\(/, "").sub(/\)/, "").split(",") if params
1725:       args_comment, params_opt = 
1726:         find_arguments(arguments, code.sub(/^s*?contains\s*?(!.*?)?$.*/im, ""),
1727:                        nil, nil, true)
1728:       params_opt = "( " + params_opt + " ) " if params_opt
1729:       subprogram.params = params_opt || ""
1730: 
1731:       block_comment = find_comments comment
1732:       if function
1733:         subprogram.comment = "<b><em> Function </em></b> :: <em>#{prefix}</em>\n"
1734:       else
1735:         subprogram.comment = "<b><em> Subroutine </em></b> :: <em>#{prefix}</em>\n"
1736:       end
1737:       subprogram.comment << args_comment if args_comment
1738:       subprogram.comment << block_comment if block_comment
1739: 
1740:       # For output source code
1741:       subprogram.start_collecting_tokens
1742:       subprogram.add_token Token.new(1,1).set_text(code)
1743: 
1744:       subprogram
1745:     end

Parse visibility

[Source]

      # File parsers/parse_f95.rb, line 2050
2050:     def parse_visibility(code, default, container)
2051:       result = []
2052:       visibility_default = default || :public
2053: 
2054:       used_modules = []
2055:       container.includes.each{|i| used_modules << i.name} if container
2056: 
2057:       remaining_code = code.gsub(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
2058:       remaining_code.split("\n").each{ |line|
2059:         if /^\s*?private\s*?$/ =~ line
2060:           visibility_default = :private
2061:           break
2062:         end
2063:       } if remaining_code
2064: 
2065:       remaining_code.split("\n").each{ |line|
2066:         if /^\s*?private\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
2067:           methods = $2.sub(/!.*$/, '')
2068:           methods.split(",").each{ |meth|
2069:             meth.sub!(/!.*$/, '')
2070:             meth.gsub!(/:/, '')
2071:             result << {
2072:               "name" => meth.chomp.strip,
2073:               "visibility" => :private,
2074:               "used_modules" => used_modules.clone,
2075:               "file_or_module" => container,
2076:               "entity_is_discovered" => nil,
2077:               "local_name" => nil
2078:             }
2079:           }
2080:         elsif /^\s*?public\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
2081:           methods = $2.sub(/!.*$/, '')
2082:           methods.split(",").each{ |meth|
2083:             meth.sub!(/!.*$/, '')
2084:             meth.gsub!(/:/, '')
2085:             result << {
2086:               "name" => meth.chomp.strip,
2087:               "visibility" => :public,
2088:               "used_modules" => used_modules.clone,
2089:               "file_or_module" => container,
2090:               "entity_is_discovered" => nil,
2091:               "local_name" => nil
2092:             }
2093:           }
2094:         end
2095:       } if remaining_code
2096: 
2097:       if container
2098:         result.each{ |vis_info|
2099:           vis_info["parent"] = container.name
2100:         }
2101:       end
2102: 
2103:       return visibility_default, result
2104:     end

[Source]

      # File parsers/parse_f95.rb, line 1990
1990:     def progress(char)
1991:       unless @options.quiet
1992:         @progress.print(char)
1993:         @progress.flush
1994:       end
1995:     end

Empty lines in header are removed

[Source]

      # File parsers/parse_f95.rb, line 2474
2474:     def remove_empty_head_lines(text)
2475:       return "" unless text
2476:       lines = text.split("\n")
2477:       header = true
2478:       lines.delete_if{ |line|
2479:         header = false if /\S/ =~ line
2480:         header && /^\s*?$/ =~ line
2481:       }
2482:       lines.join("\n")
2483:     end

header marker "=", "==", … are removed

[Source]

      # File parsers/parse_f95.rb, line 2487
2487:     def remove_header_marker(text)
2488:       return text.gsub(/^\s?(=+)/, '<tt></tt>\1')
2489:     end

[Source]

      # File parsers/parse_f95.rb, line 2491
2491:     def remove_private_comments(body)
2492:       body.gsub!(/^(\s*)!--\s*?$.*?^\s*!\+\+\s*?$/m, '\\1!')
2493:       return body
2494:     end

Remove "Alias for" in end of comments

[Source]

      # File parsers/parse_f95.rb, line 2453
2453:     def remove_trailing_alias(text)
2454:       return "" if !text
2455:       lines = text.split("\n").reverse
2456:       comment_block = Array.new
2457:       checked = false
2458:       lines.each do |line|
2459:         if !checked 
2460:           if /^\s?#{INTERNAL_ALIAS_MES}/ =~ line ||
2461:               /^\s?#{EXTERNAL_ALIAS_MES}/ =~ line
2462:             checked = true
2463:             next
2464:           end
2465:         end
2466:         comment_block.unshift line
2467:       end
2468:       nice_lines = comment_block.join("\n")
2469:       nice_lines ||= ""
2470:       return nice_lines
2471:     end

devine code constructs

[Source]

      # File parsers/parse_f95.rb, line 836
 836:     def scan
 837: 
 838:       # remove private comment
 839:       remaining_code = remove_private_comments(@body)
 840: 
 841:       # continuation lines are united to one line
 842:       remaining_code = united_to_one_line(remaining_code)
 843: 
 844:       # semicolons are replaced to line feed
 845:       remaining_code = semicolon_to_linefeed(remaining_code)
 846: 
 847:       # collect comment for file entity
 848:       whole_comment, remaining_code = collect_first_comment(remaining_code)
 849:       @top_level.comment = whole_comment
 850: 
 851:       # String "remaining_code" is converted to Array "remaining_lines"
 852:       remaining_lines = remaining_code.split("\n")
 853: 
 854:       # "module" or "program" parts are parsed (new)
 855:       #
 856:       level_depth = 0
 857:       block_searching_flag = nil
 858:       block_searching_lines = []
 859:       pre_comment = []
 860:       module_program_trailing = ""
 861:       module_program_name = ""
 862:       other_block_level_depth = 0
 863:       other_block_searching_flag = nil
 864:       remaining_lines.collect!{|line|
 865:         if !block_searching_flag && !other_block_searching_flag
 866:           if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i
 867:             block_searching_flag = :module
 868:             block_searching_lines << line
 869:             module_program_name = $1
 870:             module_program_trailing = find_comments($2)
 871:             next false
 872:           elsif line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i ||
 873:                  line =~ /^\s*?\w/ && !block_start?(line)
 874:             block_searching_flag = :program
 875:             block_searching_lines << line
 876:             module_program_name = $1 || ""
 877:             module_program_trailing = find_comments($2)
 878:             next false
 879: 
 880:           elsif block_start?(line)
 881:             other_block_searching_flag = true
 882:             next line
 883: 
 884:           elsif line =~ /^\s*?!\s?(.*)/
 885:             pre_comment << line
 886:             next line
 887:           else
 888:             pre_comment = []
 889:             next line
 890:           end
 891:         elsif other_block_searching_flag
 892:           other_block_level_depth += 1 if block_start?(line)
 893:           other_block_level_depth -= 1 if block_end?(line)
 894:           if other_block_level_depth < 0
 895:             other_block_level_depth = 0
 896:             other_block_searching_flag = nil
 897:           end
 898:           next line
 899:         end
 900: 
 901:         block_searching_lines << line
 902:         level_depth += 1 if block_start?(line)
 903:         level_depth -= 1 if block_end?(line)
 904:         if level_depth >= 0
 905:           next false
 906:         end
 907: 
 908:         # "module_program_code" is formatted.
 909:         # ":nodoc:" flag is checked.
 910:         #
 911:         module_program_code = block_searching_lines.join("\n")
 912:         module_program_code = remove_empty_head_lines(module_program_code)
 913:         if module_program_trailing =~ IGNORED_MARKER_REGEXP
 914:           # next loop to search next block
 915:           level_depth = 0
 916:           block_searching_flag = false
 917:           block_searching_lines = []
 918:           pre_comment = []
 919:           next false
 920:         end
 921: 
 922:         # NormalClass is created, and added to @top_level
 923:         #
 924:         if block_searching_flag == :module
 925:           module_name = module_program_name
 926:           module_code = module_program_code
 927:           module_trailing = module_program_trailing
 928:           progress "m"
 929:           @stats.num_modules += 1
 930:           f9x_module = @top_level.add_module NormalClass, module_name
 931:           f9x_module.record_location @top_level
 932: 
 933:           #
 934:           # Add provided modules information to @top_level comment
 935:           #
 936:           provided_modules = []
 937:           provided_mes_line_num = nil
 938:           top_level_comment_lines = []
 939:           line_num = 0
 940:           @top_level.comment.split("\n").each{|line|
 941:             top_level_comment_lines << line
 942:             line_num += 1
 943:             next if line.empty?
 944:             if !provided_mes_line_num && /^\s?#{PROVIDED_MODULES_MES}/ =~ line
 945:               provided_mes_line_num = line_num
 946:               next
 947:             end
 948:             if provided_mes_line_num
 949:               if /^\s?\*\s+<b>(\w+)<\/b>/ =~ line
 950:                 provided_modules << $1
 951:               else
 952:                 provided_mes_line_num = nil
 953:               end
 954:             end
 955:           }
 956:           line_num = 0
 957:           if provided_mes_line_num
 958:             top_level_comment_lines.collect!{ |line|
 959:               line_num += 1
 960:               if line_num < provided_mes_line_num
 961:                 line
 962:               else
 963:                 nil
 964:               end
 965:             }
 966:             top_level_comment_lines.delete_if{|line| !line }
 967:           end
 968:           top_level_comment_lines << "\n" + PROVIDED_MODULES_MES + "."
 969:           if provided_mes_line_num
 970:             top_level_comment_lines[-1].sub!(/\.$/, '')
 971:             top_level_comment_lines[-1] << "s."
 972:           end
 973:           provided_modules.each{ |mod|
 974:             top_level_comment_lines << "* <b>" + mod + "</b>"
 975:           }
 976:           top_level_comment_lines << "* <b>" + module_name + "</b>"
 977:           @top_level.comment = top_level_comment_lines.join("\n")
 978: 
 979:           #
 980:           # Information about the module is parsed
 981:           #
 982:           f9x_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) +
 983:             "\n" + module_trailing : module_trailing + "\n" +
 984:             find_comments(module_code.sub(/^.*$\n/i, ''))
 985:           f9x_module.comment = f9x_comment
 986:           parse_program_or_module(f9x_module, module_code)
 987: 
 988:           TopLevel.all_files.each do |name, toplevel|
 989:             if toplevel.include_includes?(module_name, @options_ignore_case)
 990:               if !toplevel.include_requires?(@file_name, @options_ignore_case)
 991:                 toplevel.add_require(Require.new(@file_name, ""))
 992:               end
 993:             end
 994:             toplevel.each_classmodule{|m|
 995:               if m.include_includes?(module_name, @options_ignore_case)
 996:                 if !m.include_requires?(@file_name, @options_ignore_case)
 997:                   m.add_require(Require.new(@file_name, ""))
 998:                 end
 999:               end
1000:             }
1001:           end
1002: 
1003:           namelist_comment = 
1004:             find_namelists(f9x_module, before_contains(module_code))
1005:           f9x_module.comment << namelist_comment if namelist_comment
1006: 
1007:         elsif block_searching_flag == :program
1008:           program_name = module_program_name
1009:           program_name = "main_program" if program_name.empty?
1010:           program_code = module_program_code
1011:           program_trailing = module_program_trailing
1012:           program_priority, program_trailing = doc_priority_from_trailing(program_trailing)
1013: 
1014:           program_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) + 
1015:             "\n" + program_trailing : program_trailing + "\n" + 
1016:             find_comments(program_code.sub(/^.*$\n/i, ''))
1017: 
1018:           progress "p"
1019:           @stats.num_methods += 1
1020:           f9x_mainprogram = AnyMethod.new("main_program", program_name)
1021:           f9x_mainprogram.singleton = false
1022:           f9x_mainprogram.comment = "<b><em> Main Program </em></b> :: <tt></tt>\n"
1023:           f9x_mainprogram.comment << program_comment
1024:           f9x_mainprogram.params = ""
1025:           f9x_mainprogram.set_priority(program_priority) if program_priority
1026: 
1027:           # For output source code
1028:           f9x_mainprogram.start_collecting_tokens
1029:           f9x_mainprogram.add_token Token.new(1,1).set_text(program_code)
1030: 
1031:           @top_level.add_method f9x_mainprogram
1032:           parse_program_or_module(@top_level, program_code, :private)
1033: 
1034:           namelist_comment = find_namelists(f9x_mainprogram, program_code)
1035:           f9x_mainprogram.comment << namelist_comment if namelist_comment
1036:         end
1037: 
1038:         # next loop to search next block
1039:         level_depth = 0
1040:         block_searching_flag = false
1041:         block_searching_lines = []
1042:         pre_comment = []
1043:         next false
1044:       }
1045: 
1046:       remaining_lines.delete_if{ |line|
1047:         line == false
1048:       }
1049: 
1050:       # External subprograms and functions are parsed
1051:       #
1052:       # 単一のファイル内において program や module に格納されない,
1053:       # 外部サブルーチン, 外部関数部分の解析.
1054:       #
1055:       parse_program_or_module(@top_level, remaining_lines.join("\n"),
1056:                               :public, true)
1057: 
1058:       @top_level
1059:     end

Semicolons are replaced to line feed.

[Source]

      # File parsers/parse_f95.rb, line 2356
2356:     def semicolon_to_linefeed(text)
2357:       return "" unless text
2358:       lines = text.split("\n")
2359:       lines.collect!{ |line|
2360:         indent_space = ""
2361:         if line =~ /^(\s+)/
2362:           indent_space = $1
2363:         end
2364:         words = line.split("")
2365:         commentout = false
2366:         squote = false ; dquote = false
2367:         words.collect! { |char|
2368:           if !(squote) && !(dquote) && !(commentout)
2369:             case char
2370:             when "!" ; commentout = true ; next char
2371:             when "\""; dquote = true     ; next char
2372:             when "\'"; squote = true     ; next char
2373:             when ";" ;                     "\n"+indent_space
2374:             else next char
2375:             end
2376:           elsif commentout
2377:             next char
2378:           elsif squote
2379:             case char
2380:             when "\'"; squote = false ; next char
2381:             else next char
2382:             end
2383:           elsif dquote
2384:             case char
2385:             when "\""; dquote = false ; next char
2386:             else next char
2387:             end
2388:           end
2389:         }
2390:         words.join("")
2391:       }
2392:       return lines.join("\n")
2393:     end

Set visibility

"subname" element of "visibility_info" is deleted.

[Source]

      # File parsers/parse_f95.rb, line 2111
2111:     def set_visibility(container, subname, visibility_default, visibility_info)
2112:       return unless container || subname || visibility_default || visibility_info
2113:       not_found = true
2114:       visibility_info.collect!{ |info|
2115:         if info["name"] == subname ||
2116:             @options_ignore_case && info["name"].upcase == subname.upcase
2117:           if info["file_or_module"].name == container.name
2118:             container.set_visibility_for([subname], info["visibility"])
2119:             info["entity_is_discovered"] = true
2120:             not_found = false
2121:           end
2122:         end
2123:         info
2124:       }
2125:       if not_found
2126:         return container.set_visibility_for([subname], visibility_default)
2127:       else
2128:         return container
2129:       end
2130:     end

Continuous lines are united.

Comments in continuous lines are removed. If delete_space=false, spaces around "&" are not deleted.

Example

before

   subroutine func(a, b, c, d, e, & ! ignored comments
     &             f, g, h)         ! valid comments

after

   subroutine func(a, b, c, d, e, f, g, h)         ! valid comments

[Source]

      # File parsers/parse_f95.rb, line 2231
2231:     def united_to_one_line(f90src, delete_space=true)
2232:       return "" unless f90src
2233:       lines = f90src.split("\n")
2234:       previous_continuing = false
2235:       now_continuing = false
2236:       body = ""
2237:       squote = false ; dquote = false
2238:       lines.each{ |line|
2239:         words = line.split("")
2240:         next if words.empty? && previous_continuing
2241:         commentout = false
2242:         brank_flag = true ; brank_char = ""
2243:         ignore = false
2244:         words.collect! { |char|
2245:           if previous_continuing && brank_flag
2246:             now_continuing = true
2247:             ignore         = true
2248:             case char
2249:             when "!"                       ; break
2250:             when " " ; brank_char << char  ; next ""
2251:             when "&"
2252:               brank_flag = false
2253:               now_continuing = false
2254:               next ""
2255:             else 
2256:               brank_flag     = false
2257:               now_continuing = false
2258:               ignore         = false
2259:               next brank_char + char
2260:             end
2261:           end
2262:           ignore = false
2263: 
2264:           if now_continuing && !(squote) && !(dquote)
2265:             next ""
2266:           elsif !(squote) && !(dquote) && !(commentout)
2267:             case char
2268:             when "!" ; commentout = true     ; next char
2269:             when "\""; dquote = true         ; next char
2270:             when "\'"; squote = true         ; next char
2271:             when "&" ; now_continuing = true ; next ""
2272:             else next char
2273:             end
2274:           elsif commentout
2275:             next char
2276:           elsif squote
2277:             case char
2278:             when "\'"; squote = false ; now_continuing = false ; next char
2279:             when "&" ; now_continuing = true ; next ""
2280:             else next char
2281:             end
2282:           elsif dquote
2283:             case char
2284:             when "\""; dquote = false ; now_continuing = false ; next char
2285:             when "&" ; now_continuing = true ; next ""
2286:             else next char
2287:             end
2288:           end
2289:         }
2290:         if !ignore && !previous_continuing || !brank_flag
2291:           if previous_continuing
2292:             if delete_space
2293:               joined_words = words.join("")
2294:               body = body.rstrip + " " + joined_words.lstrip
2295:             else
2296:               body << words.join("")
2297:             end
2298:           else
2299:             body << "\n" + words.join("")
2300:           end
2301:         end
2302:         previous_continuing = now_continuing ? true : false
2303:         now_continuing = false
2304:       }
2305:       return body
2306:     end

[Validate]