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 671
671:     def initialize(top_level, file_name, body, options, stats)
672:       @body = body
673:       @stats = stats
674:       @file_name  = file_name
675:       @options = options
676:       @top_level = top_level
677:       @progress = $stderr unless options.quiet
678: 
679:       begin
680:         @options_ignore_case = options.ignore_case
681:       rescue
682:         @options_ignore_case = true
683:       end
684: 
685:     end

Public Instance methods

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

[Source]

      # File parsers/parse_f95.rb, line 1586
1586:     def before_contains(code)
1587:       level_depth = 0
1588:       before_contains_lines = []
1589:       before_contains_code = nil
1590:       before_contains_flag = nil
1591:       code.split("\n").each{ |line|
1592:         if !before_contains_flag
1593:           if line =~ /^\s*?module\s+\w+\s*?(!.*?)?$/i
1594:             before_contains_flag = true
1595:           end
1596:         else
1597:           break if line =~ /^\s*?contains\s*?(!.*?)?$/i
1598:           level_depth += 1 if block_start?(line)
1599:           level_depth -= 1 if block_end?(line)
1600:           break if level_depth < 0
1601:           before_contains_lines << line
1602:         end
1603: 
1604:       }
1605:       before_contains_code = before_contains_lines.join("\n")
1606:       if before_contains_code
1607:         before_contains_code.gsub!(/^\s*?interface\s+.*?\s+end\s+interface.*?$/im, "")
1608:         before_contains_code.gsub!(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
1609:       end
1610: 
1611:       before_contains_code
1612:     end

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

[Source]

      # File parsers/parse_f95.rb, line 2253
2253:     def block_end?(line)
2254:       return nil if !line
2255: 
2256:       if line =~ /^\s*?end\s*?(!.*?)?$/i                 ||
2257:           line =~ /^\s*?end\s+module(\s+\w+)?\s*?(!.*?)?$/i       ||
2258:           line =~ /^\s*?end\s+program(\s+\w+)?\s*?(!.*?)?$/i      ||
2259:           line =~ /^\s*?end\s+block\s+data(\s+\w+)?\s*?(!.*?)?$/i  ||
2260:           line =~ /^\s*?end\s+subroutine(\s+\w+)?\s*?(!.*?)?$/i   ||
2261:           line =~ /^\s*?end\s+function(\s+\w+)?\s*?(!.*?)?$/i
2262:         return true
2263:       end
2264: 
2265:       return nil
2266:     end

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

[Source]

      # File parsers/parse_f95.rb, line 2217
2217:     def block_start?(line)
2218:       return nil if !line
2219: 
2220:       if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i    ||
2221:           line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i  ||
2222:           line =~ /^\s*?block\s+data(\s+\w+)?\s*?(!.*?)?$/i     ||
2223:           line =~ \
2224:                   /^\s*?
2225:                    (recursive|pure|elemental)?\s*?
2226:                    subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
2227:                   /ix ||
2228:           line =~ \
2229:                   /^\s*?
2230:                    (recursive|pure|elemental)?\s*?
2231:                    (
2232:                        character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
2233:                      | type\s*?\([\w\s]+?\)\s+
2234:                      | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
2235:                      | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
2236:                      | double\s+precision\s+
2237:                      | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
2238:                      | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
2239:                    )?
2240:                    function\s+(\w+)\s*?
2241:                    (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
2242:                   /ix
2243:         return true
2244:       end
2245: 
2246:       return nil
2247:     end

Check external aliases

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

[Source]

      # File parsers/parse_f95.rb, line 1973
1973:     def check_external_aliases(subname, params, comment, test=nil)
1974:       @@external_aliases.each{ |alias_item|
1975:         if subname == alias_item["old_name"] ||
1976:                     subname.upcase == alias_item["old_name"].upcase &&
1977:                             @options_ignore_case
1978: 
1979:           new_meth = initialize_external_method(alias_item["new_name"], 
1980:                                                 subname, params, @file_name, 
1981:                                                 comment)
1982:           new_meth.visibility = alias_item["visibility"]
1983: 
1984:           progress "e"
1985:           @stats.num_methods += 1
1986:           alias_item["file_or_module"].add_method(new_meth)
1987: 
1988:           if !alias_item["file_or_module"].include_requires?(@file_name, @options_ignore_case)
1989:             alias_item["file_or_module"].add_require(Require.new(@file_name, ""))
1990:           end
1991:         end
1992:       }
1993:     end

Check public_methods

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

[Source]

      # File parsers/parse_f95.rb, line 2003
2003:     def check_public_methods(method, parent)
2004:       return if !method || !parent
2005:       @@public_methods.each{ |alias_item|
2006:         parent_is_used_module = nil
2007:         alias_item["used_modules"].each{ |used_module|
2008:           if used_module == parent ||
2009:               used_module.upcase == parent.upcase &&
2010:               @options_ignore_case
2011:             parent_is_used_module = true
2012:           end
2013:         }
2014:         next if !parent_is_used_module
2015: 
2016:         if method.name == alias_item["name"] ||
2017:             method.name.upcase == alias_item["name"].upcase &&
2018:             @options_ignore_case
2019: 
2020:           new_meth = initialize_public_method(method, parent)
2021:           if alias_item["local_name"]
2022:             new_meth.name = alias_item["local_name"]
2023:           end
2024: 
2025:           progress "e"
2026:           @stats.num_methods += 1
2027:           alias_item["file_or_module"].add_method new_meth
2028:         end
2029:       }
2030:     end

Collect comment for file entity

[Source]

      # File parsers/parse_f95.rb, line 1617
1617:     def collect_first_comment(body)
1618:       comment = ""
1619:       not_comment = ""
1620:       comment_start = false
1621:       comment_end   = false
1622:       body.split("\n").each{ |line|
1623:         if comment_end
1624:           not_comment << line
1625:           not_comment << "\n"
1626:         elsif /^\s*?!\s?(.*)$/i =~ line
1627:           comment_start = true
1628:           comment << $1
1629:           comment << "\n"
1630:         elsif /^\s*?$/i =~ line
1631:           comment_end = true if comment_start && COMMENTS_ARE_UPPER
1632:         else
1633:           comment_end = true
1634:           not_comment << line
1635:           not_comment << "\n"
1636:         end
1637:       }
1638:       return comment, not_comment
1639:     end

Comment out checker

[Source]

      # File parsers/parse_f95.rb, line 2144
2144:     def comment_out?(line)
2145:       return nil unless line
2146:       commentout = false
2147:       squote = false ; dquote = false
2148:       line.split("").each { |char|
2149:         if !(squote) && !(dquote)
2150:           case char
2151:           when "!" ; commentout = true ; break
2152:           when "\""; dquote = true
2153:           when "\'"; squote = true
2154:           else next
2155:           end
2156:         elsif squote
2157:           case char
2158:           when "\'"; squote = false
2159:           else next
2160:           end
2161:         elsif dquote
2162:           case char
2163:           when "\""; dquote = false
2164:           else next
2165:           end
2166:         end
2167:       }
2168:       return commentout
2169:     end

Continuous line checker

[Source]

      # File parsers/parse_f95.rb, line 2130
2130:     def continuous_line?(line)
2131:       continuous = false
2132:       if /&\s*?(!.*)?$/ =~ line
2133:         continuous = true
2134:         if comment_out?($~.pre_match)
2135:           continuous = false
2136:         end
2137:       end
2138:       return continuous
2139:     end

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

[Source]

      # File parsers/parse_f95.rb, line 2389
2389:     def definition_info(text)
2390:       return nil unless text
2391:       lines = "#{text}"
2392:       defs = Array.new
2393:       comment = ""
2394:       trailing_comment = ""
2395:       under_comment_valid = false
2396:       lines.split("\n").each{ |line|
2397:         if /^\s*?!\s?(.*)/ =~ line
2398:           if COMMENTS_ARE_UPPER
2399:             comment << remove_header_marker($1)
2400:             comment << "\n"
2401:           elsif defs[-1] && under_comment_valid
2402:             defs[-1].comment << "\n"
2403:             defs[-1].comment << remove_header_marker($1)
2404:           end
2405:           next
2406:         elsif /^\s*?$/ =~ line
2407:           comment = ""
2408:           under_comment_valid = false
2409:           next
2410:         end
2411:         type = ""
2412:         characters = ""
2413:         if line =~ /^\s*?
2414:                     (
2415:                         character\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2416:                       | type\s*?\([\w\s]+?\)[\s\,]*
2417:                       | integer\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2418:                       | real\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2419:                       | double\s+precision[\s\,]*
2420:                       | logical\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2421:                       | complex\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2422:                     )
2423:                     (.*?::)?
2424:                     (.+)$
2425:                    /ix
2426:           characters = $8
2427:           type = $1
2428:           type << $7.gsub(/::/, '').gsub(/^\s*?\,/, '') if $7
2429:         else
2430:           under_comment_valid = false
2431:           next
2432:         end
2433:         squote = false ; dquote = false ; bracket = 0
2434:         iniflag = false; commentflag = false
2435:         varname = "" ; arraysuffix = "" ; inivalue = ""
2436:         start_pos = defs.size
2437:         characters.split("").each { |char|
2438:           if !(squote) && !(dquote) && bracket <= 0 && !(iniflag) && !(commentflag)
2439:             case char
2440:             when "!" ; commentflag = true
2441:             when "(" ; bracket += 1       ; arraysuffix = char
2442:             when "\""; dquote = true
2443:             when "\'"; squote = true
2444:             when "=" ; iniflag = true     ; inivalue << char
2445:             when ","
2446:               defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2447:               varname = "" ; arraysuffix = "" ; inivalue = ""
2448:               under_comment_valid = true
2449:             when " " ; next
2450:             else     ; varname << char
2451:             end
2452:           elsif commentflag
2453:             comment << remove_header_marker(char)
2454:             trailing_comment << remove_header_marker(char)
2455:           elsif iniflag
2456:             if dquote
2457:               case char
2458:               when "\"" ; dquote = false ; inivalue << char
2459:               else      ; inivalue << char
2460:               end
2461:             elsif squote
2462:               case char
2463:               when "\'" ; squote = false ; inivalue << char
2464:               else      ; inivalue << char
2465:               end
2466:             elsif bracket > 0
2467:               case char
2468:               when "(" ; bracket += 1 ; inivalue << char
2469:               when ")" ; bracket -= 1 ; inivalue << char
2470:               else     ; inivalue << char
2471:               end
2472:             else
2473:               case char
2474:               when ","
2475:                 defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2476:                 varname = "" ; arraysuffix = "" ; inivalue = ""
2477:                 iniflag = false
2478:                 under_comment_valid = true
2479:               when "(" ; bracket += 1 ; inivalue << char
2480:               when "\""; dquote = true  ; inivalue << char
2481:               when "\'"; squote = true  ; inivalue << char
2482:               when "!" ; commentflag = true
2483:               else     ; inivalue << char
2484:               end
2485:             end
2486:           elsif !(squote) && !(dquote) && bracket > 0
2487:             case char
2488:             when "(" ; bracket += 1 ; arraysuffix << char
2489:             when ")" ; bracket -= 1 ; arraysuffix << char
2490:             else     ; arraysuffix << char
2491:             end
2492:           elsif squote
2493:             case char
2494:             when "\'"; squote = false ; inivalue << char
2495:             else     ; inivalue << char
2496:             end
2497:           elsif dquote
2498:             case char
2499:             when "\""; dquote = false ; inivalue << char
2500:             else     ; inivalue << char
2501:             end
2502:           end
2503:         }
2504:         defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2505:         if trailing_comment =~ /^:nodoc:/
2506:           defs[start_pos..-1].collect!{ |defitem|
2507:             defitem.nodoc = true
2508:           }
2509:         end
2510:         varname = "" ; arraysuffix = "" ; inivalue = ""
2511:         comment = ""
2512:         under_comment_valid = true
2513:         trailing_comment = ""
2514:       }
2515:       return defs
2516:     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 1648
1648:     def find_arguments(args, text, all=nil, indent=nil, modified_params=nil)
1649:       return unless args || all
1650:       indent = "" unless indent
1651:       args = ["all"] if all
1652:       params = "" if modified_params
1653:       comma = ""
1654:       return unless text
1655:       args_rdocforms = "\n"
1656:       remaining_lines = "#{text}"
1657:       definitions = definition_info(remaining_lines)
1658:       args.each{ |arg|
1659:         arg.strip!
1660:         arg.chomp!
1661:         definitions.each { |defitem|
1662:           if arg == defitem.varname.strip.chomp || all
1663:             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"
1664:             if !defitem.comment.chomp.strip.empty?
1665:               comment = ""
1666:               defitem.comment.split("\n").each{ |line|
1667:                 comment << "       " + line + "\n"
1668:               }
1669:               args_rdocforms << "\n\#{indent}   <tt></tt> ::\n\#{indent}       <tt></tt>\n\#{indent}       \#{comment.chomp.strip}\n"
1670:             end
1671: 
1672:             if modified_params
1673:               if defitem.include_attr?("optional")
1674:                 params << "#{comma}[#{arg}]"
1675:               else
1676:                 params << "#{comma}#{arg}"
1677:               end
1678:               comma = ", "
1679:             end
1680:           end
1681:         }
1682:       }
1683:       if modified_params
1684:         return args_rdocforms, params
1685:       else
1686:         return args_rdocforms
1687:       end
1688:     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 1791
1791:     def find_comments text
1792:       return "" unless text
1793:       lines = text.split("\n")
1794:       lines.reverse! if COMMENTS_ARE_UPPER
1795:       comment_block = Array.new
1796:       lines.each do |line|
1797:         break if line =~ /^\s*?\w/ || line =~ /^\s*?$/
1798:         if COMMENTS_ARE_UPPER
1799:           comment_block.unshift line.sub(/^\s*?!\s?/,"")
1800:         else
1801:           comment_block.push line.sub(/^\s*?!\s?/,"")
1802:         end
1803:       end
1804:       nice_lines = comment_block.join("\n").split "\n\s*?\n"
1805:       nice_lines[0] ||= ""
1806:       nice_lines.shift
1807:     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 1706
1706:     def find_namelists(container, text, before_contains=nil)
1707:       return nil if !text
1708:       top_level = find_toplevel(container)
1709: 
1710:       if text =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)(!.*?)?$/i
1711:         if top_level.include_includes?(NAMELIST_REPOSITORY_NAME)
1712:           namelist_module = 
1713:             top_level.find_module_named(NAMELIST_REPOSITORY_NAME)
1714:         else
1715:           namelist_module = 
1716:             top_level.add_module NormalClass, NAMELIST_REPOSITORY_NAME
1717:           namelist_module.record_location top_level
1718:           namelist_module.comment = "This is not a module but a repository of NAMELIST group names declared\nin all Fortran 90/95 files\n"
1719:         end
1720:       else
1721:         return ""
1722:       end
1723: 
1724:       nml_group_name_lists = []
1725:       lines = "#{text}"
1726:       before_contains = "" if !before_contains
1727:       while lines =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)(!.*?)?$/i
1728:         lines = $~.post_match
1729:         pre_match = $~.pre_match ; post_match = $~.post_match
1730:         nml_group_name = $1
1731:         trailing_comment = $3 || ""
1732:         nml_vars_list  = $2.split(",")
1733:         nml_comment = COMMENTS_ARE_UPPER ? 
1734:             find_comments(pre_match.sub(/\n$/, '')) :
1735:             find_comments(trailing_comment + post_match)
1736:         if lines.split("\n")[0] =~ /^\//i
1737:           lines = "namelist " + lines
1738:         end
1739: 
1740:         nml_meth = AnyMethod.new("NAMELIST", nml_group_name)
1741:         nml_meth.singleton = false
1742:         nml_meth.params    = "( " + nml_vars_list.join(", ") + " )"
1743:         nml_meth.comment   = "<b><em> NAMELIST </em></b> :: <tt></tt>\n"
1744:         nml_meth.comment   << find_arguments(nml_vars_list, "#{text}" + "\n" + before_contains)
1745:         nml_meth.comment   << "\n" + nml_comment if nml_comment
1746:         if container.parent.parent
1747:           parent_object = container.parent.name
1748:         else
1749:           parent_object = container.parent.file_relative_name
1750:         end
1751:         nml_meth.comment   << "\n\nThis namelist group name is input/output in "
1752:         nml_meth.comment   << parent_object + "#" + container.name
1753: 
1754:         progress "n"
1755:         @stats.num_methods += 1
1756:         namelist_module.add_method nml_meth
1757: 
1758:         nml_group_name_lists << NAMELIST_REPOSITORY_NAME + "#" + nml_group_name
1759:       end
1760: 
1761:       if !nml_group_name_lists.empty?
1762:         comments_in_procedures = "\n\nThis procedure input/output "
1763:         comments_in_procedures << nml_group_name_lists.join(", ") + " . "
1764:       else
1765:         comments_in_procedures = ""
1766:       end
1767: 
1768:       comments_in_procedures
1769:     end

