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 912 912: def initialize(top_level, file_name, body, options, stats) 913: @body = body 914: @stats = stats 915: @file_name = file_name 916: @options = options 917: @top_level = top_level 918: @progress = $stderr unless options.quiet 919: 920: begin 921: @options_ignore_case = options.ignore_case 922: rescue 923: @options_ignore_case = true 924: end 925: 926: end
Return lines before "contains" statement in modules. "interface", "type" statements are removed.
# File parsers/parse_f95.rb, line 1860 1860: def before_contains(code) 1861: level_depth = 0 1862: before_contains_lines = [] 1863: before_contains_code = nil 1864: before_contains_flag = nil 1865: code.split("\n").each{ |line| 1866: if !before_contains_flag 1867: if line =~ /^\s*?module\s+\w+\s*?(!.*?)?$/i 1868: before_contains_flag = true 1869: end 1870: else 1871: break if line =~ /^\s*?contains\s*?(!.*?)?$/i 1872: level_depth += 1 if block_start?(line) 1873: level_depth -= 1 if block_end?(line) 1874: break if level_depth < 0 1875: before_contains_lines << line 1876: end 1877: 1878: } 1879: before_contains_code = before_contains_lines.join("\n") 1880: if before_contains_code 1881: before_contains_code.gsub!(/^\s*?interface\s+.*?\s+end\s+interface.*?$/im, "") 1882: before_contains_code.gsub!(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "") 1883: end 1884: 1885: before_contains_code 1886: end
Which "line" is end of block (module, program, block data, subroutine, function) statement ?
# File parsers/parse_f95.rb, line 2528 2528: def block_end?(line) 2529: return nil if !line 2530: 2531: if line =~ /^\s*?end\s*?(!.*?)?$/i || 2532: line =~ /^\s*?end\s+module(\s+\w+)?\s*?(!.*?)?$/i || 2533: line =~ /^\s*?end\s+program(\s+\w+)?\s*?(!.*?)?$/i || 2534: line =~ /^\s*?end\s+block\s+data(\s+\w+)?\s*?(!.*?)?$/i || 2535: line =~ /^\s*?end\s+subroutine(\s+\w+)?\s*?(!.*?)?$/i || 2536: line =~ /^\s*?end\s+function(\s+\w+)?\s*?(!.*?)?$/i 2537: return true 2538: end 2539: 2540: return nil 2541: end
Which "line" is start of block (module, program, block data, subroutine, function) statement ?
# File parsers/parse_f95.rb, line 2492 2492: def block_start?(line) 2493: return nil if !line 2494: 2495: if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i || 2496: line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i || 2497: line =~ /^\s*?block\s+data(\s+\w+)?\s*?(!.*?)?$/i || 2498: line =~ \ 2499: /^\s*? 2500: (recursive|pure|elemental)?\s*? 2501: subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$ 2502: /ix || 2503: line =~ \ 2504: /^\s*? 2505: (recursive|pure|elemental)?\s*? 2506: ( 2507: character\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 2508: | type\s*?\([\w\s]+?\)\s+ 2509: | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 2510: | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 2511: | double\s+precision\s+ 2512: | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 2513: | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 2514: )? 2515: function\s+(\w+)\s*? 2516: (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$ 2517: /ix 2518: return true 2519: end 2520: 2521: return nil 2522: end
Check external aliases
subname というサブルーチン名, または関数名を持つファイルを 探査し, 存在する場合にはそのファイル内へメソッドを追加する.
# File parsers/parse_f95.rb, line 2247 2247: def check_external_aliases(subname, params, comment, test=nil) 2248: @@external_aliases.each{ |alias_item| 2249: if subname == alias_item["old_name"] || 2250: subname.upcase == alias_item["old_name"].upcase && 2251: @options_ignore_case 2252: 2253: new_meth = initialize_external_method(alias_item["new_name"], 2254: subname, params, @file_name, 2255: comment) 2256: new_meth.visibility = alias_item["visibility"] 2257: new_meth.set_priority(alias_item["doc_priority"]) if alias_item["doc_priority"] 2258: 2259: progress "e" 2260: @stats.num_methods += 1 2261: alias_item["file_or_module"].add_method(new_meth) 2262: 2263: if !alias_item["file_or_module"].include_requires?(@file_name, @options_ignore_case) 2264: alias_item["file_or_module"].add_require(Require.new(@file_name, "")) 2265: end 2266: end 2267: } 2268: end
Check public_methods
use したモジュールからそのまま引き継いで public として 公開する場合のチェックを行う. subname というサブルーチン名, または関数名を持つファイルを 探査し, 存在する場合にはそのファイル内へメソッドを追加する.
# File parsers/parse_f95.rb, line 2278 2278: def check_public_methods(method, parent) 2279: return if !method || !parent 2280: @@public_methods.each{ |alias_item| 2281: parent_is_used_module = nil 2282: alias_item["used_modules"].each{ |used_module| 2283: if used_module == parent || 2284: used_module.upcase == parent.upcase && 2285: @options_ignore_case 2286: parent_is_used_module = true 2287: end 2288: } 2289: next if !parent_is_used_module 2290: 2291: if method.name == alias_item["name"] || 2292: method.name.upcase == alias_item["name"].upcase && 2293: @options_ignore_case 2294: 2295: new_meth = initialize_public_method(method, parent) 2296: if alias_item["local_name"] 2297: new_meth.name = alias_item["local_name"] 2298: end 2299: 2300: progress "e" 2301: @stats.num_methods += 1 2302: alias_item["file_or_module"].add_method new_meth 2303: end 2304: } 2305: end
Collect comment for file entity
# File parsers/parse_f95.rb, line 1891 1891: def collect_first_comment(body) 1892: comment = "" 1893: not_comment = "" 1894: comment_start = false 1895: comment_end = false 1896: body.split("\n").each{ |line| 1897: if comment_end 1898: not_comment << line 1899: not_comment << "\n" 1900: elsif /^\s*?!\s?(.*)$/i =~ line 1901: comment_start = true 1902: comment << $1 1903: comment << "\n" 1904: elsif /^\s*?$/i =~ line 1905: comment_end = true if comment_start && COMMENTS_ARE_UPPER 1906: else 1907: comment_end = true 1908: not_comment << line 1909: not_comment << "\n" 1910: end 1911: } 1912: return comment, not_comment 1913: end
Comment out checker
# File parsers/parse_f95.rb, line 2419 2419: def comment_out?(line) 2420: return nil unless line 2421: commentout = false 2422: squote = false ; dquote = false 2423: line.split("").each { |char| 2424: if !(squote) && !(dquote) 2425: case char 2426: when "!" ; commentout = true ; break 2427: when "\""; dquote = true 2428: when "\'"; squote = true 2429: else next 2430: end 2431: elsif squote 2432: case char 2433: when "\'"; squote = false 2434: else next 2435: end 2436: elsif dquote 2437: case char 2438: when "\""; dquote = false 2439: else next 2440: end 2441: end 2442: } 2443: return commentout 2444: end
Continuous line checker
# File parsers/parse_f95.rb, line 2405 2405: def continuous_line?(line) 2406: continuous = false 2407: if /&\s*?(!.*)?$/ =~ line 2408: continuous = true 2409: if comment_out?($~.pre_match) 2410: continuous = false 2411: end 2412: end 2413: return continuous 2414: end
Parse string argument "text", and Return Array of Fortran95Definition object
# File parsers/parse_f95.rb, line 2670 2670: def definition_info(text) 2671: return nil unless text 2672: lines = "#{text}" 2673: defs = Array.new 2674: comment = "" 2675: trailing_comment = "" 2676: under_comment_valid = false 2677: lines.split("\n").each{ |line| 2678: if /^\s*?!\s?(.*)/ =~ line 2679: if COMMENTS_ARE_UPPER 2680: comment << remove_header_marker($1) 2681: comment << "\n" 2682: elsif defs[-1] && under_comment_valid 2683: defs[-1].comment << "\n" 2684: defs[-1].comment << remove_header_marker($1) 2685: end 2686: next 2687: elsif /^\s*?$/ =~ line 2688: comment = "" 2689: under_comment_valid = false 2690: next 2691: end 2692: type = "" 2693: characters = "" 2694: if line =~ /^\s*? 2695: ( 2696: character\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* 2697: | type\s*?\([\w\s]+?\)[\s\,]* 2698: | integer\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* 2699: | real\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* 2700: | double\s+precision[\s\,]* 2701: | logical\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* 2702: | complex\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* 2703: ) 2704: (.*?::)? 2705: (.+)$ 2706: /ix 2707: characters = $8 2708: type = $1 2709: type << $7.gsub(/::/, '').gsub(/^\s*?\,/, '') if $7 2710: else 2711: under_comment_valid = false 2712: next 2713: end 2714: squote = false ; dquote = false ; bracket = 0 2715: iniflag = false; commentflag = false 2716: varname = "" ; arraysuffix = "" ; inivalue = "" 2717: start_pos = defs.size 2718: characters.split("").each { |char| 2719: if !(squote) && !(dquote) && bracket <= 0 && !(iniflag) && !(commentflag) 2720: case char 2721: when "!" ; commentflag = true 2722: when "(" ; bracket += 1 ; arraysuffix = char 2723: when "\""; dquote = true 2724: when "\'"; squote = true 2725: when "=" ; iniflag = true ; inivalue << char 2726: when "," 2727: defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment) 2728: varname = "" ; arraysuffix = "" ; inivalue = "" 2729: under_comment_valid = true 2730: when " " ; next 2731: else ; varname << char 2732: end 2733: elsif commentflag 2734: comment << remove_header_marker(char) 2735: trailing_comment << remove_header_marker(char) 2736: elsif iniflag 2737: if dquote 2738: case char 2739: when "\"" ; dquote = false ; inivalue << char 2740: else ; inivalue << char 2741: end 2742: elsif squote 2743: case char 2744: when "\'" ; squote = false ; inivalue << char 2745: else ; inivalue << char 2746: end 2747: elsif bracket > 0 2748: case char 2749: when "(" ; bracket += 1 ; inivalue << char 2750: when ")" ; bracket -= 1 ; inivalue << char 2751: else ; inivalue << char 2752: end 2753: else 2754: case char 2755: when "," 2756: defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment) 2757: varname = "" ; arraysuffix = "" ; inivalue = "" 2758: iniflag = false 2759: under_comment_valid = true 2760: when "(" ; bracket += 1 ; inivalue << char 2761: when "\""; dquote = true ; inivalue << char 2762: when "\'"; squote = true ; inivalue << char 2763: when "!" ; commentflag = true 2764: else ; inivalue << char 2765: end 2766: end 2767: elsif !(squote) && !(dquote) && bracket > 0 2768: case char 2769: when "(" ; bracket += 1 ; arraysuffix << char 2770: when ")" ; bracket -= 1 ; arraysuffix << char 2771: else ; arraysuffix << char 2772: end 2773: elsif squote 2774: case char 2775: when "\'"; squote = false ; inivalue << char 2776: else ; inivalue << char 2777: end 2778: elsif dquote 2779: case char 2780: when "\""; dquote = false ; inivalue << char 2781: else ; inivalue << char 2782: end 2783: end 2784: } 2785: defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment) 2786: if trailing_comment =~ IGNORED_MARKER_REGEXP 2787: defs[start_pos..-1].collect!{ |defitem| 2788: defitem.nodoc = true 2789: } 2790: end 2791: if trailing_comment =~ DOC_PRIORITY_REGEXP 2792: doc_priority = $1.to_i 2793: defs[start_pos..-1].collect!{ |defitem| 2794: defitem.doc_priority = doc_priority 2795: defitem.comment.sub!(DOC_PRIORITY_REGEXP, '') 2796: } 2797: end 2798: varname = "" ; arraysuffix = "" ; inivalue = "" 2799: comment = "" 2800: under_comment_valid = true 2801: trailing_comment = "" 2802: } 2803: return defs 2804: end
# File parsers/parse_f95.rb, line 1840 1840: def doc_priority_from_trailing(trailing) 1841: prefix = '' 1842: if trailing =~ /^(\s*!)(.*)$/ 1843: prefix = $1 1844: trailing = $2 1845: end 1846: if trailing =~ DOC_PRIORITY_REGEXP 1847: priority = $1.to_i 1848: trailing.sub!(DOC_PRIORITY_REGEXP, '') 1849: else 1850: priority = false 1851: end 1852: trailing = prefix + trailing 1853: return priority, trailing 1854: 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 1922 1922: def find_arguments(args, text, all=nil, indent=nil, modified_params=nil) 1923: return unless args || all 1924: indent = "" unless indent 1925: args = ["all"] if all 1926: params = "" if modified_params 1927: comma = "" 1928: return unless text 1929: args_rdocforms = "\n" 1930: remaining_lines = "#{text}" 1931: definitions = definition_info(remaining_lines) 1932: args.each{ |arg| 1933: arg.strip! 1934: arg.chomp! 1935: definitions.each { |defitem| 1936: if arg == defitem.varname.strip.chomp || all 1937: 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" 1938: if !defitem.comment.chomp.strip.empty? 1939: comment = "" 1940: defitem.comment.split("\n").each{ |line| 1941: comment << " " + line + "\n" 1942: } 1943: args_rdocforms << "\n\#{indent} <tt></tt> ::\n\#{indent} <tt></tt>\n\#{indent} \#{comment.chomp.strip}\n" 1944: end 1945: 1946: if modified_params 1947: if defitem.include_attr?("optional") 1948: params << "#{comma}[#{arg}]" 1949: else 1950: params << "#{comma}#{arg}" 1951: end 1952: comma = ", " 1953: end 1954: end 1955: } 1956: } 1957: if modified_params 1958: return args_rdocforms, params 1959: else 1960: return args_rdocforms 1961: end 1962: 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 2065 2065: def find_comments text 2066: return "" unless text 2067: lines = text.split("\n") 2068: lines.reverse! if COMMENTS_ARE_UPPER 2069: comment_block = Array.new 2070: lines.each do |line| 2071: break if line =~ /^\s*?\w/ || line =~ /^\s*?$/ 2072: if COMMENTS_ARE_UPPER 2073: comment_block.unshift line.sub(/^\s*?!\s?/,"") 2074: else 2075: comment_block.push line.sub(/^\s*?!\s?/,"") 2076: end 2077: end 2078: nice_lines = comment_block.join("\n").split "\n\s*?\n" 2079: nice_lines[0] ||= "" 2080: nice_lines.shift 2081: 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 1980 1980: def find_namelists(container, text, before_contains=nil) 1981: return nil if !text 1982: top_level = find_toplevel(container) 1983: 1984: if text =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)(!.*?)?$/i 1985: if top_level.include_includes?(NAMELIST_REPOSITORY_NAME) 1986: namelist_module = 1987: top_level.find_module_named(NAMELIST_REPOSITORY_NAME) 1988: else 1989: namelist_module = 1990: top_level.add_module NormalClass, NAMELIST_REPOSITORY_NAME 1991: namelist_module.record_location top_level 1992: namelist_module.comment = "This is not a module but a repository of NAMELIST group names declared\nin all Fortran 90/95 files\n" 1993: end 1994: else 1995: return "" 1996: end 1997: 1998: nml_group_name_lists = [] 1999: lines = "#{text}" 2000: before_contains = "" if !before_contains 2001: while lines =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)(!.*?)?$/i 2002: lines = $~.post_match 2003: pre_match = $~.pre_match ; post_match = $~.post_match 2004: nml_group_name = $1 2005: trailing_comment = $3 || "" 2006: nml_vars_list = $2.split(",") 2007: nml_comment = COMMENTS_ARE_UPPER ? 2008: find_comments(pre_match.sub(/\n$/, '')) : 2009: find_comments(trailing_comment + post_match) 2010: if lines.split("\n")[0] =~ /^\//i 2011: lines = "namelist " + lines 2012: end 2013: 2014: nml_meth = AnyMethod.new("NAMELIST", nml_group_name) 2015: nml_meth.singleton = false 2016: nml_meth.params = "( " + nml_vars_list.join(", ") + " )" 2017: nml_meth.comment = "<b><em> NAMELIST </em></b> :: <tt></tt>\n" 2018: nml_meth.comment << find_arguments(nml_vars_list, "#{text}" + "\n" + before_contains) 2019: nml_meth.comment << "\n" + nml_comment if nml_comment 2020: if container.parent.parent 2021: parent_object = container.parent.name 2022: else 2023: parent_object = container.parent.file_relative_name 2024: end 2025: nml_meth.comment << "\n\nThis namelist group name is input/output in " 2026: nml_meth.comment << parent_object + "#" + container.name 2027: 2028: progress "n" 2029: @stats.num_methods += 1 2030: namelist_module.add_method nml_meth 2031: 2032: nml_group_name_lists << NAMELIST_REPOSITORY_NAME + "#" + nml_group_name 2033: end 2034: 2035: if !nml_group_name_lists.empty? 2036: comments_in_procedures = "\n\nThis procedure input/output " 2037: comments_in_procedures << nml_group_name_lists.join(", ") + " . " 2038: else 2039: comments_in_procedures = "" 2040: end 2041: 2042: comments_in_procedures 2043: end
Return toplevel class of container
# File parsers/parse_f95.rb, line 2052 2052: def find_toplevel(container) 2053: top_level = container 2054: while top_level.parent 2055: top_level = top_level.parent 2056: end 2057: top_level 2058: end
Find visibility
# File parsers/parse_f95.rb, line 2228 2228: def find_visibility(container, subname, visibility_info) 2229: return nil if !subname || !visibility_info 2230: visibility_info.each{ |info| 2231: if info["name"] == subname || 2232: @options_ignore_case && info["name"].upcase == subname.upcase 2233: if info["parent"] == container.name 2234: return info["visibility"] 2235: end 2236: end 2237: } 2238: return nil 2239: end
Create method for external alias
If argument "internal" is true, file is ignored.
# File parsers/parse_f95.rb, line 2110 2110: def initialize_external_method(new, old, params, file, comment, token=nil, 2111: internal=nil, nolink=nil) 2112: return nil unless new || old 2113: 2114: if internal 2115: external_alias_header = "#{INTERNAL_ALIAS_MES} " 2116: external_alias_text = external_alias_header + old 2117: elsif file 2118: external_alias_header = "#{EXTERNAL_ALIAS_MES} " 2119: external_alias_text = external_alias_header + file + "#" + old 2120: else 2121: return nil 2122: end 2123: external_meth = AnyMethod.new(external_alias_text, new) 2124: external_meth.singleton = false 2125: external_meth.params = params 2126: external_comment = remove_trailing_alias(comment) + "\n\n" if comment 2127: external_meth.comment = external_comment || "" 2128: if nolink && token 2129: external_meth.start_collecting_tokens 2130: external_meth.add_token Token.new(1,1).set_text(token) 2131: else 2132: external_meth.comment << external_alias_text 2133: end 2134: 2135: return external_meth 2136: end
Create method for internal alias
# File parsers/parse_f95.rb, line 2093 2093: def initialize_public_method(method, parent) 2094: return if !method || !parent 2095: 2096: new_meth = AnyMethod.new("External Alias for module", method.name) 2097: new_meth.singleton = method.singleton 2098: new_meth.params = method.params.clone 2099: new_meth.comment = remove_trailing_alias(method.comment.clone) 2100: new_meth.comment << "\n\n#{EXTERNAL_ALIAS_MES} #{parent.strip.chomp}\##{method.name}" 2101: 2102: return new_meth 2103: end
# File parsers/parse_f95.rb, line 1156 1156: def parse_program_or_module(container, code, 1157: visibility=:public, external=nil) 1158: return unless container 1159: return unless code 1160: remaining_lines = code.split("\n") 1161: remaining_code = "#{code}" 1162: 1163: # 1164: # Parse variables before "contains" in module 1165: # 1166: # namelist 変数の定義に使われたり, これ自体が定数, 変数 1167: # 提供されるのに利用される. (変数や定数として利用される場合, 1168: # これもメソッドとして提供する. 1169: # 1170: before_contains_code = before_contains(remaining_code) 1171: 1172: # 1173: # Parse global "use" 1174: # 1175: use_check_code = "#{before_contains_code}" 1176: cascaded_modules_list = [] 1177: while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i 1178: use_check_code = $~.pre_match 1179: use_check_code << $~.post_match 1180: used_mod_name = $1.strip.chomp 1181: used_list = $2 || "" 1182: used_trailing = $3 || "" 1183: next if used_trailing.sub(/^!/, '') =~ IGNORED_MARKER_REGEXP 1184: if !container.include_includes?(used_mod_name, @options_ignore_case) 1185: progress "." 1186: container.add_include Include.new(used_mod_name, "") 1187: end 1188: if ! (used_list =~ /\,\s*?only\s*?:/i ) 1189: cascaded_modules_list << "\#" + used_mod_name 1190: end 1191: end 1192: 1193: # 1194: # Parse public and private, and store information. 1195: # This information is used when "add_method" and 1196: # "set_visibility_for" are called. 1197: # 1198: visibility_default, visibility_info = 1199: parse_visibility(remaining_lines.join("\n"), visibility, container) 1200: @@public_methods.concat visibility_info 1201: if visibility_default == :public 1202: if !cascaded_modules_list.empty? 1203: cascaded_modules = 1204: Attr.new("Cascaded Modules", 1205: "Imported modules all of whose components are published again", 1206: "", 1207: cascaded_modules_list.join(", ")) 1208: container.add_attribute(cascaded_modules) 1209: end 1210: end 1211: 1212: # 1213: # Check rename elements 1214: # 1215: use_check_code = "#{before_contains_code}" 1216: while use_check_code =~ /^\s*?use\s+(\w+)\s*?\,(.+)$/i 1217: use_check_code = $~.pre_match 1218: use_check_code << $~.post_match 1219: used_mod_name = $1.strip.chomp 1220: used_elements = $2.sub(/\s*?only\s*?:\s*?/i, '') 1221: used_elements.split(",").each{ |used| 1222: if /\s*?(\w+)\s*?=>\s*?(\w+)\s*?/ =~ used 1223: local = $1 1224: org = $2 1225: @@public_methods.collect!{ |pub_meth| 1226: if local == pub_meth["name"] || 1227: local.upcase == pub_meth["name"].upcase && 1228: @options_ignore_case 1229: pub_meth["name"] = org 1230: pub_meth["local_name"] = local 1231: end 1232: pub_meth 1233: } 1234: end 1235: } 1236: end 1237: 1238: # 1239: # Parse private "use" 1240: # 1241: use_check_code = remaining_lines.join("\n") 1242: while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i 1243: use_check_code = $~.pre_match 1244: use_check_code << $~.post_match 1245: used_mod_name = $1.strip.chomp 1246: used_trailing = $3 || "" 1247: next if used_trailing.sub(/^!/, '') =~ IGNORED_MARKER_REGEXP 1248: if !container.include_includes?(used_mod_name, @options_ignore_case) 1249: progress "." 1250: container.add_include Include.new(used_mod_name, "") 1251: end 1252: end 1253: 1254: container.each_includes{ |inc| 1255: TopLevel.all_files.each do |name, toplevel| 1256: indicated_mod = toplevel.find_symbol(inc.name, 1257: nil, @options_ignore_case) 1258: if indicated_mod 1259: indicated_name = indicated_mod.parent.file_relative_name 1260: if !container.include_requires?(indicated_name, @options_ignore_case) 1261: container.add_require(Require.new(indicated_name, "")) 1262: end 1263: break 1264: end 1265: end 1266: } 1267: 1268: # 1269: # Parse derived types definitions 1270: # 1271: derived_types_comment = "" 1272: remaining_code = remaining_lines.join("\n") 1273: while remaining_code =~ /^\s*? 1274: type[\s\,]+(public|private)?\s*?(::)?\s*? 1275: (\w+)\s*?(!.*?)?$ 1276: (.*?) 1277: ^\s*?end\s+type.*?$ 1278: /imx 1279: remaining_code = $~.pre_match 1280: remaining_code << $~.post_match 1281: typename = $3.chomp.strip 1282: type_elements = $5 || "" 1283: type_code = remove_empty_head_lines($&) 1284: type_trailing = find_comments($4) 1285: type_visibility = $1 1286: pre_match = $~.pre_match 1287: next if type_trailing =~ IGNORED_MARKER_REGEXP 1288: type_priority, type_trailing = doc_priority_from_trailing(type_trailing) 1289: type_comment = COMMENTS_ARE_UPPER ? 1290: find_comments(pre_match) + "\n" + type_trailing : 1291: type_trailing + "\n" + find_comments(type_code.sub(/^.*$\n/i, '')) 1292: type_element_visibility_public = true 1293: type_code.split("\n").each{ |line| 1294: if /^\s*?private\s*?$/ =~ line 1295: type_element_visibility_public = nil 1296: break 1297: end 1298: } if type_code 1299: 1300: args_comment = "" 1301: type_args_info = nil 1302: 1303: if @options.show_all 1304: args_comment = find_arguments(nil, type_code, true) 1305: else 1306: type_public_args_list = [] 1307: type_args_info = definition_info(type_code) 1308: type_args_info.each{ |arg| 1309: arg_is_public = type_element_visibility_public 1310: arg_is_public = true if arg.include_attr?("public") 1311: arg_is_public = nil if arg.include_attr?("private") 1312: type_public_args_list << arg.varname if arg_is_public 1313: } 1314: args_comment = find_arguments(type_public_args_list, type_code) 1315: end 1316: 1317: type = AnyMethod.new("type #{typename}", typename) 1318: type.singleton = false 1319: type.params = "" 1320: type.comment = "<b><em> Derived Type </em></b> :: <tt></tt>\n" 1321: type.comment << args_comment if args_comment 1322: type.comment << type_comment if type_comment 1323: type.set_priority(type_priority) if type_priority 1324: progress "t" 1325: @stats.num_methods += 1 1326: container.add_method type 1327: 1328: set_visibility(container, typename, visibility_default, @@public_methods) 1329: 1330: if type_visibility 1331: type_visibility.gsub!(/\s/,'') 1332: type_visibility.gsub!(/\,/,'') 1333: type_visibility.gsub!(/:/,'') 1334: type_visibility.downcase! 1335: if type_visibility == "public" 1336: container.set_visibility_for([typename], :public) 1337: elsif type_visibility == "private" 1338: container.set_visibility_for([typename], :private) 1339: end 1340: end 1341: 1342: check_public_methods(type, container.name) 1343: 1344: if @options.show_all 1345: derived_types_comment << ", " unless derived_types_comment.empty? 1346: derived_types_comment << typename 1347: else 1348: if type.visibility == :public 1349: derived_types_comment << ", " unless derived_types_comment.empty? 1350: derived_types_comment << typename 1351: end 1352: end 1353: 1354: end 1355: 1356: if !derived_types_comment.empty? 1357: derived_types_table = 1358: Attr.new("Derived Types", "Derived_Types", "", 1359: derived_types_comment) 1360: container.add_attribute(derived_types_table) 1361: end 1362: 1363: # 1364: # move interface scope 1365: # 1366: interface_code = "" 1367: while remaining_code =~ /^\s*? 1368: interface( 1369: \s+\w+ | 1370: \s+operator\s*?\(.*?\) | 1371: \s+assignment\s*?\(\s*?=\s*?\) 1372: )?\s*?$ 1373: (.*?) 1374: ^\s*?end\s+interface.*?$ 1375: /imx 1376: interface_code << remove_empty_head_lines($&) + "\n" 1377: remaining_code = $~.pre_match 1378: remaining_code << $~.post_match 1379: end 1380: 1381: # 1382: # Parse global constants or variables in modules 1383: # 1384: const_var_defs = definition_info(before_contains_code) 1385: const_var_defs.each{|defitem| 1386: next if defitem.nodoc 1387: const_or_var_type = "Variable" 1388: const_or_var_progress = "v" 1389: if defitem.include_attr?("parameter") 1390: const_or_var_type = "Constant" 1391: const_or_var_progress = "c" 1392: end 1393: const_or_var = AnyMethod.new(const_or_var_type, defitem.varname) 1394: const_or_var.set_priority(defitem.doc_priority) if defitem.doc_priority 1395: const_or_var.singleton = false 1396: const_or_var.params = "" 1397: self_comment = find_arguments([defitem.varname], before_contains_code) 1398: const_or_var.comment = "<b><em>" + const_or_var_type + "</em></b> :: <tt></tt>\n" 1399: const_or_var.comment << self_comment if self_comment 1400: progress const_or_var_progress 1401: @stats.num_methods += 1 1402: container.add_method const_or_var 1403: 1404: set_visibility(container, defitem.varname, visibility_default, @@public_methods) 1405: 1406: if defitem.include_attr?("public") 1407: container.set_visibility_for([defitem.varname], :public) 1408: elsif defitem.include_attr?("private") 1409: container.set_visibility_for([defitem.varname], :private) 1410: end 1411: 1412: check_public_methods(const_or_var, container.name) 1413: 1414: } if const_var_defs 1415: 1416: remaining_lines = remaining_code.split("\n") 1417: 1418: # "subroutine" or "function" parts are parsed (new) 1419: # 1420: level_depth = 0 1421: block_searching_flag = nil 1422: block_searching_lines = [] 1423: pre_comment = [] 1424: procedure_trailing = "" 1425: procedure_name = "" 1426: procedure_params = "" 1427: procedure_prefix = "" 1428: procedure_result_arg = "" 1429: procedure_type = "" 1430: contains_lines = [] 1431: contains_flag = nil 1432: remaining_lines.collect!{|line| 1433: if !block_searching_flag 1434: # subroutine 1435: if line =~ /^\s*? 1436: (recursive|pure|elemental)?\s*? 1437: subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$ 1438: /ix 1439: block_searching_flag = :subroutine 1440: block_searching_lines << line 1441: 1442: procedure_name = $2.chomp.strip 1443: procedure_params = $3 || "" 1444: procedure_prefix = $1 || "" 1445: procedure_trailing = $4 || "!" 1446: next false 1447: 1448: # function 1449: elsif line =~ /^\s*? 1450: (recursive|pure|elemental)?\s*? 1451: ( 1452: character\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1453: | type\s*?\([\w\s]+?\)\s+ 1454: | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1455: | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1456: | double\s+precision\s+ 1457: | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1458: | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1459: )? 1460: function\s+(\w+)\s*? 1461: (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$ 1462: /ix 1463: block_searching_flag = :function 1464: block_searching_lines << line 1465: 1466: procedure_prefix = $1 || "" 1467: procedure_type = $2 ? $2.chomp.strip : nil 1468: procedure_name = $8.chomp.strip 1469: procedure_params = $9 || "" 1470: procedure_result_arg = $11 ? $11.chomp.strip : procedure_name 1471: procedure_trailing = $12 || "!" 1472: next false 1473: elsif line =~ /^\s*?!\s?(.*)/ 1474: pre_comment << line 1475: next line 1476: else 1477: pre_comment = [] 1478: next line 1479: end 1480: end 1481: contains_flag = true if line =~ /^\s*?contains\s*?(!.*?)?$/ 1482: block_searching_lines << line 1483: contains_lines << line if contains_flag 1484: 1485: level_depth += 1 if block_start?(line) 1486: level_depth -= 1 if block_end?(line) 1487: if level_depth >= 0 1488: next false 1489: end 1490: 1491: # "procedure_code" is formatted. 1492: # ":nodoc:" flag is checked. 1493: # 1494: procedure_code = block_searching_lines.join("\n") 1495: procedure_code = remove_empty_head_lines(procedure_code) 1496: if procedure_trailing.sub(/^!/, '') =~ IGNORED_MARKER_REGEXP 1497: # next loop to search next block 1498: level_depth = 0 1499: block_searching_flag = nil 1500: block_searching_lines = [] 1501: pre_comment = [] 1502: procedure_trailing = "" 1503: procedure_name = "" 1504: procedure_params = "" 1505: procedure_prefix = "" 1506: procedure_result_arg = "" 1507: procedure_type = "" 1508: contains_lines = [] 1509: contains_flag = nil 1510: next false 1511: end 1512: 1513: # AnyMethod is created, and added to container 1514: # 1515: subroutine_function = nil 1516: if block_searching_flag == :subroutine 1517: subroutine_prefix = procedure_prefix 1518: subroutine_name = procedure_name 1519: subroutine_params = procedure_params 1520: subroutine_trailing = procedure_trailing 1521: subroutine_code = procedure_code 1522: subroutine_priority, subroutine_trailing = doc_priority_from_trailing(subroutine_trailing) 1523: 1524: subroutine_comment = COMMENTS_ARE_UPPER ? 1525: pre_comment.join("\n") + "\n" + subroutine_trailing : 1526: subroutine_trailing + "\n" + subroutine_code.sub(/^.*$\n/i, '') 1527: subroutine = AnyMethod.new("subroutine", subroutine_name) 1528: parse_subprogram(subroutine, subroutine_params, 1529: subroutine_comment, subroutine_code, 1530: before_contains_code, nil, subroutine_prefix) 1531: subroutine.set_priority(subroutine_priority) if subroutine_priority 1532: progress "s" 1533: @stats.num_methods += 1 1534: container.add_method subroutine 1535: subroutine_function = subroutine 1536: 1537: namelist_comment = 1538: find_namelists(subroutine, subroutine_code, before_contains_code) 1539: subroutine.comment << namelist_comment if namelist_comment 1540: 1541: elsif block_searching_flag == :function 1542: function_prefix = procedure_prefix 1543: function_type = procedure_type 1544: function_name = procedure_name 1545: function_params_org = procedure_params 1546: function_result_arg = procedure_result_arg 1547: function_trailing = procedure_trailing 1548: function_code_org = procedure_code 1549: function_priority, function_trailing = doc_priority_from_trailing(function_trailing) 1550: 1551: function_comment = COMMENTS_ARE_UPPER ? 1552: pre_comment.join("\n") + "\n" + function_trailing : 1553: function_trailing + "\n " + function_code_org.sub(/^.*$\n/i, '') 1554: 1555: function_code = "#{function_code_org}" 1556: if function_type 1557: function_code << "\n" + function_type + " :: " + function_result_arg 1558: end 1559: 1560: function_params = 1561: function_params_org.sub(/^\(/, "\(#{function_result_arg}, ") 1562: 1563: function = AnyMethod.new("function", function_name) 1564: parse_subprogram(function, function_params, 1565: function_comment, function_code, 1566: before_contains_code, true, function_prefix) 1567: function.set_priority(function_priority) if function_priority 1568: 1569: # Specific modification due to function 1570: function.params.sub!(/\(\s*?#{function_result_arg}\s*?,\s*?/, "\( ") 1571: function.params << " result(" + function_result_arg + ")" 1572: function.start_collecting_tokens 1573: function.add_token Token.new(1,1).set_text(function_code_org) 1574: 1575: progress "f" 1576: @stats.num_methods += 1 1577: container.add_method function 1578: subroutine_function = function 1579: 1580: namelist_comment = 1581: find_namelists(function, function_code, before_contains_code) 1582: function.comment << namelist_comment if namelist_comment 1583: 1584: end 1585: 1586: # The visibility of procedure is specified 1587: # 1588: set_visibility(container, procedure_name, 1589: visibility_default, @@public_methods) 1590: 1591: # The alias for this procedure from external modules 1592: # 1593: check_external_aliases(procedure_name, 1594: subroutine_function.params, 1595: subroutine_function.comment, subroutine_function) if external 1596: check_public_methods(subroutine_function, container.name) 1597: 1598: 1599: # contains_lines are parsed as private procedures 1600: if contains_flag 1601: parse_program_or_module(container, 1602: contains_lines.join("\n"), :private) 1603: end 1604: 1605: # next loop to search next block 1606: level_depth = 0 1607: block_searching_flag = nil 1608: block_searching_lines = [] 1609: pre_comment = [] 1610: procedure_trailing = "" 1611: procedure_name = "" 1612: procedure_params = "" 1613: procedure_prefix = "" 1614: procedure_result_arg = "" 1615: contains_lines = [] 1616: contains_flag = nil 1617: next false 1618: } # End of remaining_lines.collect!{|line| 1619: 1620: # Array remains_lines is converted to String remains_code again 1621: # 1622: remaining_code = remaining_lines.join("\n") 1623: 1624: # 1625: # Parse interface 1626: # 1627: interface_scope = false 1628: generic_name = "" 1629: interface_code.split("\n").each{ |line| 1630: if /^\s*? 1631: interface( 1632: \s+\w+| 1633: \s+operator\s*?\(.*?\)| 1634: \s+assignment\s*?\(\s*?=\s*?\) 1635: )? 1636: \s*?(!.*?)?$ 1637: /ix =~ line 1638: generic_name = $1 ? $1.strip.chomp : nil 1639: interface_trailing = $2 || "!" 1640: interface_scope = true 1641: interface_scope = false if interface_trailing.sub(/^!/, '') =~ IGNORED_MARKER_REGEXP 1642: # if generic_name =~ /operator\s*?\((.*?)\)/i 1643: # operator_name = $1 1644: # if operator_name && !operator_name.empty? 1645: # generic_name = "#{operator_name}" 1646: # end 1647: # end 1648: # if generic_name =~ /assignment\s*?\((.*?)\)/i 1649: # assignment_name = $1 1650: # if assignment_name && !assignment_name.empty? 1651: # generic_name = "#{assignment_name}" 1652: # end 1653: # end 1654: end 1655: if /^\s*?end\s+interface/i =~ line 1656: interface_scope = false 1657: generic_name = nil 1658: end 1659: # internal alias 1660: if interface_scope && /^\s*?module\s+procedure\s+(.*?)(!.*?)?$/i =~ line 1661: procedures = $1.strip.chomp 1662: procedures_trailing = $2 || "!" 1663: next if procedures_trailing.sub(/^!/, '') =~ IGNORED_MARKER_REGEXP 1664: procedures_priority, procedures_trailing = doc_priority_from_trailing(procedures_trailing) 1665: 1666: procedures.split(",").each{ |proc| 1667: proc.strip! 1668: proc.chomp! 1669: next if generic_name == proc || !generic_name 1670: old_meth = container.find_symbol(proc, nil, @options_ignore_case) 1671: next if !old_meth 1672: nolink = old_meth.visibility == :private ? true : nil 1673: nolink = nil if @options.show_all 1674: new_meth = 1675: initialize_external_method(generic_name, proc, 1676: old_meth.params, nil, 1677: old_meth.comment, 1678: old_meth.clone.token_stream[0].text, 1679: true, nolink) 1680: new_meth.singleton = old_meth.singleton 1681: new_meth.set_priority(procedures_priority) if procedures_priority 1682: 1683: progress "i" 1684: @stats.num_methods += 1 1685: container.add_method new_meth 1686: 1687: set_visibility(container, generic_name, visibility_default, @@public_methods) 1688: 1689: check_public_methods(new_meth, container.name) 1690: 1691: } 1692: end 1693: 1694: # external aliases 1695: if interface_scope 1696: # subroutine 1697: proc = nil 1698: params = nil 1699: procedures_trailing = nil 1700: if line =~ /^\s*? 1701: (recursive|pure|elemental)?\s*? 1702: subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$ 1703: /ix 1704: proc = $2.chomp.strip 1705: proc_name = generic_name || proc 1706: params = $3 || "" 1707: procedures_trailing = $4 || "!" 1708: 1709: # function 1710: elsif line =~ /^\s*? 1711: (recursive|pure|elemental)?\s*? 1712: ( 1713: character\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1714: | type\s*?\([\w\s]+?\)\s+ 1715: | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1716: | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1717: | double\s+precision\s+ 1718: | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1719: | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1720: )? 1721: function\s+(\w+)\s*? 1722: (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$ 1723: /ix 1724: proc = $8.chomp.strip 1725: proc_name = generic_name || proc 1726: params = $9 || "" 1727: procedures_trailing = $12 || "!" 1728: else 1729: next 1730: end 1731: next if procedures_trailing.sub(/^!/, '') =~ IGNORED_MARKER_REGEXP 1732: procedures_priority, procedures_trailing = doc_priority_from_trailing(procedures_trailing) 1733: indicated_method = nil 1734: indicated_file = nil 1735: TopLevel.all_files.each do |name, toplevel| 1736: indicated_method = toplevel.find_local_symbol(proc, @options_ignore_case) 1737: indicated_file = name 1738: break if indicated_method 1739: end 1740: 1741: if indicated_method 1742: external_method = 1743: initialize_external_method(proc_name, proc, 1744: indicated_method.params, 1745: indicated_file, 1746: indicated_method.comment) 1747: external_method.set_priority(procedures_priority) if procedures_priority 1748: 1749: progress "e" 1750: @stats.num_methods += 1 1751: container.add_method external_method 1752: set_visibility(container, proc_name, visibility_default, @@public_methods) 1753: if !container.include_requires?(indicated_file, @options_ignore_case) 1754: container.add_require(Require.new(indicated_file, "")) 1755: end 1756: check_public_methods(external_method, container.name) 1757: 1758: else 1759: @@external_aliases << { 1760: "new_name" => proc_name, 1761: "old_name" => proc, 1762: "file_or_module" => container, 1763: "visibility" => find_visibility(container, proc_name, @@public_methods) || visibility_default, 1764: "doc_priority" => procedures_priority 1765: } 1766: end 1767: end 1768: 1769: } if interface_code # End of interface_code.split("\n").each ... 1770: 1771: # 1772: # Already imported methods are removed from @@public_methods. 1773: # Remainders are assumed to be imported from other modules. 1774: # 1775: # 既に参照済みのメソッドは @@public_methods から取り除く. 1776: # 残りは外部モジュールからの参照と仮定する. 1777: # 1778: @@public_methods.delete_if{ |method| method["entity_is_discovered"]} 1779: 1780: @@public_methods.each{ |pub_meth| 1781: next unless pub_meth["file_or_module"].name == container.name 1782: pub_meth["used_modules"].each{ |used_mod| 1783: TopLevel.all_classes_and_modules.each{ |modules| 1784: if modules.name == used_mod || 1785: modules.name.upcase == used_mod.upcase && 1786: @options_ignore_case 1787: modules.method_list.each{ |meth| 1788: if meth.name == pub_meth["name"] || 1789: meth.name.upcase == pub_meth["name"].upcase && 1790: @options_ignore_case 1791: new_meth = initialize_public_method(meth, 1792: modules.name) 1793: if pub_meth["local_name"] 1794: new_meth.name = pub_meth["local_name"] 1795: end 1796: progress "e" 1797: @stats.num_methods += 1 1798: container.add_method new_meth 1799: end 1800: } 1801: end 1802: } 1803: } 1804: } 1805: 1806: container 1807: end
Parse arguments, comment, code of subroutine and function. Return AnyMethod object.
# File parsers/parse_f95.rb, line 1813 1813: def parse_subprogram(subprogram, params, comment, code, 1814: before_contains=nil, function=nil, prefix=nil) 1815: subprogram.singleton = false 1816: prefix = "" if !prefix 1817: arguments = params.sub(/\(/, "").sub(/\)/, "").split(",") if params 1818: args_comment, params_opt = 1819: find_arguments(arguments, code.sub(/^s*?contains\s*?(!.*?)?$.*/im, ""), 1820: nil, nil, true) 1821: params_opt = "( " + params_opt + " ) " if params_opt 1822: subprogram.params = params_opt || "" 1823: 1824: block_comment = find_comments comment 1825: if function 1826: subprogram.comment = "<b><em> Function </em></b> :: <em>#{prefix}</em>\n" 1827: else 1828: subprogram.comment = "<b><em> Subroutine </em></b> :: <em>#{prefix}</em>\n" 1829: end 1830: subprogram.comment << args_comment if args_comment 1831: subprogram.comment << block_comment if block_comment 1832: 1833: # For output source code 1834: subprogram.start_collecting_tokens 1835: subprogram.add_token Token.new(1,1).set_text(code) 1836: 1837: subprogram 1838: end
Parse visibility
# File parsers/parse_f95.rb, line 2143 2143: def parse_visibility(code, default, container) 2144: result = [] 2145: visibility_default = default || :public 2146: 2147: used_modules = [] 2148: container.includes.each{|i| used_modules << i.name} if container 2149: 2150: remaining_code = code.gsub(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "") 2151: remaining_code.split("\n").each{ |line| 2152: if /^\s*?private\s*?$/ =~ line 2153: visibility_default = :private 2154: break 2155: end 2156: } if remaining_code 2157: 2158: remaining_code.split("\n").each{ |line| 2159: if /^\s*?private\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line 2160: methods = $2.sub(/!.*$/, '') 2161: methods.split(",").each{ |meth| 2162: meth.sub!(/!.*$/, '') 2163: meth.gsub!(/:/, '') 2164: result << { 2165: "name" => meth.chomp.strip, 2166: "visibility" => :private, 2167: "used_modules" => used_modules.clone, 2168: "file_or_module" => container, 2169: "entity_is_discovered" => nil, 2170: "local_name" => nil 2171: } 2172: } 2173: elsif /^\s*?public\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line 2174: methods = $2.sub(/!.*$/, '') 2175: methods.split(",").each{ |meth| 2176: meth.sub!(/!.*$/, '') 2177: meth.gsub!(/:/, '') 2178: result << { 2179: "name" => meth.chomp.strip, 2180: "visibility" => :public, 2181: "used_modules" => used_modules.clone, 2182: "file_or_module" => container, 2183: "entity_is_discovered" => nil, 2184: "local_name" => nil 2185: } 2186: } 2187: end 2188: } if remaining_code 2189: 2190: if container 2191: result.each{ |vis_info| 2192: vis_info["parent"] = container.name 2193: } 2194: end 2195: 2196: return visibility_default, result 2197: end
# File parsers/parse_f95.rb, line 2083 2083: def progress(char) 2084: unless @options.quiet 2085: @progress.print(char) 2086: @progress.flush 2087: end 2088: end
Empty lines in header are removed
# File parsers/parse_f95.rb, line 2567 2567: def remove_empty_head_lines(text) 2568: return "" unless text 2569: lines = text.split("\n") 2570: header = true 2571: lines.delete_if{ |line| 2572: header = false if /\S/ =~ line 2573: header && /^\s*?$/ =~ line 2574: } 2575: lines.join("\n") 2576: end
header marker "=", "==", … are removed
# File parsers/parse_f95.rb, line 2580 2580: def remove_header_marker(text) 2581: return text.gsub(/^\s?(=+)/, '<tt></tt>\1') 2582: end
# File parsers/parse_f95.rb, line 2584 2584: def remove_private_comments(body) 2585: body.gsub!(/^(\s*)!--\s*?$.*?^\s*!\+\+\s*?$/m, '\\1!') 2586: return body 2587: end
Remove "Alias for" in end of comments
# File parsers/parse_f95.rb, line 2546 2546: def remove_trailing_alias(text) 2547: return "" if !text 2548: lines = text.split("\n").reverse 2549: comment_block = Array.new 2550: checked = false 2551: lines.each do |line| 2552: if !checked 2553: if /^\s?#{INTERNAL_ALIAS_MES}/ =~ line || 2554: /^\s?#{EXTERNAL_ALIAS_MES}/ =~ line 2555: checked = true 2556: next 2557: end 2558: end 2559: comment_block.unshift line 2560: end 2561: nice_lines = comment_block.join("\n") 2562: nice_lines ||= "" 2563: return nice_lines 2564: end
devine code constructs
# File parsers/parse_f95.rb, line 929 929: def scan 930: 931: # remove private comment 932: remaining_code = remove_private_comments(@body) 933: 934: # continuation lines are united to one line 935: remaining_code = united_to_one_line(remaining_code) 936: 937: # semicolons are replaced to line feed 938: remaining_code = semicolon_to_linefeed(remaining_code) 939: 940: # collect comment for file entity 941: whole_comment, remaining_code = collect_first_comment(remaining_code) 942: @top_level.comment = whole_comment 943: 944: # String "remaining_code" is converted to Array "remaining_lines" 945: remaining_lines = remaining_code.split("\n") 946: 947: # "module" or "program" parts are parsed (new) 948: # 949: level_depth = 0 950: block_searching_flag = nil 951: block_searching_lines = [] 952: pre_comment = [] 953: module_program_trailing = "" 954: module_program_name = "" 955: other_block_level_depth = 0 956: other_block_searching_flag = nil 957: remaining_lines.collect!{|line| 958: if !block_searching_flag && !other_block_searching_flag 959: if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i 960: block_searching_flag = :module 961: block_searching_lines << line 962: module_program_name = $1 963: module_program_trailing = find_comments($2) 964: next false 965: elsif line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i || 966: line =~ /^\s*?\w/ && !block_start?(line) 967: block_searching_flag = :program 968: block_searching_lines << line 969: module_program_name = $1 || "" 970: module_program_trailing = find_comments($2) 971: next false 972: 973: elsif block_start?(line) 974: other_block_searching_flag = true 975: next line 976: 977: elsif line =~ /^\s*?!\s?(.*)/ 978: pre_comment << line 979: next line 980: else 981: pre_comment = [] 982: next line 983: end 984: elsif other_block_searching_flag 985: other_block_level_depth += 1 if block_start?(line) 986: other_block_level_depth -= 1 if block_end?(line) 987: if other_block_level_depth < 0 988: other_block_level_depth = 0 989: other_block_searching_flag = nil 990: end 991: next line 992: end 993: 994: block_searching_lines << line 995: level_depth += 1 if block_start?(line) 996: level_depth -= 1 if block_end?(line) 997: if level_depth >= 0 998: next false 999: end 1000: 1001: # "module_program_code" is formatted. 1002: # ":nodoc:" flag is checked. 1003: # 1004: module_program_code = block_searching_lines.join("\n") 1005: module_program_code = remove_empty_head_lines(module_program_code) 1006: if module_program_trailing =~ IGNORED_MARKER_REGEXP 1007: # next loop to search next block 1008: level_depth = 0 1009: block_searching_flag = false 1010: block_searching_lines = [] 1011: pre_comment = [] 1012: next false 1013: end 1014: 1015: # NormalClass is created, and added to @top_level 1016: # 1017: if block_searching_flag == :module 1018: module_name = module_program_name 1019: module_code = module_program_code 1020: module_trailing = module_program_trailing 1021: progress "m" 1022: @stats.num_modules += 1 1023: f9x_module = @top_level.add_module NormalClass, module_name 1024: f9x_module.record_location @top_level 1025: 1026: # 1027: # Add provided modules information to @top_level comment 1028: # 1029: provided_modules = [] 1030: provided_mes_line_num = nil 1031: top_level_comment_lines = [] 1032: line_num = 0 1033: @top_level.comment.split("\n").each{|line| 1034: top_level_comment_lines << line 1035: line_num += 1 1036: next if line.empty? 1037: if !provided_mes_line_num && /^\s?#{PROVIDED_MODULES_MES}/ =~ line 1038: provided_mes_line_num = line_num 1039: next 1040: end 1041: if provided_mes_line_num 1042: if /^\s?\*\s+<b>(\w+)<\/b>/ =~ line 1043: provided_modules << $1 1044: else 1045: provided_mes_line_num = nil 1046: end 1047: end 1048: } 1049: line_num = 0 1050: if provided_mes_line_num 1051: top_level_comment_lines.collect!{ |line| 1052: line_num += 1 1053: if line_num < provided_mes_line_num 1054: line 1055: else 1056: nil 1057: end 1058: } 1059: top_level_comment_lines.delete_if{|line| !line } 1060: end 1061: top_level_comment_lines << "\n" + PROVIDED_MODULES_MES + "." 1062: if provided_mes_line_num 1063: top_level_comment_lines[-1].sub!(/\.$/, '') 1064: top_level_comment_lines[-1] << "s." 1065: end 1066: provided_modules.each{ |mod| 1067: top_level_comment_lines << "* <b>" + mod + "</b>" 1068: } 1069: top_level_comment_lines << "* <b>" + module_name + "</b>" 1070: @top_level.comment = top_level_comment_lines.join("\n") 1071: 1072: # 1073: # Information about the module is parsed 1074: # 1075: f9x_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) + 1076: "\n" + module_trailing : module_trailing + "\n" + 1077: find_comments(module_code.sub(/^.*$\n/i, '')) 1078: f9x_module.comment = f9x_comment 1079: parse_program_or_module(f9x_module, module_code) 1080: 1081: TopLevel.all_files.each do |name, toplevel| 1082: if toplevel.include_includes?(module_name, @options_ignore_case) 1083: if !toplevel.include_requires?(@file_name, @options_ignore_case) 1084: toplevel.add_require(Require.new(@file_name, "")) 1085: end 1086: end 1087: toplevel.each_classmodule{|m| 1088: if m.include_includes?(module_name, @options_ignore_case) 1089: if !m.include_requires?(@file_name, @options_ignore_case) 1090: m.add_require(Require.new(@file_name, "")) 1091: end 1092: end 1093: } 1094: end 1095: 1096: namelist_comment = 1097: find_namelists(f9x_module, before_contains(module_code)) 1098: f9x_module.comment << namelist_comment if namelist_comment 1099: 1100: elsif block_searching_flag == :program 1101: program_name = module_program_name 1102: program_name = "main_program" if program_name.empty? 1103: program_code = module_program_code 1104: program_trailing = module_program_trailing 1105: program_priority, program_trailing = doc_priority_from_trailing(program_trailing) 1106: 1107: program_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) + 1108: "\n" + program_trailing : program_trailing + "\n" + 1109: find_comments(program_code.sub(/^.*$\n/i, '')) 1110: 1111: progress "p" 1112: @stats.num_methods += 1 1113: f9x_mainprogram = AnyMethod.new("main_program", program_name) 1114: f9x_mainprogram.singleton = false 1115: f9x_mainprogram.comment = "<b><em> Main Program </em></b> :: <tt></tt>\n" 1116: f9x_mainprogram.comment << program_comment 1117: f9x_mainprogram.params = "" 1118: f9x_mainprogram.set_priority(program_priority) if program_priority 1119: 1120: # For output source code 1121: f9x_mainprogram.start_collecting_tokens 1122: f9x_mainprogram.add_token Token.new(1,1).set_text(program_code) 1123: 1124: @top_level.add_method f9x_mainprogram 1125: parse_program_or_module(@top_level, program_code, :private) 1126: 1127: namelist_comment = find_namelists(f9x_mainprogram, program_code) 1128: f9x_mainprogram.comment << namelist_comment if namelist_comment 1129: end 1130: 1131: # next loop to search next block 1132: level_depth = 0 1133: block_searching_flag = false 1134: block_searching_lines = [] 1135: pre_comment = [] 1136: next false 1137: } 1138: 1139: remaining_lines.delete_if{ |line| 1140: line == false 1141: } 1142: 1143: # External subprograms and functions are parsed 1144: # 1145: # 単一のファイル内において program や module に格納されない, 1146: # 外部サブルーチン, 外部関数部分の解析. 1147: # 1148: parse_program_or_module(@top_level, remaining_lines.join("\n"), 1149: :public, true) 1150: 1151: @top_level 1152: end
Semicolons are replaced to line feed.
# File parsers/parse_f95.rb, line 2449 2449: def semicolon_to_linefeed(text) 2450: return "" unless text 2451: lines = text.split("\n") 2452: lines.collect!{ |line| 2453: indent_space = "" 2454: if line =~ /^(\s+)/ 2455: indent_space = $1 2456: end 2457: words = line.split("") 2458: commentout = false 2459: squote = false ; dquote = false 2460: words.collect! { |char| 2461: if !(squote) && !(dquote) && !(commentout) 2462: case char 2463: when "!" ; commentout = true ; next char 2464: when "\""; dquote = true ; next char 2465: when "\'"; squote = true ; next char 2466: when ";" ; "\n"+indent_space 2467: else next char 2468: end 2469: elsif commentout 2470: next char 2471: elsif squote 2472: case char 2473: when "\'"; squote = false ; next char 2474: else next char 2475: end 2476: elsif dquote 2477: case char 2478: when "\""; dquote = false ; next char 2479: else next char 2480: end 2481: end 2482: } 2483: words.join("") 2484: } 2485: return lines.join("\n") 2486: end
Set visibility
"subname" element of "visibility_info" is deleted.
# File parsers/parse_f95.rb, line 2204 2204: def set_visibility(container, subname, visibility_default, visibility_info) 2205: return unless container || subname || visibility_default || visibility_info 2206: not_found = true 2207: visibility_info.collect!{ |info| 2208: if info["name"] == subname || 2209: @options_ignore_case && info["name"].upcase == subname.upcase 2210: if info["file_or_module"].name == container.name 2211: container.set_visibility_for([subname], info["visibility"]) 2212: info["entity_is_discovered"] = true 2213: not_found = false 2214: end 2215: end 2216: info 2217: } 2218: if not_found 2219: return container.set_visibility_for([subname], visibility_default) 2220: else 2221: return container 2222: end 2223: 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 2324 2324: def united_to_one_line(f90src, delete_space=true) 2325: return "" unless f90src 2326: lines = f90src.split("\n") 2327: previous_continuing = false 2328: now_continuing = false 2329: body = "" 2330: squote = false ; dquote = false 2331: lines.each{ |line| 2332: words = line.split("") 2333: next if words.empty? && previous_continuing 2334: commentout = false 2335: brank_flag = true ; brank_char = "" 2336: ignore = false 2337: words.collect! { |char| 2338: if previous_continuing && brank_flag 2339: now_continuing = true 2340: ignore = true 2341: case char 2342: when "!" ; break 2343: when " " ; brank_char << char ; next "" 2344: when "&" 2345: brank_flag = false 2346: now_continuing = false 2347: next "" 2348: else 2349: brank_flag = false 2350: now_continuing = false 2351: ignore = false 2352: next brank_char + char 2353: end 2354: end 2355: ignore = false 2356: 2357: if now_continuing && !(squote) && !(dquote) 2358: next "" 2359: elsif !(squote) && !(dquote) && !(commentout) 2360: case char 2361: when "!" ; commentout = true ; next char 2362: when "\""; dquote = true ; next char 2363: when "\'"; squote = true ; next char 2364: when "&" ; now_continuing = true ; next "" 2365: else next char 2366: end 2367: elsif commentout 2368: next char 2369: elsif squote 2370: case char 2371: when "\'"; squote = false ; now_continuing = false ; next char 2372: when "&" ; now_continuing = true ; next "" 2373: else next char 2374: end 2375: elsif dquote 2376: case char 2377: when "\""; dquote = false ; now_continuing = false ; next char 2378: when "&" ; now_continuing = true ; next "" 2379: else next char 2380: end 2381: end 2382: } 2383: if !ignore && !previous_continuing || !brank_flag 2384: if previous_continuing 2385: if delete_space 2386: joined_words = words.join("") 2387: body = body.rstrip + " " + joined_words.lstrip 2388: else 2389: body << words.join("") 2390: end 2391: else 2392: body << "\n" + words.join("") 2393: end 2394: end 2395: previous_continuing = now_continuing ? true : false 2396: now_continuing = false 2397: } 2398: return body 2399: end