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 912
912:     def initialize(top_level, file_name, body, options, stats)
913:       @body = body
914:       @stats = stats
915:       @file_name  = file_name
916:       @options = options
917:       @top_level = top_level
918:       @progress = $stderr unless options.quiet
919: 
920:       begin
921:         @options_ignore_case = options.ignore_case
922:       rescue
923:         @options_ignore_case = true
924:       end
925: 
926:     end

Public Instance methods

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

[Source]

      # File parsers/parse_f95.rb, line 1860
1860:     def before_contains(code)
1861:       level_depth = 0
1862:       before_contains_lines = []
1863:       before_contains_code = nil
1864:       before_contains_flag = nil
1865:       code.split("\n").each{ |line|
1866:         if !before_contains_flag
1867:           if line =~ /^\s*?module\s+\w+\s*?(!.*?)?$/i
1868:             before_contains_flag = true
1869:           end
1870:         else
1871:           break if line =~ /^\s*?contains\s*?(!.*?)?$/i
1872:           level_depth += 1 if block_start?(line)
1873:           level_depth -= 1 if block_end?(line)
1874:           break if level_depth < 0
1875:           before_contains_lines << line
1876:         end
1877: 
1878:       }
1879:       before_contains_code = before_contains_lines.join("\n")
1880:       if before_contains_code
1881:         before_contains_code.gsub!(/^\s*?interface\s+.*?\s+end\s+interface.*?$/im, "")
1882:         before_contains_code.gsub!(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
1883:       end
1884: 
1885:       before_contains_code
1886:     end

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

[Source]

      # File parsers/parse_f95.rb, line 2528
2528:     def block_end?(line)
2529:       return nil if !line
2530: 
2531:       if line =~ /^\s*?end\s*?(!.*?)?$/i                 ||
2532:           line =~ /^\s*?end\s+module(\s+\w+)?\s*?(!.*?)?$/i       ||
2533:           line =~ /^\s*?end\s+program(\s+\w+)?\s*?(!.*?)?$/i      ||
2534:           line =~ /^\s*?end\s+block\s+data(\s+\w+)?\s*?(!.*?)?$/i  ||
2535:           line =~ /^\s*?end\s+subroutine(\s+\w+)?\s*?(!.*?)?$/i   ||
2536:           line =~ /^\s*?end\s+function(\s+\w+)?\s*?(!.*?)?$/i
2537:         return true
2538:       end
2539: 
2540:       return nil
2541:     end

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

[Source]

      # File parsers/parse_f95.rb, line 2492
2492:     def block_start?(line)
2493:       return nil if !line
2494: 
2495:       if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i    ||
2496:           line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i  ||
2497:           line =~ /^\s*?block\s+data(\s+\w+)?\s*?(!.*?)?$/i     ||
2498:           line =~ \
2499:                   /^\s*?
2500:                    (recursive|pure|elemental)?\s*?
2501:                    subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
2502:                   /ix ||
2503:           line =~ \
2504:                   /^\s*?
2505:                    (recursive|pure|elemental)?\s*?
2506:                    (
2507:                        character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
2508:                      | type\s*?\([\w\s]+?\)\s+
2509:                      | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
2510:                      | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
2511:                      | double\s+precision\s+
2512:                      | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
2513:                      | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
2514:                    )?
2515:                    function\s+(\w+)\s*?
2516:                    (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
2517:                   /ix
2518:         return true
2519:       end
2520: 
2521:       return nil
2522:     end

Check external aliases

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

[Source]

      # File parsers/parse_f95.rb, line 2247
2247:     def check_external_aliases(subname, params, comment, test=nil)
2248:       @@external_aliases.each{ |alias_item|
2249:         if subname == alias_item["old_name"] ||
2250:                     subname.upcase == alias_item["old_name"].upcase &&
2251:                             @options_ignore_case
2252: 
2253:           new_meth = initialize_external_method(alias_item["new_name"], 
2254:                                                 subname, params, @file_name, 
2255:                                                 comment)
2256:           new_meth.visibility = alias_item["visibility"]
2257:           new_meth.set_priority(alias_item["doc_priority"]) if alias_item["doc_priority"]
2258: 
2259:           progress "e"
2260:           @stats.num_methods += 1
2261:           alias_item["file_or_module"].add_method(new_meth)
2262: 
2263:           if !alias_item["file_or_module"].include_requires?(@file_name, @options_ignore_case)
2264:             alias_item["file_or_module"].add_require(Require.new(@file_name, ""))
2265:           end
2266:         end
2267:       }
2268:     end

Check public_methods

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

[Source]

      # File parsers/parse_f95.rb, line 2278
2278:     def check_public_methods(method, parent)
2279:       return if !method || !parent
2280:       @@public_methods.each{ |alias_item|
2281:         parent_is_used_module = nil
2282:         alias_item["used_modules"].each{ |used_module|
2283:           if used_module == parent ||
2284:               used_module.upcase == parent.upcase &&
2285:               @options_ignore_case
2286:             parent_is_used_module = true
2287:           end
2288:         }
2289:         next if !parent_is_used_module
2290: 
2291:         if method.name == alias_item["name"] ||
2292:             method.name.upcase == alias_item["name"].upcase &&
2293:             @options_ignore_case
2294: 
2295:           new_meth = initialize_public_method(method, parent)
2296:           if alias_item["local_name"]
2297:             new_meth.name = alias_item["local_name"]
2298:           end
2299: 
2300:           progress "e"
2301:           @stats.num_methods += 1
2302:           alias_item["file_or_module"].add_method new_meth
2303:         end
2304:       }
2305:     end

Collect comment for file entity

[Source]

      # File parsers/parse_f95.rb, line 1891
1891:     def collect_first_comment(body)
1892:       comment = ""
1893:       not_comment = ""
1894:       comment_start = false
1895:       comment_end   = false
1896:       body.split("\n").each{ |line|
1897:         if comment_end
1898:           not_comment << line
1899:           not_comment << "\n"
1900:         elsif /^\s*?!\s?(.*)$/i =~ line
1901:           comment_start = true
1902:           comment << $1
1903:           comment << "\n"
1904:         elsif /^\s*?$/i =~ line
1905:           comment_end = true if comment_start && COMMENTS_ARE_UPPER
1906:         else
1907:           comment_end = true
1908:           not_comment << line
1909:           not_comment << "\n"
1910:         end
1911:       }
1912:       return comment, not_comment
1913:     end

Comment out checker

[Source]

      # File parsers/parse_f95.rb, line 2419
2419:     def comment_out?(line)
2420:       return nil unless line
2421:       commentout = false
2422:       squote = false ; dquote = false
2423:       line.split("").each { |char|
2424:         if !(squote) && !(dquote)
2425:           case char
2426:           when "!" ; commentout = true ; break
2427:           when "\""; dquote = true
2428:           when "\'"; squote = true
2429:           else next
2430:           end
2431:         elsif squote
2432:           case char
2433:           when "\'"; squote = false
2434:           else next
2435:           end
2436:         elsif dquote
2437:           case char
2438:           when "\""; dquote = false
2439:           else next
2440:           end
2441:         end
2442:       }
2443:       return commentout
2444:     end

Continuous line checker

[Source]

      # File parsers/parse_f95.rb, line 2405
2405:     def continuous_line?(line)
2406:       continuous = false
2407:       if /&\s*?(!.*)?$/ =~ line
2408:         continuous = true
2409:         if comment_out?($~.pre_match)
2410:           continuous = false
2411:         end
2412:       end
2413:       return continuous
2414:     end

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

[Source]

      # File parsers/parse_f95.rb, line 2670
2670:     def definition_info(text)
2671:       return nil unless text
2672:       lines = "#{text}"
2673:       defs = Array.new
2674:       comment = ""
2675:       trailing_comment = ""
2676:       under_comment_valid = false
2677:       lines.split("\n").each{ |line|
2678:         if /^\s*?!\s?(.*)/ =~ line
2679:           if COMMENTS_ARE_UPPER
2680:             comment << remove_header_marker($1)
2681:             comment << "\n"
2682:           elsif defs[-1] && under_comment_valid
2683:             defs[-1].comment << "\n"
2684:             defs[-1].comment << remove_header_marker($1)
2685:           end
2686:           next
2687:         elsif /^\s*?$/ =~ line
2688:           comment = ""
2689:           under_comment_valid = false
2690:           next
2691:         end
2692:         type = ""
2693:         characters = ""
2694:         if line =~ /^\s*?
2695:                     (
2696:                         character\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2697:                       | type\s*?\([\w\s]+?\)[\s\,]*
2698:                       | integer\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2699:                       | real\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2700:                       | double\s+precision[\s\,]*
2701:                       | logical\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2702:                       | complex\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2703:                     )
2704:                     (.*?::)?
2705:                     (.+)$
2706:                    /ix
2707:           characters = $8
2708:           type = $1
2709:           type << $7.gsub(/::/, '').gsub(/^\s*?\,/, '') if $7
2710:         else
2711:           under_comment_valid = false
2712:           next
2713:         end
2714:         squote = false ; dquote = false ; bracket = 0
2715:         iniflag = false; commentflag = false
2716:         varname = "" ; arraysuffix = "" ; inivalue = ""
2717:         start_pos = defs.size
2718:         characters.split("").each { |char|
2719:           if !(squote) && !(dquote) && bracket <= 0 && !(iniflag) && !(commentflag)
2720:             case char
2721:             when "!" ; commentflag = true
2722:             when "(" ; bracket += 1       ; arraysuffix = char
2723:             when "\""; dquote = true
2724:             when "\'"; squote = true
2725:             when "=" ; iniflag = true     ; inivalue << char
2726:             when ","
2727:               defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2728:               varname = "" ; arraysuffix = "" ; inivalue = ""
2729:               under_comment_valid = true
2730:             when " " ; next
2731:             else     ; varname << char
2732:             end
2733:           elsif commentflag
2734:             comment << remove_header_marker(char)
2735:             trailing_comment << remove_header_marker(char)
2736:           elsif iniflag
2737:             if dquote
2738:               case char
2739:               when "\"" ; dquote = false ; inivalue << char
2740:               else      ; inivalue << char
2741:               end
2742:             elsif squote
2743:               case char
2744:               when "\'" ; squote = false ; inivalue << char
2745:               else      ; inivalue << char
2746:               end
2747:             elsif bracket > 0
2748:               case char
2749:               when "(" ; bracket += 1 ; inivalue << char
2750:               when ")" ; bracket -= 1 ; inivalue << char
2751:               else     ; inivalue << char
2752:               end
2753:             else
2754:               case char
2755:               when ","
2756:                 defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2757:                 varname = "" ; arraysuffix = "" ; inivalue = ""
2758:                 iniflag = false
2759:                 under_comment_valid = true
2760:               when "(" ; bracket += 1 ; inivalue << char
2761:               when "\""; dquote = true  ; inivalue << char
2762:               when "\'"; squote = true  ; inivalue << char
2763:               when "!" ; commentflag = true
2764:               else     ; inivalue << char
2765:               end
2766:             end
2767:           elsif !(squote) && !(dquote) && bracket > 0
2768:             case char
2769:             when "(" ; bracket += 1 ; arraysuffix << char
2770:             when ")" ; bracket -= 1 ; arraysuffix << char
2771:             else     ; arraysuffix << char
2772:             end
2773:           elsif squote
2774:             case char
2775:             when "\'"; squote = false ; inivalue << char
2776:             else     ; inivalue << char
2777:             end
2778:           elsif dquote
2779:             case char
2780:             when "\""; dquote = false ; inivalue << char
2781:             else     ; inivalue << char
2782:             end
2783:           end
2784:         }
2785:         defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2786:         if trailing_comment =~ IGNORED_MARKER_REGEXP
2787:           defs[start_pos..-1].collect!{ |defitem|
2788:             defitem.nodoc = true
2789:           }
2790:         end
2791:         if trailing_comment =~ DOC_PRIORITY_REGEXP
2792:           doc_priority = $1.to_i
2793:           defs[start_pos..-1].collect!{ |defitem|
2794:             defitem.doc_priority = doc_priority
2795:             defitem.comment.sub!(DOC_PRIORITY_REGEXP, '')
2796:           }
2797:         end
2798:         varname = "" ; arraysuffix = "" ; inivalue = ""
2799:         comment = ""
2800:         under_comment_valid = true
2801:         trailing_comment = ""
2802:       }
2803:       return defs
2804:     end

[Source]

      # File parsers/parse_f95.rb, line 1840
1840:     def doc_priority_from_trailing(trailing)
1841:       prefix = ''
1842:       if trailing =~ /^(\s*!)(.*)$/
1843:         prefix = $1
1844:         trailing = $2
1845:       end
1846:       if trailing =~ DOC_PRIORITY_REGEXP
1847:         priority = $1.to_i
1848:         trailing.sub!(DOC_PRIORITY_REGEXP, '')
1849:       else
1850:         priority = false
1851:       end
1852:       trailing = prefix + trailing
1853:       return priority, trailing
1854:     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 1922
1922:     def find_arguments(args, text, all=nil, indent=nil, modified_params=nil)
1923:       return unless args || all
1924:       indent = "" unless indent
1925:       args = ["all"] if all
1926:       params = "" if modified_params
1927:       comma = ""
1928:       return unless text
1929:       args_rdocforms = "\n"
1930:       remaining_lines = "#{text}"
1931:       definitions = definition_info(remaining_lines)
1932:       args.each{ |arg|
1933:         arg.strip!
1934:         arg.chomp!
1935:         definitions.each { |defitem|
1936:           if arg == defitem.varname.strip.chomp || all
1937:             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"
1938:             if !defitem.comment.chomp.strip.empty?
1939:               comment = ""
1940:               defitem.comment.split("\n").each{ |line|
1941:                 comment << "       " + line + "\n"
1942:               }
1943:               args_rdocforms << "\n\#{indent}   <tt></tt> ::\n\#{indent}       <tt></tt>\n\#{indent}       \#{comment.chomp.strip}\n"
1944:             end
1945: 
1946:             if modified_params
1947:               if defitem.include_attr?("optional")
1948:                 params << "#{comma}[#{arg}]"
1949:               else
1950:                 params << "#{comma}#{arg}"
1951:               end
1952:               comma = ", "
1953:             end
1954:           end
1955:         }
1956:       }
1957:       if modified_params
1958:         return args_rdocforms, params
1959:       else
1960:         return args_rdocforms
1961:       end
1962:     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 2065
2065:     def find_comments text
2066:       return "" unless text
2067:       lines = text.split("\n")
2068:       lines.reverse! if COMMENTS_ARE_UPPER
2069:       comment_block = Array.new
2070:       lines.each do |line|
2071:         break if line =~ /^\s*?\w/ || line =~ /^\s*?$/
2072:         if COMMENTS_ARE_UPPER
2073:           comment_block.unshift line.sub(/^\s*?!\s?/,"")
2074:         else
2075:           comment_block.push line.sub(/^\s*?!\s?/,"")
2076:         end
2077:       end
2078:       nice_lines = comment_block.join("\n").split "\n\s*?\n"
2079:       nice_lines[0] ||= ""
2080:       nice_lines.shift
2081:     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 1980
1980:     def find_namelists(container, text, before_contains=nil)
1981:       return nil if !text
1982:       top_level = find_toplevel(container)
1983: 
1984:       if text =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)(!.*?)?$/i
1985:         if top_level.include_includes?(NAMELIST_REPOSITORY_NAME)
1986:           namelist_module = 
1987:             top_level.find_module_named(NAMELIST_REPOSITORY_NAME)
1988:         else
1989:           namelist_module = 
1990:             top_level.add_module NormalClass, NAMELIST_REPOSITORY_NAME
1991:           namelist_module.record_location top_level
1992:           namelist_module.comment = "This is not a module but a repository of NAMELIST group names declared\nin all Fortran 90/95 files\n"
1993:         end
1994:       else
1995:         return ""
1996:       end
1997: 
1998:       nml_group_name_lists = []
1999:       lines = "#{text}"
2000:       before_contains = "" if !before_contains
2001:       while lines =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)(!.*?)?$/i
2002:         lines = $~.post_match
2003:         pre_match = $~.pre_match ; post_match = $~.post_match
2004:         nml_group_name = $1
2005:         trailing_comment = $3 || ""
2006:         nml_vars_list  = $2.split(",")
2007:         nml_comment = COMMENTS_ARE_UPPER ? 
2008:             find_comments(pre_match.sub(/\n$/, '')) :
2009:             find_comments(trailing_comment + post_match)
2010:         if lines.split("\n")[0] =~ /^\//i
2011:           lines = "namelist " + lines
2012:         end
2013: 
2014:         nml_meth = AnyMethod.new("NAMELIST", nml_group_name)
2015:         nml_meth.singleton = false
2016:         nml_meth.params    = "( " + nml_vars_list.join(", ") + " )"
2017:         nml_meth.comment   = "<b><em> NAMELIST </em></b> :: <tt></tt>\n"
2018:         nml_meth.comment   << find_arguments(nml_vars_list, "#{text}" + "\n" + before_contains)
2019:         nml_meth.comment   << "\n" + nml_comment if nml_comment
2020:         if container.parent.parent
2021:           parent_object = container.parent.name
2022:         else
2023:           parent_object = container.parent.file_relative_name
2024:         end
2025:         nml_meth.comment   << "\n\nThis namelist group name is input/output in "
2026:         nml_meth.comment   << parent_object + "#" + container.name
2027: 
2028:         progress "n"
2029:         @stats.num_methods += 1
2030:         namelist_module.add_method nml_meth
2031: 
2032:         nml_group_name_lists << NAMELIST_REPOSITORY_NAME + "#" + nml_group_name
2033:       end
2034: 
2035:       if !nml_group_name_lists.empty?
2036:         comments_in_procedures = "\n\nThis procedure input/output "
2037:         comments_in_procedures << nml_group_name_lists.join(", ") + " . "
2038:       else
2039:         comments_in_procedures = ""
2040:       end
2041: 
2042:       comments_in_procedures
2043:     end

