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 | |||||
IGNORED_MARKER_REGEXP | = | /^:nodoc:/ | Ignored marker | |||||
DOC_PRIORITY_REGEXP | = | /^:doc\-priority\s+([\-\+]?\d+):\s*/ | Document priority marker |
prepare to parse a Fortran 95 file
# File parsers/parse_f95.rb, line 819 819: def initialize(top_level, file_name, body, options, stats) 820: @body = body 821: @stats = stats 822: @file_name = file_name 823: @options = options 824: @top_level = top_level 825: @progress = $stderr unless options.quiet 826: 827: begin 828: @options_ignore_case = options.ignore_case 829: rescue 830: @options_ignore_case = true 831: end 832: 833: end
Return lines before "contains" statement in modules. "interface", "type" statements are removed.
# File parsers/parse_f95.rb, line 1767 1767: def before_contains(code) 1768: level_depth = 0 1769: before_contains_lines = [] 1770: before_contains_code = nil 1771: before_contains_flag = nil 1772: code.split("\n").each{ |line| 1773: if !before_contains_flag 1774: if line =~ /^\s*?module\s+\w+\s*?(!.*?)?$/i 1775: before_contains_flag = true 1776: end 1777: else 1778: break if line =~ /^\s*?contains\s*?(!.*?)?$/i 1779: level_depth += 1 if block_start?(line) 1780: level_depth -= 1 if block_end?(line) 1781: break if level_depth < 0 1782: before_contains_lines << line 1783: end 1784: 1785: } 1786: before_contains_code = before_contains_lines.join("\n") 1787: if before_contains_code 1788: before_contains_code.gsub!(/^\s*?interface\s+.*?\s+end\s+interface.*?$/im, "") 1789: before_contains_code.gsub!(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "") 1790: end 1791: 1792: before_contains_code 1793: end
Which "line" is end of block (module, program, block data, subroutine, function) statement ?
# File parsers/parse_f95.rb, line 2435 2435: def block_end?(line) 2436: return nil if !line 2437: 2438: if line =~ /^\s*?end\s*?(!.*?)?$/i || 2439: line =~ /^\s*?end\s+module(\s+\w+)?\s*?(!.*?)?$/i || 2440: line =~ /^\s*?end\s+program(\s+\w+)?\s*?(!.*?)?$/i || 2441: line =~ /^\s*?end\s+block\s+data(\s+\w+)?\s*?(!.*?)?$/i || 2442: line =~ /^\s*?end\s+subroutine(\s+\w+)?\s*?(!.*?)?$/i || 2443: line =~ /^\s*?end\s+function(\s+\w+)?\s*?(!.*?)?$/i 2444: return true 2445: end 2446: 2447: return nil 2448: end
Which "line" is start of block (module, program, block data, subroutine, function) statement ?
# File parsers/parse_f95.rb, line 2399 2399: def block_start?(line) 2400: return nil if !line 2401: 2402: if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i || 2403: line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i || 2404: line =~ /^\s*?block\s+data(\s+\w+)?\s*?(!.*?)?$/i || 2405: line =~ \ 2406: /^\s*? 2407: (recursive|pure|elemental)?\s*? 2408: subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$ 2409: /ix || 2410: line =~ \ 2411: /^\s*? 2412: (recursive|pure|elemental)?\s*? 2413: ( 2414: character\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 2415: | type\s*?\([\w\s]+?\)\s+ 2416: | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 2417: | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 2418: | double\s+precision\s+ 2419: | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 2420: | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 2421: )? 2422: function\s+(\w+)\s*? 2423: (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$ 2424: /ix 2425: return true 2426: end 2427: 2428: return nil 2429: end
Check external aliases
subname というサブルーチン名, または関数名を持つファイルを 探査し, 存在する場合にはそのファイル内へメソッドを追加する.
# File parsers/parse_f95.rb, line 2154 2154: def check_external_aliases(subname, params, comment, test=nil) 2155: @@external_aliases.each{ |alias_item| 2156: if subname == alias_item["old_name"] || 2157: subname.upcase == alias_item["old_name"].upcase && 2158: @options_ignore_case 2159: 2160: new_meth = initialize_external_method(alias_item["new_name"], 2161: subname, params, @file_name, 2162: comment) 2163: new_meth.visibility = alias_item["visibility"] 2164: new_meth.set_priority(alias_item["doc_priority"]) if alias_item["doc_priority"] 2165: 2166: progress "e" 2167: @stats.num_methods += 1 2168: alias_item["file_or_module"].add_method(new_meth) 2169: 2170: if !alias_item["file_or_module"].include_requires?(@file_name, @options_ignore_case) 2171: alias_item["file_or_module"].add_require(Require.new(@file_name, "")) 2172: end 2173: end 2174: } 2175: end
Check public_methods
use したモジュールからそのまま引き継いで public として 公開する場合のチェックを行う. subname というサブルーチン名, または関数名を持つファイルを 探査し, 存在する場合にはそのファイル内へメソッドを追加する.
# File parsers/parse_f95.rb, line 2185 2185: def check_public_methods(method, parent) 2186: return if !method || !parent 2187: @@public_methods.each{ |alias_item| 2188: parent_is_used_module = nil 2189: alias_item["used_modules"].each{ |used_module| 2190: if used_module == parent || 2191: used_module.upcase == parent.upcase && 2192: @options_ignore_case 2193: parent_is_used_module = true 2194: end 2195: } 2196: next if !parent_is_used_module 2197: 2198: if method.name == alias_item["name"] || 2199: method.name.upcase == alias_item["name"].upcase && 2200: @options_ignore_case 2201: 2202: new_meth = initialize_public_method(method, parent) 2203: if alias_item["local_name"] 2204: new_meth.name = alias_item["local_name"] 2205: end 2206: 2207: progress "e" 2208: @stats.num_methods += 1 2209: alias_item["file_or_module"].add_method new_meth 2210: end 2211: } 2212: end
Collect comment for file entity
# File parsers/parse_f95.rb, line 1798 1798: def collect_first_comment(body) 1799: comment = "" 1800: not_comment = "" 1801: comment_start = false 1802: comment_end = false 1803: body.split("\n").each{ |line| 1804: if comment_end 1805: not_comment << line 1806: not_comment << "\n" 1807: elsif /^\s*?!\s?(.*)$/i =~ line 1808: comment_start = true 1809: comment << $1 1810: comment << "\n" 1811: elsif /^\s*?$/i =~ line 1812: comment_end = true if comment_start && COMMENTS_ARE_UPPER 1813: else 1814: comment_end = true 1815: not_comment << line 1816: not_comment << "\n" 1817: end 1818: } 1819: return comment, not_comment 1820: end
Comment out checker
# File parsers/parse_f95.rb, line 2326 2326: def comment_out?(line) 2327: return nil unless line 2328: commentout = false 2329: squote = false ; dquote = false 2330: line.split("").each { |char| 2331: if !(squote) && !(dquote) 2332: case char 2333: when "!" ; commentout = true ; break 2334: when "\""; dquote = true 2335: when "\'"; squote = true 2336: else next 2337: end 2338: elsif squote 2339: case char 2340: when "\'"; squote = false 2341: else next 2342: end 2343: elsif dquote 2344: case char 2345: when "\""; dquote = false 2346: else next 2347: end 2348: end 2349: } 2350: return commentout 2351: end
Continuous line checker
# File parsers/parse_f95.rb, line 2312 2312: def continuous_line?(line) 2313: continuous = false 2314: if /&\s*?(!.*)?$/ =~ line 2315: continuous = true 2316: if comment_out?($~.pre_match) 2317: continuous = false 2318: end 2319: end 2320: return continuous 2321: end
Parse string argument "text", and Return Array of Fortran95Definition object
# File parsers/parse_f95.rb, line 2577 2577: def definition_info(text) 2578: return nil unless text 2579: lines = "#{text}" 2580: defs = Array.new 2581: comment = "" 2582: trailing_comment = "" 2583: under_comment_valid = false 2584: lines.split("\n").each{ |line| 2585: if /^\s*?!\s?(.*)/ =~ line 2586: if COMMENTS_ARE_UPPER 2587: comment << remove_header_marker($1) 2588: comment << "\n" 2589: elsif defs[-1] && under_comment_valid 2590: defs[-1].comment << "\n" 2591: defs[-1].comment << remove_header_marker($1) 2592: end 2593: next 2594: elsif /^\s*?$/ =~ line 2595: comment = "" 2596: under_comment_valid = false 2597: next 2598: end 2599: type = "" 2600: characters = "" 2601: if line =~ /^\s*? 2602: ( 2603: character\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* 2604: | type\s*?\([\w\s]+?\)[\s\,]* 2605: | integer\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* 2606: | real\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* 2607: | double\s+precision[\s\,]* 2608: | logical\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* 2609: | complex\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* 2610: ) 2611: (.*?::)? 2612: (.+)$ 2613: /ix 2614: characters = $8 2615: type = $1 2616: type << $7.gsub(/::/, '').gsub(/^\s*?\,/, '') if $7 2617: else 2618: under_comment_valid = false 2619: next 2620: end 2621: squote = false ; dquote = false ; bracket = 0 2622: iniflag = false; commentflag = false 2623: varname = "" ; arraysuffix = "" ; inivalue = "" 2624: start_pos = defs.size 2625: characters.split("").each { |char| 2626: if !(squote) && !(dquote) && bracket <= 0 && !(iniflag) && !(commentflag) 2627: case char 2628: when "!" ; commentflag = true 2629: when "(" ; bracket += 1 ; arraysuffix = char 2630: when "\""; dquote = true 2631: when "\'"; squote = true 2632: when "=" ; iniflag = true ; inivalue << char 2633: when "," 2634: defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment) 2635: varname = "" ; arraysuffix = "" ; inivalue = "" 2636: under_comment_valid = true 2637: when " " ; next 2638: else ; varname << char 2639: end 2640: elsif commentflag 2641: comment << remove_header_marker(char) 2642: trailing_comment << remove_header_marker(char) 2643: elsif iniflag 2644: if dquote 2645: case char 2646: when "\"" ; dquote = false ; inivalue << char 2647: else ; inivalue << char 2648: end 2649: elsif squote 2650: case char 2651: when "\'" ; squote = false ; inivalue << char 2652: else ; inivalue << char 2653: end 2654: elsif bracket > 0 2655: case char 2656: when "(" ; bracket += 1 ; inivalue << char 2657: when ")" ; bracket -= 1 ; inivalue << char 2658: else ; inivalue << char 2659: end 2660: else 2661: case char 2662: when "," 2663: defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment) 2664: varname = "" ; arraysuffix = "" ; inivalue = "" 2665: iniflag = false 2666: under_comment_valid = true 2667: when "(" ; bracket += 1 ; inivalue << char 2668: when "\""; dquote = true ; inivalue << char 2669: when "\'"; squote = true ; inivalue << char 2670: when "!" ; commentflag = true 2671: else ; inivalue << char 2672: end 2673: end 2674: elsif !(squote) && !(dquote) && bracket > 0 2675: case char 2676: when "(" ; bracket += 1 ; arraysuffix << char 2677: when ")" ; bracket -= 1 ; arraysuffix << char 2678: else ; arraysuffix << char 2679: end 2680: elsif squote 2681: case char 2682: when "\'"; squote = false ; inivalue << char 2683: else ; inivalue << char 2684: end 2685: elsif dquote 2686: case char 2687: when "\""; dquote = false ; inivalue << char 2688: else ; inivalue << char 2689: end 2690: end 2691: } 2692: defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment) 2693: if trailing_comment =~ IGNORED_MARKER_REGEXP 2694: defs[start_pos..-1].collect!{ |defitem| 2695: defitem.nodoc = true 2696: } 2697: end 2698: if trailing_comment =~ DOC_PRIORITY_REGEXP 2699: doc_priority = $1.to_i 2700: defs[start_pos..-1].collect!{ |defitem| 2701: defitem.doc_priority = doc_priority 2702: defitem.comment.sub!(DOC_PRIORITY_REGEXP, '') 2703: } 2704: end 2705: varname = "" ; arraysuffix = "" ; inivalue = "" 2706: comment = "" 2707: under_comment_valid = true 2708: trailing_comment = "" 2709: } 2710: return defs 2711: end
# File parsers/parse_f95.rb, line 1747 1747: def doc_priority_from_trailing(trailing) 1748: prefix = '' 1749: if trailing =~ /^(\s*!)(.*)$/ 1750: prefix = $1 1751: trailing = $2 1752: end 1753: if trailing =~ DOC_PRIORITY_REGEXP 1754: priority = $1.to_i 1755: trailing.sub!(DOC_PRIORITY_REGEXP, '') 1756: else 1757: priority = false 1758: end 1759: trailing = prefix + trailing 1760: return priority, trailing 1761: 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 1829 1829: def find_arguments(args, text, all=nil, indent=nil, modified_params=nil) 1830: return unless args || all 1831: indent = "" unless indent 1832: args = ["all"] if all 1833: params = "" if modified_params 1834: comma = "" 1835: return unless text 1836: args_rdocforms = "\n" 1837: remaining_lines = "#{text}" 1838: definitions = definition_info(remaining_lines) 1839: args.each{ |arg| 1840: arg.strip! 1841: arg.chomp! 1842: definitions.each { |defitem| 1843: if arg == defitem.varname.strip.chomp || all 1844: 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" 1845: if !defitem.comment.chomp.strip.empty? 1846: comment = "" 1847: defitem.comment.split("\n").each{ |line| 1848: comment << " " + line + "\n" 1849: } 1850: args_rdocforms << "\n\#{indent} <tt></tt> ::\n\#{indent} <tt></tt>\n\#{indent} \#{comment.chomp.strip}\n" 1851: end 1852: 1853: if modified_params 1854: if defitem.include_attr?("optional") 1855: params << "#{comma}[#{arg}]" 1856: else 1857: params << "#{comma}#{arg}" 1858: end 1859: comma = ", " 1860: end 1861: end 1862: } 1863: } 1864: if modified_params 1865: return args_rdocforms, params 1866: else 1867: return args_rdocforms 1868: end 1869: 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 1972 1972: def find_comments text 1973: return "" unless text 1974: lines = text.split("\n") 1975: lines.reverse! if COMMENTS_ARE_UPPER 1976: comment_block = Array.new 1977: lines.each do |line| 1978: break if line =~ /^\s*?\w/ || line =~ /^\s*?$/ 1979: if COMMENTS_ARE_UPPER 1980: comment_block.unshift line.sub(/^\s*?!\s?/,"") 1981: else 1982: comment_block.push line.sub(/^\s*?!\s?/,"") 1983: end 1984: end 1985: nice_lines = comment_block.join("\n").split "\n\s*?\n" 1986: nice_lines[0] ||= "" 1987: nice_lines.shift 1988: 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 1887 1887: def find_namelists(container, text, before_contains=nil) 1888: return nil if !text 1889: top_level = find_toplevel(container) 1890: 1891: if text =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)(!.*?)?$/i 1892: if top_level.include_includes?(NAMELIST_REPOSITORY_NAME) 1893: namelist_module = 1894: top_level.find_module_named(NAMELIST_REPOSITORY_NAME) 1895: else 1896: namelist_module = 1897: top_level.add_module NormalClass, NAMELIST_REPOSITORY_NAME 1898: namelist_module.record_location top_level 1899: namelist_module.comment = "This is not a module but a repository of NAMELIST group names declared\nin all Fortran 90/95 files\n" 1900: end 1901: else 1902: return "" 1903: end 1904: 1905: nml_group_name_lists = [] 1906: lines = "#{text}" 1907: before_contains = "" if !before_contains 1908: while lines =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)(!.*?)?$/i 1909: lines = $~.post_match 1910: pre_match = $~.pre_match ; post_match = $~.post_match 1911: nml_group_name = $1 1912: trailing_comment = $3 || "" 1913: nml_vars_list = $2.split(",") 1914: nml_comment = COMMENTS_ARE_UPPER ? 1915: find_comments(pre_match.sub(/\n$/, '')) : 1916: find_comments(trailing_comment + post_match) 1917: if lines.split("\n")[0] =~ /^\//i 1918: lines = "namelist " + lines 1919: end 1920: 1921: nml_meth = AnyMethod.new("NAMELIST", nml_group_name) 1922: nml_meth.singleton = false 1923: nml_meth.params = "( " + nml_vars_list.join(", ") + " )" 1924: nml_meth.comment = "<b><em> NAMELIST </em></b> :: <tt></tt>\n" 1925: nml_meth.comment << find_arguments(nml_vars_list, "#{text}" + "\n" + before_contains) 1926: nml_meth.comment << "\n" + nml_comment if nml_comment 1927: if container.parent.parent 1928: parent_object = container.parent.name 1929: else 1930: parent_object = container.parent.file_relative_name 1931: end 1932: nml_meth.comment << "\n\nThis namelist group name is input/output in " 1933: nml_meth.comment << parent_object + "#" + container.name 1934: 1935: progress "n" 1936: @stats.num_methods += 1 1937: namelist_module.add_method nml_meth 1938: 1939: nml_group_name_lists << NAMELIST_REPOSITORY_NAME + "#" + nml_group_name 1940: end 1941: 1942: if !nml_group_name_lists.empty? 1943: comments_in_procedures = "\n\nThis procedure input/output " 1944: comments_in_procedures << nml_group_name_lists.join(", ") + " . " 1945: else 1946: comments_in_procedures = "" 1947: end 1948: 1949: comments_in_procedures 1950: end
Return toplevel class of container
# File parsers/parse_f95.rb, line 1959 1959: def find_toplevel(container) 1960: top_level = container 1961: while top_level.parent 1962: top_level = top_level.parent 1963: end 1964: top_level 1965: end
Find visibility
# File parsers/parse_f95.rb, line 2135 2135: def find_visibility(container, subname, visibility_info) 2136: return nil if !subname || !visibility_info 2137: visibility_info.each{ |info| 2138: if info["name"] == subname || 2139: @options_ignore_case && info["name"].upcase == subname.upcase 2140: if info["parent"] == container.name 2141: return info["visibility"] 2142: end 2143: end 2144: } 2145: return nil 2146: end
Create method for external alias
If argument "internal" is true, file is ignored.
# File parsers/parse_f95.rb, line 2017 2017: def initialize_external_method(new, old, params, file, comment, token=nil, 2018: internal=nil, nolink=nil) 2019: return nil unless new || old 2020: 2021: if internal 2022: external_alias_header = "#{INTERNAL_ALIAS_MES} " 2023: external_alias_text = external_alias_header + old 2024: elsif file 2025: external_alias_header = "#{EXTERNAL_ALIAS_MES} " 2026: external_alias_text = external_alias_header + file + "#" + old 2027: else 2028: return nil 2029: end 2030: external_meth = AnyMethod.new(external_alias_text, new) 2031: external_meth.singleton = false 2032: external_meth.params = params 2033: external_comment = remove_trailing_alias(comment) + "\n\n" if comment 2034: external_meth.comment = external_comment || "" 2035: if nolink && token 2036: external_meth.start_collecting_tokens 2037: external_meth.add_token Token.new(1,1).set_text(token) 2038: else 2039: external_meth.comment << external_alias_text 2040: end 2041: 2042: return external_meth 2043: end
Create method for internal alias
# File parsers/parse_f95.rb, line 2000 2000: def initialize_public_method(method, parent) 2001: return if !method || !parent 2002: 2003: new_meth = AnyMethod.new("External Alias for module", method.name) 2004: new_meth.singleton = method.singleton 2005: new_meth.params = method.params.clone 2006: new_meth.comment = remove_trailing_alias(method.comment.clone) 2007: new_meth.comment << "\n\n#{EXTERNAL_ALIAS_MES} #{parent.strip.chomp}\##{method.name}" 2008: 2009: return new_meth 2010: end
# File parsers/parse_f95.rb, line 1063 1063: def parse_program_or_module(container, code, 1064: visibility=:public, external=nil) 1065: return unless container 1066: return unless code 1067: remaining_lines = code.split("\n") 1068: remaining_code = "#{code}" 1069: 1070: # 1071: # Parse variables before "contains" in module 1072: # 1073: # namelist 変数の定義に使われたり, これ自体が定数, 変数 1074: # 提供されるのに利用される. (変数や定数として利用される場合, 1075: # これもメソッドとして提供する. 1076: # 1077: before_contains_code = before_contains(remaining_code) 1078: 1079: # 1080: # Parse global "use" 1081: # 1082: use_check_code = "#{before_contains_code}" 1083: cascaded_modules_list = [] 1084: while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i 1085: use_check_code = $~.pre_match 1086: use_check_code << $~.post_match 1087: used_mod_name = $1.strip.chomp 1088: used_list = $2 || "" 1089: used_trailing = $3 || "" 1090: next if used_trailing.sub(/^!/, '') =~ IGNORED_MARKER_REGEXP 1091: if !container.include_includes?(used_mod_name, @options_ignore_case) 1092: progress "." 1093: container.add_include Include.new(used_mod_name, "") 1094: end 1095: if ! (used_list =~ /\,\s*?only\s*?:/i ) 1096: cascaded_modules_list << "\#" + used_mod_name 1097: end 1098: end 1099: 1100: # 1101: # Parse public and private, and store information. 1102: # This information is used when "add_method" and 1103: # "set_visibility_for" are called. 1104: # 1105: visibility_default, visibility_info = 1106: parse_visibility(remaining_lines.join("\n"), visibility, container) 1107: @@public_methods.concat visibility_info 1108: if visibility_default == :public 1109: if !cascaded_modules_list.empty? 1110: cascaded_modules = 1111: Attr.new("Cascaded Modules", 1112: "Imported modules all of whose components are published again", 1113: "", 1114: cascaded_modules_list.join(", ")) 1115: container.add_attribute(cascaded_modules) 1116: end 1117: end 1118: 1119: # 1120: # Check rename elements 1121: # 1122: use_check_code = "#{before_contains_code}" 1123: while use_check_code =~ /^\s*?use\s+(\w+)\s*?\,(.+)$/i 1124: use_check_code = $~.pre_match 1125: use_check_code << $~.post_match 1126: used_mod_name = $1.strip.chomp 1127: used_elements = $2.sub(/\s*?only\s*?:\s*?/i, '') 1128: used_elements.split(",").each{ |used| 1129: if /\s*?(\w+)\s*?=>\s*?(\w+)\s*?/ =~ used 1130: local = $1 1131: org = $2 1132: @@public_methods.collect!{ |pub_meth| 1133: if local == pub_meth["name"] || 1134: local.upcase == pub_meth["name"].upcase && 1135: @options_ignore_case 1136: pub_meth["name"] = org 1137: pub_meth["local_name"] = local 1138: end 1139: pub_meth 1140: } 1141: end 1142: } 1143: end 1144: 1145: # 1146: # Parse private "use" 1147: # 1148: use_check_code = remaining_lines.join("\n") 1149: while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i 1150: use_check_code = $~.pre_match 1151: use_check_code << $~.post_match 1152: used_mod_name = $1.strip.chomp 1153: used_trailing = $3 || "" 1154: next if used_trailing.sub(/^!/, '') =~ IGNORED_MARKER_REGEXP 1155: if !container.include_includes?(used_mod_name, @options_ignore_case) 1156: progress "." 1157: container.add_include Include.new(used_mod_name, "") 1158: end 1159: end 1160: 1161: container.each_includes{ |inc| 1162: TopLevel.all_files.each do |name, toplevel| 1163: indicated_mod = toplevel.find_symbol(inc.name, 1164: nil, @options_ignore_case) 1165: if indicated_mod 1166: indicated_name = indicated_mod.parent.file_relative_name 1167: if !container.include_requires?(indicated_name, @options_ignore_case) 1168: container.add_require(Require.new(indicated_name, "")) 1169: end 1170: break 1171: end 1172: end 1173: } 1174: 1175: # 1176: # Parse derived types definitions 1177: # 1178: derived_types_comment = "" 1179: remaining_code = remaining_lines.join("\n") 1180: while remaining_code =~ /^\s*? 1181: type[\s\,]+(public|private)?\s*?(::)?\s*? 1182: (\w+)\s*?(!.*?)?$ 1183: (.*?) 1184: ^\s*?end\s+type.*?$ 1185: /imx 1186: remaining_code = $~.pre_match 1187: remaining_code << $~.post_match 1188: typename = $3.chomp.strip 1189: type_elements = $5 || "" 1190: type_code = remove_empty_head_lines($&) 1191: type_trailing = find_comments($4) 1192: type_visibility = $1 1193: pre_match = $~.pre_match 1194: next if type_trailing =~ IGNORED_MARKER_REGEXP 1195: type_priority, type_trailing = doc_priority_from_trailing(type_trailing) 1196: type_comment = COMMENTS_ARE_UPPER ? 1197: find_comments(pre_match) + "\n" + type_trailing : 1198: type_trailing + "\n" + find_comments(type_code.sub(/^.*$\n/i, '')) 1199: type_element_visibility_public = true 1200: type_code.split("\n").each{ |line| 1201: if /^\s*?private\s*?$/ =~ line 1202: type_element_visibility_public = nil 1203: break 1204: end 1205: } if type_code 1206: 1207: args_comment = "" 1208: type_args_info = nil 1209: 1210: if @options.show_all 1211: args_comment = find_arguments(nil, type_code, true) 1212: else 1213: type_public_args_list = [] 1214: type_args_info = definition_info(type_code) 1215: type_args_info.each{ |arg| 1216: arg_is_public = type_element_visibility_public 1217: arg_is_public = true if arg.include_attr?("public") 1218: arg_is_public = nil if arg.include_attr?("private") 1219: type_public_args_list << arg.varname if arg_is_public 1220: } 1221: args_comment = find_arguments(type_public_args_list, type_code) 1222: end 1223: 1224: type = AnyMethod.new("type #{typename}", typename) 1225: type.singleton = false 1226: type.params = "" 1227: type.comment = "<b><em> Derived Type </em></b> :: <tt></tt>\n" 1228: type.comment << args_comment if args_comment 1229: type.comment << type_comment if type_comment 1230: type.set_priority(type_priority) if type_priority 1231: progress "t" 1232: @stats.num_methods += 1 1233: container.add_method type 1234: 1235: set_visibility(container, typename, visibility_default, @@public_methods) 1236: 1237: if type_visibility 1238: type_visibility.gsub!(/\s/,'') 1239: type_visibility.gsub!(/\,/,'') 1240: type_visibility.gsub!(/:/,'') 1241: type_visibility.downcase! 1242: if type_visibility == "public" 1243: container.set_visibility_for([typename], :public) 1244: elsif type_visibility == "private" 1245: container.set_visibility_for([typename], :private) 1246: end 1247: end 1248: 1249: check_public_methods(type, container.name) 1250: 1251: if @options.show_all 1252: derived_types_comment << ", " unless derived_types_comment.empty? 1253: derived_types_comment << typename 1254: else 1255: if type.visibility == :public 1256: derived_types_comment << ", " unless derived_types_comment.empty? 1257: derived_types_comment << typename 1258: end 1259: end 1260: 1261: end 1262: 1263: if !derived_types_comment.empty? 1264: derived_types_table = 1265: Attr.new("Derived Types", "Derived_Types", "", 1266: derived_types_comment) 1267: container.add_attribute(derived_types_table) 1268: end 1269: 1270: # 1271: # move interface scope 1272: # 1273: interface_code = "" 1274: while remaining_code =~ /^\s*? 1275: interface( 1276: \s+\w+ | 1277: \s+operator\s*?\(.*?\) | 1278: \s+assignment\s*?\(\s*?=\s*?\) 1279: )?\s*?$ 1280: (.*?) 1281: ^\s*?end\s+interface.*?$ 1282: /imx 1283: interface_code << remove_empty_head_lines($&) + "\n" 1284: remaining_code = $~.pre_match 1285: remaining_code << $~.post_match 1286: end 1287: 1288: # 1289: # Parse global constants or variables in modules 1290: # 1291: const_var_defs = definition_info(before_contains_code) 1292: const_var_defs.each{|defitem| 1293: next if defitem.nodoc 1294: const_or_var_type = "Variable" 1295: const_or_var_progress = "v" 1296: if defitem.include_attr?("parameter") 1297: const_or_var_type = "Constant" 1298: const_or_var_progress = "c" 1299: end 1300: const_or_var = AnyMethod.new(const_or_var_type, defitem.varname) 1301: const_or_var.set_priority(defitem.doc_priority) if defitem.doc_priority 1302: const_or_var.singleton = false 1303: const_or_var.params = "" 1304: self_comment = find_arguments([defitem.varname], before_contains_code) 1305: const_or_var.comment = "<b><em>" + const_or_var_type + "</em></b> :: <tt></tt>\n" 1306: const_or_var.comment << self_comment if self_comment 1307: progress const_or_var_progress 1308: @stats.num_methods += 1 1309: container.add_method const_or_var 1310: 1311: set_visibility(container, defitem.varname, visibility_default, @@public_methods) 1312: 1313: if defitem.include_attr?("public") 1314: container.set_visibility_for([defitem.varname], :public) 1315: elsif defitem.include_attr?("private") 1316: container.set_visibility_for([defitem.varname], :private) 1317: end 1318: 1319: check_public_methods(const_or_var, container.name) 1320: 1321: } if const_var_defs 1322: 1323: remaining_lines = remaining_code.split("\n") 1324: 1325: # "subroutine" or "function" parts are parsed (new) 1326: # 1327: level_depth = 0 1328: block_searching_flag = nil 1329: block_searching_lines = [] 1330: pre_comment = [] 1331: procedure_trailing = "" 1332: procedure_name = "" 1333: procedure_params = "" 1334: procedure_prefix = "" 1335: procedure_result_arg = "" 1336: procedure_type = "" 1337: contains_lines = [] 1338: contains_flag = nil 1339: remaining_lines.collect!{|line| 1340: if !block_searching_flag 1341: # subroutine 1342: if line =~ /^\s*? 1343: (recursive|pure|elemental)?\s*? 1344: subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$ 1345: /ix 1346: block_searching_flag = :subroutine 1347: block_searching_lines << line 1348: 1349: procedure_name = $2.chomp.strip 1350: procedure_params = $3 || "" 1351: procedure_prefix = $1 || "" 1352: procedure_trailing = $4 || "!" 1353: next false 1354: 1355: # function 1356: elsif line =~ /^\s*? 1357: (recursive|pure|elemental)?\s*? 1358: ( 1359: character\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1360: | type\s*?\([\w\s]+?\)\s+ 1361: | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1362: | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1363: | double\s+precision\s+ 1364: | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1365: | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1366: )? 1367: function\s+(\w+)\s*? 1368: (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$ 1369: /ix 1370: block_searching_flag = :function 1371: block_searching_lines << line 1372: 1373: procedure_prefix = $1 || "" 1374: procedure_type = $2 ? $2.chomp.strip : nil 1375: procedure_name = $8.chomp.strip 1376: procedure_params = $9 || "" 1377: procedure_result_arg = $11 ? $11.chomp.strip : procedure_name 1378: procedure_trailing = $12 || "!" 1379: next false 1380: elsif line =~ /^\s*?!\s?(.*)/ 1381: pre_comment << line 1382: next line 1383: else 1384: pre_comment = [] 1385: next line 1386: end 1387: end 1388: contains_flag = true if line =~ /^\s*?contains\s*?(!.*?)?$/ 1389: block_searching_lines << line 1390: contains_lines << line if contains_flag 1391: 1392: level_depth += 1 if block_start?(line) 1393: level_depth -= 1 if block_end?(line) 1394: if level_depth >= 0 1395: next false 1396: end 1397: 1398: # "procedure_code" is formatted. 1399: # ":nodoc:" flag is checked. 1400: # 1401: procedure_code = block_searching_lines.join("\n") 1402: procedure_code = remove_empty_head_lines(procedure_code) 1403: if procedure_trailing.sub(/^!/, '') =~ IGNORED_MARKER_REGEXP 1404: # next loop to search next block 1405: level_depth = 0 1406: block_searching_flag = nil 1407: block_searching_lines = [] 1408: pre_comment = [] 1409: procedure_trailing = "" 1410: procedure_name = "" 1411: procedure_params = "" 1412: procedure_prefix = "" 1413: procedure_result_arg = "" 1414: procedure_type = "" 1415: contains_lines = [] 1416: contains_flag = nil 1417: next false 1418: end 1419: 1420: # AnyMethod is created, and added to container 1421: # 1422: subroutine_function = nil 1423: if block_searching_flag == :subroutine 1424: subroutine_prefix = procedure_prefix 1425: subroutine_name = procedure_name 1426: subroutine_params = procedure_params 1427: subroutine_trailing = procedure_trailing 1428: subroutine_code = procedure_code 1429: subroutine_priority, subroutine_trailing = doc_priority_from_trailing(subroutine_trailing) 1430: 1431: subroutine_comment = COMMENTS_ARE_UPPER ? 1432: pre_comment.join("\n") + "\n" + subroutine_trailing : 1433: subroutine_trailing + "\n" + subroutine_code.sub(/^.*$\n/i, '') 1434: subroutine = AnyMethod.new("subroutine", subroutine_name) 1435: parse_subprogram(subroutine, subroutine_params, 1436: subroutine_comment, subroutine_code, 1437: before_contains_code, nil, subroutine_prefix) 1438: subroutine.set_priority(subroutine_priority) if subroutine_priority 1439: progress "s" 1440: @stats.num_methods += 1 1441: container.add_method subroutine 1442: subroutine_function = subroutine 1443: 1444: namelist_comment = 1445: find_namelists(subroutine, subroutine_code, before_contains_code) 1446: subroutine.comment << namelist_comment if namelist_comment 1447: 1448: elsif block_searching_flag == :function 1449: function_prefix = procedure_prefix 1450: function_type = procedure_type 1451: function_name = procedure_name 1452: function_params_org = procedure_params 1453: function_result_arg = procedure_result_arg 1454: function_trailing = procedure_trailing 1455: function_code_org = procedure_code 1456: function_priority, function_trailing = doc_priority_from_trailing(function_trailing) 1457: 1458: function_comment = COMMENTS_ARE_UPPER ? 1459: pre_comment.join("\n") + "\n" + function_trailing : 1460: function_trailing + "\n " + function_code_org.sub(/^.*$\n/i, '') 1461: 1462: function_code = "#{function_code_org}" 1463: if function_type 1464: function_code << "\n" + function_type + " :: " + function_result_arg 1465: end 1466: 1467: function_params = 1468: function_params_org.sub(/^\(/, "\(#{function_result_arg}, ") 1469: 1470: function = AnyMethod.new("function", function_name) 1471: parse_subprogram(function, function_params, 1472: function_comment, function_code, 1473: before_contains_code, true, function_prefix) 1474: function.set_priority(function_priority) if function_priority 1475: 1476: # Specific modification due to function 1477: function.params.sub!(/\(\s*?#{function_result_arg}\s*?,\s*?/, "\( ") 1478: function.params << " result(" + function_result_arg + ")" 1479: function.start_collecting_tokens 1480: function.add_token Token.new(1,1).set_text(function_code_org) 1481: 1482: progress "f" 1483: @stats.num_methods += 1 1484: container.add_method function 1485: subroutine_function = function 1486: 1487: namelist_comment = 1488: find_namelists(function, function_code, before_contains_code) 1489: function.comment << namelist_comment if namelist_comment 1490: 1491: end 1492: 1493: # The visibility of procedure is specified 1494: # 1495: set_visibility(container, procedure_name, 1496: visibility_default, @@public_methods) 1497: 1498: # The alias for this procedure from external modules 1499: # 1500: check_external_aliases(procedure_name, 1501: subroutine_function.params, 1502: subroutine_function.comment, subroutine_function) if external 1503: check_public_methods(subroutine_function, container.name) 1504: 1505: 1506: # contains_lines are parsed as private procedures 1507: if contains_flag 1508: parse_program_or_module(container, 1509: contains_lines.join("\n"), :private) 1510: end 1511: 1512: # next loop to search next block 1513: level_depth = 0 1514: block_searching_flag = nil 1515: block_searching_lines = [] 1516: pre_comment = [] 1517: procedure_trailing = "" 1518: procedure_name = "" 1519: procedure_params = "" 1520: procedure_prefix = "" 1521: procedure_result_arg = "" 1522: contains_lines = [] 1523: contains_flag = nil 1524: next false 1525: } # End of remaining_lines.collect!{|line| 1526: 1527: # Array remains_lines is converted to String remains_code again 1528: # 1529: remaining_code = remaining_lines.join("\n") 1530: 1531: # 1532: # Parse interface 1533: # 1534: interface_scope = false 1535: generic_name = "" 1536: interface_code.split("\n").each{ |line| 1537: if /^\s*? 1538: interface( 1539: \s+\w+| 1540: \s+operator\s*?\(.*?\)| 1541: \s+assignment\s*?\(\s*?=\s*?\) 1542: )? 1543: \s*?(!.*?)?$ 1544: /ix =~ line 1545: generic_name = $1 ? $1.strip.chomp : nil 1546: interface_trailing = $2 || "!" 1547: interface_scope = true 1548: interface_scope = false if interface_trailing.sub(/^!/, '') =~ IGNORED_MARKER_REGEXP 1549: # if generic_name =~ /operator\s*?\((.*?)\)/i 1550: # operator_name = $1 1551: # if operator_name && !operator_name.empty? 1552: # generic_name = "#{operator_name}" 1553: # end 1554: # end 1555: # if generic_name =~ /assignment\s*?\((.*?)\)/i 1556: # assignment_name = $1 1557: # if assignment_name && !assignment_name.empty? 1558: # generic_name = "#{assignment_name}" 1559: # end 1560: # end 1561: end 1562: if /^\s*?end\s+interface/i =~ line 1563: interface_scope = false 1564: generic_name = nil 1565: end 1566: # internal alias 1567: if interface_scope && /^\s*?module\s+procedure\s+(.*?)(!.*?)?$/i =~ line 1568: procedures = $1.strip.chomp 1569: procedures_trailing = $2 || "!" 1570: next if procedures_trailing.sub(/^!/, '') =~ IGNORED_MARKER_REGEXP 1571: procedures_priority, procedures_trailing = doc_priority_from_trailing(procedures_trailing) 1572: 1573: procedures.split(",").each{ |proc| 1574: proc.strip! 1575: proc.chomp! 1576: next if generic_name == proc || !generic_name 1577: old_meth = container.find_symbol(proc, nil, @options_ignore_case) 1578: next if !old_meth 1579: nolink = old_meth.visibility == :private ? true : nil 1580: nolink = nil if @options.show_all 1581: new_meth = 1582: initialize_external_method(generic_name, proc, 1583: old_meth.params, nil, 1584: old_meth.comment, 1585: old_meth.clone.token_stream[0].text, 1586: true, nolink) 1587: new_meth.singleton = old_meth.singleton 1588: new_meth.set_priority(procedures_priority) if procedures_priority 1589: 1590: progress "i" 1591: @stats.num_methods += 1 1592: container.add_method new_meth 1593: 1594: set_visibility(container, generic_name, visibility_default, @@public_methods) 1595: 1596: check_public_methods(new_meth, container.name) 1597: 1598: } 1599: end 1600: 1601: # external aliases 1602: if interface_scope 1603: # subroutine 1604: proc = nil 1605: params = nil 1606: procedures_trailing = nil 1607: if line =~ /^\s*? 1608: (recursive|pure|elemental)?\s*? 1609: subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$ 1610: /ix 1611: proc = $2.chomp.strip 1612: proc_name = generic_name || proc 1613: params = $3 || "" 1614: procedures_trailing = $4 || "!" 1615: 1616: # function 1617: elsif line =~ /^\s*? 1618: (recursive|pure|elemental)?\s*? 1619: ( 1620: character\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1621: | type\s*?\([\w\s]+?\)\s+ 1622: | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1623: | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1624: | double\s+precision\s+ 1625: | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1626: | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1627: )? 1628: function\s+(\w+)\s*? 1629: (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$ 1630: /ix 1631: proc = $8.chomp.strip 1632: proc_name = generic_name || proc 1633: params = $9 || "" 1634: procedures_trailing = $12 || "!" 1635: else 1636: next 1637: end 1638: next if procedures_trailing.sub(/^!/, '') =~ IGNORED_MARKER_REGEXP 1639: procedures_priority, procedures_trailing = doc_priority_from_trailing(procedures_trailing) 1640: indicated_method = nil 1641: indicated_file = nil 1642: TopLevel.all_files.each do |name, toplevel| 1643: indicated_method = toplevel.find_local_symbol(proc, @options_ignore_case) 1644: indicated_file = name 1645: break if indicated_method 1646: end 1647: 1648: if indicated_method 1649: external_method = 1650: initialize_external_method(proc_name, proc, 1651: indicated_method.params, 1652: indicated_file, 1653: indicated_method.comment) 1654: external_method.set_priority(procedures_priority) if procedures_priority 1655: 1656: progress "e" 1657: @stats.num_methods += 1 1658: container.add_method external_method 1659: set_visibility(container, proc_name, visibility_default, @@public_methods) 1660: if !container.include_requires?(indicated_file, @options_ignore_case) 1661: container.add_require(Require.new(indicated_file, "")) 1662: end 1663: check_public_methods(external_method, container.name) 1664: 1665: else 1666: @@external_aliases << { 1667: "new_name" => proc_name, 1668: "old_name" => proc, 1669: "file_or_module" => container, 1670: "visibility" => find_visibility(container, proc_name, @@public_methods) || visibility_default, 1671: "doc_priority" => procedures_priority 1672: } 1673: end 1674: end 1675: 1676: } if interface_code # End of interface_code.split("\n").each ... 1677: 1678: # 1679: # Already imported methods are removed from @@public_methods. 1680: # Remainders are assumed to be imported from other modules. 1681: # 1682: # 既に参照済みのメソッドは @@public_methods から取り除く. 1683: # 残りは外部モジュールからの参照と仮定する. 1684: # 1685: @@public_methods.delete_if{ |method| method["entity_is_discovered"]} 1686: 1687: @@public_methods.each{ |pub_meth| 1688: next unless pub_meth["file_or_module"].name == container.name 1689: pub_meth["used_modules"].each{ |used_mod| 1690: TopLevel.all_classes_and_modules.each{ |modules| 1691: if modules.name == used_mod || 1692: modules.name.upcase == used_mod.upcase && 1693: @options_ignore_case 1694: modules.method_list.each{ |meth| 1695: if meth.name == pub_meth["name"] || 1696: meth.name.upcase == pub_meth["name"].upcase && 1697: @options_ignore_case 1698: new_meth = initialize_public_method(meth, 1699: modules.name) 1700: if pub_meth["local_name"] 1701: new_meth.name = pub_meth["local_name"] 1702: end 1703: progress "e" 1704: @stats.num_methods += 1 1705: container.add_method new_meth 1706: end 1707: } 1708: end 1709: } 1710: } 1711: } 1712: 1713: container 1714: end
Parse arguments, comment, code of subroutine and function. Return AnyMethod object.
# File parsers/parse_f95.rb, line 1720 1720: def parse_subprogram(subprogram, params, comment, code, 1721: before_contains=nil, function=nil, prefix=nil) 1722: subprogram.singleton = false 1723: prefix = "" if !prefix 1724: arguments = params.sub(/\(/, "").sub(/\)/, "").split(",") if params 1725: args_comment, params_opt = 1726: find_arguments(arguments, code.sub(/^s*?contains\s*?(!.*?)?$.*/im, ""), 1727: nil, nil, true) 1728: params_opt = "( " + params_opt + " ) " if params_opt 1729: subprogram.params = params_opt || "" 1730: 1731: block_comment = find_comments comment 1732: if function 1733: subprogram.comment = "<b><em> Function </em></b> :: <em>#{prefix}</em>\n" 1734: else 1735: subprogram.comment = "<b><em> Subroutine </em></b> :: <em>#{prefix}</em>\n" 1736: end 1737: subprogram.comment << args_comment if args_comment 1738: subprogram.comment << block_comment if block_comment 1739: 1740: # For output source code 1741: subprogram.start_collecting_tokens 1742: subprogram.add_token Token.new(1,1).set_text(code) 1743: 1744: subprogram 1745: end
Parse visibility
# File parsers/parse_f95.rb, line 2050 2050: def parse_visibility(code, default, container) 2051: result = [] 2052: visibility_default = default || :public 2053: 2054: used_modules = [] 2055: container.includes.each{|i| used_modules << i.name} if container 2056: 2057: remaining_code = code.gsub(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "") 2058: remaining_code.split("\n").each{ |line| 2059: if /^\s*?private\s*?$/ =~ line 2060: visibility_default = :private 2061: break 2062: end 2063: } if remaining_code 2064: 2065: remaining_code.split("\n").each{ |line| 2066: if /^\s*?private\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line 2067: methods = $2.sub(/!.*$/, '') 2068: methods.split(",").each{ |meth| 2069: meth.sub!(/!.*$/, '') 2070: meth.gsub!(/:/, '') 2071: result << { 2072: "name" => meth.chomp.strip, 2073: "visibility" => :private, 2074: "used_modules" => used_modules.clone, 2075: "file_or_module" => container, 2076: "entity_is_discovered" => nil, 2077: "local_name" => nil 2078: } 2079: } 2080: elsif /^\s*?public\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line 2081: methods = $2.sub(/!.*$/, '') 2082: methods.split(",").each{ |meth| 2083: meth.sub!(/!.*$/, '') 2084: meth.gsub!(/:/, '') 2085: result << { 2086: "name" => meth.chomp.strip, 2087: "visibility" => :public, 2088: "used_modules" => used_modules.clone, 2089: "file_or_module" => container, 2090: "entity_is_discovered" => nil, 2091: "local_name" => nil 2092: } 2093: } 2094: end 2095: } if remaining_code 2096: 2097: if container 2098: result.each{ |vis_info| 2099: vis_info["parent"] = container.name 2100: } 2101: end 2102: 2103: return visibility_default, result 2104: end
# File parsers/parse_f95.rb, line 1990 1990: def progress(char) 1991: unless @options.quiet 1992: @progress.print(char) 1993: @progress.flush 1994: end 1995: end
Empty lines in header are removed
# File parsers/parse_f95.rb, line 2474 2474: def remove_empty_head_lines(text) 2475: return "" unless text 2476: lines = text.split("\n") 2477: header = true 2478: lines.delete_if{ |line| 2479: header = false if /\S/ =~ line 2480: header && /^\s*?$/ =~ line 2481: } 2482: lines.join("\n") 2483: end
header marker "=", "==", … are removed
# File parsers/parse_f95.rb, line 2487 2487: def remove_header_marker(text) 2488: return text.gsub(/^\s?(=+)/, '<tt></tt>\1') 2489: end
# File parsers/parse_f95.rb, line 2491 2491: def remove_private_comments(body) 2492: body.gsub!(/^(\s*)!--\s*?$.*?^\s*!\+\+\s*?$/m, '\\1!') 2493: return body 2494: end
Remove "Alias for" in end of comments
# File parsers/parse_f95.rb, line 2453 2453: def remove_trailing_alias(text) 2454: return "" if !text 2455: lines = text.split("\n").reverse 2456: comment_block = Array.new 2457: checked = false 2458: lines.each do |line| 2459: if !checked 2460: if /^\s?#{INTERNAL_ALIAS_MES}/ =~ line || 2461: /^\s?#{EXTERNAL_ALIAS_MES}/ =~ line 2462: checked = true 2463: next 2464: end 2465: end 2466: comment_block.unshift line 2467: end 2468: nice_lines = comment_block.join("\n") 2469: nice_lines ||= "" 2470: return nice_lines 2471: end
devine code constructs
# File parsers/parse_f95.rb, line 836 836: def scan 837: 838: # remove private comment 839: remaining_code = remove_private_comments(@body) 840: 841: # continuation lines are united to one line 842: remaining_code = united_to_one_line(remaining_code) 843: 844: # semicolons are replaced to line feed 845: remaining_code = semicolon_to_linefeed(remaining_code) 846: 847: # collect comment for file entity 848: whole_comment, remaining_code = collect_first_comment(remaining_code) 849: @top_level.comment = whole_comment 850: 851: # String "remaining_code" is converted to Array "remaining_lines" 852: remaining_lines = remaining_code.split("\n") 853: 854: # "module" or "program" parts are parsed (new) 855: # 856: level_depth = 0 857: block_searching_flag = nil 858: block_searching_lines = [] 859: pre_comment = [] 860: module_program_trailing = "" 861: module_program_name = "" 862: other_block_level_depth = 0 863: other_block_searching_flag = nil 864: remaining_lines.collect!{|line| 865: if !block_searching_flag && !other_block_searching_flag 866: if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i 867: block_searching_flag = :module 868: block_searching_lines << line 869: module_program_name = $1 870: module_program_trailing = find_comments($2) 871: next false 872: elsif line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i || 873: line =~ /^\s*?\w/ && !block_start?(line) 874: block_searching_flag = :program 875: block_searching_lines << line 876: module_program_name = $1 || "" 877: module_program_trailing = find_comments($2) 878: next false 879: 880: elsif block_start?(line) 881: other_block_searching_flag = true 882: next line 883: 884: elsif line =~ /^\s*?!\s?(.*)/ 885: pre_comment << line 886: next line 887: else 888: pre_comment = [] 889: next line 890: end 891: elsif other_block_searching_flag 892: other_block_level_depth += 1 if block_start?(line) 893: other_block_level_depth -= 1 if block_end?(line) 894: if other_block_level_depth < 0 895: other_block_level_depth = 0 896: other_block_searching_flag = nil 897: end 898: next line 899: end 900: 901: block_searching_lines << line 902: level_depth += 1 if block_start?(line) 903: level_depth -= 1 if block_end?(line) 904: if level_depth >= 0 905: next false 906: end 907: 908: # "module_program_code" is formatted. 909: # ":nodoc:" flag is checked. 910: # 911: module_program_code = block_searching_lines.join("\n") 912: module_program_code = remove_empty_head_lines(module_program_code) 913: if module_program_trailing =~ IGNORED_MARKER_REGEXP 914: # next loop to search next block 915: level_depth = 0 916: block_searching_flag = false 917: block_searching_lines = [] 918: pre_comment = [] 919: next false 920: end 921: 922: # NormalClass is created, and added to @top_level 923: # 924: if block_searching_flag == :module 925: module_name = module_program_name 926: module_code = module_program_code 927: module_trailing = module_program_trailing 928: progress "m" 929: @stats.num_modules += 1 930: f9x_module = @top_level.add_module NormalClass, module_name 931: f9x_module.record_location @top_level 932: 933: # 934: # Add provided modules information to @top_level comment 935: # 936: provided_modules = [] 937: provided_mes_line_num = nil 938: top_level_comment_lines = [] 939: line_num = 0 940: @top_level.comment.split("\n").each{|line| 941: top_level_comment_lines << line 942: line_num += 1 943: next if line.empty? 944: if !provided_mes_line_num && /^\s?#{PROVIDED_MODULES_MES}/ =~ line 945: provided_mes_line_num = line_num 946: next 947: end 948: if provided_mes_line_num 949: if /^\s?\*\s+<b>(\w+)<\/b>/ =~ line 950: provided_modules << $1 951: else 952: provided_mes_line_num = nil 953: end 954: end 955: } 956: line_num = 0 957: if provided_mes_line_num 958: top_level_comment_lines.collect!{ |line| 959: line_num += 1 960: if line_num < provided_mes_line_num 961: line 962: else 963: nil 964: end 965: } 966: top_level_comment_lines.delete_if{|line| !line } 967: end 968: top_level_comment_lines << "\n" + PROVIDED_MODULES_MES + "." 969: if provided_mes_line_num 970: top_level_comment_lines[-1].sub!(/\.$/, '') 971: top_level_comment_lines[-1] << "s." 972: end 973: provided_modules.each{ |mod| 974: top_level_comment_lines << "* <b>" + mod + "</b>" 975: } 976: top_level_comment_lines << "* <b>" + module_name + "</b>" 977: @top_level.comment = top_level_comment_lines.join("\n") 978: 979: # 980: # Information about the module is parsed 981: # 982: f9x_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) + 983: "\n" + module_trailing : module_trailing + "\n" + 984: find_comments(module_code.sub(/^.*$\n/i, '')) 985: f9x_module.comment = f9x_comment 986: parse_program_or_module(f9x_module, module_code) 987: 988: TopLevel.all_files.each do |name, toplevel| 989: if toplevel.include_includes?(module_name, @options_ignore_case) 990: if !toplevel.include_requires?(@file_name, @options_ignore_case) 991: toplevel.add_require(Require.new(@file_name, "")) 992: end 993: end 994: toplevel.each_classmodule{|m| 995: if m.include_includes?(module_name, @options_ignore_case) 996: if !m.include_requires?(@file_name, @options_ignore_case) 997: m.add_require(Require.new(@file_name, "")) 998: end 999: end 1000: } 1001: end 1002: 1003: namelist_comment = 1004: find_namelists(f9x_module, before_contains(module_code)) 1005: f9x_module.comment << namelist_comment if namelist_comment 1006: 1007: elsif block_searching_flag == :program 1008: program_name = module_program_name 1009: program_name = "main_program" if program_name.empty? 1010: program_code = module_program_code 1011: program_trailing = module_program_trailing 1012: program_priority, program_trailing = doc_priority_from_trailing(program_trailing) 1013: 1014: program_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) + 1015: "\n" + program_trailing : program_trailing + "\n" + 1016: find_comments(program_code.sub(/^.*$\n/i, '')) 1017: 1018: progress "p" 1019: @stats.num_methods += 1 1020: f9x_mainprogram = AnyMethod.new("main_program", program_name) 1021: f9x_mainprogram.singleton = false 1022: f9x_mainprogram.comment = "<b><em> Main Program </em></b> :: <tt></tt>\n" 1023: f9x_mainprogram.comment << program_comment 1024: f9x_mainprogram.params = "" 1025: f9x_mainprogram.set_priority(program_priority) if program_priority 1026: 1027: # For output source code 1028: f9x_mainprogram.start_collecting_tokens 1029: f9x_mainprogram.add_token Token.new(1,1).set_text(program_code) 1030: 1031: @top_level.add_method f9x_mainprogram 1032: parse_program_or_module(@top_level, program_code, :private) 1033: 1034: namelist_comment = find_namelists(f9x_mainprogram, program_code) 1035: f9x_mainprogram.comment << namelist_comment if namelist_comment 1036: end 1037: 1038: # next loop to search next block 1039: level_depth = 0 1040: block_searching_flag = false 1041: block_searching_lines = [] 1042: pre_comment = [] 1043: next false 1044: } 1045: 1046: remaining_lines.delete_if{ |line| 1047: line == false 1048: } 1049: 1050: # External subprograms and functions are parsed 1051: # 1052: # 単一のファイル内において program や module に格納されない, 1053: # 外部サブルーチン, 外部関数部分の解析. 1054: # 1055: parse_program_or_module(@top_level, remaining_lines.join("\n"), 1056: :public, true) 1057: 1058: @top_level 1059: end
Semicolons are replaced to line feed.
# File parsers/parse_f95.rb, line 2356 2356: def semicolon_to_linefeed(text) 2357: return "" unless text 2358: lines = text.split("\n") 2359: lines.collect!{ |line| 2360: indent_space = "" 2361: if line =~ /^(\s+)/ 2362: indent_space = $1 2363: end 2364: words = line.split("") 2365: commentout = false 2366: squote = false ; dquote = false 2367: words.collect! { |char| 2368: if !(squote) && !(dquote) && !(commentout) 2369: case char 2370: when "!" ; commentout = true ; next char 2371: when "\""; dquote = true ; next char 2372: when "\'"; squote = true ; next char 2373: when ";" ; "\n"+indent_space 2374: else next char 2375: end 2376: elsif commentout 2377: next char 2378: elsif squote 2379: case char 2380: when "\'"; squote = false ; next char 2381: else next char 2382: end 2383: elsif dquote 2384: case char 2385: when "\""; dquote = false ; next char 2386: else next char 2387: end 2388: end 2389: } 2390: words.join("") 2391: } 2392: return lines.join("\n") 2393: end
Set visibility
"subname" element of "visibility_info" is deleted.
# File parsers/parse_f95.rb, line 2111 2111: def set_visibility(container, subname, visibility_default, visibility_info) 2112: return unless container || subname || visibility_default || visibility_info 2113: not_found = true 2114: visibility_info.collect!{ |info| 2115: if info["name"] == subname || 2116: @options_ignore_case && info["name"].upcase == subname.upcase 2117: if info["file_or_module"].name == container.name 2118: container.set_visibility_for([subname], info["visibility"]) 2119: info["entity_is_discovered"] = true 2120: not_found = false 2121: end 2122: end 2123: info 2124: } 2125: if not_found 2126: return container.set_visibility_for([subname], visibility_default) 2127: else 2128: return container 2129: end 2130: 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 2231 2231: def united_to_one_line(f90src, delete_space=true) 2232: return "" unless f90src 2233: lines = f90src.split("\n") 2234: previous_continuing = false 2235: now_continuing = false 2236: body = "" 2237: squote = false ; dquote = false 2238: lines.each{ |line| 2239: words = line.split("") 2240: next if words.empty? && previous_continuing 2241: commentout = false 2242: brank_flag = true ; brank_char = "" 2243: ignore = false 2244: words.collect! { |char| 2245: if previous_continuing && brank_flag 2246: now_continuing = true 2247: ignore = true 2248: case char 2249: when "!" ; break 2250: when " " ; brank_char << char ; next "" 2251: when "&" 2252: brank_flag = false 2253: now_continuing = false 2254: next "" 2255: else 2256: brank_flag = false 2257: now_continuing = false 2258: ignore = false 2259: next brank_char + char 2260: end 2261: end 2262: ignore = false 2263: 2264: if now_continuing && !(squote) && !(dquote) 2265: next "" 2266: elsif !(squote) && !(dquote) && !(commentout) 2267: case char 2268: when "!" ; commentout = true ; next char 2269: when "\""; dquote = true ; next char 2270: when "\'"; squote = true ; next char 2271: when "&" ; now_continuing = true ; next "" 2272: else next char 2273: end 2274: elsif commentout 2275: next char 2276: elsif squote 2277: case char 2278: when "\'"; squote = false ; now_continuing = false ; next char 2279: when "&" ; now_continuing = true ; next "" 2280: else next char 2281: end 2282: elsif dquote 2283: case char 2284: when "\""; dquote = false ; now_continuing = false ; next char 2285: when "&" ; now_continuing = true ; next "" 2286: else next char 2287: end 2288: end 2289: } 2290: if !ignore && !previous_continuing || !brank_flag 2291: if previous_continuing 2292: if delete_space 2293: joined_words = words.join("") 2294: body = body.rstrip + " " + joined_words.lstrip 2295: else 2296: body << words.join("") 2297: end 2298: else 2299: body << "\n" + words.join("") 2300: end 2301: end 2302: previous_continuing = now_continuing ? true : false 2303: now_continuing = false 2304: } 2305: return body 2306: end