Class | RDoc::Fortran95parser |
In: |
parsers/parse_f95.rb
|
Parent: | Object |
See rdoc/parsers/parse_f95.rb
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 1865 1865: def before_contains(code) 1866: level_depth = 0 1867: before_contains_lines = [] 1868: before_contains_code = nil 1869: before_contains_flag = nil 1870: code.split("\n").each{ |line| 1871: if !before_contains_flag 1872: if line =~ /^\s*?module\s+\w+\s*?(!.*?)?$/i 1873: before_contains_flag = true 1874: end 1875: else 1876: break if line =~ /^\s*?contains\s*?(!.*?)?$/i 1877: level_depth += 1 if block_start?(line) 1878: level_depth -= 1 if block_end?(line) 1879: break if level_depth < 0 1880: before_contains_lines << line 1881: end 1882: 1883: } 1884: before_contains_code = before_contains_lines.join("\n") 1885: if before_contains_code 1886: before_contains_code.gsub!(/^\s*?interface\s+.*?\s+end\s+interface.*?$/im, "") 1887: before_contains_code.gsub!(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "") 1888: end 1889: 1890: before_contains_code 1891: end
Which "line" is end of block (module, program, block data, subroutine, function) statement ?
# File parsers/parse_f95.rb, line 2533 2533: def block_end?(line) 2534: return nil if !line 2535: 2536: if line =~ /^\s*?end\s*?(!.*?)?$/i || 2537: line =~ /^\s*?end\s+module(\s+\w+)?\s*?(!.*?)?$/i || 2538: line =~ /^\s*?end\s+program(\s+\w+)?\s*?(!.*?)?$/i || 2539: line =~ /^\s*?end\s+block\s+data(\s+\w+)?\s*?(!.*?)?$/i || 2540: line =~ /^\s*?end\s+subroutine(\s+\w+)?\s*?(!.*?)?$/i || 2541: line =~ /^\s*?end\s+function(\s+\w+)?\s*?(!.*?)?$/i 2542: return true 2543: end 2544: 2545: return nil 2546: end
Which "line" is start of block (module, program, block data, subroutine, function) statement ?
# File parsers/parse_f95.rb, line 2497 2497: def block_start?(line) 2498: return nil if !line 2499: 2500: if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i || 2501: line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i || 2502: line =~ /^\s*?block\s+data(\s+\w+)?\s*?(!.*?)?$/i || 2503: line =~ \ 2504: /^\s*? 2505: (recursive|pure|elemental)?\s*? 2506: subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$ 2507: /ix || 2508: line =~ \ 2509: /^\s*? 2510: (recursive|pure|elemental)?\s*? 2511: ( 2512: character\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 2513: | type\s*?\([\w\s]+?\)\s+ 2514: | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 2515: | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 2516: | double\s+precision\s+ 2517: | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 2518: | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 2519: )? 2520: function\s+(\w+)\s*? 2521: (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$ 2522: /ix 2523: return true 2524: end 2525: 2526: return nil 2527: end
Check external aliases
subname というサブルーチン名, または関数名を持つファイルを 探査し, 存在する場合にはそのファイル内へメソッドを追加する.
# File parsers/parse_f95.rb, line 2252 2252: def check_external_aliases(subname, params, comment, test=nil) 2253: @@external_aliases.each{ |alias_item| 2254: if subname == alias_item["old_name"] || 2255: subname.upcase == alias_item["old_name"].upcase && 2256: @options_ignore_case 2257: 2258: new_meth = initialize_external_method(alias_item["new_name"], 2259: subname, params, @file_name, 2260: comment) 2261: new_meth.visibility = alias_item["visibility"] 2262: new_meth.set_priority(alias_item["doc_priority"]) if alias_item["doc_priority"] 2263: 2264: progress "e" 2265: @stats.num_methods += 1 2266: alias_item["file_or_module"].add_method(new_meth) 2267: 2268: if !alias_item["file_or_module"].include_requires?(@file_name, @options_ignore_case) 2269: alias_item["file_or_module"].add_require(Require.new(@file_name, "")) 2270: end 2271: end 2272: } 2273: end
Check public_methods
use したモジュールからそのまま引き継いで public として 公開する場合のチェックを行う. subname というサブルーチン名, または関数名を持つファイルを 探査し, 存在する場合にはそのファイル内へメソッドを追加する.
# File parsers/parse_f95.rb, line 2283 2283: def check_public_methods(method, parent) 2284: return if !method || !parent 2285: @@public_methods.each{ |alias_item| 2286: parent_is_used_module = nil 2287: alias_item["used_modules"].each{ |used_module| 2288: if used_module == parent || 2289: used_module.upcase == parent.upcase && 2290: @options_ignore_case 2291: parent_is_used_module = true 2292: end 2293: } 2294: next if !parent_is_used_module 2295: 2296: if method.name == alias_item["name"] || 2297: method.name.upcase == alias_item["name"].upcase && 2298: @options_ignore_case 2299: 2300: new_meth = initialize_public_method(method, parent) 2301: if alias_item["local_name"] 2302: new_meth.name = alias_item["local_name"] 2303: end 2304: 2305: progress "e" 2306: @stats.num_methods += 1 2307: alias_item["file_or_module"].add_method new_meth 2308: end 2309: } 2310: end
Collect comment for file entity
# File parsers/parse_f95.rb, line 1896 1896: def collect_first_comment(body) 1897: comment = "" 1898: not_comment = "" 1899: comment_start = false 1900: comment_end = false 1901: body.split("\n").each{ |line| 1902: if comment_end 1903: not_comment << line 1904: not_comment << "\n" 1905: elsif /^\s*?!\s?(.*)$/i =~ line 1906: comment_start = true 1907: comment << $1 1908: comment << "\n" 1909: elsif /^\s*?$/i =~ line 1910: comment_end = true if comment_start && COMMENTS_ARE_UPPER 1911: else 1912: comment_end = true 1913: not_comment << line 1914: not_comment << "\n" 1915: end 1916: } 1917: return comment, not_comment 1918: end
Comment out checker
# File parsers/parse_f95.rb, line 2424 2424: def comment_out?(line) 2425: return nil unless line 2426: commentout = false 2427: squote = false ; dquote = false 2428: line.split("").each { |char| 2429: if !(squote) && !(dquote) 2430: case char 2431: when "!" ; commentout = true ; break 2432: when "\""; dquote = true 2433: when "\'"; squote = true 2434: else next 2435: end 2436: elsif squote 2437: case char 2438: when "\'"; squote = false 2439: else next 2440: end 2441: elsif dquote 2442: case char 2443: when "\""; dquote = false 2444: else next 2445: end 2446: end 2447: } 2448: return commentout 2449: end
Continuous line checker
# File parsers/parse_f95.rb, line 2410 2410: def continuous_line?(line) 2411: continuous = false 2412: if /&\s*?(!.*)?$/ =~ line 2413: continuous = true 2414: if comment_out?($~.pre_match) 2415: continuous = false 2416: end 2417: end 2418: return continuous 2419: end
Parse string argument "text", and Return Array of Fortran95Definition object
# File parsers/parse_f95.rb, line 2675 2675: def definition_info(text) 2676: return nil unless text 2677: lines = "#{text}" 2678: defs = Array.new 2679: comment = "" 2680: trailing_comment = "" 2681: under_comment_valid = false 2682: lines.split("\n").each{ |line| 2683: if /^\s*?!\s?(.*)/ =~ line 2684: if COMMENTS_ARE_UPPER 2685: comment << remove_header_marker($1) 2686: comment << "\n" 2687: elsif defs[-1] && under_comment_valid 2688: defs[-1].comment << "\n" 2689: defs[-1].comment << remove_header_marker($1) 2690: end 2691: next 2692: elsif /^\s*?$/ =~ line 2693: comment = "" 2694: under_comment_valid = false 2695: next 2696: end 2697: type = "" 2698: characters = "" 2699: if line =~ /^\s*? 2700: ( 2701: character\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* 2702: | type\s*?\([\w\s]+?\)[\s\,]* 2703: | integer\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* 2704: | real\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* 2705: | double\s+precision[\s\,]* 2706: | logical\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* 2707: | complex\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]* 2708: ) 2709: (.*?::)? 2710: (.+)$ 2711: /ix 2712: characters = $8 2713: type = $1 2714: type << $7.gsub(/::/, '').gsub(/^\s*?\,/, '') if $7 2715: else 2716: under_comment_valid = false 2717: next 2718: end 2719: squote = false ; dquote = false ; bracket = 0 2720: iniflag = false; commentflag = false 2721: varname = "" ; arraysuffix = "" ; inivalue = "" 2722: start_pos = defs.size 2723: characters.split("").each { |char| 2724: if !(squote) && !(dquote) && bracket <= 0 && !(iniflag) && !(commentflag) 2725: case char 2726: when "!" ; commentflag = true 2727: when "(" ; bracket += 1 ; arraysuffix = char 2728: when "\""; dquote = true 2729: when "\'"; squote = true 2730: when "=" ; iniflag = true ; inivalue << char 2731: when "," 2732: defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment) 2733: varname = "" ; arraysuffix = "" ; inivalue = "" 2734: under_comment_valid = true 2735: when " " ; next 2736: else ; varname << char 2737: end 2738: elsif commentflag 2739: comment << remove_header_marker(char) 2740: trailing_comment << remove_header_marker(char) 2741: elsif iniflag 2742: if dquote 2743: case char 2744: when "\"" ; dquote = false ; inivalue << char 2745: else ; inivalue << char 2746: end 2747: elsif squote 2748: case char 2749: when "\'" ; squote = false ; inivalue << char 2750: else ; inivalue << char 2751: end 2752: elsif bracket > 0 2753: case char 2754: when "(" ; bracket += 1 ; inivalue << char 2755: when ")" ; bracket -= 1 ; inivalue << char 2756: else ; inivalue << char 2757: end 2758: else 2759: case char 2760: when "," 2761: defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment) 2762: varname = "" ; arraysuffix = "" ; inivalue = "" 2763: iniflag = false 2764: under_comment_valid = true 2765: when "(" ; bracket += 1 ; inivalue << char 2766: when "\""; dquote = true ; inivalue << char 2767: when "\'"; squote = true ; inivalue << char 2768: when "!" ; commentflag = true 2769: else ; inivalue << char 2770: end 2771: end 2772: elsif !(squote) && !(dquote) && bracket > 0 2773: case char 2774: when "(" ; bracket += 1 ; arraysuffix << char 2775: when ")" ; bracket -= 1 ; arraysuffix << char 2776: else ; arraysuffix << char 2777: end 2778: elsif squote 2779: case char 2780: when "\'"; squote = false ; inivalue << char 2781: else ; inivalue << char 2782: end 2783: elsif dquote 2784: case char 2785: when "\""; dquote = false ; inivalue << char 2786: else ; inivalue << char 2787: end 2788: end 2789: } 2790: defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment) 2791: if trailing_comment =~ IGNORED_MARKER_REGEXP 2792: defs[start_pos..-1].collect!{ |defitem| 2793: defitem.nodoc = true 2794: } 2795: end 2796: if trailing_comment =~ DOC_PRIORITY_REGEXP 2797: doc_priority = $1.to_i 2798: defs[start_pos..-1].collect!{ |defitem| 2799: defitem.doc_priority = doc_priority 2800: defitem.comment.sub!(DOC_PRIORITY_REGEXP, '') 2801: } 2802: end 2803: varname = "" ; arraysuffix = "" ; inivalue = "" 2804: comment = "" 2805: under_comment_valid = true 2806: trailing_comment = "" 2807: } 2808: return defs 2809: end
# File parsers/parse_f95.rb, line 1845 1845: def doc_priority_from_trailing(trailing) 1846: prefix = '' 1847: if trailing =~ /^(\s*!)(.*)$/ 1848: prefix = $1 1849: trailing = $2 1850: end 1851: if trailing =~ DOC_PRIORITY_REGEXP 1852: priority = $1.to_i 1853: trailing.sub!(DOC_PRIORITY_REGEXP, '') 1854: else 1855: priority = false 1856: end 1857: trailing = prefix + trailing 1858: return priority, trailing 1859: 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 1927 1927: def find_arguments(args, text, all=nil, indent=nil, modified_params=nil) 1928: return unless args || all 1929: indent = "" unless indent 1930: args = ["all"] if all 1931: params = "" if modified_params 1932: comma = "" 1933: return unless text 1934: args_rdocforms = "\n" 1935: remaining_lines = "#{text}" 1936: definitions = definition_info(remaining_lines) 1937: args.each{ |arg| 1938: arg.strip! 1939: arg.chomp! 1940: definitions.each { |defitem| 1941: if arg == defitem.varname.strip.chomp || all 1942: 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" 1943: if !defitem.comment.chomp.strip.empty? 1944: comment = "" 1945: defitem.comment.split("\n").each{ |line| 1946: comment << " " + line + "\n" 1947: } 1948: args_rdocforms << "\n\#{indent} <tt></tt> ::\n\#{indent} <tt></tt>\n\#{indent} \#{comment.chomp.strip}\n" 1949: end 1950: 1951: if modified_params 1952: if defitem.include_attr?("optional") 1953: params << "#{comma}[#{arg}]" 1954: else 1955: params << "#{comma}#{arg}" 1956: end 1957: comma = ", " 1958: end 1959: end 1960: } 1961: } 1962: if modified_params 1963: return args_rdocforms, params 1964: else 1965: return args_rdocforms 1966: end 1967: 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 2070 2070: def find_comments text 2071: return "" unless text 2072: lines = text.split("\n") 2073: lines.reverse! if COMMENTS_ARE_UPPER 2074: comment_block = Array.new 2075: lines.each do |line| 2076: break if line =~ /^\s*?\w/ || line =~ /^\s*?$/ 2077: if COMMENTS_ARE_UPPER 2078: comment_block.unshift line.sub(/^\s*?!\s?/,"") 2079: else 2080: comment_block.push line.sub(/^\s*?!\s?/,"") 2081: end 2082: end 2083: nice_lines = comment_block.join("\n").split "\n\s*?\n" 2084: nice_lines[0] ||= "" 2085: nice_lines.shift 2086: 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 1985 1985: def find_namelists(container, text, before_contains=nil) 1986: return nil if !text 1987: top_level = find_toplevel(container) 1988: 1989: if text =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)(!.*?)?$/i 1990: if top_level.include_includes?(NAMELIST_REPOSITORY_NAME) 1991: namelist_module = 1992: top_level.find_module_named(NAMELIST_REPOSITORY_NAME) 1993: else 1994: namelist_module = 1995: top_level.add_module NormalClass, NAMELIST_REPOSITORY_NAME 1996: namelist_module.record_location top_level 1997: namelist_module.comment = "This is not a module but a repository of NAMELIST group names declared\nin all Fortran 90/95 files\n" 1998: end 1999: else 2000: return "" 2001: end 2002: 2003: nml_group_name_lists = [] 2004: lines = "#{text}" 2005: before_contains = "" if !before_contains 2006: while lines =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)(!.*?)?$/i 2007: lines = $~.post_match 2008: pre_match = $~.pre_match ; post_match = $~.post_match 2009: nml_group_name = $1 2010: trailing_comment = $3 || "" 2011: nml_vars_list = $2.split(",") 2012: nml_comment = COMMENTS_ARE_UPPER ? 2013: find_comments(pre_match.sub(/\n$/, '')) : 2014: find_comments(trailing_comment + post_match) 2015: if lines.split("\n")[0] =~ /^\//i 2016: lines = "namelist " + lines 2017: end 2018: 2019: nml_meth = AnyMethod.new("NAMELIST", nml_group_name) 2020: nml_meth.singleton = false 2021: nml_meth.params = "( " + nml_vars_list.join(", ") + " )" 2022: nml_meth.comment = "<b><em> NAMELIST </em></b> :: <tt></tt>\n" 2023: nml_meth.comment << find_arguments(nml_vars_list, "#{text}" + "\n" + before_contains) 2024: nml_meth.comment << "\n" + nml_comment if nml_comment 2025: if container.parent.parent 2026: parent_object = container.parent.name 2027: else 2028: parent_object = container.parent.file_relative_name 2029: end 2030: nml_meth.comment << "\n\nThis namelist group name is input/output in " 2031: nml_meth.comment << parent_object + "#" + container.name 2032: 2033: progress "n" 2034: @stats.num_methods += 1 2035: namelist_module.add_method nml_meth 2036: 2037: nml_group_name_lists << NAMELIST_REPOSITORY_NAME + "#" + nml_group_name 2038: end 2039: 2040: if !nml_group_name_lists.empty? 2041: comments_in_procedures = "\n\nThis procedure input/output " 2042: comments_in_procedures << nml_group_name_lists.join(", ") + " . " 2043: else 2044: comments_in_procedures = "" 2045: end 2046: 2047: comments_in_procedures 2048: end
Return toplevel class of container
# File parsers/parse_f95.rb, line 2057 2057: def find_toplevel(container) 2058: top_level = container 2059: while top_level.parent 2060: top_level = top_level.parent 2061: end 2062: top_level 2063: end
Find visibility
# File parsers/parse_f95.rb, line 2233 2233: def find_visibility(container, subname, visibility_info) 2234: return nil if !subname || !visibility_info 2235: visibility_info.each{ |info| 2236: if info["name"] == subname || 2237: @options_ignore_case && info["name"].upcase == subname.upcase 2238: if info["parent"] == container.name 2239: return info["visibility"] 2240: end 2241: end 2242: } 2243: return nil 2244: end
Create method for external alias
If argument "internal" is true, file is ignored.
# File parsers/parse_f95.rb, line 2115 2115: def initialize_external_method(new, old, params, file, comment, token=nil, 2116: internal=nil, nolink=nil) 2117: return nil unless new || old 2118: 2119: if internal 2120: external_alias_header = "#{INTERNAL_ALIAS_MES} " 2121: external_alias_text = external_alias_header + old 2122: elsif file 2123: external_alias_header = "#{EXTERNAL_ALIAS_MES} " 2124: external_alias_text = external_alias_header + file + "#" + old 2125: else 2126: return nil 2127: end 2128: external_meth = AnyMethod.new(external_alias_text, new) 2129: external_meth.singleton = false 2130: external_meth.params = params 2131: external_comment = remove_trailing_alias(comment) + "\n\n" if comment 2132: external_meth.comment = external_comment || "" 2133: if nolink && token 2134: external_meth.start_collecting_tokens 2135: external_meth.add_token Token.new(1,1).set_text(token) 2136: else 2137: external_meth.comment << external_alias_text 2138: end 2139: 2140: return external_meth 2141: end
Create method for internal alias
# File parsers/parse_f95.rb, line 2098 2098: def initialize_public_method(method, parent) 2099: return if !method || !parent 2100: 2101: new_meth = AnyMethod.new("External Alias for module", method.name) 2102: new_meth.singleton = method.singleton 2103: new_meth.params = method.params.clone 2104: new_meth.comment = remove_trailing_alias(method.comment.clone) 2105: new_meth.comment << "\n\n#{EXTERNAL_ALIAS_MES} #{parent.strip.chomp}\##{method.name}" 2106: 2107: return new_meth 2108: 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: if function_params_org =~ /^\s*\(\s*\)\s*$/ 1561: function_params = 1562: function_params_org.sub(/^\(/, "\(#{function_result_arg}") 1563: else 1564: function_params = 1565: function_params_org.sub(/^\(/, "\(#{function_result_arg}, ") 1566: end 1567: 1568: function = AnyMethod.new("function", function_name) 1569: parse_subprogram(function, function_params, 1570: function_comment, function_code, 1571: before_contains_code, true, function_prefix) 1572: function.set_priority(function_priority) if function_priority 1573: 1574: # Specific modification due to function 1575: function.params.sub!(/\(\s*?#{function_result_arg}\s*?,?\s*?/, "\( ") 1576: function.params << " result(" + function_result_arg + ")" 1577: function.start_collecting_tokens 1578: function.add_token Token.new(1,1).set_text(function_code_org) 1579: 1580: progress "f" 1581: @stats.num_methods += 1 1582: container.add_method function 1583: subroutine_function = function 1584: 1585: namelist_comment = 1586: find_namelists(function, function_code, before_contains_code) 1587: function.comment << namelist_comment if namelist_comment 1588: 1589: end 1590: 1591: # The visibility of procedure is specified 1592: # 1593: set_visibility(container, procedure_name, 1594: visibility_default, @@public_methods) 1595: 1596: # The alias for this procedure from external modules 1597: # 1598: check_external_aliases(procedure_name, 1599: subroutine_function.params, 1600: subroutine_function.comment, subroutine_function) if external 1601: check_public_methods(subroutine_function, container.name) 1602: 1603: 1604: # contains_lines are parsed as private procedures 1605: if contains_flag 1606: parse_program_or_module(container, 1607: contains_lines.join("\n"), :private) 1608: end 1609: 1610: # next loop to search next block 1611: level_depth = 0 1612: block_searching_flag = nil 1613: block_searching_lines = [] 1614: pre_comment = [] 1615: procedure_trailing = "" 1616: procedure_name = "" 1617: procedure_params = "" 1618: procedure_prefix = "" 1619: procedure_result_arg = "" 1620: contains_lines = [] 1621: contains_flag = nil 1622: next false 1623: } # End of remaining_lines.collect!{|line| 1624: 1625: # Array remains_lines is converted to String remains_code again 1626: # 1627: remaining_code = remaining_lines.join("\n") 1628: 1629: # 1630: # Parse interface 1631: # 1632: interface_scope = false 1633: generic_name = "" 1634: interface_code.split("\n").each{ |line| 1635: if /^\s*? 1636: interface( 1637: \s+\w+| 1638: \s+operator\s*?\(.*?\)| 1639: \s+assignment\s*?\(\s*?=\s*?\) 1640: )? 1641: \s*?(!.*?)?$ 1642: /ix =~ line 1643: generic_name = $1 ? $1.strip.chomp : nil 1644: interface_trailing = $2 || "!" 1645: interface_scope = true 1646: interface_scope = false if interface_trailing.sub(/^!/, '') =~ IGNORED_MARKER_REGEXP 1647: # if generic_name =~ /operator\s*?\((.*?)\)/i 1648: # operator_name = $1 1649: # if operator_name && !operator_name.empty? 1650: # generic_name = "#{operator_name}" 1651: # end 1652: # end 1653: # if generic_name =~ /assignment\s*?\((.*?)\)/i 1654: # assignment_name = $1 1655: # if assignment_name && !assignment_name.empty? 1656: # generic_name = "#{assignment_name}" 1657: # end 1658: # end 1659: end 1660: if /^\s*?end\s+interface/i =~ line 1661: interface_scope = false 1662: generic_name = nil 1663: end 1664: # internal alias 1665: if interface_scope && /^\s*?module\s+procedure\s+(.*?)(!.*?)?$/i =~ line 1666: procedures = $1.strip.chomp 1667: procedures_trailing = $2 || "!" 1668: next if procedures_trailing.sub(/^!/, '') =~ IGNORED_MARKER_REGEXP 1669: procedures_priority, procedures_trailing = doc_priority_from_trailing(procedures_trailing) 1670: 1671: procedures.split(",").each{ |proc| 1672: proc.strip! 1673: proc.chomp! 1674: next if generic_name == proc || !generic_name 1675: old_meth = container.find_symbol(proc, nil, @options_ignore_case) 1676: next if !old_meth 1677: nolink = old_meth.visibility == :private ? true : nil 1678: nolink = nil if @options.show_all 1679: new_meth = 1680: initialize_external_method(generic_name, proc, 1681: old_meth.params, nil, 1682: old_meth.comment, 1683: old_meth.clone.token_stream[0].text, 1684: true, nolink) 1685: new_meth.singleton = old_meth.singleton 1686: new_meth.set_priority(procedures_priority) if procedures_priority 1687: 1688: progress "i" 1689: @stats.num_methods += 1 1690: container.add_method new_meth 1691: 1692: set_visibility(container, generic_name, visibility_default, @@public_methods) 1693: 1694: check_public_methods(new_meth, container.name) 1695: 1696: } 1697: end 1698: 1699: # external aliases 1700: if interface_scope 1701: # subroutine 1702: proc = nil 1703: params = nil 1704: procedures_trailing = nil 1705: if line =~ /^\s*? 1706: (recursive|pure|elemental)?\s*? 1707: subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$ 1708: /ix 1709: proc = $2.chomp.strip 1710: proc_name = generic_name || proc 1711: params = $3 || "" 1712: procedures_trailing = $4 || "!" 1713: 1714: # function 1715: elsif line =~ /^\s*? 1716: (recursive|pure|elemental)?\s*? 1717: ( 1718: character\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1719: | type\s*?\([\w\s]+?\)\s+ 1720: | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1721: | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1722: | double\s+precision\s+ 1723: | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1724: | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+ 1725: )? 1726: function\s+(\w+)\s*? 1727: (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$ 1728: /ix 1729: proc = $8.chomp.strip 1730: proc_name = generic_name || proc 1731: params = $9 || "" 1732: procedures_trailing = $12 || "!" 1733: else 1734: next 1735: end 1736: next if procedures_trailing.sub(/^!/, '') =~ IGNORED_MARKER_REGEXP 1737: procedures_priority, procedures_trailing = doc_priority_from_trailing(procedures_trailing) 1738: indicated_method = nil 1739: indicated_file = nil 1740: TopLevel.all_files.each do |name, toplevel| 1741: indicated_method = toplevel.find_local_symbol(proc, @options_ignore_case) 1742: indicated_file = name 1743: break if indicated_method 1744: end 1745: 1746: if indicated_method 1747: external_method = 1748: initialize_external_method(proc_name, proc, 1749: indicated_method.params, 1750: indicated_file, 1751: indicated_method.comment) 1752: external_method.set_priority(procedures_priority) if procedures_priority 1753: 1754: progress "e" 1755: @stats.num_methods += 1 1756: container.add_method external_method 1757: set_visibility(container, proc_name, visibility_default, @@public_methods) 1758: if !container.include_requires?(indicated_file, @options_ignore_case) 1759: container.add_require(Require.new(indicated_file, "")) 1760: end 1761: check_public_methods(external_method, container.name) 1762: 1763: else 1764: @@external_aliases << { 1765: "new_name" => proc_name, 1766: "old_name" => proc, 1767: "file_or_module" => container, 1768: "visibility" => find_visibility(container, proc_name, @@public_methods) || visibility_default, 1769: "doc_priority" => procedures_priority 1770: } 1771: end 1772: end 1773: 1774: } if interface_code # End of interface_code.split("\n").each ... 1775: 1776: # 1777: # Already imported methods are removed from @@public_methods. 1778: # Remainders are assumed to be imported from other modules. 1779: # 1780: # 既に参照済みのメソッドは @@public_methods から取り除く. 1781: # 残りは外部モジュールからの参照と仮定する. 1782: # 1783: @@public_methods.delete_if{ |method| method["entity_is_discovered"]} 1784: 1785: @@public_methods.each{ |pub_meth| 1786: next unless pub_meth["file_or_module"].name == container.name 1787: pub_meth["used_modules"].each{ |used_mod| 1788: TopLevel.all_classes_and_modules.each{ |modules| 1789: if modules.name == used_mod || 1790: modules.name.upcase == used_mod.upcase && 1791: @options_ignore_case 1792: modules.method_list.each{ |meth| 1793: if meth.name == pub_meth["name"] || 1794: meth.name.upcase == pub_meth["name"].upcase && 1795: @options_ignore_case 1796: new_meth = initialize_public_method(meth, 1797: modules.name) 1798: if pub_meth["local_name"] 1799: new_meth.name = pub_meth["local_name"] 1800: end 1801: progress "e" 1802: @stats.num_methods += 1 1803: container.add_method new_meth 1804: end 1805: } 1806: end 1807: } 1808: } 1809: } 1810: 1811: container 1812: end
Parse arguments, comment, code of subroutine and function. Return AnyMethod object.
# File parsers/parse_f95.rb, line 1818 1818: def parse_subprogram(subprogram, params, comment, code, 1819: before_contains=nil, function=nil, prefix=nil) 1820: subprogram.singleton = false 1821: prefix = "" if !prefix 1822: arguments = params.sub(/\(/, "").sub(/\)/, "").split(",") if params 1823: args_comment, params_opt = 1824: find_arguments(arguments, code.sub(/^s*?contains\s*?(!.*?)?$.*/im, ""), 1825: nil, nil, true) 1826: params_opt = "( " + params_opt + " ) " if params_opt 1827: subprogram.params = params_opt || "" 1828: 1829: block_comment = find_comments comment 1830: if function 1831: subprogram.comment = "<b><em> Function </em></b> :: <em>#{prefix}</em>\n" 1832: else 1833: subprogram.comment = "<b><em> Subroutine </em></b> :: <em>#{prefix}</em>\n" 1834: end 1835: subprogram.comment << args_comment if args_comment 1836: subprogram.comment << block_comment if block_comment 1837: 1838: # For output source code 1839: subprogram.start_collecting_tokens 1840: subprogram.add_token Token.new(1,1).set_text(code) 1841: 1842: subprogram 1843: end
Parse visibility
# File parsers/parse_f95.rb, line 2148 2148: def parse_visibility(code, default, container) 2149: result = [] 2150: visibility_default = default || :public 2151: 2152: used_modules = [] 2153: container.includes.each{|i| used_modules << i.name} if container 2154: 2155: remaining_code = code.gsub(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "") 2156: remaining_code.split("\n").each{ |line| 2157: if /^\s*?private\s*?$/ =~ line 2158: visibility_default = :private 2159: break 2160: end 2161: } if remaining_code 2162: 2163: remaining_code.split("\n").each{ |line| 2164: if /^\s*?private\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line 2165: methods = $2.sub(/!.*$/, '') 2166: methods.split(",").each{ |meth| 2167: meth.sub!(/!.*$/, '') 2168: meth.gsub!(/:/, '') 2169: result << { 2170: "name" => meth.chomp.strip, 2171: "visibility" => :private, 2172: "used_modules" => used_modules.clone, 2173: "file_or_module" => container, 2174: "entity_is_discovered" => nil, 2175: "local_name" => nil 2176: } 2177: } 2178: elsif /^\s*?public\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line 2179: methods = $2.sub(/!.*$/, '') 2180: methods.split(",").each{ |meth| 2181: meth.sub!(/!.*$/, '') 2182: meth.gsub!(/:/, '') 2183: result << { 2184: "name" => meth.chomp.strip, 2185: "visibility" => :public, 2186: "used_modules" => used_modules.clone, 2187: "file_or_module" => container, 2188: "entity_is_discovered" => nil, 2189: "local_name" => nil 2190: } 2191: } 2192: end 2193: } if remaining_code 2194: 2195: if container 2196: result.each{ |vis_info| 2197: vis_info["parent"] = container.name 2198: } 2199: end 2200: 2201: return visibility_default, result 2202: end
# File parsers/parse_f95.rb, line 2088 2088: def progress(char) 2089: unless @options.quiet 2090: @progress.print(char) 2091: @progress.flush 2092: end 2093: end
Empty lines in header are removed
# File parsers/parse_f95.rb, line 2572 2572: def remove_empty_head_lines(text) 2573: return "" unless text 2574: lines = text.split("\n") 2575: header = true 2576: lines.delete_if{ |line| 2577: header = false if /\S/ =~ line 2578: header && /^\s*?$/ =~ line 2579: } 2580: lines.join("\n") 2581: end
header marker "=", "==", … are removed
# File parsers/parse_f95.rb, line 2585 2585: def remove_header_marker(text) 2586: return text.gsub(/^\s?(=+)/, '<tt></tt>\1') 2587: end
# File parsers/parse_f95.rb, line 2589 2589: def remove_private_comments(body) 2590: body.gsub!(/^(\s*)!--\s*?$.*?^\s*!\+\+\s*?$/m, '\\1!') 2591: return body 2592: end
Remove "Alias for" in end of comments
# File parsers/parse_f95.rb, line 2551 2551: def remove_trailing_alias(text) 2552: return "" if !text 2553: lines = text.split("\n").reverse 2554: comment_block = Array.new 2555: checked = false 2556: lines.each do |line| 2557: if !checked 2558: if /^\s?#{INTERNAL_ALIAS_MES}/ =~ line || 2559: /^\s?#{EXTERNAL_ALIAS_MES}/ =~ line 2560: checked = true 2561: next 2562: end 2563: end 2564: comment_block.unshift line 2565: end 2566: nice_lines = comment_block.join("\n") 2567: nice_lines ||= "" 2568: return nice_lines 2569: 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 2454 2454: def semicolon_to_linefeed(text) 2455: return "" unless text 2456: lines = text.split("\n") 2457: lines.collect!{ |line| 2458: indent_space = "" 2459: if line =~ /^(\s+)/ 2460: indent_space = $1 2461: end 2462: words = line.split("") 2463: commentout = false 2464: squote = false ; dquote = false 2465: words.collect! { |char| 2466: if !(squote) && !(dquote) && !(commentout) 2467: case char 2468: when "!" ; commentout = true ; next char 2469: when "\""; dquote = true ; next char 2470: when "\'"; squote = true ; next char 2471: when ";" ; "\n"+indent_space 2472: else next char 2473: end 2474: elsif commentout 2475: next char 2476: elsif squote 2477: case char 2478: when "\'"; squote = false ; next char 2479: else next char 2480: end 2481: elsif dquote 2482: case char 2483: when "\""; dquote = false ; next char 2484: else next char 2485: end 2486: end 2487: } 2488: words.join("") 2489: } 2490: return lines.join("\n") 2491: end
Set visibility
"subname" element of "visibility_info" is deleted.
# File parsers/parse_f95.rb, line 2209 2209: def set_visibility(container, subname, visibility_default, visibility_info) 2210: return unless container || subname || visibility_default || visibility_info 2211: not_found = true 2212: visibility_info.collect!{ |info| 2213: if info["name"] == subname || 2214: @options_ignore_case && info["name"].upcase == subname.upcase 2215: if info["file_or_module"].name == container.name 2216: container.set_visibility_for([subname], info["visibility"]) 2217: info["entity_is_discovered"] = true 2218: not_found = false 2219: end 2220: end 2221: info 2222: } 2223: if not_found 2224: return container.set_visibility_for([subname], visibility_default) 2225: else 2226: return container 2227: end 2228: 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 2329 2329: def united_to_one_line(f90src, delete_space=true) 2330: return "" unless f90src 2331: lines = f90src.split("\n") 2332: previous_continuing = false 2333: now_continuing = false 2334: body = "" 2335: squote = false ; dquote = false 2336: lines.each{ |line| 2337: words = line.split("") 2338: next if words.empty? && previous_continuing 2339: commentout = false 2340: brank_flag = true ; brank_char = "" 2341: ignore = false 2342: words.collect! { |char| 2343: if previous_continuing && brank_flag 2344: now_continuing = true 2345: ignore = true 2346: case char 2347: when "!" ; break 2348: when " " ; brank_char << char ; next "" 2349: when "&" 2350: brank_flag = false 2351: now_continuing = false 2352: next "" 2353: else 2354: brank_flag = false 2355: now_continuing = false 2356: ignore = false 2357: next brank_char + char 2358: end 2359: end 2360: ignore = false 2361: 2362: if now_continuing && !(squote) && !(dquote) 2363: next "" 2364: elsif !(squote) && !(dquote) && !(commentout) 2365: case char 2366: when "!" ; commentout = true ; next char 2367: when "\""; dquote = true ; next char 2368: when "\'"; squote = true ; next char 2369: when "&" ; now_continuing = true ; next "" 2370: else next char 2371: end 2372: elsif commentout 2373: next char 2374: elsif squote 2375: case char 2376: when "\'"; squote = false ; now_continuing = false ; next char 2377: when "&" ; now_continuing = true ; next "" 2378: else next char 2379: end 2380: elsif dquote 2381: case char 2382: when "\""; dquote = false ; now_continuing = false ; next char 2383: when "&" ; now_continuing = true ; next "" 2384: else next char 2385: end 2386: end 2387: } 2388: if !ignore && !previous_continuing || !brank_flag 2389: if previous_continuing 2390: if delete_space 2391: joined_words = words.join("") 2392: body = body.rstrip + " " + joined_words.lstrip 2393: else 2394: body << words.join("") 2395: end 2396: else 2397: body << "\n" + words.join("") 2398: end 2399: end 2400: previous_continuing = now_continuing ? true : false 2401: now_continuing = false 2402: } 2403: return body 2404: end