Return toplevel class of container

[Source]

      # File parsers/parse_f95.rb, line 2052
2052:     def find_toplevel(container)
2053:       top_level = container
2054:       while top_level.parent
2055:         top_level = top_level.parent
2056:       end
2057:       top_level
2058:     end

Find visibility

[Source]

      # File parsers/parse_f95.rb, line 2228
2228:     def find_visibility(container, subname, visibility_info)
2229:       return nil if !subname || !visibility_info
2230:       visibility_info.each{ |info|
2231:         if info["name"] == subname ||
2232:             @options_ignore_case && info["name"].upcase == subname.upcase
2233:           if info["parent"] == container.name
2234:             return info["visibility"]
2235:           end
2236:         end
2237:       }
2238:       return nil
2239:     end

Create method for external alias

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

[Source]

      # File parsers/parse_f95.rb, line 2110
2110:     def initialize_external_method(new, old, params, file, comment, token=nil,
2111:                                    internal=nil, nolink=nil)
2112:       return nil unless new || old
2113: 
2114:       if internal
2115:         external_alias_header = "#{INTERNAL_ALIAS_MES} "
2116:         external_alias_text   = external_alias_header + old 
2117:       elsif file
2118:         external_alias_header = "#{EXTERNAL_ALIAS_MES} "
2119:         external_alias_text   = external_alias_header + file + "#" + old
2120:       else
2121:         return nil
2122:       end
2123:       external_meth = AnyMethod.new(external_alias_text, new)
2124:       external_meth.singleton    = false
2125:       external_meth.params       = params
2126:       external_comment = remove_trailing_alias(comment) + "\n\n" if comment
2127:       external_meth.comment = external_comment || ""
2128:       if nolink && token
2129:         external_meth.start_collecting_tokens
2130:         external_meth.add_token Token.new(1,1).set_text(token)
2131:       else
2132:         external_meth.comment << external_alias_text
2133:       end
2134: 
2135:       return external_meth
2136:     end

