Class RDoc::Fortran95parser
In: lib/rdoc/parsers/parse_f95.rb
Parent: Object

See rdoc/parsers/parse_f95.rb

Methods

Classes and Modules

Class RDoc::Fortran95parser::Fortran95Definition

Constants

COMMENTS_ARE_UPPER = false  
"false":Comments are below source code
"true" :Comments are upper source code
INTERNAL_ALIAS_MES = "Alias for"   Internal alias message
EXTERNAL_ALIAS_MES = "The entity is"   External alias message

Public Class methods

prepare to parse a Fortran 95 file

[Source]

     # File lib/rdoc/parsers/parse_f95.rb, line 195
195:     def initialize(top_level, file_name, body, options, stats)
196:       @body = body
197:       @stats = stats
198:       @file_name  = file_name
199:       @options = options
200:       @top_level = top_level
201:       @progress = $stderr unless options.quiet
202:     end

Public Instance methods

define code constructs

[Source]

     # File lib/rdoc/parsers/parse_f95.rb, line 205
205:     def scan
206: 
207:       # remove private comment
208:       remaining_code = remove_private_comments(@body)
209: 
210:       # continuation lines are united to one line
211:       remaining_code = united_to_one_line(remaining_code)
212: 
213:       # semicolons are replaced to line feed
214:       remaining_code = semicolon_to_linefeed(remaining_code)
215: 
216:       # collect comment for file entity
217:       whole_comment, remaining_code = collect_first_comment(remaining_code)
218:       @top_level.comment = whole_comment
219: 
220:       # String "remaining_code" is converted to Array "remaining_lines"
221:       remaining_lines = remaining_code.split("\n")
222: 
223:       # "module" or "program" parts are parsed (new)
224:       #
225:       level_depth = 0
226:       block_searching_flag = nil
227:       block_searching_lines = []
228:       pre_comment = []
229:       module_program_trailing = ""
230:       module_program_name = ""
231:       other_block_level_depth = 0
232:       other_block_searching_flag = nil
233:       remaining_lines.collect!{|line|
234:         if !block_searching_flag && !other_block_searching_flag
235:           if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i
236:             block_searching_flag = :module
237:             block_searching_lines << line
238:             module_program_name = $1
239:             module_program_trailing = find_comments($2)
240:             next false
241:           elsif line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i ||
242:                  line =~ /^\s*?\w/ && !block_start?(line)
243:             block_searching_flag = :program
244:             block_searching_lines << line
245:             module_program_name = $1 || ""
246:             module_program_trailing = find_comments($2)
247:             next false
248: 
249:           elsif block_start?(line)
250:             other_block_searching_flag = true
251:             next line
252: 
253:           elsif line =~ /^\s*?!\s?(.*)/
254:             pre_comment << line
255:             next line
256:           else
257:             pre_comment = []
258:             next line
259:           end
260:         elsif other_block_searching_flag
261:           other_block_level_depth += 1 if block_start?(line)
262:           other_block_level_depth -= 1 if block_end?(line)
263:           if other_block_level_depth < 0
264:             other_block_level_depth = 0
265:             other_block_searching_flag = nil
266:           end
267:           next line
268:         end
269: 
270:         block_searching_lines << line
271:         level_depth += 1 if block_start?(line)
272:         level_depth -= 1 if block_end?(line)
273:         if level_depth >= 0
274:           next false
275:         end
276: 
277:         # "module_program_code" is formatted.
278:         # ":nodoc:" flag is checked.
279:         #
280:         module_program_code = block_searching_lines.join("\n")
281:         module_program_code = remove_empty_head_lines(module_program_code)
282:         if module_program_trailing =~ /^:nodoc:/
283:           # next loop to search next block
284:           level_depth = 0
285:           block_searching_flag = false
286:           block_searching_lines = []
287:           pre_comment = []
288:           next false
289:         end
290: 
291:         # NormalClass is created, and added to @top_level
292:         #
293:         if block_searching_flag == :module
294:           module_name = module_program_name
295:           module_code = module_program_code
296:           module_trailing = module_program_trailing
297:           progress "m"
298:           @stats.num_modules += 1
299:           f9x_module = @top_level.add_module NormalClass, module_name
300:           f9x_module.record_location @top_level
301: 
302:           f9x_comment = COMMENTS_ARE_UPPER ? 
303:             find_comments(pre_comment.join("\n"))  + "\n" + module_trailing :
304:               module_trailing + "\n" + find_comments(module_code.sub(/^.*$\n/i, ''))
305:           f9x_module.comment = f9x_comment
306:           parse_program_or_module(f9x_module, module_code)
307: 
308:           TopLevel.all_files.each do |name, toplevel|
309:             if toplevel.include_includes?(module_name, @options.ignore_case)
310:               if !toplevel.include_requires?(@file_name, @options.ignore_case)
311:                 toplevel.add_require(Require.new(@file_name, ""))
312:               end
313:             end
314:             toplevel.each_classmodule{|m|
315:               if m.include_includes?(module_name, @options.ignore_case)
316:                 if !m.include_requires?(@file_name, @options.ignore_case)
317:                   m.add_require(Require.new(@file_name, ""))
318:                 end
319:               end
320:             }
321:           end
322:         elsif block_searching_flag == :program
323:           program_name = module_program_name
324:           program_code = module_program_code
325:           program_trailing = module_program_trailing
326:           progress "p"
327:           program_comment = COMMENTS_ARE_UPPER ? 
328:             find_comments(pre_comment.join("\n")) + "\n" + program_trailing : 
329:               program_trailing + "\n" + find_comments(program_code.sub(/^.*$\n/i, ''))
330:           program_comment = "\n\n= <i>Program</i> <tt>#{program_name}</tt>\n\n" \
331:                             + program_comment
332:           @top_level.comment << program_comment
333:           parse_program_or_module(@top_level, program_code, :private)
334:         end
335: 
336:         # next loop to search next block
337:         level_depth = 0
338:         block_searching_flag = false
339:         block_searching_lines = []
340:         pre_comment = []
341:         next false
342:       }
343: 
344:       remaining_lines.delete_if{ |line|
345:         line == false
346:       }
347: 
348:       # External subprograms and functions are parsed
349:       #
350:       parse_program_or_module(@top_level, remaining_lines.join("\n"),
351:                               :public, true)
352: 
353:       @top_level
354:     end

Private Instance methods

Which "line" is end of block (module, program, block data, subroutine, function) statement ?

[Source]

      # File lib/rdoc/parsers/parse_f95.rb, line 1582
1582:     def block_end?(line)
1583:       return nil if !line
1584: 
1585:       if line =~ /^\s*?end\s*?(!.*?)?$/i                 ||
1586:           line =~ /^\s*?end\s+module(\s+\w+)?\s*?(!.*?)?$/i       ||
1587:           line =~ /^\s*?end\s+program(\s+\w+)?\s*?(!.*?)?$/i      ||
1588:           line =~ /^\s*?end\s+block\s+data(\s+\w+)?\s*?(!.*?)?$/i  ||
1589:           line =~ /^\s*?end\s+subroutine(\s+\w+)?\s*?(!.*?)?$/i   ||
1590:           line =~ /^\s*?end\s+function(\s+\w+)?\s*?(!.*?)?$/i
1591:         return true
1592:       end
1593: 
1594:       return nil
1595:     end

