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 = "The entity is"   External alias message

Public Class methods

prepare to parse a Fortran 95 file

[Source]

     # File parsers/parse_f95.rb, line 397
397:     def initialize(top_level, file_name, body, options, stats)
398:       @body = body
399:       @stats = stats
400:       @file_name  = file_name
401:       @options = options
402:       @top_level = top_level
403:       @progress = $stderr unless options.quiet
404:     end

Public Instance methods

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

[Source]

      # File parsers/parse_f95.rb, line 1802
1802:     def block_end?(line)
1803:       return nil if !line
1804: 
1805:       if line =~ /^\s*?end\s*?(!.*?)?$/i                 ||
1806:           line =~ /^\s*?end\s+module(\s+\w+)?\s*?(!.*?)?$/i       ||
1807:           line =~ /^\s*?end\s+program(\s+\w+)?\s*?(!.*?)?$/i      ||
1808:           line =~ /^\s*?end\s+block\s+data(\s+\w+)?\s*?(!.*?)?$/i  ||
1809:           line =~ /^\s*?end\s+subroutine(\s+\w+)?\s*?(!.*?)?$/i   ||
1810:           line =~ /^\s*?end\s+function(\s+\w+)?\s*?(!.*?)?$/i
1811:         return true
1812:       end
1813: 
1814:       return nil
1815:     end

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

[Source]

      # File parsers/parse_f95.rb, line 1766