Create method for internal alias

[Source]

      # File parsers/parse_f95.rb, line 2093
2093:     def initialize_public_method(method, parent)
2094:       return if !method || !parent
2095: 
2096:       new_meth = AnyMethod.new("External Alias for module", method.name)
2097:       new_meth.singleton    = method.singleton
2098:       new_meth.params       = method.params.clone
2099:       new_meth.comment      = remove_trailing_alias(method.comment.clone)
2100:       new_meth.comment      << "\n\n#{EXTERNAL_ALIAS_MES} #{parent.strip.chomp}\##{method.name}"
2101: 
2102:       return new_meth
2103:     end

[Source]

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

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

[Source]

      # File parsers/parse_f95.rb, line 1813
1813:     def parse_subprogram(subprogram, params, comment, code, 
1814:                          before_contains=nil, function=nil, prefix=nil)
1815:       subprogram.singleton = false
1816:       prefix = "" if !prefix
1817:       arguments = params.sub(/\(/, "").sub(/\)/, "").split(",") if params
1818:       args_comment, params_opt = 
1819:         find_arguments(arguments, code.sub(/^s*?contains\s*?(!.*?)?$.*/im, ""),
1820:                        nil, nil, true)
1821:       params_opt = "( " + params_opt + " ) " if params_opt
1822:       subprogram.params = params_opt || ""
1823: 
1824:       block_comment = find_comments comment
1825:       if function
1826:         subprogram.comment = "<b><em> Function </em></b> :: <em>#{prefix}</em>\n"
1827:       else
1828:         subprogram.comment = "<b><em> Subroutine </em></b> :: <em>#{prefix}</em>\n"
1829:       end
1830:       subprogram.comment << args_comment if args_comment
1831:       subprogram.comment << block_comment if block_comment
1832: 
1833:       # For output source code
1834:       subprogram.start_collecting_tokens
1835:       subprogram.add_token Token.new(1,1).set_text(code)
1836: 
1837:       subprogram
1838:     end