Which "line" is start of block (module, program, block data, subroutine, function) statement ?

[Source]

      # File lib/rdoc/parsers/parse_f95.rb, line 1546
1546:     def block_start?(line)
1547:       return nil if !line
1548: 
1549:       if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i    ||
1550:           line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i  ||
1551:           line =~ /^\s*?block\s+data(\s+\w+)?\s*?(!.*?)?$/i     ||
1552:           line =~ \
1553:                   /^\s*?
1554:                    (recursive|pure|elemental)?\s*?
1555:                    subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
1556:                   /ix ||
1557:           line =~ \
1558:                   /^\s*?
1559:                    (recursive|pure|elemental)?\s*?
1560:                    (
1561:                        character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1562:                      | type\s*?\([\w\s]+?\)\s+
1563:                      | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1564:                      | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1565:                      | double\s+precision\s+
1566:                      | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1567:                      | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1568:                    )?
1569:                    function\s+(\w+)\s*?
1570:                    (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
1571:                   /ix
1572:         return true
1573:       end
1574: 
1575:       return nil
1576:     end

Check external aliases

[Source]

      # File lib/rdoc/parsers/parse_f95.rb, line 1330
1330:     def check_external_aliases(subname, params, comment, test=nil)
1331:       @@external_aliases.each{ |alias_item|
1332:         if subname == alias_item["old_name"] ||
1333:                     subname.upcase == alias_item["old_name"].upcase &&
1334:                             @options.ignore_case
1335: 
1336:           new_meth = initialize_external_method(alias_item["new_name"], 
1337:                                                 subname, params, @file_name, 
1338:                                                 comment)
1339:           new_meth.visibility = alias_item["visibility"]
1340: 
1341:           progress "e"
1342:           @stats.num_methods += 1
1343:           alias_item["file_or_module"].add_method(new_meth)
1344: 
1345:           if !alias_item["file_or_module"].include_requires?(@file_name, @options.ignore_case)
1346:             alias_item["file_or_module"].add_require(Require.new(@file_name, ""))
1347:           end
1348:         end
1349:       }
1350:     end

Check public_methods

[Source]

      # File lib/rdoc/parsers/parse_f95.rb, line 1355
1355:     def check_public_methods(method, parent)
1356:       return if !method || !parent
1357:       @@public_methods.each{ |alias_item|
1358:         parent_is_used_module = nil
1359:         alias_item["used_modules"].each{ |used_module|
1360:           if used_module == parent ||
1361:               used_module.upcase == parent.upcase &&
1362:               @options.ignore_case
1363:             parent_is_used_module = true
1364:           end
1365:         }
1366:         next if !parent_is_used_module
1367: 
1368:         if method.name == alias_item["name"] ||
1369:             method.name.upcase == alias_item["name"].upcase &&
1370:             @options.ignore_case
1371: 
1372:           new_meth = initialize_public_method(method, parent)
1373:           if alias_item["local_name"]
1374:             new_meth.name = alias_item["local_name"]
1375:           end
1376: 
1377:           progress "e"
1378:           @stats.num_methods += 1
1379:           alias_item["file_or_module"].add_method new_meth
1380:         end
1381:       }
1382:     end

Collect comment for file entity

[Source]

      # File lib/rdoc/parsers/parse_f95.rb, line 1039
1039:     def collect_first_comment(body)
1040:       comment = ""
1041:       not_comment = ""
1042:       comment_start = false
1043:       comment_end   = false
1044:       body.split("\n").each{ |line|
1045:         if comment_end
1046:           not_comment << line
1047:           not_comment << "\n"
1048:         elsif /^\s*?!\s?(.*)$/i =~ line
1049:           comment_start = true
1050:           comment << $1
1051:           comment << "\n"
1052:         elsif /^\s*?$/i =~ line
1053:           comment_end = true if comment_start && COMMENTS_ARE_UPPER
1054:         else
1055:           comment_end = true
1056:           not_comment << line
1057:           not_comment << "\n"
1058:         end
1059:       }
1060:       return comment, not_comment
1061:     end

Comment out checker

[Source]

      # File lib/rdoc/parsers/parse_f95.rb, line 1477
1477:     def comment_out?(line)
1478:       return nil unless line
1479:       commentout = false
1480:       squote = false ; dquote = false
1481:       line.split("").each { |char|
1482:         if !(squote) && !(dquote)
1483:           case char
1484:           when "!" ; commentout = true ; break
1485:           when "\""; dquote = true
1486:           when "\'"; squote = true
1487:           else next
1488:           end
1489:         elsif squote
1490:           case char
1491:           when "\'"; squote = false
1492:           else next
1493:           end
1494:         elsif dquote
1495:           case char
1496:           when "\""; dquote = false
1497:           else next
1498:           end
1499:         end
1500:       }
1501:       return commentout
1502:     end

Continuous line checker

[Source]

      # File lib/rdoc/parsers/parse_f95.rb, line 1463
1463:     def continuous_line?(line)
1464:       continuous = false
1465:       if /&\s*?(!.*)?$/ =~ line
1466:         continuous = true
1467:         if comment_out?($~.pre_match)
1468:           continuous = false
1469:         end
1470:       end
1471:       return continuous
1472:     end

Parse string argument "text", and Return Array of Fortran95Definition object

[Source]

      # File lib/rdoc/parsers/parse_f95.rb, line 1712
1712:     def definition_info(text)
1713:       return nil unless text
1714:       lines = "#{text}"
1715:       defs = Array.new
1716:       comment = ""
1717:       trailing_comment = ""
1718:       under_comment_valid = false
1719:       lines.split("\n").each{ |line|
1720:         if /^\s*?!\s?(.*)/ =~ line
1721:           if COMMENTS_ARE_UPPER
1722:             comment << remove_header_marker($1)
1723:             comment << "\n"
1724:           elsif defs[-1] && under_comment_valid
1725:             defs[-1].comment << "\n"
1726:             defs[-1].comment << remove_header_marker($1)
1727:           end
1728:           next
1729:         elsif /^\s*?$/ =~ line
1730:           comment = ""
1731:           under_comment_valid = false
1732:           next
1733:         end
1734:         type = ""
1735:         characters = ""
1736:         if line =~ /^\s*?
1737:                     (
1738:                         character\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
1739:                       | type\s*?\([\w\s]+?\)[\s\,]*
1740:                       | integer\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
1741:                       | real\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
1742:                       | double\s+precision[\s\,]*
1743:                       | logical\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
1744:                       | complex\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
1745:                     )
1746:                     (.*?::)?
1747:                     (.+)$
1748:                    /ix
1749:           characters = $8
1750:           type = $1
1751:           type << $7.gsub(/::/, '').gsub(/^\s*?\,/, '') if $7
1752:         else
1753:           under_comment_valid = false
1754:           next
1755:         end
1756:         squote = false ; dquote = false ; bracket = 0
1757:         iniflag = false; commentflag = false
1758:         varname = "" ; arraysuffix = "" ; inivalue = ""
1759:         start_pos = defs.size
1760:         characters.split("").each { |char|
1761:           if !(squote) && !(dquote) && bracket <= 0 && !(iniflag) && !(commentflag)
1762:             case char
1763:             when "!" ; commentflag = true
1764:             when "(" ; bracket += 1       ; arraysuffix = char
1765:             when "\""; dquote = true
1766:             when "\'"; squote = true
1767:             when "=" ; iniflag = true     ; inivalue << char
1768:             when ","
1769:               defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
1770:               varname = "" ; arraysuffix = "" ; inivalue = ""
1771:               under_comment_valid = true
1772:             when " " ; next
1773:             else     ; varname << char
1774:             end
1775:           elsif commentflag
1776:             comment << remove_header_marker(char)
1777:             trailing_comment << remove_header_marker(char)
1778:           elsif iniflag
1779:             if dquote
1780:               case char
1781:               when "\"" ; dquote = false ; inivalue << char
1782:               else      ; inivalue << char
1783:               end
1784:             elsif squote
1785:               case char
1786:               when "\'" ; squote = false ; inivalue << char
1787:               else      ; inivalue << char
1788:               end
1789:             elsif bracket > 0
1790:               case char
1791:               when "(" ; bracket += 1 ; inivalue << char
1792:               when ")" ; bracket -= 1 ; inivalue << char
1793:               else     ; inivalue << char
1794:               end
1795:             else
1796:               case char
1797:               when ","
1798:                 defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
1799:                 varname = "" ; arraysuffix = "" ; inivalue = ""
1800:                 iniflag = false
1801:                 under_comment_valid = true
1802:               when "(" ; bracket += 1 ; inivalue << char
1803:               when "\""; dquote = true  ; inivalue << char
1804:               when "\'"; squote = true  ; inivalue << char
1805:               when "!" ; commentflag = true
1806:               else     ; inivalue << char
1807:               end
1808:             end
1809:           elsif !(squote) && !(dquote) && bracket > 0
1810:             case char
1811:             when "(" ; bracket += 1 ; arraysuffix << char
1812:             when ")" ; bracket -= 1 ; arraysuffix << char
1813:             else     ; arraysuffix << char
1814:             end
1815:           elsif squote
1816:             case char
1817:             when "\'"; squote = false ; inivalue << char
1818:             else     ; inivalue << char
1819:             end
1820:           elsif dquote
1821:             case char
1822:             when "\""; dquote = false ; inivalue << char
1823:             else     ; inivalue << char
1824:             end
1825:           end
1826:         }
1827:         defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
1828:         if trailing_comment =~ /^:nodoc:/
1829:           defs[start_pos..-1].collect!{ |defitem|
1830:             defitem.nodoc = true
1831:           }
1832:         end
1833:         varname = "" ; arraysuffix = "" ; inivalue = ""
1834:         comment = ""
1835:         under_comment_valid = true
1836:         trailing_comment = ""
1837:       }
1838:       return defs
1839:     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 example, optional arguments are parenthetic as "[arg]".

[Source]

      # File lib/rdoc/parsers/parse_f95.rb, line 1070
1070:     def find_arguments(args, text, all=nil, indent=nil, modified_params=nil)
1071:       return unless args || all
1072:       indent = "" unless indent
1073:       args = ["all"] if all
1074:       params = "" if modified_params
1075:       comma = ""
1076:       return unless text
1077:       args_rdocforms = "\n"
1078:       remaining_lines = "#{text}"
1079:       definitions = definition_info(remaining_lines)
1080:       args.each{ |arg|
1081:         arg.strip!
1082:         arg.chomp!
1083:         definitions.each { |defitem|
1084:           if arg == defitem.varname.strip.chomp || all
1085:             args_rdocforms << "\n\#{indent}<tt><b>\#{defitem.varname.chomp.strip}\#{defitem.arraysuffix}</b> \#{defitem.inivalue}</tt> ::\n\#{indent}   <tt>\#{defitem.types.chomp.strip}</tt>\n"
1086:             if !defitem.comment.chomp.strip.empty?
1087:               comment = ""
1088:               defitem.comment.split("\n").each{ |line|
1089:                 comment << "       " + line + "\n"
1090:               }
1091:               args_rdocforms << "\n\#{indent}   <tt></tt> ::\n\#{indent}       <tt></tt>\n\#{indent}       \#{comment.chomp.strip}\n"
1092:             end
1093: 
1094:             if modified_params
1095:               if defitem.include_attr?("optional")
1096:                 params << "#{comma}[#{arg}]"
1097:               else
1098:                 params << "#{comma}#{arg}"
1099:               end
1100:               comma = ", "
1101:             end
1102:           end
1103:         }
1104:       }
1105:       if modified_params
1106:         return args_rdocforms, params
1107:       else
1108:         return args_rdocforms
1109:       end
1110:     end

Comments just after module or subprogram, or arguments are returned. If "COMMENTS_ARE_UPPER" is true, comments just before modules or subprograms are returned

[Source]

      # File lib/rdoc/parsers/parse_f95.rb, line 1151
1151:     def find_comments text
1152:       return "" unless text
1153:       lines = text.split("\n")
1154:       lines.reverse! if COMMENTS_ARE_UPPER
1155:       comment_block = Array.new
1156:       lines.each do |line|
1157:         break if line =~ /^\s*?\w/ || line =~ /^\s*?$/
1158:         if COMMENTS_ARE_UPPER
1159:           comment_block.unshift line.sub(/^\s*?!\s?/,"")
1160:         else
1161:           comment_block.push line.sub(/^\s*?!\s?/,"")
1162:         end
1163:       end
1164:       nice_lines = comment_block.join("\n").split "\n\s*?\n"
1165:       nice_lines[0] ||= ""
1166:       nice_lines.shift
1167:     end

Return comments of definitions of namelists

[Source]

      # File lib/rdoc/parsers/parse_f95.rb, line 1125
1125:     def find_namelists(text, before_contains=nil)
1126:       return nil if !text
1127:       result = ""
1128:       lines = "#{text}"
1129:       before_contains = "" if !before_contains
1130:       while lines =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)$/i
1131:         lines = $~.post_match
1132:         nml_comment = COMMENTS_ARE_UPPER ? 
1133:             find_comments($~.pre_match) : find_comments($~.post_match)
1134:         nml_name = $1
1135:         nml_args = $2.split(",")
1136:         result << "\n\n=== NAMELIST <tt><b>" + nml_name + "</tt></b>\n\n"
1137:         result << nml_comment + "\n" if nml_comment
1138:         if lines.split("\n")[0] =~ /^\//i
1139:           lines = "namelist " + lines
1140:         end
1141:         result << find_arguments(nml_args, "#{text}" + "\n" + before_contains)
1142:       end
1143:       return result
1144:     end

