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 1964
1964:     def block_end?(line)
1965:       return nil if !line
1966: 
1967:       if line =~ /^\s*?end\s*?(!.*?)?$/i                 ||
1968:           line =~ /^\s*?end\s+module(\s+\w+)?\s*?(!.*?)?$/i       ||
1969:           line =~ /^\s*?end\s+program(\s+\w+)?\s*?(!.*?)?$/i      ||
1970:           line =~ /^\s*?end\s+block\s+data(\s+\w+)?\s*?(!.*?)?$/i  ||
1971:           line =~ /^\s*?end\s+subroutine(\s+\w+)?\s*?(!.*?)?$/i   ||
1972:           line =~ /^\s*?end\s+function(\s+\w+)?\s*?(!.*?)?$/i
1973:         return true
1974:       end
1975: 
1976:       return nil
1977:     end

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

[Source]

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

Check external aliases

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

[Source]

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

Check public_methods

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

[Source]

      # File parsers/parse_f95.rb, line 1716
1716:     def check_public_methods(method, parent)
1717:       return if !method || !parent
1718:       @@public_methods.each{ |alias_item|
1719:         parent_is_used_module = nil
1720:         alias_item["used_modules"].each{ |used_module|
1721:           if used_module == parent ||
1722:               used_module.upcase == parent.upcase &&
1723:               @options.ignore_case
1724:             parent_is_used_module = true
1725:           end
1726:         }
1727:         next if !parent_is_used_module
1728: 
1729:         if method.name == alias_item["name"] ||
1730:             method.name.upcase == alias_item["name"].upcase &&
1731:             @options.ignore_case
1732: 
1733:           new_meth = initialize_public_method(method, parent)
1734:           if alias_item["local_name"]
1735:             new_meth.name = alias_item["local_name"]
1736:           end
1737: 
1738:           progress "e"
1739:           @stats.num_methods += 1
1740:           alias_item["file_or_module"].add_method new_meth
1741:         end
1742:       }
1743:     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 1855
1855:     def comment_out?(line)
1856:       return nil unless line
1857:       commentout = false
1858:       squote = false ; dquote = false
1859:       line.split("").each { |char|
1860:         if !(squote) && !(dquote)
1861:           case char
1862:           when "!" ; commentout = true ; break
1863:           when "\""; dquote = true
1864:           when "\'"; squote = true
1865:           else next
1866:           end
1867:         elsif squote
1868:           case char
1869:           when "\'"; squote = false
1870:           else next
1871:           end
1872:         elsif dquote
1873:           case char
1874:           when "\""; dquote = false
1875:           else next
1876:           end
1877:         end
1878:       }
1879:       return commentout
1880:     end

Continuous line checker

[Source]

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

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

[Source]

      # File parsers/parse_f95.rb, line 2100