Return toplevel class of container

[Source]

      # File parsers/parse_f95.rb, line 1778
1778:     def find_toplevel(container)
1779:       top_level = container
1780:       while top_level.parent
1781:         top_level = top_level.parent
1782:       end
1783:       top_level
1784:     end

Find visibility

[Source]

      # File parsers/parse_f95.rb, line 1954
1954:     def find_visibility(container, subname, visibility_info)
1955:       return nil if !subname || !visibility_info
1956:       visibility_info.each{ |info|
1957:         if info["name"] == subname ||
1958:             @options_ignore_case && info["name"].upcase == subname.upcase
1959:           if info["parent"] == container.name
1960:             return info["visibility"]
1961:           end
1962:         end
1963:       }
1964:       return nil
1965:     end

Create method for external alias

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

[Source]

      # File parsers/parse_f95.rb, line 1836
1836:     def initialize_external_method(new, old, params, file, comment, token=nil,
1837:                                    internal=nil, nolink=nil)
1838:       return nil unless new || old
1839: 
1840:       if internal
1841:         external_alias_header = "#{INTERNAL_ALIAS_MES} "
1842:         external_alias_text   = external_alias_header + old 
1843:       elsif file
1844:         external_alias_header = "#{EXTERNAL_ALIAS_MES} "
1845:         external_alias_text   = external_alias_header + file + "#" + old
1846:       else
1847:         return nil
1848:       end
1849:       external_meth = AnyMethod.new(external_alias_text, new)
1850:       external_meth.singleton    = false
1851:       external_meth.params       = params
1852:       external_comment = remove_trailing_alias(comment) + "\n\n" if comment
1853:       external_meth.comment = external_comment || ""
1854:       if nolink && token
1855:         external_meth.start_collecting_tokens
1856:         external_meth.add_token Token.new(1,1).set_text(token)
1857:       else
1858:         external_meth.comment << external_alias_text
1859:       end
1860: 
1861:       return external_meth
1862:     end