Find visibility

[Source]

      # File lib/rdoc/parsers/parse_f95.rb, line 1314
1314:     def find_visibility(container, subname, visibility_info)
1315:       return nil if !subname || !visibility_info
1316:       visibility_info.each{ |info|
1317:         if info["name"] == subname ||
1318:             @options.ignore_case && info["name"].upcase == subname.upcase
1319:           if info["parent"] == container.name
1320:             return info["visibility"]
1321:           end
1322:         end
1323:       }
1324:       return nil
1325:     end

Create method for external alias

If argument "internal" is true, file is ignored.

[Source]

      # File lib/rdoc/parsers/parse_f95.rb, line 1196
1196:     def initialize_external_method(new, old, params, file, comment, token=nil,
1197:                                    internal=nil, nolink=nil)
1198:       return nil unless new || old
1199: 
1200:       if internal
1201:         external_alias_header = "#{INTERNAL_ALIAS_MES} "
1202:         external_alias_text   = external_alias_header + old 
1203:       elsif file
1204:         external_alias_header = "#{EXTERNAL_ALIAS_MES} "
1205:         external_alias_text   = external_alias_header + file + "#" + old
1206:       else
1207:         return nil
1208:       end
1209:       external_meth = AnyMethod.new(external_alias_text, new)
1210:       external_meth.singleton    = false
1211:       external_meth.params       = params
1212:       external_comment = remove_trailing_alias(comment) + "\n\n" if comment
1213:       external_meth.comment = external_comment || ""
1214:       if nolink && token
1215:         external_meth.start_collecting_tokens
1216:         external_meth.add_token Token.new(1,1).set_text(token)
1217:       else
1218:         external_meth.comment << external_alias_text
1219:       end
1220: 
1221:       return external_meth
1222:     end

