iownbey-rdoc 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/History.txt +13 -0
  2. data/Manifest.txt +61 -0
  3. data/README.txt +34 -0
  4. data/bin/rdoc +22 -0
  5. data/bin/ri +6 -0
  6. data/lib/rdoc.rb +277 -0
  7. data/lib/rdoc/code_objects.rb +776 -0
  8. data/lib/rdoc/diagram.rb +338 -0
  9. data/lib/rdoc/dot.rb +249 -0
  10. data/lib/rdoc/generator.rb +1050 -0
  11. data/lib/rdoc/generator/chm.rb +113 -0
  12. data/lib/rdoc/generator/chm/chm.rb +98 -0
  13. data/lib/rdoc/generator/html.rb +370 -0
  14. data/lib/rdoc/generator/html/hefss.rb +414 -0
  15. data/lib/rdoc/generator/html/html.rb +704 -0
  16. data/lib/rdoc/generator/html/kilmer.rb +418 -0
  17. data/lib/rdoc/generator/html/one_page_html.rb +121 -0
  18. data/lib/rdoc/generator/ri.rb +229 -0
  19. data/lib/rdoc/generator/texinfo.rb +84 -0
  20. data/lib/rdoc/generator/texinfo/class.texinfo.erb +44 -0
  21. data/lib/rdoc/generator/texinfo/file.texinfo.erb +6 -0
  22. data/lib/rdoc/generator/texinfo/method.texinfo.erb +6 -0
  23. data/lib/rdoc/generator/texinfo/texinfo.erb +28 -0
  24. data/lib/rdoc/generator/xml.rb +120 -0
  25. data/lib/rdoc/generator/xml/rdf.rb +113 -0
  26. data/lib/rdoc/generator/xml/xml.rb +111 -0
  27. data/lib/rdoc/markup.rb +473 -0
  28. data/lib/rdoc/markup/attribute_manager.rb +274 -0
  29. data/lib/rdoc/markup/formatter.rb +14 -0
  30. data/lib/rdoc/markup/fragments.rb +337 -0
  31. data/lib/rdoc/markup/inline.rb +101 -0
  32. data/lib/rdoc/markup/lines.rb +152 -0
  33. data/lib/rdoc/markup/preprocess.rb +71 -0
  34. data/lib/rdoc/markup/to_flow.rb +185 -0
  35. data/lib/rdoc/markup/to_html.rb +354 -0
  36. data/lib/rdoc/markup/to_html_crossref.rb +86 -0
  37. data/lib/rdoc/markup/to_latex.rb +328 -0
  38. data/lib/rdoc/markup/to_test.rb +50 -0
  39. data/lib/rdoc/markup/to_texinfo.rb +69 -0
  40. data/lib/rdoc/options.rb +621 -0
  41. data/lib/rdoc/parsers/parse_c.rb +775 -0
  42. data/lib/rdoc/parsers/parse_f95.rb +1841 -0
  43. data/lib/rdoc/parsers/parse_rb.rb +2584 -0
  44. data/lib/rdoc/parsers/parse_simple.rb +40 -0
  45. data/lib/rdoc/parsers/parserfactory.rb +99 -0
  46. data/lib/rdoc/rdoc.rb +277 -0
  47. data/lib/rdoc/ri.rb +4 -0
  48. data/lib/rdoc/ri/cache.rb +188 -0
  49. data/lib/rdoc/ri/descriptions.rb +150 -0
  50. data/lib/rdoc/ri/display.rb +274 -0
  51. data/lib/rdoc/ri/driver.rb +452 -0
  52. data/lib/rdoc/ri/formatter.rb +616 -0
  53. data/lib/rdoc/ri/paths.rb +102 -0
  54. data/lib/rdoc/ri/reader.rb +106 -0
  55. data/lib/rdoc/ri/util.rb +81 -0
  56. data/lib/rdoc/ri/writer.rb +68 -0
  57. data/lib/rdoc/stats.rb +25 -0
  58. data/lib/rdoc/template.rb +64 -0
  59. data/lib/rdoc/tokenstream.rb +33 -0
  60. data/test/test_rdoc_c_parser.rb +261 -0
  61. data/test/test_rdoc_info_formatting.rb +179 -0
  62. data/test/test_rdoc_info_sections.rb +93 -0
  63. data/test/test_rdoc_markup.rb +613 -0
  64. data/test/test_rdoc_markup_attribute_manager.rb +224 -0
  65. data/test/test_rdoc_ri_attribute_formatter.rb +42 -0
  66. data/test/test_rdoc_ri_default_display.rb +295 -0
  67. data/test/test_rdoc_ri_formatter.rb +318 -0
  68. data/test/test_rdoc_ri_overstrike_formatter.rb +69 -0
  69. metadata +142 -0