Create method for internal alias

[Source]

      # File parsers/parse_f95.rb, line 1819
1819:     def initialize_public_method(method, parent)
1820:       return if !method || !parent
1821: 
1822:       new_meth = AnyMethod.new("External Alias for module", method.name)
1823:       new_meth.singleton    = method.singleton
1824:       new_meth.params       = method.params.clone
1825:       new_meth.comment      = remove_trailing_alias(method.comment.clone)
1826:       new_meth.comment      << "\n\n#{EXTERNAL_ALIAS_MES} #{parent.strip.chomp}\##{method.name}"
1827: 
1828:       return new_meth
1829:     end

[Source]

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

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

[Source]

      # File parsers/parse_f95.rb, line 1555
1555:     def parse_subprogram(subprogram, params, comment, code, 
1556:                          before_contains=nil, function=nil, prefix=nil)
1557:       subprogram.singleton = false
1558:       prefix = "" if !prefix
1559:       arguments = params.sub(/\(/, "").sub(/\)/, "").split(",") if params
1560:       args_comment, params_opt = 
1561:         find_arguments(arguments, code.sub(/^s*?contains\s*?(!.*?)?$.*/im, ""),
1562:                        nil, nil, true)
1563:       params_opt = "( " + params_opt + " ) " if params_opt
1564:       subprogram.params = params_opt || ""
1565: 
1566:       block_comment = find_comments comment
1567:       if function
1568:         subprogram.comment = "<b><em> Function </em></b> :: <em>#{prefix}</em>\n"
1569:       else
1570:         subprogram.comment = "<b><em> Subroutine </em></b> :: <em>#{prefix}</em>\n"
1571:       end
1572:       subprogram.comment << args_comment if args_comment
1573:       subprogram.comment << block_comment if block_comment
1574: 
1575:       # For output source code
1576:       subprogram.start_collecting_tokens
1577:       subprogram.add_token Token.new(1,1).set_text(code)
1578: 
1579:       subprogram
1580:     end