Create method for internal alias

[Source]

      # File lib/rdoc/parsers/parse_f95.rb, line 1179
1179:     def initialize_public_method(method, parent)
1180:       return if !method || !parent
1181: 
1182:       new_meth = AnyMethod.new("External Alias for module", method.name)
1183:       new_meth.singleton    = method.singleton
1184:       new_meth.params       = method.params.clone
1185:       new_meth.comment      = remove_trailing_alias(method.comment.clone)
1186:       new_meth.comment      << "\n\n#{EXTERNAL_ALIAS_MES} #{parent.strip.chomp}\##{method.name}"
1187: 
1188:       return new_meth
1189:     end

[Source]

      # File lib/rdoc/parsers/parse_f95.rb, line 358
 358:     def parse_program_or_module(container, code,
 359:                                 visibility=:public, external=nil)
 360:       return unless container
 361:       return unless code
 362:       remaining_lines = code.split("\n")
 363:       remaining_code = "#{code}"
 364: 
 365:       #
 366:       # Parse variables before "contains" in module
 367:       #
 368:       level_depth = 0
 369:       before_contains_lines = []
 370:       before_contains_code = nil
 371:       before_contains_flag = nil
 372:       remaining_lines.each{ |line|
 373:         if !before_contains_flag
 374:           if line =~ /^\s*?module\s+\w+\s*?(!.*?)?$/i
 375:             before_contains_flag = true
 376:           end
 377:         else
 378:           break if line =~ /^\s*?contains\s*?(!.*?)?$/i
 379:           level_depth += 1 if block_start?(line)
 380:           level_depth -= 1 if block_end?(line)
 381:           break if level_depth < 0
 382:           before_contains_lines << line
 383:         end
 384:       }
 385:       before_contains_code = before_contains_lines.join("\n")
 386:       if before_contains_code
 387:         before_contains_code.gsub!(/^\s*?interface\s+.*?\s+end\s+interface.*?$/im, "")
 388:         before_contains_code.gsub!(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
 389:       end
 390: 
 391:       #
 392:       # Parse global "use"
 393:       #
 394:       use_check_code = "#{before_contains_code}"
 395:       cascaded_modules_list = []
 396:       while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i
 397:         use_check_code = $~.pre_match
 398:         use_check_code << $~.post_match
 399:         used_mod_name = $1.strip.chomp
 400:         used_list = $2 || ""
 401:         used_trailing = $3 || ""
 402:         next if used_trailing =~ /!:nodoc:/
 403:         if !container.include_includes?(used_mod_name, @options.ignore_case)
 404:           progress "."
 405:           container.add_include Include.new(used_mod_name, "")
 406:         end
 407:         if ! (used_list =~ /\,\s*?only\s*?:/i )
 408:           cascaded_modules_list << "\#" + used_mod_name
 409:         end
 410:       end
 411: 
 412:       #
 413:       # Parse public and private, and store information.
 414:       # This information is used when "add_method" and
 415:       # "set_visibility_for" are called.
 416:       #
 417:       visibility_default, visibility_info = 
 418:                 parse_visibility(remaining_lines.join("\n"), visibility, container)
 419:       @@public_methods.concat visibility_info
 420:       if visibility_default == :public
 421:         if !cascaded_modules_list.empty?
 422:           cascaded_modules = 
 423:             Attr.new("Cascaded Modules",
 424:                      "Imported modules all of whose components are published again",
 425:                      "",
 426:                      cascaded_modules_list.join(", "))
 427:           container.add_attribute(cascaded_modules)
 428:         end
 429:       end
 430: 
 431:       #
 432:       # Check rename elements
 433:       #
 434:       use_check_code = "#{before_contains_code}"
 435:       while use_check_code =~ /^\s*?use\s+(\w+)\s*?\,(.+)$/i
 436:         use_check_code = $~.pre_match
 437:         use_check_code << $~.post_match
 438:         used_mod_name = $1.strip.chomp
 439:         used_elements = $2.sub(/\s*?only\s*?:\s*?/i, '')
 440:         used_elements.split(",").each{ |used|
 441:           if /\s*?(\w+)\s*?=>\s*?(\w+)\s*?/ =~ used
 442:             local = $1
 443:             org = $2
 444:             @@public_methods.collect!{ |pub_meth|
 445:               if local == pub_meth["name"] ||
 446:                   local.upcase == pub_meth["name"].upcase &&
 447:                   @options.ignore_case
 448:                 pub_meth["name"] = org
 449:                 pub_meth["local_name"] = local
 450:               end
 451:               pub_meth
 452:             }
 453:           end
 454:         }
 455:       end
 456: 
 457:       #
 458:       # Parse private "use"
 459:       #
 460:       use_check_code = remaining_lines.join("\n")
 461:       while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i
 462:         use_check_code = $~.pre_match
 463:         use_check_code << $~.post_match
 464:         used_mod_name = $1.strip.chomp
 465:         used_trailing = $3 || ""
 466:         next if used_trailing =~ /!:nodoc:/
 467:         if !container.include_includes?(used_mod_name, @options.ignore_case)
 468:           progress "."
 469:           container.add_include Include.new(used_mod_name, "")
 470:         end
 471:       end
 472: 
 473:       container.each_includes{ |inc|
 474:         TopLevel.all_files.each do |name, toplevel|
 475:           indicated_mod = toplevel.find_symbol(inc.name,
 476:                                                nil, @options.ignore_case)
 477:           if indicated_mod
 478:             indicated_name = indicated_mod.parent.file_relative_name
 479:             if !container.include_requires?(indicated_name, @options.ignore_case)
 480:               container.add_require(Require.new(indicated_name, ""))
 481:             end
 482:             break
 483:           end
 484:         end
 485:       }
 486: 
 487:       #
 488:       # Parse derived-types definitions
 489:       #
 490:       derived_types_comment = ""
 491:       remaining_code = remaining_lines.join("\n")
 492:       while remaining_code =~ /^\s*?
 493:                                     type[\s\,]+(public|private)?\s*?(::)?\s*?
 494:                                     (\w+)\s*?(!.*?)?$
 495:                                     (.*?)
 496:                                     ^\s*?end\s+type.*?$
 497:                               /imx
 498:         remaining_code = $~.pre_match
 499:         remaining_code << $~.post_match
 500:         typename = $3.chomp.strip
 501:         type_elements = $5 || ""
 502:         type_code = remove_empty_head_lines($&)
 503:         type_trailing = find_comments($4)
 504:         next if type_trailing =~ /^:nodoc:/
 505:         type_visibility = $1
 506:         type_comment = COMMENTS_ARE_UPPER ? 
 507:           find_comments($~.pre_match) + "\n" + type_trailing :
 508:             type_trailing + "\n" + find_comments(type_code.sub(/^.*$\n/i, ''))
 509:         type_element_visibility_public = true
 510:         type_code.split("\n").each{ |line|
 511:           if /^\s*?private\s*?$/ =~ line
 512:             type_element_visibility_public = nil
 513:             break
 514:           end
 515:         } if type_code
 516: 
 517:         args_comment = ""
 518:         type_args_info = nil
 519: 
 520:         if @options.show_all
 521:           args_comment = find_arguments(nil, type_code, true)
 522:         else
 523:           type_public_args_list = []
 524:           type_args_info = definition_info(type_code)
 525:           type_args_info.each{ |arg|
 526:             arg_is_public = type_element_visibility_public
 527:             arg_is_public = true if arg.include_attr?("public")
 528:             arg_is_public = nil if arg.include_attr?("private")
 529:             type_public_args_list << arg.varname if arg_is_public
 530:           }
 531:           args_comment = find_arguments(type_public_args_list, type_code)
 532:         end
 533: 
 534:         type = AnyMethod.new("type #{typename}", typename)
 535:         type.singleton = false
 536:         type.params = ""
 537:         type.comment = "<b><em> Derived Type </em></b> :: <tt></tt>\n"
 538:         type.comment << args_comment if args_comment
 539:         type.comment << type_comment if type_comment
 540:         progress "t"
 541:         @stats.num_methods += 1
 542:         container.add_method type
 543: 
 544:         set_visibility(container, typename, visibility_default, @@public_methods)
 545: 
 546:         if type_visibility
 547:           type_visibility.gsub!(/\s/,'')
 548:           type_visibility.gsub!(/\,/,'')
 549:           type_visibility.gsub!(/:/,'')
 550:           type_visibility.downcase!
 551:           if type_visibility == "public"
 552:             container.set_visibility_for([typename], :public)
 553:           elsif type_visibility == "private"
 554:             container.set_visibility_for([typename], :private)
 555:           end
 556:         end
 557: 
 558:         check_public_methods(type, container.name)
 559: 
 560:         if @options.show_all
 561:           derived_types_comment << ", " unless derived_types_comment.empty?
 562:           derived_types_comment << typename
 563:         else
 564:           if type.visibility == :public
 565:           derived_types_comment << ", " unless derived_types_comment.empty?
 566:           derived_types_comment << typename
 567:           end
 568:         end
 569: 
 570:       end
 571: 
 572:       if !derived_types_comment.empty?
 573:         derived_types_table = 
 574:           Attr.new("Derived Types", "Derived_Types", "", 
 575:                    derived_types_comment)
 576:         container.add_attribute(derived_types_table)
 577:       end
 578: 
 579:       #
 580:       # move interface scope
 581:       #
 582:       interface_code = ""
 583:       while remaining_code =~ /^\s*?
 584:                                    interface(
 585:                                               \s+\w+                      |
 586:                                               \s+operator\s*?\(.*?\)       |
 587:                                               \s+assignment\s*?\(\s*?=\s*?\)
 588:                                             )?\s*?$
 589:                                    (.*?)
 590:                                    ^\s*?end\s+interface.*?$
 591:                               /imx
 592:         interface_code << remove_empty_head_lines($&) + "\n"
 593:         remaining_code = $~.pre_match
 594:         remaining_code << $~.post_match
 595:       end
 596: 
 597:       #
 598:       # Parse global constants or variables in modules
 599:       #
 600:       const_var_defs = definition_info(before_contains_code)
 601:       const_var_defs.each{|defitem|
 602:         next if defitem.nodoc
 603:         const_or_var_type = "Variable"
 604:         const_or_var_progress = "v"
 605:         if defitem.include_attr?("parameter")
 606:           const_or_var_type = "Constant"
 607:           const_or_var_progress = "c"
 608:         end
 609:         const_or_var = AnyMethod.new(const_or_var_type, defitem.varname)
 610:         const_or_var.singleton = false
 611:         const_or_var.params = ""
 612:         self_comment = find_arguments([defitem.varname], before_contains_code)
 613:         const_or_var.comment = "<b><em>" + const_or_var_type + "</em></b> :: <tt></tt>\n"
 614:         const_or_var.comment << self_comment if self_comment
 615:         progress const_or_var_progress
 616:         @stats.num_methods += 1
 617:         container.add_method const_or_var
 618: 
 619:         set_visibility(container, defitem.varname, visibility_default, @@public_methods)
 620: 
 621:         if defitem.include_attr?("public")
 622:           container.set_visibility_for([defitem.varname], :public)
 623:         elsif defitem.include_attr?("private")
 624:           container.set_visibility_for([defitem.varname], :private)
 625:         end
 626: 
 627:         check_public_methods(const_or_var, container.name)
 628: 
 629:       } if const_var_defs
 630: 
 631:       remaining_lines = remaining_code.split("\n")
 632: 
 633:       # "subroutine" or "function" parts are parsed (new)
 634:       #
 635:       level_depth = 0
 636:       block_searching_flag = nil
 637:       block_searching_lines = []
 638:       pre_comment = []
 639:       procedure_trailing = ""
 640:       procedure_name = ""
 641:       procedure_params = ""
 642:       procedure_prefix = ""
 643:       procedure_result_arg = ""
 644:       procedure_type = ""
 645:       contains_lines = []
 646:       contains_flag = nil
 647:       remaining_lines.collect!{|line|
 648:         if !block_searching_flag
 649:           # subroutine
 650:           if line =~ /^\s*?
 651:                            (recursive|pure|elemental)?\s*?
 652:                            subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
 653:                      /ix
 654:             block_searching_flag = :subroutine
 655:             block_searching_lines << line
 656: 
 657:             procedure_name = $2.chomp.strip
 658:             procedure_params = $3 || ""
 659:             procedure_prefix = $1 || ""
 660:             procedure_trailing = $4 || "!"
 661:             next false
 662: 
 663:           # function
 664:           elsif line =~ /^\s*?
 665:                          (recursive|pure|elemental)?\s*?
 666:                          (
 667:                              character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
 668:                            | type\s*?\([\w\s]+?\)\s+
 669:                            | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
 670:                            | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
 671:                            | double\s+precision\s+
 672:                            | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
 673:                            | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
 674:                          )?
 675:                          function\s+(\w+)\s*?
 676:                          (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
 677:                         /ix
 678:             block_searching_flag = :function
 679:             block_searching_lines << line
 680: 
 681:             procedure_prefix = $1 || ""
 682:             procedure_type = $2 ? $2.chomp.strip : nil
 683:             procedure_name = $8.chomp.strip
 684:             procedure_params = $9 || ""
 685:             procedure_result_arg = $11 ? $11.chomp.strip : procedure_name
 686:             procedure_trailing = $12 || "!"
 687:             next false
 688:           elsif line =~ /^\s*?!\s?(.*)/
 689:             pre_comment << line
 690:             next line
 691:           else
 692:             pre_comment = []
 693:             next line
 694:           end
 695:         end
 696:         contains_flag = true if line =~ /^\s*?contains\s*?(!.*?)?$/
 697:         block_searching_lines << line
 698:         contains_lines << line if contains_flag
 699: 
 700:         level_depth += 1 if block_start?(line)
 701:         level_depth -= 1 if block_end?(line)
 702:         if level_depth >= 0
 703:           next false
 704:         end
 705: 
 706:         # "procedure_code" is formatted.
 707:         # ":nodoc:" flag is checked.
 708:         #
 709:         procedure_code = block_searching_lines.join("\n")
 710:         procedure_code = remove_empty_head_lines(procedure_code)
 711:         if procedure_trailing =~ /^!:nodoc:/
 712:           # next loop to search next block
 713:           level_depth = 0
 714:           block_searching_flag = nil
 715:           block_searching_lines = []
 716:           pre_comment = []
 717:           procedure_trailing = ""
 718:           procedure_name = ""
 719:           procedure_params = ""
 720:           procedure_prefix = ""
 721:           procedure_result_arg = ""
 722:           procedure_type = ""
 723:           contains_lines = []
 724:           contains_flag = nil
 725:           next false
 726:         end
 727: 
 728:         # AnyMethod is created, and added to container
 729:         #
 730:         subroutine_function = nil
 731:         if block_searching_flag == :subroutine
 732:           subroutine_prefix   = procedure_prefix
 733:           subroutine_name     = procedure_name
 734:           subroutine_params   = procedure_params
 735:           subroutine_trailing = procedure_trailing
 736:           subroutine_code     = procedure_code
 737: 
 738:           subroutine_comment = COMMENTS_ARE_UPPER ? 
 739:             pre_comment.join("\n") + "\n" + subroutine_trailing : 
 740:               subroutine_trailing + "\n" + subroutine_code.sub(/^.*$\n/i, '')
 741:           subroutine = AnyMethod.new("subroutine", subroutine_name)
 742:           parse_subprogram(subroutine, subroutine_params,
 743:                            subroutine_comment, subroutine_code,
 744:                            before_contains_code, nil, subroutine_prefix)
 745:           progress "s"
 746:           @stats.num_methods += 1
 747:           container.add_method subroutine
 748:           subroutine_function = subroutine
 749: 
 750:         elsif block_searching_flag == :function
 751:           function_prefix     = procedure_prefix
 752:           function_type       = procedure_type
 753:           function_name       = procedure_name
 754:           function_params_org = procedure_params
 755:           function_result_arg = procedure_result_arg
 756:           function_trailing   = procedure_trailing
 757:           function_code_org   = procedure_code
 758: 
 759:           function_comment = COMMENTS_ARE_UPPER ?
 760:             pre_comment.join("\n") + "\n" + function_trailing :
 761:               function_trailing + "\n " + function_code_org.sub(/^.*$\n/i, '')
 762: 
 763:           function_code = "#{function_code_org}"
 764:           if function_type
 765:             function_code << "\n" + function_type + " :: " + function_result_arg
 766:           end
 767: 
 768:           function_params =
 769:             function_params_org.sub(/^\(/, "\(#{function_result_arg}, ")
 770: 
 771:           function = AnyMethod.new("function", function_name)
 772:           parse_subprogram(function, function_params,
 773:                            function_comment, function_code,
 774:                            before_contains_code, true, function_prefix)
 775: 
 776:           # Specific modification due to function
 777:           function.params.sub!(/\(\s*?#{function_result_arg}\s*?,\s*?/, "\( ")
 778:           function.params << " result(" + function_result_arg + ")"
 779:           function.start_collecting_tokens
 780:           function.add_token Token.new(1,1).set_text(function_code_org)
 781: 
 782:           progress "f"
 783:           @stats.num_methods += 1
 784:           container.add_method function
 785:           subroutine_function = function
 786: 
 787:         end
 788: 
 789:         # The visibility of procedure is specified
 790:         #
 791:         set_visibility(container, procedure_name, 
 792:                        visibility_default, @@public_methods)
 793: 
 794:         # The alias for this procedure from external modules
 795:         #
 796:         check_external_aliases(procedure_name,
 797:                                subroutine_function.params,
 798:                                subroutine_function.comment, subroutine_function) if external
 799:         check_public_methods(subroutine_function, container.name)
 800: 
 801: 
 802:         # contains_lines are parsed as private procedures
 803:         if contains_flag
 804:           parse_program_or_module(container,
 805:                                   contains_lines.join("\n"), :private)
 806:         end
 807: 
 808:         # next loop to search next block
 809:         level_depth = 0
 810:         block_searching_flag = nil
 811:         block_searching_lines = []
 812:         pre_comment = []
 813:         procedure_trailing = ""
 814:         procedure_name = ""
 815:         procedure_params = ""
 816:         procedure_prefix = ""
 817:         procedure_result_arg = ""
 818:         contains_lines = []
 819:         contains_flag = nil
 820:         next false
 821:       } # End of remaining_lines.collect!{|line|
 822: 
 823:       # Array remains_lines is converted to String remains_code again
 824:       #
 825:       remaining_code = remaining_lines.join("\n")
 826: 
 827:       #
 828:       # Parse interface
 829:       #
 830:       interface_scope = false
 831:       generic_name = ""
 832:       interface_code.split("\n").each{ |line|
 833:         if /^\s*?
 834:                  interface(
 835:                             \s+\w+|
 836:                             \s+operator\s*?\(.*?\)|
 837:                             \s+assignment\s*?\(\s*?=\s*?\)
 838:                           )?
 839:                  \s*?(!.*?)?$
 840:            /ix =~ line
 841:           generic_name = $1 ? $1.strip.chomp : nil
 842:           interface_trailing = $2 || "!"
 843:           interface_scope = true
 844:           interface_scope = false if interface_trailing =~ /!:nodoc:/
 845: #          if generic_name =~ /operator\s*?\((.*?)\)/i
 846: #            operator_name = $1
 847: #            if operator_name && !operator_name.empty?
 848: #              generic_name = "#{operator_name}"
 849: #            end
 850: #          end
 851: #          if generic_name =~ /assignment\s*?\((.*?)\)/i
 852: #            assignment_name = $1
 853: #            if assignment_name && !assignment_name.empty?
 854: #              generic_name = "#{assignment_name}"
 855: #            end
 856: #          end
 857:         end
 858:         if /^\s*?end\s+interface/i =~ line
 859:           interface_scope = false
 860:           generic_name = nil
 861:         end
 862:         # internal alias
 863:         if interface_scope && /^\s*?module\s+procedure\s+(.*?)(!.*?)?$/i =~ line
 864:           procedures = $1.strip.chomp
 865:           procedures_trailing = $2 || "!"
 866:           next if procedures_trailing =~ /!:nodoc:/
 867:           procedures.split(",").each{ |proc|
 868:             proc.strip!
 869:             proc.chomp!
 870:             next if generic_name == proc || !generic_name
 871:             old_meth = container.find_symbol(proc, nil, @options.ignore_case)
 872:             next if !old_meth
 873:             nolink = old_meth.visibility == :private ? true : nil
 874:             nolink = nil if @options.show_all
 875:             new_meth = 
 876:                initialize_external_method(generic_name, proc, 
 877:                                           old_meth.params, nil, 
 878:                                           old_meth.comment, 
 879:                                           old_meth.clone.token_stream[0].text, 
 880:                                           true, nolink)
 881:             new_meth.singleton = old_meth.singleton
 882: 
 883:             progress "i"
 884:             @stats.num_methods += 1
 885:             container.add_method new_meth
 886: 
 887:             set_visibility(container, generic_name, visibility_default, @@public_methods)
 888: 
 889:             check_public_methods(new_meth, container.name)
 890: 
 891:           }
 892:         end
 893: 
 894:         # external aliases
 895:         if interface_scope
 896:           # subroutine
 897:           proc = nil
 898:           params = nil
 899:           procedures_trailing = nil
 900:           if line =~ /^\s*?
 901:                            (recursive|pure|elemental)?\s*?
 902:                            subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
 903:                      /ix
 904:             proc = $2.chomp.strip
 905:             generic_name = proc unless generic_name
 906:             params = $3 || ""
 907:             procedures_trailing = $4 || "!"
 908: 
 909:           # function
 910:           elsif line =~ /^\s*?
 911:                          (recursive|pure|elemental)?\s*?
 912:                          (
 913:                              character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
 914:                            | type\s*?\([\w\s]+?\)\s+
 915:                            | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
 916:                            | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
 917:                            | double\s+precision\s+
 918:                            | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
 919:                            | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
 920:                          )?
 921:                          function\s+(\w+)\s*?
 922:                          (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
 923:                         /ix
 924:             proc = $8.chomp.strip
 925:             generic_name = proc unless generic_name
 926:             params = $9 || ""
 927:             procedures_trailing = $12 || "!"
 928:           else
 929:             next
 930:           end
 931:           next if procedures_trailing =~ /!:nodoc:/
 932:           indicated_method = nil
 933:           indicated_file   = nil
 934:           TopLevel.all_files.each do |name, toplevel|
 935:             indicated_method = toplevel.find_local_symbol(proc, @options.ignore_case)
 936:             indicated_file = name
 937:             break if indicated_method
 938:           end
 939: 
 940:           if indicated_method
 941:             external_method = 
 942:               initialize_external_method(generic_name, proc, 
 943:                                          indicated_method.params, 
 944:                                          indicated_file, 
 945:                                          indicated_method.comment)
 946: 
 947:             progress "e"
 948:             @stats.num_methods += 1
 949:             container.add_method external_method
 950:             set_visibility(container, generic_name, visibility_default, @@public_methods)
 951:             if !container.include_requires?(indicated_file, @options.ignore_case)
 952:               container.add_require(Require.new(indicated_file, ""))
 953:             end
 954:             check_public_methods(external_method, container.name)
 955: 
 956:           else
 957:             @@external_aliases << {
 958:               "new_name"  => generic_name,
 959:               "old_name"  => proc,
 960:               "file_or_module" => container,
 961:               "visibility" => find_visibility(container, generic_name, @@public_methods) || visibility_default
 962:             }
 963:           end
 964:         end
 965: 
 966:       } if interface_code # End of interface_code.split("\n").each ...
 967: 
 968:       #
 969:       # Already imported methods are removed from @@public_methods.
 970:       # Remainders are assumed to be imported from other modules.
 971:       #
 972:       @@public_methods.delete_if{ |method| method["entity_is_discovered"]}
 973: 
 974:       @@public_methods.each{ |pub_meth|
 975:         next unless pub_meth["file_or_module"].name == container.name
 976:         pub_meth["used_modules"].each{ |used_mod|
 977:           TopLevel.all_classes_and_modules.each{ |modules|
 978:             if modules.name == used_mod ||
 979:                 modules.name.upcase == used_mod.upcase &&
 980:                 @options.ignore_case
 981:               modules.method_list.each{ |meth|
 982:                 if meth.name == pub_meth["name"] ||
 983:                     meth.name.upcase == pub_meth["name"].upcase &&
 984:                     @options.ignore_case
 985:                   new_meth = initialize_public_method(meth,
 986:                                                       modules.name)
 987:                   if pub_meth["local_name"]
 988:                     new_meth.name = pub_meth["local_name"]
 989:                   end
 990:                   progress "e"
 991:                   @stats.num_methods += 1
 992:                   container.add_method new_meth
 993:                 end
 994:               }
 995:             end
 996:           }
 997:         }
 998:       }
 999: 
1000:       container
1001:     end

Parse arguments, comment, code of subroutine and function. Return AnyMethod object.

[Source]

      # File lib/rdoc/parsers/parse_f95.rb, line 1007
1007:     def parse_subprogram(subprogram, params, comment, code, 
1008:                          before_contains=nil, function=nil, prefix=nil)
1009:       subprogram.singleton = false
1010:       prefix = "" if !prefix
1011:       arguments = params.sub(/\(/, "").sub(/\)/, "").split(",") if params
1012:       args_comment, params_opt = 
1013:         find_arguments(arguments, code.sub(/^s*?contains\s*?(!.*?)?$.*/im, ""),
1014:                        nil, nil, true)
1015:       params_opt = "( " + params_opt + " ) " if params_opt
1016:       subprogram.params = params_opt || ""
1017:       namelist_comment = find_namelists(code, before_contains)
1018: 
1019:       block_comment = find_comments comment
1020:       if function
1021:         subprogram.comment = "<b><em> Function </em></b> :: <em>#{prefix}</em>\n"
1022:       else
1023:         subprogram.comment = "<b><em> Subroutine </em></b> :: <em>#{prefix}</em>\n"
1024:       end
1025:       subprogram.comment << args_comment if args_comment
1026:       subprogram.comment << block_comment if block_comment
1027:       subprogram.comment << namelist_comment if namelist_comment
1028: 
1029:       # For output source code
1030:       subprogram.start_collecting_tokens
1031:       subprogram.add_token Token.new(1,1).set_text(code)
1032: 
1033:       subprogram
1034:     end

Parse visibility

[Source]

      # File lib/rdoc/parsers/parse_f95.rb, line 1229
1229:     def parse_visibility(code, default, container)
1230:       result = []
1231:       visibility_default = default || :public
1232: 
1233:       used_modules = []
1234:       container.includes.each{|i| used_modules << i.name} if container
1235: 
1236:       remaining_code = code.gsub(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
1237:       remaining_code.split("\n").each{ |line|
1238:         if /^\s*?private\s*?$/ =~ line
1239:           visibility_default = :private
1240:           break
1241:         end
1242:       } if remaining_code
1243: 
1244:       remaining_code.split("\n").each{ |line|
1245:         if /^\s*?private\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
1246:           methods = $2.sub(/!.*$/, '')
1247:           methods.split(",").each{ |meth|
1248:             meth.sub!(/!.*$/, '')
1249:             meth.gsub!(/:/, '')
1250:             result << {
1251:               "name" => meth.chomp.strip,
1252:               "visibility" => :private,
1253:               "used_modules" => used_modules.clone,
1254:               "file_or_module" => container,
1255:               "entity_is_discovered" => nil,
1256:               "local_name" => nil
1257:             }
1258:           }
1259:         elsif /^\s*?public\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
1260:           methods = $2.sub(/!.*$/, '')
1261:           methods.split(",").each{ |meth|
1262:             meth.sub!(/!.*$/, '')
1263:             meth.gsub!(/:/, '')
1264:             result << {
1265:               "name" => meth.chomp.strip,
1266:               "visibility" => :public,
1267:               "used_modules" => used_modules.clone,
1268:               "file_or_module" => container,
1269:               "entity_is_discovered" => nil,
1270:               "local_name" => nil
1271:             }
1272:           }
1273:         end
1274:       } if remaining_code
1275: 
1276:       if container
1277:         result.each{ |vis_info|
1278:           vis_info["parent"] = container.name
1279:         }
1280:       end
1281: 
1282:       return visibility_default, result
1283:     end

[Source]

      # File lib/rdoc/parsers/parse_f95.rb, line 1169
1169:     def progress(char)
1170:       unless @options.quiet
1171:         @progress.print(char)
1172:         @progress.flush
1173:       end
1174:     end

Empty lines in header are removed

[Source]

      # File lib/rdoc/parsers/parse_f95.rb, line 1621
1621:     def remove_empty_head_lines(text)
1622:       return "" unless text
1623:       lines = text.split("\n")
1624:       header = true
1625:       lines.delete_if{ |line|
1626:         header = false if /\S/ =~ line
1627:         header && /^\s*?$/ =~ line
1628:       }
1629:       lines.join("\n")
1630:     end

header marker "=", "==", … are removed

[Source]

      # File lib/rdoc/parsers/parse_f95.rb, line 1634
1634:     def remove_header_marker(text)
1635:       return text.gsub(/^\s?(=+)/, '<tt></tt>\1')
1636:     end

[Source]

      # File lib/rdoc/parsers/parse_f95.rb, line 1638
1638:     def remove_private_comments(body)
1639:       body.gsub!(/^\s*!--\s*?$.*?^\s*!\+\+\s*?$/m, '')
1640:       return body
1641:     end

Remove "Alias for" in end of comments

[Source]

      # File lib/rdoc/parsers/parse_f95.rb, line 1600
1600:     def remove_trailing_alias(text)
1601:       return "" if !text
1602:       lines = text.split("\n").reverse
1603:       comment_block = Array.new
1604:       checked = false
1605:       lines.each do |line|
1606:         if !checked 
1607:           if /^\s?#{INTERNAL_ALIAS_MES}/ =~ line ||
1608:               /^\s?#{EXTERNAL_ALIAS_MES}/ =~ line
1609:             checked = true
1610:             next
1611:           end
1612:         end
1613:         comment_block.unshift line
1614:       end
1615:       nice_lines = comment_block.join("\n")
1616:       nice_lines ||= ""
1617:       return nice_lines
1618:     end

Semicolons are replaced to line feed.

[Source]

      # File lib/rdoc/parsers/parse_f95.rb, line 1507
1507:     def semicolon_to_linefeed(text)
1508:       return "" unless text
1509:       lines = text.split("\n")
1510:       lines.collect!{ |line|
1511:         words = line.split("")
1512:         commentout = false
1513:         squote = false ; dquote = false
1514:         words.collect! { |char|
1515:           if !(squote) && !(dquote) && !(commentout)
1516:             case char
1517:             when "!" ; commentout = true ; next char
1518:             when "\""; dquote = true     ; next char
1519:             when "\'"; squote = true     ; next char
1520:             when ";" ;                     "\n"
1521:             else next char
1522:             end
1523:           elsif commentout
1524:             next char
1525:           elsif squote
1526:             case char
1527:             when "\'"; squote = false ; next char
1528:             else next char
1529:             end
1530:           elsif dquote
1531:             case char
1532:             when "\""; dquote = false ; next char
1533:             else next char
1534:             end
1535:           end
1536:         }
1537:         words.join("")
1538:       }
1539:       return lines.join("\n")
1540:     end

Set visibility

"subname" element of "visibility_info" is deleted.

[Source]

      # File lib/rdoc/parsers/parse_f95.rb, line 1290
1290:     def set_visibility(container, subname, visibility_default, visibility_info)
1291:       return unless container || subname || visibility_default || visibility_info
1292:       not_found = true
1293:       visibility_info.collect!{ |info|
1294:         if info["name"] == subname ||
1295:             @options.ignore_case && info["name"].upcase == subname.upcase
1296:           if info["file_or_module"].name == container.name
1297:             container.set_visibility_for([subname], info["visibility"])
1298:             info["entity_is_discovered"] = true
1299:             not_found = false
1300:           end
1301:         end
1302:         info
1303:       }
1304:       if not_found
1305:         return container.set_visibility_for([subname], visibility_default)
1306:       else
1307:         return container
1308:       end
1309:     end

Continuous lines are united.

Comments in continuous lines are removed.

[Source]

      # File lib/rdoc/parsers/parse_f95.rb, line 1389
1389:     def united_to_one_line(f90src)
1390:       return "" unless f90src
1391:       lines = f90src.split("\n")
1392:       previous_continuing = false
1393:       now_continuing = false
1394:       body = ""
1395:       lines.each{ |line|
1396:         words = line.split("")
1397:         next if words.empty? && previous_continuing
1398:         commentout = false
1399:         brank_flag = true ; brank_char = ""
1400:         squote = false    ; dquote = false
1401:         ignore = false
1402:         words.collect! { |char|
1403:           if previous_continuing && brank_flag
1404:             now_continuing = true
1405:             ignore         = true
1406:             case char
1407:             when "!"                       ; break
1408:             when " " ; brank_char << char  ; next ""
1409:             when "&"
1410:               brank_flag = false
1411:               now_continuing = false
1412:               next ""
1413:             else 
1414:               brank_flag     = false
1415:               now_continuing = false
1416:               ignore         = false
1417:               next brank_char + char
1418:             end
1419:           end
1420:           ignore = false
1421: 
1422:           if now_continuing
1423:             next ""
1424:           elsif !(squote) && !(dquote) && !(commentout)
1425:             case char
1426:             when "!" ; commentout = true     ; next char
1427:             when "\""; dquote = true         ; next char
1428:             when "\'"; squote = true         ; next char
1429:             when "&" ; now_continuing = true ; next ""
1430:             else next char
1431:             end
1432:           elsif commentout
1433:             next char
1434:           elsif squote
1435:             case char
1436:             when "\'"; squote = false ; next char
1437:             else next char
1438:             end
1439:           elsif dquote
1440:             case char
1441:             when "\""; dquote = false ; next char
1442:             else next char
1443:             end
1444:           end
1445:         }
1446:         if !ignore && !previous_continuing || !brank_flag
1447:           if previous_continuing
1448:             body << words.join("")
1449:           else
1450:             body << "\n" + words.join("")
1451:           end
1452:         end
1453:         previous_continuing = now_continuing ? true : nil
1454:         now_continuing = nil
1455:       }
1456:       return body
1457:     end

[Validate]