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