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

Public Class methods

prepare to parse a Fortran 95 file

[Source]

     # File parsers/parse_f95.rb, line 696
696:     def initialize(top_level, file_name, body, options, stats)
697:       @body = body
698:       @stats = stats
699:       @file_name  = file_name
700:       @options = options
701:       @top_level = top_level
702:       @progress = $stderr unless options.quiet
703: 
704:       begin
705:         @options_ignore_case = options.ignore_case
706:       rescue
707:         @options_ignore_case = true
708:       end
709: 
710:     end

Public Instance methods

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

[Source]

      # File parsers/parse_f95.rb, line 1611
1611:     def before_contains(code)
1612:       level_depth = 0
1613:       before_contains_lines = []
1614:       before_contains_code = nil
1615:       before_contains_flag = nil
1616:       code.split("\n").each{ |line|
1617:         if !before_contains_flag
1618:           if line =~ /^\s*?module\s+\w+\s*?(!.*?)?$/i
1619:             before_contains_flag = true
1620:           end
1621:         else
1622:           break if line =~ /^\s*?contains\s*?(!.*?)?$/i
1623:           level_depth += 1 if block_start?(line)
1624:           level_depth -= 1 if block_end?(line)
1625:           break if level_depth < 0
1626:           before_contains_lines << line
1627:         end
1628: 
1629:       }
1630:       before_contains_code = before_contains_lines.join("\n")
1631:       if before_contains_code
1632:         before_contains_code.gsub!(/^\s*?interface\s+.*?\s+end\s+interface.*?$/im, "")
1633:         before_contains_code.gsub!(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
1634:       end
1635: 
1636:       before_contains_code
1637:     end

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

[Source]

      # File parsers/parse_f95.rb, line 2278
2278:     def block_end?(line)
2279:       return nil if !line
2280: 
2281:       if line =~ /^\s*?end\s*?(!.*?)?$/i                 ||
2282:           line =~ /^\s*?end\s+module(\s+\w+)?\s*?(!.*?)?$/i       ||
2283:           line =~ /^\s*?end\s+program(\s+\w+)?\s*?(!.*?)?$/i      ||
2284:           line =~ /^\s*?end\s+block\s+data(\s+\w+)?\s*?(!.*?)?$/i  ||
2285:           line =~ /^\s*?end\s+subroutine(\s+\w+)?\s*?(!.*?)?$/i   ||
2286:           line =~ /^\s*?end\s+function(\s+\w+)?\s*?(!.*?)?$/i
2287:         return true
2288:       end
2289: 
2290:       return nil
2291:     end

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

[Source]

      # File parsers/parse_f95.rb, line 2242
2242:     def block_start?(line)
2243:       return nil if !line
2244: 
2245:       if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i    ||
2246:           line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i  ||
2247:           line =~ /^\s*?block\s+data(\s+\w+)?\s*?(!.*?)?$/i     ||
2248:           line =~ \
2249:                   /^\s*?
2250:                    (recursive|pure|elemental)?\s*?
2251:                    subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
2252:                   /ix ||
2253:           line =~ \
2254:                   /^\s*?
2255:                    (recursive|pure|elemental)?\s*?
2256:                    (
2257:                        character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
2258:                      | type\s*?\([\w\s]+?\)\s+
2259:                      | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
2260:                      | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
2261:                      | double\s+precision\s+
2262:                      | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
2263:                      | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
2264:                    )?
2265:                    function\s+(\w+)\s*?
2266:                    (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
2267:                   /ix
2268:         return true
2269:       end
2270: 
2271:       return nil
2272:     end

Check external aliases

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

[Source]

      # File parsers/parse_f95.rb, line 1998
1998:     def check_external_aliases(subname, params, comment, test=nil)
1999:       @@external_aliases.each{ |alias_item|
2000:         if subname == alias_item["old_name"] ||
2001:                     subname.upcase == alias_item["old_name"].upcase &&
2002:                             @options_ignore_case
2003: 
2004:           new_meth = initialize_external_method(alias_item["new_name"], 
2005:                                                 subname, params, @file_name, 
2006:                                                 comment)
2007:           new_meth.visibility = alias_item["visibility"]
2008: 
2009:           progress "e"
2010:           @stats.num_methods += 1
2011:           alias_item["file_or_module"].add_method(new_meth)
2012: 
2013:           if !alias_item["file_or_module"].include_requires?(@file_name, @options_ignore_case)
2014:             alias_item["file_or_module"].add_require(Require.new(@file_name, ""))
2015:           end
2016:         end
2017:       }
2018:     end

Check public_methods

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

[Source]

      # File parsers/parse_f95.rb, line 2028
2028:     def check_public_methods(method, parent)
2029:       return if !method || !parent
2030:       @@public_methods.each{ |alias_item|
2031:         parent_is_used_module = nil
2032:         alias_item["used_modules"].each{ |used_module|
2033:           if used_module == parent ||
2034:               used_module.upcase == parent.upcase &&
2035:               @options_ignore_case
2036:             parent_is_used_module = true
2037:           end
2038:         }
2039:         next if !parent_is_used_module
2040: 
2041:         if method.name == alias_item["name"] ||
2042:             method.name.upcase == alias_item["name"].upcase &&
2043:             @options_ignore_case
2044: 
2045:           new_meth = initialize_public_method(method, parent)
2046:           if alias_item["local_name"]
2047:             new_meth.name = alias_item["local_name"]
2048:           end
2049: 
2050:           progress "e"
2051:           @stats.num_methods += 1
2052:           alias_item["file_or_module"].add_method new_meth
2053:         end
2054:       }
2055:     end

Collect comment for file entity

[Source]

      # File parsers/parse_f95.rb, line 1642
1642:     def collect_first_comment(body)
1643:       comment = ""
1644:       not_comment = ""
1645:       comment_start = false
1646:       comment_end   = false
1647:       body.split("\n").each{ |line|
1648:         if comment_end
1649:           not_comment << line
1650:           not_comment << "\n"
1651:         elsif /^\s*?!\s?(.*)$/i =~ line
1652:           comment_start = true
1653:           comment << $1
1654:           comment << "\n"
1655:         elsif /^\s*?$/i =~ line
1656:           comment_end = true if comment_start && COMMENTS_ARE_UPPER
1657:         else
1658:           comment_end = true
1659:           not_comment << line
1660:           not_comment << "\n"
1661:         end
1662:       }
1663:       return comment, not_comment
1664:     end

Comment out checker

[Source]

      # File parsers/parse_f95.rb, line 2169
2169:     def comment_out?(line)
2170:       return nil unless line
2171:       commentout = false
2172:       squote = false ; dquote = false
2173:       line.split("").each { |char|
2174:         if !(squote) && !(dquote)
2175:           case char
2176:           when "!" ; commentout = true ; break
2177:           when "\""; dquote = true
2178:           when "\'"; squote = true
2179:           else next
2180:           end
2181:         elsif squote
2182:           case char
2183:           when "\'"; squote = false
2184:           else next
2185:           end
2186:         elsif dquote
2187:           case char
2188:           when "\""; dquote = false
2189:           else next
2190:           end
2191:         end
2192:       }
2193:       return commentout
2194:     end

Continuous line checker

[Source]

      # File parsers/parse_f95.rb, line 2155
2155:     def continuous_line?(line)
2156:       continuous = false
2157:       if /&\s*?(!.*)?$/ =~ line
2158:         continuous = true
2159:         if comment_out?($~.pre_match)
2160:           continuous = false
2161:         end
2162:       end
2163:       return continuous
2164:     end

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

[Source]

      # File parsers/parse_f95.rb, line 2414
2414:     def definition_info(text)
2415:       return nil unless text
2416:       lines = "#{text}"
2417:       defs = Array.new
2418:       comment = ""
2419:       trailing_comment = ""
2420:       under_comment_valid = false
2421:       lines.split("\n").each{ |line|
2422:         if /^\s*?!\s?(.*)/ =~ line
2423:           if COMMENTS_ARE_UPPER
2424:             comment << remove_header_marker($1)
2425:             comment << "\n"
2426:           elsif defs[-1] && under_comment_valid
2427:             defs[-1].comment << "\n"
2428:             defs[-1].comment << remove_header_marker($1)
2429:           end
2430:           next
2431:         elsif /^\s*?$/ =~ line
2432:           comment = ""
2433:           under_comment_valid = false
2434:           next
2435:         end
2436:         type = ""
2437:         characters = ""
2438:         if line =~ /^\s*?
2439:                     (
2440:                         character\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2441:                       | type\s*?\([\w\s]+?\)[\s\,]*
2442:                       | integer\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2443:                       | real\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2444:                       | double\s+precision[\s\,]*
2445:                       | logical\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2446:                       | complex\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2447:                     )
2448:                     (.*?::)?
2449:                     (.+)$
2450:                    /ix
2451:           characters = $8
2452:           type = $1
2453:           type << $7.gsub(/::/, '').gsub(/^\s*?\,/, '') if $7
2454:         else
2455:           under_comment_valid = false
2456:           next
2457:         end
2458:         squote = false ; dquote = false ; bracket = 0
2459:         iniflag = false; commentflag = false
2460:         varname = "" ; arraysuffix = "" ; inivalue = ""
2461:         start_pos = defs.size
2462:         characters.split("").each { |char|
2463:           if !(squote) && !(dquote) && bracket <= 0 && !(iniflag) && !(commentflag)
2464:             case char
2465:             when "!" ; commentflag = true
2466:             when "(" ; bracket += 1       ; arraysuffix = char
2467:             when "\""; dquote = true
2468:             when "\'"; squote = true
2469:             when "=" ; iniflag = true     ; inivalue << char
2470:             when ","
2471:               defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2472:               varname = "" ; arraysuffix = "" ; inivalue = ""
2473:               under_comment_valid = true
2474:             when " " ; next
2475:             else     ; varname << char
2476:             end
2477:           elsif commentflag
2478:             comment << remove_header_marker(char)
2479:             trailing_comment << remove_header_marker(char)
2480:           elsif iniflag
2481:             if dquote
2482:               case char
2483:               when "\"" ; dquote = false ; inivalue << char
2484:               else      ; inivalue << char
2485:               end
2486:             elsif squote
2487:               case char
2488:               when "\'" ; squote = false ; inivalue << char
2489:               else      ; inivalue << char
2490:               end
2491:             elsif bracket > 0
2492:               case char
2493:               when "(" ; bracket += 1 ; inivalue << char
2494:               when ")" ; bracket -= 1 ; inivalue << char
2495:               else     ; inivalue << char
2496:               end
2497:             else
2498:               case char
2499:               when ","
2500:                 defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2501:                 varname = "" ; arraysuffix = "" ; inivalue = ""
2502:                 iniflag = false
2503:                 under_comment_valid = true
2504:               when "(" ; bracket += 1 ; inivalue << char
2505:               when "\""; dquote = true  ; inivalue << char
2506:               when "\'"; squote = true  ; inivalue << char
2507:               when "!" ; commentflag = true
2508:               else     ; inivalue << char
2509:               end
2510:             end
2511:           elsif !(squote) && !(dquote) && bracket > 0
2512:             case char
2513:             when "(" ; bracket += 1 ; arraysuffix << char
2514:             when ")" ; bracket -= 1 ; arraysuffix << char
2515:             else     ; arraysuffix << char
2516:             end
2517:           elsif squote
2518:             case char
2519:             when "\'"; squote = false ; inivalue << char
2520:             else     ; inivalue << char
2521:             end
2522:           elsif dquote
2523:             case char
2524:             when "\""; dquote = false ; inivalue << char
2525:             else     ; inivalue << char
2526:             end
2527:           end
2528:         }
2529:         defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2530:         if trailing_comment =~ /^:nodoc:/
2531:           defs[start_pos..-1].collect!{ |defitem|
2532:             defitem.nodoc = true
2533:           }
2534:         end
2535:         varname = "" ; arraysuffix = "" ; inivalue = ""
2536:         comment = ""
2537:         under_comment_valid = true
2538:         trailing_comment = ""
2539:       }
2540:       return defs
2541:     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 1673
1673:     def find_arguments(args, text, all=nil, indent=nil, modified_params=nil)
1674:       return unless args || all
1675:       indent = "" unless indent
1676:       args = ["all"] if all
1677:       params = "" if modified_params
1678:       comma = ""
1679:       return unless text
1680:       args_rdocforms = "\n"
1681:       remaining_lines = "#{text}"
1682:       definitions = definition_info(remaining_lines)
1683:       args.each{ |arg|
1684:         arg.strip!
1685:         arg.chomp!
1686:         definitions.each { |defitem|
1687:           if arg == defitem.varname.strip.chomp || all
1688:             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"
1689:             if !defitem.comment.chomp.strip.empty?
1690:               comment = ""
1691:               defitem.comment.split("\n").each{ |line|
1692:                 comment << "       " + line + "\n"
1693:               }
1694:               args_rdocforms << "\n\#{indent}   <tt></tt> ::\n\#{indent}       <tt></tt>\n\#{indent}       \#{comment.chomp.strip}\n"
1695:             end
1696: 
1697:             if modified_params
1698:               if defitem.include_attr?("optional")
1699:                 params << "#{comma}[#{arg}]"
1700:               else
1701:                 params << "#{comma}#{arg}"
1702:               end
1703:               comma = ", "
1704:             end
1705:           end
1706:         }
1707:       }
1708:       if modified_params
1709:         return args_rdocforms, params
1710:       else
1711:         return args_rdocforms
1712:       end
1713:     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 1816
1816:     def find_comments text
1817:       return "" unless text
1818:       lines = text.split("\n")
1819:       lines.reverse! if COMMENTS_ARE_UPPER
1820:       comment_block = Array.new
1821:       lines.each do |line|
1822:         break if line =~ /^\s*?\w/ || line =~ /^\s*?$/
1823:         if COMMENTS_ARE_UPPER
1824:           comment_block.unshift line.sub(/^\s*?!\s?/,"")
1825:         else
1826:           comment_block.push line.sub(/^\s*?!\s?/,"")
1827:         end
1828:       end
1829:       nice_lines = comment_block.join("\n").split "\n\s*?\n"
1830:       nice_lines[0] ||= ""
1831:       nice_lines.shift
1832:     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 1731
1731:     def find_namelists(container, text, before_contains=nil)
1732:       return nil if !text
1733:       top_level = find_toplevel(container)
1734: 
1735:       if text =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)(!.*?)?$/i
1736:         if top_level.include_includes?(NAMELIST_REPOSITORY_NAME)
1737:           namelist_module = 
1738:             top_level.find_module_named(NAMELIST_REPOSITORY_NAME)
1739:         else
1740:           namelist_module = 
1741:             top_level.add_module NormalClass, NAMELIST_REPOSITORY_NAME
1742:           namelist_module.record_location top_level
1743:           namelist_module.comment = "This is not a module but a repository of NAMELIST group names declared\nin all Fortran 90/95 files\n"
1744:         end
1745:       else
1746:         return ""
1747:       end
1748: 
1749:       nml_group_name_lists = []
1750:       lines = "#{text}"
1751:       before_contains = "" if !before_contains
1752:       while lines =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)(!.*?)?$/i
1753:         lines = $~.post_match
1754:         pre_match = $~.pre_match ; post_match = $~.post_match
1755:         nml_group_name = $1
1756:         trailing_comment = $3 || ""
1757:         nml_vars_list  = $2.split(",")
1758:         nml_comment = COMMENTS_ARE_UPPER ? 
1759:             find_comments(pre_match.sub(/\n$/, '')) :
1760:             find_comments(trailing_comment + post_match)
1761:         if lines.split("\n")[0] =~ /^\//i
1762:           lines = "namelist " + lines
1763:         end
1764: 
1765:         nml_meth = AnyMethod.new("NAMELIST", nml_group_name)
1766:         nml_meth.singleton = false
1767:         nml_meth.params    = "( " + nml_vars_list.join(", ") + " )"
1768:         nml_meth.comment   = "<b><em> NAMELIST </em></b> :: <tt></tt>\n"
1769:         nml_meth.comment   << find_arguments(nml_vars_list, "#{text}" + "\n" + before_contains)
1770:         nml_meth.comment   << "\n" + nml_comment if nml_comment
1771:         if container.parent.parent
1772:           parent_object = container.parent.name
1773:         else
1774:           parent_object = container.parent.file_relative_name
1775:         end
1776:         nml_meth.comment   << "\n\nThis namelist group name is input/output in "
1777:         nml_meth.comment   << parent_object + "#" + container.name
1778: 
1779:         progress "n"
1780:         @stats.num_methods += 1
1781:         namelist_module.add_method nml_meth
1782: 
1783:         nml_group_name_lists << NAMELIST_REPOSITORY_NAME + "#" + nml_group_name
1784:       end
1785: 
1786:       if !nml_group_name_lists.empty?
1787:         comments_in_procedures = "\n\nThis procedure input/output "
1788:         comments_in_procedures << nml_group_name_lists.join(", ") + " . "
1789:       else
1790:         comments_in_procedures = ""
1791:       end
1792: 
1793:       comments_in_procedures
1794:     end

