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 400
400:     def initialize(top_level, file_name, body, options, stats)
401:       @body = body
402:       @stats = stats
403:       @file_name  = file_name
404:       @options = options
405:       @top_level = top_level
406:       @progress = $stderr unless options.quiet
407:     end

Public Instance methods

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

[Source]

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

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

[Source]

      # File parsers/parse_f95.rb, line 1975
1975:     def block_end?(line)
1976:       return nil if !line
1977: 
1978:       if line =~ /^\s*?end\s*?(!.*?)?$/i                 ||
1979:           line =~ /^\s*?end\s+module(\s+\w+)?\s*?(!.*?)?$/i       ||
1980:           line =~ /^\s*?end\s+program(\s+\w+)?\s*?(!.*?)?$/i      ||
1981:           line =~ /^\s*?end\s+block\s+data(\s+\w+)?\s*?(!.*?)?$/i  ||
1982:           line =~ /^\s*?end\s+subroutine(\s+\w+)?\s*?(!.*?)?$/i   ||
1983:           line =~ /^\s*?end\s+function(\s+\w+)?\s*?(!.*?)?$/i
1984:         return true
1985:       end
1986: 
1987:       return nil
1988:     end

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

[Source]

      # File parsers/parse_f95.rb, line 1939
1939:     def block_start?(line)
1940:       return nil if !line
1941: 
1942:       if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i    ||
1943:           line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i  ||
1944:           line =~ /^\s*?block\s+data(\s+\w+)?\s*?(!.*?)?$/i     ||
1945:           line =~ \
1946:                   /^\s*?
1947:                    (recursive|pure|elemental)?\s*?
1948:                    subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
1949:                   /ix ||
1950:           line =~ \
1951:                   /^\s*?
1952:                    (recursive|pure|elemental)?\s*?
1953:                    (
1954:                        character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1955:                      | type\s*?\([\w\s]+?\)\s+
1956:                      | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1957:                      | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1958:                      | double\s+precision\s+
1959:                      | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1960:                      | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1961:                    )?
1962:                    function\s+(\w+)\s*?
1963:                    (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
1964:                   /ix
1965:         return true
1966:       end
1967: 
1968:       return nil
1969:     end

Check external aliases

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

[Source]

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

Check public_methods

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

[Source]

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

Collect comment for file entity

[Source]

      # File parsers/parse_f95.rb, line 1339
1339:     def collect_first_comment(body)
1340:       comment = ""
1341:       not_comment = ""
1342:       comment_start = false
1343:       comment_end   = false
1344:       body.split("\n").each{ |line|
1345:         if comment_end
1346:           not_comment << line
1347:           not_comment << "\n"
1348:         elsif /^\s*?!\s?(.*)$/i =~ line
1349:           comment_start = true
1350:           comment << $1
1351:           comment << "\n"
1352:         elsif /^\s*?$/i =~ line
1353:           comment_end = true if comment_start && COMMENTS_ARE_UPPER
1354:         else
1355:           comment_end = true
1356:           not_comment << line
1357:           not_comment << "\n"
1358:         end
1359:       }
1360:       return comment, not_comment
1361:     end

Comment out checker

[Source]

      # File parsers/parse_f95.rb, line 1866
1866:     def comment_out?(line)
1867:       return nil unless line
1868:       commentout = false
1869:       squote = false ; dquote = false
1870:       line.split("").each { |char|
1871:         if !(squote) && !(dquote)
1872:           case char
1873:           when "!" ; commentout = true ; break
1874:           when "\""; dquote = true
1875:           when "\'"; squote = true
1876:           else next
1877:           end
1878:         elsif squote
1879:           case char
1880:           when "\'"; squote = false
1881:           else next
1882:           end
1883:         elsif dquote
1884:           case char
1885:           when "\""; dquote = false
1886:           else next
1887:           end
1888:         end
1889:       }
1890:       return commentout
1891:     end

Continuous line checker

[Source]

      # File parsers/parse_f95.rb, line 1852
1852:     def continuous_line?(line)
1853:       continuous = false
1854:       if /&\s*?(!.*)?$/ =~ line
1855:         continuous = true
1856:         if comment_out?($~.pre_match)
1857:           continuous = false
1858:         end
1859:       end
1860:       return continuous
1861:     end

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

[Source]

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

Return toplevel class of container

[Source]

      # File parsers/parse_f95.rb, line 1500
1500:     def find_toplevel(container)
1501:       top_level = container
1502:       while top_level.parent
1503:         top_level = top_level.parent
1504:       end
1505:       top_level
1506:     end

Find visibility

[Source]

      # File parsers/parse_f95.rb, line 1676
1676:     def find_visibility(container, subname, visibility_info)
1677:       return nil if !subname || !visibility_info
1678:       visibility_info.each{ |info|
1679:         if info["name"] == subname ||
1680:             @options.ignore_case && info["name"].upcase == subname.upcase
1681:           if info["parent"] == container.name
1682:             return info["visibility"]
1683:           end
1684:         end
1685:       }
1686:       return nil
1687:     end

Create method for external alias

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

[Source]

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

Create method for internal alias

[Source]

      # File parsers/parse_f95.rb, line 1541
1541:     def initialize_public_method(method, parent)
1542:       return if !method || !parent
1543: 
1544:       new_meth = AnyMethod.new("External Alias for module", method.name)
1545:       new_meth.singleton    = method.singleton
1546:       new_meth.params       = method.params.clone
1547:       new_meth.comment      = remove_trailing_alias(method.comment.clone)
1548:       new_meth.comment      << "\n\n#{EXTERNAL_ALIAS_MES} #{parent.strip.chomp}\##{method.name}"
1549: 
1550:       return new_meth
1551:     end

[Source]

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

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

[Source]

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

Parse visibility

[Source]

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

[Source]

      # File parsers/parse_f95.rb, line 1531
1531:     def progress(char)
1532:       unless @options.quiet
1533:         @progress.print(char)
1534:         @progress.flush
1535:       end
1536:     end

Empty lines in header are removed

[Source]

      # File parsers/parse_f95.rb, line 2014
2014:     def remove_empty_head_lines(text)
2015:       return "" unless text
2016:       lines = text.split("\n")
2017:       header = true
2018:       lines.delete_if{ |line|
2019:         header = false if /\S/ =~ line
2020:         header && /^\s*?$/ =~ line
2021:       }
2022:       lines.join("\n")
2023:     end

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

[Source]

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

[Source]

      # File parsers/parse_f95.rb, line 2031
2031:     def remove_private_comments(body)
2032:       body.gsub!(/^(\s*)!--\s*?$.*?^\s*!\+\+\s*?$/m, '\\1!')
2033:       return body
2034:     end

Remove "Alias for" in end of comments

[Source]

      # File parsers/parse_f95.rb, line 1993
1993:     def remove_trailing_alias(text)
1994:       return "" if !text
1995:       lines = text.split("\n").reverse
1996:       comment_block = Array.new
1997:       checked = false
1998:       lines.each do |line|
1999:         if !checked 
2000:           if /^\s?#{INTERNAL_ALIAS_MES}/ =~ line ||
2001:               /^\s?#{EXTERNAL_ALIAS_MES}/ =~ line
2002:             checked = true
2003:             next
2004:           end
2005:         end
2006:         comment_block.unshift line
2007:       end
2008:       nice_lines = comment_block.join("\n")
2009:       nice_lines ||= ""
2010:       return nice_lines
2011:     end

devine code constructs

[Source]

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

Semicolons are replaced to line feed.

[Source]

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

Set visibility

"subname" element of "visibility_info" is deleted.

[Source]

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

[Validate]