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 1964 1964: def block_end?(line) 1965: return nil if !line 1966: 1967: if line =~ /^\s*?end\s*?(!.*?)?$/i || 1968: line =~ /^\s*?end\s+module(\s+\w+)?\s*?(!.*?)?$/i || 1969: line =~ /^\s*?end\s+program(\s+\w+)?\s*?(!.*?)?$/i || 1970: line =~ /^\s*?end\s+block\s+data(\s+\w+)?\s*?(!.*?)?$/i || 1971: line =~ /^\s*?end\s+subroutine(\s+\w+)?\s*?(!.*?)?$/i || 1972: line =~ /^\s*?end\s+function(\s+\w+)?\s*?(!.*?)?$/i 1973: return true 1974: end 1975: 1976: return nil 1977: end
Which "line" is start of block (module, program, block data, subroutine, function) statement ?
# File parsers/parse_f95.rb, line 1928 1928: def block_start?(line) 1929: return nil if !line 1930: 1931: if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i || 1932: line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i || 1933: line =~ /^\s*?block\s+data(\s+\w+)?\s*?(!.*?)?$/i || 1934: line =~ \ 1935: /^\s*? 1936: (recursive|pure|elemental)?\s*? 1937: subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$ 1938: /ix || 1939: line =~ \ 1940: /^\s*? 1941: (recursive|pure|elemental)?\s*? 1942: ( 1943: character\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1944: | type\s*?\([\w\s]+?\)\s+ 1945: | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1946: | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1947: | double\s+precision\s+ 1948: | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1949: | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1950: )? 1951: function\s+(\w+)\s*? 1952: (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$ 1953: /ix 1954: return true 1955: end 1956: 1957: return nil 1958: end
Check external aliases
subname というサブルーチン名, または関数名を持つファイルを 探査し, 存在する場合にはそのファイル内へメソッドを追加する.
# File parsers/parse_f95.rb, line 1686 1686: def check_external_aliases(subname, params, comment, test=nil) 1687: @@external_aliases.each{ |alias_item| 1688: if subname == alias_item["old_name"] || 1689: subname.upcase == alias_item["old_name"].upcase && 1690: @options.ignore_case 1691: 1692: new_meth = initialize_external_method(alias_item["new_name"], 1693: subname, params, @file_name, 1694: comment) 1695: new_meth.visibility = alias_item["visibility"] 1696: 1697: progress "e" 1698: @stats.num_methods += 1 1699: alias_item["file_or_module"].add_method(new_meth) 1700: 1701: if !alias_item["file_or_module"].include_requires?(@file_name, @options.ignore_case) 1702: alias_item["file_or_module"].add_require(Require.new(@file_name, "")) 1703: end 1704: end 1705: } 1706: end
Check public_methods
use したモジュールからそのまま引き継いで public として 公開する場合のチェックを行う. subname というサブルーチン名, または関数名を持つファイルを 探査し, 存在する場合にはそのファイル内へメソッドを追加する.
# File parsers/parse_f95.rb, line 1716 1716: def check_public_methods(method, parent) 1717: return if !method || !parent 1718: @@public_methods.each{ |alias_item| 1719: parent_is_used_module = nil 1720: alias_item["used_modules"].each{ |used_module| 1721: if used_module == parent || 1722: used_module.upcase == parent.upcase && 1723: @options.ignore_case 1724: parent_is_used_module = true 1725: end 1726: } 1727: next if !parent_is_used_module 1728: 1729: if method.name == alias_item["name"] || 1730: method.name.upcase == alias_item["name"].upcase && 1731: @options.ignore_case 1732: 1733: new_meth = initialize_public_method(method, parent) 1734: if alias_item["local_name"] 1735: new_meth.name = alias_item["local_name"] 1736: end 1737: 1738: progress "e" 1739: @stats.num_methods += 1 1740: alias_item["file_or_module"].add_method new_meth 1741: end 1742: } 1743: 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 1855 1855: def comment_out?(line) 1856: return nil unless line 1857: commentout = false 1858: squote = false ; dquote = false 1859: line.split("").each { |char| 1860: if !(squote) && !(dquote) 1861: case char 1862: when "!" ; commentout = true ; break 1863: when "\""; dquote = true 1864: when "\'"; squote = true 1865: else next 1866: end 1867: elsif squote 1868: case char 1869: when "\'"; squote = false 1870: else next 1871: end 1872: elsif dquote 1873: case char 1874: when "\""; dquote = false 1875: else next 1876: end 1877: end 1878: } 1879: return commentout 1880: end
Continuous line checker
# File parsers/parse_f95.rb, line 1841 1841: def continuous_line?(line) 1842: continuous = false 1843: if /&\s*?(!.*)?$/ =~ line 1844: continuous = true 1845: if comment_out?($~.pre_match) 1846: continuous = false 1847: end 1848: end 1849: return continuous 1850: end
Parse string argument "text", and Return Array of Fortran95Definition object
# File parsers/parse_f95.rb, line 2100 2100: def definition_info(text) 2101: return nil unless text 2102: lines = "#{text}" 2103: defs = Array.new 2104: comment = "" 2105: trailing_comment = "" 2106: under_comment_valid = false 2107: lines.split("\n").each{ |line| 2108: if /^\s*?!\s?(.*)/ =~ line 2109: if COMMENTS_ARE_UPPER 2110: comment << remove_header_marker($1) 2111: comment << "\n" 2112: elsif defs[-1] && under_comment_valid 2113: defs[-1].comment << "\n" 2114: defs[-1].comment << remove_header_marker($1) 2115: end 2116: next 2117: elsif /^\s*?$/ =~ line 2118: comment = "" 2119: under_comment_valid = false 2120: next 2121: end 2122: type = "" 2123: characters = "" 2124: if line =~ /^\s*? 2125: ( 2126: character\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* 2127: | type\s*?\([\w\s]+?\)[\s\,]* 2128: | integer\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* 2129: | real\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* 2130: | double\s+precision[\s\,]* 2131: | logical\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* 2132: | complex\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* 2133: ) 2134: (.*?::)? 2135: (.+)$ 2136: /ix 2137: characters = $8 2138: type = $1 2139: type << $7.gsub(/::/, '').gsub(/^\s*?\,/, '') if $7 2140: else 2141: under_comment_valid = false 2142: next 2143: end 2144: squote = false ; dquote = false ; bracket = 0 2145: iniflag = false; commentflag = false 2146: varname = "" ; arraysuffix = "" ; inivalue = "" 2147: start_pos = defs.size 2148: characters.split("").each { |char| 2149: if !(squote) && !(dquote) && bracket <= 0 && !(iniflag) && !(commentflag) 2150: case char 2151: when "!" ; commentflag = true 2152: when "(" ; bracket += 1 ; arraysuffix = char 2153: when "\""; dquote = true 2154: when "\'"; squote = true 2155: when "=" ; iniflag = true ; inivalue << char 2156: when "," 2157: defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment) 2158: varname = "" ; arraysuffix = "" ; inivalue = "" 2159: under_comment_valid = true 2160: when " " ; next 2161: else ; varname << char 2162: end 2163: elsif commentflag 2164: comment << remove_header_marker(char) 2165: trailing_comment << remove_header_marker(char) 2166: elsif iniflag 2167: if dquote 2168: case char 2169: when "\"" ; dquote = false ; inivalue << char 2170: else ; inivalue << char 2171: end 2172: elsif squote 2173: case char 2174: when "\'" ; squote = false ; inivalue << char 2175: else ; inivalue << char 2176: end 2177: elsif bracket > 0 2178: case char 2179: when "(" ; bracket += 1 ; inivalue << char 2180: when ")" ; bracket -= 1 ; inivalue << char 2181: else ; inivalue << char 2182: end 2183: else 2184: case char 2185: when "," 2186: defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment) 2187: varname = "" ; arraysuffix = "" ; inivalue = "" 2188: iniflag = false 2189: under_comment_valid = true 2190: when "(" ; bracket += 1 ; inivalue << char 2191: when "\""; dquote = true ; inivalue << char 2192: when "\'"; squote = true ; inivalue << char 2193: when "!" ; commentflag = true 2194: else ; inivalue << char 2195: end 2196: end 2197: elsif !(squote) && !(dquote) && bracket > 0 2198: case char 2199: when "(" ; bracket += 1 ; arraysuffix << char 2200: when ")" ; bracket -= 1 ; arraysuffix << char 2201: else ; arraysuffix << char 2202: end 2203: elsif squote 2204: case char 2205: when "\'"; squote = false ; inivalue << char 2206: else ; inivalue << char 2207: end 2208: elsif dquote 2209: case char 2210: when "\""; dquote = false ; inivalue << char 2211: else ; inivalue << char 2212: end 2213: end 2214: } 2215: defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment) 2216: if trailing_comment =~ /^:nodoc:/ 2217: defs[start_pos..-1].collect!{ |defitem| 2218: defitem.nodoc = true 2219: } 2220: end 2221: varname = "" ; arraysuffix = "" ; inivalue = "" 2222: comment = "" 2223: under_comment_valid = true 2224: trailing_comment = "" 2225: } 2226: return defs 2227: 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 1504 1504: def find_comments text 1505: return "" unless text 1506: lines = text.split("\n") 1507: lines.reverse! if COMMENTS_ARE_UPPER 1508: comment_block = Array.new 1509: lines.each do |line| 1510: break if line =~ /^\s*?\w/ || line =~ /^\s*?$/ 1511: if COMMENTS_ARE_UPPER 1512: comment_block.unshift line.sub(/^\s*?!\s?/,"") 1513: else 1514: comment_block.push line.sub(/^\s*?!\s?/,"") 1515: end 1516: end 1517: nice_lines = comment_block.join("\n").split "\n\s*?\n" 1518: nice_lines[0] ||= "" 1519: nice_lines.shift 1520: 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: nml_vars_list = $2.split(",") 1446: nml_comment = COMMENTS_ARE_UPPER ? 1447: find_comments(pre_match.sub(/\n$/, '')) : 1448: find_comments(post_match.sub(/^\n/, '')) 1449: if lines.split("\n")[0] =~ /^\//i 1450: lines = "namelist " + lines 1451: end 1452: 1453: nml_meth = AnyMethod.new("NAMELIST", nml_group_name) 1454: nml_meth.singleton = false 1455: nml_meth.params = "( " + nml_vars_list.join(", ") + " )" 1456: nml_meth.comment = "<b><em> NAMELIST </em></b> :: <tt></tt>\n" 1457: nml_meth.comment << find_arguments(nml_vars_list, "#{text}" + "\n" + before_contains) 1458: nml_meth.comment << "\n" + nml_comment if nml_comment 1459: if container.parent.parent 1460: parent_object = container.parent.name 1461: else 1462: parent_object = container.parent.file_relative_name 1463: end 1464: nml_meth.comment << "\n\nThis namelist group name is input/output in " 1465: nml_meth.comment << parent_object + "#" + container.name 1466: 1467: progress "n" 1468: @stats.num_methods += 1 1469: namelist_module.add_method nml_meth 1470: 1471: nml_group_name_lists << NAMELIST_REPOSITORY_NAME + "#" + nml_group_name 1472: end 1473: 1474: if !nml_group_name_lists.empty? 1475: comments_in_procedures = "\n\nThis procedure input/output " 1476: comments_in_procedures << nml_group_name_lists.join(", ") + " . " 1477: else 1478: comments_in_procedures = "" 1479: end 1480: 1481: comments_in_procedures 1482: end
Return toplevel class of container
# File parsers/parse_f95.rb, line 1491 1491: def find_toplevel(container) 1492: top_level = container 1493: while top_level.parent 1494: top_level = top_level.parent 1495: end 1496: top_level 1497: end
Find visibility
# File parsers/parse_f95.rb, line 1667 1667: def find_visibility(container, subname, visibility_info) 1668: return nil if !subname || !visibility_info 1669: visibility_info.each{ |info| 1670: if info["name"] == subname || 1671: @options.ignore_case && info["name"].upcase == subname.upcase 1672: if info["parent"] == container.name 1673: return info["visibility"] 1674: end 1675: end 1676: } 1677: return nil 1678: end
Create method for external alias
If argument "internal" is true, file is ignored.
# File parsers/parse_f95.rb, line 1549 1549: def initialize_external_method(new, old, params, file, comment, token=nil, 1550: internal=nil, nolink=nil) 1551: return nil unless new || old 1552: 1553: if internal 1554: external_alias_header = "#{INTERNAL_ALIAS_MES} " 1555: external_alias_text = external_alias_header + old 1556: elsif file 1557: external_alias_header = "#{EXTERNAL_ALIAS_MES} " 1558: external_alias_text = external_alias_header + file + "#" + old 1559: else 1560: return nil 1561: end 1562: external_meth = AnyMethod.new(external_alias_text, new) 1563: external_meth.singleton = false 1564: external_meth.params = params 1565: external_comment = remove_trailing_alias(comment) + "\n\n" if comment 1566: external_meth.comment = external_comment || "" 1567: if nolink && token 1568: external_meth.start_collecting_tokens 1569: external_meth.add_token Token.new(1,1).set_text(token) 1570: else 1571: external_meth.comment << external_alias_text 1572: end 1573: 1574: return external_meth 1575: end
Create method for internal alias
# File parsers/parse_f95.rb, line 1532 1532: def initialize_public_method(method, parent) 1533: return if !method || !parent 1534: 1535: new_meth = AnyMethod.new("External Alias for module", method.name) 1536: new_meth.singleton = method.singleton 1537: new_meth.params = method.params.clone 1538: new_meth.comment = remove_trailing_alias(method.comment.clone) 1539: new_meth.comment << "\n\n#{EXTERNAL_ALIAS_MES} #{parent.strip.chomp}\##{method.name}" 1540: 1541: return new_meth 1542: 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 1582 1582: def parse_visibility(code, default, container) 1583: result = [] 1584: visibility_default = default || :public 1585: 1586: used_modules = [] 1587: container.includes.each{|i| used_modules << i.name} if container 1588: 1589: remaining_code = code.gsub(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "") 1590: remaining_code.split("\n").each{ |line| 1591: if /^\s*?private\s*?$/ =~ line 1592: visibility_default = :private 1593: break 1594: end 1595: } if remaining_code 1596: 1597: remaining_code.split("\n").each{ |line| 1598: if /^\s*?private\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line 1599: methods = $2.sub(/!.*$/, '') 1600: methods.split(",").each{ |meth| 1601: meth.sub!(/!.*$/, '') 1602: meth.gsub!(/:/, '') 1603: result << { 1604: "name" => meth.chomp.strip, 1605: "visibility" => :private, 1606: "used_modules" => used_modules.clone, 1607: "file_or_module" => container, 1608: "entity_is_discovered" => nil, 1609: "local_name" => nil 1610: } 1611: } 1612: elsif /^\s*?public\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line 1613: methods = $2.sub(/!.*$/, '') 1614: methods.split(",").each{ |meth| 1615: meth.sub!(/!.*$/, '') 1616: meth.gsub!(/:/, '') 1617: result << { 1618: "name" => meth.chomp.strip, 1619: "visibility" => :public, 1620: "used_modules" => used_modules.clone, 1621: "file_or_module" => container, 1622: "entity_is_discovered" => nil, 1623: "local_name" => nil 1624: } 1625: } 1626: end 1627: } if remaining_code 1628: 1629: if container 1630: result.each{ |vis_info| 1631: vis_info["parent"] = container.name 1632: } 1633: end 1634: 1635: return visibility_default, result 1636: end
# File parsers/parse_f95.rb, line 1522 1522: def progress(char) 1523: unless @options.quiet 1524: @progress.print(char) 1525: @progress.flush 1526: end 1527: end
Empty lines in header are removed
# File parsers/parse_f95.rb, line 2003 2003: def remove_empty_head_lines(text) 2004: return "" unless text 2005: lines = text.split("\n") 2006: header = true 2007: lines.delete_if{ |line| 2008: header = false if /\S/ =~ line 2009: header && /^\s*?$/ =~ line 2010: } 2011: lines.join("\n") 2012: end
header marker "=", "==", … are removed
# File parsers/parse_f95.rb, line 2016 2016: def remove_header_marker(text) 2017: return text.gsub(/^\s?(=+)/, '<tt></tt>\1') 2018: end
# File parsers/parse_f95.rb, line 2020 2020: def remove_private_comments(body) 2021: body.gsub!(/^(\s*)!--\s*?$.*?^\s*!\+\+\s*?$/m, '\\1!') 2022: return body 2023: end
Remove "Alias for" in end of comments
# File parsers/parse_f95.rb, line 1982 1982: def remove_trailing_alias(text) 1983: return "" if !text 1984: lines = text.split("\n").reverse 1985: comment_block = Array.new 1986: checked = false 1987: lines.each do |line| 1988: if !checked 1989: if /^\s?#{INTERNAL_ALIAS_MES}/ =~ line || 1990: /^\s?#{EXTERNAL_ALIAS_MES}/ =~ line 1991: checked = true 1992: next 1993: end 1994: end 1995: comment_block.unshift line 1996: end 1997: nice_lines = comment_block.join("\n") 1998: nice_lines ||= "" 1999: return nice_lines 2000: 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> :\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 1885 1885: def semicolon_to_linefeed(text) 1886: return "" unless text 1887: lines = text.split("\n") 1888: lines.collect!{ |line| 1889: indent_space = "" 1890: if line =~ /^(\s+)/ 1891: indent_space = $1 1892: end 1893: words = line.split("") 1894: commentout = false 1895: squote = false ; dquote = false 1896: words.collect! { |char| 1897: if !(squote) && !(dquote) && !(commentout) 1898: case char 1899: when "!" ; commentout = true ; next char 1900: when "\""; dquote = true ; next char 1901: when "\'"; squote = true ; next char 1902: when ";" ; "\n"+indent_space 1903: else next char 1904: end 1905: elsif commentout 1906: next char 1907: elsif squote 1908: case char 1909: when "\'"; squote = false ; next char 1910: else next char 1911: end 1912: elsif dquote 1913: case char 1914: when "\""; dquote = false ; next char 1915: else next char 1916: end 1917: end 1918: } 1919: words.join("") 1920: } 1921: return lines.join("\n") 1922: end
Set visibility
"subname" element of "visibility_info" is deleted.
# File parsers/parse_f95.rb, line 1643 1643: def set_visibility(container, subname, visibility_default, visibility_info) 1644: return unless container || subname || visibility_default || visibility_info 1645: not_found = true 1646: visibility_info.collect!{ |info| 1647: if info["name"] == subname || 1648: @options.ignore_case && info["name"].upcase == subname.upcase 1649: if info["file_or_module"].name == container.name 1650: container.set_visibility_for([subname], info["visibility"]) 1651: info["entity_is_discovered"] = true 1652: not_found = false 1653: end 1654: end 1655: info 1656: } 1657: if not_found 1658: return container.set_visibility_for([subname], visibility_default) 1659: else 1660: return container 1661: end 1662: 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 1762 1762: def united_to_one_line(f90src, delete_space=true) 1763: return "" unless f90src 1764: lines = f90src.split("\n") 1765: previous_continuing = false 1766: now_continuing = false 1767: body = "" 1768: lines.each{ |line| 1769: words = line.split("") 1770: next if words.empty? && previous_continuing 1771: commentout = false 1772: brank_flag = true ; brank_char = "" 1773: squote = false ; dquote = false 1774: ignore = false 1775: words.collect! { |char| 1776: if previous_continuing && brank_flag 1777: now_continuing = true 1778: ignore = true 1779: case char 1780: when "!" ; break 1781: when " " ; brank_char << char ; next "" 1782: when "&" 1783: brank_flag = false 1784: now_continuing = false 1785: next "" 1786: else 1787: brank_flag = false 1788: now_continuing = false 1789: ignore = false 1790: next brank_char + char 1791: end 1792: end 1793: ignore = false 1794: 1795: if now_continuing 1796: next "" 1797: elsif !(squote) && !(dquote) && !(commentout) 1798: case char 1799: when "!" ; commentout = true ; next char 1800: when "\""; dquote = true ; next char 1801: when "\'"; squote = true ; next char 1802: when "&" ; now_continuing = true ; next "" 1803: else next char 1804: end 1805: elsif commentout 1806: next char 1807: elsif squote 1808: case char 1809: when "\'"; squote = false ; next char 1810: else next char 1811: end 1812: elsif dquote 1813: case char 1814: when "\""; dquote = false ; next char 1815: else next char 1816: end 1817: end 1818: } 1819: if !ignore && !previous_continuing || !brank_flag 1820: if previous_continuing 1821: if delete_space 1822: joined_words = words.join("") 1823: body = body.rstrip + " " + joined_words.lstrip 1824: else 1825: body << words.join("") 1826: end 1827: else 1828: body << "\n" + words.join("") 1829: end 1830: end 1831: previous_continuing = now_continuing ? true : nil 1832: now_continuing = nil 1833: } 1834: return body 1835: end