Return toplevel class of container

[Source]

      # File parsers/parse_f95.rb, line 1803
1803:     def find_toplevel(container)
1804:       top_level = container
1805:       while top_level.parent
1806:         top_level = top_level.parent
1807:       end
1808:       top_level
1809:     end

Find visibility

[Source]

      # File parsers/parse_f95.rb, line 1979
1979:     def find_visibility(container, subname, visibility_info)
1980:       return nil if !subname || !visibility_info
1981:       visibility_info.each{ |info|
1982:         if info["name"] == subname ||
1983:             @options_ignore_case && info["name"].upcase == subname.upcase
1984:           if info["parent"] == container.name
1985:             return info["visibility"]
1986:           end
1987:         end
1988:       }
1989:       return nil
1990:     end

Create method for external alias

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

[Source]

      # File parsers/parse_f95.rb, line 1861
1861:     def initialize_external_method(new, old, params, file, comment, token=nil,
1862:                                    internal=nil, nolink=nil)
1863:       return nil unless new || old
1864: 
1865:       if internal
1866:         external_alias_header = "#{INTERNAL_ALIAS_MES} "
1867:         external_alias_text   = external_alias_header + old 
1868:       elsif file
1869:         external_alias_header = "#{EXTERNAL_ALIAS_MES} "
1870:         external_alias_text   = external_alias_header + file + "#" + old
1871:       else
1872:         return nil
1873:       end
1874:       external_meth = AnyMethod.new(external_alias_text, new)
1875:       external_meth.singleton    = false
1876:       external_meth.params       = params
1877:       external_comment = remove_trailing_alias(comment) + "\n\n" if comment
1878:       external_meth.comment = external_comment || ""
1879:       if nolink && token
1880:         external_meth.start_collecting_tokens
1881:         external_meth.add_token Token.new(1,1).set_text(token)
1882:       else
1883:         external_meth.comment << external_alias_text
1884:       end
1885: 
1886:       return external_meth
1887:     end

