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 392
392:     def initialize(top_level, file_name, body, options, stats)
393:       @body = body
394:       @stats = stats
395:       @file_name  = file_name
396:       @options = options
397:       @top_level = top_level
398:       @progress = $stderr unless options.quiet
399:     end

Public Instance methods

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

[Source]

      # File parsers/parse_f95.rb, line 1300
1300:     def before_contains(code)
1301:       level_depth = 0
1302:       before_contains_lines = []
1303:       before_contains_code = nil
1304:       before_contains_flag = nil
1305:       code.split("\n").each{ |line|
1306:         if !before_contains_flag
1307:           if line =~ /^\s*?module\s+\w+\s*?(!.*?)?$/i
1308:             before_contains_flag = true
1309:           end
1310:         else
1311:           break if line =~ /^\s*?contains\s*?(!.*?)?$/i
1312:           level_depth += 1 if block_start?(line)
1313:           level_depth -= 1 if block_end?(line)
1314:           break if level_depth < 0
1315:           before_contains_lines << line
1316:         end
1317: 
1318:       }
1319:       before_contains_code = before_contains_lines.join("\n")
1320:       if before_contains_code
1321:         before_contains_code.gsub!(/^\s*?interface\s+.*?\s+end\s+interface.*?$/im, "")
1322:         before_contains_code.gsub!(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
1323:       end
1324: 
1325:       before_contains_code
1326:     end

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

[Source]

      # File parsers/parse_f95.rb, line 1965
1965:     def block_end?(line)
1966:       return nil if !line
1967: 
1968:       if line =~ /^\s*?end\s*?(!.*?)?$/i                 ||
1969:           line =~ /^\s*?end\s+module(\s+\w+)?\s*?(!.*?)?$/i       ||
1970:           line =~ /^\s*?end\s+program(\s+\w+)?\s*?(!.*?)?$/i      ||
1971:           line =~ /^\s*?end\s+block\s+data(\s+\w+)?\s*?(!.*?)?$/i  ||
1972:           line =~ /^\s*?end\s+subroutine(\s+\w+)?\s*?(!.*?)?$/i   ||
1973:           line =~ /^\s*?end\s+function(\s+\w+)?\s*?(!.*?)?$/i
1974:         return true
1975:       end
1976: 
1977:       return nil
1978:     end

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

[Source]

      # File parsers/parse_f95.rb, line 1929
1929:     def block_start?(line)
1930:       return nil if !line
1931: 
1932:       if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i    ||
1933:           line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i  ||
1934:           line =~ /^\s*?block\s+data(\s+\w+)?\s*?(!.*?)?$/i     ||
1935:           line =~ \
1936:                   /^\s*?
1937:                    (recursive|pure|elemental)?\s*?
1938:                    subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
1939:                   /ix ||
1940:           line =~ \
1941:                   /^\s*?
1942:                    (recursive|pure|elemental)?\s*?
1943:                    (
1944:                        character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1945:                      | type\s*?\([\w\s]+?\)\s+
1946:                      | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1947:                      | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1948:                      | double\s+precision\s+
1949:                      | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1950:                      | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1951:                    )?
1952:                    function\s+(\w+)\s*?
1953:                    (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
1954:                   /ix
1955:         return true
1956:       end
1957: 
1958:       return nil
1959:     end

Check external aliases

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

[Source]

      # File parsers/parse_f95.rb, line 1687
1687:     def check_external_aliases(subname, params, comment, test=nil)
1688:       @@external_aliases.each{ |alias_item|
1689:         if subname == alias_item["old_name"] ||
1690:                     subname.upcase == alias_item["old_name"].upcase &&
1691:                             @options.ignore_case
1692: 
1693:           new_meth = initialize_external_method(alias_item["new_name"], 
1694:                                                 subname, params, @file_name, 
1695:                                                 comment)
1696:           new_meth.visibility = alias_item["visibility"]
1697: 
1698:           progress "e"
1699:           @stats.num_methods += 1
1700:           alias_item["file_or_module"].add_method(new_meth)
1701: 
1702:           if !alias_item["file_or_module"].include_requires?(@file_name, @options.ignore_case)
1703:             alias_item["file_or_module"].add_require(Require.new(@file_name, ""))
1704:           end
1705:         end
1706:       }
1707:     end

Check public_methods

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

[Source]

      # File parsers/parse_f95.rb, line 1717
1717:     def check_public_methods(method, parent)
1718:       return if !method || !parent
1719:       @@public_methods.each{ |alias_item|
1720:         parent_is_used_module = nil
1721:         alias_item["used_modules"].each{ |used_module|
1722:           if used_module == parent ||
1723:               used_module.upcase == parent.upcase &&
1724:               @options.ignore_case
1725:             parent_is_used_module = true
1726:           end
1727:         }
1728:         next if !parent_is_used_module
1729: 
1730:         if method.name == alias_item["name"] ||
1731:             method.name.upcase == alias_item["name"].upcase &&
1732:             @options.ignore_case
1733: 
1734:           new_meth = initialize_public_method(method, parent)
1735:           if alias_item["local_name"]
1736:             new_meth.name = alias_item["local_name"]
1737:           end
1738: 
1739:           progress "e"
1740:           @stats.num_methods += 1
1741:           alias_item["file_or_module"].add_method new_meth
1742:         end
1743:       }
1744:     end

Collect comment for file entity

[Source]

      # File parsers/parse_f95.rb, line 1331
1331:     def collect_first_comment(body)
1332:       comment = ""
1333:       not_comment = ""
1334:       comment_start = false
1335:       comment_end   = false
1336:       body.split("\n").each{ |line|
1337:         if comment_end
1338:           not_comment << line
1339:           not_comment << "\n"
1340:         elsif /^\s*?!\s?(.*)$/i =~ line
1341:           comment_start = true
1342:           comment << $1
1343:           comment << "\n"
1344:         elsif /^\s*?$/i =~ line
1345:           comment_end = true if comment_start && COMMENTS_ARE_UPPER
1346:         else
1347:           comment_end = true
1348:           not_comment << line
1349:           not_comment << "\n"
1350:         end
1351:       }
1352:       return comment, not_comment
1353:     end

Comment out checker

[Source]

      # File parsers/parse_f95.rb, line 1856
1856:     def comment_out?(line)
1857:       return nil unless line
1858:       commentout = false
1859:       squote = false ; dquote = false
1860:       line.split("").each { |char|
1861:         if !(squote) && !(dquote)
1862:           case char
1863:           when "!" ; commentout = true ; break
1864:           when "\""; dquote = true
1865:           when "\'"; squote = true
1866:           else next
1867:           end
1868:         elsif squote
1869:           case char
1870:           when "\'"; squote = false
1871:           else next
1872:           end
1873:         elsif dquote
1874:           case char
1875:           when "\""; dquote = false
1876:           else next
1877:           end
1878:         end
1879:       }
1880:       return commentout
1881:     end

Continuous line checker

[Source]

      # File parsers/parse_f95.rb, line 1842
1842:     def continuous_line?(line)
1843:       continuous = false
1844:       if /&\s*?(!.*)?$/ =~ line
1845:         continuous = true
1846:         if comment_out?($~.pre_match)
1847:           continuous = false
1848:         end
1849:       end
1850:       return continuous
1851:     end

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

[Source]

      # File parsers/parse_f95.rb, line 2101
2101:     def definition_info(text)
2102:       return nil unless text
2103:       lines = "#{text}"
2104:       defs = Array.new
2105:       comment = ""
2106:       trailing_comment = ""
2107:       under_comment_valid = false
2108:       lines.split("\n").each{ |line|
2109:         if /^\s*?!\s?(.*)/ =~ line
2110:           if COMMENTS_ARE_UPPER
2111:             comment << remove_header_marker($1)
2112:             comment << "\n"
2113:           elsif defs[-1] && under_comment_valid
2114:             defs[-1].comment << "\n"
2115:             defs[-1].comment << remove_header_marker($1)
2116:           end
2117:           next
2118:         elsif /^\s*?$/ =~ line
2119:           comment = ""
2120:           under_comment_valid = false
2121:           next
2122:         end
2123:         type = ""
2124:         characters = ""
2125:         if line =~ /^\s*?
2126:                     (
2127:                         character\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2128:                       | type\s*?\([\w\s]+?\)[\s\,]*
2129:                       | integer\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2130:                       | real\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2131:                       | double\s+precision[\s\,]*
2132:                       | logical\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2133:                       | complex\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2134:                     )
2135:                     (.*?::)?
2136:                     (.+)$
2137:                    /ix
2138:           characters = $8
2139:           type = $1
2140:           type << $7.gsub(/::/, '').gsub(/^\s*?\,/, '') if $7
2141:         else
2142:           under_comment_valid = false
2143:           next
2144:         end
2145:         squote = false ; dquote = false ; bracket = 0
2146:         iniflag = false; commentflag = false
2147:         varname = "" ; arraysuffix = "" ; inivalue = ""
2148:         start_pos = defs.size
2149:         characters.split("").each { |char|
2150:           if !(squote) && !(dquote) && bracket <= 0 && !(iniflag) && !(commentflag)
2151:             case char
2152:             when "!" ; commentflag = true
2153:             when "(" ; bracket += 1       ; arraysuffix = char
2154:             when "\""; dquote = true
2155:             when "\'"; squote = true
2156:             when "=" ; iniflag = true     ; inivalue << char
2157:             when ","
2158:               defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2159:               varname = "" ; arraysuffix = "" ; inivalue = ""
2160:               under_comment_valid = true
2161:             when " " ; next
2162:             else     ; varname << char
2163:             end
2164:           elsif commentflag
2165:             comment << remove_header_marker(char)
2166:             trailing_comment << remove_header_marker(char)
2167:           elsif iniflag
2168:             if dquote
2169:               case char
2170:               when "\"" ; dquote = false ; inivalue << char
2171:               else      ; inivalue << char
2172:               end
2173:             elsif squote
2174:               case char
2175:               when "\'" ; squote = false ; inivalue << char
2176:               else      ; inivalue << char
2177:               end
2178:             elsif bracket > 0
2179:               case char
2180:               when "(" ; bracket += 1 ; inivalue << char
2181:               when ")" ; bracket -= 1 ; inivalue << char
2182:               else     ; inivalue << char
2183:               end
2184:             else
2185:               case char
2186:               when ","
2187:                 defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2188:                 varname = "" ; arraysuffix = "" ; inivalue = ""
2189:                 iniflag = false
2190:                 under_comment_valid = true
2191:               when "(" ; bracket += 1 ; inivalue << char
2192:               when "\""; dquote = true  ; inivalue << char
2193:               when "\'"; squote = true  ; inivalue << char
2194:               when "!" ; commentflag = true
2195:               else     ; inivalue << char
2196:               end
2197:             end
2198:           elsif !(squote) && !(dquote) && bracket > 0
2199:             case char
2200:             when "(" ; bracket += 1 ; arraysuffix << char
2201:             when ")" ; bracket -= 1 ; arraysuffix << char
2202:             else     ; arraysuffix << char
2203:             end
2204:           elsif squote
2205:             case char
2206:             when "\'"; squote = false ; inivalue << char
2207:             else     ; inivalue << char
2208:             end
2209:           elsif dquote
2210:             case char
2211:             when "\""; dquote = false ; inivalue << char
2212:             else     ; inivalue << char
2213:             end
2214:           end
2215:         }
2216:         defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2217:         if trailing_comment =~ /^:nodoc:/
2218:           defs[start_pos..-1].collect!{ |defitem|
2219:             defitem.nodoc = true
2220:           }
2221:         end
2222:         varname = "" ; arraysuffix = "" ; inivalue = ""
2223:         comment = ""
2224:         under_comment_valid = true
2225:         trailing_comment = ""
2226:       }
2227:       return defs
2228:     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 1362
1362:     def find_arguments(args, text, all=nil, indent=nil, modified_params=nil)
1363:       return unless args || all
1364:       indent = "" unless indent
1365:       args = ["all"] if all
1366:       params = "" if modified_params
1367:       comma = ""
1368:       return unless text
1369:       args_rdocforms = "\n"
1370:       remaining_lines = "#{text}"
1371:       definitions = definition_info(remaining_lines)
1372:       args.each{ |arg|
1373:         arg.strip!
1374:         arg.chomp!
1375:         definitions.each { |defitem|
1376:           if arg == defitem.varname.strip.chomp || all
1377:             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"
1378:             if !defitem.comment.chomp.strip.empty?
1379:               comment = ""
1380:               defitem.comment.split("\n").each{ |line|
1381:                 comment << "       " + line + "\n"
1382:               }
1383:               args_rdocforms << "\n\#{indent}   <tt></tt> ::\n\#{indent}       <tt></tt>\n\#{indent}       \#{comment.chomp.strip}\n"
1384:             end
1385: 
1386:             if modified_params
1387:               if defitem.include_attr?("optional")
1388:                 params << "#{comma}[#{arg}]"
1389:               else
1390:                 params << "#{comma}#{arg}"
1391:               end
1392:               comma = ", "
1393:             end
1394:           end
1395:         }
1396:       }
1397:       if modified_params
1398:         return args_rdocforms, params
1399:       else
1400:         return args_rdocforms
1401:       end
1402:     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 1505
1505:     def find_comments text
1506:       return "" unless text
1507:       lines = text.split("\n")
1508:       lines.reverse! if COMMENTS_ARE_UPPER
1509:       comment_block = Array.new
1510:       lines.each do |line|
1511:         break if line =~ /^\s*?\w/ || line =~ /^\s*?$/
1512:         if COMMENTS_ARE_UPPER
1513:           comment_block.unshift line.sub(/^\s*?!\s?/,"")
1514:         else
1515:           comment_block.push line.sub(/^\s*?!\s?/,"")
1516:         end
1517:       end
1518:       nice_lines = comment_block.join("\n").split "\n\s*?\n"
1519:       nice_lines[0] ||= ""
1520:       nice_lines.shift
1521:     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 1420
1420:     def find_namelists(container, text, before_contains=nil)
1421:       return nil if !text
1422:       top_level = find_toplevel(container)
1423: 
1424:       if text =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)(!.*?)?$/i
1425:         if top_level.include_includes?(NAMELIST_REPOSITORY_NAME)
1426:           namelist_module = 
1427:             top_level.find_module_named(NAMELIST_REPOSITORY_NAME)
1428:         else
1429:           namelist_module = 
1430:             top_level.add_module NormalClass, NAMELIST_REPOSITORY_NAME
1431:           namelist_module.record_location top_level
1432:           namelist_module.comment = "This is not a module but a repository of NAMELIST group names declared\nin all Fortran 90/95 files\n"
1433:         end
1434:       else
1435:         return ""
1436:       end
1437: 
1438:       nml_group_name_lists = []
1439:       lines = "#{text}"
1440:       before_contains = "" if !before_contains
1441:       while lines =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)(!.*?)?$/i
1442:         lines = $~.post_match
1443:         pre_match = $~.pre_match ; post_match = $~.post_match
1444:         nml_group_name = $1
1445:         trailing_comment = $3 || ""
1446:         nml_vars_list  = $2.split(",")
1447:         nml_comment = COMMENTS_ARE_UPPER ? 
1448:             find_comments(pre_match.sub(/\n$/, '')) :
1449:             find_comments(trailing_comment + post_match)
1450:         if lines.split("\n")[0] =~ /^\//i
1451:           lines = "namelist " + lines
1452:         end
1453: 
1454:         nml_meth = AnyMethod.new("NAMELIST", nml_group_name)
1455:         nml_meth.singleton = false
1456:         nml_meth.params    = "( " + nml_vars_list.join(", ") + " )"
1457:         nml_meth.comment   = "<b><em> NAMELIST </em></b> :: <tt></tt>\n"
1458:         nml_meth.comment   << find_arguments(nml_vars_list, "#{text}" + "\n" + before_contains)
1459:         nml_meth.comment   << "\n" + nml_comment if nml_comment
1460:         if container.parent.parent
1461:           parent_object = container.parent.name
1462:         else
1463:           parent_object = container.parent.file_relative_name
1464:         end
1465:         nml_meth.comment   << "\n\nThis namelist group name is input/output in "
1466:         nml_meth.comment   << parent_object + "#" + container.name
1467: 
1468:         progress "n"
1469:         @stats.num_methods += 1
1470:         namelist_module.add_method nml_meth
1471: 
1472:         nml_group_name_lists << NAMELIST_REPOSITORY_NAME + "#" + nml_group_name
1473:       end
1474: 
1475:       if !nml_group_name_lists.empty?
1476:         comments_in_procedures = "\n\nThis procedure input/output "
1477:         comments_in_procedures << nml_group_name_lists.join(", ") + " . "
1478:       else
1479:         comments_in_procedures = ""
1480:       end
1481: 
1482:       comments_in_procedures
1483:     end

