| 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 |
prepare to parse a Fortran 95 file
# File parsers/parse_f95.rb, line 696
696: def initialize(top_level, file_name, body, options, stats)
697: @body = body
698: @stats = stats
699: @file_name = file_name
700: @options = options
701: @top_level = top_level
702: @progress = $stderr unless options.quiet
703:
704: begin
705: @options_ignore_case = options.ignore_case
706: rescue
707: @options_ignore_case = true
708: end
709:
710: end
Return lines before "contains" statement in modules. "interface", "type" statements are removed.
# File parsers/parse_f95.rb, line 1611
1611: def before_contains(code)
1612: level_depth = 0
1613: before_contains_lines = []
1614: before_contains_code = nil
1615: before_contains_flag = nil
1616: code.split("\n").each{ |line|
1617: if !before_contains_flag
1618: if line =~ /^\s*?module\s+\w+\s*?(!.*?)?$/i
1619: before_contains_flag = true
1620: end
1621: else
1622: break if line =~ /^\s*?contains\s*?(!.*?)?$/i
1623: level_depth += 1 if block_start?(line)
1624: level_depth -= 1 if block_end?(line)
1625: break if level_depth < 0
1626: before_contains_lines << line
1627: end
1628:
1629: }
1630: before_contains_code = before_contains_lines.join("\n")
1631: if before_contains_code
1632: before_contains_code.gsub!(/^\s*?interface\s+.*?\s+end\s+interface.*?$/im, "")
1633: before_contains_code.gsub!(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
1634: end
1635:
1636: before_contains_code
1637: end
Which "line" is end of block (module, program, block data, subroutine, function) statement ?
# File parsers/parse_f95.rb, line 2278
2278: def block_end?(line)
2279: return nil if !line
2280:
2281: if line =~ /^\s*?end\s*?(!.*?)?$/i ||
2282: line =~ /^\s*?end\s+module(\s+\w+)?\s*?(!.*?)?$/i ||
2283: line =~ /^\s*?end\s+program(\s+\w+)?\s*?(!.*?)?$/i ||
2284: line =~ /^\s*?end\s+block\s+data(\s+\w+)?\s*?(!.*?)?$/i ||
2285: line =~ /^\s*?end\s+subroutine(\s+\w+)?\s*?(!.*?)?$/i ||
2286: line =~ /^\s*?end\s+function(\s+\w+)?\s*?(!.*?)?$/i
2287: return true
2288: end
2289:
2290: return nil
2291: end
Which "line" is start of block (module, program, block data, subroutine, function) statement ?
# File parsers/parse_f95.rb, line 2242
2242: def block_start?(line)
2243: return nil if !line
2244:
2245: if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i ||
2246: line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i ||
2247: line =~ /^\s*?block\s+data(\s+\w+)?\s*?(!.*?)?$/i ||
2248: line =~ \
2249: /^\s*?
2250: (recursive|pure|elemental)?\s*?
2251: subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
2252: /ix ||
2253: line =~ \
2254: /^\s*?
2255: (recursive|pure|elemental)?\s*?
2256: (
2257: character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
2258: | type\s*?\([\w\s]+?\)\s+
2259: | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
2260: | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
2261: | double\s+precision\s+
2262: | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
2263: | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
2264: )?
2265: function\s+(\w+)\s*?
2266: (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
2267: /ix
2268: return true
2269: end
2270:
2271: return nil
2272: end
Check external aliases
subname というサブルーチン名, または関数名を持つファイルを 探査し, 存在する場合にはそのファイル内へメソッドを追加する.
# File parsers/parse_f95.rb, line 1998
1998: def check_external_aliases(subname, params, comment, test=nil)
1999: @@external_aliases.each{ |alias_item|
2000: if subname == alias_item["old_name"] ||
2001: subname.upcase == alias_item["old_name"].upcase &&
2002: @options_ignore_case
2003:
2004: new_meth = initialize_external_method(alias_item["new_name"],
2005: subname, params, @file_name,
2006: comment)
2007: new_meth.visibility = alias_item["visibility"]
2008:
2009: progress "e"
2010: @stats.num_methods += 1
2011: alias_item["file_or_module"].add_method(new_meth)
2012:
2013: if !alias_item["file_or_module"].include_requires?(@file_name, @options_ignore_case)
2014: alias_item["file_or_module"].add_require(Require.new(@file_name, ""))
2015: end
2016: end
2017: }
2018: end
Check public_methods
use したモジュールからそのまま引き継いで public として 公開する場合のチェックを行う. subname というサブルーチン名, または関数名を持つファイルを 探査し, 存在する場合にはそのファイル内へメソッドを追加する.
# File parsers/parse_f95.rb, line 2028
2028: def check_public_methods(method, parent)
2029: return if !method || !parent
2030: @@public_methods.each{ |alias_item|
2031: parent_is_used_module = nil
2032: alias_item["used_modules"].each{ |used_module|
2033: if used_module == parent ||
2034: used_module.upcase == parent.upcase &&
2035: @options_ignore_case
2036: parent_is_used_module = true
2037: end
2038: }
2039: next if !parent_is_used_module
2040:
2041: if method.name == alias_item["name"] ||
2042: method.name.upcase == alias_item["name"].upcase &&
2043: @options_ignore_case
2044:
2045: new_meth = initialize_public_method(method, parent)
2046: if alias_item["local_name"]
2047: new_meth.name = alias_item["local_name"]
2048: end
2049:
2050: progress "e"
2051: @stats.num_methods += 1
2052: alias_item["file_or_module"].add_method new_meth
2053: end
2054: }
2055: end
Collect comment for file entity
# File parsers/parse_f95.rb, line 1642
1642: def collect_first_comment(body)
1643: comment = ""
1644: not_comment = ""
1645: comment_start = false
1646: comment_end = false
1647: body.split("\n").each{ |line|
1648: if comment_end
1649: not_comment << line
1650: not_comment << "\n"
1651: elsif /^\s*?!\s?(.*)$/i =~ line
1652: comment_start = true
1653: comment << $1
1654: comment << "\n"
1655: elsif /^\s*?$/i =~ line
1656: comment_end = true if comment_start && COMMENTS_ARE_UPPER
1657: else
1658: comment_end = true
1659: not_comment << line
1660: not_comment << "\n"
1661: end
1662: }
1663: return comment, not_comment
1664: end
Comment out checker
# File parsers/parse_f95.rb, line 2169
2169: def comment_out?(line)
2170: return nil unless line
2171: commentout = false
2172: squote = false ; dquote = false
2173: line.split("").each { |char|
2174: if !(squote) && !(dquote)
2175: case char
2176: when "!" ; commentout = true ; break
2177: when "\""; dquote = true
2178: when "\'"; squote = true
2179: else next
2180: end
2181: elsif squote
2182: case char
2183: when "\'"; squote = false
2184: else next
2185: end
2186: elsif dquote
2187: case char
2188: when "\""; dquote = false
2189: else next
2190: end
2191: end
2192: }
2193: return commentout
2194: end
Continuous line checker
# File parsers/parse_f95.rb, line 2155
2155: def continuous_line?(line)
2156: continuous = false
2157: if /&\s*?(!.*)?$/ =~ line
2158: continuous = true
2159: if comment_out?($~.pre_match)
2160: continuous = false
2161: end
2162: end
2163: return continuous
2164: end
Parse string argument "text", and Return Array of Fortran95Definition object
# File parsers/parse_f95.rb, line 2414
2414: def definition_info(text)
2415: return nil unless text
2416: lines = "#{text}"
2417: defs = Array.new
2418: comment = ""
2419: trailing_comment = ""
2420: under_comment_valid = false
2421: lines.split("\n").each{ |line|
2422: if /^\s*?!\s?(.*)/ =~ line
2423: if COMMENTS_ARE_UPPER
2424: comment << remove_header_marker($1)
2425: comment << "\n"
2426: elsif defs[-1] && under_comment_valid
2427: defs[-1].comment << "\n"
2428: defs[-1].comment << remove_header_marker($1)
2429: end
2430: next
2431: elsif /^\s*?$/ =~ line
2432: comment = ""
2433: under_comment_valid = false
2434: next
2435: end
2436: type = ""
2437: characters = ""
2438: if line =~ /^\s*?
2439: (
2440: character\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2441: | type\s*?\([\w\s]+?\)[\s\,]*
2442: | integer\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2443: | real\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2444: | double\s+precision[\s\,]*
2445: | logical\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2446: | complex\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
2447: )
2448: (.*?::)?
2449: (.+)$
2450: /ix
2451: characters = $8
2452: type = $1
2453: type << $7.gsub(/::/, '').gsub(/^\s*?\,/, '') if $7
2454: else
2455: under_comment_valid = false
2456: next
2457: end
2458: squote = false ; dquote = false ; bracket = 0
2459: iniflag = false; commentflag = false
2460: varname = "" ; arraysuffix = "" ; inivalue = ""
2461: start_pos = defs.size
2462: characters.split("").each { |char|
2463: if !(squote) && !(dquote) && bracket <= 0 && !(iniflag) && !(commentflag)
2464: case char
2465: when "!" ; commentflag = true
2466: when "(" ; bracket += 1 ; arraysuffix = char
2467: when "\""; dquote = true
2468: when "\'"; squote = true
2469: when "=" ; iniflag = true ; inivalue << char
2470: when ","
2471: defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2472: varname = "" ; arraysuffix = "" ; inivalue = ""
2473: under_comment_valid = true
2474: when " " ; next
2475: else ; varname << char
2476: end
2477: elsif commentflag
2478: comment << remove_header_marker(char)
2479: trailing_comment << remove_header_marker(char)
2480: elsif iniflag
2481: if dquote
2482: case char
2483: when "\"" ; dquote = false ; inivalue << char
2484: else ; inivalue << char
2485: end
2486: elsif squote
2487: case char
2488: when "\'" ; squote = false ; inivalue << char
2489: else ; inivalue << char
2490: end
2491: elsif bracket > 0
2492: case char
2493: when "(" ; bracket += 1 ; inivalue << char
2494: when ")" ; bracket -= 1 ; inivalue << char
2495: else ; inivalue << char
2496: end
2497: else
2498: case char
2499: when ","
2500: defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2501: varname = "" ; arraysuffix = "" ; inivalue = ""
2502: iniflag = false
2503: under_comment_valid = true
2504: when "(" ; bracket += 1 ; inivalue << char
2505: when "\""; dquote = true ; inivalue << char
2506: when "\'"; squote = true ; inivalue << char
2507: when "!" ; commentflag = true
2508: else ; inivalue << char
2509: end
2510: end
2511: elsif !(squote) && !(dquote) && bracket > 0
2512: case char
2513: when "(" ; bracket += 1 ; arraysuffix << char
2514: when ")" ; bracket -= 1 ; arraysuffix << char
2515: else ; arraysuffix << char
2516: end
2517: elsif squote
2518: case char
2519: when "\'"; squote = false ; inivalue << char
2520: else ; inivalue << char
2521: end
2522: elsif dquote
2523: case char
2524: when "\""; dquote = false ; inivalue << char
2525: else ; inivalue << char
2526: end
2527: end
2528: }
2529: defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
2530: if trailing_comment =~ /^:nodoc:/
2531: defs[start_pos..-1].collect!{ |defitem|
2532: defitem.nodoc = true
2533: }
2534: end
2535: varname = "" ; arraysuffix = "" ; inivalue = ""
2536: comment = ""
2537: under_comment_valid = true
2538: trailing_comment = ""
2539: }
2540: return defs
2541: 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 1673
1673: def find_arguments(args, text, all=nil, indent=nil, modified_params=nil)
1674: return unless args || all
1675: indent = "" unless indent
1676: args = ["all"] if all
1677: params = "" if modified_params
1678: comma = ""
1679: return unless text
1680: args_rdocforms = "\n"
1681: remaining_lines = "#{text}"
1682: definitions = definition_info(remaining_lines)
1683: args.each{ |arg|
1684: arg.strip!
1685: arg.chomp!
1686: definitions.each { |defitem|
1687: if arg == defitem.varname.strip.chomp || all
1688: 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"
1689: if !defitem.comment.chomp.strip.empty?
1690: comment = ""
1691: defitem.comment.split("\n").each{ |line|
1692: comment << " " + line + "\n"
1693: }
1694: args_rdocforms << "\n\#{indent} <tt></tt> ::\n\#{indent} <tt></tt>\n\#{indent} \#{comment.chomp.strip}\n"
1695: end
1696:
1697: if modified_params
1698: if defitem.include_attr?("optional")
1699: params << "#{comma}[#{arg}]"
1700: else
1701: params << "#{comma}#{arg}"
1702: end
1703: comma = ", "
1704: end
1705: end
1706: }
1707: }
1708: if modified_params
1709: return args_rdocforms, params
1710: else
1711: return args_rdocforms
1712: end
1713: 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 1816
1816: def find_comments text
1817: return "" unless text
1818: lines = text.split("\n")
1819: lines.reverse! if COMMENTS_ARE_UPPER
1820: comment_block = Array.new
1821: lines.each do |line|
1822: break if line =~ /^\s*?\w/ || line =~ /^\s*?$/
1823: if COMMENTS_ARE_UPPER
1824: comment_block.unshift line.sub(/^\s*?!\s?/,"")
1825: else
1826: comment_block.push line.sub(/^\s*?!\s?/,"")
1827: end
1828: end
1829: nice_lines = comment_block.join("\n").split "\n\s*?\n"
1830: nice_lines[0] ||= ""
1831: nice_lines.shift
1832: 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 1731
1731: def find_namelists(container, text, before_contains=nil)
1732: return nil if !text
1733: top_level = find_toplevel(container)
1734:
1735: if text =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)(!.*?)?$/i
1736: if top_level.include_includes?(NAMELIST_REPOSITORY_NAME)
1737: namelist_module =
1738: top_level.find_module_named(NAMELIST_REPOSITORY_NAME)
1739: else
1740: namelist_module =
1741: top_level.add_module NormalClass, NAMELIST_REPOSITORY_NAME
1742: namelist_module.record_location top_level
1743: namelist_module.comment = "This is not a module but a repository of NAMELIST group names declared\nin all Fortran 90/95 files\n"
1744: end
1745: else
1746: return ""
1747: end
1748:
1749: nml_group_name_lists = []
1750: lines = "#{text}"
1751: before_contains = "" if !before_contains
1752: while lines =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)(!.*?)?$/i
1753: lines = $~.post_match
1754: pre_match = $~.pre_match ; post_match = $~.post_match
1755: nml_group_name = $1
1756: trailing_comment = $3 || ""
1757: nml_vars_list = $2.split(",")
1758: nml_comment = COMMENTS_ARE_UPPER ?
1759: find_comments(pre_match.sub(/\n$/, '')) :
1760: find_comments(trailing_comment + post_match)
1761: if lines.split("\n")[0] =~ /^\//i
1762: lines = "namelist " + lines
1763: end
1764:
1765: nml_meth = AnyMethod.new("NAMELIST", nml_group_name)
1766: nml_meth.singleton = false
1767: nml_meth.params = "( " + nml_vars_list.join(", ") + " )"
1768: nml_meth.comment = "<b><em> NAMELIST </em></b> :: <tt></tt>\n"
1769: nml_meth.comment << find_arguments(nml_vars_list, "#{text}" + "\n" + before_contains)
1770: nml_meth.comment << "\n" + nml_comment if nml_comment
1771: if container.parent.parent
1772: parent_object = container.parent.name
1773: else
1774: parent_object = container.parent.file_relative_name
1775: end
1776: nml_meth.comment << "\n\nThis namelist group name is input/output in "
1777: nml_meth.comment << parent_object + "#" + container.name
1778:
1779: progress "n"
1780: @stats.num_methods += 1
1781: namelist_module.add_method nml_meth
1782:
1783: nml_group_name_lists << NAMELIST_REPOSITORY_NAME + "#" + nml_group_name
1784: end
1785:
1786: if !nml_group_name_lists.empty?
1787: comments_in_procedures = "\n\nThis procedure input/output "
1788: comments_in_procedures << nml_group_name_lists.join(", ") + " . "
1789: else
1790: comments_in_procedures = ""
1791: end
1792:
1793: comments_in_procedures
1794: end
Return toplevel class of container
# File parsers/parse_f95.rb, line 1803
1803: def find_toplevel(container)
1804: top_level = container
1805: while top_level.parent
1806: top_level = top_level.parent
1807: end
1808: top_level
1809: end
Find visibility
# File parsers/parse_f95.rb, line 1979
1979: def find_visibility(container, subname, visibility_info)
1980: return nil if !subname || !visibility_info
1981: visibility_info.each{ |info|
1982: if info["name"] == subname ||
1983: @options_ignore_case && info["name"].upcase == subname.upcase
1984: if info["parent"] == container.name
1985: return info["visibility"]
1986: end
1987: end
1988: }
1989: return nil
1990: end
Create method for external alias
If argument "internal" is true, file is ignored.
# File parsers/parse_f95.rb, line 1861
1861: def initialize_external_method(new, old, params, file, comment, token=nil,
1862: internal=nil, nolink=nil)
1863: return nil unless new || old
1864:
1865: if internal
1866: external_alias_header = "#{INTERNAL_ALIAS_MES} "
1867: external_alias_text = external_alias_header + old
1868: elsif file
1869: external_alias_header = "#{EXTERNAL_ALIAS_MES} "
1870: external_alias_text = external_alias_header + file + "#" + old
1871: else
1872: return nil
1873: end
1874: external_meth = AnyMethod.new(external_alias_text, new)
1875: external_meth.singleton = false
1876: external_meth.params = params
1877: external_comment = remove_trailing_alias(comment) + "\n\n" if comment
1878: external_meth.comment = external_comment || ""
1879: if nolink && token
1880: external_meth.start_collecting_tokens
1881: external_meth.add_token Token.new(1,1).set_text(token)
1882: else
1883: external_meth.comment << external_alias_text
1884: end
1885:
1886: return external_meth
1887: end
Create method for internal alias
# File parsers/parse_f95.rb, line 1844
1844: def initialize_public_method(method, parent)
1845: return if !method || !parent
1846:
1847: new_meth = AnyMethod.new("External Alias for module", method.name)
1848: new_meth.singleton = method.singleton
1849: new_meth.params = method.params.clone
1850: new_meth.comment = remove_trailing_alias(method.comment.clone)
1851: new_meth.comment << "\n\n#{EXTERNAL_ALIAS_MES} #{parent.strip.chomp}\##{method.name}"
1852:
1853: return new_meth
1854: end
# File parsers/parse_f95.rb, line 937
937: def parse_program_or_module(container, code,
938: visibility=:public, external=nil)
939: return unless container
940: return unless code
941: remaining_lines = code.split("\n")
942: remaining_code = "#{code}"
943:
944: #
945: # Parse variables before "contains" in module
946: #
947: # namelist 変数の定義に使われたり, これ自体が定数, 変数
948: # 提供されるのに利用される. (変数や定数として利用される場合,
949: # これもメソッドとして提供する.
950: #
951: before_contains_code = before_contains(remaining_code)
952:
953: #
954: # Parse global "use"
955: #
956: use_check_code = "#{before_contains_code}"
957: cascaded_modules_list = []
958: while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i
959: use_check_code = $~.pre_match
960: use_check_code << $~.post_match
961: used_mod_name = $1.strip.chomp
962: used_list = $2 || ""
963: used_trailing = $3 || ""
964: next if used_trailing =~ /!:nodoc:/
965: if !container.include_includes?(used_mod_name, @options_ignore_case)
966: progress "."
967: container.add_include Include.new(used_mod_name, "")
968: end
969: if ! (used_list =~ /\,\s*?only\s*?:/i )
970: cascaded_modules_list << "\#" + used_mod_name
971: end
972: end
973:
974: #
975: # Parse public and private, and store information.
976: # This information is used when "add_method" and
977: # "set_visibility_for" are called.
978: #
979: visibility_default, visibility_info =
980: parse_visibility(remaining_lines.join("\n"), visibility, container)
981: @@public_methods.concat visibility_info
982: if visibility_default == :public
983: if !cascaded_modules_list.empty?
984: cascaded_modules =
985: Attr.new("Cascaded Modules",
986: "Imported modules all of whose components are published again",
987: "",
988: cascaded_modules_list.join(", "))
989: container.add_attribute(cascaded_modules)
990: end
991: end
992:
993: #
994: # Check rename elements
995: #
996: use_check_code = "#{before_contains_code}"
997: while use_check_code =~ /^\s*?use\s+(\w+)\s*?\,(.+)$/i
998: use_check_code = $~.pre_match
999: use_check_code << $~.post_match
1000: used_mod_name = $1.strip.chomp
1001: used_elements = $2.sub(/\s*?only\s*?:\s*?/i, '')
1002: used_elements.split(",").each{ |used|
1003: if /\s*?(\w+)\s*?=>\s*?(\w+)\s*?/ =~ used
1004: local = $1
1005: org = $2
1006: @@public_methods.collect!{ |pub_meth|
1007: if local == pub_meth["name"] ||
1008: local.upcase == pub_meth["name"].upcase &&
1009: @options_ignore_case
1010: pub_meth["name"] = org
1011: pub_meth["local_name"] = local
1012: end
1013: pub_meth
1014: }
1015: end
1016: }
1017: end
1018:
1019: #
1020: # Parse private "use"
1021: #
1022: use_check_code = remaining_lines.join("\n")
1023: while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i
1024: use_check_code = $~.pre_match
1025: use_check_code << $~.post_match
1026: used_mod_name = $1.strip.chomp
1027: used_trailing = $3 || ""
1028: next if used_trailing =~ /!:nodoc:/
1029: if !container.include_includes?(used_mod_name, @options_ignore_case)
1030: progress "."
1031: container.add_include Include.new(used_mod_name, "")
1032: end
1033: end
1034:
1035: container.each_includes{ |inc|
1036: TopLevel.all_files.each do |name, toplevel|
1037: indicated_mod = toplevel.find_symbol(inc.name,
1038: nil, @options_ignore_case)
1039: if indicated_mod
1040: indicated_name = indicated_mod.parent.file_relative_name
1041: if !container.include_requires?(indicated_name, @options_ignore_case)
1042: container.add_require(Require.new(indicated_name, ""))
1043: end
1044: break
1045: end
1046: end
1047: }
1048:
1049: #
1050: # Parse derived types definitions
1051: #
1052: derived_types_comment = ""
1053: remaining_code = remaining_lines.join("\n")
1054: while remaining_code =~ /^\s*?
1055: type[\s\,]+(public|private)?\s*?(::)?\s*?
1056: (\w+)\s*?(!.*?)?$
1057: (.*?)
1058: ^\s*?end\s+type.*?$
1059: /imx
1060: remaining_code = $~.pre_match
1061: remaining_code << $~.post_match
1062: typename = $3.chomp.strip
1063: type_elements = $5 || ""
1064: type_code = remove_empty_head_lines($&)
1065: type_trailing = find_comments($4)
1066: next if type_trailing =~ /^:nodoc:/
1067: type_visibility = $1
1068: type_comment = COMMENTS_ARE_UPPER ?
1069: find_comments($~.pre_match) + "\n" + type_trailing :
1070: type_trailing + "\n" + find_comments(type_code.sub(/^.*$\n/i, ''))
1071: type_element_visibility_public = true
1072: type_code.split("\n").each{ |line|
1073: if /^\s*?private\s*?$/ =~ line
1074: type_element_visibility_public = nil
1075: break
1076: end
1077: } if type_code
1078:
1079: args_comment = ""
1080: type_args_info = nil
1081:
1082: if @options.show_all
1083: args_comment = find_arguments(nil, type_code, true)
1084: else
1085: type_public_args_list = []
1086: type_args_info = definition_info(type_code)
1087: type_args_info.each{ |arg|
1088: arg_is_public = type_element_visibility_public
1089: arg_is_public = true if arg.include_attr?("public")
1090: arg_is_public = nil if arg.include_attr?("private")
1091: type_public_args_list << arg.varname if arg_is_public
1092: }
1093: args_comment = find_arguments(type_public_args_list, type_code)
1094: end
1095:
1096: type = AnyMethod.new("type #{typename}", typename)
1097: type.singleton = false
1098: type.params = ""
1099: type.comment = "<b><em> Derived Type </em></b> :: <tt></tt>\n"
1100: type.comment << args_comment if args_comment
1101: type.comment << type_comment if type_comment
1102: progress "t"
1103: @stats.num_methods += 1
1104: container.add_method type
1105:
1106: set_visibility(container, typename, visibility_default, @@public_methods)
1107:
1108: if type_visibility
1109: type_visibility.gsub!(/\s/,'')
1110: type_visibility.gsub!(/\,/,'')
1111: type_visibility.gsub!(/:/,'')
1112: type_visibility.downcase!
1113: if type_visibility == "public"
1114: container.set_visibility_for([typename], :public)
1115: elsif type_visibility == "private"
1116: container.set_visibility_for([typename], :private)
1117: end
1118: end
1119:
1120: check_public_methods(type, container.name)
1121:
1122: if @options.show_all
1123: derived_types_comment << ", " unless derived_types_comment.empty?
1124: derived_types_comment << typename
1125: else
1126: if type.visibility == :public
1127: derived_types_comment << ", " unless derived_types_comment.empty?
1128: derived_types_comment << typename
1129: end
1130: end
1131:
1132: end
1133:
1134: if !derived_types_comment.empty?
1135: derived_types_table =
1136: Attr.new("Derived Types", "Derived_Types", "",
1137: derived_types_comment)
1138: container.add_attribute(derived_types_table)
1139: end
1140:
1141: #
1142: # move interface scope
1143: #
1144: interface_code = ""
1145: while remaining_code =~ /^\s*?
1146: interface(
1147: \s+\w+ |
1148: \s+operator\s*?\(.*?\) |
1149: \s+assignment\s*?\(\s*?=\s*?\)
1150: )?\s*?$
1151: (.*?)
1152: ^\s*?end\s+interface.*?$
1153: /imx
1154: interface_code << remove_empty_head_lines($&) + "\n"
1155: remaining_code = $~.pre_match
1156: remaining_code << $~.post_match
1157: end
1158:
1159: #
1160: # Parse global constants or variables in modules
1161: #
1162: const_var_defs = definition_info(before_contains_code)
1163: const_var_defs.each{|defitem|
1164: next if defitem.nodoc
1165: const_or_var_type = "Variable"
1166: const_or_var_progress = "v"
1167: if defitem.include_attr?("parameter")
1168: const_or_var_type = "Constant"
1169: const_or_var_progress = "c"
1170: end
1171: const_or_var = AnyMethod.new(const_or_var_type, defitem.varname)
1172: const_or_var.singleton = false
1173: const_or_var.params = ""
1174: self_comment = find_arguments([defitem.varname], before_contains_code)
1175: const_or_var.comment = "<b><em>" + const_or_var_type + "</em></b> :: <tt></tt>\n"
1176: const_or_var.comment << self_comment if self_comment
1177: progress const_or_var_progress
1178: @stats.num_methods += 1
1179: container.add_method const_or_var
1180:
1181: set_visibility(container, defitem.varname, visibility_default, @@public_methods)
1182:
1183: if defitem.include_attr?("public")
1184: container.set_visibility_for([defitem.varname], :public)
1185: elsif defitem.include_attr?("private")
1186: container.set_visibility_for([defitem.varname], :private)
1187: end
1188:
1189: check_public_methods(const_or_var, container.name)
1190:
1191: } if const_var_defs
1192:
1193: remaining_lines = remaining_code.split("\n")
1194:
1195: # "subroutine" or "function" parts are parsed (new)
1196: #
1197: level_depth = 0
1198: block_searching_flag = nil
1199: block_searching_lines = []
1200: pre_comment = []
1201: procedure_trailing = ""
1202: procedure_name = ""
1203: procedure_params = ""
1204: procedure_prefix = ""
1205: procedure_result_arg = ""
1206: procedure_type = ""
1207: contains_lines = []
1208: contains_flag = nil
1209: remaining_lines.collect!{|line|
1210: if !block_searching_flag
1211: # subroutine
1212: if line =~ /^\s*?
1213: (recursive|pure|elemental)?\s*?
1214: subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
1215: /ix
1216: block_searching_flag = :subroutine
1217: block_searching_lines << line
1218:
1219: procedure_name = $2.chomp.strip
1220: procedure_params = $3 || ""
1221: procedure_prefix = $1 || ""
1222: procedure_trailing = $4 || "!"
1223: next false
1224:
1225: # function
1226: elsif line =~ /^\s*?
1227: (recursive|pure|elemental)?\s*?
1228: (
1229: character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1230: | type\s*?\([\w\s]+?\)\s+
1231: | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1232: | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1233: | double\s+precision\s+
1234: | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1235: | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1236: )?
1237: function\s+(\w+)\s*?
1238: (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
1239: /ix
1240: block_searching_flag = :function
1241: block_searching_lines << line
1242:
1243: procedure_prefix = $1 || ""
1244: procedure_type = $2 ? $2.chomp.strip : nil
1245: procedure_name = $8.chomp.strip
1246: procedure_params = $9 || ""
1247: procedure_result_arg = $11 ? $11.chomp.strip : procedure_name
1248: procedure_trailing = $12 || "!"
1249: next false
1250: elsif line =~ /^\s*?!\s?(.*)/
1251: pre_comment << line
1252: next line
1253: else
1254: pre_comment = []
1255: next line
1256: end
1257: end
1258: contains_flag = true if line =~ /^\s*?contains\s*?(!.*?)?$/
1259: block_searching_lines << line
1260: contains_lines << line if contains_flag
1261:
1262: level_depth += 1 if block_start?(line)
1263: level_depth -= 1 if block_end?(line)
1264: if level_depth >= 0
1265: next false
1266: end
1267:
1268: # "procedure_code" is formatted.
1269: # ":nodoc:" flag is checked.
1270: #
1271: procedure_code = block_searching_lines.join("\n")
1272: procedure_code = remove_empty_head_lines(procedure_code)
1273: if procedure_trailing =~ /^!:nodoc:/
1274: # next loop to search next block
1275: level_depth = 0
1276: block_searching_flag = nil
1277: block_searching_lines = []
1278: pre_comment = []
1279: procedure_trailing = ""
1280: procedure_name = ""
1281: procedure_params = ""
1282: procedure_prefix = ""
1283: procedure_result_arg = ""
1284: procedure_type = ""
1285: contains_lines = []
1286: contains_flag = nil
1287: next false
1288: end
1289:
1290: # AnyMethod is created, and added to container
1291: #
1292: subroutine_function = nil
1293: if block_searching_flag == :subroutine
1294: subroutine_prefix = procedure_prefix
1295: subroutine_name = procedure_name
1296: subroutine_params = procedure_params
1297: subroutine_trailing = procedure_trailing
1298: subroutine_code = procedure_code
1299:
1300: subroutine_comment = COMMENTS_ARE_UPPER ?
1301: pre_comment.join("\n") + "\n" + subroutine_trailing :
1302: subroutine_trailing + "\n" + subroutine_code.sub(/^.*$\n/i, '')
1303: subroutine = AnyMethod.new("subroutine", subroutine_name)
1304: parse_subprogram(subroutine, subroutine_params,
1305: subroutine_comment, subroutine_code,
1306: before_contains_code, nil, subroutine_prefix)
1307: progress "s"
1308: @stats.num_methods += 1
1309: container.add_method subroutine
1310: subroutine_function = subroutine
1311:
1312: namelist_comment =
1313: find_namelists(subroutine, subroutine_code, before_contains_code)
1314: subroutine.comment << namelist_comment if namelist_comment
1315:
1316: elsif block_searching_flag == :function
1317: function_prefix = procedure_prefix
1318: function_type = procedure_type
1319: function_name = procedure_name
1320: function_params_org = procedure_params
1321: function_result_arg = procedure_result_arg
1322: function_trailing = procedure_trailing
1323: function_code_org = procedure_code
1324:
1325: function_comment = COMMENTS_ARE_UPPER ?
1326: pre_comment.join("\n") + "\n" + function_trailing :
1327: function_trailing + "\n " + function_code_org.sub(/^.*$\n/i, '')
1328:
1329: function_code = "#{function_code_org}"
1330: if function_type
1331: function_code << "\n" + function_type + " :: " + function_result_arg
1332: end
1333:
1334: function_params =
1335: function_params_org.sub(/^\(/, "\(#{function_result_arg}, ")
1336:
1337: function = AnyMethod.new("function", function_name)
1338: parse_subprogram(function, function_params,
1339: function_comment, function_code,
1340: before_contains_code, true, function_prefix)
1341:
1342: # Specific modification due to function
1343: function.params.sub!(/\(\s*?#{function_result_arg}\s*?,\s*?/, "\( ")
1344: function.params << " result(" + function_result_arg + ")"
1345: function.start_collecting_tokens
1346: function.add_token Token.new(1,1).set_text(function_code_org)
1347:
1348: progress "f"
1349: @stats.num_methods += 1
1350: container.add_method function
1351: subroutine_function = function
1352:
1353: namelist_comment =
1354: find_namelists(function, function_code, before_contains_code)
1355: function.comment << namelist_comment if namelist_comment
1356:
1357: end
1358:
1359: # The visibility of procedure is specified
1360: #
1361: set_visibility(container, procedure_name,
1362: visibility_default, @@public_methods)
1363:
1364: # The alias for this procedure from external modules
1365: #
1366: check_external_aliases(procedure_name,
1367: subroutine_function.params,
1368: subroutine_function.comment, subroutine_function) if external
1369: check_public_methods(subroutine_function, container.name)
1370:
1371:
1372: # contains_lines are parsed as private procedures
1373: if contains_flag
1374: parse_program_or_module(container,
1375: contains_lines.join("\n"), :private)
1376: end
1377:
1378: # next loop to search next block
1379: level_depth = 0
1380: block_searching_flag = nil
1381: block_searching_lines = []
1382: pre_comment = []
1383: procedure_trailing = ""
1384: procedure_name = ""
1385: procedure_params = ""
1386: procedure_prefix = ""
1387: procedure_result_arg = ""
1388: contains_lines = []
1389: contains_flag = nil
1390: next false
1391: } # End of remaining_lines.collect!{|line|
1392:
1393: # Array remains_lines is converted to String remains_code again
1394: #
1395: remaining_code = remaining_lines.join("\n")
1396:
1397: #
1398: # Parse interface
1399: #
1400: interface_scope = false
1401: generic_name = ""
1402: interface_code.split("\n").each{ |line|
1403: if /^\s*?
1404: interface(
1405: \s+\w+|
1406: \s+operator\s*?\(.*?\)|
1407: \s+assignment\s*?\(\s*?=\s*?\)
1408: )?
1409: \s*?(!.*?)?$
1410: /ix =~ line
1411: generic_name = $1 ? $1.strip.chomp : nil
1412: interface_trailing = $2 || "!"
1413: interface_scope = true
1414: interface_scope = false if interface_trailing =~ /!:nodoc:/
1415: # if generic_name =~ /operator\s*?\((.*?)\)/i
1416: # operator_name = $1
1417: # if operator_name && !operator_name.empty?
1418: # generic_name = "#{operator_name}"
1419: # end
1420: # end
1421: # if generic_name =~ /assignment\s*?\((.*?)\)/i
1422: # assignment_name = $1
1423: # if assignment_name && !assignment_name.empty?
1424: # generic_name = "#{assignment_name}"
1425: # end
1426: # end
1427: end
1428: if /^\s*?end\s+interface/i =~ line
1429: interface_scope = false
1430: generic_name = nil
1431: end
1432: # internal alias
1433: if interface_scope && /^\s*?module\s+procedure\s+(.*?)(!.*?)?$/i =~ line
1434: procedures = $1.strip.chomp
1435: procedures_trailing = $2 || "!"
1436: next if procedures_trailing =~ /!:nodoc:/
1437: procedures.split(",").each{ |proc|
1438: proc.strip!
1439: proc.chomp!
1440: next if generic_name == proc || !generic_name
1441: old_meth = container.find_symbol(proc, nil, @options_ignore_case)
1442: next if !old_meth
1443: nolink = old_meth.visibility == :private ? true : nil
1444: nolink = nil if @options.show_all
1445: new_meth =
1446: initialize_external_method(generic_name, proc,
1447: old_meth.params, nil,
1448: old_meth.comment,
1449: old_meth.clone.token_stream[0].text,
1450: true, nolink)
1451: new_meth.singleton = old_meth.singleton
1452:
1453: progress "i"
1454: @stats.num_methods += 1
1455: container.add_method new_meth
1456:
1457: set_visibility(container, generic_name, visibility_default, @@public_methods)
1458:
1459: check_public_methods(new_meth, container.name)
1460:
1461: }
1462: end
1463:
1464: # external aliases
1465: if interface_scope
1466: # subroutine
1467: proc = nil
1468: params = nil
1469: procedures_trailing = nil
1470: if line =~ /^\s*?
1471: (recursive|pure|elemental)?\s*?
1472: subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
1473: /ix
1474: proc = $2.chomp.strip
1475: proc_name = generic_name || proc
1476: params = $3 || ""
1477: procedures_trailing = $4 || "!"
1478:
1479: # function
1480: elsif line =~ /^\s*?
1481: (recursive|pure|elemental)?\s*?
1482: (
1483: character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1484: | type\s*?\([\w\s]+?\)\s+
1485: | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1486: | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1487: | double\s+precision\s+
1488: | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1489: | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1490: )?
1491: function\s+(\w+)\s*?
1492: (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
1493: /ix
1494: proc = $8.chomp.strip
1495: proc_name = generic_name || proc
1496: params = $9 || ""
1497: procedures_trailing = $12 || "!"
1498: else
1499: next
1500: end
1501: next if procedures_trailing =~ /!:nodoc:/
1502: indicated_method = nil
1503: indicated_file = nil
1504: TopLevel.all_files.each do |name, toplevel|
1505: indicated_method = toplevel.find_local_symbol(proc, @options_ignore_case)
1506: indicated_file = name
1507: break if indicated_method
1508: end
1509:
1510: if indicated_method
1511: external_method =
1512: initialize_external_method(proc_name, proc,
1513: indicated_method.params,
1514: indicated_file,
1515: indicated_method.comment)
1516:
1517: progress "e"
1518: @stats.num_methods += 1
1519: container.add_method external_method
1520: set_visibility(container, proc_name, visibility_default, @@public_methods)
1521: if !container.include_requires?(indicated_file, @options_ignore_case)
1522: container.add_require(Require.new(indicated_file, ""))
1523: end
1524: check_public_methods(external_method, container.name)
1525:
1526: else
1527: @@external_aliases << {
1528: "new_name" => proc_name,
1529: "old_name" => proc,
1530: "file_or_module" => container,
1531: "visibility" => find_visibility(container, proc_name, @@public_methods) || visibility_default
1532: }
1533: end
1534: end
1535:
1536: } if interface_code # End of interface_code.split("\n").each ...
1537:
1538: #
1539: # Already imported methods are removed from @@public_methods.
1540: # Remainders are assumed to be imported from other modules.
1541: #
1542: # 既に参照済みのメソッドは @@public_methods から取り除く.
1543: # 残りは外部モジュールからの参照と仮定する.
1544: #
1545: @@public_methods.delete_if{ |method| method["entity_is_discovered"]}
1546:
1547: @@public_methods.each{ |pub_meth|
1548: next unless pub_meth["file_or_module"].name == container.name
1549: pub_meth["used_modules"].each{ |used_mod|
1550: TopLevel.all_classes_and_modules.each{ |modules|
1551: if modules.name == used_mod ||
1552: modules.name.upcase == used_mod.upcase &&
1553: @options_ignore_case
1554: modules.method_list.each{ |meth|
1555: if meth.name == pub_meth["name"] ||
1556: meth.name.upcase == pub_meth["name"].upcase &&
1557: @options_ignore_case
1558: new_meth = initialize_public_method(meth,
1559: modules.name)
1560: if pub_meth["local_name"]
1561: new_meth.name = pub_meth["local_name"]
1562: end
1563: progress "e"
1564: @stats.num_methods += 1
1565: container.add_method new_meth
1566: end
1567: }
1568: end
1569: }
1570: }
1571: }
1572:
1573: container
1574: end
Parse arguments, comment, code of subroutine and function. Return AnyMethod object.
# File parsers/parse_f95.rb, line 1580
1580: def parse_subprogram(subprogram, params, comment, code,
1581: before_contains=nil, function=nil, prefix=nil)
1582: subprogram.singleton = false
1583: prefix = "" if !prefix
1584: arguments = params.sub(/\(/, "").sub(/\)/, "").split(",") if params
1585: args_comment, params_opt =
1586: find_arguments(arguments, code.sub(/^s*?contains\s*?(!.*?)?$.*/im, ""),
1587: nil, nil, true)
1588: params_opt = "( " + params_opt + " ) " if params_opt
1589: subprogram.params = params_opt || ""
1590:
1591: block_comment = find_comments comment
1592: if function
1593: subprogram.comment = "<b><em> Function </em></b> :: <em>#{prefix}</em>\n"
1594: else
1595: subprogram.comment = "<b><em> Subroutine </em></b> :: <em>#{prefix}</em>\n"
1596: end
1597: subprogram.comment << args_comment if args_comment
1598: subprogram.comment << block_comment if block_comment
1599:
1600: # For output source code
1601: subprogram.start_collecting_tokens
1602: subprogram.add_token Token.new(1,1).set_text(code)
1603:
1604: subprogram
1605: end
Parse visibility
# File parsers/parse_f95.rb, line 1894
1894: def parse_visibility(code, default, container)
1895: result = []
1896: visibility_default = default || :public
1897:
1898: used_modules = []
1899: container.includes.each{|i| used_modules << i.name} if container
1900:
1901: remaining_code = code.gsub(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
1902: remaining_code.split("\n").each{ |line|
1903: if /^\s*?private\s*?$/ =~ line
1904: visibility_default = :private
1905: break
1906: end
1907: } if remaining_code
1908:
1909: remaining_code.split("\n").each{ |line|
1910: if /^\s*?private\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
1911: methods = $2.sub(/!.*$/, '')
1912: methods.split(",").each{ |meth|
1913: meth.sub!(/!.*$/, '')
1914: meth.gsub!(/:/, '')
1915: result << {
1916: "name" => meth.chomp.strip,
1917: "visibility" => :private,
1918: "used_modules" => used_modules.clone,
1919: "file_or_module" => container,
1920: "entity_is_discovered" => nil,
1921: "local_name" => nil
1922: }
1923: }
1924: elsif /^\s*?public\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
1925: methods = $2.sub(/!.*$/, '')
1926: methods.split(",").each{ |meth|
1927: meth.sub!(/!.*$/, '')
1928: meth.gsub!(/:/, '')
1929: result << {
1930: "name" => meth.chomp.strip,
1931: "visibility" => :public,
1932: "used_modules" => used_modules.clone,
1933: "file_or_module" => container,
1934: "entity_is_discovered" => nil,
1935: "local_name" => nil
1936: }
1937: }
1938: end
1939: } if remaining_code
1940:
1941: if container
1942: result.each{ |vis_info|
1943: vis_info["parent"] = container.name
1944: }
1945: end
1946:
1947: return visibility_default, result
1948: end
# File parsers/parse_f95.rb, line 1834
1834: def progress(char)
1835: unless @options.quiet
1836: @progress.print(char)
1837: @progress.flush
1838: end
1839: end
Empty lines in header are removed
# File parsers/parse_f95.rb, line 2317
2317: def remove_empty_head_lines(text)
2318: return "" unless text
2319: lines = text.split("\n")
2320: header = true
2321: lines.delete_if{ |line|
2322: header = false if /\S/ =~ line
2323: header && /^\s*?$/ =~ line
2324: }
2325: lines.join("\n")
2326: end
header marker "=", "==", … are removed
# File parsers/parse_f95.rb, line 2330
2330: def remove_header_marker(text)
2331: return text.gsub(/^\s?(=+)/, '<tt></tt>\1')
2332: end
# File parsers/parse_f95.rb, line 2334
2334: def remove_private_comments(body)
2335: body.gsub!(/^(\s*)!--\s*?$.*?^\s*!\+\+\s*?$/m, '\\1!')
2336: return body
2337: end
Remove "Alias for" in end of comments
# File parsers/parse_f95.rb, line 2296
2296: def remove_trailing_alias(text)
2297: return "" if !text
2298: lines = text.split("\n").reverse
2299: comment_block = Array.new
2300: checked = false
2301: lines.each do |line|
2302: if !checked
2303: if /^\s?#{INTERNAL_ALIAS_MES}/ =~ line ||
2304: /^\s?#{EXTERNAL_ALIAS_MES}/ =~ line
2305: checked = true
2306: next
2307: end
2308: end
2309: comment_block.unshift line
2310: end
2311: nice_lines = comment_block.join("\n")
2312: nice_lines ||= ""
2313: return nice_lines
2314: end
devine code constructs
# File parsers/parse_f95.rb, line 713
713: def scan
714:
715: # remove private comment
716: remaining_code = remove_private_comments(@body)
717:
718: # continuation lines are united to one line
719: remaining_code = united_to_one_line(remaining_code)
720:
721: # semicolons are replaced to line feed
722: remaining_code = semicolon_to_linefeed(remaining_code)
723:
724: # collect comment for file entity
725: whole_comment, remaining_code = collect_first_comment(remaining_code)
726: @top_level.comment = whole_comment
727:
728: # String "remaining_code" is converted to Array "remaining_lines"
729: remaining_lines = remaining_code.split("\n")
730:
731: # "module" or "program" parts are parsed (new)
732: #
733: level_depth = 0
734: block_searching_flag = nil
735: block_searching_lines = []
736: pre_comment = []
737: module_program_trailing = ""
738: module_program_name = ""
739: other_block_level_depth = 0
740: other_block_searching_flag = nil
741: remaining_lines.collect!{|line|
742: if !block_searching_flag && !other_block_searching_flag
743: if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i
744: block_searching_flag = :module
745: block_searching_lines << line
746: module_program_name = $1
747: module_program_trailing = find_comments($2)
748: next false
749: elsif line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i ||
750: line =~ /^\s*?\w/ && !block_start?(line)
751: block_searching_flag = :program
752: block_searching_lines << line
753: module_program_name = $1 || ""
754: module_program_trailing = find_comments($2)
755: next false
756:
757: elsif block_start?(line)
758: other_block_searching_flag = true
759: next line
760:
761: elsif line =~ /^\s*?!\s?(.*)/
762: pre_comment << line
763: next line
764: else
765: pre_comment = []
766: next line
767: end
768: elsif other_block_searching_flag
769: other_block_level_depth += 1 if block_start?(line)
770: other_block_level_depth -= 1 if block_end?(line)
771: if other_block_level_depth < 0
772: other_block_level_depth = 0
773: other_block_searching_flag = nil
774: end
775: next line
776: end
777:
778: block_searching_lines << line
779: level_depth += 1 if block_start?(line)
780: level_depth -= 1 if block_end?(line)
781: if level_depth >= 0
782: next false
783: end
784:
785: # "module_program_code" is formatted.
786: # ":nodoc:" flag is checked.
787: #
788: module_program_code = block_searching_lines.join("\n")
789: module_program_code = remove_empty_head_lines(module_program_code)
790: if module_program_trailing =~ /^:nodoc:/
791: # next loop to search next block
792: level_depth = 0
793: block_searching_flag = false
794: block_searching_lines = []
795: pre_comment = []
796: next false
797: end
798:
799: # NormalClass is created, and added to @top_level
800: #
801: if block_searching_flag == :module
802: module_name = module_program_name
803: module_code = module_program_code
804: module_trailing = module_program_trailing
805: progress "m"
806: @stats.num_modules += 1
807: f9x_module = @top_level.add_module NormalClass, module_name
808: f9x_module.record_location @top_level
809:
810: #
811: # Add provided modules information to @top_level comment
812: #
813: provided_modules = []
814: provided_mes_line_num = nil
815: top_level_comment_lines = []
816: line_num = 0
817: @top_level.comment.split("\n").each{|line|
818: top_level_comment_lines << line
819: line_num += 1
820: next if line.empty?
821: if !provided_mes_line_num && /^\s?#{PROVIDED_MODULES_MES}/ =~ line
822: provided_mes_line_num = line_num
823: next
824: end
825: if provided_mes_line_num
826: if /^\s?\*\s+<b>(\w+)<\/b>/ =~ line
827: provided_modules << $1
828: else
829: provided_mes_line_num = nil
830: end
831: end
832: }
833: line_num = 0
834: if provided_mes_line_num
835: top_level_comment_lines.collect!{ |line|
836: line_num += 1
837: if line_num < provided_mes_line_num
838: line
839: else
840: nil
841: end
842: }
843: top_level_comment_lines.delete_if{|line| !line }
844: end
845: top_level_comment_lines << "\n" + PROVIDED_MODULES_MES + "."
846: if provided_mes_line_num
847: top_level_comment_lines[-1].sub!(/\.$/, '')
848: top_level_comment_lines[-1] << "s."
849: end
850: provided_modules.each{ |mod|
851: top_level_comment_lines << "* <b>" + mod + "</b>"
852: }
853: top_level_comment_lines << "* <b>" + module_name + "</b>"
854: @top_level.comment = top_level_comment_lines.join("\n")
855:
856: #
857: # Information about the module is parsed
858: #
859: f9x_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) +
860: "\n" + module_trailing : module_trailing + "\n" +
861: find_comments(module_code.sub(/^.*$\n/i, ''))
862: f9x_module.comment = f9x_comment
863: parse_program_or_module(f9x_module, module_code)
864:
865: TopLevel.all_files.each do |name, toplevel|
866: if toplevel.include_includes?(module_name, @options_ignore_case)
867: if !toplevel.include_requires?(@file_name, @options_ignore_case)
868: toplevel.add_require(Require.new(@file_name, ""))
869: end
870: end
871: toplevel.each_classmodule{|m|
872: if m.include_includes?(module_name, @options_ignore_case)
873: if !m.include_requires?(@file_name, @options_ignore_case)
874: m.add_require(Require.new(@file_name, ""))
875: end
876: end
877: }
878: end
879:
880: namelist_comment =
881: find_namelists(f9x_module, before_contains(module_code))
882: f9x_module.comment << namelist_comment if namelist_comment
883:
884: elsif block_searching_flag == :program
885: program_name = module_program_name
886: program_name = "main_program" if program_name.empty?
887: program_code = module_program_code
888: program_trailing = module_program_trailing
889: program_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) +
890: "\n" + program_trailing : program_trailing + "\n" +
891: find_comments(program_code.sub(/^.*$\n/i, ''))
892:
893: progress "p"
894: @stats.num_methods += 1
895: f9x_mainprogram = AnyMethod.new("main_program", program_name)
896: f9x_mainprogram.singleton = false
897: f9x_mainprogram.comment = "<b><em> Main Program </em></b> :: <tt></tt>\n"
898: f9x_mainprogram.comment << program_comment
899: f9x_mainprogram.params = ""
900:
901: # For output source code
902: f9x_mainprogram.start_collecting_tokens
903: f9x_mainprogram.add_token Token.new(1,1).set_text(program_code)
904:
905: @top_level.add_method f9x_mainprogram
906: parse_program_or_module(@top_level, program_code, :private)
907:
908: namelist_comment = find_namelists(f9x_mainprogram, program_code)
909: f9x_mainprogram.comment << namelist_comment if namelist_comment
910: end
911:
912: # next loop to search next block
913: level_depth = 0
914: block_searching_flag = false
915: block_searching_lines = []
916: pre_comment = []
917: next false
918: }
919:
920: remaining_lines.delete_if{ |line|
921: line == false
922: }
923:
924: # External subprograms and functions are parsed
925: #
926: # 単一のファイル内において program や module に格納されない,
927: # 外部サブルーチン, 外部関数部分の解析.
928: #
929: parse_program_or_module(@top_level, remaining_lines.join("\n"),
930: :public, true)
931:
932: @top_level
933: end
Semicolons are replaced to line feed.
# File parsers/parse_f95.rb, line 2199
2199: def semicolon_to_linefeed(text)
2200: return "" unless text
2201: lines = text.split("\n")
2202: lines.collect!{ |line|
2203: indent_space = ""
2204: if line =~ /^(\s+)/
2205: indent_space = $1
2206: end
2207: words = line.split("")
2208: commentout = false
2209: squote = false ; dquote = false
2210: words.collect! { |char|
2211: if !(squote) && !(dquote) && !(commentout)
2212: case char
2213: when "!" ; commentout = true ; next char
2214: when "\""; dquote = true ; next char
2215: when "\'"; squote = true ; next char
2216: when ";" ; "\n"+indent_space
2217: else next char
2218: end
2219: elsif commentout
2220: next char
2221: elsif squote
2222: case char
2223: when "\'"; squote = false ; next char
2224: else next char
2225: end
2226: elsif dquote
2227: case char
2228: when "\""; dquote = false ; next char
2229: else next char
2230: end
2231: end
2232: }
2233: words.join("")
2234: }
2235: return lines.join("\n")
2236: end
Set visibility
"subname" element of "visibility_info" is deleted.
# File parsers/parse_f95.rb, line 1955
1955: def set_visibility(container, subname, visibility_default, visibility_info)
1956: return unless container || subname || visibility_default || visibility_info
1957: not_found = true
1958: visibility_info.collect!{ |info|
1959: if info["name"] == subname ||
1960: @options_ignore_case && info["name"].upcase == subname.upcase
1961: if info["file_or_module"].name == container.name
1962: container.set_visibility_for([subname], info["visibility"])
1963: info["entity_is_discovered"] = true
1964: not_found = false
1965: end
1966: end
1967: info
1968: }
1969: if not_found
1970: return container.set_visibility_for([subname], visibility_default)
1971: else
1972: return container
1973: end
1974: 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 2074
2074: def united_to_one_line(f90src, delete_space=true)
2075: return "" unless f90src
2076: lines = f90src.split("\n")
2077: previous_continuing = false
2078: now_continuing = false
2079: body = ""
2080: squote = false ; dquote = false
2081: lines.each{ |line|
2082: words = line.split("")
2083: next if words.empty? && previous_continuing
2084: commentout = false
2085: brank_flag = true ; brank_char = ""
2086: ignore = false
2087: words.collect! { |char|
2088: if previous_continuing && brank_flag
2089: now_continuing = true
2090: ignore = true
2091: case char
2092: when "!" ; break
2093: when " " ; brank_char << char ; next ""
2094: when "&"
2095: brank_flag = false
2096: now_continuing = false
2097: next ""
2098: else
2099: brank_flag = false
2100: now_continuing = false
2101: ignore = false
2102: next brank_char + char
2103: end
2104: end
2105: ignore = false
2106:
2107: if now_continuing && !(squote) && !(dquote)
2108: next ""
2109: elsif !(squote) && !(dquote) && !(commentout)
2110: case char
2111: when "!" ; commentout = true ; next char
2112: when "\""; dquote = true ; next char
2113: when "\'"; squote = true ; next char
2114: when "&" ; now_continuing = true ; next ""
2115: else next char
2116: end
2117: elsif commentout
2118: next char
2119: elsif squote
2120: case char
2121: when "\'"; squote = false ; now_continuing = false ; next char
2122: when "&" ; now_continuing = true ; next ""
2123: else next char
2124: end
2125: elsif dquote
2126: case char
2127: when "\""; dquote = false ; now_continuing = false ; next char
2128: when "&" ; now_continuing = true ; next ""
2129: else next char
2130: end
2131: end
2132: }
2133: if !ignore && !previous_continuing || !brank_flag
2134: if previous_continuing
2135: if delete_space
2136: joined_words = words.join("")
2137: body = body.rstrip + " " + joined_words.lstrip
2138: else
2139: body << words.join("")
2140: end
2141: else
2142: body << "\n" + words.join("")
2143: end
2144: end
2145: previous_continuing = now_continuing ? true : false
2146: now_continuing = false
2147: }
2148: return body
2149: end