Parse visibility

[Source]

      # File parsers/parse_f95.rb, line 2143
2143:     def parse_visibility(code, default, container)
2144:       result = []
2145:       visibility_default = default || :public
2146: 
2147:       used_modules = []
2148:       container.includes.each{|i| used_modules << i.name} if container
2149: 
2150:       remaining_code = code.gsub(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
2151:       remaining_code.split("\n").each{ |line|
2152:         if /^\s*?private\s*?$/ =~ line
2153:           visibility_default = :private
2154:           break
2155:         end
2156:       } if remaining_code
2157: 
2158:       remaining_code.split("\n").each{ |line|
2159:         if /^\s*?private\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
2160:           methods = $2.sub(/!.*$/, '')
2161:           methods.split(",").each{ |meth|
2162:             meth.sub!(/!.*$/, '')
2163:             meth.gsub!(/:/, '')
2164:             result << {
2165:               "name" => meth.chomp.strip,
2166:               "visibility" => :private,
2167:               "used_modules" => used_modules.clone,
2168:               "file_or_module" => container,
2169:               "entity_is_discovered" => nil,
2170:               "local_name" => nil
2171:             }
2172:           }
2173:         elsif /^\s*?public\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
2174:           methods = $2.sub(/!.*$/, '')
2175:           methods.split(",").each{ |meth|
2176:             meth.sub!(/!.*$/, '')
2177:             meth.gsub!(/:/, '')
2178:             result << {
2179:               "name" => meth.chomp.strip,
2180:               "visibility" => :public,
2181:               "used_modules" => used_modules.clone,
2182:               "file_or_module" => container,
2183:               "entity_is_discovered" => nil,
2184:               "local_name" => nil
2185:             }
2186:           }
2187:         end
2188:       } if remaining_code
2189: 
2190:       if container
2191:         result.each{ |vis_info|
2192:           vis_info["parent"] = container.name
2193:         }
2194:       end
2195: 
2196:       return visibility_default, result
2197:     end

[Source]

      # File parsers/parse_f95.rb, line 2083
2083:     def progress(char)
2084:       unless @options.quiet
2085:         @progress.print(char)
2086:         @progress.flush
2087:       end
2088:     end

Empty lines in header are removed

[Source]

      # File parsers/parse_f95.rb, line 2567
2567:     def remove_empty_head_lines(text)
2568:       return "" unless text
2569:       lines = text.split("\n")
2570:       header = true
2571:       lines.delete_if{ |line|
2572:         header = false if /\S/ =~ line
2573:         header && /^\s*?$/ =~ line
2574:       }
2575:       lines.join("\n")
2576:     end

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

[Source]

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

[Source]

      # File parsers/parse_f95.rb, line 2584
2584:     def remove_private_comments(body)
2585:       body.gsub!(/^(\s*)!--\s*?$.*?^\s*!\+\+\s*?$/m, '\\1!')
2586:       return body
2587:     end

Remove "Alias for" in end of comments

[Source]

      # File parsers/parse_f95.rb, line 2546
2546:     def remove_trailing_alias(text)
2547:       return "" if !text
2548:       lines = text.split("\n").reverse
2549:       comment_block = Array.new
2550:       checked = false
2551:       lines.each do |line|
2552:         if !checked 
2553:           if /^\s?#{INTERNAL_ALIAS_MES}/ =~ line ||
2554:               /^\s?#{EXTERNAL_ALIAS_MES}/ =~ line
2555:             checked = true
2556:             next
2557:           end
2558:         end
2559:         comment_block.unshift line
2560:       end
2561:       nice_lines = comment_block.join("\n")
2562:       nice_lines ||= ""
2563:       return nice_lines
2564:     end

devine code constructs

[Source]

      # File parsers/parse_f95.rb, line 929
 929:     def scan
 930: 
 931:       # remove private comment
 932:       remaining_code = remove_private_comments(@body)
 933: 
 934:       # continuation lines are united to one line
 935:       remaining_code = united_to_one_line(remaining_code)
 936: 
 937:       # semicolons are replaced to line feed
 938:       remaining_code = semicolon_to_linefeed(remaining_code)
 939: 
 940:       # collect comment for file entity
 941:       whole_comment, remaining_code = collect_first_comment(remaining_code)
 942:       @top_level.comment = whole_comment
 943: 
 944:       # String "remaining_code" is converted to Array "remaining_lines"
 945:       remaining_lines = remaining_code.split("\n")
 946: 
 947:       # "module" or "program" parts are parsed (new)
 948:       #
 949:       level_depth = 0
 950:       block_searching_flag = nil
 951:       block_searching_lines = []
 952:       pre_comment = []
 953:       module_program_trailing = ""
 954:       module_program_name = ""
 955:       other_block_level_depth = 0
 956:       other_block_searching_flag = nil
 957:       remaining_lines.collect!{|line|
 958:         if !block_searching_flag && !other_block_searching_flag
 959:           if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i
 960:             block_searching_flag = :module
 961:             block_searching_lines << line
 962:             module_program_name = $1
 963:             module_program_trailing = find_comments($2)
 964:             next false
 965:           elsif line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i ||
 966:                  line =~ /^\s*?\w/ && !block_start?(line)
 967:             block_searching_flag = :program
 968:             block_searching_lines << line
 969:             module_program_name = $1 || ""
 970:             module_program_trailing = find_comments($2)
 971:             next false
 972: 
 973:           elsif block_start?(line)
 974:             other_block_searching_flag = true
 975:             next line
 976: 
 977:           elsif line =~ /^\s*?!\s?(.*)/
 978:             pre_comment << line
 979:             next line
 980:           else
 981:             pre_comment = []
 982:             next line
 983:           end
 984:         elsif other_block_searching_flag
 985:           other_block_level_depth += 1 if block_start?(line)
 986:           other_block_level_depth -= 1 if block_end?(line)
 987:           if other_block_level_depth < 0
 988:             other_block_level_depth = 0
 989:             other_block_searching_flag = nil
 990:           end
 991:           next line
 992:         end
 993: 
 994:         block_searching_lines << line
 995:         level_depth += 1 if block_start?(line)
 996:         level_depth -= 1 if block_end?(line)
 997:         if level_depth >= 0
 998:           next false
 999:         end
1000: 
1001:         # "module_program_code" is formatted.
1002:         # ":nodoc:" flag is checked.
1003:         #
1004:         module_program_code = block_searching_lines.join("\n")
1005:         module_program_code = remove_empty_head_lines(module_program_code)
1006:         if module_program_trailing =~ IGNORED_MARKER_REGEXP
1007:           # next loop to search next block
1008:           level_depth = 0
1009:           block_searching_flag = false
1010:           block_searching_lines = []
1011:           pre_comment = []
1012:           next false
1013:         end
1014: 
1015:         # NormalClass is created, and added to @top_level
1016:         #
1017:         if block_searching_flag == :module
1018:           module_name = module_program_name
1019:           module_code = module_program_code
1020:           module_trailing = module_program_trailing
1021:           progress "m"
1022:           @stats.num_modules += 1
1023:           f9x_module = @top_level.add_module NormalClass, module_name
1024:           f9x_module.record_location @top_level
1025: 
1026:           #
1027:           # Add provided modules information to @top_level comment
1028:           #
1029:           provided_modules = []
1030:           provided_mes_line_num = nil
1031:           top_level_comment_lines = []
1032:           line_num = 0
1033:           @top_level.comment.split("\n").each{|line|
1034:             top_level_comment_lines << line
1035:             line_num += 1
1036:             next if line.empty?
1037:             if !provided_mes_line_num && /^\s?#{PROVIDED_MODULES_MES}/ =~ line
1038:               provided_mes_line_num = line_num
1039:               next
1040:             end
1041:             if provided_mes_line_num
1042:               if /^\s?\*\s+<b>(\w+)<\/b>/ =~ line
1043:                 provided_modules << $1
1044:               else
1045:                 provided_mes_line_num = nil
1046:               end
1047:             end
1048:           }
1049:           line_num = 0
1050:           if provided_mes_line_num
1051:             top_level_comment_lines.collect!{ |line|
1052:               line_num += 1
1053:               if line_num < provided_mes_line_num
1054:                 line
1055:               else
1056:                 nil
1057:               end
1058:             }
1059:             top_level_comment_lines.delete_if{|line| !line }
1060:           end
1061:           top_level_comment_lines << "\n" + PROVIDED_MODULES_MES + "."
1062:           if provided_mes_line_num
1063:             top_level_comment_lines[-1].sub!(/\.$/, '')
1064:             top_level_comment_lines[-1] << "s."
1065:           end
1066:           provided_modules.each{ |mod|
1067:             top_level_comment_lines << "* <b>" + mod + "</b>"
1068:           }
1069:           top_level_comment_lines << "* <b>" + module_name + "</b>"
1070:           @top_level.comment = top_level_comment_lines.join("\n")
1071: 
1072:           #
1073:           # Information about the module is parsed
1074:           #
1075:           f9x_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) +
1076:             "\n" + module_trailing : module_trailing + "\n" +
1077:             find_comments(module_code.sub(/^.*$\n/i, ''))
1078:           f9x_module.comment = f9x_comment
1079:           parse_program_or_module(f9x_module, module_code)
1080: 
1081:           TopLevel.all_files.each do |name, toplevel|
1082:             if toplevel.include_includes?(module_name, @options_ignore_case)
1083:               if !toplevel.include_requires?(@file_name, @options_ignore_case)
1084:                 toplevel.add_require(Require.new(@file_name, ""))
1085:               end
1086:             end
1087:             toplevel.each_classmodule{|m|
1088:               if m.include_includes?(module_name, @options_ignore_case)
1089:                 if !m.include_requires?(@file_name, @options_ignore_case)
1090:                   m.add_require(Require.new(@file_name, ""))
1091:                 end
1092:               end
1093:             }
1094:           end
1095: 
1096:           namelist_comment = 
1097:             find_namelists(f9x_module, before_contains(module_code))
1098:           f9x_module.comment << namelist_comment if namelist_comment
1099: 
1100:         elsif block_searching_flag == :program
1101:           program_name = module_program_name
1102:           program_name = "main_program" if program_name.empty?
1103:           program_code = module_program_code
1104:           program_trailing = module_program_trailing
1105:           program_priority, program_trailing = doc_priority_from_trailing(program_trailing)
1106: 
1107:           program_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) + 
1108:             "\n" + program_trailing : program_trailing + "\n" + 
1109:             find_comments(program_code.sub(/^.*$\n/i, ''))
1110: 
1111:           progress "p"
1112:           @stats.num_methods += 1
1113:           f9x_mainprogram = AnyMethod.new("main_program", program_name)
1114:           f9x_mainprogram.singleton = false
1115:           f9x_mainprogram.comment = "<b><em> Main Program </em></b> :: <tt></tt>\n"
1116:           f9x_mainprogram.comment << program_comment
1117:           f9x_mainprogram.params = ""
1118:           f9x_mainprogram.set_priority(program_priority) if program_priority
1119: 
1120:           # For output source code
1121:           f9x_mainprogram.start_collecting_tokens
1122:           f9x_mainprogram.add_token Token.new(1,1).set_text(program_code)
1123: 
1124:           @top_level.add_method f9x_mainprogram
1125:           parse_program_or_module(@top_level, program_code, :private)
1126: 
1127:           namelist_comment = find_namelists(f9x_mainprogram, program_code)
1128:           f9x_mainprogram.comment << namelist_comment if namelist_comment
1129:         end
1130: 
1131:         # next loop to search next block
1132:         level_depth = 0
1133:         block_searching_flag = false
1134:         block_searching_lines = []
1135:         pre_comment = []
1136:         next false
1137:       }
1138: 
1139:       remaining_lines.delete_if{ |line|
1140:         line == false
1141:       }
1142: 
1143:       # External subprograms and functions are parsed
1144:       #
1145:       # 単一のファイル内において program や module に格納されない,
1146:       # 外部サブルーチン, 外部関数部分の解析.
1147:       #
1148:       parse_program_or_module(@top_level, remaining_lines.join("\n"),
1149:                               :public, true)
1150: 
1151:       @top_level
1152:     end