Create method for internal alias

[Source]

      # File parsers/parse_f95.rb, line 1844
1844:     def initialize_public_method(method, parent)
1845:       return if !method || !parent
1846: 
1847:       new_meth = AnyMethod.new("External Alias for module", method.name)
1848:       new_meth.singleton    = method.singleton
1849:       new_meth.params       = method.params.clone
1850:       new_meth.comment      = remove_trailing_alias(method.comment.clone)
1851:       new_meth.comment      << "\n\n#{EXTERNAL_ALIAS_MES} #{parent.strip.chomp}\##{method.name}"
1852: 
1853:       return new_meth
1854:     end

[Source]

      # File parsers/parse_f95.rb, line 937
 937:     def parse_program_or_module(container, code,
 938:                                 visibility=:public, external=nil)
 939:       return unless container
 940:       return unless code
 941:       remaining_lines = code.split("\n")
 942:       remaining_code = "#{code}"
 943: 
 944:       #
 945:       # Parse variables before "contains" in module
 946:       #
 947:       # namelist 変数の定義に使われたり, これ自体が定数, 変数
 948:       # 提供されるのに利用される. (変数や定数として利用される場合,
 949:       # これもメソッドとして提供する.
 950:       #
 951:       before_contains_code = before_contains(remaining_code)
 952: 
 953:       #
 954:       # Parse global "use"
 955:       #
 956:       use_check_code = "#{before_contains_code}"
 957:       cascaded_modules_list = []
 958:       while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i
 959:         use_check_code = $~.pre_match
 960:         use_check_code << $~.post_match
 961:         used_mod_name = $1.strip.chomp
 962:         used_list = $2 || ""
 963:         used_trailing = $3 || ""
 964:         next if used_trailing =~ /!:nodoc:/
 965:         if !container.include_includes?(used_mod_name, @options_ignore_case)
 966:           progress "."
 967:           container.add_include Include.new(used_mod_name, "")
 968:         end
 969:         if ! (used_list =~ /\,\s*?only\s*?:/i )
 970:           cascaded_modules_list << "\#" + used_mod_name
 971:         end
 972:       end
 973: 
 974:       #
 975:       # Parse public and private, and store information.
 976:       # This information is used when "add_method" and
 977:       # "set_visibility_for" are called.
 978:       #
 979:       visibility_default, visibility_info = 
 980:                 parse_visibility(remaining_lines.join("\n"), visibility, container)
 981:       @@public_methods.concat visibility_info
 982:       if visibility_default == :public
 983:         if !cascaded_modules_list.empty?
 984:           cascaded_modules = 
 985:             Attr.new("Cascaded Modules",
 986:                      "Imported modules all of whose components are published again",
 987:                      "",
 988:                      cascaded_modules_list.join(", "))
 989:           container.add_attribute(cascaded_modules)
 990:         end
 991:       end
 992: 
 993:       #
 994:       # Check rename elements
 995:       #
 996:       use_check_code = "#{before_contains_code}"
 997:       while use_check_code =~ /^\s*?use\s+(\w+)\s*?\,(.+)$/i
 998:         use_check_code = $~.pre_match
 999:         use_check_code << $~.post_match
