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