Semicolons are replaced to line feed.

[Source]

      # File parsers/parse_f95.rb, line 2449
2449:     def semicolon_to_linefeed(text)
2450:       return "" unless text
2451:       lines = text.split("\n")
2452:       lines.collect!{ |line|
2453:         indent_space = ""
2454:         if line =~ /^(\s+)/
2455:           indent_space = $1
2456:         end
2457:         words = line.split("")
2458:         commentout = false
2459:         squote = false ; dquote = false
2460:         words.collect! { |char|
2461:           if !(squote) && !(dquote) && !(commentout)
2462:             case char
2463:             when "!" ; commentout = true ; next char
2464:             when "\""; dquote = true     ; next char
2465:             when "\'"; squote = true     ; next char
2466:             when ";" ;                     "\n"+indent_space
2467:             else next char
2468:             end
2469:           elsif commentout
2470:             next char
2471:           elsif squote
2472:             case char
2473:             when "\'"; squote = false ; next char
2474:             else next char
2475:             end
2476:           elsif dquote
2477:             case char
2478:             when "\""; dquote = false ; next char
2479:             else next char
2480:             end
2481:           end
2482:         }
2483:         words.join("")
2484:       }
2485:       return lines.join("\n")
2486:     end

Set visibility

"subname" element of "visibility_info" is deleted.

