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
|
---|