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