| 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