1766:     def block_start?(line)
1767:       return nil if !line
1768: 
1769:       if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i    ||
1770:           line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i  ||
1771:           line =~ /^\s*?block\s+data(\s+\w+)?\s*?(!.*?)?$/i     ||
1772:           line =~ \
1773:                   /^\s*?
1774:                    (recursive|pure|elemental)?\s*?
1775:                    subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
1776:                   /ix ||
1777:           line =~ \
1778:                   /^\s*?
1779:                    (recursive|pure|elemental)?\s*?
1780:                    (
1781:                        character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1782:                      | type\s*?\([\w\s]+?\)\s+
1783:                      | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1784:                      | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1785:                      | double\s+precision\s+
1786:                      | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1787:                      | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1788:                    )?
1789:                    function\s+(\w+)\s*?
1790:                    (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
1791:                   /ix
1792:         return true
1793:       end
1794: 
1795:       return nil
1796:     end

Check external aliases

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

[Source]

      # File parsers/parse_f95.rb, line 1545
1545:     def check_external_aliases(subname, params, comment, test=nil)
1546:       @@external_aliases.each{ |alias_item|
1547:         if subname == alias_item["old_name"] ||
1548:                     subname.upcase == alias_item["old_name"].upcase &&
1549:                             @options.ignore_case
1550: 
1551:           new_meth = initialize_external_method(alias_item["new_name"], 
1552:                                                 subname, params, @file_name, 
1553:                                                 comment)
1554:           new_meth.visibility = alias_item["visibility"]
1555: 
1556:           progress "e"
1557:           @stats.num_methods += 1
1558:           alias_item["file_or_module"].add_method(new_meth)
1559: 
1560:           if !alias_item["file_or_module"].include_requires?(@file_name, @options.ignore_case)
1561:             alias_item["file_or_module"].add_require(Require.new(@file_name, ""))
1562:           end
1563:         end
1564:       }
1565:     end

Check public_methods

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

[Source]

      # File parsers/parse_f95.rb, line 1575
1575:     def check_public_methods(method, parent)
1576:       return if !method || !parent
1577:       @@public_methods.each{ |alias_item|
1578:         parent_is_used_module = nil
1579:         alias_item["used_modules"].each{ |used_module|
1580:           if used_module == parent ||
1581:               used_module.upcase == parent.upcase &&
1582:               @options.ignore_case
1583:             parent_is_used_module = true
1584:           end
1585:         }
1586:         next if !parent_is_used_module
1587: 
1588:         if method.name == alias_item["name"] ||
1589:             method.name.upcase == alias_item["name"].upcase &&
1590:             @options.ignore_case
1591: 
1592:           new_meth = initialize_public_method(method, parent)
1593:           if alias_item["local_name"]
1594:             new_meth.name = alias_item["local_name"]
1595:           end
1596: 
1597:           progress "e"
1598:           @stats.num_methods += 1
1599:           alias_item["file_or_module"].add_method new_meth
1600:         end
1601:       }
1602:     end

Collect comment for file entity

[Source]

      # File parsers/parse_f95.rb, line 1251
1251:     def collect_first_comment(body)
1252:       comment = ""
1253:       not_comment = ""
1254:       comment_start = false
1255:       comment_end   = false
1256:       body.split("\n").each{ |line|
1257:         if comment_end
1258:           not_comment << line
1259:           not_comment << "\n"
1260:         elsif /^\s*?!\s?(.*)$/i =~ line
1261:           comment_start = true
1262:           comment << $1
1263:           comment << "\n"
1264:         elsif /^\s*?$/i =~ line
1265:           comment_end = true if comment_start && COMMENTS_ARE_UPPER
1266:         else
1267:           comment_end = true
1268:           not_comment << line
1269:           not_comment << "\n"
1270:         end
1271:       }
1272:       return comment, not_comment
1273:     end

Comment out checker

[Source]

      # File parsers/parse_f95.rb, line 1697
1697:     def comment_out?(line)
1698:       return nil unless line
1699:       commentout = false
1700:       squote = false ; dquote = false
1701:       line.split("").each { |char|
1702:         if !(squote) && !(dquote)
1703:           case char
1704:           when "!" ; commentout = true ; break
1705:           when "\""; dquote = true
1706:           when "\'"; squote = true
1707:           else next
1708:           end
1709:         elsif squote
1710:           case char
1711:           when "\'"; squote = false
1712:           else next
1713:           end
1714:         elsif dquote
1715:           case char
1716:           when "\""; dquote = false
1717:           else next
1718:           end
1719:         end
1720:       }
1721:       return commentout
1722:     end

Continuous line checker

[Source]

      # File parsers/parse_f95.rb, line 1683
1683:     def continuous_line?(line)
1684:       continuous = false
1685:       if /&\s*?(!.*)?$/ =~ line
1686:         continuous = true
1687:         if comment_out?($~.pre_match)
1688:           continuous = false
1689:         end
1690:       end
1691:       return continuous
1692:     end

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

[Source]

      # File parsers/parse_f95.rb, line 1938
1938:     def definition_info(text)
1939:       return nil unless text
1940:       lines = "#{text}"
1941:       defs = Array.new
1942:       comment = ""
1943:       trailing_comment = ""
1944:       under_comment_valid = false
1945:       lines.split("\n").each{ |line|
1946:         if /^\s*?!\s?(.*)/ =~ line
1947:           if COMMENTS_ARE_UPPER
1948:             comment << remove_header_marker($1)
1949:             comment << "\n"
1950:           elsif defs[-1] && under_comment_valid
1951:             defs[-1].comment << "\n"
1952:             defs[-1].comment << remove_header_marker($1)
1953:           end
1954:           next
1955:         elsif /^\s*?$/ =~ line
1956:           comment = ""
1957:           under_comment_valid = false
1958:           next
1959:         end
1960:         type = ""
1961:         characters = ""
1962:         if line =~ /^\s*?
1963:                     (
1964:                         character\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
1965:                       | type\s*?\([\w\s]+?\)[\s\,]*
1966:                       | integer\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
1967:                       | real\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
1968:                       | double\s+precision[\s\,]*
1969:                       | logical\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
1970:                       | complex\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
1971:                     )
1972:                     (.*?::)?
1973:                     (.+)$
1974:                    /ix
1975:           characters = $8
1976:           type = $1
1977:           type << $7.gsub(/::/, '').gsub(/^\s*?\,/, '') if $7
1978:         else
1979:           under_comment_valid = false
1980:           next
1981:         end
1982:         squote = false ; dquote = false ; bracket = 0
1983:         iniflag = false; commentflag = false
1984:         varname = "" ; arraysuffix = "" ; inivalue = ""
1985:         start_pos = defs.size
1986:         characters.split("").each { |char|
1987:           if !(squote) && !(dquote) && bracket <= 0 && !(iniflag) && !(commentflag)
1988:             case char
1989:             when "!" ; commentflag = true
1990:             when "(" ; bracket += 1       ; arraysuffix = char
1991:             when "\""; dquote = true
1992:             when "\'"; squote = true
1993:             when "=" ; iniflag = true     ; inivalue << char
1994:             when ","
1995:               defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
1996:               varname = "" ; arraysuffix = "" ; inivalue = ""
1997:               under_comment_valid = true
1998:             when " " ; next
1999:             else     ; varname << char
2000:             end
2001:           elsif commentflag
2002:             comment << remove_header_marker(char)
2003:             trailing_comment << remove_header_marker(char)
2004:           elsif iniflag
2005:             if dquote
2006:               case char
2007:               when "\"" ; dquote = false ; inivalue << char
2008:               else      ; inivalue << char
2009:               end
2010:             elsif squote
2011:               case char
2012:               when "\'" ; squote = false ; inivalue << char
2013:               else      ; inivalue << char
2014:               end
2015:             elsif bracket > 0
2016:               case char
2017:               when "(" ; bracket += 1 ; inivalue << char
2018:               when ")" ; bracket -= 1 ; inivalue << char
2019:               else     ; inivalue << char
2020:               end
2021:             else
2022:               case char
2023:               when ","
2024:                 defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2025:                 varname = "" ; arraysuffix = "" ; inivalue = ""
2026:                 iniflag = false
2027:                 under_comment_valid = true
2028:               when "(" ; bracket += 1 ; inivalue << char
2029:               when "\""; dquote = true  ; inivalue << char
2030:               when "\'"; squote = true  ; inivalue << char
2031:               when "!" ; commentflag = true
2032:               else     ; inivalue << char
2033:               end
2034:             end
2035:           elsif !(squote) && !(dquote) && bracket > 0
2036:             case char
2037:             when "(" ; bracket += 1 ; arraysuffix << char
2038:             when ")" ; bracket -= 1 ; arraysuffix << char
2039:             else     ; arraysuffix << char
2040:             end
2041:           elsif squote
2042:             case char
2043:             when "\'"; squote = false ; inivalue << char
2044:             else     ; inivalue << char
2045:             end
2046:           elsif dquote
2047:             case char
2048:             when "\""; dquote = false ; inivalue << char
2049:             else     ; inivalue << char
2050:             end
2051:           end
2052:         }
2053:         defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2054:         if trailing_comment =~ /^:nodoc:/
2055:           defs[start_pos..-1].collect!{ |defitem|
2056:             defitem.nodoc = true
2057:           }
2058:         end
2059:         varname = "" ; arraysuffix = "" ; inivalue = ""
2060:         comment = ""
2061:         under_comment_valid = true
2062:         trailing_comment = ""
2063:       }
2064:       return defs
2065:     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 1282
1282:     def find_arguments(args, text, all=nil, indent=nil, modified_params=nil)
1283:       return unless args || all
1284:       indent = "" unless indent
1285:       args = ["all"] if all
1286:       params = "" if modified_params
1287:       comma = ""
1288:       return unless text
1289:       args_rdocforms = "\n"
1290:       remaining_lines = "#{text}"
1291:       definitions = definition_info(remaining_lines)
1292:       args.each{ |arg|
1293:         arg.strip!
1294:         arg.chomp!
1295:         definitions.each { |defitem|
1296:           if arg == defitem.varname.strip.chomp || all
1297:             args_rdocforms << "\n\#{indent}<tt><b>\#{defitem.varname.chomp.strip}\#{defitem.arraysuffix}</b> \#{defitem.inivalue}</tt> ::\n\#{indent}   <tt>\#{defitem.types.chomp.strip}</tt>\n"
1298:             if !defitem.comment.chomp.strip.empty?
1299:               comment = ""
1300:               defitem.comment.split("\n").each{ |line|
1301:                 comment << "       " + line + "\n"
1302:               }
1303:               args_rdocforms << "\n\#{indent}   <tt></tt> ::\n\#{indent}       <tt></tt>\n\#{indent}       \#{comment.chomp.strip}\n"
1304:             end
1305: 
1306:             if modified_params
1307:               if defitem.include_attr?("optional")
1308:                 params << "#{comma}[#{arg}]"
1309:               else
1310:                 params << "#{comma}#{arg}"
1311:               end
1312:               comma = ", "
1313:             end
1314:           end
1315:         }
1316:       }
1317:       if modified_params
1318:         return args_rdocforms, params
1319:       else
1320:         return args_rdocforms
1321:       end
1322:     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 1363
1363:     def find_comments text
1364:       return "" unless text
1365:       lines = text.split("\n")
1366:       lines.reverse! if COMMENTS_ARE_UPPER
1367:       comment_block = Array.new
1368:       lines.each do |line|
1369:         break if line =~ /^\s*?\w/ || line =~ /^\s*?$/
1370:         if COMMENTS_ARE_UPPER
1371:           comment_block.unshift line.sub(/^\s*?!\s?/,"")
1372:         else
1373:           comment_block.push line.sub(/^\s*?!\s?/,"")
1374:         end
1375:       end
1376:       nice_lines = comment_block.join("\n").split "\n\s*?\n"
1377:       nice_lines[0] ||= ""
1378:       nice_lines.shift
1379:     end

Return comments of definitions of namelists

[Source]

      # File parsers/parse_f95.rb, line 1337
1337:     def find_namelists(text, before_contains=nil)
1338:       return nil if !text
1339:       result = ""
1340:       lines = "#{text}"
1341:       before_contains = "" if !before_contains
1342:       while lines =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)$/i
1343:         lines = $~.post_match
1344:         nml_comment = COMMENTS_ARE_UPPER ? 
1345:             find_comments($~.pre_match) : find_comments($~.post_match)
1346:         nml_name = $1
1347:         nml_args = $2.split(",")
1348:         result << "\n\n=== NAMELIST <tt><b>" + nml_name + "</tt></b>\n\n"
1349:         result << nml_comment + "\n" if nml_comment
1350:         if lines.split("\n")[0] =~ /^\//i
1351:           lines = "namelist " + lines
1352:         end
1353:         result << find_arguments(nml_args, "#{text}" + "\n" + before_contains)
1354:       end
1355:       return result
1356:     end

