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