| Class | RDoc::Fortran95parser |
| In: |
parsers/parse_f95.rb
|
| Parent: | Object |
See rdoc/parsers/parse_f95.rb
| COMMENTS_ARE_UPPER | = | false |
|
|||||
| 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 |
prepare to parse a Fortran 95 file
# File parsers/parse_f95.rb, line 393
393: def initialize(top_level, file_name, body, options, stats)
394: @body = body
395: @stats = stats
396: @file_name = file_name
397: @options = options
398: @top_level = top_level
399: @progress = $stderr unless options.quiet
400: end
Return lines before "contains" statement in modules. "interface", "type" statements are removed.
# File parsers/parse_f95.rb, line 1301
1301: def before_contains(code)
1302: level_depth = 0
1303: before_contains_lines = []
1304: before_contains_code = nil
1305: before_contains_flag = nil
1306: code.split("\n").each{ |line|
1307: if !before_contains_flag
1308: if line =~ /^\s*?module\s+\w+\s*?(!.*?)?$/i
1309: before_contains_flag = true
1310: end
1311: else
1312: break if line =~ /^\s*?contains\s*?(!.*?)?$/i
1313: level_depth += 1 if block_start?(line)
1314: level_depth -= 1 if block_end?(line)
1315: break if level_depth < 0
1316: before_contains_lines << line
1317: end
1318:
1319: }
1320: before_contains_code = before_contains_lines.join("\n")
1321: if before_contains_code
1322: before_contains_code.gsub!(/^\s*?interface\s+.*?\s+end\s+interface.*?$/im, "")
1323: before_contains_code.gsub!(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
1324: end
1325:
1326: before_contains_code
1327: end
Which "line" is end of block (module, program, block data, subroutine, function) statement ?
# File parsers/parse_f95.rb, line 1965
1965: def block_end?(line)
1966: return nil if !line
1967:
1968: if line =~ /^\s*?end\s*?(!.*?)?$/i ||
1969: line =~ /^\s*?end\s+module(\s+\w+)?\s*?(!.*?)?$/i ||
1970: line =~ /^\s*?end\s+program(\s+\w+)?\s*?(!.*?)?$/i ||
1971: line =~ /^\s*?end\s+block\s+data(\s+\w+)?\s*?(!.*?)?$/i ||
1972: line =~ /^\s*?end\s+subroutine(\s+\w+)?\s*?(!.*?)?$/i ||
1973: line =~ /^\s*?end\s+function(\s+\w+)?\s*?(!.*?)?$/i
1974: return true
1975: end
1976:
1977: return nil
1978: end
Which "line" is start of block (module, program, block data, subroutine, function) statement ?
# File parsers/parse_f95.rb, line 1929
1929: def block_start?(line)
1930: return nil if !line
1931:
1932: if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i ||
1933: line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i ||
1934: line =~ /^\s*?block\s+data(\s+\w+)?\s*?(!.*?)?$/i ||
1935: line =~ \
1936: /^\s*?
1937: (recursive|pure|elemental)?\s*?
1938: subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
1939: /ix ||
1940: line =~ \
1941: /^\s*?
1942: (recursive|pure|elemental)?\s*?
1943: (
1944: character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1945: | type\s*?\([\w\s]+?\)\s+
1946: | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1947: | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1948: | double\s+precision\s+
1949: | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1950: | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1951: )?
1952: function\s+(\w+)\s*?
1953: (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
1954: /ix
1955: return true
1956: end
1957:
1958: return nil
1959: end
Check external aliases
subname というサブルーチン名, または関数名を持つファイルを 探査し, 存在する場合にはそのファイル内へメソッドを追加する.
# File parsers/parse_f95.rb, line 1687
1687: def check_external_aliases(subname, params, comment, test=nil)
1688: @@external_aliases.each{ |alias_item|
1689: if subname == alias_item["old_name"] ||
1690: subname.upcase == alias_item["old_name"].upcase &&
1691: @options.ignore_case
1692:
1693: new_meth = initialize_external_method(alias_item["new_name"],
1694: subname, params, @file_name,
1695: comment)
1696: new_meth.visibility = alias_item["visibility"]
1697:
1698: progress "e"
1699: @stats.num_methods += 1
1700: alias_item["file_or_module"].add_method(new_meth)
1701:
1702: if !alias_item["file_or_module"].include_requires?(@file_name, @options.ignore_case)
1703: alias_item["file_or_module"].add_require(Require.new(@file_name, ""))
1704: end
1705: end
1706: }
1707: end
Check public_methods
use したモジュールからそのまま引き継いで public として 公開する場合のチェックを行う. subname というサブルーチン名, または関数名を持つファイルを 探査し, 存在する場合にはそのファイル内へメソッドを追加する.
# File parsers/parse_f95.rb, line 1717
1717: def check_public_methods(method, parent)
1718: return if !method || !parent
1719: @@public_methods.each{ |alias_item|
1720: parent_is_used_module = nil
1721: alias_item["used_modules"].each{ |used_module|
1722: if used_module == parent ||
1723: used_module.upcase == parent.upcase &&
1724: @options.ignore_case
1725: parent_is_used_module = true
1726: end
1727: }
1728: next if !parent_is_used_module
1729:
1730: if method.name == alias_item["name"] ||
1731: method.name.upcase == alias_item["name"].upcase &&
1732: @options.ignore_case
1733:
1734: new_meth = initialize_public_method(method, parent)
1735: if alias_item["local_name"]
1736: new_meth.name = alias_item["local_name"]
1737: end
1738:
1739: progress "e"
1740: @stats.num_methods += 1
1741: alias_item["file_or_module"].add_method new_meth
1742: end
1743: }
1744: end
Collect comment for file entity
# File parsers/parse_f95.rb, line 1332
1332: def collect_first_comment(body)
1333: comment = ""
1334: not_comment = ""
1335: comment_start = false
1336: comment_end = false
1337: body.split("\n").each{ |line|
1338: if comment_end
1339: not_comment << line
1340: not_comment << "\n"
1341: elsif /^\s*?!\s?(.*)$/i =~ line
1342: comment_start = true
1343: comment << $1
1344: comment << "\n"
1345: elsif /^\s*?$/i =~ line
1346: comment_end = true if comment_start && COMMENTS_ARE_UPPER
1347: else
1348: comment_end = true
1349: not_comment << line
1350: not_comment << "\n"
1351: end
1352: }
1353: return comment, not_comment
1354: end
Comment out checker
# File parsers/parse_f95.rb, line 1856
1856: def comment_out?(line)
1857: return nil unless line
1858: commentout = false
1859: squote = false ; dquote = false
1860: line.split("").each { |char|
1861: if !(squote) && !(dquote)
1862: case char
1863: when "!" ; commentout = true ; break
1864: when "\""; dquote = true
1865: when "\'"; squote = true
1866: else next
1867: end
1868: elsif squote
1869: case char
1870: when "\'"; squote = false
1871: else next
1872: end
1873: elsif dquote
1874: case char
1875: when "\""; dquote = false
1876: else next
1877: end
1878: end
1879: }
1880: return commentout
1881: end
Continuous line checker
# File parsers/parse_f95.rb, line 1842
1842: def continuous_line?(line)
1843: continuous = false
1844: if /&\s*?(!.*)?$/ =~ line
1845: continuous = true
1846: if comment_out?($~.pre_match)
1847: continuous = false
1848: end
1849: end
1850: return continuous
1851: end
Parse string argument "text", and Return Array of Fortran95Definition object
# File parsers/parse_f95.rb, line 2101
2101: def definition_info(text)
2102: return nil unless text
2103: lines = "#{text}"
2104: defs = Array.new
2105: comment = ""
2106: trailing_comment = ""
2107: under_comment_valid = false
2108: lines.split("\n").each{ |line|
2109: if /^\s*?!\s?(.*)/ =~ line
2110: if COMMENTS_ARE_UPPER
2111: comment << remove_header_marker($1)
2112: comment << "\n"
2113: elsif defs[-1] && under_comment_valid
2114: defs[-1].comment << "\n"
2115: defs[-1].comment << remove_header_marker($1)
2116: end
2117: next
2118: elsif /^\s*?$/ =~ line
2119: comment = ""
2120: under_comment_valid = false
2121: next
2122: end
2123: type = ""
2124: characters = ""
2125: if line =~ /^\s*?
2126: (
2127: character\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2128: | type\s*?\([\w\s]+?\)[\s\,]*
2129: | integer\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2130: | real\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2131: | double\s+precision[\s\,]*
2132: | logical\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2133: | complex\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2134: )
2135: (.*?::)?
2136: (.+)$
2137: /ix
2138: characters = $8
2139: type = $1
2140: type << $7.gsub(/::/, '').gsub(/^\s*?\,/, '') if $7
2141: else
2142: under_comment_valid = false
2143: next
2144: end
2145: squote = false ; dquote = false ; bracket = 0
2146: iniflag = false; commentflag = false
2147: varname = "" ; arraysuffix = "" ; inivalue = ""
2148: start_pos = defs.size
2149: characters.split("").each { |char|
2150: if !(squote) && !(dquote) && bracket <= 0 && !(iniflag) && !(commentflag)
2151: case char
2152: when "!" ; commentflag = true
2153: when "(" ; bracket += 1 ; arraysuffix = char
2154: when "\""; dquote = true
2155: when "\'"; squote = true
2156: when "=" ; iniflag = true ; inivalue << char
2157: when ","
2158: defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2159: varname = "" ; arraysuffix = "" ; inivalue = ""
2160: under_comment_valid = true
2161: when " " ; next
2162: else ; varname << char
2163: end
2164: elsif commentflag
2165: comment << remove_header_marker(char)
2166: trailing_comment << remove_header_marker(char)
2167: elsif iniflag
2168: if dquote
2169: case char
2170: when "\"" ; dquote = false ; inivalue << char
2171: else ; inivalue << char
2172: end
2173: elsif squote
2174: case char
2175: when "\'" ; squote = false ; inivalue << char
2176: else ; inivalue << char
2177: end
2178: elsif bracket > 0
2179: case char
2180: when "(" ; bracket += 1 ; inivalue << char
2181: when ")" ; bracket -= 1 ; inivalue << char
2182: else ; inivalue << char
2183: end
2184: else
2185: case char
2186: when ","
2187: defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2188: varname = "" ; arraysuffix = "" ; inivalue = ""
2189: iniflag = false
2190: under_comment_valid = true
2191: when "(" ; bracket += 1 ; inivalue << char
2192: when "\""; dquote = true ; inivalue << char
2193: when "\'"; squote = true ; inivalue << char
2194: when "!" ; commentflag = true
2195: else ; inivalue << char
2196: end
2197: end
2198: elsif !(squote) && !(dquote) && bracket > 0
2199: case char
2200: when "(" ; bracket += 1 ; arraysuffix << char
2201: when ")" ; bracket -= 1 ; arraysuffix << char
2202: else ; arraysuffix << char
2203: end
2204: elsif squote
2205: case char
2206: when "\'"; squote = false ; inivalue << char
2207: else ; inivalue << char
2208: end
2209: elsif dquote
2210: case char
2211: when "\""; dquote = false ; inivalue << char
2212: else ; inivalue << char
2213: end
2214: end
2215: }
2216: defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2217: if trailing_comment =~ /^:nodoc:/
2218: defs[start_pos..-1].collect!{ |defitem|
2219: defitem.nodoc = true
2220: }
2221: end
2222: varname = "" ; arraysuffix = "" ; inivalue = ""
2223: comment = ""
2224: under_comment_valid = true
2225: trailing_comment = ""
2226: }
2227: return defs
2228: end
Return comments of definitions of arguments
If "all" argument is true, information of all arguments are returned. If "modified_params" is true, list of arguments are decorated, for exameple, optional arguments are parenthetic as "[arg]".
# File parsers/parse_f95.rb, line 1363
1363: def find_arguments(args, text, all=nil, indent=nil, modified_params=nil)
1364: return unless args || all
1365: indent = "" unless indent
1366: args = ["all"] if all
1367: params = "" if modified_params
1368: comma = ""
1369: return unless text
1370: args_rdocforms = "\n"
1371: remaining_lines = "#{text}"
1372: definitions = definition_info(remaining_lines)
1373: args.each{ |arg|
1374: arg.strip!
1375: arg.chomp!
1376: definitions.each { |defitem|
1377: if arg == defitem.varname.strip.chomp || all
1378: args_rdocforms << "\n\#{indent}<b><tt>\#{defitem.varname.chomp.strip}\#{defitem.arraysuffix} </tt></b> <tt> \#{defitem.inivalue}</tt> ::\n\#{indent} <tt>\#{defitem.types.chomp.strip}</tt>\n"
1379: if !defitem.comment.chomp.strip.empty?
1380: comment = ""
1381: defitem.comment.split("\n").each{ |line|
1382: comment << " " + line + "\n"
1383: }
1384: args_rdocforms << "\n\#{indent} <tt></tt> ::\n\#{indent} <tt></tt>\n\#{indent} \#{comment.chomp.strip}\n"
1385: end
1386:
1387: if modified_params
1388: if defitem.include_attr?("optional")
1389: params << "#{comma}[#{arg}]"
1390: else
1391: params << "#{comma}#{arg}"
1392: end
1393: comma = ", "
1394: end
1395: end
1396: }
1397: }
1398: if modified_params
1399: return args_rdocforms, params
1400: else
1401: return args_rdocforms
1402: end
1403: end
Comments just after module or subprogram, or arguments are returnd. If "COMMENTS_ARE_UPPER" is true, comments just before modules or subprograms are returnd
# File parsers/parse_f95.rb, line 1505
1505: def find_comments text
1506: return "" unless text
1507: lines = text.split("\n")
1508: lines.reverse! if COMMENTS_ARE_UPPER
1509: comment_block = Array.new
1510: lines.each do |line|
1511: break if line =~ /^\s*?\w/ || line =~ /^\s*?$/
1512: if COMMENTS_ARE_UPPER
1513: comment_block.unshift line.sub(/^\s*?!\s?/,"")
1514: else
1515: comment_block.push line.sub(/^\s*?!\s?/,"")
1516: end
1517: end
1518: nice_lines = comment_block.join("\n").split "\n\s*?\n"
1519: nice_lines[0] ||= ""
1520: nice_lines.shift
1521: end
Add namelist information to Repository (dummy module of each @top_level) of NAMELIST statements. And return comments about namelist group names
# File parsers/parse_f95.rb, line 1421
1421: def find_namelists(container, text, before_contains=nil)
1422: return nil if !text
1423: top_level = find_toplevel(container)
1424:
1425: if text =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)(!.*?)?$/i
1426: if top_level.include_includes?(NAMELIST_REPOSITORY_NAME)
1427: namelist_module =
1428: top_level.find_module_named(NAMELIST_REPOSITORY_NAME)
1429: else
1430: namelist_module =
1431: top_level.add_module NormalClass, NAMELIST_REPOSITORY_NAME
1432: namelist_module.record_location top_level
1433: namelist_module.comment = "This is not a module but a repository of NAMELIST group names declared\nin all Fortran 90/95 files\n"
1434: end
1435: else
1436: return ""
1437: end
1438:
1439: nml_group_name_lists = []
1440: lines = "#{text}"
1441: before_contains = "" if !before_contains
1442: while lines =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)(!.*?)?$/i
1443: lines = $~.post_match
1444: pre_match = $~.pre_match ; post_match = $~.post_match
1445: nml_group_name = $1
1446: nml_vars_list = $2.split(",")
1447: nml_comment = COMMENTS_ARE_UPPER ?
1448: find_comments(pre_match.sub(/\n$/, '')) :
1449: find_comments(post_match.sub(/^\n/, ''))
1450: if lines.split("\n")[0] =~ /^\//i
1451: lines = "namelist " + lines
1452: end
1453:
1454: nml_meth = AnyMethod.new("NAMELIST", nml_group_name)
1455: nml_meth.singleton = false
1456: nml_meth.params = "( " + nml_vars_list.join(", ") + " )"
1457: nml_meth.comment = "<b><em> NAMELIST </em></b> :: <tt></tt>\n"
1458: nml_meth.comment << find_arguments(nml_vars_list, "#{text}" + "\n" + before_contains)
1459: nml_meth.comment << "\n" + nml_comment if nml_comment
1460: if container.parent.parent
1461: parent_object = container.parent.name
1462: else
1463: parent_object = container.parent.file_relative_name
1464: end
1465: nml_meth.comment << "\n\nThis namelist group name is input/output in "
1466: nml_meth.comment << parent_object + "#" + container.name
1467:
1468: progress "n"
1469: @stats.num_methods += 1
1470: namelist_module.add_method nml_meth
1471:
1472: nml_group_name_lists << NAMELIST_REPOSITORY_NAME + "#" + nml_group_name
1473: end
1474:
1475: if !nml_group_name_lists.empty?
1476: comments_in_procedures = "\n\nThis procedure input/output "
1477: comments_in_procedures << nml_group_name_lists.join(", ") + " . "
1478: else
1479: comments_in_procedures = ""
1480: end
1481:
1482: comments_in_procedures
1483: end
Return toplevel class of container
# File parsers/parse_f95.rb, line 1492
1492: def find_toplevel(container)
1493: top_level = container
1494: while top_level.parent
1495: top_level = top_level.parent
1496: end
1497: top_level
1498: end
Find visibility
# File parsers/parse_f95.rb, line 1668
1668: def find_visibility(container, subname, visibility_info)
1669: return nil if !subname || !visibility_info
1670: visibility_info.each{ |info|
1671: if info["name"] == subname ||
1672: @options.ignore_case && info["name"].upcase == subname.upcase
1673: if info["parent"] == container.name
1674: return info["visibility"]
1675: end
1676: end
1677: }
1678: return nil
1679: end
Create method for external alias
If argument "internal" is true, file is ignored.
# File parsers/parse_f95.rb, line 1550
1550: def initialize_external_method(new, old, params, file, comment, token=nil,
1551: internal=nil, nolink=nil)
1552: return nil unless new || old
1553:
1554: if internal
1555: external_alias_header = "#{INTERNAL_ALIAS_MES} "
1556: external_alias_text = external_alias_header + old
1557: elsif file
1558: external_alias_header = "#{EXTERNAL_ALIAS_MES} "
1559: external_alias_text = external_alias_header + file + "#" + old
1560: else
1561: return nil
1562: end
1563: external_meth = AnyMethod.new(external_alias_text, new)
1564: external_meth.singleton = false
1565: external_meth.params = params
1566: external_comment = remove_trailing_alias(comment) + "\n\n" if comment
1567: external_meth.comment = external_comment || ""
1568: if nolink && token
1569: external_meth.start_collecting_tokens
1570: external_meth.add_token Token.new(1,1).set_text(token)
1571: else
1572: external_meth.comment << external_alias_text
1573: end
1574:
1575: return external_meth
1576: end
Create method for internal alias
# File parsers/parse_f95.rb, line 1533
1533: def initialize_public_method(method, parent)
1534: return if !method || !parent
1535:
1536: new_meth = AnyMethod.new("External Alias for module", method.name)
1537: new_meth.singleton = method.singleton
1538: new_meth.params = method.params.clone
1539: new_meth.comment = remove_trailing_alias(method.comment.clone)
1540: new_meth.comment << "\n\n#{EXTERNAL_ALIAS_MES} #{parent.strip.chomp}\##{method.name}"
1541:
1542: return new_meth
1543: end
# File parsers/parse_f95.rb, line 627
627: def parse_program_or_module(container, code,
628: visibility=:public, external=nil)
629: return unless container
630: return unless code
631: remaining_lines = code.split("\n")
632: remaining_code = "#{code}"
633:
634: #
635: # Parse variables before "contains" in module
636: #
637: # namelist 変数の定義に使われたり, これ自体が定数, 変数
638: # 提供されるのに利用される. (変数や定数として利用される場合,
639: # これもメソッドとして提供する.
640: #
641: before_contains_code = before_contains(remaining_code)
642:
643: #
644: # Parse global "use"
645: #
646: use_check_code = "#{before_contains_code}"
647: cascaded_modules_list = []
648: while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i
649: use_check_code = $~.pre_match
650: use_check_code << $~.post_match
651: used_mod_name = $1.strip.chomp
652: used_list = $2 || ""
653: used_trailing = $3 || ""
654: next if used_trailing =~ /!:nodoc:/
655: if !container.include_includes?(used_mod_name, @options.ignore_case)
656: progress "."
657: container.add_include Include.new(used_mod_name, "")
658: end
659: if ! (used_list =~ /\,\s*?only\s*?:/i )
660: cascaded_modules_list << "\#" + used_mod_name
661: end
662: end
663:
664: #
665: # Parse public and private, and store information.
666: # This information is used when "add_method" and
667: # "set_visibility_for" are called.
668: #
669: visibility_default, visibility_info =
670: parse_visibility(remaining_lines.join("\n"), visibility, container)
671: @@public_methods.concat visibility_info
672: if visibility_default == :public
673: if !cascaded_modules_list.empty?
674: cascaded_modules =
675: Attr.new("Cascaded Modules",
676: "Imported modules all of whose components are published again",
677: "",
678: cascaded_modules_list.join(", "))
679: container.add_attribute(cascaded_modules)
680: end
681: end
682:
683: #
684: # Check rename elements
685: #
686: use_check_code = "#{before_contains_code}"
687: while use_check_code =~ /^\s*?use\s+(\w+)\s*?\,(.+)$/i
688: use_check_code = $~.pre_match
689: use_check_code << $~.post_match
690: used_mod_name = $1.strip.chomp
691: used_elements = $2.sub(/\s*?only\s*?:\s*?/i, '')
692: used_elements.split(",").each{ |used|
693: if /\s*?(\w+)\s*?=>\s*?(\w+)\s*?/ =~ used
694: local = $1
695: org = $2
696: @@public_methods.collect!{ |pub_meth|
697: if local == pub_meth["name"] ||
698: local.upcase == pub_meth["name"].upcase &&
699: @options.ignore_case
700: pub_meth["name"] = org
701: pub_meth["local_name"] = local
702: end
703: pub_meth
704: }
705: end
706: }
707: end
708:
709: #
710: # Parse private "use"
711: #
712: use_check_code = remaining_lines.join("\n")
713: while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i
714: use_check_code = $~.pre_match
715: use_check_code << $~.post_match
716: used_mod_name = $1.strip.chomp
717: used_trailing = $3 || ""
718: next if used_trailing =~ /!:nodoc:/
719: if !container.include_includes?(used_mod_name, @options.ignore_case)
720: progress "."
721: container.add_include Include.new(used_mod_name, "")
722: end
723: end
724:
725: container.each_includes{ |inc|
726: TopLevel.all_files.each do |name, toplevel|
727: indicated_mod = toplevel.find_symbol(inc.name,
728: nil, @options.ignore_case)
729: if indicated_mod
730: indicated_name = indicated_mod.parent.file_relative_name
731: if !container.include_requires?(indicated_name, @options.ignore_case)
732: container.add_require(Require.new(indicated_name, ""))
733: end
734: break
735: end
736: end
737: }
738:
739: #
740: # Parse derived types definitions
741: #
742: derived_types_comment = ""
743: remaining_code = remaining_lines.join("\n")
744: while remaining_code =~ /^\s*?
745: type[\s\,]+(public|private)?\s*?(::)?\s*?
746: (\w+)\s*?(!.*?)?$
747: (.*?)
748: ^\s*?end\s+type.*?$
749: /imx
750: remaining_code = $~.pre_match
751: remaining_code << $~.post_match
752: typename = $3.chomp.strip
753: type_elements = $5 || ""
754: type_code = remove_empty_head_lines($&)
755: type_trailing = find_comments($4)
756: next if type_trailing =~ /^:nodoc:/
757: type_visibility = $1
758: type_comment = COMMENTS_ARE_UPPER ?
759: find_comments($~.pre_match) + "\n" + type_trailing :
760: type_trailing + "\n" + find_comments(type_code.sub(/^.*$\n/i, ''))
761: type_element_visibility_public = true
762: type_code.split("\n").each{ |line|
763: if /^\s*?private\s*?$/ =~ line
764: type_element_visibility_public = nil
765: break
766: end
767: } if type_code
768:
769: args_comment = ""
770: type_args_info = nil
771:
772: if @options.show_all
773: args_comment = find_arguments(nil, type_code, true)
774: else
775: type_public_args_list = []
776: type_args_info = definition_info(type_code)
777: type_args_info.each{ |arg|
778: arg_is_public = type_element_visibility_public
779: arg_is_public = true if arg.include_attr?("public")
780: arg_is_public = nil if arg.include_attr?("private")
781: type_public_args_list << arg.varname if arg_is_public
782: }
783: args_comment = find_arguments(type_public_args_list, type_code)
784: end
785:
786: type = AnyMethod.new("type #{typename}", typename)
787: type.singleton = false
788: type.params = ""
789: type.comment = "<b><em> Derived Type </em></b> :: <tt></tt>\n"
790: type.comment << args_comment if args_comment
791: type.comment << type_comment if type_comment
792: progress "t"
793: @stats.num_methods += 1
794: container.add_method type
795:
796: set_visibility(container, typename, visibility_default, @@public_methods)
797:
798: if type_visibility
799: type_visibility.gsub!(/\s/,'')
800: type_visibility.gsub!(/\,/,'')
801: type_visibility.gsub!(/:/,'')
802: type_visibility.downcase!
803: if type_visibility == "public"
804: container.set_visibility_for([typename], :public)
805: elsif type_visibility == "private"
806: container.set_visibility_for([typename], :private)
807: end
808: end
809:
810: check_public_methods(type, container.name)
811:
812: if @options.show_all
813: derived_types_comment << ", " unless derived_types_comment.empty?
814: derived_types_comment << typename
815: else
816: if type.visibility == :public
817: derived_types_comment << ", " unless derived_types_comment.empty?
818: derived_types_comment << typename
819: end
820: end
821:
822: end
823:
824: if !derived_types_comment.empty?
825: derived_types_table =
826: Attr.new("Derived Types", "Derived_Types", "",
827: derived_types_comment)
828: container.add_attribute(derived_types_table)
829: end
830:
831: #
832: # move interface scope
833: #
834: interface_code = ""
835: while remaining_code =~ /^\s*?
836: interface(
837: \s+\w+ |
838: \s+operator\s*?\(.*?\) |
839: \s+assignment\s*?\(\s*?=\s*?\)
840: )?\s*?$
841: (.*?)
842: ^\s*?end\s+interface.*?$
843: /imx
844: interface_code << remove_empty_head_lines($&) + "\n"
845: remaining_code = $~.pre_match
846: remaining_code << $~.post_match
847: end
848:
849: #
850: # Parse global constants or variables in modules
851: #
852: const_var_defs = definition_info(before_contains_code)
853: const_var_defs.each{|defitem|
854: next if defitem.nodoc
855: const_or_var_type = "Variable"
856: const_or_var_progress = "v"
857: if defitem.include_attr?("parameter")
858: const_or_var_type = "Constant"
859: const_or_var_progress = "c"
860: end
861: const_or_var = AnyMethod.new(const_or_var_type, defitem.varname)
862: const_or_var.singleton = false
863: const_or_var.params = ""
864: self_comment = find_arguments([defitem.varname], before_contains_code)
865: const_or_var.comment = "<b><em>" + const_or_var_type + "</em></b> :: <tt></tt>\n"
866: const_or_var.comment << self_comment if self_comment
867: progress const_or_var_progress
868: @stats.num_methods += 1
869: container.add_method const_or_var
870:
871: set_visibility(container, defitem.varname, visibility_default, @@public_methods)
872:
873: if defitem.include_attr?("public")
874: container.set_visibility_for([defitem.varname], :public)
875: elsif defitem.include_attr?("private")
876: container.set_visibility_for([defitem.varname], :private)
877: end
878:
879: check_public_methods(const_or_var, container.name)
880:
881: } if const_var_defs
882:
883: remaining_lines = remaining_code.split("\n")
884:
885: # "subroutine" or "function" parts are parsed (new)
886: #
887: level_depth = 0
888: block_searching_flag = nil
889: block_searching_lines = []
890: pre_comment = []
891: procedure_trailing = ""
892: procedure_name = ""
893: procedure_params = ""
894: procedure_prefix = ""
895: procedure_result_arg = ""
896: procedure_type = ""
897: contains_lines = []
898: contains_flag = nil
899: remaining_lines.collect!{|line|
900: if !block_searching_flag
901: # subroutine
902: if line =~ /^\s*?
903: (recursive|pure|elemental)?\s*?
904: subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
905: /ix
906: block_searching_flag = :subroutine
907: block_searching_lines << line
908:
909: procedure_name = $2.chomp.strip
910: procedure_params = $3 || ""
911: procedure_prefix = $1 || ""
912: procedure_trailing = $4 || "!"
913: next false
914:
915: # function
916: elsif line =~ /^\s*?
917: (recursive|pure|elemental)?\s*?
918: (
919: character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
920: | type\s*?\([\w\s]+?\)\s+
921: | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
922: | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
923: | double\s+precision\s+
924: | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
925: | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
926: )?
927: function\s+(\w+)\s*?
928: (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
929: /ix
930: block_searching_flag = :function
931: block_searching_lines << line
932:
933: procedure_prefix = $1 || ""
934: procedure_type = $2 ? $2.chomp.strip : nil
935: procedure_name = $8.chomp.strip
936: procedure_params = $9 || ""
937: procedure_result_arg = $11 ? $11.chomp.strip : procedure_name
938: procedure_trailing = $12 || "!"
939: next false
940: elsif line =~ /^\s*?!\s?(.*)/
941: pre_comment << line
942: next line
943: else
944: pre_comment = []
945: next line
946: end
947: end
948: contains_flag = true if line =~ /^\s*?contains\s*?(!.*?)?$/
949: block_searching_lines << line
950: contains_lines << line if contains_flag
951:
952: level_depth += 1 if block_start?(line)
953: level_depth -= 1 if block_end?(line)
954: if level_depth >= 0
955: next false
956: end
957:
958: # "procedure_code" is formatted.
959: # ":nodoc:" flag is checked.
960: #
961: procedure_code = block_searching_lines.join("\n")
962: procedure_code = remove_empty_head_lines(procedure_code)
963: if procedure_trailing =~ /^!:nodoc:/
964: # next loop to search next block
965: level_depth = 0
966: block_searching_flag = nil
967: block_searching_lines = []
968: pre_comment = []
969: procedure_trailing = ""
970: procedure_name = ""
971: procedure_params = ""
972: procedure_prefix = ""
973: procedure_result_arg = ""
974: procedure_type = ""
975: contains_lines = []
976: contains_flag = nil
977: next false
978: end
979:
980: # AnyMethod is created, and added to container
981: #
982: subroutine_function = nil
983: if block_searching_flag == :subroutine
984: subroutine_prefix = procedure_prefix
985: subroutine_name = procedure_name
986: subroutine_params = procedure_params
987: subroutine_trailing = procedure_trailing
988: subroutine_code = procedure_code
989:
990: subroutine_comment = COMMENTS_ARE_UPPER ?
991: pre_comment.join("\n") + "\n" + subroutine_trailing :
992: subroutine_trailing + "\n" + subroutine_code.sub(/^.*$\n/i, '')
993: subroutine = AnyMethod.new("subroutine", subroutine_name)
994: parse_subprogram(subroutine, subroutine_params,
995: subroutine_comment, subroutine_code,
996: before_contains_code, nil, subroutine_prefix)
997: progress "s"
998: @stats.num_methods += 1
999: container.add_method subroutine
1000: subroutine_function = subroutine
1001:
1002: namelist_comment =
1003: find_namelists(subroutine, subroutine_code, before_contains_code)
1004: subroutine.comment << namelist_comment if namelist_comment
1005:
1006: elsif block_searching_flag == :function
1007: function_prefix = procedure_prefix
1008: function_type = procedure_type
1009: function_name = procedure_name
1010: function_params_org = procedure_params
1011: function_result_arg = procedure_result_arg
1012: function_trailing = procedure_trailing
1013: function_code_org = procedure_code
1014:
1015: function_comment = COMMENTS_ARE_UPPER ?
1016: pre_comment.join("\n") + "\n" + function_trailing :
1017: function_trailing + "\n " + function_code_org.sub(/^.*$\n/i, '')
1018:
1019: function_code = "#{function_code_org}"
1020: if function_type
1021: function_code << "\n" + function_type + " :: " + function_result_arg
1022: end
1023:
1024: function_params =
1025: function_params_org.sub(/^\(/, "\(#{function_result_arg}, ")
1026:
1027: function = AnyMethod.new("function", function_name)
1028: parse_subprogram(function, function_params,
1029: function_comment, function_code,
1030: before_contains_code, true, function_prefix)
1031:
1032: # Specific modification due to function
1033: function.params.sub!(/\(\s*?#{function_result_arg}\s*?,\s*?/, "\( ")
1034: function.params << " result(" + function_result_arg + ")"
1035: function.start_collecting_tokens
1036: function.add_token Token.new(1,1).set_text(function_code_org)
1037:
1038: progress "f"
1039: @stats.num_methods += 1
1040: container.add_method function
1041: subroutine_function = function
1042:
1043: namelist_comment =
1044: find_namelists(function, function_code, before_contains_code)
1045: function.comment << namelist_comment if namelist_comment
1046:
1047: end
1048:
1049: # The visibility of procedure is specified
1050: #
1051: set_visibility(container, procedure_name,
1052: visibility_default, @@public_methods)
1053:
1054: # The alias for this procedure from external modules
1055: #
1056: check_external_aliases(procedure_name,
1057: subroutine_function.params,
1058: subroutine_function.comment, subroutine_function) if external
1059: check_public_methods(subroutine_function, container.name)
1060:
1061:
1062: # contains_lines are parsed as private procedures
1063: if contains_flag
1064: parse_program_or_module(container,
1065: contains_lines.join("\n"), :private)
1066: end
1067:
1068: # next loop to search next block
1069: level_depth = 0
1070: block_searching_flag = nil
1071: block_searching_lines = []
1072: pre_comment = []
1073: procedure_trailing = ""
1074: procedure_name = ""
1075: procedure_params = ""
1076: procedure_prefix = ""
1077: procedure_result_arg = ""
1078: contains_lines = []
1079: contains_flag = nil
1080: next false
1081: } # End of remaining_lines.collect!{|line|
1082:
1083: # Array remains_lines is converted to String remains_code again
1084: #
1085: remaining_code = remaining_lines.join("\n")
1086:
1087: #
1088: # Parse interface
1089: #
1090: interface_scope = false
1091: generic_name = ""
1092: interface_code.split("\n").each{ |line|
1093: if /^\s*?
1094: interface(
1095: \s+\w+|
1096: \s+operator\s*?\(.*?\)|
1097: \s+assignment\s*?\(\s*?=\s*?\)
1098: )?
1099: \s*?(!.*?)?$
1100: /ix =~ line
1101: generic_name = $1 ? $1.strip.chomp : nil
1102: interface_trailing = $2 || "!"
1103: interface_scope = true
1104: interface_scope = false if interface_trailing =~ /!:nodoc:/
1105: # if generic_name =~ /operator\s*?\((.*?)\)/i
1106: # operator_name = $1
1107: # if operator_name && !operator_name.empty?
1108: # generic_name = "#{operator_name}"
1109: # end
1110: # end
1111: # if generic_name =~ /assignment\s*?\((.*?)\)/i
1112: # assignment_name = $1
1113: # if assignment_name && !assignment_name.empty?
1114: # generic_name = "#{assignment_name}"
1115: # end
1116: # end
1117: end
1118: if /^\s*?end\s+interface/i =~ line
1119: interface_scope = false
1120: generic_name = nil
1121: end
1122: # internal alias
1123: if interface_scope && /^\s*?module\s+procedure\s+(.*?)(!.*?)?$/i =~ line
1124: procedures = $1.strip.chomp
1125: procedures_trailing = $2 || "!"
1126: next if procedures_trailing =~ /!:nodoc:/
1127: procedures.split(",").each{ |proc|
1128: proc.strip!
1129: proc.chomp!
1130: next if generic_name == proc || !generic_name
1131: old_meth = container.find_symbol(proc, nil, @options.ignore_case)
1132: next if !old_meth
1133: nolink = old_meth.visibility == :private ? true : nil
1134: nolink = nil if @options.show_all
1135: new_meth =
1136: initialize_external_method(generic_name, proc,
1137: old_meth.params, nil,
1138: old_meth.comment,
1139: old_meth.clone.token_stream[0].text,
1140: true, nolink)
1141: new_meth.singleton = old_meth.singleton
1142:
1143: progress "i"
1144: @stats.num_methods += 1
1145: container.add_method new_meth
1146:
1147: set_visibility(container, generic_name, visibility_default, @@public_methods)
1148:
1149: check_public_methods(new_meth, container.name)
1150:
1151: }
1152: end
1153:
1154: # external aliases
1155: if interface_scope
1156: # subroutine
1157: proc = nil
1158: params = nil
1159: procedures_trailing = nil
1160: if line =~ /^\s*?
1161: (recursive|pure|elemental)?\s*?
1162: subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
1163: /ix
1164: proc = $2.chomp.strip
1165: generic_name = proc unless generic_name
1166: params = $3 || ""
1167: procedures_trailing = $4 || "!"
1168:
1169: # function
1170: elsif line =~ /^\s*?
1171: (recursive|pure|elemental)?\s*?
1172: (
1173: character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1174: | type\s*?\([\w\s]+?\)\s+
1175: | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1176: | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1177: | double\s+precision\s+
1178: | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1179: | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1180: )?
1181: function\s+(\w+)\s*?
1182: (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
1183: /ix
1184: proc = $8.chomp.strip
1185: generic_name = proc unless generic_name
1186: params = $9 || ""
1187: procedures_trailing = $12 || "!"
1188: else
1189: next
1190: end
1191: next if procedures_trailing =~ /!:nodoc:/
1192: indicated_method = nil
1193: indicated_file = nil
1194: TopLevel.all_files.each do |name, toplevel|
1195: indicated_method = toplevel.find_local_symbol(proc, @options.ignore_case)
1196: indicated_file = name
1197: break if indicated_method
1198: end
1199:
1200: if indicated_method
1201: external_method =
1202: initialize_external_method(generic_name, proc,
1203: indicated_method.params,
1204: indicated_file,
1205: indicated_method.comment)
1206:
1207: progress "e"
1208: @stats.num_methods += 1
1209: container.add_method external_method
1210: set_visibility(container, generic_name, visibility_default, @@public_methods)
1211: if !container.include_requires?(indicated_file, @options.ignore_case)
1212: container.add_require(Require.new(indicated_file, ""))
1213: end
1214: check_public_methods(external_method, container.name)
1215:
1216: else
1217: @@external_aliases << {
1218: "new_name" => generic_name,
1219: "old_name" => proc,
1220: "file_or_module" => container,
1221: "visibility" => find_visibility(container, generic_name, @@public_methods) || visibility_default
1222: }
1223: end
1224: end
1225:
1226: } if interface_code # End of interface_code.split("\n").each ...
1227:
1228: #
1229: # Already imported methods are removed from @@public_methods.
1230: # Remainders are assumed to be imported from other modules.
1231: #
1232: # 既に参照済みのメソッドは @@public_methods から取り除く.
1233: # 残りは外部モジュールからの参照と仮定する.
1234: #
1235: @@public_methods.delete_if{ |method| method["entity_is_discovered"]}
1236:
1237: @@public_methods.each{ |pub_meth|
1238: next unless pub_meth["file_or_module"].name == container.name
1239: pub_meth["used_modules"].each{ |used_mod|
1240: TopLevel.all_classes_and_modules.each{ |modules|
1241: if modules.name == used_mod ||
1242: modules.name.upcase == used_mod.upcase &&
1243: @options.ignore_case
1244: modules.method_list.each{ |meth|
1245: if meth.name == pub_meth["name"] ||
1246: meth.name.upcase == pub_meth["name"].upcase &&
1247: @options.ignore_case
1248: new_meth = initialize_public_method(meth,
1249: modules.name)
1250: if pub_meth["local_name"]
1251: new_meth.name = pub_meth["local_name"]
1252: end
1253: progress "e"
1254: @stats.num_methods += 1
1255: container.add_method new_meth
1256: end
1257: }
1258: end
1259: }
1260: }
1261: }
1262:
1263: container
1264: end
Parse arguments, comment, code of subroutine and function. Return AnyMethod object.
# File parsers/parse_f95.rb, line 1270
1270: def parse_subprogram(subprogram, params, comment, code,
1271: before_contains=nil, function=nil, prefix=nil)
1272: subprogram.singleton = false
1273: prefix = "" if !prefix
1274: arguments = params.sub(/\(/, "").sub(/\)/, "").split(",") if params
1275: args_comment, params_opt =
1276: find_arguments(arguments, code.sub(/^s*?contains\s*?(!.*?)?$.*/im, ""),
1277: nil, nil, true)
1278: params_opt = "( " + params_opt + " ) " if params_opt
1279: subprogram.params = params_opt || ""
1280:
1281: block_comment = find_comments comment
1282: if function
1283: subprogram.comment = "<b><em> Function </em></b> :: <em>#{prefix}</em>\n"
1284: else
1285: subprogram.comment = "<b><em> Subroutine </em></b> :: <em>#{prefix}</em>\n"
1286: end
1287: subprogram.comment << args_comment if args_comment
1288: subprogram.comment << block_comment if block_comment
1289:
1290: # For output source code
1291: subprogram.start_collecting_tokens
1292: subprogram.add_token Token.new(1,1).set_text(code)
1293:
1294: subprogram
1295: end
Parse visibility
# File parsers/parse_f95.rb, line 1583
1583: def parse_visibility(code, default, container)
1584: result = []
1585: visibility_default = default || :public
1586:
1587: used_modules = []
1588: container.includes.each{|i| used_modules << i.name} if container
1589:
1590: remaining_code = code.gsub(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
1591: remaining_code.split("\n").each{ |line|
1592: if /^\s*?private\s*?$/ =~ line
1593: visibility_default = :private
1594: break
1595: end
1596: } if remaining_code
1597:
1598: remaining_code.split("\n").each{ |line|
1599: if /^\s*?private\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
1600: methods = $2.sub(/!.*$/, '')
1601: methods.split(",").each{ |meth|
1602: meth.sub!(/!.*$/, '')
1603: meth.gsub!(/:/, '')
1604: result << {
1605: "name" => meth.chomp.strip,
1606: "visibility" => :private,
1607: "used_modules" => used_modules.clone,
1608: "file_or_module" => container,
1609: "entity_is_discovered" => nil,
1610: "local_name" => nil
1611: }
1612: }
1613: elsif /^\s*?public\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
1614: methods = $2.sub(/!.*$/, '')
1615: methods.split(",").each{ |meth|
1616: meth.sub!(/!.*$/, '')
1617: meth.gsub!(/:/, '')
1618: result << {
1619: "name" => meth.chomp.strip,
1620: "visibility" => :public,
1621: "used_modules" => used_modules.clone,
1622: "file_or_module" => container,
1623: "entity_is_discovered" => nil,
1624: "local_name" => nil
1625: }
1626: }
1627: end
1628: } if remaining_code
1629:
1630: if container
1631: result.each{ |vis_info|
1632: vis_info["parent"] = container.name
1633: }
1634: end
1635:
1636: return visibility_default, result
1637: end
# File parsers/parse_f95.rb, line 1523
1523: def progress(char)
1524: unless @options.quiet
1525: @progress.print(char)
1526: @progress.flush
1527: end
1528: end
Empty lines in header are removed
# File parsers/parse_f95.rb, line 2004
2004: def remove_empty_head_lines(text)
2005: return "" unless text
2006: lines = text.split("\n")
2007: header = true
2008: lines.delete_if{ |line|
2009: header = false if /\S/ =~ line
2010: header && /^\s*?$/ =~ line
2011: }
2012: lines.join("\n")
2013: end
header marker "=", "==", … are removed
# File parsers/parse_f95.rb, line 2017
2017: def remove_header_marker(text)
2018: return text.gsub(/^\s?(=+)/, '<tt></tt>\1')
2019: end
# File parsers/parse_f95.rb, line 2021
2021: def remove_private_comments(body)
2022: body.gsub!(/^(\s*)!--\s*?$.*?^\s*!\+\+\s*?$/m, '\\1!')
2023: return body
2024: end
Remove "Alias for" in end of comments
# File parsers/parse_f95.rb, line 1983
1983: def remove_trailing_alias(text)
1984: return "" if !text
1985: lines = text.split("\n").reverse
1986: comment_block = Array.new
1987: checked = false
1988: lines.each do |line|
1989: if !checked
1990: if /^\s?#{INTERNAL_ALIAS_MES}/ =~ line ||
1991: /^\s?#{EXTERNAL_ALIAS_MES}/ =~ line
1992: checked = true
1993: next
1994: end
1995: end
1996: comment_block.unshift line
1997: end
1998: nice_lines = comment_block.join("\n")
1999: nice_lines ||= ""
2000: return nice_lines
2001: end
devine code constructs
# File parsers/parse_f95.rb, line 403
403: def scan
404:
405: # remove private comment
406: remaining_code = remove_private_comments(@body)
407:
408: # continuation lines are united to one line
409: remaining_code = united_to_one_line(remaining_code)
410:
411: # semicolons are replaced to line feed
412: remaining_code = semicolon_to_linefeed(remaining_code)
413:
414: # collect comment for file entity
415: whole_comment, remaining_code = collect_first_comment(remaining_code)
416: @top_level.comment = whole_comment
417:
418: # String "remaining_code" is converted to Array "remaining_lines"
419: remaining_lines = remaining_code.split("\n")
420:
421: # "module" or "program" parts are parsed (new)
422: #
423: level_depth = 0
424: block_searching_flag = nil
425: block_searching_lines = []
426: pre_comment = []
427: module_program_trailing = ""
428: module_program_name = ""
429: other_block_level_depth = 0
430: other_block_searching_flag = nil
431: remaining_lines.collect!{|line|
432: if !block_searching_flag && !other_block_searching_flag
433: if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i
434: block_searching_flag = :module
435: block_searching_lines << line
436: module_program_name = $1
437: module_program_trailing = find_comments($2)
438: next false
439: elsif line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i ||
440: line =~ /^\s*?\w/ && !block_start?(line)
441: block_searching_flag = :program
442: block_searching_lines << line
443: module_program_name = $1 || ""
444: module_program_trailing = find_comments($2)
445: next false
446:
447: elsif block_start?(line)
448: other_block_searching_flag = true
449: next line
450:
451: elsif line =~ /^\s*?!\s?(.*)/
452: pre_comment << line
453: next line
454: else
455: pre_comment = []
456: next line
457: end
458: elsif other_block_searching_flag
459: other_block_level_depth += 1 if block_start?(line)
460: other_block_level_depth -= 1 if block_end?(line)
461: if other_block_level_depth < 0
462: other_block_level_depth = 0
463: other_block_searching_flag = nil
464: end
465: next line
466: end
467:
468: block_searching_lines << line
469: level_depth += 1 if block_start?(line)
470: level_depth -= 1 if block_end?(line)
471: if level_depth >= 0
472: next false
473: end
474:
475: # "module_program_code" is formatted.
476: # ":nodoc:" flag is checked.
477: #
478: module_program_code = block_searching_lines.join("\n")
479: module_program_code = remove_empty_head_lines(module_program_code)
480: if module_program_trailing =~ /^:nodoc:/
481: # next loop to search next block
482: level_depth = 0
483: block_searching_flag = false
484: block_searching_lines = []
485: pre_comment = []
486: next false
487: end
488:
489: # NormalClass is created, and added to @top_level
490: #
491: if block_searching_flag == :module
492: module_name = module_program_name
493: module_code = module_program_code
494: module_trailing = module_program_trailing
495: progress "m"
496: @stats.num_modules += 1
497: f9x_module = @top_level.add_module NormalClass, module_name
498: f9x_module.record_location @top_level
499:
500: #
501: # Add provided modules information to @top_level comment
502: #
503: provided_modules = []
504: provided_mes_line_num = nil
505: top_level_comment_lines = []
506: line_num = 0
507: @top_level.comment.split("\n").each{|line|
508: top_level_comment_lines << line
509: line_num += 1
510: next if line.empty?
511: if !provided_mes_line_num && /^\s?#{PROVIDED_MODULES_MES}/ =~ line
512: provided_mes_line_num = line_num
513: next
514: end
515: if provided_mes_line_num
516: if /^\s?\*\s+<b>(\w+)<\/b>/ =~ line
517: provided_modules << $1
518: else
519: provided_mes_line_num = nil
520: end
521: end
522: }
523: line_num = 0
524: if provided_mes_line_num
525: top_level_comment_lines.collect!{ |line|
526: line_num += 1
527: if line_num < provided_mes_line_num
528: line
529: else
530: nil
531: end
532: }
533: top_level_comment_lines.delete_if{|line| !line }
534: end
535: top_level_comment_lines << "\n" + PROVIDED_MODULES_MES + "."
536: if provided_mes_line_num
537: top_level_comment_lines[-1].sub!(/\.$/, '')
538: top_level_comment_lines[-1] << "s."
539: end
540: provided_modules.each{ |mod|
541: top_level_comment_lines << "* <b>" + mod + "</b>"
542: }
543: top_level_comment_lines << "* <b>" + module_name + "</b>"
544: @top_level.comment = top_level_comment_lines.join("\n")
545:
546: #
547: # Information about the module is parsed
548: #
549: f9x_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) +
550: "\n" + module_trailing : module_trailing + "\n" +
551: find_comments(module_code.sub(/^.*$\n/i, ''))
552: f9x_module.comment = f9x_comment
553: parse_program_or_module(f9x_module, module_code)
554:
555: TopLevel.all_files.each do |name, toplevel|
556: if toplevel.include_includes?(module_name, @options.ignore_case)
557: if !toplevel.include_requires?(@file_name, @options.ignore_case)
558: toplevel.add_require(Require.new(@file_name, ""))
559: end
560: end
561: toplevel.each_classmodule{|m|
562: if m.include_includes?(module_name, @options.ignore_case)
563: if !m.include_requires?(@file_name, @options.ignore_case)
564: m.add_require(Require.new(@file_name, ""))
565: end
566: end
567: }
568: end
569:
570: namelist_comment =
571: find_namelists(f9x_module, before_contains(module_code))
572: f9x_module.comment << namelist_comment if namelist_comment
573:
574: elsif block_searching_flag == :program
575: program_name = module_program_name
576: program_name = "main_program" if program_name.empty?
577: program_code = module_program_code
578: program_trailing = module_program_trailing
579: program_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) +
580: "\n" + program_trailing : program_trailing + "\n" +
581: find_comments(program_code.sub(/^.*$\n/i, ''))
582:
583: progress "p"
584: @stats.num_methods += 1
585: f9x_mainprogram = AnyMethod.new("main_program", program_name)
586: f9x_mainprogram.singleton = false
587: f9x_mainprogram.comment = "<b><em> Main Program </em></b> :\n"
588: f9x_mainprogram.comment << program_comment
589: f9x_mainprogram.params = ""
590:
591: # For output source code
592: f9x_mainprogram.start_collecting_tokens
593: f9x_mainprogram.add_token Token.new(1,1).set_text(program_code)
594:
595: @top_level.add_method f9x_mainprogram
596: parse_program_or_module(@top_level, program_code, :private)
597:
598: namelist_comment = find_namelists(f9x_mainprogram, program_code)
599: f9x_mainprogram.comment << namelist_comment if namelist_comment
600: end
601:
602: # next loop to search next block
603: level_depth = 0
604: block_searching_flag = false
605: block_searching_lines = []
606: pre_comment = []
607: next false
608: }
609:
610: remaining_lines.delete_if{ |line|
611: line == false
612: }
613:
614: # External subprograms and functions are parsed
615: #
616: # 単一のファイル内において program や module に格納されない,
617: # 外部サブルーチン, 外部関数部分の解析.
618: #
619: parse_program_or_module(@top_level, remaining_lines.join("\n"),
620: :public, true)
621:
622: @top_level
623: end
Semicolons are replaced to line feed.
# File parsers/parse_f95.rb, line 1886
1886: def semicolon_to_linefeed(text)
1887: return "" unless text
1888: lines = text.split("\n")
1889: lines.collect!{ |line|
1890: indent_space = ""
1891: if line =~ /^(\s+)/
1892: indent_space = $1
1893: end
1894: words = line.split("")
1895: commentout = false
1896: squote = false ; dquote = false
1897: words.collect! { |char|
1898: if !(squote) && !(dquote) && !(commentout)
1899: case char
1900: when "!" ; commentout = true ; next char
1901: when "\""; dquote = true ; next char
1902: when "\'"; squote = true ; next char
1903: when ";" ; "\n"+indent_space
1904: else next char
1905: end
1906: elsif commentout
1907: next char
1908: elsif squote
1909: case char
1910: when "\'"; squote = false ; next char
1911: else next char
1912: end
1913: elsif dquote
1914: case char
1915: when "\""; dquote = false ; next char
1916: else next char
1917: end
1918: end
1919: }
1920: words.join("")
1921: }
1922: return lines.join("\n")
1923: end
Set visibility
"subname" element of "visibility_info" is deleted.
# File parsers/parse_f95.rb, line 1644
1644: def set_visibility(container, subname, visibility_default, visibility_info)
1645: return unless container || subname || visibility_default || visibility_info
1646: not_found = true
1647: visibility_info.collect!{ |info|
1648: if info["name"] == subname ||
1649: @options.ignore_case && info["name"].upcase == subname.upcase
1650: if info["file_or_module"].name == container.name
1651: container.set_visibility_for([subname], info["visibility"])
1652: info["entity_is_discovered"] = true
1653: not_found = false
1654: end
1655: end
1656: info
1657: }
1658: if not_found
1659: return container.set_visibility_for([subname], visibility_default)
1660: else
1661: return container
1662: end
1663: end
Continuous lines are united.
Comments in continuous lines are removed. If delete_space=false, spaces around "&" are not deleted.
Example
before
subroutine func(a, b, c, d, e, & ! ignored comments
& f, g, h) ! valid comments
after
subroutine func(a, b, c, d, e, f, g, h) ! valid comments
# File parsers/parse_f95.rb, line 1763
1763: def united_to_one_line(f90src, delete_space=true)
1764: return "" unless f90src
1765: lines = f90src.split("\n")
1766: previous_continuing = false
1767: now_continuing = false
1768: body = ""
1769: lines.each{ |line|
1770: words = line.split("")
1771: next if words.empty? && previous_continuing
1772: commentout = false
1773: brank_flag = true ; brank_char = ""
1774: squote = false ; dquote = false
1775: ignore = false
1776: words.collect! { |char|
1777: if previous_continuing && brank_flag
1778: now_continuing = true
1779: ignore = true
1780: case char
1781: when "!" ; break
1782: when " " ; brank_char << char ; next ""
1783: when "&"
1784: brank_flag = false
1785: now_continuing = false
1786: next ""
1787: else
1788: brank_flag = false
1789: now_continuing = false
1790: ignore = false
1791: next brank_char + char
1792: end
1793: end
1794: ignore = false
1795:
1796: if now_continuing
1797: next ""
1798: elsif !(squote) && !(dquote) && !(commentout)
1799: case char
1800: when "!" ; commentout = true ; next char
1801: when "\""; dquote = true ; next char
1802: when "\'"; squote = true ; next char
1803: when "&" ; now_continuing = true ; next ""
1804: else next char
1805: end
1806: elsif commentout
1807: next char
1808: elsif squote
1809: case char
1810: when "\'"; squote = false ; next char
1811: else next char
1812: end
1813: elsif dquote
1814: case char
1815: when "\""; dquote = false ; next char
1816: else next char
1817: end
1818: end
1819: }
1820: if !ignore && !previous_continuing || !brank_flag
1821: if previous_continuing
1822: if delete_space
1823: joined_words = words.join("")
1824: body = body.rstrip + " " + joined_words.lstrip
1825: else
1826: body << words.join("")
1827: end
1828: else
1829: body << "\n" + words.join("")
1830: end
1831: end
1832: previous_continuing = now_continuing ? true : nil
1833: now_continuing = nil
1834: }
1835: return body
1836: end