Find visibility

[Source]

      # File parsers/parse_f95.rb, line 1526
1526:     def find_visibility(container, subname, visibility_info)
1527:       return nil if !subname || !visibility_info
1528:       visibility_info.each{ |info|
1529:         if info["name"] == subname ||
1530:             @options.ignore_case && info["name"].upcase == subname.upcase
1531:           if info["parent"] == container.name
1532:             return info["visibility"]
1533:           end
1534:         end
1535:       }
1536:       return nil
1537:     end

Create method for external alias

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

[Source]

      # File parsers/parse_f95.rb, line 1408
1408:     def initialize_external_method(new, old, params, file, comment, token=nil,
1409:                                    internal=nil, nolink=nil)
1410:       return nil unless new || old
1411: 
1412:       if internal
1413:         external_alias_header = "#{INTERNAL_ALIAS_MES} "
1414:         external_alias_text   = external_alias_header + old 
1415:       elsif file
1416:         external_alias_header = "#{EXTERNAL_ALIAS_MES} "
1417:         external_alias_text   = external_alias_header + file + "#" + old
1418:       else
1419:         return nil
1420:       end
1421:       external_meth = AnyMethod.new(external_alias_text, new)
1422:       external_meth.singleton    = false
1423:       external_meth.params       = params
1424:       external_comment = remove_trailing_alias(comment) + "\n\n" if comment
1425:       external_meth.comment = external_comment || ""
1426:       if nolink && token
1427:         external_meth.start_collecting_tokens
1428:         external_meth.add_token Token.new(1,1).set_text(token)
1429:       else
1430:         external_meth.comment << external_alias_text
1431:       end
1432: 
1433:       return external_meth
1434:     end