Return toplevel class of container

[Source]

      # File parsers/parse_f95.rb, line 1492
1492:     def find_toplevel(container)
1493:       top_level = container
1494:       while top_level.parent
1495:         top_level = top_level.parent
1496:       end
1497:       top_level
1498:     end

Find visibility

[Source]

      # File parsers/parse_f95.rb, line 1668
1668:     def find_visibility(container, subname, visibility_info)
1669:       return nil if !subname || !visibility_info
1670:       visibility_info.each{ |info|
1671:         if info["name"] == subname ||
1672:             @options.ignore_case && info["name"].upcase == subname.upcase
1673:           if info["parent"] == container.name
1674:             return info["visibility"]
1675:           end
1676:         end
1677:       }
1678:       return nil
1679:     end

Create method for external alias

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

[Source]

      # File parsers/parse_f95.rb, line 1550
1550:     def initialize_external_method(new, old, params, file, comment, token=nil,
1551:                                    internal=nil, nolink=nil)
1552:       return nil unless new || old
1553: 
1554:       if internal
1555:         external_alias_header = "#{INTERNAL_ALIAS_MES} "
1556:         external_alias_text   = external_alias_header + old 
1557:       elsif file
1558:         external_alias_header = "#{EXTERNAL_ALIAS_MES} "
1559:         external_alias_text   = external_alias_header + file + "#" + old
1560:       else
1561:         return nil
1562:       end
1563:       external_meth = AnyMethod.new(external_alias_text, new)
1564:       external_meth.singleton    = false
1565:       external_meth.params       = params
1566:       external_comment = remove_trailing_alias(comment) + "\n\n" if comment
1567:       external_meth.comment = external_comment || ""
1568:       if nolink && token
1569:         external_meth.start_collecting_tokens
1570:         external_meth.add_token Token.new(1,1).set_text(token)
1571:       else
1572:         external_meth.comment << external_alias_text
1573:       end
1574: 
1575:       return external_meth
1576:     end