Parse visibility

[Source]

      # File parsers/parse_f95.rb, line 1869
1869:     def parse_visibility(code, default, container)
1870:       result = []
1871:       visibility_default = default || :public
1872: 
1873:       used_modules = []
1874:       container.includes.each{|i| used_modules << i.name} if container
1875: 
1876:       remaining_code = code.gsub(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
1877:       remaining_code.split("\n").each{ |line|
1878:         if /^\s*?private\s*?$/ =~ line
1879:           visibility_default = :private
1880:           break
1881:         end
1882:       } if remaining_code
1883: 
1884:       remaining_code.split("\n").each{ |line|
1885:         if /^\s*?private\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
1886:           methods = $2.sub(/!.*$/, '')
1887:           methods.split(",").each{ |meth|
1888:             meth.sub!(/!.*$/, '')
1889:             meth.gsub!(/:/, '')
1890:             result << {
1891:               "name" => meth.chomp.strip,
1892:               "visibility" => :private,
1893:               "used_modules" => used_modules.clone,
1894:               "file_or_module" => container,
1895:               "entity_is_discovered" => nil,
1896:               "local_name" => nil
1897:             }
1898:           }
1899:         elsif /^\s*?public\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
1900:           methods = $2.sub(/!.*$/, '')
1901:           methods.split(",").each{ |meth|
1902:             meth.sub!(/!.*$/, '')
1903:             meth.gsub!(/:/, '')
1904:             result << {
1905:               "name" => meth.chomp.strip,
1906:               "visibility" => :public,
1907:               "used_modules" => used_modules.clone,
1908:               "file_or_module" => container,
1909:               "entity_is_discovered" => nil,
1910:               "local_name" => nil
1911:             }
1912:           }
1913:         end
1914:       } if remaining_code
1915: 
1916:       if container
1917:         result.each{ |vis_info|
1918:           vis_info["parent"] = container.name
1919:         }
1920:       end
1921: 
1922:       return visibility_default, result
1923:     end

[Source]

      # File parsers/parse_f95.rb, line 1809
1809:     def progress(char)
1810:       unless @options.quiet
1811:         @progress.print(char)
1812:         @progress.flush
1813:       end
1814:     end

Empty lines in header are removed

[Source]

      # File parsers/parse_f95.rb, line 2292
2292:     def remove_empty_head_lines(text)
2293:       return "" unless text
2294:       lines = text.split("\n")
2295:       header = true
2296:       lines.delete_if{ |line|
2297:         header = false if /\S/ =~ line
2298:         header && /^\s*?$/ =~ line
2299:       }
2300:       lines.join("\n")
2301:     end

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

[Source]

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

[Source]

      # File parsers/parse_f95.rb, line 2309
2309:     def remove_private_comments(body)
2310:       body.gsub!(/^(\s*)!--\s*?$.*?^\s*!\+\+\s*?$/m, '\\1!')
2311:       return body
2312:     end

Remove "Alias for" in end of comments

[Source]

      # File parsers/parse_f95.rb, line 2271
2271:     def remove_trailing_alias(text)
2272:       return "" if !text
2273:       lines = text.split("\n").reverse
2274:       comment_block = Array.new
2275:       checked = false
2276:       lines.each do |line|
2277:         if !checked 
2278:           if /^\s?#{INTERNAL_ALIAS_MES}/ =~ line ||
2279:               /^\s?#{EXTERNAL_ALIAS_MES}/ =~ line
2280:             checked = true
2281:             next
2282:           end
2283:         end
2284:         comment_block.unshift line
2285:       end
2286:       nice_lines = comment_block.join("\n")
2287:       nice_lines ||= ""
2288:       return nice_lines
2289:     end

devine code constructs

[Source]

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

Semicolons are replaced to line feed.

[Source]

      # File parsers/parse_f95.rb, line 2174
2174:     def semicolon_to_linefeed(text)
2175:       return "" unless text
2176:       lines = text.split("\n")
2177:       lines.collect!{ |line|
2178:         indent_space = ""
2179:         if line =~ /^(\s+)/
2180:           indent_space = $1
2181:         end
2182:         words = line.split("")
2183:         commentout = false
2184:         squote = false ; dquote = false
2185:         words.collect! { |char|
2186:           if !(squote) && !(dquote) && !(commentout)
2187:             case char
2188:             when "!" ; commentout = true ; next char
2189:             when "\""; dquote = true     ; next char
2190:             when "\'"; squote = true     ; next char
2191:             when ";" ;                     "\n"+indent_space
2192:             else next char
2193:             end
2194:           elsif commentout
2195:             next char
2196:           elsif squote
2197:             case char
2198:             when "\'"; squote = false ; next char
2199:             else next char
2200:             end
2201:           elsif dquote
2202:             case char
2203:             when "\""; dquote = false ; next char
2204:             else next char
2205:             end
2206:           end
2207:         }
2208:         words.join("")
2209:       }
2210:       return lines.join("\n")
2211:     end

Set visibility

"subname" element of "visibility_info" is deleted.

[Source]

      # File parsers/parse_f95.rb, line 1930
1930:     def set_visibility(container, subname, visibility_default, visibility_info)
1931:       return unless container || subname || visibility_default || visibility_info
1932:       not_found = true
1933:       visibility_info.collect!{ |info|
1934:         if info["name"] == subname ||
1935:             @options_ignore_case && info["name"].upcase == subname.upcase
1936:           if info["file_or_module"].name == container.name
1937:             container.set_visibility_for([subname], info["visibility"])
1938:             info["entity_is_discovered"] = true
1939:             not_found = false
1940:           end
1941:         end
1942:         info
1943:       }
1944:       if not_found
1945:         return container.set_visibility_for([subname], visibility_default)
1946:       else
1947:         return container
1948:       end
1949:     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 2049
2049:     def united_to_one_line(f90src, delete_space=true)
2050:       return "" unless f90src
2051:       lines = f90src.split("\n")
2052:       previous_continuing = false
2053:       now_continuing = false
2054:       body = ""
2055:       squote = false ; dquote = false
2056:       lines.each{ |line|
2057:         words = line.split("")
2058:         next if words.empty? && previous_continuing
2059:         commentout = false
2060:         brank_flag = true ; brank_char = ""
2061:         ignore = false
2062:         words.collect! { |char|
2063:           if previous_continuing && brank_flag
2064:             now_continuing = true
2065:             ignore         = true
2066:             case char
2067:             when "!"                       ; break
2068:             when " " ; brank_char << char  ; next ""
2069:             when "&"
2070:               brank_flag = false
2071:               now_continuing = false
2072:               next ""
2073:             else 
2074:               brank_flag     = false
2075:               now_continuing = false
2076:               ignore         = false
2077:               next brank_char + char
2078:             end
2079:           end
2080:           ignore = false
2081: 
2082:           if now_continuing && !(squote) && !(dquote)
2083:             next ""
2084:           elsif !(squote) && !(dquote) && !(commentout)
2085:             case char
2086:             when "!" ; commentout = true     ; next char
2087:             when "\""; dquote = true         ; next char
2088:             when "\'"; squote = true         ; next char
2089:             when "&" ; now_continuing = true ; next ""
2090:             else next char
2091:             end
2092:           elsif commentout
2093:             next char
2094:           elsif squote
2095:             case char
2096:             when "\'"; squote = false ; now_continuing = false ; next char
2097:             when "&" ; now_continuing = true ; next ""
2098:             else next char
2099:             end
2100:           elsif dquote
2101:             case char
2102:             when "\""; dquote = false ; now_continuing = false ; next char
2103:             when "&" ; now_continuing = true ; next ""
2104:             else next char
2105:             end
2106:           end
2107:         }
2108:         if !ignore && !previous_continuing || !brank_flag
2109:           if previous_continuing
2110:             if delete_space
2111:               joined_words = words.join("")
2112:               body = body.rstrip + " " + joined_words.lstrip
2113:             else
2114:               body << words.join("")
2115:             end
2116:           else
2117:             body << "\n" + words.join("")
2118:           end
2119:         end
2120:         previous_continuing = now_continuing ? true : false
2121:         now_continuing = false
2122:       }
2123:       return body
2124:     end

[Validate]