[Source]

      # File parsers/parse_f95.rb, line 2204
2204:     def set_visibility(container, subname, visibility_default, visibility_info)
2205:       return unless container || subname || visibility_default || visibility_info
2206:       not_found = true
2207:       visibility_info.collect!{ |info|
2208:         if info["name"] == subname ||
2209:             @options_ignore_case && info["name"].upcase == subname.upcase
2210:           if info["file_or_module"].name == container.name
2211:             container.set_visibility_for([subname], info["visibility"])
2212:             info["entity_is_discovered"] = true
2213:             not_found = false
2214:           end
2215:         end
2216:         info
2217:       }
2218:       if not_found
2219:         return container.set_visibility_for([subname], visibility_default)
2220:       else
2221:         return container
2222:       end
2223:     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 2324
2324:     def united_to_one_line(f90src, delete_space=true)
2325:       return "" unless f90src
2326:       lines = f90src.split("\n")
2327:       previous_continuing = false
2328:       now_continuing = false
2329:       body = ""
2330:       squote = false ; dquote = false
2331:       lines.each{ |line|
2332:         words = line.split("")
2333:         next if words.empty? && previous_continuing
2334:         commentout = false
2335:         brank_flag = true ; brank_char = ""
2336:         ignore = false
2337:         words.collect! { |char|
2338:           if previous_continuing && brank_flag
2339:             now_continuing = true
2340:             ignore         = true
2341:             case char
2342:             when "!"                       ; break
2343:             when " " ; brank_char << char  ; next ""
2344:             when "&"
2345:               brank_flag = false
2346:               now_continuing = false
2347:               next ""
2348:             else 
2349:               brank_flag     = false
2350:               now_continuing = false
2351:               ignore         = false
2352:               next brank_char + char
2353:             end
2354:           end
2355:           ignore = false
2356: 
2357:           if now_continuing && !(squote) && !(dquote)
2358:             next ""
2359:           elsif !(squote) && !(dquote) && !(commentout)
2360:             case char
2361:             when "!" ; commentout = true     ; next char
2362:             when "\""; dquote = true         ; next char
2363:             when "\'"; squote = true         ; next char
2364:             when "&" ; now_continuing = true ; next ""
2365:             else next char
2366:             end
2367:           elsif commentout
2368:             next char
2369:           elsif squote
2370:             case char
2371:             when "\'"; squote = false ; now_continuing = false ; next char
2372:             when "&" ; now_continuing = true ; next ""
2373:             else next char
2374:             end
2375:           elsif dquote
2376:             case char
2377:             when "\""; dquote = false ; now_continuing = false ; next char
2378:             when "&" ; now_continuing = true ; next ""
2379:             else next char
2380:             end
2381:           end
2382:         }
2383:         if !ignore && !previous_continuing || !brank_flag
2384:           if previous_continuing
2385:             if delete_space
2386:               joined_words = words.join("")
2387:               body = body.rstrip + " " + joined_words.lstrip
2388:             else
2389:               body << words.join("")
2390:             end
2391:           else
2392:             body << "\n" + words.join("")
2393:           end
2394:         end
2395:         previous_continuing = now_continuing ? true : false
2396:         now_continuing = false
2397:       }
2398:       return body
2399:     end

[Validate]