Create method for internal alias

[Source]

      # File parsers/parse_f95.rb, line 1533
1533:     def initialize_public_method(method, parent)
1534:       return if !method || !parent
1535: 
1536:       new_meth = AnyMethod.new("External Alias for module", method.name)
1537:       new_meth.singleton    = method.singleton
1538:       new_meth.params       = method.params.clone
1539:       new_meth.comment      = remove_trailing_alias(method.comment.clone)
1540:       new_meth.comment      << "\n\n#{EXTERNAL_ALIAS_MES} #{parent.strip.chomp}\##{method.name}"
1541: 
1542:       return new_meth
1543:     end

[Source]

      # File parsers/parse_f95.rb, line 626
 626:     def parse_program_or_module(container, code,
 627:                                 visibility=:public, external=nil)
 628:       return unless container
 629:       return unless code
 630:       remaining_lines = code.split("\n")
 631:       remaining_code = "#{code}"
 632: 
 633:       #
 634:       # Parse variables before "contains" in module
 635:       #
 636:       # namelist 変数の定義に使われたり, これ自体が定数, 変数
 637:       # 提供されるのに利用される. (変数や定数として利用される場合,
 638:       # これもメソッドとして提供する.
 639:       #
 640:       before_contains_code = before_contains(remaining_code)
 641: 
 642:       #
 643:       # Parse global "use"
 644:       #
 645:       use_check_code = "#{before_contains_code}"
 646:       cascaded_modules_list = []
 647:       while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i
 648:         use_check_code = $~.pre_match
 649:         use_check_code << $~.post_match
 650:         used_mod_name = $1.strip.chomp
 651:         used_list = $2 || ""
 652:         used_trailing = $3 || ""
 653:         next if used_trailing =~ /!:nodoc:/
 654:         if !container.include_includes?(used_mod_name, @options.ignore_case)
 655:           progress "."
 656:           container.add_include Include.new(used_mod_name, "")
 657:         end
 658:         if ! (used_list =~ /\,\s*?only\s*?:/i )
 659:           cascaded_modules_list << "\#" + used_mod_name
 660:         end
 661:       end
 662: 
 663:       #
 664:       # Parse public and private, and store information.
 665:       # This information is used when "add_method" and
 666:       # "set_visibility_for" are called.
 667:       #
 668:       visibility_default, visibility_info = 
 669:                 parse_visibility(remaining_lines.join("\n"), visibility, container)
 670:       @@public_methods.concat visibility_info
 671:       if visibility_default == :public
 672:         if !cascaded_modules_list.empty?
 673:           cascaded_modules = 
 674:             Attr.new("Cascaded Modules",
 675:                      "Imported modules all of whose components are published again",
 676:                      "",
 677:                      cascaded_modules_list.join(", "))
 678:           container.add_attribute(cascaded_modules)
 679:         end
 680:       end
 681: 
 682:       #
 683:       # Check rename elements
 684:       #
 685:       use_check_code = "#{before_contains_code}"
 686:       while use_check_code =~ /^\s*?use\s+(\w+)\s*?\,(.+)$/i
 687:         use_check_code = $~.pre_match
 688:         use_check_code << $~.post_match
 689:         used_mod_name = $1.strip.chomp
 690:         used_elements = $2.sub(/\s*?only\s*?:\s*?/i, '')
 691:         used_elements.split(",").each{ |used|
 692:           if /\s*?(\w+)\s*?=>\s*?(\w+)\s*?/ =~ used
 693:             local = $1
 694:             org = $2
 695:             @@public_methods.collect!{ |pub_meth|
 696:               if local == pub_meth["name"] ||
 697:                   local.upcase == pub_meth["name"].upcase &&
 698:                   @options.ignore_case
 699:                 pub_meth["name"] = org
 700:                 pub_meth["local_name"] = local
 701:               end
 702:               pub_meth
 703:             }
 704:           end
 705:         }
 706:       end
 707: 
 708:       #
 709:       # Parse private "use"
 710:       #
 711:       use_check_code = remaining_lines.join("\n")
 712:       while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i
 713:         use_check_code = $~.pre_match
 714:         use_check_code << $~.post_match
 715:         used_mod_name = $1.strip.chomp
 716:         used_trailing = $3 || ""
 717:         next if used_trailing =~ /!:nodoc:/
 718:         if !container.include_includes?(used_mod_name, @options.ignore_case)
 719:           progress "."
 720:           container.add_include Include.new(used_mod_name, "")
 721:         end
 722:       end
 723: 
 724:       container.each_includes{ |inc|
 725:         TopLevel.all_files.each do |name, toplevel|
 726:           indicated_mod = toplevel.find_symbol(inc.name,
 727:                                                nil, @options.ignore_case)
 728:           if indicated_mod
 729:             indicated_name = indicated_mod.parent.file_relative_name
 730:             if !container.include_requires?(indicated_name, @options.ignore_case)
 731:               container.add_require(Require.new(indicated_name, ""))
 732:             end
 733:             break
 734:           end
 735:         end
 736:       }
 737: 
 738:       #
 739:       # Parse derived types definitions
 740:       #
 741:       derived_types_comment = ""
 742:       remaining_code = remaining_lines.join("\n")
 743:       while remaining_code =~ /^\s*?
 744:                                     type[\s\,]+(public|private)?\s*?(::)?\s*?
 745:                                     (\w+)\s*?(!.*?)?$
 746:                                     (.*?)
 747:                                     ^\s*?end\s+type.*?$
 748:                               /imx
 749:         remaining_code = $~.pre_match
 750:         remaining_code << $~.post_match
 751:         typename = $3.chomp.strip
 752:         type_elements = $5 || ""
 753:         type_code = remove_empty_head_lines($&)
 754:         type_trailing = find_comments($4)
 755:         next if type_trailing =~ /^:nodoc:/
 756:         type_visibility = $1
 757:         type_comment = COMMENTS_ARE_UPPER ? 
 758:           find_comments($~.pre_match) + "\n" + type_trailing :
 759:             type_trailing + "\n" + find_comments(type_code.sub(/^.*$\n/i, ''))
 760:         type_element_visibility_public = true
 761:         type_code.split("\n").each{ |line|
 762:           if /^\s*?private\s*?$/ =~ line
 763:             type_element_visibility_public = nil
 764:             break
 765:           end
 766:         } if type_code
 767: 
 768:         args_comment = ""
 769:         type_args_info = nil
 770: 
 771:         if @options.show_all
 772:           args_comment = find_arguments(nil, type_code, true)
 773:         else
 774:           type_public_args_list = []
 775:           type_args_info = definition_info(type_code)
 776:           type_args_info.each{ |arg|
 777:             arg_is_public = type_element_visibility_public
 778:             arg_is_public = true if arg.include_attr?("public")
 779:             arg_is_public = nil if arg.include_attr?("private")
 780:             type_public_args_list << arg.varname if arg_is_public
 781:           }
 782:           args_comment = find_arguments(type_public_args_list, type_code)
 783:         end
 784: 
 785:         type = AnyMethod.new("type #{typename}", typename)
 786:         type.singleton = false
 787:         type.params = ""
 788:         type.comment = "<b><em> Derived Type </em></b> :: <tt></tt>\n"
 789:         type.comment << args_comment if args_comment
 790:         type.comment << type_comment if type_comment
 791:         progress "t"
 792:         @stats.num_methods += 1
 793:         container.add_method type
 794: 
 795:         set_visibility(container, typename, visibility_default, @@public_methods)
 796: 
 797:         if type_visibility
 798:           type_visibility.gsub!(/\s/,'')
 799:           type_visibility.gsub!(/\,/,'')
 800:           type_visibility.gsub!(/:/,'')
 801:           type_visibility.downcase!
 802:           if type_visibility == "public"
 803:             container.set_visibility_for([typename], :public)
 804:           elsif type_visibility == "private"
 805:             container.set_visibility_for([typename], :private)
 806:           end
 807:         end
 808: 
 809:         check_public_methods(type, container.name)
 810: 
 811:         if @options.show_all
 812:           derived_types_comment << ", " unless derived_types_comment.empty?
 813:           derived_types_comment << typename
 814:         else
 815:           if type.visibility == :public
 816:           derived_types_comment << ", " unless derived_types_comment.empty?
 817:           derived_types_comment << typename
 818:           end
 819:         end
 820: 
 821:       end
 822: 
 823:       if !derived_types_comment.empty?
 824:         derived_types_table = 
 825:           Attr.new("Derived Types", "Derived_Types", "", 
 826:                    derived_types_comment)
 827:         container.add_attribute(derived_types_table)
 828:       end
 829: 
 830:       #
 831:       # move interface scope
 832:       #
 833:       interface_code = ""
 834:       while remaining_code =~ /^\s*?
 835:                                    interface(
 836:                                               \s+\w+                      |
 837:                                               \s+operator\s*?\(.*?\)       |
 838:                                               \s+assignment\s*?\(\s*?=\s*?\)
 839:                                             )?\s*?$
 840:                                    (.*?)
 841:                                    ^\s*?end\s+interface.*?$
 842:                               /imx
 843:         interface_code << remove_empty_head_lines($&) + "\n"
 844:         remaining_code = $~.pre_match
 845:         remaining_code << $~.post_match
 846:       end
 847: 
 848:       #
 849:       # Parse global constants or variables in modules
 850:       #
 851:       const_var_defs = definition_info(before_contains_code)
 852:       const_var_defs.each{|defitem|
 853:         next if defitem.nodoc
 854:         const_or_var_type = "Variable"
 855:         const_or_var_progress = "v"
 856:         if defitem.include_attr?("parameter")
 857:           const_or_var_type = "Constant"
 858:           const_or_var_progress = "c"
 859:         end
 860:         const_or_var = AnyMethod.new(const_or_var_type, defitem.varname)
 861:         const_or_var.singleton = false
 862:         const_or_var.params = ""
 863:         self_comment = find_arguments([defitem.varname], before_contains_code)
 864:         const_or_var.comment = "<b><em>" + const_or_var_type + "</em></b> :: <tt></tt>\n"
 865:         const_or_var.comment << self_comment if self_comment
 866:         progress const_or_var_progress
 867:         @stats.num_methods += 1
 868:         container.add_method const_or_var
 869: 
 870:         set_visibility(container, defitem.varname, visibility_default, @@public_methods)
 871: 
 872:         if defitem.include_attr?("public")
 873:           container.set_visibility_for([defitem.varname], :public)
 874:         elsif defitem.include_attr?("private")
 875:           container.set_visibility_for([defitem.varname], :private)
 876:         end
 877: 
 878:         check_public_methods(const_or_var, container.name)
 879: 
 880:       } if const_var_defs
 881: 
 882:       remaining_lines = remaining_code.split("\n")
 883: 
 884:       # "subroutine" or "function" parts are parsed (new)
 885:       #
 886:       level_depth = 0
 887:       block_searching_flag = nil
 888:       block_searching_lines = []
 889:       pre_comment = []
 890:       procedure_trailing = ""
 891:       procedure_name = ""
 892:       procedure_params = ""
 893:       procedure_prefix = ""
 894:       procedure_result_arg = ""
 895:       procedure_type = ""
 896:       contains_lines = []
 897:       contains_flag = nil
 898:       remaining_lines.collect!{|line|
 899:         if !block_searching_flag
 900:           # subroutine
 901:           if line =~ /^\s*?
 902:                            (recursive|pure|elemental)?\s*?
 903:                            subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
 904:                      /ix
 905:             block_searching_flag = :subroutine
 906:             block_searching_lines << line
 907: 
 908:             procedure_name = $2.chomp.strip
 909:             procedure_params = $3 || ""
 910:             procedure_prefix = $1 || ""
 911:             procedure_trailing = $4 || "!"
 912:             next false
 913: 
 914:           # function
 915:           elsif line =~ /^\s*?
 916:                          (recursive|pure|elemental)?\s*?
 917:                          (
 918:                              character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
 919:                            | type\s*?\([\w\s]+?\)\s+
 920:                            | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
 921:                            | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
 922:                            | double\s+precision\s+
 923:                            | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
 924:                            | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
 925:                          )?
 926:                          function\s+(\w+)\s*?
 927:                          (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
 928:                         /ix
 929:             block_searching_flag = :function
 930:             block_searching_lines << line
 931: 
 932:             procedure_prefix = $1 || ""
 933:             procedure_type = $2 ? $2.chomp.strip : nil
 934:             procedure_name = $8.chomp.strip
 935:             procedure_params = $9 || ""
 936:             procedure_result_arg = $11 ? $11.chomp.strip : procedure_name
 937:             procedure_trailing = $12 || "!"
 938:             next false
 939:           elsif line =~ /^\s*?!\s?(.*)/
 940:             pre_comment << line
 941:             next line
 942:           else
 943:             pre_comment = []
 944:             next line
 945:           end
 946:         end
 947:         contains_flag = true if line =~ /^\s*?contains\s*?(!.*?)?$/
 948:         block_searching_lines << line
 949:         contains_lines << line if contains_flag
 950: 
 951:         level_depth += 1 if block_start?(line)
 952:         level_depth -= 1 if block_end?(line)
 953:         if level_depth >= 0
 954:           next false
 955:         end
 956: 
 957:         # "procedure_code" is formatted.
 958:         # ":nodoc:" flag is checked.
 959:         #
 960:         procedure_code = block_searching_lines.join("\n")
 961:         procedure_code = remove_empty_head_lines(procedure_code)
 962:         if procedure_trailing =~ /^!:nodoc:/
 963:           # next loop to search next block
 964:           level_depth = 0
 965:           block_searching_flag = nil
 966:           block_searching_lines = []
 967:           pre_comment = []
 968:           procedure_trailing = ""
 969:           procedure_name = ""
 970:           procedure_params = ""
 971:           procedure_prefix = ""
 972:           procedure_result_arg = ""
 973:           procedure_type = ""
 974:           contains_lines = []
 975:           contains_flag = nil
 976:           next false
 977:         end
 978: 
 979:         # AnyMethod is created, and added to container
 980:         #
 981:         subroutine_function = nil
 982:         if block_searching_flag == :subroutine
 983:           subroutine_prefix   = procedure_prefix
 984:           subroutine_name     = procedure_name
 985:           subroutine_params   = procedure_params
 986:           subroutine_trailing = procedure_trailing
 987:           subroutine_code     = procedure_code
 988: 
 989:           subroutine_comment = COMMENTS_ARE_UPPER ? 
 990:             pre_comment.join("\n") + "\n" + subroutine_trailing : 
 991:               subroutine_trailing + "\n" + subroutine_code.sub(/^.*$\n/i, '')
 992:           subroutine = AnyMethod.new("subroutine", subroutine_name)
 993:           parse_subprogram(subroutine, subroutine_params,
 994:                            subroutine_comment, subroutine_code,
 995:                            before_contains_code, nil, subroutine_prefix)
 996:           progress "s"
 997:           @stats.num_methods += 1
 998:           container.add_method subroutine
 999:           subroutine_function = subroutine
1000: 
1001:           namelist_comment = 
1002:             find_namelists(subroutine, subroutine_code, before_contains_code)
1003:           subroutine.comment << namelist_comment if namelist_comment
1004: 
1005:         elsif block_searching_flag == :function
1006:           function_prefix     = procedure_prefix
1007:           function_type       = procedure_type
1008:           function_name       = procedure_name
1009:           function_params_org = procedure_params
1010:           function_result_arg = procedure_result_arg
1011:           function_trailing   = procedure_trailing
1012:           function_code_org   = procedure_code
1013: 
1014:           function_comment = COMMENTS_ARE_UPPER ?
1015:             pre_comment.join("\n") + "\n" + function_trailing :
1016:               function_trailing + "\n " + function_code_org.sub(/^.*$\n/i, '')
1017: 
1018:           function_code = "#{function_code_org}"
1019:           if function_type
1020:             function_code << "\n" + function_type + " :: " + function_result_arg
1021:           end
1022: 
1023:           function_params =
1024:             function_params_org.sub(/^\(/, "\(#{function_result_arg}, ")
1025: 
1026:           function = AnyMethod.new("function", function_name)
1027:           parse_subprogram(function, function_params,
1028:                            function_comment, function_code,
1029:                            before_contains_code, true, function_prefix)
1030: 
1031:           # Specific modification due to function
1032:           function.params.sub!(/\(\s*?#{function_result_arg}\s*?,\s*?/, "\( ")
1033:           function.params << " result(" + function_result_arg + ")"
1034:           function.start_collecting_tokens
1035:           function.add_token Token.new(1,1).set_text(function_code_org)
1036: 
1037:           progress "f"
1038:           @stats.num_methods += 1
1039:           container.add_method function
1040:           subroutine_function = function
1041: 
1042:           namelist_comment = 
1043:             find_namelists(function, function_code, before_contains_code)
1044:           function.comment << namelist_comment if namelist_comment
1045: 
1046:         end
1047: 
1048:         # The visibility of procedure is specified
1049:         #
1050:         set_visibility(container, procedure_name, 
1051:                        visibility_default, @@public_methods)
1052: 
1053:         # The alias for this procedure from external modules
1054:         #
1055:         check_external_aliases(procedure_name,
1056:                                subroutine_function.params,
1057:                                subroutine_function.comment, subroutine_function) if external
1058:         check_public_methods(subroutine_function, container.name)
1059: 
1060: 
1061:         # contains_lines are parsed as private procedures
1062:         if contains_flag
1063:           parse_program_or_module(container,
1064:                                   contains_lines.join("\n"), :private)
1065:         end
1066: 
1067:         # next loop to search next block
1068:         level_depth = 0
1069:         block_searching_flag = nil
1070:         block_searching_lines = []
1071:         pre_comment = []
1072:         procedure_trailing = ""
1073:         procedure_name = ""
1074:         procedure_params = ""
1075:         procedure_prefix = ""
1076:         procedure_result_arg = ""
1077:         contains_lines = []
1078:         contains_flag = nil
1079:         next false
1080:       } # End of remaining_lines.collect!{|line|
1081: 
1082:       # Array remains_lines is converted to String remains_code again
1083:       #
1084:       remaining_code = remaining_lines.join("\n")
1085: 
1086:       #
1087:       # Parse interface
1088:       #
1089:       interface_scope = false
1090:       generic_name = ""
1091:       interface_code.split("\n").each{ |line|
1092:         if /^\s*?
1093:                  interface(
1094:                             \s+\w+|
1095:                             \s+operator\s*?\(.*?\)|
1096:                             \s+assignment\s*?\(\s*?=\s*?\)
1097:                           )?
1098:                  \s*?(!.*?)?$
1099:            /ix =~ line
1100:           generic_name = $1 ? $1.strip.chomp : nil
1101:           interface_trailing = $2 || "!"
1102:           interface_scope = true
1103:           interface_scope = false if interface_trailing =~ /!:nodoc:/
1104: #          if generic_name =~ /operator\s*?\((.*?)\)/i
1105: #            operator_name = $1
1106: #            if operator_name && !operator_name.empty?
1107: #              generic_name = "#{operator_name}"
1108: #            end
1109: #          end
1110: #          if generic_name =~ /assignment\s*?\((.*?)\)/i
1111: #            assignment_name = $1
1112: #            if assignment_name && !assignment_name.empty?
1113: #              generic_name = "#{assignment_name}"
1114: #            end
1115: #          end
1116:         end
1117:         if /^\s*?end\s+interface/i =~ line
1118:           interface_scope = false
1119:           generic_name = nil
1120:         end
1121:         # internal alias
1122:         if interface_scope && /^\s*?module\s+procedure\s+(.*?)(!.*?)?$/i =~ line
1123:           procedures = $1.strip.chomp
1124:           procedures_trailing = $2 || "!"
1125:           next if procedures_trailing =~ /!:nodoc:/
1126:           procedures.split(",").each{ |proc|
1127:             proc.strip!
1128:             proc.chomp!
1129:             next if generic_name == proc || !generic_name
1130:             old_meth = container.find_symbol(proc, nil, @options.ignore_case)
1131:             next if !old_meth
1132:             nolink = old_meth.visibility == :private ? true : nil
1133:             nolink = nil if @options.show_all
1134:             new_meth = 
1135:                initialize_external_method(generic_name, proc, 
1136:                                           old_meth.params, nil, 
1137:                                           old_meth.comment, 
1138:                                           old_meth.clone.token_stream[0].text, 
1139:                                           true, nolink)
1140:             new_meth.singleton = old_meth.singleton
1141: 
1142:             progress "i"
1143:             @stats.num_methods += 1
1144:             container.add_method new_meth
1145: 
1146:             set_visibility(container, generic_name, visibility_default, @@public_methods)
1147: 
1148:             check_public_methods(new_meth, container.name)
1149: 
1150:           }
1151:         end
1152: 
1153:         # external aliases
1154:         if interface_scope
1155:           # subroutine
1156:           proc = nil
1157:           params = nil
1158:           procedures_trailing = nil
1159:           if line =~ /^\s*?
1160:                            (recursive|pure|elemental)?\s*?
1161:                            subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
1162:                      /ix
1163:             proc = $2.chomp.strip
1164:             generic_name = proc unless generic_name
1165:             params = $3 || ""
1166:             procedures_trailing = $4 || "!"
1167: 
1168:           # function
1169:           elsif line =~ /^\s*?
1170:                          (recursive|pure|elemental)?\s*?
1171:                          (
1172:                              character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1173:                            | type\s*?\([\w\s]+?\)\s+
1174:                            | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1175:                            | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1176:                            | double\s+precision\s+
1177:                            | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1178:                            | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1179:                          )?
1180:                          function\s+(\w+)\s*?
1181:                          (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
1182:                         /ix
1183:             proc = $8.chomp.strip
1184:             generic_name = proc unless generic_name
1185:             params = $9 || ""
1186:             procedures_trailing = $12 || "!"
1187:           else
1188:             next
1189:           end
1190:           next if procedures_trailing =~ /!:nodoc:/
1191:           indicated_method = nil
1192:           indicated_file   = nil
1193:           TopLevel.all_files.each do |name, toplevel|
1194:             indicated_method = toplevel.find_local_symbol(proc, @options.ignore_case)
1195:             indicated_file = name
1196:             break if indicated_method
1197:           end
1198: 
1199:           if indicated_method
1200:             external_method = 
1201:               initialize_external_method(generic_name, proc, 
1202:                                          indicated_method.params, 
1203:                                          indicated_file, 
1204:                                          indicated_method.comment)
1205: 
1206:             progress "e"
1207:             @stats.num_methods += 1
1208:             container.add_method external_method
1209:             set_visibility(container, generic_name, visibility_default, @@public_methods)
1210:             if !container.include_requires?(indicated_file, @options.ignore_case)
1211:               container.add_require(Require.new(indicated_file, ""))
1212:             end
1213:             check_public_methods(external_method, container.name)
1214: 
1215:           else
1216:             @@external_aliases << {
1217:               "new_name"  => generic_name,
1218:               "old_name"  => proc,
1219:               "file_or_module" => container,
1220:               "visibility" => find_visibility(container, generic_name, @@public_methods) || visibility_default
1221:             }
1222:           end
1223:         end
1224: 
1225:       } if interface_code # End of interface_code.split("\n").each ...
1226: 
1227:       #
1228:       # Already imported methods are removed from @@public_methods.
1229:       # Remainders are assumed to be imported from other modules.
1230:       #
1231:       # 既に参照済みのメソッドは @@public_methods から取り除く.
1232:       # 残りは外部モジュールからの参照と仮定する.
1233:       #
1234:       @@public_methods.delete_if{ |method| method["entity_is_discovered"]}
1235: 
1236:       @@public_methods.each{ |pub_meth|
1237:         next unless pub_meth["file_or_module"].name == container.name
1238:         pub_meth["used_modules"].each{ |used_mod|
1239:           TopLevel.all_classes_and_modules.each{ |modules|
1240:             if modules.name == used_mod ||
1241:                 modules.name.upcase == used_mod.upcase &&
1242:                 @options.ignore_case
1243:               modules.method_list.each{ |meth|
1244:                 if meth.name == pub_meth["name"] ||
1245:                     meth.name.upcase == pub_meth["name"].upcase &&
1246:                     @options.ignore_case
1247:                   new_meth = initialize_public_method(meth,
1248:                                                       modules.name)
1249:                   if pub_meth["local_name"]
1250:                     new_meth.name = pub_meth["local_name"]
1251:                   end
1252:                   progress "e"
1253:                   @stats.num_methods += 1
1254:                   container.add_method new_meth
1255:                 end
1256:               }
1257:             end
1258:           }
1259:         }
1260:       }
1261: 
1262:       container
1263:     end

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

[Source]

      # File parsers/parse_f95.rb, line 1269
1269:     def parse_subprogram(subprogram, params, comment, code, 
1270:                          before_contains=nil, function=nil, prefix=nil)
1271:       subprogram.singleton = false
1272:       prefix = "" if !prefix
1273:       arguments = params.sub(/\(/, "").sub(/\)/, "").split(",") if params
1274:       args_comment, params_opt = 
1275:         find_arguments(arguments, code.sub(/^s*?contains\s*?(!.*?)?$.*/im, ""),
1276:                        nil, nil, true)
1277:       params_opt = "( " + params_opt + " ) " if params_opt
1278:       subprogram.params = params_opt || ""
1279: 
1280:       block_comment = find_comments comment
1281:       if function
1282:         subprogram.comment = "<b><em> Function </em></b> :: <em>#{prefix}</em>\n"
1283:       else
1284:         subprogram.comment = "<b><em> Subroutine </em></b> :: <em>#{prefix}</em>\n"
1285:       end
1286:       subprogram.comment << args_comment if args_comment
1287:       subprogram.comment << block_comment if block_comment
1288: 
1289:       # For output source code
1290:       subprogram.start_collecting_tokens
1291:       subprogram.add_token Token.new(1,1).set_text(code)
1292: 
1293:       subprogram
1294:     end

Parse visibility

[Source]

      # File parsers/parse_f95.rb, line 1583
1583:     def parse_visibility(code, default, container)
1584:       result = []
1585:       visibility_default = default || :public
1586: 
1587:       used_modules = []
1588:       container.includes.each{|i| used_modules << i.name} if container
1589: 
1590:       remaining_code = code.gsub(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
1591:       remaining_code.split("\n").each{ |line|
1592:         if /^\s*?private\s*?$/ =~ line
1593:           visibility_default = :private
1594:           break
1595:         end
1596:       } if remaining_code
1597: 
1598:       remaining_code.split("\n").each{ |line|
1599:         if /^\s*?private\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
1600:           methods = $2.sub(/!.*$/, '')
1601:           methods.split(",").each{ |meth|
1602:             meth.sub!(/!.*$/, '')
1603:             meth.gsub!(/:/, '')
1604:             result << {
1605:               "name" => meth.chomp.strip,
1606:               "visibility" => :private,
1607:               "used_modules" => used_modules.clone,
1608:               "file_or_module" => container,
1609:               "entity_is_discovered" => nil,
1610:               "local_name" => nil
1611:             }
1612:           }
1613:         elsif /^\s*?public\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
1614:           methods = $2.sub(/!.*$/, '')
1615:           methods.split(",").each{ |meth|
1616:             meth.sub!(/!.*$/, '')
1617:             meth.gsub!(/:/, '')
1618:             result << {
1619:               "name" => meth.chomp.strip,
1620:               "visibility" => :public,
1621:               "used_modules" => used_modules.clone,
1622:               "file_or_module" => container,
1623:               "entity_is_discovered" => nil,
1624:               "local_name" => nil
1625:             }
1626:           }
1627:         end
1628:       } if remaining_code
1629: 
1630:       if container
1631:         result.each{ |vis_info|
1632:           vis_info["parent"] = container.name
1633:         }
1634:       end
1635: 
1636:       return visibility_default, result
1637:     end

[Source]

      # File parsers/parse_f95.rb, line 1523
1523:     def progress(char)
1524:       unless @options.quiet
1525:         @progress.print(char)
1526:         @progress.flush
1527:       end
1528:     end

Empty lines in header are removed

[Source]

      # File parsers/parse_f95.rb, line 2004
2004:     def remove_empty_head_lines(text)
2005:       return "" unless text
2006:       lines = text.split("\n")
2007:       header = true
2008:       lines.delete_if{ |line|
2009:         header = false if /\S/ =~ line
2010:         header && /^\s*?$/ =~ line
2011:       }
2012:       lines.join("\n")
2013:     end

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

[Source]

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

[Source]

      # File parsers/parse_f95.rb, line 2021
2021:     def remove_private_comments(body)
2022:       body.gsub!(/^(\s*)!--\s*?$.*?^\s*!\+\+\s*?$/m, '\\1!')
2023:       return body
2024:     end

Remove "Alias for" in end of comments

[Source]

      # File parsers/parse_f95.rb, line 1983
1983:     def remove_trailing_alias(text)
1984:       return "" if !text
1985:       lines = text.split("\n").reverse
1986:       comment_block = Array.new
1987:       checked = false
1988:       lines.each do |line|
1989:         if !checked 
1990:           if /^\s?#{INTERNAL_ALIAS_MES}/ =~ line ||
1991:               /^\s?#{EXTERNAL_ALIAS_MES}/ =~ line
1992:             checked = true
1993:             next
1994:           end
1995:         end
1996:         comment_block.unshift line
1997:       end
1998:       nice_lines = comment_block.join("\n")
1999:       nice_lines ||= ""
2000:       return nice_lines
2001:     end

devine code constructs

[Source]

     # File parsers/parse_f95.rb, line 402
402:     def scan
403: 
404:       # remove private comment
405:       remaining_code = remove_private_comments(@body)
406: 
407:       # continuation lines are united to one line
408:       remaining_code = united_to_one_line(remaining_code)
409: 
410:       # semicolons are replaced to line feed
411:       remaining_code = semicolon_to_linefeed(remaining_code)
412: 
413:       # collect comment for file entity
414:       whole_comment, remaining_code = collect_first_comment(remaining_code)
415:       @top_level.comment = whole_comment
416: 
417:       # String "remaining_code" is converted to Array "remaining_lines"
418:       remaining_lines = remaining_code.split("\n")
419: 
420:       # "module" or "program" parts are parsed (new)
421:       #
422:       level_depth = 0
423:       block_searching_flag = nil
424:       block_searching_lines = []
425:       pre_comment = []
426:       module_program_trailing = ""
427:       module_program_name = ""
428:       other_block_level_depth = 0
429:       other_block_searching_flag = nil
430:       remaining_lines.collect!{|line|
431:         if !block_searching_flag && !other_block_searching_flag
432:           if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i
433:             block_searching_flag = :module
434:             block_searching_lines << line
435:             module_program_name = $1
436:             module_program_trailing = find_comments($2)
437:             next false
438:           elsif line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i ||
439:                  line =~ /^\s*?\w/ && !block_start?(line)
440:             block_searching_flag = :program
441:             block_searching_lines << line
442:             module_program_name = $1 || ""
443:             module_program_trailing = find_comments($2)
444:             next false
445: 
446:           elsif block_start?(line)
447:             other_block_searching_flag = true
448:             next line
449: 
450:           elsif line =~ /^\s*?!\s?(.*)/
451:             pre_comment << line
452:             next line
453:           else
454:             pre_comment = []
455:             next line
456:           end
457:         elsif other_block_searching_flag
458:           other_block_level_depth += 1 if block_start?(line)
459:           other_block_level_depth -= 1 if block_end?(line)
460:           if other_block_level_depth < 0
461:             other_block_level_depth = 0
462:             other_block_searching_flag = nil
463:           end
464:           next line
465:         end
466: 
467:         block_searching_lines << line
468:         level_depth += 1 if block_start?(line)
469:         level_depth -= 1 if block_end?(line)
470:         if level_depth >= 0
471:           next false
472:         end
473: 
474:         # "module_program_code" is formatted.
475:         # ":nodoc:" flag is checked.
476:         #
477:         module_program_code = block_searching_lines.join("\n")
478:         module_program_code = remove_empty_head_lines(module_program_code)
479:         if module_program_trailing =~ /^:nodoc:/
480:           # next loop to search next block
481:           level_depth = 0
482:           block_searching_flag = false
483:           block_searching_lines = []
484:           pre_comment = []
485:           next false
486:         end
487: 
488:         # NormalClass is created, and added to @top_level
489:         #
490:         if block_searching_flag == :module
491:           module_name = module_program_name
492:           module_code = module_program_code
493:           module_trailing = module_program_trailing
494:           progress "m"
495:           @stats.num_modules += 1
496:           f9x_module = @top_level.add_module NormalClass, module_name
497:           f9x_module.record_location @top_level
498: 
499:           #
500:           # Add provided modules information to @top_level comment
501:           #
502:           provided_modules = []
503:           provided_mes_line_num = nil
504:           top_level_comment_lines = []
505:           line_num = 0
506:           @top_level.comment.split("\n").each{|line|
507:             top_level_comment_lines << line
508:             line_num += 1
509:             next if line.empty?
510:             if !provided_mes_line_num && /^\s?#{PROVIDED_MODULES_MES}/ =~ line
511:               provided_mes_line_num = line_num
512:               next
513:             end
514:             if provided_mes_line_num
515:               if /^\s?\*\s+<b>(\w+)<\/b>/ =~ line
516:                 provided_modules << $1
517:               else
518:                 provided_mes_line_num = nil
519:               end
520:             end
521:           }
522:           line_num = 0
523:           if provided_mes_line_num
524:             top_level_comment_lines.collect!{ |line|
525:               line_num += 1
526:               if line_num < provided_mes_line_num
527:                 line
528:               else
529:                 nil
530:               end
531:             }
532:             top_level_comment_lines.delete_if{|line| !line }
533:           end
534:           top_level_comment_lines << "\n" + PROVIDED_MODULES_MES + "."
535:           if provided_mes_line_num
536:             top_level_comment_lines[-1].sub!(/\.$/, '')
537:             top_level_comment_lines[-1] << "s."
538:           end
539:           provided_modules.each{ |mod|
540:             top_level_comment_lines << "* <b>" + mod + "</b>"
541:           }
542:           top_level_comment_lines << "* <b>" + module_name + "</b>"
543:           @top_level.comment = top_level_comment_lines.join("\n")
544: 
545:           #
546:           # Information about the module is parsed
547:           #
548:           f9x_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) +
549:             "\n" + module_trailing : module_trailing + "\n" +
550:             find_comments(module_code.sub(/^.*$\n/i, ''))
551:           f9x_module.comment = f9x_comment
552:           parse_program_or_module(f9x_module, module_code)
553: 
554:           TopLevel.all_files.each do |name, toplevel|
555:             if toplevel.include_includes?(module_name, @options.ignore_case)
556:               if !toplevel.include_requires?(@file_name, @options.ignore_case)
557:                 toplevel.add_require(Require.new(@file_name, ""))
558:               end
559:             end
560:             toplevel.each_classmodule{|m|
561:               if m.include_includes?(module_name, @options.ignore_case)
562:                 if !m.include_requires?(@file_name, @options.ignore_case)
563:                   m.add_require(Require.new(@file_name, ""))
564:                 end
565:               end
566:             }
567:           end
568: 
569:           namelist_comment = 
570:             find_namelists(f9x_module, before_contains(module_code))
571:           f9x_module.comment << namelist_comment if namelist_comment
572: 
573:         elsif block_searching_flag == :program
574:           program_name = module_program_name
575:           program_name = "main_program" if program_name.empty?
576:           program_code = module_program_code
577:           program_trailing = module_program_trailing
578:           program_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) + 
579:             "\n" + program_trailing : program_trailing + "\n" + 
580:             find_comments(program_code.sub(/^.*$\n/i, ''))
581: 
582:           progress "p"
583:           @stats.num_methods += 1
584:           f9x_mainprogram = AnyMethod.new("main_program", program_name)
585:           f9x_mainprogram.singleton = false
586:           f9x_mainprogram.comment = "<b><em> Main Program </em></b> :: <tt></tt>\n"
587:           f9x_mainprogram.comment << program_comment
588:           f9x_mainprogram.params = ""
589: 
590:           # For output source code
591:           f9x_mainprogram.start_collecting_tokens
592:           f9x_mainprogram.add_token Token.new(1,1).set_text(program_code)
593: 
594:           @top_level.add_method f9x_mainprogram
595:           parse_program_or_module(@top_level, program_code, :private)
596: 
597:           namelist_comment = find_namelists(f9x_mainprogram, program_code)
598:           f9x_mainprogram.comment << namelist_comment if namelist_comment
599:         end
600: 
601:         # next loop to search next block
602:         level_depth = 0
603:         block_searching_flag = false
604:         block_searching_lines = []
605:         pre_comment = []
606:         next false
607:       }
608: 
609:       remaining_lines.delete_if{ |line|
610:         line == false
611:       }
612: 
613:       # External subprograms and functions are parsed
614:       #
615:       # 単一のファイル内において program や module に格納されない,
616:       # 外部サブルーチン, 外部関数部分の解析.
617:       #
618:       parse_program_or_module(@top_level, remaining_lines.join("\n"),
619:                               :public, true)
620: 
621:       @top_level
622:     end

Semicolons are replaced to line feed.

[Source]

      # File parsers/parse_f95.rb, line 1886
1886:     def semicolon_to_linefeed(text)
1887:       return "" unless text
1888:       lines = text.split("\n")
1889:       lines.collect!{ |line|
1890:         indent_space = ""
1891:         if line =~ /^(\s+)/
1892:           indent_space = $1
1893:         end
1894:         words = line.split("")
1895:         commentout = false
1896:         squote = false ; dquote = false
1897:         words.collect! { |char|
1898:           if !(squote) && !(dquote) && !(commentout)
1899:             case char
1900:             when "!" ; commentout = true ; next char
1901:             when "\""; dquote = true     ; next char
1902:             when "\'"; squote = true     ; next char
1903:             when ";" ;                     "\n"+indent_space
1904:             else next char
1905:             end
1906:           elsif commentout
1907:             next char
1908:           elsif squote
1909:             case char
1910:             when "\'"; squote = false ; next char
1911:             else next char
1912:             end
1913:           elsif dquote
1914:             case char
1915:             when "\""; dquote = false ; next char
1916:             else next char
1917:             end
1918:           end
1919:         }
1920:         words.join("")
1921:       }
1922:       return lines.join("\n")
1923:     end

Set visibility

"subname" element of "visibility_info" is deleted.

[Source]

      # File parsers/parse_f95.rb, line 1644
1644:     def set_visibility(container, subname, visibility_default, visibility_info)
1645:       return unless container || subname || visibility_default || visibility_info
1646:       not_found = true
1647:       visibility_info.collect!{ |info|
1648:         if info["name"] == subname ||
1649:             @options.ignore_case && info["name"].upcase == subname.upcase
1650:           if info["file_or_module"].name == container.name
1651:             container.set_visibility_for([subname], info["visibility"])
1652:             info["entity_is_discovered"] = true
1653:             not_found = false
1654:           end
1655:         end
1656:         info
1657:       }
1658:       if not_found
1659:         return container.set_visibility_for([subname], visibility_default)
1660:       else
1661:         return container
1662:       end
1663:     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 1763
1763:     def united_to_one_line(f90src, delete_space=true)
1764:       return "" unless f90src
1765:       lines = f90src.split("\n")
1766:       previous_continuing = false
1767:       now_continuing = false
1768:       body = ""
1769:       lines.each{ |line|
1770:         words = line.split("")
1771:         next if words.empty? && previous_continuing
1772:         commentout = false
1773:         brank_flag = true ; brank_char = ""
1774:         squote = false    ; dquote = false
1775:         ignore = false
1776:         words.collect! { |char|
1777:           if previous_continuing && brank_flag
1778:             now_continuing = true
1779:             ignore         = true
1780:             case char
1781:             when "!"                       ; break
1782:             when " " ; brank_char << char  ; next ""
1783:             when "&"
1784:               brank_flag = false
1785:               now_continuing = false
1786:               next ""
1787:             else 
1788:               brank_flag     = false
1789:               now_continuing = false
1790:               ignore         = false
1791:               next brank_char + char
1792:             end
1793:           end
1794:           ignore = false
1795: 
1796:           if now_continuing
1797:             next ""
1798:           elsif !(squote) && !(dquote) && !(commentout)
1799:             case char
1800:             when "!" ; commentout = true     ; next char
1801:             when "\""; dquote = true         ; next char
1802:             when "\'"; squote = true         ; next char
1803:             when "&" ; now_continuing = true ; next ""
1804:             else next char
1805:             end
1806:           elsif commentout
1807:             next char
1808:           elsif squote
1809:             case char
1810:             when "\'"; squote = false ; next char
1811:             else next char
1812:             end
1813:           elsif dquote
1814:             case char
1815:             when "\""; dquote = false ; next char
1816:             else next char
1817:             end
1818:           end
1819:         }
1820:         if !ignore && !previous_continuing || !brank_flag
1821:           if previous_continuing
1822:             if delete_space
1823:               joined_words = words.join("")
1824:               body = body.rstrip + " " + joined_words.lstrip
1825:             else
1826:               body << words.join("")
1827:             end
1828:           else
1829:             body << "\n" + words.join("")
1830:           end
1831:         end
1832:         previous_continuing = now_continuing ? true : nil
1833:         now_continuing = nil
1834:       }
1835:       return body
1836:     end

[Validate]