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