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

Public Instance methods

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

[Source]

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

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

[Source]

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