Create method for internal alias

[Source]

      # File parsers/parse_f95.rb, line 1391
1391:     def initialize_public_method(method, parent)
1392:       return if !method || !parent
1393: 
1394:       new_meth = AnyMethod.new("External Alias for module", method.name)
1395:       new_meth.singleton    = method.singleton
1396:       new_meth.params       = method.params.clone
1397:       new_meth.comment      = remove_trailing_alias(method.comment.clone)
1398:       new_meth.comment      << "\n\n#{EXTERNAL_ALIAS_MES} #{parent.strip.chomp}\##{method.name}"
1399: 
1400:       return new_meth
1401:     end

[Source]

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

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

[Source]

      # File parsers/parse_f95.rb, line 1219
1219:     def parse_subprogram(subprogram, params, comment, code, 
1220:                          before_contains=nil, function=nil, prefix=nil)
1221:       subprogram.singleton = false
1222:       prefix = "" if !prefix
1223:       arguments = params.sub(/\(/, "").sub(/\)/, "").split(",") if params
1224:       args_comment, params_opt = 
1225:         find_arguments(arguments, code.sub(/^s*?contains\s*?(!.*?)?$.*/im, ""),
1226:                        nil, nil, true)
1227:       params_opt = "( " + params_opt + " ) " if params_opt
1228:       subprogram.params = params_opt || ""
1229:       namelist_comment = find_namelists(code, before_contains)
1230: 
1231:       block_comment = find_comments comment
1232:       if function
1233:         subprogram.comment = "<b><em> Function </em></b> :: <em>#{prefix}</em>\n"
1234:       else
1235:         subprogram.comment = "<b><em> Subroutine </em></b> :: <em>#{prefix}</em>\n"
1236:       end
1237:       subprogram.comment << args_comment if args_comment
1238:       subprogram.comment << block_comment if block_comment
1239:       subprogram.comment << namelist_comment if namelist_comment
1240: 
1241:       # For output source code
1242:       subprogram.start_collecting_tokens
1243:       subprogram.add_token Token.new(1,1).set_text(code)
1244: 
1245:       subprogram
1246:     end