@@ -0,0 +1,1841 @@
1
+ #= parse_f95.rb - Fortran95 Parser
2
+ #
3
+ #== Overview
4
+ #
5
+ #"parse_f95.rb" parses Fortran95 files with suffixes "f90", "F90", "f95"
6
+ #and "F95". Fortran95 files are expected to be conformed to Fortran95
7
+ #standards.
8
+ #
9
+ #== Rules
10
+ #
11
+ #Fundamental rules are same as that of the Ruby parser.
12
+ #But comment markers are '!' not '#'.
13
+ #
14
+ #=== Correspondence between RDoc documentation and Fortran95 programs
15
+ #
16
+ #"parse_f95.rb" parses main programs, modules, subroutines, functions,
17
+ #derived-types, public variables, public constants,
18
+ #defined operators and defined assignments.
19
+ #These components are described in items of RDoc documentation, as follows.
20
+ #
21
+ #Files :: Files (same as Ruby)
22
+ #Classes :: Modules
23
+ #Methods :: Subroutines, functions, variables, constants, derived-types, defined operators, defined assignments
24
+ #Required files :: Files in which imported modules, external subroutines and external functions are defined.
25
+ #Included Modules :: List of imported modules
26
+ #Attributes :: List of derived-types, List of imported modules all of whose components are published again
27
+ #
28
+ #Components listed in 'Methods' (subroutines, functions, ...)
29
+ #defined in modules are described in the item of 'Classes'.
30
+ #On the other hand, components defined in main programs or
31
+ #as external procedures are described in the item of 'Files'.
32
+ #
33
+ #=== Components parsed by default
34
+ #
35
+ #By default, documentation on public components (subroutines, functions,
36
+ #variables, constants, derived-types, defined operators,
37
+ #defined assignments) are generated.
38
+ #With "--all" option, documentation on all components
39
+ #are generated (almost same as the Ruby parser).
40
+ #
41
+ #=== Information parsed automatically
42
+ #
43
+ #The following information is automatically parsed.
44
+ #
45
+ #* Types of arguments
46
+ #* Types of variables and constants
47
+ #* Types of variables in the derived types, and initial values
48
+ #* NAMELISTs and types of variables in them, and initial values
49
+ #
50
+ #Aliases by interface statement are described in the item of 'Methods'.
51
+ #
52
+ #Components which are imported from other modules and published again
53
+ #are described in the item of 'Methods'.
54
+ #
55
+ #=== Format of comment blocks
56
+ #
57
+ #Comment blocks should be written as follows.
58
+ #Comment blocks are considered to be ended when the line without '!'
59
+ #appears.
60
+ #The indentation is not necessary.
61
+ #
62
+ # ! (Top of file)
63
+ # !
64
+ # ! Comment blocks for the files.
65
+ # !
66
+ # !--
67
+ # ! The comment described in the part enclosed by
68
+ # ! "!--" and "!++" is ignored.
69
+ # !++
70
+ # !
71
+ # module hogehoge
72
+ # !
73
+ # ! Comment blocks for the modules (or the programs).
74
+ # !
75
+ #
76
+ # private
77
+ #
78
+ # logical :: a ! a private variable
79
+ # real, public :: b ! a public variable
80
+ # integer, parameter :: c = 0 ! a public constant
81
+ #
82
+ # public :: c
83
+ # public :: MULTI_ARRAY
84
+ # public :: hoge, foo
85
+ #
86
+ # type MULTI_ARRAY
87
+ # !
88
+ # ! Comment blocks for the derived-types.
89
+ # !
90
+ # real, pointer :: var(:) =>null() ! Comments block for the variables.
91
+ # integer :: num = 0
92
+ # end type MULTI_ARRAY
93
+ #
94
+ # contains
95
+ #
96
+ # subroutine hoge( in, & ! Comment blocks between continuation lines are ignored.
97
+ # & out )
98
+ # !
99
+ # ! Comment blocks for the subroutines or functions
100
+ # !
101
+ # character(*),intent(in):: in ! Comment blocks for the arguments.
102
+ # character(*),intent(out),allocatable,target :: in
103
+ # ! Comment blocks can be
104
+ # ! written under Fortran statements.
105
+ #
106
+ # character(32) :: file ! This comment parsed as a variable in below NAMELIST.
107
+ # integer :: id
108
+ #
109
+ # namelist /varinfo_nml/ file, id
110
+ # !
111
+ # ! Comment blocks for the NAMELISTs.
112
+ # ! Information about variables are described above.
113
+ # !
114
+ #
115
+ # ....
116
+ #
117
+ # end subroutine hoge
118
+ #
119
+ # integer function foo( in )
120
+ # !
121
+ # ! This part is considered as comment block.
122
+ #
123
+ # ! Comment blocks under blank lines are ignored.
124
+ # !
125
+ # integer, intent(in):: inA ! This part is considered as comment block.
126
+ #
127
+ # ! This part is ignored.
128
+ #
129
+ # end function foo
130
+ #
131
+ # subroutine hide( in, &
132
+ # & out ) !:nodoc:
133
+ # !
134
+ # ! If "!:nodoc:" is described at end-of-line in subroutine
135
+ # ! statement as above, the subroutine is ignored.
136
+ # ! This assignment can be used to modules, subroutines,
137
+ # ! functions, variables, constants, derived-types,
138
+ # ! defined operators, defined assignments,
139
+ # ! list of imported modules ("use" statement).
140
+ # !
141
+ #
142
+ # ....
143
+ #
144
+ # end subroutine hide
145
+ #
146
+ # end module hogehoge
147
+ #
148
+
149
+
150
+ require "rdoc/code_objects"
151
+
152
+ module RDoc
153
+
154
+ class Token
155
+
156
+ NO_TEXT = "??".freeze
157
+
158
+ def initialize(line_no, char_no)
159
+ @line_no = line_no
160
+ @char_no = char_no
161
+ @text = NO_TEXT
162
+ end
163
+ # Because we're used in contexts that expect to return a token,
164
+ # we set the text string and then return ourselves
165
+ def set_text(text)
166
+ @text = text
167
+ self
168
+ end
169
+
170
+ attr_reader :line_no, :char_no, :text
171
+
172
+ end
173
+
174
+ # See rdoc/parsers/parse_f95.rb
175
+
176
+ class Fortran95parser
177
+
178
+ extend ParserFactory
179
+ parse_files_matching(/\.((f|F)9(0|5)|F)$/)
180
+
181
+ @@external_aliases = []
182
+ @@public_methods = []
183
+
184
+ # "false":: Comments are below source code
185
+ # "true" :: Comments are upper source code
186
+ COMMENTS_ARE_UPPER = false
187
+
188
+ # Internal alias message
189
+ INTERNAL_ALIAS_MES = "Alias for"
190
+
191
+ # External alias message
192
+ EXTERNAL_ALIAS_MES = "The entity is"
193
+
194
+ # prepare to parse a Fortran 95 file
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
203
+
204
+ # devine code constructs
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 # End of scan
355
+
356
+ private
357
+
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 # End of parse_program_or_module
1002
+
1003
+ #
1004
+ # Parse arguments, comment, code of subroutine and function.
1005
+ # Return AnyMethod object.
1006
+ #
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
1035
+
1036
+ #
1037
+ # Collect comment for file entity
1038
+ #
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
1062
+
1063
+
1064
+ # Return comments of definitions of arguments
1065
+ #
1066
+ # If "all" argument is true, information of all arguments are returned.
1067
+ # If "modified_params" is true, list of arguments are decorated,
1068
+ # for exameple, optional arguments are parenthetic as "[arg]".
1069
+ #
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 << <<-"EOF"
1086
+
1087
+ #{indent}<tt><b>#{defitem.varname.chomp.strip}#{defitem.arraysuffix}</b> #{defitem.inivalue}</tt> ::
1088
+ #{indent} <tt>#{defitem.types.chomp.strip}</tt>
1089
+ EOF
1090
+ if !defitem.comment.chomp.strip.empty?
1091
+ comment = ""
1092
+ defitem.comment.split("\n").each{ |line|
1093
+ comment << " " + line + "\n"
1094
+ }
1095
+ args_rdocforms << <<-"EOF"
1096
+
1097
+ #{indent} <tt></tt> ::
1098
+ #{indent} <tt></tt>
1099
+ #{indent} #{comment.chomp.strip}
1100
+ EOF
1101
+ end
1102
+
1103
+ if modified_params
1104
+ if defitem.include_attr?("optional")
1105
+ params << "#{comma}[#{arg}]"
1106
+ else
1107
+ params << "#{comma}#{arg}"
1108
+ end
1109
+ comma = ", "
1110
+ end
1111
+ end
1112
+ }
1113
+ }
1114
+ if modified_params
1115
+ return args_rdocforms, params
1116
+ else
1117
+ return args_rdocforms
1118
+ end
1119
+ end
1120
+
1121
+ # Return comments of definitions of namelists
1122
+ #
1123
+ def find_namelists(text, before_contains=nil)
1124
+ return nil if !text
1125
+ result = ""
1126
+ lines = "#{text}"
1127
+ before_contains = "" if !before_contains
1128
+ while lines =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)$/i
1129
+ lines = $~.post_match
1130
+ nml_comment = COMMENTS_ARE_UPPER ?
1131
+ find_comments($~.pre_match) : find_comments($~.post_match)
1132
+ nml_name = $1
1133
+ nml_args = $2.split(",")
1134
+ result << "\n\n=== NAMELIST <tt><b>" + nml_name + "</tt></b>\n\n"
1135
+ result << nml_comment + "\n" if nml_comment
1136
+ if lines.split("\n")[0] =~ /^\//i
1137
+ lines = "namelist " + lines
1138
+ end
1139
+ result << find_arguments(nml_args, "#{text}" + "\n" + before_contains)
1140
+ end
1141
+ return result
1142
+ end
1143
+
1144
+ #
1145
+ # Comments just after module or subprogram, or arguments are
1146
+ # returnd. If "COMMENTS_ARE_UPPER" is true, comments just before
1147
+ # modules or subprograms are returnd
1148
+ #
1149
+ def find_comments text
1150
+ return "" unless text
1151
+ lines = text.split("\n")
1152
+ lines.reverse! if COMMENTS_ARE_UPPER
1153
+ comment_block = Array.new
1154
+ lines.each do |line|
1155
+ break if line =~ /^\s*?\w/ || line =~ /^\s*?$/
1156
+ if COMMENTS_ARE_UPPER
1157
+ comment_block.unshift line.sub(/^\s*?!\s?/,"")
1158
+ else
1159
+ comment_block.push line.sub(/^\s*?!\s?/,"")
1160
+ end
1161
+ end
1162
+ nice_lines = comment_block.join("\n").split "\n\s*?\n"
1163
+ nice_lines[0] ||= ""
1164
+ nice_lines.shift
1165
+ end
1166
+
1167
+ def progress(char)
1168
+ unless @options.quiet
1169
+ @progress.print(char)
1170
+ @progress.flush
1171
+ end
1172
+ end
1173
+
1174
+ #
1175
+ # Create method for internal alias
1176
+ #
1177
+ def initialize_public_method(method, parent)
1178
+ return if !method || !parent
1179
+
1180
+ new_meth = AnyMethod.new("External Alias for module", method.name)
1181
+ new_meth.singleton = method.singleton
1182
+ new_meth.params = method.params.clone
1183
+ new_meth.comment = remove_trailing_alias(method.comment.clone)
1184
+ new_meth.comment << "\n\n#{EXTERNAL_ALIAS_MES} #{parent.strip.chomp}\##{method.name}"
1185
+
1186
+ return new_meth
1187
+ end
1188
+
1189
+ #
1190
+ # Create method for external alias
1191
+ #
1192
+ # If argument "internal" is true, file is ignored.
1193
+ #
1194
+ def initialize_external_method(new, old, params, file, comment, token=nil,
1195
+ internal=nil, nolink=nil)
1196
+ return nil unless new || old
1197
+
1198
+ if internal
1199
+ external_alias_header = "#{INTERNAL_ALIAS_MES} "
1200
+ external_alias_text = external_alias_header + old
1201
+ elsif file
1202
+ external_alias_header = "#{EXTERNAL_ALIAS_MES} "
1203
+ external_alias_text = external_alias_header + file + "#" + old
1204
+ else
1205
+ return nil
1206
+ end
1207
+ external_meth = AnyMethod.new(external_alias_text, new)
1208
+ external_meth.singleton = false
1209
+ external_meth.params = params
1210
+ external_comment = remove_trailing_alias(comment) + "\n\n" if comment
1211
+ external_meth.comment = external_comment || ""
1212
+ if nolink && token
1213
+ external_meth.start_collecting_tokens
1214
+ external_meth.add_token Token.new(1,1).set_text(token)
1215
+ else
1216
+ external_meth.comment << external_alias_text
1217
+ end
1218
+
1219
+ return external_meth
1220
+ end
1221
+
1222
+
1223
+
1224
+ #
1225
+ # Parse visibility
1226
+ #
1227
+ def parse_visibility(code, default, container)
1228
+ result = []
1229
+ visibility_default = default || :public
1230
+
1231
+ used_modules = []
1232
+ container.includes.each{|i| used_modules << i.name} if container
1233
+
1234
+ remaining_code = code.gsub(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
1235
+ remaining_code.split("\n").each{ |line|
1236
+ if /^\s*?private\s*?$/ =~ line
1237
+ visibility_default = :private
1238
+ break
1239
+ end
1240
+ } if remaining_code
1241
+
1242
+ remaining_code.split("\n").each{ |line|
1243
+ if /^\s*?private\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
1244
+ methods = $2.sub(/!.*$/, '')
1245
+ methods.split(",").each{ |meth|
1246
+ meth.sub!(/!.*$/, '')
1247
+ meth.gsub!(/:/, '')
1248
+ result << {
1249
+ "name" => meth.chomp.strip,
1250
+ "visibility" => :private,
1251
+ "used_modules" => used_modules.clone,
1252
+ "file_or_module" => container,
1253
+ "entity_is_discovered" => nil,
1254
+ "local_name" => nil
1255
+ }
1256
+ }
1257
+ elsif /^\s*?public\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
1258
+ methods = $2.sub(/!.*$/, '')
1259
+ methods.split(",").each{ |meth|
1260
+ meth.sub!(/!.*$/, '')
1261
+ meth.gsub!(/:/, '')
1262
+ result << {
1263
+ "name" => meth.chomp.strip,
1264
+ "visibility" => :public,
1265
+ "used_modules" => used_modules.clone,
1266
+ "file_or_module" => container,
1267
+ "entity_is_discovered" => nil,
1268
+ "local_name" => nil
1269
+ }
1270
+ }
1271
+ end
1272
+ } if remaining_code
1273
+
1274
+ if container
1275
+ result.each{ |vis_info|
1276
+ vis_info["parent"] = container.name
1277
+ }
1278
+ end
1279
+
1280
+ return visibility_default, result
1281
+ end
1282
+
1283
+ #
1284
+ # Set visibility
1285
+ #
1286
+ # "subname" element of "visibility_info" is deleted.
1287
+ #
1288
+ def set_visibility(container, subname, visibility_default, visibility_info)
1289
+ return unless container || subname || visibility_default || visibility_info
1290
+ not_found = true
1291
+ visibility_info.collect!{ |info|
1292
+ if info["name"] == subname ||
1293
+ @options.ignore_case && info["name"].upcase == subname.upcase
1294
+ if info["file_or_module"].name == container.name
1295
+ container.set_visibility_for([subname], info["visibility"])
1296
+ info["entity_is_discovered"] = true
1297
+ not_found = false
1298
+ end
1299
+ end
1300
+ info
1301
+ }
1302
+ if not_found
1303
+ return container.set_visibility_for([subname], visibility_default)
1304
+ else
1305
+ return container
1306
+ end
1307
+ end
1308
+
1309
+ #
1310
+ # Find visibility
1311
+ #
1312
+ def find_visibility(container, subname, visibility_info)
1313
+ return nil if !subname || !visibility_info
1314
+ visibility_info.each{ |info|
1315
+ if info["name"] == subname ||
1316
+ @options.ignore_case && info["name"].upcase == subname.upcase
1317
+ if info["parent"] == container.name
1318
+ return info["visibility"]
1319
+ end
1320
+ end
1321
+ }
1322
+ return nil
1323
+ end
1324
+
1325
+ #
1326
+ # Check external aliases
1327
+ #
1328
+ def check_external_aliases(subname, params, comment, test=nil)
1329
+ @@external_aliases.each{ |alias_item|
1330
+ if subname == alias_item["old_name"] ||
1331
+ subname.upcase == alias_item["old_name"].upcase &&
1332
+ @options.ignore_case
1333
+
1334
+ new_meth = initialize_external_method(alias_item["new_name"],
1335
+ subname, params, @file_name,
1336
+ comment)
1337
+ new_meth.visibility = alias_item["visibility"]
1338
+
1339
+ progress "e"
1340
+ @stats.num_methods += 1
1341
+ alias_item["file_or_module"].add_method(new_meth)
1342
+
1343
+ if !alias_item["file_or_module"].include_requires?(@file_name, @options.ignore_case)
1344
+ alias_item["file_or_module"].add_require(Require.new(@file_name, ""))
1345
+ end
1346
+ end
1347
+ }
1348
+ end
1349
+
1350
+ #
1351
+ # Check public_methods
1352
+ #
1353
+ def check_public_methods(method, parent)
1354
+ return if !method || !parent
1355
+ @@public_methods.each{ |alias_item|
1356
+ parent_is_used_module = nil
1357
+ alias_item["used_modules"].each{ |used_module|
1358
+ if used_module == parent ||
1359
+ used_module.upcase == parent.upcase &&
1360
+ @options.ignore_case
1361
+ parent_is_used_module = true
1362
+ end
1363
+ }
1364
+ next if !parent_is_used_module
1365
+
1366
+ if method.name == alias_item["name"] ||
1367
+ method.name.upcase == alias_item["name"].upcase &&
1368
+ @options.ignore_case
1369
+
1370
+ new_meth = initialize_public_method(method, parent)
1371
+ if alias_item["local_name"]
1372
+ new_meth.name = alias_item["local_name"]
1373
+ end
1374
+
1375
+ progress "e"
1376
+ @stats.num_methods += 1
1377
+ alias_item["file_or_module"].add_method new_meth
1378
+ end
1379
+ }
1380
+ end
1381
+
1382
+ #
1383
+ # Continuous lines are united.
1384
+ #
1385
+ # Comments in continuous lines are removed.
1386
+ #
1387
+ def united_to_one_line(f90src)
1388
+ return "" unless f90src
1389
+ lines = f90src.split("\n")
1390
+ previous_continuing = false
1391
+ now_continuing = false
1392
+ body = ""
1393
+ lines.each{ |line|
1394
+ words = line.split("")
1395
+ next if words.empty? && previous_continuing
1396
+ commentout = false
1397
+ brank_flag = true ; brank_char = ""
1398
+ squote = false ; dquote = false
1399
+ ignore = false
1400
+ words.collect! { |char|
1401
+ if previous_continuing && brank_flag
1402
+ now_continuing = true
1403
+ ignore = true
1404
+ case char
1405
+ when "!" ; break
1406
+ when " " ; brank_char << char ; next ""
1407
+ when "&"
1408
+ brank_flag = false
1409
+ now_continuing = false
1410
+ next ""
1411
+ else
1412
+ brank_flag = false
1413
+ now_continuing = false
1414
+ ignore = false
1415
+ next brank_char + char
1416
+ end
1417
+ end
1418
+ ignore = false
1419
+
1420
+ if now_continuing
1421
+ next ""
1422
+ elsif !(squote) && !(dquote) && !(commentout)
1423
+ case char
1424
+ when "!" ; commentout = true ; next char
1425
+ when "\""; dquote = true ; next char
1426
+ when "\'"; squote = true ; next char
1427
+ when "&" ; now_continuing = true ; next ""
1428
+ else next char
1429
+ end
1430
+ elsif commentout
1431
+ next char
1432
+ elsif squote
1433
+ case char
1434
+ when "\'"; squote = false ; next char
1435
+ else next char
1436
+ end
1437
+ elsif dquote
1438
+ case char
1439
+ when "\""; dquote = false ; next char
1440
+ else next char
1441
+ end
1442
+ end
1443
+ }
1444
+ if !ignore && !previous_continuing || !brank_flag
1445
+ if previous_continuing
1446
+ body << words.join("")
1447
+ else
1448
+ body << "\n" + words.join("")
1449
+ end
1450
+ end
1451
+ previous_continuing = now_continuing ? true : nil
1452
+ now_continuing = nil
1453
+ }
1454
+ return body
1455
+ end
1456
+
1457
+
1458
+ #
1459
+ # Continuous line checker
1460
+ #
1461
+ def continuous_line?(line)
1462
+ continuous = false
1463
+ if /&\s*?(!.*)?$/ =~ line
1464
+ continuous = true
1465
+ if comment_out?($~.pre_match)
1466
+ continuous = false
1467
+ end
1468
+ end
1469
+ return continuous
1470
+ end
1471
+
1472
+ #
1473
+ # Comment out checker
1474
+ #
1475
+ def comment_out?(line)
1476
+ return nil unless line
1477
+ commentout = false
1478
+ squote = false ; dquote = false
1479
+ line.split("").each { |char|
1480
+ if !(squote) && !(dquote)
1481
+ case char
1482
+ when "!" ; commentout = true ; break
1483
+ when "\""; dquote = true
1484
+ when "\'"; squote = true
1485
+ else next
1486
+ end
1487
+ elsif squote
1488
+ case char
1489
+ when "\'"; squote = false
1490
+ else next
1491
+ end
1492
+ elsif dquote
1493
+ case char
1494
+ when "\""; dquote = false
1495
+ else next
1496
+ end
1497
+ end
1498
+ }
1499
+ return commentout
1500
+ end
1501
+
1502
+ #
1503
+ # Semicolons are replaced to line feed.
1504
+ #
1505
+ def semicolon_to_linefeed(text)
1506
+ return "" unless text
1507
+ lines = text.split("\n")
1508
+ lines.collect!{ |line|
1509
+ words = line.split("")
1510
+ commentout = false
1511
+ squote = false ; dquote = false
1512
+ words.collect! { |char|
1513
+ if !(squote) && !(dquote) && !(commentout)
1514
+ case char
1515
+ when "!" ; commentout = true ; next char
1516
+ when "\""; dquote = true ; next char
1517
+ when "\'"; squote = true ; next char
1518
+ when ";" ; "\n"
1519
+ else next char
1520
+ end
1521
+ elsif commentout
1522
+ next char
1523
+ elsif squote
1524
+ case char
1525
+ when "\'"; squote = false ; next char
1526
+ else next char
1527
+ end
1528
+ elsif dquote
1529
+ case char
1530
+ when "\""; dquote = false ; next char
1531
+ else next char
1532
+ end
1533
+ end
1534
+ }
1535
+ words.join("")
1536
+ }
1537
+ return lines.join("\n")
1538
+ end
1539
+
1540
+ #
1541
+ # Which "line" is start of block (module, program, block data,
1542
+ # subroutine, function) statement ?
1543
+ #
1544
+ def block_start?(line)
1545
+ return nil if !line
1546
+
1547
+ if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i ||
1548
+ line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i ||
1549
+ line =~ /^\s*?block\s+data(\s+\w+)?\s*?(!.*?)?$/i ||
1550
+ line =~ \
1551
+ /^\s*?
1552
+ (recursive|pure|elemental)?\s*?
1553
+ subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
1554
+ /ix ||
1555
+ line =~ \
1556
+ /^\s*?
1557
+ (recursive|pure|elemental)?\s*?
1558
+ (
1559
+ character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1560
+ | type\s*?\([\w\s]+?\)\s+
1561
+ | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1562
+ | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1563
+ | double\s+precision\s+
1564
+ | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1565
+ | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
1566
+ )?
1567
+ function\s+(\w+)\s*?
1568
+ (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
1569
+ /ix
1570
+ return true
1571
+ end
1572
+
1573
+ return nil
1574
+ end
1575
+
1576
+ #
1577
+ # Which "line" is end of block (module, program, block data,
1578
+ # subroutine, function) statement ?
1579
+ #
1580
+ def block_end?(line)
1581
+ return nil if !line
1582
+
1583
+ if line =~ /^\s*?end\s*?(!.*?)?$/i ||
1584
+ line =~ /^\s*?end\s+module(\s+\w+)?\s*?(!.*?)?$/i ||
1585
+ line =~ /^\s*?end\s+program(\s+\w+)?\s*?(!.*?)?$/i ||
1586
+ line =~ /^\s*?end\s+block\s+data(\s+\w+)?\s*?(!.*?)?$/i ||
1587
+ line =~ /^\s*?end\s+subroutine(\s+\w+)?\s*?(!.*?)?$/i ||
1588
+ line =~ /^\s*?end\s+function(\s+\w+)?\s*?(!.*?)?$/i
1589
+ return true
1590
+ end
1591
+
1592
+ return nil
1593
+ end
1594
+
1595
+ #
1596
+ # Remove "Alias for" in end of comments
1597
+ #
1598
+ def remove_trailing_alias(text)
1599
+ return "" if !text
1600
+ lines = text.split("\n").reverse
1601
+ comment_block = Array.new
1602
+ checked = false
1603
+ lines.each do |line|
1604
+ if !checked
1605
+ if /^\s?#{INTERNAL_ALIAS_MES}/ =~ line ||
1606
+ /^\s?#{EXTERNAL_ALIAS_MES}/ =~ line
1607
+ checked = true
1608
+ next
1609
+ end
1610
+ end
1611
+ comment_block.unshift line
1612
+ end
1613
+ nice_lines = comment_block.join("\n")
1614
+ nice_lines ||= ""
1615
+ return nice_lines
1616
+ end
1617
+
1618
+ # Empty lines in header are removed
1619
+ def remove_empty_head_lines(text)
1620
+ return "" unless text
1621
+ lines = text.split("\n")
1622
+ header = true
1623
+ lines.delete_if{ |line|
1624
+ header = false if /\S/ =~ line
1625
+ header && /^\s*?$/ =~ line
1626
+ }
1627
+ lines.join("\n")
1628
+ end
1629
+
1630
+
1631
+ # header marker "=", "==", ... are removed
1632
+ def remove_header_marker(text)
1633
+ return text.gsub(/^\s?(=+)/, '<tt></tt>\1')
1634
+ end
1635
+
1636
+ def remove_private_comments(body)
1637
+ body.gsub!(/^\s*!--\s*?$.*?^\s*!\+\+\s*?$/m, '')
1638
+ return body
1639
+ end
1640
+
1641
+
1642
+ #
1643
+ # Information of arguments of subroutines and functions in Fortran95
1644
+ #
1645
+ class Fortran95Definition
1646
+
1647
+ # Name of variable
1648
+ #
1649
+ attr_reader :varname
1650
+
1651
+ # Types of variable
1652
+ #
1653
+ attr_reader :types
1654
+
1655
+ # Initial Value
1656
+ #
1657
+ attr_reader :inivalue
1658
+
1659
+ # Suffix of array
1660
+ #
1661
+ attr_reader :arraysuffix
1662
+
1663
+ # Comments
1664
+ #
1665
+ attr_accessor :comment
1666
+
1667
+ # Flag of non documentation
1668
+ #
1669
+ attr_accessor :nodoc
1670
+
1671
+ def initialize(varname, types, inivalue, arraysuffix, comment,
1672
+ nodoc=false)
1673
+ @varname = varname
1674
+ @types = types
1675
+ @inivalue = inivalue
1676
+ @arraysuffix = arraysuffix
1677
+ @comment = comment
1678
+ @nodoc = nodoc
1679
+ end
1680
+
1681
+ def to_s
1682
+ return <<-EOF
1683
+ <Fortran95Definition:
1684
+ varname=#{@varname}, types=#{types},
1685
+ inivalue=#{@inivalue}, arraysuffix=#{@arraysuffix}, nodoc=#{@nodoc},
1686
+ comment=
1687
+ #{@comment}
1688
+ >
1689
+ EOF
1690
+ end
1691
+
1692
+ #
1693
+ # If attr is included, true is returned
1694
+ #
1695
+ def include_attr?(attr)
1696
+ return if !attr
1697
+ @types.split(",").each{ |type|
1698
+ return true if type.strip.chomp.upcase == attr.strip.chomp.upcase
1699
+ }
1700
+ return nil
1701
+ end
1702
+
1703
+ end # End of Fortran95Definition
1704
+
1705
+ #
1706
+ # Parse string argument "text", and Return Array of
1707
+ # Fortran95Definition object
1708
+ #
1709
+ def definition_info(text)
1710
+ return nil unless text
1711
+ lines = "#{text}"
1712
+ defs = Array.new
1713
+ comment = ""
1714
+ trailing_comment = ""
1715
+ under_comment_valid = false
1716
+ lines.split("\n").each{ |line|
1717
+ if /^\s*?!\s?(.*)/ =~ line
1718
+ if COMMENTS_ARE_UPPER
1719
+ comment << remove_header_marker($1)
1720
+ comment << "\n"
1721
+ elsif defs[-1] && under_comment_valid
1722
+ defs[-1].comment << "\n"
1723
+ defs[-1].comment << remove_header_marker($1)
1724
+ end
1725
+ next
1726
+ elsif /^\s*?$/ =~ line
1727
+ comment = ""
1728
+ under_comment_valid = false
1729
+ next
1730
+ end
1731
+ type = ""
1732
+ characters = ""
1733
+ if line =~ /^\s*?
1734
+ (
1735
+ character\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
1736
+ | type\s*?\([\w\s]+?\)[\s\,]*
1737
+ | integer\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
1738
+ | real\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
1739
+ | double\s+precision[\s\,]*
1740
+ | logical\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
1741
+ | complex\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
1742
+ )
1743
+ (.*?::)?
1744
+ (.+)$
1745
+ /ix
1746
+ characters = $8
1747
+ type = $1
1748
+ type << $7.gsub(/::/, '').gsub(/^\s*?\,/, '') if $7
1749
+ else
1750
+ under_comment_valid = false
1751
+ next
1752
+ end
1753
+ squote = false ; dquote = false ; bracket = 0
1754
+ iniflag = false; commentflag = false
1755
+ varname = "" ; arraysuffix = "" ; inivalue = ""
1756
+ start_pos = defs.size
1757
+ characters.split("").each { |char|
1758
+ if !(squote) && !(dquote) && bracket <= 0 && !(iniflag) && !(commentflag)
1759
+ case char
1760
+ when "!" ; commentflag = true
1761
+ when "(" ; bracket += 1 ; arraysuffix = char
1762
+ when "\""; dquote = true
1763
+ when "\'"; squote = true
1764
+ when "=" ; iniflag = true ; inivalue << char
1765
+ when ","
1766
+ defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
1767
+ varname = "" ; arraysuffix = "" ; inivalue = ""
1768
+ under_comment_valid = true
1769
+ when " " ; next
1770
+ else ; varname << char
1771
+ end
1772
+ elsif commentflag
1773
+ comment << remove_header_marker(char)
1774
+ trailing_comment << remove_header_marker(char)
1775
+ elsif iniflag
1776
+ if dquote
1777
+ case char
1778
+ when "\"" ; dquote = false ; inivalue << char
1779
+ else ; inivalue << char
1780
+ end
1781
+ elsif squote
1782
+ case char
1783
+ when "\'" ; squote = false ; inivalue << char
1784
+ else ; inivalue << char
1785
+ end
1786
+ elsif bracket > 0
1787
+ case char
1788
+ when "(" ; bracket += 1 ; inivalue << char
1789
+ when ")" ; bracket -= 1 ; inivalue << char
1790
+ else ; inivalue << char
1791
+ end
1792
+ else
1793
+ case char
1794
+ when ","
1795
+ defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
1796
+ varname = "" ; arraysuffix = "" ; inivalue = ""
1797
+ iniflag = false
1798
+ under_comment_valid = true
1799
+ when "(" ; bracket += 1 ; inivalue << char
1800
+ when "\""; dquote = true ; inivalue << char
1801
+ when "\'"; squote = true ; inivalue << char
1802
+ when "!" ; commentflag = true
1803
+ else ; inivalue << char
1804
+ end
1805
+ end
1806
+ elsif !(squote) && !(dquote) && bracket > 0
1807
+ case char
1808
+ when "(" ; bracket += 1 ; arraysuffix << char
1809
+ when ")" ; bracket -= 1 ; arraysuffix << char
1810
+ else ; arraysuffix << char
1811
+ end
1812
+ elsif squote
1813
+ case char
1814
+ when "\'"; squote = false ; inivalue << char
1815
+ else ; inivalue << char
1816
+ end
1817
+ elsif dquote
1818
+ case char
1819
+ when "\""; dquote = false ; inivalue << char
1820
+ else ; inivalue << char
1821
+ end
1822
+ end
1823
+ }
1824
+ defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
1825
+ if trailing_comment =~ /^:nodoc:/
1826
+ defs[start_pos..-1].collect!{ |defitem|
1827
+ defitem.nodoc = true
1828
+ }
1829
+ end
1830
+ varname = "" ; arraysuffix = "" ; inivalue = ""
1831
+ comment = ""
1832
+ under_comment_valid = true
1833
+ trailing_comment = ""
1834
+ }
1835
+ return defs
1836
+ end
1837
+
1838
+
1839
+ end # class Fortran95parser
1840
+
1841
+ end # module RDoc