2100:     def definition_info(text)
2101:       return nil unless text
2102:       lines = "#{text}"
2103:       defs = Array.new
2104:       comment = ""
2105:       trailing_comment = ""
2106:       under_comment_valid = false
2107:       lines.split("\n").each{ |line|
2108:         if /^\s*?!\s?(.*)/ =~ line
2109:           if COMMENTS_ARE_UPPER
2110:             comment << remove_header_marker($1)
2111:             comment << "\n"
2112:           elsif defs[-1] && under_comment_valid
2113:             defs[-1].comment << "\n"
2114:             defs[-1].comment << remove_header_marker($1)
2115:           end
2116:           next
2117:         elsif /^\s*?$/ =~ line
2118:           comment = ""
2119:           under_comment_valid = false
2120:           next
2121:         end
2122:         type = ""
2123:         characters = ""
2124:         if line =~ /^\s*?
2125:                     (
2126:                         character\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2127:                       | type\s*?\([\w\s]+?\)[\s\,]*
2128:                       | integer\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2129:                       | real\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2130:                       | double\s+precision[\s\,]*
2131:                       | logical\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2132:                       | complex\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2133:                     )
2134:                     (.*?::)?
2135:                     (.+)$
2136:                    /ix
2137:           characters = $8
2138:           type = $1
2139:           type << $7.gsub(/::/, '').gsub(/^\s*?\,/, '') if $7
2140:         else
2141:           under_comment_valid = false
2142:           next
2143:         end
2144:         squote = false ; dquote = false ; bracket = 0
2145:         iniflag = false; commentflag = false
2146:         varname = "" ; arraysuffix = "" ; inivalue = ""
2147:         start_pos = defs.size
2148:         characters.split("").each { |char|
2149:           if !(squote) && !(dquote) && bracket <= 0 && !(iniflag) && !(commentflag)
2150:             case char
2151:             when "!" ; commentflag = true
2152:             when "(" ; bracket += 1       ; arraysuffix = char
2153:             when "\""; dquote = true
2154:             when "\'"; squote = true
2155:             when "=" ; iniflag = true     ; inivalue << char
2156:             when ","
2157:               defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2158:               varname = "" ; arraysuffix = "" ; inivalue = ""
2159:               under_comment_valid = true
2160:             when " " ; next
2161:             else     ; varname << char
2162:             end
2163:           elsif commentflag
2164:             comment << remove_header_marker(char)
2165:             trailing_comment << remove_header_marker(char)
2166:           elsif iniflag
2167:             if dquote
2168:               case char
2169:               when "\"" ; dquote = false ; inivalue << char
2170:               else      ; inivalue << char
2171:               end
2172:             elsif squote
2173:               case char
2174:               when "\'" ; squote = false ; inivalue << char
2175:               else      ; inivalue << char
2176:               end
2177:             elsif bracket > 0
2178:               case char
2179:               when "(" ; bracket += 1 ; inivalue << char
2180:               when ")" ; bracket -= 1 ; inivalue << char
2181:               else     ; inivalue << char
2182:               end
2183:             else
2184:               case char
2185:               when ","
2186:                 defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2187:                 varname = "" ; arraysuffix = "" ; inivalue = ""
2188:                 iniflag = false
2189:                 under_comment_valid = true
2190:               when "(" ; bracket += 1 ; inivalue << char
2191:               when "\""; dquote = true  ; inivalue << char
2192:               when "\'"; squote = true  ; inivalue << char
2193:               when "!" ; commentflag = true
2194:               else     ; inivalue << char
2195:               end
2196:             end
2197:           elsif !(squote) && !(dquote) && bracket > 0
2198:             case char
2199:             when "(" ; bracket += 1 ; arraysuffix << char
2200:             when ")" ; bracket -= 1 ; arraysuffix << char
2201:             else     ; arraysuffix << char
2202:             end
2203:           elsif squote
2204:             case char
2205:             when "\'"; squote = false ; inivalue << char
2206:             else     ; inivalue << char
2207:             end
2208:           elsif dquote
2209:             case char
2210:             when "\""; dquote = false ; inivalue << char
2211:             else     ; inivalue << char
2212:             end
2213:           end
2214:         }
2215:         defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2216:         if trailing_comment =~ /^:nodoc:/
2217:           defs[start_pos..-1].collect!{ |defitem|
2218:             defitem.nodoc = true
2219:           }
2220:         end
2221:         varname = "" ; arraysuffix = "" ; inivalue = ""
2222:         comment = ""
2223:         under_comment_valid = true
2224:         trailing_comment = ""
2225:       }
2226:       return defs
2227:     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 1504
1504:     def find_comments text
1505:       return "" unless text
1506:       lines = text.split("\n")
1507:       lines.reverse! if COMMENTS_ARE_UPPER
1508:       comment_block = Array.new
1509:       lines.each do |line|
1510:         break if line =~ /^\s*?\w/ || line =~ /^\s*?$/
1511:         if COMMENTS_ARE_UPPER
1512:           comment_block.unshift line.sub(/^\s*?!\s?/,"")
1513:         else
1514:           comment_block.push line.sub(/^\s*?!\s?/,"")
1515:         end
1516:       end
1517:       nice_lines = comment_block.join("\n").split "\n\s*?\n"
1518:       nice_lines[0] ||= ""
1519:       nice_lines.shift
1520:     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:         nml_vars_list  = $2.split(",")
1446:         nml_comment = COMMENTS_ARE_UPPER ? 
1447:             find_comments(pre_match.sub(/\n$/, '')) :
1448:             find_comments(post_match.sub(/^\n/, ''))
1449:         if lines.split("\n")[0] =~ /^\//i
1450:           lines = "namelist " + lines
1451:         end
1452: 
1453:         nml_meth = AnyMethod.new("NAMELIST", nml_group_name)
1454:         nml_meth.singleton = false
1455:         nml_meth.params    = "( " + nml_vars_list.join(", ") + " )"
1456:         nml_meth.comment   = "<b><em> NAMELIST </em></b> :: <tt></tt>\n"
1457:         nml_meth.comment   << find_arguments(nml_vars_list, "#{text}" + "\n" + before_contains)
1458:         nml_meth.comment   << "\n" + nml_comment if nml_comment
1459:         if container.parent.parent
1460:           parent_object = container.parent.name
1461:         else
1462:           parent_object = container.parent.file_relative_name
1463:         end
1464:         nml_meth.comment   << "\n\nThis namelist group name is input/output in "
1465:         nml_meth.comment   << parent_object + "#" + container.name
1466: 
1467:         progress "n"
1468:         @stats.num_methods += 1
1469:         namelist_module.add_method nml_meth
1470: 
1471:         nml_group_name_lists << NAMELIST_REPOSITORY_NAME + "#" + nml_group_name
1472:       end
1473: 
1474:       if !nml_group_name_lists.empty?
1475:         comments_in_procedures = "\n\nThis procedure input/output "
1476:         comments_in_procedures << nml_group_name_lists.join(", ") + " . "
1477:       else
1478:         comments_in_procedures = ""
1479:       end
1480: 
1481:       comments_in_procedures
1482:     end