Parse visibility

[Source]

      # File parsers/parse_f95.rb, line 1441
1441:     def parse_visibility(code, default, container)
1442:       result = []
1443:       visibility_default = default || :public
1444: 
1445:       used_modules = []
1446:       container.includes.each{|i| used_modules << i.name} if container
1447: 
1448:       remaining_code = code.gsub(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
1449:       remaining_code.split("\n").each{ |line|
1450:         if /^\s*?private\s*?$/ =~ line
1451:           visibility_default = :private
1452:           break
1453:         end
1454:       } if remaining_code
1455: 
1456:       remaining_code.split("\n").each{ |line|
1457:         if /^\s*?private\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
1458:           methods = $2.sub(/!.*$/, '')
1459:           methods.split(",").each{ |meth|
1460:             meth.sub!(/!.*$/, '')
1461:             meth.gsub!(/:/, '')
1462:             result << {
1463:               "name" => meth.chomp.strip,
1464:               "visibility" => :private,
1465:               "used_modules" => used_modules.clone,
1466:               "file_or_module" => container,
1467:               "entity_is_discovered" => nil,
1468:               "local_name" => nil
1469:             }
1470:           }
1471:         elsif /^\s*?public\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
1472:           methods = $2.sub(/!.*$/, '')
1473:           methods.split(",").each{ |meth|
1474:             meth.sub!(/!.*$/, '')
1475:             meth.gsub!(/:/, '')
1476:             result << {
1477:               "name" => meth.chomp.strip,
1478:               "visibility" => :public,
1479:               "used_modules" => used_modules.clone,
1480:               "file_or_module" => container,
1481:               "entity_is_discovered" => nil,
1482:               "local_name" => nil
1483:             }
1484:           }
1485:         end
1486:       } if remaining_code
1487: 
1488:       if container
1489:         result.each{ |vis_info|
1490:           vis_info["parent"] = container.name
1491:         }
1492:       end
1493: 
1494:       return visibility_default, result
1495:     end

[Source]

      # File parsers/parse_f95.rb, line 1381
1381:     def progress(char)
1382:       unless @options.quiet
1383:         @progress.print(char)
1384:         @progress.flush
1385:       end
1386:     end

Empty lines in header are removed

[Source]

      # File parsers/parse_f95.rb, line 1841
1841:     def remove_empty_head_lines(text)
1842:       return "" unless text
1843:       lines = text.split("\n")
1844:       header = true
1845:       lines.delete_if{ |line|
1846:         header = false if /\S/ =~ line
1847:         header && /^\s*?$/ =~ line
1848:       }
1849:       lines.join("\n")
1850:     end

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

[Source]

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

[Source]

      # File parsers/parse_f95.rb, line 1858
1858:     def remove_private_comments(body)
1859:       body.gsub!(/^\s*!--\s*?$.*?^\s*!\+\+\s*?$/m, '')
1860:       return body
1861:     end

Remove "Alias for" in end of comments

[Source]

      # File parsers/parse_f95.rb, line 1820
1820:     def remove_trailing_alias(text)
1821:       return "" if !text
1822:       lines = text.split("\n").reverse
1823:       comment_block = Array.new
1824:       checked = false
1825:       lines.each do |line|
1826:         if !checked 
1827:           if /^\s?#{INTERNAL_ALIAS_MES}/ =~ line ||
1828:               /^\s?#{EXTERNAL_ALIAS_MES}/ =~ line
1829:             checked = true
1830:             next
1831:           end
1832:         end
1833:         comment_block.unshift line
1834:       end
1835:       nice_lines = comment_block.join("\n")
1836:       nice_lines ||= ""
1837:       return nice_lines
1838:     end

devine code constructs

[Source]

     # File parsers/parse_f95.rb, line 407
407:     def scan
408: 
409:       # remove private comment
410:       remaining_code = remove_private_comments(@body)
411: 
412:       # continuation lines are united to one line
413:       remaining_code = united_to_one_line(remaining_code)
414: 
415:       # semicolons are replaced to line feed
416:       remaining_code = semicolon_to_linefeed(remaining_code)
417: 
418:       # collect comment for file entity
419:       whole_comment, remaining_code = collect_first_comment(remaining_code)
420:       @top_level.comment = whole_comment
421: 
422:       # String "remaining_code" is converted to Array "remaining_lines"
423:       remaining_lines = remaining_code.split("\n")
424: 
425:       # "module" or "program" parts are parsed (new)
426:       #
427:       level_depth = 0
428:       block_searching_flag = nil
429:       block_searching_lines = []
430:       pre_comment = []
431:       module_program_trailing = ""
432:       module_program_name = ""
433:       other_block_level_depth = 0
434:       other_block_searching_flag = nil
435:       remaining_lines.collect!{|line|
436:         if !block_searching_flag && !other_block_searching_flag
437:           if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i
438:             block_searching_flag = :module
439:             block_searching_lines << line
440:             module_program_name = $1
441:             module_program_trailing = find_comments($2)
442:             next false
443:           elsif line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i ||
444:                  line =~ /^\s*?\w/ && !block_start?(line)
445:             block_searching_flag = :program
446:             block_searching_lines << line
447:             module_program_name = $1 || ""
448:             module_program_trailing = find_comments($2)
449:             next false
450: 
451:           elsif block_start?(line)
452:             other_block_searching_flag = true
453:             next line
454: 
455:           elsif line =~ /^\s*?!\s?(.*)/
456:             pre_comment << line
457:             next line
458:           else
459:             pre_comment = []
460:             next line
461:           end
462:         elsif other_block_searching_flag
463:           other_block_level_depth += 1 if block_start?(line)
464:           other_block_level_depth -= 1 if block_end?(line)
465:           if other_block_level_depth < 0
466:             other_block_level_depth = 0
467:             other_block_searching_flag = nil
468:           end
469:           next line
470:         end
471: 
472:         block_searching_lines << line
473:         level_depth += 1 if block_start?(line)
474:         level_depth -= 1 if block_end?(line)
475:         if level_depth >= 0
476:           next false
477:         end
478: 
479:         # "module_program_code" is formatted.
480:         # ":nodoc:" flag is checked.
481:         #
482:         module_program_code = block_searching_lines.join("\n")
483:         module_program_code = remove_empty_head_lines(module_program_code)
484:         if module_program_trailing =~ /^:nodoc:/
485:           # next loop to search next block
486:           level_depth = 0
487:           block_searching_flag = false
488:           block_searching_lines = []
489:           pre_comment = []
490:           next false
491:         end
492: 
493:         # NormalClass is created, and added to @top_level
494:         #
495:         if block_searching_flag == :module
496:           module_name = module_program_name
497:           module_code = module_program_code
498:           module_trailing = module_program_trailing
499:           progress "m"
500:           @stats.num_modules += 1
501:           f9x_module = @top_level.add_module NormalClass, module_name
502:           f9x_module.record_location @top_level
503: 
504:           f9x_comment = COMMENTS_ARE_UPPER ? 
505:             find_comments(pre_comment.join("\n"))  + "\n" + module_trailing :
506:               module_trailing + "\n" + find_comments(module_code.sub(/^.*$\n/i, ''))
507:           f9x_module.comment = f9x_comment
508:           parse_program_or_module(f9x_module, module_code)
509: 
510:           TopLevel.all_files.each do |name, toplevel|
511:             if toplevel.include_includes?(module_name, @options.ignore_case)
512:               if !toplevel.include_requires?(@file_name, @options.ignore_case)
513:                 toplevel.add_require(Require.new(@file_name, ""))
514:               end
515:             end
516:             toplevel.each_classmodule{|m|
517:               if m.include_includes?(module_name, @options.ignore_case)
518:                 if !m.include_requires?(@file_name, @options.ignore_case)
519:                   m.add_require(Require.new(@file_name, ""))
520:                 end
521:               end
522:             }
523:           end
524:         elsif block_searching_flag == :program
525:           program_name = module_program_name
526:           program_code = module_program_code
527:           program_trailing = module_program_trailing
528:           progress "p"
529:           program_comment = COMMENTS_ARE_UPPER ? 
530:             find_comments(pre_comment.join("\n")) + "\n" + program_trailing : 
531:               program_trailing + "\n" + find_comments(program_code.sub(/^.*$\n/i, ''))
532:           program_comment = "\n\n= <i>Program</i> <tt>#{program_name}</tt>\n\n" \
533:                             + program_comment
534:           @top_level.comment << program_comment
535:           parse_program_or_module(@top_level, program_code, :private)
536:         end
537: 
538:         # next loop to search next block
539:         level_depth = 0
540:         block_searching_flag = false
541:         block_searching_lines = []
542:         pre_comment = []
543:         next false
544:       }
545: 
546:       remaining_lines.delete_if{ |line|
547:         line == false
548:       }
549: 
550:       # External subprograms and functions are parsed
551:       #
552:       # 単一のファイル内において program や module に格納されない,
553:       # 外部サブルーチン, 外部関数部分の解析.
554:       #
555:       parse_program_or_module(@top_level, remaining_lines.join("\n"),
556:                               :public, true)
557: 
558:       @top_level
559:     end

Semicolons are replaced to line feed.

[Source]

      # File parsers/parse_f95.rb, line 1727
1727:     def semicolon_to_linefeed(text)
1728:       return "" unless text
1729:       lines = text.split("\n")
1730:       lines.collect!{ |line|
1731:         words = line.split("")
1732:         commentout = false
1733:         squote = false ; dquote = false
1734:         words.collect! { |char|
1735:           if !(squote) && !(dquote) && !(commentout)
1736:             case char
1737:             when "!" ; commentout = true ; next char
1738:             when "\""; dquote = true     ; next char
1739:             when "\'"; squote = true     ; next char
1740:             when ";" ;                     "\n"
1741:             else next char
1742:             end
1743:           elsif commentout
1744:             next char
1745:           elsif squote
1746:             case char
1747:             when "\'"; squote = false ; next char
1748:             else next char
1749:             end
1750:           elsif dquote
1751:             case char
1752:             when "\""; dquote = false ; next char
1753:             else next char
1754:             end
1755:           end
1756:         }
1757:         words.join("")
1758:       }
1759:       return lines.join("\n")
1760:     end

Set visibility

"subname" element of "visibility_info" is deleted.

[Source]

      # File parsers/parse_f95.rb, line 1502
1502:     def set_visibility(container, subname, visibility_default, visibility_info)
1503:       return unless container || subname || visibility_default || visibility_info
1504:       not_found = true
1505:       visibility_info.collect!{ |info|
1506:         if info["name"] == subname ||
1507:             @options.ignore_case && info["name"].upcase == subname.upcase
1508:           if info["file_or_module"].name == container.name
1509:             container.set_visibility_for([subname], info["visibility"])
1510:             info["entity_is_discovered"] = true
1511:             not_found = false
1512:           end
1513:         end
1514:         info
1515:       }
1516:       if not_found
1517:         return container.set_visibility_for([subname], visibility_default)
1518:       else
1519:         return container
1520:       end
1521:     end

Continuous lines are united.

Comments in continuous lines are removed.

[Source]

      # File parsers/parse_f95.rb, line 1609
1609:     def united_to_one_line(f90src)
1610:       return "" unless f90src
1611:       lines = f90src.split("\n")
1612:       previous_continuing = false
1613:       now_continuing = false
1614:       body = ""
1615:       lines.each{ |line|
1616:         words = line.split("")
1617:         next if words.empty? && previous_continuing
1618:         commentout = false
1619:         brank_flag = true ; brank_char = ""
1620:         squote = false    ; dquote = false
1621:         ignore = false
1622:         words.collect! { |char|
1623:           if previous_continuing && brank_flag
1624:             now_continuing = true
1625:             ignore         = true
1626:             case char
1627:             when "!"                       ; break
1628:             when " " ; brank_char << char  ; next ""
1629:             when "&"
1630:               brank_flag = false
1631:               now_continuing = false
1632:               next ""
1633:             else 
1634:               brank_flag     = false
1635:               now_continuing = false
1636:               ignore         = false
1637:               next brank_char + char
1638:             end
1639:           end
1640:           ignore = false
1641: 
1642:           if now_continuing
1643:             next ""
1644:           elsif !(squote) && !(dquote) && !(commentout)
1645:             case char
1646:             when "!" ; commentout = true     ; next char
1647:             when "\""; dquote = true         ; next char
1648:             when "\'"; squote = true         ; next char
1649:             when "&" ; now_continuing = true ; next ""
1650:             else next char
1651:             end
1652:           elsif commentout
1653:             next char
1654:           elsif squote
1655:             case char
1656:             when "\'"; squote = false ; next char
1657:             else next char
1658:             end
1659:           elsif dquote
1660:             case char
1661:             when "\""; dquote = false ; next char
1662:             else next char
1663:             end
1664:           end
1665:         }
1666:         if !ignore && !previous_continuing || !brank_flag
1667:           if previous_continuing
1668:             body << words.join("")
1669:           else
1670:             body << "\n" + words.join("")
1671:           end
1672:         end
1673:         previous_continuing = now_continuing ? true : nil
1674:         now_continuing = nil
1675:       }
1676:       return body
1677:     end

[Validate]