1000:         used_mod_name = $1.strip.chomp
1001:         used_elements = $2.sub(/\s*?only\s*?:\s*?/i, '')
1002:         used_elements.split(",").each{ |used|
1003:           if /\s*?(\w+)\s*?=>\s*?(\w+)\s*?/ =~ used
1004:             local = $1
1005:             org = $2
1006:             @@public_methods.collect!{ |pub_meth|
1007:               if local == pub_meth["name"] ||
1008:                   local.upcase == pub_meth["name"].upcase &&
1009:                   @options_ignore_case
1010:                 pub_meth["name"] = org
1011:                 pub_meth["local_name"] = local
1012:               end
1013:               pub_meth
1014:             }
1015:           end
1016:         }
1017:       end
1018: 
1019:       #
1020:       # Parse private "use"
1021:       #
1022:       use_check_code = remaining_lines.join("\n")
1023:       while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i
1024:         use_check_code = $~.pre_match
1025:         use_check_code << $~.post_match
1026:         used_mod_name = $1.strip.chomp
1027:         used_trailing = $3 || ""
1028:         next if used_trailing =~ /!:nodoc:/
1029:         if !container.include_includes?(used_mod_name, @options_ignore_case)
1030:           progress "."
1031:           container.add_include Include.new(used_mod_name, "")
1032:         end
1033:       end
1034: 
1035:       container.each_includes{ |inc|
1036:         TopLevel.all_files.each do |name, toplevel|
1037:           indicated_mod = toplevel.find_symbol(inc.name,
1038:                                                nil, @options_ignore_case)
1039:           if indicated_mod
1040:             indicated_name = indicated_mod.parent.file_relative_name
1041:             if !container.include_requires?(indicated_name, @options_ignore_case)
1042:               container.add_require(Require.new(indicated_name, ""))
1043:             end
1044:             break
1045:           end
1046:         end
1047:       }
1048: 
1049:       #
1050:       # Parse derived types definitions
1051:       #
1052:       derived_types_comment = ""
1053:       remaining_code = remaining_lines.join("\n")
1054:       while remaining_code =~ /^\s*?
1055:                                     type[\s\,]+(public|private)?\s*?(::)?\s*?
1056:                                     (\w+)\s*?(!.*?)?$
1057:                                     (.*?)
1058:                                     ^\s*?end\s+type.*?$
1059:                               /imx
1060:         remaining_code = $~.pre_match
1061:         remaining_code << $~.post_match
1062:         typename = $3.chomp.strip
1063:         type_elements = $5 || ""
1064:         type_code = remove_empty_head_lines($&)
1065:         type_trailing = find_comments($4)
1066:         next if type_trailing =~ /^:nodoc:/
1067:         type_visibility = $1
1068:         type_comment = COMMENTS_ARE_UPPER ? 
1069:           find_comments($~.pre_match) + "\n" + type_trailing :
1070:             type_trailing + "\n" + find_comments(type_code.sub(/^.*$\n/i, ''))
1071:         type_element_visibility_public = true
1072:         type_code.split("\n").each{ |line|
1073:           if /^\s*?private\s*?$/ =~ line
1074:             type_element_visibility_public = nil
1075:             break
1076:           end
1077:         } if type_code
1078: 
1079:         args_comment = ""
1080:         type_args_info = nil
1081: 
1082:         if @options.show_all
1083:           args_comment = find_arguments(nil, type_code, true)
1084:         else
1085:           type_public_args_list = []
1086:           type_args_info = definition_info(type_code)
1087:           type_args_info.each{ |arg|
1088:             arg_is_public = type_element_visibility_public
1089:             arg_is_public = true if arg.include_attr?("public")
1090:             arg_is_public = nil if arg.include_attr?("private")
1091:             type_public_args_list << arg.varname if arg_is_public
1092:           }
1093:           args_comment = find_arguments(type_public_args_list, type_code)
1094:         end
1095: 
1096:         type = AnyMethod.new("type #{typename}", typename)
1097:         type.singleton = false
1098:         type.params = ""
1099:         type.comment = "<b><em> Derived Type </em></b> :: <tt></tt>\n"
1100:         type.comment << args_comment if args_comment
1101:         type.comment << type_comment if type_comment
1102:         progress "t"
1103:         @stats.num_methods += 1
1104:         container.add_method type
1105: 
1106:         set_visibility(container, typename, visibility_default, @@public_methods)
1107: 
1108:         if type_visibility
1109:           type_visibility.gsub!(/\s/,'')
1110:           type_visibility.gsub!(/\,/,'')
1111:           type_visibility.gsub!(/:/,'')
1112:           type_visibility.downcase!
1113:           if type_visibility == "public"
1114:             container.set_visibility_for([typename], :public)
1115:           elsif type_visibility == "private"
1116:             container.set_visibility_for([typename], :private)
1117:           end
1118:         end
1119: 
1120:         check_public_methods(type, container.name)
1121: 
1122:         if @options.show_all
1123:           derived_types_comment << ", " unless derived_types_comment.empty?
1124:           derived_types_comment << typename
1125:         else
1126:           if type.visibility == :public
1127:           derived_types_comment << ", " unless derived_types_comment.empty?
1128:           derived_types_comment << typename
1129:           end
1130:         end
1131: 
1132:       end
1133: 
1134:       if !derived_types_comment.empty?
1135:         derived_types_table = 
1136:           Attr.new("Derived Types", "Derived_Types", "", 
1137:                    derived_types_comment)
1138:         container.add_attribute(derived_types_table)
1139:       end
1140: 
1141:       #
1142:       # move interface scope
1143:       #
1144:       interface_code = ""
1145:       while remaining_code =~ /^\s*?
1146:                                    interface(
1147:                                               \s+\w+                      |
1148:                                               \s+operator\s*?\(.*?\)       |
1149:                                               \s+assignment\s*?\(\s*?=\s*?\)
1150:                                             )?\s*?$
1151:                                    (.*?)
1152:                                    ^\s*?end\s+interface.*?$
1153:                               /imx
1154:         interface_code << remove_empty_head_lines($&) + "\n"
1155:         remaining_code = $~.pre_match
1156:         remaining_code << $~.post_match
1157:       end
1158: 
1159:       #
1160:       # Parse global constants or variables in modules
1161:       #
1162:       const_var_defs = definition_info(before_contains_code)
1163:       const_var_defs.each{|defitem|
1164:         next if defitem.nodoc
1165:         const_or_var_type = "Variable"
1166:         const_or_var_progress = "v"
1167:         if defitem.include_attr?("parameter")
1168:           const_or_var_type = "Constant"
1169:           const_or_var_progress = "c"
1170:         end
1171:         const_or_var = AnyMethod.new(const_or_var_type, defitem.varname)
1172:         const_or_var.singleton = false
1173:         const_or_var.params = ""
1174:         self_comment = find_arguments([defitem.varname], before_contains_code)
1175:         const_or_var.comment = "<b><em>" + const_or_var_type + "</em></b> :: <tt></tt>\n"
1176:         const_or_var.comment << self_comment if self_comment
1177:         progress const_or_var_progress
1178:         @stats.num_methods += 1
1179:         container.add_method const_or_var
1180: 
1181:         set_visibility(container, defitem.varname, visibility_default, @@public_methods)
1182: 
1183:         if defitem.include_attr?("public")
1184:           container.set_visibility_for([defitem.varname], :public)
1185:         elsif defitem.include_attr?("private")
1186:           container.set_visibility_for([defitem.varname], :private)
1187:         end
1188: 
1189:         check_public_methods(const_or_var, container.name)
1190: 
1191:       } if const_var_defs
1192: 
1193:       remaining_lines = remaining_code.split("\n")
1194: 
1195:       # "subroutine" or "function" parts are parsed (new)
1196:       #
1197:       level_depth = 0
1198:       block_searching_flag = nil
1199:       block_searching_lines = []
1200:       pre_comment = []
1201:       procedure_trailing = ""
1202:       procedure_name = ""
1203:       procedure_params = ""
1204:       procedure_prefix = ""
1205:       procedure_result_arg = ""
1206:       procedure_type = ""
1207:       contains_lines = []
1208:       contains_flag = nil
1209:       remaining_lines.collect!{|line|
1210:         if !block_searching_flag
1211:           # subroutine
1212:           if line =~ /^\s*?
1213:                            (recursive|pure|elemental)?\s*?
1214:                            subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
1215:                      /ix
1216:             block_searching_flag = :subroutine
1217:             block_searching_lines << line
1218: 
1219:             procedure_name = $2.chomp.strip
1220:             procedure_params = $3 || ""
1221:             procedure_prefix = $1 || ""
1222:             procedure_trailing = $4 || "!"
1223:             next false
1224: 
1225:           # function
1226:           elsif line =~ /^\s*?
1227:                          (recursive|pure|elemental)?\s*?
1228:                          (
1229:                              character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1230:                            | type\s*?\([\w\s]+?\)\s+
1231:                            | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1232:                            | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1233:                            | double\s+precision\s+
1234:                            | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1235:                            | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1236:                          )?
1237:                          function\s+(\w+)\s*?
1238:                          (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
1239:                         /ix
1240:             block_searching_flag = :function
1241:             block_searching_lines << line
1242: 
1243:             procedure_prefix = $1 || ""
1244:             procedure_type = $2 ? $2.chomp.strip : nil
1245:             procedure_name = $8.chomp.strip
1246:             procedure_params = $9 || ""
1247:             procedure_result_arg = $11 ? $11.chomp.strip : procedure_name
1248:             procedure_trailing = $12 || "!"
1249:             next false
1250:           elsif line =~ /^\s*?!\s?(.*)/
1251:             pre_comment << line
1252:             next line
1253:           else
1254:             pre_comment = []
1255:             next line
1256:           end
1257:         end
1258:         contains_flag = true if line =~ /^\s*?contains\s*?(!.*?)?$/
1259:         block_searching_lines << line
1260:         contains_lines << line if contains_flag
1261: 
1262:         level_depth += 1 if block_start?(line)
1263:         level_depth -= 1 if block_end?(line)
1264:         if level_depth >= 0
1265:           next false
1266:         end
1267: 
1268:         # "procedure_code" is formatted.
1269:         # ":nodoc:" flag is checked.
1270:         #
1271:         procedure_code = block_searching_lines.join("\n")
1272:         procedure_code = remove_empty_head_lines(procedure_code)
1273:         if procedure_trailing =~ /^!:nodoc:/
1274:           # next loop to search next block
1275:           level_depth = 0
1276:           block_searching_flag = nil
1277:           block_searching_lines = []
1278:           pre_comment = []
1279:           procedure_trailing = ""
1280:           procedure_name = ""
1281:           procedure_params = ""
1282:           procedure_prefix = ""
1283:           procedure_result_arg = ""
1284:           procedure_type = ""
1285:           contains_lines = []
1286:           contains_flag = nil
1287:           next false
1288:         end
1289: 
1290:         # AnyMethod is created, and added to container
1291:         #
1292:         subroutine_function = nil
1293:         if block_searching_flag == :subroutine
1294:           subroutine_prefix   = procedure_prefix
1295:           subroutine_name     = procedure_name
1296:           subroutine_params   = procedure_params
1297:           subroutine_trailing = procedure_trailing
1298:           subroutine_code     = procedure_code
1299: 
1300:           subroutine_comment = COMMENTS_ARE_UPPER ? 
1301:             pre_comment.join("\n") + "\n" + subroutine_trailing : 
1302:               subroutine_trailing + "\n" + subroutine_code.sub(/^.*$\n/i, '')
1303:           subroutine = AnyMethod.new("subroutine", subroutine_name)
1304:           parse_subprogram(subroutine, subroutine_params,
1305:                            subroutine_comment, subroutine_code,
1306:                            before_contains_code, nil, subroutine_prefix)
1307:           progress "s"
1308:           @stats.num_methods += 1
1309:           container.add_method subroutine
1310:           subroutine_function = subroutine
1311: 
1312:           namelist_comment = 
1313:             find_namelists(subroutine, subroutine_code, before_contains_code)
1314:           subroutine.comment << namelist_comment if namelist_comment
1315: 
1316:         elsif block_searching_flag == :function
1317:           function_prefix     = procedure_prefix
1318:           function_type       = procedure_type
1319:           function_name       = procedure_name
1320:           function_params_org = procedure_params
1321:           function_result_arg = procedure_result_arg
1322:           function_trailing   = procedure_trailing
1323:           function_code_org   = procedure_code
1324: 
1325:           function_comment = COMMENTS_ARE_UPPER ?
1326:             pre_comment.join("\n") + "\n" + function_trailing :
1327:               function_trailing + "\n " + function_code_org.sub(/^.*$\n/i, '')
1328: 
1329:           function_code = "#{function_code_org}"
1330:           if function_type
1331:             function_code << "\n" + function_type + " :: " + function_result_arg
1332:           end
1333: 
1334:           function_params =
1335:             function_params_org.sub(/^\(/, "\(#{function_result_arg}, ")
1336: 
1337:           function = AnyMethod.new("function", function_name)
1338:           parse_subprogram(function, function_params,
1339:                            function_comment, function_code,
1340:                            before_contains_code, true, function_prefix)
1341: 
1342:           # Specific modification due to function
1343:           function.params.sub!(/\(\s*?#{function_result_arg}\s*?,\s*?/, "\( ")
1344:           function.params << " result(" + function_result_arg + ")"
1345:           function.start_collecting_tokens
1346:           function.add_token Token.new(1,1).set_text(function_code_org)
1347: 
1348:           progress "f"
1349:           @stats.num_methods += 1
1350:           container.add_method function
1351:           subroutine_function = function
1352: 
1353:           namelist_comment = 
1354:             find_namelists(function, function_code, before_contains_code)
1355:           function.comment << namelist_comment if namelist_comment
1356: 
1357:         end
1358: 
1359:         # The visibility of procedure is specified
1360:         #
1361:         set_visibility(container, procedure_name, 
1362:                        visibility_default, @@public_methods)
1363: 
1364:         # The alias for this procedure from external modules
1365:         #
1366:         check_external_aliases(procedure_name,
1367:                                subroutine_function.params,
1368:                                subroutine_function.comment, subroutine_function) if external
1369:         check_public_methods(subroutine_function, container.name)
1370: 
1371: 
1372:         # contains_lines are parsed as private procedures
1373:         if contains_flag
1374:           parse_program_or_module(container,
1375:                                   contains_lines.join("\n"), :private)
1376:         end
1377: 
1378:         # next loop to search next block
1379:         level_depth = 0
1380:         block_searching_flag = nil
1381:         block_searching_lines = []
1382:         pre_comment = []
1383:         procedure_trailing = ""
1384:         procedure_name = ""
1385:         procedure_params = ""
1386:         procedure_prefix = ""
1387:         procedure_result_arg = ""
1388:         contains_lines = []
1389:         contains_flag = nil
1390:         next false
1391:       } # End of remaining_lines.collect!{|line|
1392: 
1393:       # Array remains_lines is converted to String remains_code again
1394:       #
1395:       remaining_code = remaining_lines.join("\n")
1396: 
1397:       #
1398:       # Parse interface
1399:       #
1400:       interface_scope = false
1401:       generic_name = ""
1402:       interface_code.split("\n").each{ |line|
1403:         if /^\s*?
1404:                  interface(
1405:                             \s+\w+|
1406:                             \s+operator\s*?\(.*?\)|
1407:                             \s+assignment\s*?\(\s*?=\s*?\)
1408:                           )?
1409:                  \s*?(!.*?)?$
1410:            /ix =~ line
1411:           generic_name = $1 ? $1.strip.chomp : nil
1412:           interface_trailing = $2 || "!"
1413:           interface_scope = true
1414:           interface_scope = false if interface_trailing =~ /!:nodoc:/
1415: #          if generic_name =~ /operator\s*?\((.*?)\)/i
1416: #            operator_name = $1
1417: #            if operator_name && !operator_name.empty?
1418: #              generic_name = "#{operator_name}"
1419: #            end
1420: #          end
1421: #          if generic_name =~ /assignment\s*?\((.*?)\)/i
1422: #            assignment_name = $1
1423: #            if assignment_name && !assignment_name.empty?
1424: #              generic_name = "#{assignment_name}"
1425: #            end
1426: #          end
1427:         end
1428:         if /^\s*?end\s+interface/i =~ line
1429:           interface_scope = false
1430:           generic_name = nil
1431:         end
1432:         # internal alias
1433:         if interface_scope && /^\s*?module\s+procedure\s+(.*?)(!.*?)?$/i =~ line
1434:           procedures = $1.strip.chomp
1435:           procedures_trailing = $2 || "!"
1436:           next if procedures_trailing =~ /!:nodoc:/
1437:           procedures.split(",").each{ |proc|
1438:             proc.strip!
1439:             proc.chomp!
1440:             next if generic_name == proc || !generic_name
1441:             old_meth = container.find_symbol(proc, nil, @options_ignore_case)
1442:             next if !old_meth
1443:             nolink = old_meth.visibility == :private ? true : nil
1444:             nolink = nil if @options.show_all
1445:             new_meth = 
1446:                initialize_external_method(generic_name, proc, 
1447:                                           old_meth.params, nil, 
1448:                                           old_meth.comment, 
1449:                                           old_meth.clone.token_stream[0].text, 
1450:                                           true, nolink)
1451:             new_meth.singleton = old_meth.singleton
1452: 
1453:             progress "i"
1454:             @stats.num_methods += 1
1455:             container.add_method new_meth
1456: 
1457:             set_visibility(container, generic_name, visibility_default, @@public_methods)
1458: 
1459:             check_public_methods(new_meth, container.name)
1460: 
1461:           }
1462:         end
1463: 
1464:         # external aliases
1465:         if interface_scope
1466:           # subroutine
1467:           proc = nil
1468:           params = nil
1469:           procedures_trailing = nil
1470:           if line =~ /^\s*?
1471:                            (recursive|pure|elemental)?\s*?
1472:                            subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
1473:                      /ix
1474:             proc = $2.chomp.strip
1475:             proc_name = generic_name || proc
1476:             params = $3 || ""
1477:             procedures_trailing = $4 || "!"
1478: 
1479:           # function
1480:           elsif line =~ /^\s*?
1481:                          (recursive|pure|elemental)?\s*?
1482:                          (
1483:                              character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1484:                            | type\s*?\([\w\s]+?\)\s+
1485:                            | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1486:                            | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1487:                            | double\s+precision\s+
1488:                            | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1489:                            | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1490:                          )?
1491:                          function\s+(\w+)\s*?
1492:                          (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
1493:                         /ix
1494:             proc = $8.chomp.strip
1495:             proc_name = generic_name || proc
1496:             params = $9 || ""
1497:             procedures_trailing = $12 || "!"
1498:           else
1499:             next
1500:           end
1501:           next if procedures_trailing =~ /!:nodoc:/
1502:           indicated_method = nil
1503:           indicated_file   = nil
1504:           TopLevel.all_files.each do |name, toplevel|
1505:             indicated_method = toplevel.find_local_symbol(proc, @options_ignore_case)
1506:             indicated_file = name
1507:             break if indicated_method
1508:           end
1509: 
1510:           if indicated_method
1511:             external_method = 
1512:               initialize_external_method(proc_name, proc, 
1513:                                          indicated_method.params, 
1514:                                          indicated_file, 
1515:                                          indicated_method.comment)
1516: 
1517:             progress "e"
1518:             @stats.num_methods += 1
1519:             container.add_method external_method
1520:             set_visibility(container, proc_name, visibility_default, @@public_methods)
1521:             if !container.include_requires?(indicated_file, @options_ignore_case)
1522:               container.add_require(Require.new(indicated_file, ""))
1523:             end
1524:             check_public_methods(external_method, container.name)
1525: 
1526:           else
1527:             @@external_aliases << {
1528:               "new_name"  => proc_name,
1529:               "old_name"  => proc,
1530:               "file_or_module" => container,
1531:               "visibility" => find_visibility(container, proc_name, @@public_methods) || visibility_default
1532:             }
1533:           end
1534:         end
1535: 
1536:       } if interface_code # End of interface_code.split("\n").each ...
1537: 
1538:       #
1539:       # Already imported methods are removed from @@public_methods.
1540:       # Remainders are assumed to be imported from other modules.
1541:       #
1542:       # 既に参照済みのメソッドは @@public_methods から取り除く.
1543:       # 残りは外部モジュールからの参照と仮定する.
1544:       #
1545:       @@public_methods.delete_if{ |method| method["entity_is_discovered"]}
1546: 
1547:       @@public_methods.each{ |pub_meth|
1548:         next unless pub_meth["file_or_module"].name == container.name
1549:         pub_meth["used_modules"].each{ |used_mod|
1550:           TopLevel.all_classes_and_modules.each{ |modules|
1551:             if modules.name == used_mod ||
1552:                 modules.name.upcase == used_mod.upcase &&
1553:                 @options_ignore_case
1554:               modules.method_list.each{ |meth|
1555:                 if meth.name == pub_meth["name"] ||
1556:                     meth.name.upcase == pub_meth["name"].upcase &&
1557:                     @options_ignore_case
1558:                   new_meth = initialize_public_method(meth,
1559:                                                       modules.name)
1560:                   if pub_meth["local_name"]
1561:                     new_meth.name = pub_meth["local_name"]
1562:                   end
1563:                   progress "e"
1564:                   @stats.num_methods += 1
1565:                   container.add_method new_meth
1566:                 end
1567:               }
1568:             end
1569:           }
1570:         }
1571:       }
1572: 
1573:       container
1574:     end

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

[Source]

      # File parsers/parse_f95.rb, line 1580
1580:     def parse_subprogram(subprogram, params, comment, code, 
1581:                          before_contains=nil, function=nil, prefix=nil)
1582:       subprogram.singleton = false
1583:       prefix = "" if !prefix
1584:       arguments = params.sub(/\(/, "").sub(/\)/, "").split(",") if params
1585:       args_comment, params_opt = 
1586:         find_arguments(arguments, code.sub(/^s*?contains\s*?(!.*?)?$.*/im, ""),
1587:                        nil, nil, true)
1588:       params_opt = "( " + params_opt + " ) " if params_opt
1589:       subprogram.params = params_opt || ""
1590: 
1591:       block_comment = find_comments comment
1592:       if function
1593:         subprogram.comment = "<b><em> Function </em></b> :: <em>#{prefix}</em>\n"
1594:       else
1595:         subprogram.comment = "<b><em> Subroutine </em></b> :: <em>#{prefix}</em>\n"
1596:       end
1597:       subprogram.comment << args_comment if args_comment
1598:       subprogram.comment << block_comment if block_comment
1599: 
1600:       # For output source code
1601:       subprogram.start_collecting_tokens
1602:       subprogram.add_token Token.new(1,1).set_text(code)
1603: 
1604:       subprogram
1605:     end

Parse visibility

[Source]

      # File parsers/parse_f95.rb, line 1894
1894:     def parse_visibility(code, default, container)
1895:       result = []
1896:       visibility_default = default || :public
1897: 
1898:       used_modules = []
1899:       container.includes.each{|i| used_modules << i.name} if container
1900: 
1901:       remaining_code = code.gsub(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
1902:       remaining_code.split("\n").each{ |line|
1903:         if /^\s*?private\s*?$/ =~ line
1904:           visibility_default = :private
1905:           break
1906:         end
1907:       } if remaining_code
1908: 
1909:       remaining_code.split("\n").each{ |line|
1910:         if /^\s*?private\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
1911:           methods = $2.sub(/!.*$/, '')
1912:           methods.split(",").each{ |meth|
1913:             meth.sub!(/!.*$/, '')
1914:             meth.gsub!(/:/, '')
1915:             result << {
1916:               "name" => meth.chomp.strip,
1917:               "visibility" => :private,
1918:               "used_modules" => used_modules.clone,
1919:               "file_or_module" => container,
1920:               "entity_is_discovered" => nil,
1921:               "local_name" => nil
1922:             }
1923:           }
1924:         elsif /^\s*?public\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
1925:           methods = $2.sub(/!.*$/, '')
1926:           methods.split(",").each{ |meth|
1927:             meth.sub!(/!.*$/, '')
1928:             meth.gsub!(/:/, '')
1929:             result << {
1930:               "name" => meth.chomp.strip,
1931:               "visibility" => :public,
1932:               "used_modules" => used_modules.clone,
1933:               "file_or_module" => container,
1934:               "entity_is_discovered" => nil,
1935:               "local_name" => nil
1936:             }
1937:           }
1938:         end
1939:       } if remaining_code
1940: 
1941:       if container
1942:         result.each{ |vis_info|
1943:           vis_info["parent"] = container.name
1944:         }
1945:       end
1946: 
1947:       return visibility_default, result
1948:     end

[Source]

      # File parsers/parse_f95.rb, line 1834
1834:     def progress(char)
1835:       unless @options.quiet
1836:         @progress.print(char)
1837:         @progress.flush
1838:       end
1839:     end

Empty lines in header are removed

[Source]

      # File parsers/parse_f95.rb, line 2317
2317:     def remove_empty_head_lines(text)
2318:       return "" unless text
2319:       lines = text.split("\n")
2320:       header = true
2321:       lines.delete_if{ |line|
2322:         header = false if /\S/ =~ line
2323:         header && /^\s*?$/ =~ line
2324:       }
2325:       lines.join("\n")
2326:     end

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

[Source]

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

[Source]

      # File parsers/parse_f95.rb, line 2334
2334:     def remove_private_comments(body)
2335:       body.gsub!(/^(\s*)!--\s*?$.*?^\s*!\+\+\s*?$/m, '\\1!')
2336:       return body
2337:     end

Remove "Alias for" in end of comments

[Source]

      # File parsers/parse_f95.rb, line 2296
2296:     def remove_trailing_alias(text)
2297:       return "" if !text
2298:       lines = text.split("\n").reverse
2299:       comment_block = Array.new
2300:       checked = false
2301:       lines.each do |line|
2302:         if !checked 
2303:           if /^\s?#{INTERNAL_ALIAS_MES}/ =~ line ||
2304:               /^\s?#{EXTERNAL_ALIAS_MES}/ =~ line
2305:             checked = true
2306:             next
2307:           end
2308:         end
2309:         comment_block.unshift line
2310:       end
2311:       nice_lines = comment_block.join("\n")
2312:       nice_lines ||= ""
2313:       return nice_lines
2314:     end

devine code constructs

[Source]

     # File parsers/parse_f95.rb, line 713
713:     def scan
714: 
715:       # remove private comment
716:       remaining_code = remove_private_comments(@body)
717: 
718:       # continuation lines are united to one line
719:       remaining_code = united_to_one_line(remaining_code)
720: 
721:       # semicolons are replaced to line feed
722:       remaining_code = semicolon_to_linefeed(remaining_code)
723: 
724:       # collect comment for file entity
725:       whole_comment, remaining_code = collect_first_comment(remaining_code)
726:       @top_level.comment = whole_comment
727: 
728:       # String "remaining_code" is converted to Array "remaining_lines"
729:       remaining_lines = remaining_code.split("\n")
730: 
731:       # "module" or "program" parts are parsed (new)
732:       #
733:       level_depth = 0
734:       block_searching_flag = nil
735:       block_searching_lines = []
736:       pre_comment = []
737:       module_program_trailing = ""
738:       module_program_name = ""
739:       other_block_level_depth = 0
740:       other_block_searching_flag = nil
741:       remaining_lines.collect!{|line|
742:         if !block_searching_flag && !other_block_searching_flag
743:           if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i
744:             block_searching_flag = :module
745:             block_searching_lines << line
746:             module_program_name = $1
747:             module_program_trailing = find_comments($2)
748:             next false
749:           elsif line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i ||
750:                  line =~ /^\s*?\w/ && !block_start?(line)
751:             block_searching_flag = :program
752:             block_searching_lines << line
753:             module_program_name = $1 || ""
754:             module_program_trailing = find_comments($2)
755:             next false
756: 
757:           elsif block_start?(line)
758:             other_block_searching_flag = true
759:             next line
760: 
761:           elsif line =~ /^\s*?!\s?(.*)/
762:             pre_comment << line
763:             next line
764:           else
765:             pre_comment = []
766:             next line
767:           end
768:         elsif other_block_searching_flag
769:           other_block_level_depth += 1 if block_start?(line)
770:           other_block_level_depth -= 1 if block_end?(line)
771:           if other_block_level_depth < 0
772:             other_block_level_depth = 0
773:             other_block_searching_flag = nil
774:           end
775:           next line
776:         end
777: 
778:         block_searching_lines << line
779:         level_depth += 1 if block_start?(line)
780:         level_depth -= 1 if block_end?(line)
781:         if level_depth >= 0
782:           next false
783:         end
784: 
785:         # "module_program_code" is formatted.
786:         # ":nodoc:" flag is checked.
787:         #
788:         module_program_code = block_searching_lines.join("\n")
789:         module_program_code = remove_empty_head_lines(module_program_code)
790:         if module_program_trailing =~ /^:nodoc:/
791:           # next loop to search next block
792:           level_depth = 0
793:           block_searching_flag = false
794:           block_searching_lines = []
795:           pre_comment = []
796:           next false
797:         end
798: 
799:         # NormalClass is created, and added to @top_level
800:         #
801:         if block_searching_flag == :module
802:           module_name = module_program_name
803:           module_code = module_program_code
804:           module_trailing = module_program_trailing
805:           progress "m"
806:           @stats.num_modules += 1
807:           f9x_module = @top_level.add_module NormalClass, module_name
808:           f9x_module.record_location @top_level
809: 
810:           #
811:           # Add provided modules information to @top_level comment
812:           #
813:           provided_modules = []
814:           provided_mes_line_num = nil
815:           top_level_comment_lines = []
816:           line_num = 0
817:           @top_level.comment.split("\n").each{|line|
818:             top_level_comment_lines << line
819:             line_num += 1
820:             next if line.empty?
821:             if !provided_mes_line_num && /^\s?#{PROVIDED_MODULES_MES}/ =~ line
822:               provided_mes_line_num = line_num
823:               next
824:             end
825:             if provided_mes_line_num
826:               if /^\s?\*\s+<b>(\w+)<\/b>/ =~ line
827:                 provided_modules << $1
828:               else
829:                 provided_mes_line_num = nil
830:               end
831:             end
832:           }
833:           line_num = 0
834:           if provided_mes_line_num
835:             top_level_comment_lines.collect!{ |line|
836:               line_num += 1
837:               if line_num < provided_mes_line_num
838:                 line
839:               else
840:                 nil
841:               end
842:             }
843:             top_level_comment_lines.delete_if{|line| !line }
844:           end
845:           top_level_comment_lines << "\n" + PROVIDED_MODULES_MES + "."
846:           if provided_mes_line_num
847:             top_level_comment_lines[-1].sub!(/\.$/, '')
848:             top_level_comment_lines[-1] << "s."
849:           end
850:           provided_modules.each{ |mod|
851:             top_level_comment_lines << "* <b>" + mod + "</b>"
852:           }
853:           top_level_comment_lines << "* <b>" + module_name + "</b>"
854:           @top_level.comment = top_level_comment_lines.join("\n")
855: 
856:           #
857:           # Information about the module is parsed
858:           #
859:           f9x_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) +
860:             "\n" + module_trailing : module_trailing + "\n" +
861:             find_comments(module_code.sub(/^.*$\n/i, ''))
862:           f9x_module.comment = f9x_comment
863:           parse_program_or_module(f9x_module, module_code)
864: 
865:           TopLevel.all_files.each do |name, toplevel|
866:             if toplevel.include_includes?(module_name, @options_ignore_case)
867:               if !toplevel.include_requires?(@file_name, @options_ignore_case)
868:                 toplevel.add_require(Require.new(@file_name, ""))
869:               end
870:             end
871:             toplevel.each_classmodule{|m|
872:               if m.include_includes?(module_name, @options_ignore_case)
873:                 if !m.include_requires?(@file_name, @options_ignore_case)
874:                   m.add_require(Require.new(@file_name, ""))
875:                 end
876:               end
877:             }
878:           end
879: 
880:           namelist_comment = 
881:             find_namelists(f9x_module, before_contains(module_code))
882:           f9x_module.comment << namelist_comment if namelist_comment
883: 
884:         elsif block_searching_flag == :program
885:           program_name = module_program_name
886:           program_name = "main_program" if program_name.empty?
887:           program_code = module_program_code
888:           program_trailing = module_program_trailing
889:           program_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) + 
890:             "\n" + program_trailing : program_trailing + "\n" + 
891:             find_comments(program_code.sub(/^.*$\n/i, ''))
892: 
893:           progress "p"
894:           @stats.num_methods += 1
895:           f9x_mainprogram = AnyMethod.new("main_program", program_name)
896:           f9x_mainprogram.singleton = false
897:           f9x_mainprogram.comment = "<b><em> Main Program </em></b> :: <tt></tt>\n"
898:           f9x_mainprogram.comment << program_comment
899:           f9x_mainprogram.params = ""
900: 
901:           # For output source code
902:           f9x_mainprogram.start_collecting_tokens
903:           f9x_mainprogram.add_token Token.new(1,1).set_text(program_code)
904: 
905:           @top_level.add_method f9x_mainprogram
906:           parse_program_or_module(@top_level, program_code, :private)
907: 
908:           namelist_comment = find_namelists(f9x_mainprogram, program_code)
909:           f9x_mainprogram.comment << namelist_comment if namelist_comment
910:         end
911: 
912:         # next loop to search next block
913:         level_depth = 0
914:         block_searching_flag = false
915:         block_searching_lines = []
916:         pre_comment = []
917:         next false
918:       }
919: 
920:       remaining_lines.delete_if{ |line|
921:         line == false
922:       }
923: 
924:       # External subprograms and functions are parsed
925:       #
926:       # 単一のファイル内において program や module に格納されない,
927:       # 外部サブルーチン, 外部関数部分の解析.
928:       #
929:       parse_program_or_module(@top_level, remaining_lines.join("\n"),
930:                               :public, true)
931: 
932:       @top_level
933:     end

Semicolons are replaced to line feed.

[Source]

      # File parsers/parse_f95.rb, line 2199
2199:     def semicolon_to_linefeed(text)
2200:       return "" unless text
2201:       lines = text.split("\n")
2202:       lines.collect!{ |line|
2203:         indent_space = ""
2204:         if line =~ /^(\s+)/
2205:           indent_space = $1
2206:         end
2207:         words = line.split("")
2208:         commentout = false
2209:         squote = false ; dquote = false
2210:         words.collect! { |char|
2211:           if !(squote) && !(dquote) && !(commentout)
2212:             case char
2213:             when "!" ; commentout = true ; next char
2214:             when "\""; dquote = true     ; next char
2215:             when "\'"; squote = true     ; next char
2216:             when ";" ;                     "\n"+indent_space
2217:             else next char
2218:             end
2219:           elsif commentout
2220:             next char
2221:           elsif squote
2222:             case char
2223:             when "\'"; squote = false ; next char
2224:             else next char
2225:             end
2226:           elsif dquote
2227:             case char
2228:             when "\""; dquote = false ; next char
2229:             else next char
2230:             end
2231:           end
2232:         }
2233:         words.join("")
2234:       }
2235:       return lines.join("\n")
2236:     end

Set visibility

"subname" element of "visibility_info" is deleted.

[Source]

      # File parsers/parse_f95.rb, line 1955
1955:     def set_visibility(container, subname, visibility_default, visibility_info)
1956:       return unless container || subname || visibility_default || visibility_info
1957:       not_found = true
1958:       visibility_info.collect!{ |info|
1959:         if info["name"] == subname ||
1960:             @options_ignore_case && info["name"].upcase == subname.upcase
1961:           if info["file_or_module"].name == container.name
1962:             container.set_visibility_for([subname], info["visibility"])
1963:             info["entity_is_discovered"] = true
1964:             not_found = false
1965:           end
1966:         end
1967:         info
1968:       }
1969:       if not_found
1970:         return container.set_visibility_for([subname], visibility_default)
1971:       else
1972:         return container
1973:       end
1974:     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 2074
2074:     def united_to_one_line(f90src, delete_space=true)
2075:       return "" unless f90src
2076:       lines = f90src.split("\n")
2077:       previous_continuing = false
2078:       now_continuing = false
2079:       body = ""
2080:       squote = false ; dquote = false
2081:       lines.each{ |line|
2082:         words = line.split("")
2083:         next if words.empty? && previous_continuing
2084:         commentout = false
2085:         brank_flag = true ; brank_char = ""
2086:         ignore = false
2087:         words.collect! { |char|
2088:           if previous_continuing && brank_flag
2089:             now_continuing = true
2090:             ignore         = true
2091:             case char
2092:             when "!"                       ; break
2093:             when " " ; brank_char << char  ; next ""
2094:             when "&"
2095:               brank_flag = false
2096:               now_continuing = false
2097:               next ""
2098:             else 
2099:               brank_flag     = false
2100:               now_continuing = false
2101:               ignore         = false
2102:               next brank_char + char
2103:             end
2104:           end
2105:           ignore = false
2106: 
2107:           if now_continuing && !(squote) && !(dquote)
2108:             next ""
2109:           elsif !(squote) && !(dquote) && !(commentout)
2110:             case char
2111:             when "!" ; commentout = true     ; next char
2112:             when "\""; dquote = true         ; next char
2113:             when "\'"; squote = true         ; next char
2114:             when "&" ; now_continuing = true ; next ""
2115:             else next char
2116:             end
2117:           elsif commentout
2118:             next char
2119:           elsif squote
2120:             case char
2121:             when "\'"; squote = false ; now_continuing = false ; next char
2122:             when "&" ; now_continuing = true ; next ""
2123:             else next char
2124:             end
2125:           elsif dquote
2126:             case char
2127:             when "\""; dquote = false ; now_continuing = false ; next char
2128:             when "&" ; now_continuing = true ; next ""
2129:             else next char
2130:             end
2131:           end
2132:         }
2133:         if !ignore && !previous_continuing || !brank_flag
2134:           if previous_continuing
2135:             if delete_space
2136:               joined_words = words.join("")
2137:               body = body.rstrip + " " + joined_words.lstrip
2138:             else
2139:               body << words.join("")
2140:             end
2141:           else
2142:             body << "\n" + words.join("")
2143:           end
2144:         end
2145:         previous_continuing = now_continuing ? true : false
2146:         now_continuing = false
2147:       }
2148:       return body
2149:     end

[Validate]