Return toplevel class of container

[Source]

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

Find visibility

[Source]

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

Create method for external alias

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

[Source]

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

Create method for internal alias

[Source]

      # File parsers/parse_f95.rb, line 1532
1532:     def initialize_public_method(method, parent)
1533:       return if !method || !parent
1534: 
1535:       new_meth = AnyMethod.new("External Alias for module", method.name)
1536:       new_meth.singleton    = method.singleton
1537:       new_meth.params       = method.params.clone
1538:       new_meth.comment      = remove_trailing_alias(method.comment.clone)
1539:       new_meth.comment      << "\n\n#{EXTERNAL_ALIAS_MES} #{parent.strip.chomp}\##{method.name}"
1540: 
1541:       return new_meth
1542:     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 1582
1582:     def parse_visibility(code, default, container)
1583:       result = []
1584:       visibility_default = default || :public
1585: 
1586:       used_modules = []
1587:       container.includes.each{|i| used_modules << i.name} if container
1588: 
1589:       remaining_code = code.gsub(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
1590:       remaining_code.split("\n").each{ |line|
1591:         if /^\s*?private\s*?$/ =~ line
1592:           visibility_default = :private
1593:           break
1594:         end
1595:       } if remaining_code
1596: 
1597:       remaining_code.split("\n").each{ |line|
1598:         if /^\s*?private\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
1599:           methods = $2.sub(/!.*$/, '')
1600:           methods.split(",").each{ |meth|
1601:             meth.sub!(/!.*$/, '')
1602:             meth.gsub!(/:/, '')
1603:             result << {
1604:               "name" => meth.chomp.strip,
1605:               "visibility" => :private,
1606:               "used_modules" => used_modules.clone,
1607:               "file_or_module" => container,
1608:               "entity_is_discovered" => nil,
1609:               "local_name" => nil
1610:             }
1611:           }
1612:         elsif /^\s*?public\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
1613:           methods = $2.sub(/!.*$/, '')
1614:           methods.split(",").each{ |meth|
1615:             meth.sub!(/!.*$/, '')
1616:             meth.gsub!(/:/, '')
1617:             result << {
1618:               "name" => meth.chomp.strip,
1619:               "visibility" => :public,
1620:               "used_modules" => used_modules.clone,
1621:               "file_or_module" => container,
1622:               "entity_is_discovered" => nil,
1623:               "local_name" => nil
1624:             }
1625:           }
1626:         end
1627:       } if remaining_code
1628: 
1629:       if container
1630:         result.each{ |vis_info|
1631:           vis_info["parent"] = container.name
1632:         }
1633:       end
1634: 
1635:       return visibility_default, result
1636:     end

[Source]

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

Empty lines in header are removed

[Source]

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

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

[Source]

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

[Source]

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

Remove "Alias for" in end of comments

[Source]

      # File parsers/parse_f95.rb, line 1982
1982:     def remove_trailing_alias(text)
1983:       return "" if !text
1984:       lines = text.split("\n").reverse
1985:       comment_block = Array.new
1986:       checked = false
1987:       lines.each do |line|
1988:         if !checked 
1989:           if /^\s?#{INTERNAL_ALIAS_MES}/ =~ line ||
1990:               /^\s?#{EXTERNAL_ALIAS_MES}/ =~ line
1991:             checked = true
1992:             next
1993:           end
1994:         end
1995:         comment_block.unshift line
1996:       end
1997:       nice_lines = comment_block.join("\n")
1998:       nice_lines ||= ""
1999:       return nice_lines
2000:     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> :\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 1885
1885:     def semicolon_to_linefeed(text)
1886:       return "" unless text
1887:       lines = text.split("\n")
1888:       lines.collect!{ |line|
1889:         indent_space = ""
1890:         if line =~ /^(\s+)/
1891:           indent_space = $1
1892:         end
1893:         words = line.split("")
1894:         commentout = false
1895:         squote = false ; dquote = false
1896:         words.collect! { |char|
1897:           if !(squote) && !(dquote) && !(commentout)
1898:             case char
1899:             when "!" ; commentout = true ; next char
1900:             when "\""; dquote = true     ; next char
1901:             when "\'"; squote = true     ; next char
1902:             when ";" ;                     "\n"+indent_space
1903:             else next char
1904:             end
1905:           elsif commentout
1906:             next char
1907:           elsif squote
1908:             case char
1909:             when "\'"; squote = false ; next char
1910:             else next char
1911:             end
1912:           elsif dquote
1913:             case char
1914:             when "\""; dquote = false ; next char
1915:             else next char
1916:             end
1917:           end
1918:         }
1919:         words.join("")
1920:       }
1921:       return lines.join("\n")
1922:     end

Set visibility

"subname" element of "visibility_info" is deleted.

[Source]

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

[Validate]