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 696 696: def initialize(top_level, file_name, body, options, stats) 697: @body = body 698: @stats = stats 699: @file_name = file_name 700: @options = options 701: @top_level = top_level 702: @progress = $stderr unless options.quiet 703: 704: begin 705: @options_ignore_case = options.ignore_case 706: rescue 707: @options_ignore_case = true 708: end 709: 710: end
Return lines before "contains" statement in modules. "interface", "type" statements are removed.
# File parsers/parse_f95.rb, line 1611 1611: def before_contains(code) 1612: level_depth = 0 1613: before_contains_lines = [] 1614: before_contains_code = nil 1615: before_contains_flag = nil 1616: code.split("\n").each{ |line| 1617: if !before_contains_flag 1618: if line =~ /^\s*?module\s+\w+\s*?(!.*?)?$/i 1619: before_contains_flag = true 1620: end 1621: else 1622: break if line =~ /^\s*?contains\s*?(!.*?)?$/i 1623: level_depth += 1 if block_start?(line) 1624: level_depth -= 1 if block_end?(line) 1625: break if level_depth < 0 1626: before_contains_lines << line 1627: end 1628: 1629: } 1630: before_contains_code = before_contains_lines.join("\n") 1631: if before_contains_code 1632: before_contains_code.gsub!(/^\s*?interface\s+.*?\s+end\s+interface.*?$/im, "") 1633: before_contains_code.gsub!(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "") 1634: end 1635: 1636: before_contains_code 1637: end
Which "line" is end of block (module, program, block data, subroutine, function) statement ?
# File parsers/parse_f95.rb, line 2278 2278: def block_end?(line) 2279: return nil if !line 2280: 2281: if line =~ /^\s*?end\s*?(!.*?)?$/i || 2282: line =~ /^\s*?end\s+module(\s+\w+)?\s*?(!.*?)?$/i || 2283: line =~ /^\s*?end\s+program(\s+\w+)?\s*?(!.*?)?$/i || 2284: line =~ /^\s*?end\s+block\s+data(\s+\w+)?\s*?(!.*?)?$/i || 2285: line =~ /^\s*?end\s+subroutine(\s+\w+)?\s*?(!.*?)?$/i || 2286: line =~ /^\s*?end\s+function(\s+\w+)?\s*?(!.*?)?$/i 2287: return true 2288: end 2289: 2290: return nil 2291: end
Which "line" is start of block (module, program, block data, subroutine, function) statement ?
# File parsers/parse_f95.rb, line 2242 2242: def block_start?(line) 2243: return nil if !line 2244: 2245: if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i || 2246: line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i || 2247: line =~ /^\s*?block\s+data(\s+\w+)?\s*?(!.*?)?$/i || 2248: line =~ \ 2249: /^\s*? 2250: (recursive|pure|elemental)?\s*? 2251: subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$ 2252: /ix || 2253: line =~ \ 2254: /^\s*? 2255: (recursive|pure|elemental)?\s*? 2256: ( 2257: character\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 2258: | type\s*?\([\w\s]+?\)\s+ 2259: | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 2260: | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 2261: | double\s+precision\s+ 2262: | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 2263: | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 2264: )? 2265: function\s+(\w+)\s*? 2266: (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$ 2267: /ix 2268: return true 2269: end 2270: 2271: return nil 2272: end
Check external aliases
subname というサブルーチン名, または関数名を持つファイルを 探査し, 存在する場合にはそのファイル内へメソッドを追加する.
# File parsers/parse_f95.rb, line 1998 1998: def check_external_aliases(subname, params, comment, test=nil) 1999: @@external_aliases.each{ |alias_item| 2000: if subname == alias_item["old_name"] || 2001: subname.upcase == alias_item["old_name"].upcase && 2002: @options_ignore_case 2003: 2004: new_meth = initialize_external_method(alias_item["new_name"], 2005: subname, params, @file_name, 2006: comment) 2007: new_meth.visibility = alias_item["visibility"] 2008: 2009: progress "e" 2010: @stats.num_methods += 1 2011: alias_item["file_or_module"].add_method(new_meth) 2012: 2013: if !alias_item["file_or_module"].include_requires?(@file_name, @options_ignore_case) 2014: alias_item["file_or_module"].add_require(Require.new(@file_name, "")) 2015: end 2016: end 2017: } 2018: end
Check public_methods
use したモジュールからそのまま引き継いで public として 公開する場合のチェックを行う. subname というサブルーチン名, または関数名を持つファイルを 探査し, 存在する場合にはそのファイル内へメソッドを追加する.
# File parsers/parse_f95.rb, line 2028 2028: def check_public_methods(method, parent) 2029: return if !method || !parent 2030: @@public_methods.each{ |alias_item| 2031: parent_is_used_module = nil 2032: alias_item["used_modules"].each{ |used_module| 2033: if used_module == parent || 2034: used_module.upcase == parent.upcase && 2035: @options_ignore_case 2036: parent_is_used_module = true 2037: end 2038: } 2039: next if !parent_is_used_module 2040: 2041: if method.name == alias_item["name"] || 2042: method.name.upcase == alias_item["name"].upcase && 2043: @options_ignore_case 2044: 2045: new_meth = initialize_public_method(method, parent) 2046: if alias_item["local_name"] 2047: new_meth.name = alias_item["local_name"] 2048: end 2049: 2050: progress "e" 2051: @stats.num_methods += 1 2052: alias_item["file_or_module"].add_method new_meth 2053: end 2054: } 2055: end
Collect comment for file entity
# File parsers/parse_f95.rb, line 1642 1642: def collect_first_comment(body) 1643: comment = "" 1644: not_comment = "" 1645: comment_start = false 1646: comment_end = false 1647: body.split("\n").each{ |line| 1648: if comment_end 1649: not_comment << line 1650: not_comment << "\n" 1651: elsif /^\s*?!\s?(.*)$/i =~ line 1652: comment_start = true 1653: comment << $1 1654: comment << "\n" 1655: elsif /^\s*?$/i =~ line 1656: comment_end = true if comment_start && COMMENTS_ARE_UPPER 1657: else 1658: comment_end = true 1659: not_comment << line 1660: not_comment << "\n" 1661: end 1662: } 1663: return comment, not_comment 1664: end
Comment out checker
# File parsers/parse_f95.rb, line 2169 2169: def comment_out?(line) 2170: return nil unless line 2171: commentout = false 2172: squote = false ; dquote = false 2173: line.split("").each { |char| 2174: if !(squote) && !(dquote) 2175: case char 2176: when "!" ; commentout = true ; break 2177: when "\""; dquote = true 2178: when "\'"; squote = true 2179: else next 2180: end 2181: elsif squote 2182: case char 2183: when "\'"; squote = false 2184: else next 2185: end 2186: elsif dquote 2187: case char 2188: when "\""; dquote = false 2189: else next 2190: end 2191: end 2192: } 2193: return commentout 2194: end
Continuous line checker
# File parsers/parse_f95.rb, line 2155 2155: def continuous_line?(line) 2156: continuous = false 2157: if /&\s*?(!.*)?$/ =~ line 2158: continuous = true 2159: if comment_out?($~.pre_match) 2160: continuous = false 2161: end 2162: end 2163: return continuous 2164: end
Parse string argument "text", and Return Array of Fortran95Definition object
# File parsers/parse_f95.rb, line 2414 2414: def definition_info(text) 2415: return nil unless text 2416: lines = "#{text}" 2417: defs = Array.new 2418: comment = "" 2419: trailing_comment = "" 2420: under_comment_valid = false 2421: lines.split("\n").each{ |line| 2422: if /^\s*?!\s?(.*)/ =~ line 2423: if COMMENTS_ARE_UPPER 2424: comment << remove_header_marker($1) 2425: comment << "\n" 2426: elsif defs[-1] && under_comment_valid 2427: defs[-1].comment << "\n" 2428: defs[-1].comment << remove_header_marker($1) 2429: end 2430: next 2431: elsif /^\s*?$/ =~ line 2432: comment = "" 2433: under_comment_valid = false 2434: next 2435: end 2436: type = "" 2437: characters = "" 2438: if line =~ /^\s*? 2439: ( 2440: character\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* 2441: | type\s*?\([\w\s]+?\)[\s\,]* 2442: | integer\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* 2443: | real\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* 2444: | double\s+precision[\s\,]* 2445: | logical\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* 2446: | complex\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* 2447: ) 2448: (.*?::)? 2449: (.+)$ 2450: /ix 2451: characters = $8 2452: type = $1 2453: type << $7.gsub(/::/, '').gsub(/^\s*?\,/, '') if $7 2454: else 2455: under_comment_valid = false 2456: next 2457: end 2458: squote = false ; dquote = false ; bracket = 0 2459: iniflag = false; commentflag = false 2460: varname = "" ; arraysuffix = "" ; inivalue = "" 2461: start_pos = defs.size 2462: characters.split("").each { |char| 2463: if !(squote) && !(dquote) && bracket <= 0 && !(iniflag) && !(commentflag) 2464: case char 2465: when "!" ; commentflag = true 2466: when "(" ; bracket += 1 ; arraysuffix = char 2467: when "\""; dquote = true 2468: when "\'"; squote = true 2469: when "=" ; iniflag = true ; inivalue << char 2470: when "," 2471: defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment) 2472: varname = "" ; arraysuffix = "" ; inivalue = "" 2473: under_comment_valid = true 2474: when " " ; next 2475: else ; varname << char 2476: end 2477: elsif commentflag 2478: comment << remove_header_marker(char) 2479: trailing_comment << remove_header_marker(char) 2480: elsif iniflag 2481: if dquote 2482: case char 2483: when "\"" ; dquote = false ; inivalue << char 2484: else ; inivalue << char 2485: end 2486: elsif squote 2487: case char 2488: when "\'" ; squote = false ; inivalue << char 2489: else ; inivalue << char 2490: end 2491: elsif bracket > 0 2492: case char 2493: when "(" ; bracket += 1 ; inivalue << char 2494: when ")" ; bracket -= 1 ; inivalue << char 2495: else ; inivalue << char 2496: end 2497: else 2498: case char 2499: when "," 2500: defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment) 2501: varname = "" ; arraysuffix = "" ; inivalue = "" 2502: iniflag = false 2503: under_comment_valid = true 2504: when "(" ; bracket += 1 ; inivalue << char 2505: when "\""; dquote = true ; inivalue << char 2506: when "\'"; squote = true ; inivalue << char 2507: when "!" ; commentflag = true 2508: else ; inivalue << char 2509: end 2510: end 2511: elsif !(squote) && !(dquote) && bracket > 0 2512: case char 2513: when "(" ; bracket += 1 ; arraysuffix << char 2514: when ")" ; bracket -= 1 ; arraysuffix << char 2515: else ; arraysuffix << char 2516: end 2517: elsif squote 2518: case char 2519: when "\'"; squote = false ; inivalue << char 2520: else ; inivalue << char 2521: end 2522: elsif dquote 2523: case char 2524: when "\""; dquote = false ; inivalue << char 2525: else ; inivalue << char 2526: end 2527: end 2528: } 2529: defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment) 2530: if trailing_comment =~ /^:nodoc:/ 2531: defs[start_pos..-1].collect!{ |defitem| 2532: defitem.nodoc = true 2533: } 2534: end 2535: varname = "" ; arraysuffix = "" ; inivalue = "" 2536: comment = "" 2537: under_comment_valid = true 2538: trailing_comment = "" 2539: } 2540: return defs 2541: 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 1673 1673: def find_arguments(args, text, all=nil, indent=nil, modified_params=nil) 1674: return unless args || all 1675: indent = "" unless indent 1676: args = ["all"] if all 1677: params = "" if modified_params 1678: comma = "" 1679: return unless text 1680: args_rdocforms = "\n" 1681: remaining_lines = "#{text}" 1682: definitions = definition_info(remaining_lines) 1683: args.each{ |arg| 1684: arg.strip! 1685: arg.chomp! 1686: definitions.each { |defitem| 1687: if arg == defitem.varname.strip.chomp || all 1688: 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" 1689: if !defitem.comment.chomp.strip.empty? 1690: comment = "" 1691: defitem.comment.split("\n").each{ |line| 1692: comment << " " + line + "\n" 1693: } 1694: args_rdocforms << "\n\#{indent} <tt></tt> ::\n\#{indent} <tt></tt>\n\#{indent} \#{comment.chomp.strip}\n" 1695: end 1696: 1697: if modified_params 1698: if defitem.include_attr?("optional") 1699: params << "#{comma}[#{arg}]" 1700: else 1701: params << "#{comma}#{arg}" 1702: end 1703: comma = ", " 1704: end 1705: end 1706: } 1707: } 1708: if modified_params 1709: return args_rdocforms, params 1710: else 1711: return args_rdocforms 1712: end 1713: 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 1816 1816: def find_comments text 1817: return "" unless text 1818: lines = text.split("\n") 1819: lines.reverse! if COMMENTS_ARE_UPPER 1820: comment_block = Array.new 1821: lines.each do |line| 1822: break if line =~ /^\s*?\w/ || line =~ /^\s*?$/ 1823: if COMMENTS_ARE_UPPER 1824: comment_block.unshift line.sub(/^\s*?!\s?/,"") 1825: else 1826: comment_block.push line.sub(/^\s*?!\s?/,"") 1827: end 1828: end 1829: nice_lines = comment_block.join("\n").split "\n\s*?\n" 1830: nice_lines[0] ||= "" 1831: nice_lines.shift 1832: 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 1731 1731: def find_namelists(container, text, before_contains=nil) 1732: return nil if !text 1733: top_level = find_toplevel(container) 1734: 1735: if text =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)(!.*?)?$/i 1736: if top_level.include_includes?(NAMELIST_REPOSITORY_NAME) 1737: namelist_module = 1738: top_level.find_module_named(NAMELIST_REPOSITORY_NAME) 1739: else 1740: namelist_module = 1741: top_level.add_module NormalClass, NAMELIST_REPOSITORY_NAME 1742: namelist_module.record_location top_level 1743: namelist_module.comment = "This is not a module but a repository of NAMELIST group names declared\nin all Fortran 90/95 files\n" 1744: end 1745: else 1746: return "" 1747: end 1748: 1749: nml_group_name_lists = [] 1750: lines = "#{text}" 1751: before_contains = "" if !before_contains 1752: while lines =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)(!.*?)?$/i 1753: lines = $~.post_match 1754: pre_match = $~.pre_match ; post_match = $~.post_match 1755: nml_group_name = $1 1756: trailing_comment = $3 || "" 1757: nml_vars_list = $2.split(",") 1758: nml_comment = COMMENTS_ARE_UPPER ? 1759: find_comments(pre_match.sub(/\n$/, '')) : 1760: find_comments(trailing_comment + post_match) 1761: if lines.split("\n")[0] =~ /^\//i 1762: lines = "namelist " + lines 1763: end 1764: 1765: nml_meth = AnyMethod.new("NAMELIST", nml_group_name) 1766: nml_meth.singleton = false 1767: nml_meth.params = "( " + nml_vars_list.join(", ") + " )" 1768: nml_meth.comment = "<b><em> NAMELIST </em></b> :: <tt></tt>\n" 1769: nml_meth.comment << find_arguments(nml_vars_list, "#{text}" + "\n" + before_contains) 1770: nml_meth.comment << "\n" + nml_comment if nml_comment 1771: if container.parent.parent 1772: parent_object = container.parent.name 1773: else 1774: parent_object = container.parent.file_relative_name 1775: end 1776: nml_meth.comment << "\n\nThis namelist group name is input/output in " 1777: nml_meth.comment << parent_object + "#" + container.name 1778: 1779: progress "n" 1780: @stats.num_methods += 1 1781: namelist_module.add_method nml_meth 1782: 1783: nml_group_name_lists << NAMELIST_REPOSITORY_NAME + "#" + nml_group_name 1784: end 1785: 1786: if !nml_group_name_lists.empty? 1787: comments_in_procedures = "\n\nThis procedure input/output " 1788: comments_in_procedures << nml_group_name_lists.join(", ") + " . " 1789: else 1790: comments_in_procedures = "" 1791: end 1792: 1793: comments_in_procedures 1794: end
Return toplevel class of container
# File parsers/parse_f95.rb, line 1803 1803: def find_toplevel(container) 1804: top_level = container 1805: while top_level.parent 1806: top_level = top_level.parent 1807: end 1808: top_level 1809: end
Find visibility
# File parsers/parse_f95.rb, line 1979 1979: def find_visibility(container, subname, visibility_info) 1980: return nil if !subname || !visibility_info 1981: visibility_info.each{ |info| 1982: if info["name"] == subname || 1983: @options_ignore_case && info["name"].upcase == subname.upcase 1984: if info["parent"] == container.name 1985: return info["visibility"] 1986: end 1987: end 1988: } 1989: return nil 1990: end
Create method for external alias
If argument "internal" is true, file is ignored.
# File parsers/parse_f95.rb, line 1861 1861: def initialize_external_method(new, old, params, file, comment, token=nil, 1862: internal=nil, nolink=nil) 1863: return nil unless new || old 1864: 1865: if internal 1866: external_alias_header = "#{INTERNAL_ALIAS_MES} " 1867: external_alias_text = external_alias_header + old 1868: elsif file 1869: external_alias_header = "#{EXTERNAL_ALIAS_MES} " 1870: external_alias_text = external_alias_header + file + "#" + old 1871: else 1872: return nil 1873: end 1874: external_meth = AnyMethod.new(external_alias_text, new) 1875: external_meth.singleton = false 1876: external_meth.params = params 1877: external_comment = remove_trailing_alias(comment) + "\n\n" if comment 1878: external_meth.comment = external_comment || "" 1879: if nolink && token 1880: external_meth.start_collecting_tokens 1881: external_meth.add_token Token.new(1,1).set_text(token) 1882: else 1883: external_meth.comment << external_alias_text 1884: end 1885: 1886: return external_meth 1887: end
Create method for internal alias
# File parsers/parse_f95.rb, line 1844 1844: def initialize_public_method(method, parent) 1845: return if !method || !parent 1846: 1847: new_meth = AnyMethod.new("External Alias for module", method.name) 1848: new_meth.singleton = method.singleton 1849: new_meth.params = method.params.clone 1850: new_meth.comment = remove_trailing_alias(method.comment.clone) 1851: new_meth.comment << "\n\n#{EXTERNAL_ALIAS_MES} #{parent.strip.chomp}\##{method.name}" 1852: 1853: return new_meth 1854: end
# File parsers/parse_f95.rb, line 937 937: def parse_program_or_module(container, code, 938: visibility=:public, external=nil) 939: return unless container 940: return unless code 941: remaining_lines = code.split("\n") 942: remaining_code = "#{code}" 943: 944: # 945: # Parse variables before "contains" in module 946: # 947: # namelist 変数の定義に使われたり, これ自体が定数, 変数 948: # 提供されるのに利用される. (変数や定数として利用される場合, 949: # これもメソッドとして提供する. 950: # 951: before_contains_code = before_contains(remaining_code) 952: 953: # 954: # Parse global "use" 955: # 956: use_check_code = "#{before_contains_code}" 957: cascaded_modules_list = [] 958: while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i 959: use_check_code = $~.pre_match 960: use_check_code << $~.post_match 961: used_mod_name = $1.strip.chomp 962: used_list = $2 || "" 963: used_trailing = $3 || "" 964: next if used_trailing =~ /!:nodoc:/ 965: if !container.include_includes?(used_mod_name, @options_ignore_case) 966: progress "." 967: container.add_include Include.new(used_mod_name, "") 968: end 969: if ! (used_list =~ /\,\s*?only\s*?:/i ) 970: cascaded_modules_list << "\#" + used_mod_name 971: end 972: end 973: 974: # 975: # Parse public and private, and store information. 976: # This information is used when "add_method" and 977: # "set_visibility_for" are called. 978: # 979: visibility_default, visibility_info = 980: parse_visibility(remaining_lines.join("\n"), visibility, container) 981: @@public_methods.concat visibility_info 982: if visibility_default == :public 983: if !cascaded_modules_list.empty? 984: cascaded_modules = 985: Attr.new("Cascaded Modules", 986: "Imported modules all of whose components are published again", 987: "", 988: cascaded_modules_list.join(", ")) 989: container.add_attribute(cascaded_modules) 990: end 991: end 992: 993: # 994: # Check rename elements 995: # 996: use_check_code = "#{before_contains_code}" 997: while use_check_code =~ /^\s*?use\s+(\w+)\s*?\,(.+)$/i 998: use_check_code = $~.pre_match 999: use_check_code << $~.post_match 1000: used_mod_name = $1.strip.chomp 1001: used_elements = $2.sub(/\s*?only\s*?:\s*?/i, '') 1002: used_elements.split(",").each{ |used| 1003: if /\s*?(\w+)\s*?=>\s*?(\w+)\s*?/ =~ used 1004: local = $1 1005: org = $2 1006: @@public_methods.collect!{ |pub_meth| 1007: if local == pub_meth["name"] || 1008: local.upcase == pub_meth["name"].upcase && 1009: @options_ignore_case 1010: pub_meth["name"] = org 1011: pub_meth["local_name"] = local 1012: end 1013: pub_meth 1014: } 1015: end 1016: } 1017: end 1018: 1019: # 1020: # Parse private "use" 1021: # 1022: use_check_code = remaining_lines.join("\n") 1023: while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i 1024: use_check_code = $~.pre_match 1025: use_check_code << $~.post_match 1026: used_mod_name = $1.strip.chomp 1027: used_trailing = $3 || "" 1028: next if used_trailing =~ /!:nodoc:/ 1029: if !container.include_includes?(used_mod_name, @options_ignore_case) 1030: progress "." 1031: container.add_include Include.new(used_mod_name, "") 1032: end 1033: end 1034: 1035: container.each_includes{ |inc| 1036: TopLevel.all_files.each do |name, toplevel| 1037: indicated_mod = toplevel.find_symbol(inc.name, 1038: nil, @options_ignore_case) 1039: if indicated_mod 1040: indicated_name = indicated_mod.parent.file_relative_name 1041: if !container.include_requires?(indicated_name, @options_ignore_case) 1042: container.add_require(Require.new(indicated_name, "")) 1043: end 1044: break 1045: end 1046: end 1047: } 1048: 1049: # 1050: # Parse derived types definitions 1051: # 1052: derived_types_comment = "" 1053: remaining_code = remaining_lines.join("\n") 1054: while remaining_code =~ /^\s*? 1055: type[\s\,]+(public|private)?\s*?(::)?\s*? 1056: (\w+)\s*?(!.*?)?$ 1057: (.*?) 1058: ^\s*?end\s+type.*?$ 1059: /imx 1060: remaining_code = $~.pre_match 1061: remaining_code << $~.post_match 1062: typename = $3.chomp.strip 1063: type_elements = $5 || "" 1064: type_code = remove_empty_head_lines($&) 1065: type_trailing = find_comments($4) 1066: next if type_trailing =~ /^:nodoc:/ 1067: type_visibility = $1 1068: type_comment = COMMENTS_ARE_UPPER ? 1069: find_comments($~.pre_match) + "\n" + type_trailing : 1070: type_trailing + "\n" + find_comments(type_code.sub(/^.*$\n/i, '')) 1071: type_element_visibility_public = true 1072: type_code.split("\n").each{ |line| 1073: if /^\s*?private\s*?$/ =~ line 1074: type_element_visibility_public = nil 1075: break 1076: end 1077: } if type_code 1078: 1079: args_comment = "" 1080: type_args_info = nil 1081: 1082: if @options.show_all 1083: args_comment = find_arguments(nil, type_code, true) 1084: else 1085: type_public_args_list = [] 1086: type_args_info = definition_info(type_code) 1087: type_args_info.each{ |arg| 1088: arg_is_public = type_element_visibility_public 1089: arg_is_public = true if arg.include_attr?("public") 1090: arg_is_public = nil if arg.include_attr?("private") 1091: type_public_args_list << arg.varname if arg_is_public 1092: } 1093: args_comment = find_arguments(type_public_args_list, type_code) 1094: end 1095: 1096: type = AnyMethod.new("type #{typename}", typename) 1097: type.singleton = false 1098: type.params = "" 1099: type.comment = "<b><em> Derived Type </em></b> :: <tt></tt>\n" 1100: type.comment << args_comment if args_comment 1101: type.comment << type_comment if type_comment 1102: progress "t" 1103: @stats.num_methods += 1 1104: container.add_method type 1105: 1106: set_visibility(container, typename, visibility_default, @@public_methods) 1107: 1108: if type_visibility 1109: type_visibility.gsub!(/\s/,'') 1110: type_visibility.gsub!(/\,/,'') 1111: type_visibility.gsub!(/:/,'') 1112: type_visibility.downcase! 1113: if type_visibility == "public" 1114: container.set_visibility_for([typename], :public) 1115: elsif type_visibility == "private" 1116: container.set_visibility_for([typename], :private) 1117: end 1118: end 1119: 1120: check_public_methods(type, container.name) 1121: 1122: if @options.show_all 1123: derived_types_comment << ", " unless derived_types_comment.empty? 1124: derived_types_comment << typename 1125: else 1126: if type.visibility == :public 1127: derived_types_comment << ", " unless derived_types_comment.empty? 1128: derived_types_comment << typename 1129: end 1130: end 1131: 1132: end 1133: 1134: if !derived_types_comment.empty? 1135: derived_types_table = 1136: Attr.new("Derived Types", "Derived_Types", "", 1137: derived_types_comment) 1138: container.add_attribute(derived_types_table) 1139: end 1140: 1141: # 1142: # move interface scope 1143: # 1144: interface_code = "" 1145: while remaining_code =~ /^\s*? 1146: interface( 1147: \s+\w+ | 1148: \s+operator\s*?\(.*?\) | 1149: \s+assignment\s*?\(\s*?=\s*?\) 1150: )?\s*?$ 1151: (.*?) 1152: ^\s*?end\s+interface.*?$ 1153: /imx 1154: interface_code << remove_empty_head_lines($&) + "\n" 1155: remaining_code = $~.pre_match 1156: remaining_code << $~.post_match 1157: end 1158: 1159: # 1160: # Parse global constants or variables in modules 1161: # 1162: const_var_defs = definition_info(before_contains_code) 1163: const_var_defs.each{|defitem| 1164: next if defitem.nodoc 1165: const_or_var_type = "Variable" 1166: const_or_var_progress = "v" 1167: if defitem.include_attr?("parameter") 1168: const_or_var_type = "Constant" 1169: const_or_var_progress = "c" 1170: end 1171: const_or_var = AnyMethod.new(const_or_var_type, defitem.varname) 1172: const_or_var.singleton = false 1173: const_or_var.params = "" 1174: self_comment = find_arguments([defitem.varname], before_contains_code) 1175: const_or_var.comment = "<b><em>" + const_or_var_type + "</em></b> :: <tt></tt>\n" 1176: const_or_var.comment << self_comment if self_comment 1177: progress const_or_var_progress 1178: @stats.num_methods += 1 1179: container.add_method const_or_var 1180: 1181: set_visibility(container, defitem.varname, visibility_default, @@public_methods) 1182: 1183: if defitem.include_attr?("public") 1184: container.set_visibility_for([defitem.varname], :public) 1185: elsif defitem.include_attr?("private") 1186: container.set_visibility_for([defitem.varname], :private) 1187: end 1188: 1189: check_public_methods(const_or_var, container.name) 1190: 1191: } if const_var_defs 1192: 1193: remaining_lines = remaining_code.split("\n") 1194: 1195: # "subroutine" or "function" parts are parsed (new) 1196: # 1197: level_depth = 0 1198: block_searching_flag = nil 1199: block_searching_lines = [] 1200: pre_comment = [] 1201: procedure_trailing = "" 1202: procedure_name = "" 1203: procedure_params = "" 1204: procedure_prefix = "" 1205: procedure_result_arg = "" 1206: procedure_type = "" 1207: contains_lines = [] 1208: contains_flag = nil 1209: remaining_lines.collect!{|line| 1210: if !block_searching_flag 1211: # subroutine 1212: if line =~ /^\s*? 1213: (recursive|pure|elemental)?\s*? 1214: subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$ 1215: /ix 1216: block_searching_flag = :subroutine 1217: block_searching_lines << line 1218: 1219: procedure_name = $2.chomp.strip 1220: procedure_params = $3 || "" 1221: procedure_prefix = $1 || "" 1222: procedure_trailing = $4 || "!" 1223: next false 1224: 1225: # function 1226: elsif line =~ /^\s*? 1227: (recursive|pure|elemental)?\s*? 1228: ( 1229: character\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1230: | type\s*?\([\w\s]+?\)\s+ 1231: | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1232: | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1233: | double\s+precision\s+ 1234: | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1235: | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1236: )? 1237: function\s+(\w+)\s*? 1238: (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$ 1239: /ix 1240: block_searching_flag = :function 1241: block_searching_lines << line 1242: 1243: procedure_prefix = $1 || "" 1244: procedure_type = $2 ? $2.chomp.strip : nil 1245: procedure_name = $8.chomp.strip 1246: procedure_params = $9 || "" 1247: procedure_result_arg = $11 ? $11.chomp.strip : procedure_name 1248: procedure_trailing = $12 || "!" 1249: next false 1250: elsif line =~ /^\s*?!\s?(.*)/ 1251: pre_comment << line 1252: next line 1253: else 1254: pre_comment = [] 1255: next line 1256: end 1257: end 1258: contains_flag = true if line =~ /^\s*?contains\s*?(!.*?)?$/ 1259: block_searching_lines << line 1260: contains_lines << line if contains_flag 1261: 1262: level_depth += 1 if block_start?(line) 1263: level_depth -= 1 if block_end?(line) 1264: if level_depth >= 0 1265: next false 1266: end 1267: 1268: # "procedure_code" is formatted. 1269: # ":nodoc:" flag is checked. 1270: # 1271: procedure_code = block_searching_lines.join("\n") 1272: procedure_code = remove_empty_head_lines(procedure_code) 1273: if procedure_trailing =~ /^!:nodoc:/ 1274: # next loop to search next block 1275: level_depth = 0 1276: block_searching_flag = nil 1277: block_searching_lines = [] 1278: pre_comment = [] 1279: procedure_trailing = "" 1280: procedure_name = "" 1281: procedure_params = "" 1282: procedure_prefix = "" 1283: procedure_result_arg = "" 1284: procedure_type = "" 1285: contains_lines = [] 1286: contains_flag = nil 1287: next false 1288: end 1289: 1290: # AnyMethod is created, and added to container 1291: # 1292: subroutine_function = nil 1293: if block_searching_flag == :subroutine 1294: subroutine_prefix = procedure_prefix 1295: subroutine_name = procedure_name 1296: subroutine_params = procedure_params 1297: subroutine_trailing = procedure_trailing 1298: subroutine_code = procedure_code 1299: 1300: subroutine_comment = COMMENTS_ARE_UPPER ? 1301: pre_comment.join("\n") + "\n" + subroutine_trailing : 1302: subroutine_trailing + "\n" + subroutine_code.sub(/^.*$\n/i, '') 1303: subroutine = AnyMethod.new("subroutine", subroutine_name) 1304: parse_subprogram(subroutine, subroutine_params, 1305: subroutine_comment, subroutine_code, 1306: before_contains_code, nil, subroutine_prefix) 1307: progress "s" 1308: @stats.num_methods += 1 1309: container.add_method subroutine 1310: subroutine_function = subroutine 1311: 1312: namelist_comment = 1313: find_namelists(subroutine, subroutine_code, before_contains_code) 1314: subroutine.comment << namelist_comment if namelist_comment 1315: 1316: elsif block_searching_flag == :function 1317: function_prefix = procedure_prefix 1318: function_type = procedure_type 1319: function_name = procedure_name 1320: function_params_org = procedure_params 1321: function_result_arg = procedure_result_arg 1322: function_trailing = procedure_trailing 1323: function_code_org = procedure_code 1324: 1325: function_comment = COMMENTS_ARE_UPPER ? 1326: pre_comment.join("\n") + "\n" + function_trailing : 1327: function_trailing + "\n " + function_code_org.sub(/^.*$\n/i, '') 1328: 1329: function_code = "#{function_code_org}" 1330: if function_type 1331: function_code << "\n" + function_type + " :: " + function_result_arg 1332: end 1333: 1334: function_params = 1335: function_params_org.sub(/^\(/, "\(#{function_result_arg}, ") 1336: 1337: function = AnyMethod.new("function", function_name) 1338: parse_subprogram(function, function_params, 1339: function_comment, function_code, 1340: before_contains_code, true, function_prefix) 1341: 1342: # Specific modification due to function 1343: function.params.sub!(/\(\s*?#{function_result_arg}\s*?,\s*?/, "\( ") 1344: function.params << " result(" + function_result_arg + ")" 1345: function.start_collecting_tokens 1346: function.add_token Token.new(1,1).set_text(function_code_org) 1347: 1348: progress "f" 1349: @stats.num_methods += 1 1350: container.add_method function 1351: subroutine_function = function 1352: 1353: namelist_comment = 1354: find_namelists(function, function_code, before_contains_code) 1355: function.comment << namelist_comment if namelist_comment 1356: 1357: end 1358: 1359: # The visibility of procedure is specified 1360: # 1361: set_visibility(container, procedure_name, 1362: visibility_default, @@public_methods) 1363: 1364: # The alias for this procedure from external modules 1365: # 1366: check_external_aliases(procedure_name, 1367: subroutine_function.params, 1368: subroutine_function.comment, subroutine_function) if external 1369: check_public_methods(subroutine_function, container.name) 1370: 1371: 1372: # contains_lines are parsed as private procedures 1373: if contains_flag 1374: parse_program_or_module(container, 1375: contains_lines.join("\n"), :private) 1376: end 1377: 1378: # next loop to search next block 1379: level_depth = 0 1380: block_searching_flag = nil 1381: block_searching_lines = [] 1382: pre_comment = [] 1383: procedure_trailing = "" 1384: procedure_name = "" 1385: procedure_params = "" 1386: procedure_prefix = "" 1387: procedure_result_arg = "" 1388: contains_lines = [] 1389: contains_flag = nil 1390: next false 1391: } # End of remaining_lines.collect!{|line| 1392: 1393: # Array remains_lines is converted to String remains_code again 1394: # 1395: remaining_code = remaining_lines.join("\n") 1396: 1397: # 1398: # Parse interface 1399: # 1400: interface_scope = false 1401: generic_name = "" 1402: interface_code.split("\n").each{ |line| 1403: if /^\s*? 1404: interface( 1405: \s+\w+| 1406: \s+operator\s*?\(.*?\)| 1407: \s+assignment\s*?\(\s*?=\s*?\) 1408: )? 1409: \s*?(!.*?)?$ 1410: /ix =~ line 1411: generic_name = $1 ? $1.strip.chomp : nil 1412: interface_trailing = $2 || "!" 1413: interface_scope = true 1414: interface_scope = false if interface_trailing =~ /!:nodoc:/ 1415: # if generic_name =~ /operator\s*?\((.*?)\)/i 1416: # operator_name = $1 1417: # if operator_name && !operator_name.empty? 1418: # generic_name = "#{operator_name}" 1419: # end 1420: # end 1421: # if generic_name =~ /assignment\s*?\((.*?)\)/i 1422: # assignment_name = $1 1423: # if assignment_name && !assignment_name.empty? 1424: # generic_name = "#{assignment_name}" 1425: # end 1426: # end 1427: end 1428: if /^\s*?end\s+interface/i =~ line 1429: interface_scope = false 1430: generic_name = nil 1431: end 1432: # internal alias 1433: if interface_scope && /^\s*?module\s+procedure\s+(.*?)(!.*?)?$/i =~ line 1434: procedures = $1.strip.chomp 1435: procedures_trailing = $2 || "!" 1436: next if procedures_trailing =~ /!:nodoc:/ 1437: procedures.split(",").each{ |proc| 1438: proc.strip! 1439: proc.chomp! 1440: next if generic_name == proc || !generic_name 1441: old_meth = container.find_symbol(proc, nil, @options_ignore_case) 1442: next if !old_meth 1443: nolink = old_meth.visibility == :private ? true : nil 1444: nolink = nil if @options.show_all 1445: new_meth = 1446: initialize_external_method(generic_name, proc, 1447: old_meth.params, nil, 1448: old_meth.comment, 1449: old_meth.clone.token_stream[0].text, 1450: true, nolink) 1451: new_meth.singleton = old_meth.singleton 1452: 1453: progress "i" 1454: @stats.num_methods += 1 1455: container.add_method new_meth 1456: 1457: set_visibility(container, generic_name, visibility_default, @@public_methods) 1458: 1459: check_public_methods(new_meth, container.name) 1460: 1461: } 1462: end 1463: 1464: # external aliases 1465: if interface_scope 1466: # subroutine 1467: proc = nil 1468: params = nil 1469: procedures_trailing = nil 1470: if line =~ /^\s*? 1471: (recursive|pure|elemental)?\s*? 1472: subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$ 1473: /ix 1474: proc = $2.chomp.strip 1475: proc_name = generic_name || proc 1476: params = $3 || "" 1477: procedures_trailing = $4 || "!" 1478: 1479: # function 1480: elsif line =~ /^\s*? 1481: (recursive|pure|elemental)?\s*? 1482: ( 1483: character\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1484: | type\s*?\([\w\s]+?\)\s+ 1485: | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1486: | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1487: | double\s+precision\s+ 1488: | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1489: | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1490: )? 1491: function\s+(\w+)\s*? 1492: (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$ 1493: /ix 1494: proc = $8.chomp.strip 1495: proc_name = generic_name || proc 1496: params = $9 || "" 1497: procedures_trailing = $12 || "!" 1498: else 1499: next 1500: end 1501: next if procedures_trailing =~ /!:nodoc:/ 1502: indicated_method = nil 1503: indicated_file = nil 1504: TopLevel.all_files.each do |name, toplevel| 1505: indicated_method = toplevel.find_local_symbol(proc, @options_ignore_case) 1506: indicated_file = name 1507: break if indicated_method 1508: end 1509: 1510: if indicated_method 1511: external_method = 1512: initialize_external_method(proc_name, proc, 1513: indicated_method.params, 1514: indicated_file, 1515: indicated_method.comment) 1516: 1517: progress "e" 1518: @stats.num_methods += 1 1519: container.add_method external_method 1520: set_visibility(container, proc_name, visibility_default, @@public_methods) 1521: if !container.include_requires?(indicated_file, @options_ignore_case) 1522: container.add_require(Require.new(indicated_file, "")) 1523: end 1524: check_public_methods(external_method, container.name) 1525: 1526: else 1527: @@external_aliases << { 1528: "new_name" => proc_name, 1529: "old_name" => proc, 1530: "file_or_module" => container, 1531: "visibility" => find_visibility(container, proc_name, @@public_methods) || visibility_default 1532: } 1533: end 1534: end 1535: 1536: } if interface_code # End of interface_code.split("\n").each ... 1537: 1538: # 1539: # Already imported methods are removed from @@public_methods. 1540: # Remainders are assumed to be imported from other modules. 1541: # 1542: # 既に参照済みのメソッドは @@public_methods から取り除く. 1543: # 残りは外部モジュールからの参照と仮定する. 1544: # 1545: @@public_methods.delete_if{ |method| method["entity_is_discovered"]} 1546: 1547: @@public_methods.each{ |pub_meth| 1548: next unless pub_meth["file_or_module"].name == container.name 1549: pub_meth["used_modules"].each{ |used_mod| 1550: TopLevel.all_classes_and_modules.each{ |modules| 1551: if modules.name == used_mod || 1552: modules.name.upcase == used_mod.upcase && 1553: @options_ignore_case 1554: modules.method_list.each{ |meth| 1555: if meth.name == pub_meth["name"] || 1556: meth.name.upcase == pub_meth["name"].upcase && 1557: @options_ignore_case 1558: new_meth = initialize_public_method(meth, 1559: modules.name) 1560: if pub_meth["local_name"] 1561: new_meth.name = pub_meth["local_name"] 1562: end 1563: progress "e" 1564: @stats.num_methods += 1 1565: container.add_method new_meth 1566: end 1567: } 1568: end 1569: } 1570: } 1571: } 1572: 1573: container 1574: end
Parse arguments, comment, code of subroutine and function. Return AnyMethod object.
# File parsers/parse_f95.rb, line 1580 1580: def parse_subprogram(subprogram, params, comment, code, 1581: before_contains=nil, function=nil, prefix=nil) 1582: subprogram.singleton = false 1583: prefix = "" if !prefix 1584: arguments = params.sub(/\(/, "").sub(/\)/, "").split(",") if params 1585: args_comment, params_opt = 1586: find_arguments(arguments, code.sub(/^s*?contains\s*?(!.*?)?$.*/im, ""), 1587: nil, nil, true) 1588: params_opt = "( " + params_opt + " ) " if params_opt 1589: subprogram.params = params_opt || "" 1590: 1591: block_comment = find_comments comment 1592: if function 1593: subprogram.comment = "<b><em> Function </em></b> :: <em>#{prefix}</em>\n" 1594: else 1595: subprogram.comment = "<b><em> Subroutine </em></b> :: <em>#{prefix}</em>\n" 1596: end 1597: subprogram.comment << args_comment if args_comment 1598: subprogram.comment << block_comment if block_comment 1599: 1600: # For output source code 1601: subprogram.start_collecting_tokens 1602: subprogram.add_token Token.new(1,1).set_text(code) 1603: 1604: subprogram 1605: end
Parse visibility
# File parsers/parse_f95.rb, line 1894 1894: def parse_visibility(code, default, container) 1895: result = [] 1896: visibility_default = default || :public 1897: 1898: used_modules = [] 1899: container.includes.each{|i| used_modules << i.name} if container 1900: 1901: remaining_code = code.gsub(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "") 1902: remaining_code.split("\n").each{ |line| 1903: if /^\s*?private\s*?$/ =~ line 1904: visibility_default = :private 1905: break 1906: end 1907: } if remaining_code 1908: 1909: remaining_code.split("\n").each{ |line| 1910: if /^\s*?private\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line 1911: methods = $2.sub(/!.*$/, '') 1912: methods.split(",").each{ |meth| 1913: meth.sub!(/!.*$/, '') 1914: meth.gsub!(/:/, '') 1915: result << { 1916: "name" => meth.chomp.strip, 1917: "visibility" => :private, 1918: "used_modules" => used_modules.clone, 1919: "file_or_module" => container, 1920: "entity_is_discovered" => nil, 1921: "local_name" => nil 1922: } 1923: } 1924: elsif /^\s*?public\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line 1925: methods = $2.sub(/!.*$/, '') 1926: methods.split(",").each{ |meth| 1927: meth.sub!(/!.*$/, '') 1928: meth.gsub!(/:/, '') 1929: result << { 1930: "name" => meth.chomp.strip, 1931: "visibility" => :public, 1932: "used_modules" => used_modules.clone, 1933: "file_or_module" => container, 1934: "entity_is_discovered" => nil, 1935: "local_name" => nil 1936: } 1937: } 1938: end 1939: } if remaining_code 1940: 1941: if container 1942: result.each{ |vis_info| 1943: vis_info["parent"] = container.name 1944: } 1945: end 1946: 1947: return visibility_default, result 1948: end
# File parsers/parse_f95.rb, line 1834 1834: def progress(char) 1835: unless @options.quiet 1836: @progress.print(char) 1837: @progress.flush 1838: end 1839: end
Empty lines in header are removed
# File parsers/parse_f95.rb, line 2317 2317: def remove_empty_head_lines(text) 2318: return "" unless text 2319: lines = text.split("\n") 2320: header = true 2321: lines.delete_if{ |line| 2322: header = false if /\S/ =~ line 2323: header && /^\s*?$/ =~ line 2324: } 2325: lines.join("\n") 2326: end
header marker "=", "==", … are removed
# File parsers/parse_f95.rb, line 2330 2330: def remove_header_marker(text) 2331: return text.gsub(/^\s?(=+)/, '<tt></tt>\1') 2332: end
# File parsers/parse_f95.rb, line 2334 2334: def remove_private_comments(body) 2335: body.gsub!(/^(\s*)!--\s*?$.*?^\s*!\+\+\s*?$/m, '\\1!') 2336: return body 2337: end
Remove "Alias for" in end of comments
# File parsers/parse_f95.rb, line 2296 2296: def remove_trailing_alias(text) 2297: return "" if !text 2298: lines = text.split("\n").reverse 2299: comment_block = Array.new 2300: checked = false 2301: lines.each do |line| 2302: if !checked 2303: if /^\s?#{INTERNAL_ALIAS_MES}/ =~ line || 2304: /^\s?#{EXTERNAL_ALIAS_MES}/ =~ line 2305: checked = true 2306: next 2307: end 2308: end 2309: comment_block.unshift line 2310: end 2311: nice_lines = comment_block.join("\n") 2312: nice_lines ||= "" 2313: return nice_lines 2314: end
devine code constructs
# File parsers/parse_f95.rb, line 713 713: def scan 714: 715: # remove private comment 716: remaining_code = remove_private_comments(@body) 717: 718: # continuation lines are united to one line 719: remaining_code = united_to_one_line(remaining_code) 720: 721: # semicolons are replaced to line feed 722: remaining_code = semicolon_to_linefeed(remaining_code) 723: 724: # collect comment for file entity 725: whole_comment, remaining_code = collect_first_comment(remaining_code) 726: @top_level.comment = whole_comment 727: 728: # String "remaining_code" is converted to Array "remaining_lines" 729: remaining_lines = remaining_code.split("\n") 730: 731: # "module" or "program" parts are parsed (new) 732: # 733: level_depth = 0 734: block_searching_flag = nil 735: block_searching_lines = [] 736: pre_comment = [] 737: module_program_trailing = "" 738: module_program_name = "" 739: other_block_level_depth = 0 740: other_block_searching_flag = nil 741: remaining_lines.collect!{|line| 742: if !block_searching_flag && !other_block_searching_flag 743: if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i 744: block_searching_flag = :module 745: block_searching_lines << line 746: module_program_name = $1 747: module_program_trailing = find_comments($2) 748: next false 749: elsif line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i || 750: line =~ /^\s*?\w/ && !block_start?(line) 751: block_searching_flag = :program 752: block_searching_lines << line 753: module_program_name = $1 || "" 754: module_program_trailing = find_comments($2) 755: next false 756: 757: elsif block_start?(line) 758: other_block_searching_flag = true 759: next line 760: 761: elsif line =~ /^\s*?!\s?(.*)/ 762: pre_comment << line 763: next line 764: else 765: pre_comment = [] 766: next line 767: end 768: elsif other_block_searching_flag 769: other_block_level_depth += 1 if block_start?(line) 770: other_block_level_depth -= 1 if block_end?(line) 771: if other_block_level_depth < 0 772: other_block_level_depth = 0 773: other_block_searching_flag = nil 774: end 775: next line 776: end 777: 778: block_searching_lines << line 779: level_depth += 1 if block_start?(line) 780: level_depth -= 1 if block_end?(line) 781: if level_depth >= 0 782: next false 783: end 784: 785: # "module_program_code" is formatted. 786: # ":nodoc:" flag is checked. 787: # 788: module_program_code = block_searching_lines.join("\n") 789: module_program_code = remove_empty_head_lines(module_program_code) 790: if module_program_trailing =~ /^:nodoc:/ 791: # next loop to search next block 792: level_depth = 0 793: block_searching_flag = false 794: block_searching_lines = [] 795: pre_comment = [] 796: next false 797: end 798: 799: # NormalClass is created, and added to @top_level 800: # 801: if block_searching_flag == :module 802: module_name = module_program_name 803: module_code = module_program_code 804: module_trailing = module_program_trailing 805: progress "m" 806: @stats.num_modules += 1 807: f9x_module = @top_level.add_module NormalClass, module_name 808: f9x_module.record_location @top_level 809: 810: # 811: # Add provided modules information to @top_level comment 812: # 813: provided_modules = [] 814: provided_mes_line_num = nil 815: top_level_comment_lines = [] 816: line_num = 0 817: @top_level.comment.split("\n").each{|line| 818: top_level_comment_lines << line 819: line_num += 1 820: next if line.empty? 821: if !provided_mes_line_num && /^\s?#{PROVIDED_MODULES_MES}/ =~ line 822: provided_mes_line_num = line_num 823: next 824: end 825: if provided_mes_line_num 826: if /^\s?\*\s+<b>(\w+)<\/b>/ =~ line 827: provided_modules << $1 828: else 829: provided_mes_line_num = nil 830: end 831: end 832: } 833: line_num = 0 834: if provided_mes_line_num 835: top_level_comment_lines.collect!{ |line| 836: line_num += 1 837: if line_num < provided_mes_line_num 838: line 839: else 840: nil 841: end 842: } 843: top_level_comment_lines.delete_if{|line| !line } 844: end 845: top_level_comment_lines << "\n" + PROVIDED_MODULES_MES + "." 846: if provided_mes_line_num 847: top_level_comment_lines[-1].sub!(/\.$/, '') 848: top_level_comment_lines[-1] << "s." 849: end 850: provided_modules.each{ |mod| 851: top_level_comment_lines << "* <b>" + mod + "</b>" 852: } 853: top_level_comment_lines << "* <b>" + module_name + "</b>" 854: @top_level.comment = top_level_comment_lines.join("\n") 855: 856: # 857: # Information about the module is parsed 858: # 859: f9x_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) + 860: "\n" + module_trailing : module_trailing + "\n" + 861: find_comments(module_code.sub(/^.*$\n/i, '')) 862: f9x_module.comment = f9x_comment 863: parse_program_or_module(f9x_module, module_code) 864: 865: TopLevel.all_files.each do |name, toplevel| 866: if toplevel.include_includes?(module_name, @options_ignore_case) 867: if !toplevel.include_requires?(@file_name, @options_ignore_case) 868: toplevel.add_require(Require.new(@file_name, "")) 869: end 870: end 871: toplevel.each_classmodule{|m| 872: if m.include_includes?(module_name, @options_ignore_case) 873: if !m.include_requires?(@file_name, @options_ignore_case) 874: m.add_require(Require.new(@file_name, "")) 875: end 876: end 877: } 878: end 879: 880: namelist_comment = 881: find_namelists(f9x_module, before_contains(module_code)) 882: f9x_module.comment << namelist_comment if namelist_comment 883: 884: elsif block_searching_flag == :program 885: program_name = module_program_name 886: program_name = "main_program" if program_name.empty? 887: program_code = module_program_code 888: program_trailing = module_program_trailing 889: program_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) + 890: "\n" + program_trailing : program_trailing + "\n" + 891: find_comments(program_code.sub(/^.*$\n/i, '')) 892: 893: progress "p" 894: @stats.num_methods += 1 895: f9x_mainprogram = AnyMethod.new("main_program", program_name) 896: f9x_mainprogram.singleton = false 897: f9x_mainprogram.comment = "<b><em> Main Program </em></b> :: <tt></tt>\n" 898: f9x_mainprogram.comment << program_comment 899: f9x_mainprogram.params = "" 900: 901: # For output source code 902: f9x_mainprogram.start_collecting_tokens 903: f9x_mainprogram.add_token Token.new(1,1).set_text(program_code) 904: 905: @top_level.add_method f9x_mainprogram 906: parse_program_or_module(@top_level, program_code, :private) 907: 908: namelist_comment = find_namelists(f9x_mainprogram, program_code) 909: f9x_mainprogram.comment << namelist_comment if namelist_comment 910: end 911: 912: # next loop to search next block 913: level_depth = 0 914: block_searching_flag = false 915: block_searching_lines = [] 916: pre_comment = [] 917: next false 918: } 919: 920: remaining_lines.delete_if{ |line| 921: line == false 922: } 923: 924: # External subprograms and functions are parsed 925: # 926: # 単一のファイル内において program や module に格納されない, 927: # 外部サブルーチン, 外部関数部分の解析. 928: # 929: parse_program_or_module(@top_level, remaining_lines.join("\n"), 930: :public, true) 931: 932: @top_level 933: end
Semicolons are replaced to line feed.
# File parsers/parse_f95.rb, line 2199 2199: def semicolon_to_linefeed(text) 2200: return "" unless text 2201: lines = text.split("\n") 2202: lines.collect!{ |line| 2203: indent_space = "" 2204: if line =~ /^(\s+)/ 2205: indent_space = $1 2206: end 2207: words = line.split("") 2208: commentout = false 2209: squote = false ; dquote = false 2210: words.collect! { |char| 2211: if !(squote) && !(dquote) && !(commentout) 2212: case char 2213: when "!" ; commentout = true ; next char 2214: when "\""; dquote = true ; next char 2215: when "\'"; squote = true ; next char 2216: when ";" ; "\n"+indent_space 2217: else next char 2218: end 2219: elsif commentout 2220: next char 2221: elsif squote 2222: case char 2223: when "\'"; squote = false ; next char 2224: else next char 2225: end 2226: elsif dquote 2227: case char 2228: when "\""; dquote = false ; next char 2229: else next char 2230: end 2231: end 2232: } 2233: words.join("") 2234: } 2235: return lines.join("\n") 2236: end
Set visibility
"subname" element of "visibility_info" is deleted.
# File parsers/parse_f95.rb, line 1955 1955: def set_visibility(container, subname, visibility_default, visibility_info) 1956: return unless container || subname || visibility_default || visibility_info 1957: not_found = true 1958: visibility_info.collect!{ |info| 1959: if info["name"] == subname || 1960: @options_ignore_case && info["name"].upcase == subname.upcase 1961: if info["file_or_module"].name == container.name 1962: container.set_visibility_for([subname], info["visibility"]) 1963: info["entity_is_discovered"] = true 1964: not_found = false 1965: end 1966: end 1967: info 1968: } 1969: if not_found 1970: return container.set_visibility_for([subname], visibility_default) 1971: else 1972: return container 1973: end 1974: 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 2074 2074: def united_to_one_line(f90src, delete_space=true) 2075: return "" unless f90src 2076: lines = f90src.split("\n") 2077: previous_continuing = false 2078: now_continuing = false 2079: body = "" 2080: squote = false ; dquote = false 2081: lines.each{ |line| 2082: words = line.split("") 2083: next if words.empty? && previous_continuing 2084: commentout = false 2085: brank_flag = true ; brank_char = "" 2086: ignore = false 2087: words.collect! { |char| 2088: if previous_continuing && brank_flag 2089: now_continuing = true 2090: ignore = true 2091: case char 2092: when "!" ; break 2093: when " " ; brank_char << char ; next "" 2094: when "&" 2095: brank_flag = false 2096: now_continuing = false 2097: next "" 2098: else 2099: brank_flag = false 2100: now_continuing = false 2101: ignore = false 2102: next brank_char + char 2103: end 2104: end 2105: ignore = false 2106: 2107: if now_continuing && !(squote) && !(dquote) 2108: next "" 2109: elsif !(squote) && !(dquote) && !(commentout) 2110: case char 2111: when "!" ; commentout = true ; next char 2112: when "\""; dquote = true ; next char 2113: when "\'"; squote = true ; next char 2114: when "&" ; now_continuing = true ; next "" 2115: else next char 2116: end 2117: elsif commentout 2118: next char 2119: elsif squote 2120: case char 2121: when "\'"; squote = false ; now_continuing = false ; next char 2122: when "&" ; now_continuing = true ; next "" 2123: else next char 2124: end 2125: elsif dquote 2126: case char 2127: when "\""; dquote = false ; now_continuing = false ; next char 2128: when "&" ; now_continuing = true ; next "" 2129: else next char 2130: end 2131: end 2132: } 2133: if !ignore && !previous_continuing || !brank_flag 2134: if previous_continuing 2135: if delete_space 2136: joined_words = words.join("") 2137: body = body.rstrip + " " + joined_words.lstrip 2138: else 2139: body << words.join("") 2140: end 2141: else 2142: body << "\n" + words.join("") 2143: end 2144: end 2145: previous_continuing = now_continuing ? true : false 2146: now_continuing = false 2147: } 2148: return body 2149: end