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 392 392: def initialize(top_level, file_name, body, options, stats) 393: @body = body 394: @stats = stats 395: @file_name = file_name 396: @options = options 397: @top_level = top_level 398: @progress = $stderr unless options.quiet 399: end
Return lines before "contains" statement in modules. "interface", "type" statements are removed.
# File parsers/parse_f95.rb, line 1300 1300: def before_contains(code) 1301: level_depth = 0 1302: before_contains_lines = [] 1303: before_contains_code = nil 1304: before_contains_flag = nil 1305: code.split("\n").each{ |line| 1306: if !before_contains_flag 1307: if line =~ /^\s*?module\s+\w+\s*?(!.*?)?$/i 1308: before_contains_flag = true 1309: end 1310: else 1311: break if line =~ /^\s*?contains\s*?(!.*?)?$/i 1312: level_depth += 1 if block_start?(line) 1313: level_depth -= 1 if block_end?(line) 1314: break if level_depth < 0 1315: before_contains_lines << line 1316: end 1317: 1318: } 1319: before_contains_code = before_contains_lines.join("\n") 1320: if before_contains_code 1321: before_contains_code.gsub!(/^\s*?interface\s+.*?\s+end\s+interface.*?$/im, "") 1322: before_contains_code.gsub!(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "") 1323: end 1324: 1325: before_contains_code 1326: end
Which "line" is end of block (module, program, block data, subroutine, function) statement ?
# 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 1331 1331: def collect_first_comment(body) 1332: comment = "" 1333: not_comment = "" 1334: comment_start = false 1335: comment_end = false 1336: body.split("\n").each{ |line| 1337: if comment_end 1338: not_comment << line 1339: not_comment << "\n" 1340: elsif /^\s*?!\s?(.*)$/i =~ line 1341: comment_start = true 1342: comment << $1 1343: comment << "\n" 1344: elsif /^\s*?$/i =~ line 1345: comment_end = true if comment_start && COMMENTS_ARE_UPPER 1346: else 1347: comment_end = true 1348: not_comment << line 1349: not_comment << "\n" 1350: end 1351: } 1352: return comment, not_comment 1353: end
Comment out checker
# 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 1362 1362: def find_arguments(args, text, all=nil, indent=nil, modified_params=nil) 1363: return unless args || all 1364: indent = "" unless indent 1365: args = ["all"] if all 1366: params = "" if modified_params 1367: comma = "" 1368: return unless text 1369: args_rdocforms = "\n" 1370: remaining_lines = "#{text}" 1371: definitions = definition_info(remaining_lines) 1372: args.each{ |arg| 1373: arg.strip! 1374: arg.chomp! 1375: definitions.each { |defitem| 1376: if arg == defitem.varname.strip.chomp || all 1377: args_rdocforms << "\n\#{indent}<b><tt>\#{defitem.varname.chomp.strip}\#{defitem.arraysuffix} </tt></b> <tt> \#{defitem.inivalue}</tt> ::\n\#{indent} <tt>\#{defitem.types.chomp.strip}</tt>\n" 1378: if !defitem.comment.chomp.strip.empty? 1379: comment = "" 1380: defitem.comment.split("\n").each{ |line| 1381: comment << " " + line + "\n" 1382: } 1383: args_rdocforms << "\n\#{indent} <tt></tt> ::\n\#{indent} <tt></tt>\n\#{indent} \#{comment.chomp.strip}\n" 1384: end 1385: 1386: if modified_params 1387: if defitem.include_attr?("optional") 1388: params << "#{comma}[#{arg}]" 1389: else 1390: params << "#{comma}#{arg}" 1391: end 1392: comma = ", " 1393: end 1394: end 1395: } 1396: } 1397: if modified_params 1398: return args_rdocforms, params 1399: else 1400: return args_rdocforms 1401: end 1402: end
Comments just after module or subprogram, or arguments are returnd. If "COMMENTS_ARE_UPPER" is true, comments just before modules or subprograms are returnd
# 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 1420 1420: def find_namelists(container, text, before_contains=nil) 1421: return nil if !text 1422: top_level = find_toplevel(container) 1423: 1424: if text =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)(!.*?)?$/i 1425: if top_level.include_includes?(NAMELIST_REPOSITORY_NAME) 1426: namelist_module = 1427: top_level.find_module_named(NAMELIST_REPOSITORY_NAME) 1428: else 1429: namelist_module = 1430: top_level.add_module NormalClass, NAMELIST_REPOSITORY_NAME 1431: namelist_module.record_location top_level 1432: namelist_module.comment = "This is not a module but a repository of NAMELIST group names declared\nin all Fortran 90/95 files\n" 1433: end 1434: else 1435: return "" 1436: end 1437: 1438: nml_group_name_lists = [] 1439: lines = "#{text}" 1440: before_contains = "" if !before_contains 1441: while lines =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)(!.*?)?$/i 1442: lines = $~.post_match 1443: pre_match = $~.pre_match ; post_match = $~.post_match 1444: nml_group_name = $1 1445: trailing_comment = $3 || "" 1446: nml_vars_list = $2.split(",") 1447: nml_comment = COMMENTS_ARE_UPPER ? 1448: find_comments(pre_match.sub(/\n$/, '')) : 1449: find_comments(trailing_comment + post_match) 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 626 626: def parse_program_or_module(container, code, 627: visibility=:public, external=nil) 628: return unless container 629: return unless code 630: remaining_lines = code.split("\n") 631: remaining_code = "#{code}" 632: 633: # 634: # Parse variables before "contains" in module 635: # 636: # namelist 変数の定義に使われたり, これ自体が定数, 変数 637: # 提供されるのに利用される. (変数や定数として利用される場合, 638: # これもメソッドとして提供する. 639: # 640: before_contains_code = before_contains(remaining_code) 641: 642: # 643: # Parse global "use" 644: # 645: use_check_code = "#{before_contains_code}" 646: cascaded_modules_list = [] 647: while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i 648: use_check_code = $~.pre_match 649: use_check_code << $~.post_match 650: used_mod_name = $1.strip.chomp 651: used_list = $2 || "" 652: used_trailing = $3 || "" 653: next if used_trailing =~ /!:nodoc:/ 654: if !container.include_includes?(used_mod_name, @options.ignore_case) 655: progress "." 656: container.add_include Include.new(used_mod_name, "") 657: end 658: if ! (used_list =~ /\,\s*?only\s*?:/i ) 659: cascaded_modules_list << "\#" + used_mod_name 660: end 661: end 662: 663: # 664: # Parse public and private, and store information. 665: # This information is used when "add_method" and 666: # "set_visibility_for" are called. 667: # 668: visibility_default, visibility_info = 669: parse_visibility(remaining_lines.join("\n"), visibility, container) 670: @@public_methods.concat visibility_info 671: if visibility_default == :public 672: if !cascaded_modules_list.empty? 673: cascaded_modules = 674: Attr.new("Cascaded Modules", 675: "Imported modules all of whose components are published again", 676: "", 677: cascaded_modules_list.join(", ")) 678: container.add_attribute(cascaded_modules) 679: end 680: end 681: 682: # 683: # Check rename elements 684: # 685: use_check_code = "#{before_contains_code}" 686: while use_check_code =~ /^\s*?use\s+(\w+)\s*?\,(.+)$/i 687: use_check_code = $~.pre_match 688: use_check_code << $~.post_match 689: used_mod_name = $1.strip.chomp 690: used_elements = $2.sub(/\s*?only\s*?:\s*?/i, '') 691: used_elements.split(",").each{ |used| 692: if /\s*?(\w+)\s*?=>\s*?(\w+)\s*?/ =~ used 693: local = $1 694: org = $2 695: @@public_methods.collect!{ |pub_meth| 696: if local == pub_meth["name"] || 697: local.upcase == pub_meth["name"].upcase && 698: @options.ignore_case 699: pub_meth["name"] = org 700: pub_meth["local_name"] = local 701: end 702: pub_meth 703: } 704: end 705: } 706: end 707: 708: # 709: # Parse private "use" 710: # 711: use_check_code = remaining_lines.join("\n") 712: while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i 713: use_check_code = $~.pre_match 714: use_check_code << $~.post_match 715: used_mod_name = $1.strip.chomp 716: used_trailing = $3 || "" 717: next if used_trailing =~ /!:nodoc:/ 718: if !container.include_includes?(used_mod_name, @options.ignore_case) 719: progress "." 720: container.add_include Include.new(used_mod_name, "") 721: end 722: end 723: 724: container.each_includes{ |inc| 725: TopLevel.all_files.each do |name, toplevel| 726: indicated_mod = toplevel.find_symbol(inc.name, 727: nil, @options.ignore_case) 728: if indicated_mod 729: indicated_name = indicated_mod.parent.file_relative_name 730: if !container.include_requires?(indicated_name, @options.ignore_case) 731: container.add_require(Require.new(indicated_name, "")) 732: end 733: break 734: end 735: end 736: } 737: 738: # 739: # Parse derived types definitions 740: # 741: derived_types_comment = "" 742: remaining_code = remaining_lines.join("\n") 743: while remaining_code =~ /^\s*? 744: type[\s\,]+(public|private)?\s*?(::)?\s*? 745: (\w+)\s*?(!.*?)?$ 746: (.*?) 747: ^\s*?end\s+type.*?$ 748: /imx 749: remaining_code = $~.pre_match 750: remaining_code << $~.post_match 751: typename = $3.chomp.strip 752: type_elements = $5 || "" 753: type_code = remove_empty_head_lines($&) 754: type_trailing = find_comments($4) 755: next if type_trailing =~ /^:nodoc:/ 756: type_visibility = $1 757: type_comment = COMMENTS_ARE_UPPER ? 758: find_comments($~.pre_match) + "\n" + type_trailing : 759: type_trailing + "\n" + find_comments(type_code.sub(/^.*$\n/i, '')) 760: type_element_visibility_public = true 761: type_code.split("\n").each{ |line| 762: if /^\s*?private\s*?$/ =~ line 763: type_element_visibility_public = nil 764: break 765: end 766: } if type_code 767: 768: args_comment = "" 769: type_args_info = nil 770: 771: if @options.show_all 772: args_comment = find_arguments(nil, type_code, true) 773: else 774: type_public_args_list = [] 775: type_args_info = definition_info(type_code) 776: type_args_info.each{ |arg| 777: arg_is_public = type_element_visibility_public 778: arg_is_public = true if arg.include_attr?("public") 779: arg_is_public = nil if arg.include_attr?("private") 780: type_public_args_list << arg.varname if arg_is_public 781: } 782: args_comment = find_arguments(type_public_args_list, type_code) 783: end 784: 785: type = AnyMethod.new("type #{typename}", typename) 786: type.singleton = false 787: type.params = "" 788: type.comment = "<b><em> Derived Type </em></b> :: <tt></tt>\n" 789: type.comment << args_comment if args_comment 790: type.comment << type_comment if type_comment 791: progress "t" 792: @stats.num_methods += 1 793: container.add_method type 794: 795: set_visibility(container, typename, visibility_default, @@public_methods) 796: 797: if type_visibility 798: type_visibility.gsub!(/\s/,'') 799: type_visibility.gsub!(/\,/,'') 800: type_visibility.gsub!(/:/,'') 801: type_visibility.downcase! 802: if type_visibility == "public" 803: container.set_visibility_for([typename], :public) 804: elsif type_visibility == "private" 805: container.set_visibility_for([typename], :private) 806: end 807: end 808: 809: check_public_methods(type, container.name) 810: 811: if @options.show_all 812: derived_types_comment << ", " unless derived_types_comment.empty? 813: derived_types_comment << typename 814: else 815: if type.visibility == :public 816: derived_types_comment << ", " unless derived_types_comment.empty? 817: derived_types_comment << typename 818: end 819: end 820: 821: end 822: 823: if !derived_types_comment.empty? 824: derived_types_table = 825: Attr.new("Derived Types", "Derived_Types", "", 826: derived_types_comment) 827: container.add_attribute(derived_types_table) 828: end 829: 830: # 831: # move interface scope 832: # 833: interface_code = "" 834: while remaining_code =~ /^\s*? 835: interface( 836: \s+\w+ | 837: \s+operator\s*?\(.*?\) | 838: \s+assignment\s*?\(\s*?=\s*?\) 839: )?\s*?$ 840: (.*?) 841: ^\s*?end\s+interface.*?$ 842: /imx 843: interface_code << remove_empty_head_lines($&) + "\n" 844: remaining_code = $~.pre_match 845: remaining_code << $~.post_match 846: end 847: 848: # 849: # Parse global constants or variables in modules 850: # 851: const_var_defs = definition_info(before_contains_code) 852: const_var_defs.each{|defitem| 853: next if defitem.nodoc 854: const_or_var_type = "Variable" 855: const_or_var_progress = "v" 856: if defitem.include_attr?("parameter") 857: const_or_var_type = "Constant" 858: const_or_var_progress = "c" 859: end 860: const_or_var = AnyMethod.new(const_or_var_type, defitem.varname) 861: const_or_var.singleton = false 862: const_or_var.params = "" 863: self_comment = find_arguments([defitem.varname], before_contains_code) 864: const_or_var.comment = "<b><em>" + const_or_var_type + "</em></b> :: <tt></tt>\n" 865: const_or_var.comment << self_comment if self_comment 866: progress const_or_var_progress 867: @stats.num_methods += 1 868: container.add_method const_or_var 869: 870: set_visibility(container, defitem.varname, visibility_default, @@public_methods) 871: 872: if defitem.include_attr?("public") 873: container.set_visibility_for([defitem.varname], :public) 874: elsif defitem.include_attr?("private") 875: container.set_visibility_for([defitem.varname], :private) 876: end 877: 878: check_public_methods(const_or_var, container.name) 879: 880: } if const_var_defs 881: 882: remaining_lines = remaining_code.split("\n") 883: 884: # "subroutine" or "function" parts are parsed (new) 885: # 886: level_depth = 0 887: block_searching_flag = nil 888: block_searching_lines = [] 889: pre_comment = [] 890: procedure_trailing = "" 891: procedure_name = "" 892: procedure_params = "" 893: procedure_prefix = "" 894: procedure_result_arg = "" 895: procedure_type = "" 896: contains_lines = [] 897: contains_flag = nil 898: remaining_lines.collect!{|line| 899: if !block_searching_flag 900: # subroutine 901: if line =~ /^\s*? 902: (recursive|pure|elemental)?\s*? 903: subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$ 904: /ix 905: block_searching_flag = :subroutine 906: block_searching_lines << line 907: 908: procedure_name = $2.chomp.strip 909: procedure_params = $3 || "" 910: procedure_prefix = $1 || "" 911: procedure_trailing = $4 || "!" 912: next false 913: 914: # function 915: elsif line =~ /^\s*? 916: (recursive|pure|elemental)?\s*? 917: ( 918: character\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 919: | type\s*?\([\w\s]+?\)\s+ 920: | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 921: | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 922: | double\s+precision\s+ 923: | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 924: | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 925: )? 926: function\s+(\w+)\s*? 927: (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$ 928: /ix 929: block_searching_flag = :function 930: block_searching_lines << line 931: 932: procedure_prefix = $1 || "" 933: procedure_type = $2 ? $2.chomp.strip : nil 934: procedure_name = $8.chomp.strip 935: procedure_params = $9 || "" 936: procedure_result_arg = $11 ? $11.chomp.strip : procedure_name 937: procedure_trailing = $12 || "!" 938: next false 939: elsif line =~ /^\s*?!\s?(.*)/ 940: pre_comment << line 941: next line 942: else 943: pre_comment = [] 944: next line 945: end 946: end 947: contains_flag = true if line =~ /^\s*?contains\s*?(!.*?)?$/ 948: block_searching_lines << line 949: contains_lines << line if contains_flag 950: 951: level_depth += 1 if block_start?(line) 952: level_depth -= 1 if block_end?(line) 953: if level_depth >= 0 954: next false 955: end 956: 957: # "procedure_code" is formatted. 958: # ":nodoc:" flag is checked. 959: # 960: procedure_code = block_searching_lines.join("\n") 961: procedure_code = remove_empty_head_lines(procedure_code) 962: if procedure_trailing =~ /^!:nodoc:/ 963: # next loop to search next block 964: level_depth = 0 965: block_searching_flag = nil 966: block_searching_lines = [] 967: pre_comment = [] 968: procedure_trailing = "" 969: procedure_name = "" 970: procedure_params = "" 971: procedure_prefix = "" 972: procedure_result_arg = "" 973: procedure_type = "" 974: contains_lines = [] 975: contains_flag = nil 976: next false 977: end 978: 979: # AnyMethod is created, and added to container 980: # 981: subroutine_function = nil 982: if block_searching_flag == :subroutine 983: subroutine_prefix = procedure_prefix 984: subroutine_name = procedure_name 985: subroutine_params = procedure_params 986: subroutine_trailing = procedure_trailing 987: subroutine_code = procedure_code 988: 989: subroutine_comment = COMMENTS_ARE_UPPER ? 990: pre_comment.join("\n") + "\n" + subroutine_trailing : 991: subroutine_trailing + "\n" + subroutine_code.sub(/^.*$\n/i, '') 992: subroutine = AnyMethod.new("subroutine", subroutine_name) 993: parse_subprogram(subroutine, subroutine_params, 994: subroutine_comment, subroutine_code, 995: before_contains_code, nil, subroutine_prefix) 996: progress "s" 997: @stats.num_methods += 1 998: container.add_method subroutine 999: subroutine_function = subroutine 1000: 1001: namelist_comment = 1002: find_namelists(subroutine, subroutine_code, before_contains_code) 1003: subroutine.comment << namelist_comment if namelist_comment 1004: 1005: elsif block_searching_flag == :function 1006: function_prefix = procedure_prefix 1007: function_type = procedure_type 1008: function_name = procedure_name 1009: function_params_org = procedure_params 1010: function_result_arg = procedure_result_arg 1011: function_trailing = procedure_trailing 1012: function_code_org = procedure_code 1013: 1014: function_comment = COMMENTS_ARE_UPPER ? 1015: pre_comment.join("\n") + "\n" + function_trailing : 1016: function_trailing + "\n " + function_code_org.sub(/^.*$\n/i, '') 1017: 1018: function_code = "#{function_code_org}" 1019: if function_type 1020: function_code << "\n" + function_type + " :: " + function_result_arg 1021: end 1022: 1023: function_params = 1024: function_params_org.sub(/^\(/, "\(#{function_result_arg}, ") 1025: 1026: function = AnyMethod.new("function", function_name) 1027: parse_subprogram(function, function_params, 1028: function_comment, function_code, 1029: before_contains_code, true, function_prefix) 1030: 1031: # Specific modification due to function 1032: function.params.sub!(/\(\s*?#{function_result_arg}\s*?,\s*?/, "\( ") 1033: function.params << " result(" + function_result_arg + ")" 1034: function.start_collecting_tokens 1035: function.add_token Token.new(1,1).set_text(function_code_org) 1036: 1037: progress "f" 1038: @stats.num_methods += 1 1039: container.add_method function 1040: subroutine_function = function 1041: 1042: namelist_comment = 1043: find_namelists(function, function_code, before_contains_code) 1044: function.comment << namelist_comment if namelist_comment 1045: 1046: end 1047: 1048: # The visibility of procedure is specified 1049: # 1050: set_visibility(container, procedure_name, 1051: visibility_default, @@public_methods) 1052: 1053: # The alias for this procedure from external modules 1054: # 1055: check_external_aliases(procedure_name, 1056: subroutine_function.params, 1057: subroutine_function.comment, subroutine_function) if external 1058: check_public_methods(subroutine_function, container.name) 1059: 1060: 1061: # contains_lines are parsed as private procedures 1062: if contains_flag 1063: parse_program_or_module(container, 1064: contains_lines.join("\n"), :private) 1065: end 1066: 1067: # next loop to search next block 1068: level_depth = 0 1069: block_searching_flag = nil 1070: block_searching_lines = [] 1071: pre_comment = [] 1072: procedure_trailing = "" 1073: procedure_name = "" 1074: procedure_params = "" 1075: procedure_prefix = "" 1076: procedure_result_arg = "" 1077: contains_lines = [] 1078: contains_flag = nil 1079: next false 1080: } # End of remaining_lines.collect!{|line| 1081: 1082: # Array remains_lines is converted to String remains_code again 1083: # 1084: remaining_code = remaining_lines.join("\n") 1085: 1086: # 1087: # Parse interface 1088: # 1089: interface_scope = false 1090: generic_name = "" 1091: interface_code.split("\n").each{ |line| 1092: if /^\s*? 1093: interface( 1094: \s+\w+| 1095: \s+operator\s*?\(.*?\)| 1096: \s+assignment\s*?\(\s*?=\s*?\) 1097: )? 1098: \s*?(!.*?)?$ 1099: /ix =~ line 1100: generic_name = $1 ? $1.strip.chomp : nil 1101: interface_trailing = $2 || "!" 1102: interface_scope = true 1103: interface_scope = false if interface_trailing =~ /!:nodoc:/ 1104: # if generic_name =~ /operator\s*?\((.*?)\)/i 1105: # operator_name = $1 1106: # if operator_name && !operator_name.empty? 1107: # generic_name = "#{operator_name}" 1108: # end 1109: # end 1110: # if generic_name =~ /assignment\s*?\((.*?)\)/i 1111: # assignment_name = $1 1112: # if assignment_name && !assignment_name.empty? 1113: # generic_name = "#{assignment_name}" 1114: # end 1115: # end 1116: end 1117: if /^\s*?end\s+interface/i =~ line 1118: interface_scope = false 1119: generic_name = nil 1120: end 1121: # internal alias 1122: if interface_scope && /^\s*?module\s+procedure\s+(.*?)(!.*?)?$/i =~ line 1123: procedures = $1.strip.chomp 1124: procedures_trailing = $2 || "!" 1125: next if procedures_trailing =~ /!:nodoc:/ 1126: procedures.split(",").each{ |proc| 1127: proc.strip! 1128: proc.chomp! 1129: next if generic_name == proc || !generic_name 1130: old_meth = container.find_symbol(proc, nil, @options.ignore_case) 1131: next if !old_meth 1132: nolink = old_meth.visibility == :private ? true : nil 1133: nolink = nil if @options.show_all 1134: new_meth = 1135: initialize_external_method(generic_name, proc, 1136: old_meth.params, nil, 1137: old_meth.comment, 1138: old_meth.clone.token_stream[0].text, 1139: true, nolink) 1140: new_meth.singleton = old_meth.singleton 1141: 1142: progress "i" 1143: @stats.num_methods += 1 1144: container.add_method new_meth 1145: 1146: set_visibility(container, generic_name, visibility_default, @@public_methods) 1147: 1148: check_public_methods(new_meth, container.name) 1149: 1150: } 1151: end 1152: 1153: # external aliases 1154: if interface_scope 1155: # subroutine 1156: proc = nil 1157: params = nil 1158: procedures_trailing = nil 1159: if line =~ /^\s*? 1160: (recursive|pure|elemental)?\s*? 1161: subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$ 1162: /ix 1163: proc = $2.chomp.strip 1164: generic_name = proc unless generic_name 1165: params = $3 || "" 1166: procedures_trailing = $4 || "!" 1167: 1168: # function 1169: elsif line =~ /^\s*? 1170: (recursive|pure|elemental)?\s*? 1171: ( 1172: character\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1173: | type\s*?\([\w\s]+?\)\s+ 1174: | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1175: | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1176: | double\s+precision\s+ 1177: | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1178: | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1179: )? 1180: function\s+(\w+)\s*? 1181: (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$ 1182: /ix 1183: proc = $8.chomp.strip 1184: generic_name = proc unless generic_name 1185: params = $9 || "" 1186: procedures_trailing = $12 || "!" 1187: else 1188: next 1189: end 1190: next if procedures_trailing =~ /!:nodoc:/ 1191: indicated_method = nil 1192: indicated_file = nil 1193: TopLevel.all_files.each do |name, toplevel| 1194: indicated_method = toplevel.find_local_symbol(proc, @options.ignore_case) 1195: indicated_file = name 1196: break if indicated_method 1197: end 1198: 1199: if indicated_method 1200: external_method = 1201: initialize_external_method(generic_name, proc, 1202: indicated_method.params, 1203: indicated_file, 1204: indicated_method.comment) 1205: 1206: progress "e" 1207: @stats.num_methods += 1 1208: container.add_method external_method 1209: set_visibility(container, generic_name, visibility_default, @@public_methods) 1210: if !container.include_requires?(indicated_file, @options.ignore_case) 1211: container.add_require(Require.new(indicated_file, "")) 1212: end 1213: check_public_methods(external_method, container.name) 1214: 1215: else 1216: @@external_aliases << { 1217: "new_name" => generic_name, 1218: "old_name" => proc, 1219: "file_or_module" => container, 1220: "visibility" => find_visibility(container, generic_name, @@public_methods) || visibility_default 1221: } 1222: end 1223: end 1224: 1225: } if interface_code # End of interface_code.split("\n").each ... 1226: 1227: # 1228: # Already imported methods are removed from @@public_methods. 1229: # Remainders are assumed to be imported from other modules. 1230: # 1231: # 既に参照済みのメソッドは @@public_methods から取り除く. 1232: # 残りは外部モジュールからの参照と仮定する. 1233: # 1234: @@public_methods.delete_if{ |method| method["entity_is_discovered"]} 1235: 1236: @@public_methods.each{ |pub_meth| 1237: next unless pub_meth["file_or_module"].name == container.name 1238: pub_meth["used_modules"].each{ |used_mod| 1239: TopLevel.all_classes_and_modules.each{ |modules| 1240: if modules.name == used_mod || 1241: modules.name.upcase == used_mod.upcase && 1242: @options.ignore_case 1243: modules.method_list.each{ |meth| 1244: if meth.name == pub_meth["name"] || 1245: meth.name.upcase == pub_meth["name"].upcase && 1246: @options.ignore_case 1247: new_meth = initialize_public_method(meth, 1248: modules.name) 1249: if pub_meth["local_name"] 1250: new_meth.name = pub_meth["local_name"] 1251: end 1252: progress "e" 1253: @stats.num_methods += 1 1254: container.add_method new_meth 1255: end 1256: } 1257: end 1258: } 1259: } 1260: } 1261: 1262: container 1263: end
Parse arguments, comment, code of subroutine and function. Return AnyMethod object.
# File parsers/parse_f95.rb, line 1269 1269: def parse_subprogram(subprogram, params, comment, code, 1270: before_contains=nil, function=nil, prefix=nil) 1271: subprogram.singleton = false 1272: prefix = "" if !prefix 1273: arguments = params.sub(/\(/, "").sub(/\)/, "").split(",") if params 1274: args_comment, params_opt = 1275: find_arguments(arguments, code.sub(/^s*?contains\s*?(!.*?)?$.*/im, ""), 1276: nil, nil, true) 1277: params_opt = "( " + params_opt + " ) " if params_opt 1278: subprogram.params = params_opt || "" 1279: 1280: block_comment = find_comments comment 1281: if function 1282: subprogram.comment = "<b><em> Function </em></b> :: <em>#{prefix}</em>\n" 1283: else 1284: subprogram.comment = "<b><em> Subroutine </em></b> :: <em>#{prefix}</em>\n" 1285: end 1286: subprogram.comment << args_comment if args_comment 1287: subprogram.comment << block_comment if block_comment 1288: 1289: # For output source code 1290: subprogram.start_collecting_tokens 1291: subprogram.add_token Token.new(1,1).set_text(code) 1292: 1293: subprogram 1294: end
Parse visibility
# 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 402 402: def scan 403: 404: # remove private comment 405: remaining_code = remove_private_comments(@body) 406: 407: # continuation lines are united to one line 408: remaining_code = united_to_one_line(remaining_code) 409: 410: # semicolons are replaced to line feed 411: remaining_code = semicolon_to_linefeed(remaining_code) 412: 413: # collect comment for file entity 414: whole_comment, remaining_code = collect_first_comment(remaining_code) 415: @top_level.comment = whole_comment 416: 417: # String "remaining_code" is converted to Array "remaining_lines" 418: remaining_lines = remaining_code.split("\n") 419: 420: # "module" or "program" parts are parsed (new) 421: # 422: level_depth = 0 423: block_searching_flag = nil 424: block_searching_lines = [] 425: pre_comment = [] 426: module_program_trailing = "" 427: module_program_name = "" 428: other_block_level_depth = 0 429: other_block_searching_flag = nil 430: remaining_lines.collect!{|line| 431: if !block_searching_flag && !other_block_searching_flag 432: if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i 433: block_searching_flag = :module 434: block_searching_lines << line 435: module_program_name = $1 436: module_program_trailing = find_comments($2) 437: next false 438: elsif line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i || 439: line =~ /^\s*?\w/ && !block_start?(line) 440: block_searching_flag = :program 441: block_searching_lines << line 442: module_program_name = $1 || "" 443: module_program_trailing = find_comments($2) 444: next false 445: 446: elsif block_start?(line) 447: other_block_searching_flag = true 448: next line 449: 450: elsif line =~ /^\s*?!\s?(.*)/ 451: pre_comment << line 452: next line 453: else 454: pre_comment = [] 455: next line 456: end 457: elsif other_block_searching_flag 458: other_block_level_depth += 1 if block_start?(line) 459: other_block_level_depth -= 1 if block_end?(line) 460: if other_block_level_depth < 0 461: other_block_level_depth = 0 462: other_block_searching_flag = nil 463: end 464: next line 465: end 466: 467: block_searching_lines << line 468: level_depth += 1 if block_start?(line) 469: level_depth -= 1 if block_end?(line) 470: if level_depth >= 0 471: next false 472: end 473: 474: # "module_program_code" is formatted. 475: # ":nodoc:" flag is checked. 476: # 477: module_program_code = block_searching_lines.join("\n") 478: module_program_code = remove_empty_head_lines(module_program_code) 479: if module_program_trailing =~ /^:nodoc:/ 480: # next loop to search next block 481: level_depth = 0 482: block_searching_flag = false 483: block_searching_lines = [] 484: pre_comment = [] 485: next false 486: end 487: 488: # NormalClass is created, and added to @top_level 489: # 490: if block_searching_flag == :module 491: module_name = module_program_name 492: module_code = module_program_code 493: module_trailing = module_program_trailing 494: progress "m" 495: @stats.num_modules += 1 496: f9x_module = @top_level.add_module NormalClass, module_name 497: f9x_module.record_location @top_level 498: 499: # 500: # Add provided modules information to @top_level comment 501: # 502: provided_modules = [] 503: provided_mes_line_num = nil 504: top_level_comment_lines = [] 505: line_num = 0 506: @top_level.comment.split("\n").each{|line| 507: top_level_comment_lines << line 508: line_num += 1 509: next if line.empty? 510: if !provided_mes_line_num && /^\s?#{PROVIDED_MODULES_MES}/ =~ line 511: provided_mes_line_num = line_num 512: next 513: end 514: if provided_mes_line_num 515: if /^\s?\*\s+<b>(\w+)<\/b>/ =~ line 516: provided_modules << $1 517: else 518: provided_mes_line_num = nil 519: end 520: end 521: } 522: line_num = 0 523: if provided_mes_line_num 524: top_level_comment_lines.collect!{ |line| 525: line_num += 1 526: if line_num < provided_mes_line_num 527: line 528: else 529: nil 530: end 531: } 532: top_level_comment_lines.delete_if{|line| !line } 533: end 534: top_level_comment_lines << "\n" + PROVIDED_MODULES_MES + "." 535: if provided_mes_line_num 536: top_level_comment_lines[-1].sub!(/\.$/, '') 537: top_level_comment_lines[-1] << "s." 538: end 539: provided_modules.each{ |mod| 540: top_level_comment_lines << "* <b>" + mod + "</b>" 541: } 542: top_level_comment_lines << "* <b>" + module_name + "</b>" 543: @top_level.comment = top_level_comment_lines.join("\n") 544: 545: # 546: # Information about the module is parsed 547: # 548: f9x_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) + 549: "\n" + module_trailing : module_trailing + "\n" + 550: find_comments(module_code.sub(/^.*$\n/i, '')) 551: f9x_module.comment = f9x_comment 552: parse_program_or_module(f9x_module, module_code) 553: 554: TopLevel.all_files.each do |name, toplevel| 555: if toplevel.include_includes?(module_name, @options.ignore_case) 556: if !toplevel.include_requires?(@file_name, @options.ignore_case) 557: toplevel.add_require(Require.new(@file_name, "")) 558: end 559: end 560: toplevel.each_classmodule{|m| 561: if m.include_includes?(module_name, @options.ignore_case) 562: if !m.include_requires?(@file_name, @options.ignore_case) 563: m.add_require(Require.new(@file_name, "")) 564: end 565: end 566: } 567: end 568: 569: namelist_comment = 570: find_namelists(f9x_module, before_contains(module_code)) 571: f9x_module.comment << namelist_comment if namelist_comment 572: 573: elsif block_searching_flag == :program 574: program_name = module_program_name 575: program_name = "main_program" if program_name.empty? 576: program_code = module_program_code 577: program_trailing = module_program_trailing 578: program_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) + 579: "\n" + program_trailing : program_trailing + "\n" + 580: find_comments(program_code.sub(/^.*$\n/i, '')) 581: 582: progress "p" 583: @stats.num_methods += 1 584: f9x_mainprogram = AnyMethod.new("main_program", program_name) 585: f9x_mainprogram.singleton = false 586: f9x_mainprogram.comment = "<b><em> Main Program </em></b> :: <tt></tt>\n" 587: f9x_mainprogram.comment << program_comment 588: f9x_mainprogram.params = "" 589: 590: # For output source code 591: f9x_mainprogram.start_collecting_tokens 592: f9x_mainprogram.add_token Token.new(1,1).set_text(program_code) 593: 594: @top_level.add_method f9x_mainprogram 595: parse_program_or_module(@top_level, program_code, :private) 596: 597: namelist_comment = find_namelists(f9x_mainprogram, program_code) 598: f9x_mainprogram.comment << namelist_comment if namelist_comment 599: end 600: 601: # next loop to search next block 602: level_depth = 0 603: block_searching_flag = false 604: block_searching_lines = [] 605: pre_comment = [] 606: next false 607: } 608: 609: remaining_lines.delete_if{ |line| 610: line == false 611: } 612: 613: # External subprograms and functions are parsed 614: # 615: # 単一のファイル内において program や module に格納されない, 616: # 外部サブルーチン, 外部関数部分の解析. 617: # 618: parse_program_or_module(@top_level, remaining_lines.join("\n"), 619: :public, true) 620: 621: @top_level 622: end
Semicolons are replaced to line feed.
# 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