rdoc-f95 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +4 -0
- data/Manifest.txt +79 -0
- data/PostInstall.txt +7 -0
- data/README.rdoc +147 -0
- data/Rakefile +28 -0
- data/bin/rdoc-f95 +70 -0
- data/lib/rdoc-f95.rb +306 -0
- data/lib/rdoc-f95/code_objects.rb +776 -0
- data/lib/rdoc-f95/diagram.rb +342 -0
- data/lib/rdoc-f95/dot.rb +249 -0
- data/lib/rdoc-f95/generator.rb +1088 -0
- data/lib/rdoc-f95/generator/chm.rb +113 -0
- data/lib/rdoc-f95/generator/chm/chm.rb +98 -0
- data/lib/rdoc-f95/generator/html.rb +370 -0
- data/lib/rdoc-f95/generator/html/hefss.rb +414 -0
- data/lib/rdoc-f95/generator/html/html.rb +708 -0
- data/lib/rdoc-f95/generator/html/kilmer.rb +418 -0
- data/lib/rdoc-f95/generator/html/one_page_html.rb +121 -0
- data/lib/rdoc-f95/generator/ri.rb +229 -0
- data/lib/rdoc-f95/generator/xhtml.rb +106 -0
- data/lib/rdoc-f95/generator/xhtml/ctop.xsl +1318 -0
- data/lib/rdoc-f95/generator/xhtml/mathml.xsl +42 -0
- data/lib/rdoc-f95/generator/xhtml/pmathml.xsl +612 -0
- data/lib/rdoc-f95/generator/xhtml/pmathmlcss.xsl +872 -0
- data/lib/rdoc-f95/generator/xhtml/xhtml.rb +732 -0
- data/lib/rdoc-f95/generator/xml.rb +120 -0
- data/lib/rdoc-f95/generator/xml/rdf.rb +113 -0
- data/lib/rdoc-f95/generator/xml/xml.rb +111 -0
- data/lib/rdoc-f95/install.rb +166 -0
- data/lib/rdoc-f95/markup.rb +506 -0
- data/lib/rdoc-f95/markup/formatter.rb +14 -0
- data/lib/rdoc-f95/markup/fragments.rb +337 -0
- data/lib/rdoc-f95/markup/inline.rb +361 -0
- data/lib/rdoc-f95/markup/install.rb +57 -0
- data/lib/rdoc-f95/markup/lines.rb +152 -0
- data/lib/rdoc-f95/markup/mathml_wrapper.rb +91 -0
- data/lib/rdoc-f95/markup/preprocess.rb +71 -0
- data/lib/rdoc-f95/markup/sample/rdoc2latex.rb +16 -0
- data/lib/rdoc-f95/markup/sample/sample.rb +42 -0
- data/lib/rdoc-f95/markup/to_flow.rb +185 -0
- data/lib/rdoc-f95/markup/to_html.rb +357 -0
- data/lib/rdoc-f95/markup/to_html_crossref.rb +123 -0
- data/lib/rdoc-f95/markup/to_latex.rb +328 -0
- data/lib/rdoc-f95/markup/to_test.rb +50 -0
- data/lib/rdoc-f95/markup/to_xhtml_texparser.rb +234 -0
- data/lib/rdoc-f95/options.rb +745 -0
- data/lib/rdoc-f95/parsers/parse_c.rb +775 -0
- data/lib/rdoc-f95/parsers/parse_f95.rb +2499 -0
- data/lib/rdoc-f95/parsers/parse_rb.rb +2587 -0
- data/lib/rdoc-f95/parsers/parse_simple.rb +39 -0
- data/lib/rdoc-f95/parsers/parserfactory.rb +99 -0
- data/lib/rdoc-f95/ri.rb +2 -0
- data/lib/rdoc-f95/ri/cache.rb +188 -0
- data/lib/rdoc-f95/ri/descriptions.rb +147 -0
- data/lib/rdoc-f95/ri/display.rb +244 -0
- data/lib/rdoc-f95/ri/driver.rb +435 -0
- data/lib/rdoc-f95/ri/formatter.rb +603 -0
- data/lib/rdoc-f95/ri/paths.rb +105 -0
- data/lib/rdoc-f95/ri/reader.rb +106 -0
- data/lib/rdoc-f95/ri/util.rb +81 -0
- data/lib/rdoc-f95/ri/writer.rb +64 -0
- data/lib/rdoc-f95/stats.rb +23 -0
- data/lib/rdoc-f95/template.rb +64 -0
- data/lib/rdoc-f95/tokenstream.rb +33 -0
- data/lib/rdoc-f95/usage.rb +210 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/test/test_helper.rb +3 -0
- data/test/test_rdoc-f95.rb +11 -0
- metadata +156 -0
@@ -0,0 +1,2499 @@
|
|
1
|
+
#= parse_f95.rb - Fortran 90/95 Parser
|
2
|
+
#
|
3
|
+
#== Overview
|
4
|
+
#
|
5
|
+
#"parse_f95.rb" parses Fortran 90/95 files with suffixes "f90", "F90", "f95"
|
6
|
+
#and "F95". These files are expected to conform to Fortran 90 or
|
7
|
+
#Fortran 95 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 Fortran 90/95 programs
|
15
|
+
#
|
16
|
+
#"parse_f95.rb" parses entities of Fortran 90/95 standards, or main programs,
|
17
|
+
#modules, subroutines, functions, derived types, public variables,
|
18
|
+
#public constants, defined operators and defined assignments.
|
19
|
+
#These entities are described in items of RDoc documentation, as follows.
|
20
|
+
#
|
21
|
+
#Files :: Files (same as Ruby)
|
22
|
+
#Classes :: Modules, list of NAMELIST group names
|
23
|
+
#Methods :: Main programs, subroutines, functions, variables, constants,
|
24
|
+
# derived types, defined operators, defined assignments,
|
25
|
+
# NAMELIST group names
|
26
|
+
#Required files :: Files in which imported modules, external subroutines
|
27
|
+
# and external functions are defined.
|
28
|
+
#Included Modules :: List of imported modules
|
29
|
+
#Attributes :: List of derived types, List of imported modules all of
|
30
|
+
# whose components are published again
|
31
|
+
#
|
32
|
+
#Entities listed in 'Methods' (subroutines, functions, ...)
|
33
|
+
#defined in modules are described in the item of 'Classes'.
|
34
|
+
#On the other hand, defined in main programs or
|
35
|
+
#as external procedures are described in the item of 'Files'.
|
36
|
+
#Main programs are described in the item of 'Files', too.
|
37
|
+
#
|
38
|
+
#=== Parsed entities
|
39
|
+
#
|
40
|
+
#Documentation on public entities (main programs,
|
41
|
+
#subroutines, functions, variables, constants,
|
42
|
+
#derived types, defined operators,
|
43
|
+
#defined assignments, NAMELIST group names) are generated.
|
44
|
+
#With "--all" option, documentation on all entities
|
45
|
+
#are generated (almost same as the Ruby parser).
|
46
|
+
#
|
47
|
+
#
|
48
|
+
#=== Parsed information
|
49
|
+
#
|
50
|
+
#The following information is automatically parsed.
|
51
|
+
#
|
52
|
+
#* Data types and attributes of arguments of functions and subprograms
|
53
|
+
#* Data types and attributes of public variables and public constants
|
54
|
+
#* Data types, initial values, and attributes of variables in the derived types
|
55
|
+
#* Data types, initial values, and attributes of variables declared in NAMELIST statement
|
56
|
+
#
|
57
|
+
#Only attributes specified in type declaration statements are parsed.
|
58
|
+
#Attributes specified in POINTER, TARGET, ALLOCATE, INTENT, OPTIONAL, SAVE
|
59
|
+
#statements are not parsed.
|
60
|
+
#
|
61
|
+
#Aliases declared by INTERFACE statements are described in the item
|
62
|
+
#of 'Methods'.
|
63
|
+
#
|
64
|
+
#Entities which are imported from other modules and published again
|
65
|
+
#are described in the item of 'Methods'.
|
66
|
+
#
|
67
|
+
#
|
68
|
+
#=== Format of comment blocks
|
69
|
+
#
|
70
|
+
#Comment blocks should be written as follows.
|
71
|
+
#Comment blocks are considered to be ended when the line without '!'
|
72
|
+
#appears.
|
73
|
+
#The indentation is not necessary.
|
74
|
+
#
|
75
|
+
# ! (Top of file)
|
76
|
+
# !
|
77
|
+
# ! Comment blocks for the files.
|
78
|
+
# !
|
79
|
+
# !--
|
80
|
+
# ! The comment described in the part enclosed by
|
81
|
+
# ! "!--" and "!++" is ignored.
|
82
|
+
# !++
|
83
|
+
# !
|
84
|
+
# module hogehoge
|
85
|
+
# !
|
86
|
+
# ! Comment blocks for the modules (or the main programs).
|
87
|
+
# !
|
88
|
+
#
|
89
|
+
# private
|
90
|
+
#
|
91
|
+
# logical :: a ! a private variable
|
92
|
+
# real, public :: b ! a public variable
|
93
|
+
# integer, parameter :: c = 0 ! a public constant
|
94
|
+
#
|
95
|
+
# public :: c
|
96
|
+
# public :: MULTI_ARRAY
|
97
|
+
# public :: hoge, foo
|
98
|
+
#
|
99
|
+
# type MULTI_ARRAY
|
100
|
+
# !
|
101
|
+
# ! Comment blocks for the derived types.
|
102
|
+
# !
|
103
|
+
# real, pointer :: var(:) =>null() ! Comments block for the variables.
|
104
|
+
# integer :: num = 0
|
105
|
+
# end type MULTI_ARRAY
|
106
|
+
#
|
107
|
+
# contains
|
108
|
+
#
|
109
|
+
# subroutine hoge( in, & ! Comment blocks between continuation lines are ignored.
|
110
|
+
# & out )
|
111
|
+
# !
|
112
|
+
# ! Comment blocks for the subroutines or functions
|
113
|
+
# !
|
114
|
+
# character(*),intent(in):: in ! Comment blocks for the arguments.
|
115
|
+
# character(*),intent(out),allocatable,target :: in
|
116
|
+
# ! Comment blocks can be
|
117
|
+
# ! written under Fortran statements.
|
118
|
+
#
|
119
|
+
# character(32) :: file ! This comment parsed as a variable in below NAMELIST.
|
120
|
+
# integer :: id
|
121
|
+
#
|
122
|
+
# namelist /varinfo_nml/ file, id
|
123
|
+
# !
|
124
|
+
# ! Comment blocks for the NAMELIST statement.
|
125
|
+
# ! Information about variables are described above.
|
126
|
+
# !
|
127
|
+
#
|
128
|
+
# ....
|
129
|
+
#
|
130
|
+
# end subroutine hoge
|
131
|
+
#
|
132
|
+
# integer function foo( in )
|
133
|
+
# !
|
134
|
+
# ! This part is considered as comment block.
|
135
|
+
#
|
136
|
+
# ! Comment blocks under blank lines are ignored.
|
137
|
+
# !
|
138
|
+
# integer, intent(in):: inA ! This part is considered as comment block.
|
139
|
+
#
|
140
|
+
# ! This part is ignored.
|
141
|
+
#
|
142
|
+
# end function foo
|
143
|
+
#
|
144
|
+
# subroutine hide( in, &
|
145
|
+
# & out ) !:nodoc:
|
146
|
+
# !
|
147
|
+
# ! If '!:nodoc:' is described at end-of-line in SUBROUTINE
|
148
|
+
# ! statement as above, the subroutine is ignored.
|
149
|
+
# ! This assignment can be used to main programs, modules,
|
150
|
+
# ! subroutines, functions, variables, constants, derived types,
|
151
|
+
# ! defined operators, defined assignments,
|
152
|
+
# ! list of imported modules (USE statement).
|
153
|
+
# !
|
154
|
+
#
|
155
|
+
# ....
|
156
|
+
#
|
157
|
+
# end subroutine hide
|
158
|
+
#
|
159
|
+
# end module hogehoge
|
160
|
+
#
|
161
|
+
#
|
162
|
+
#=== The sequence of displayed entities
|
163
|
+
#
|
164
|
+
#Entities listed in 'Files' and 'Classes' are displayed in
|
165
|
+
#ASCII order usually (in particular, A...Z, a...z, ...).
|
166
|
+
#Entities with the same names declared by INTERFACE statements
|
167
|
+
#are ordered by argument keywords or contents in comment blocks.
|
168
|
+
#
|
169
|
+
#If you want to order entities manually, describe a comment
|
170
|
+
#like '<b><tt>!:doc-priority 100:</tt></b>' at end-of-line in
|
171
|
+
#the statement of the entities.
|
172
|
+
#`100` represents priority. Priority level is specified as follows.
|
173
|
+
#(Default number is '50').
|
174
|
+
#
|
175
|
+
#Integer of 0 or less :: Entities are displayed at the head of the document. Entities with more small number go upstairs.
|
176
|
+
#Integer from 1 to 99 :: Priority within entities with the same names. Entities with more small number go upstairs.
|
177
|
+
#Integer of 100 or more :: Entities are displayed at the foot of the document. Entities with more large number go downstairs.
|
178
|
+
#
|
179
|
+
#An example is showed as follows. When 'doc-priority' is written as
|
180
|
+
#a following example, a sequence of displayed entities is
|
181
|
+
#
|
182
|
+
#* top_display, generic_name_procedures (an original entity: bottom_display),
|
183
|
+
# generic_name_procedures (an original entity: top_display), bottom_display.
|
184
|
+
#
|
185
|
+
#On the other hand, if 'doc-priority' is not written, the sequence become
|
186
|
+
#
|
187
|
+
#* bottom_display, generic_name_procedures (an original entity: top_display),
|
188
|
+
# generic_name_procedures (an original entity: bottom_display), top_display.
|
189
|
+
#
|
190
|
+
#The details are given in the following example.
|
191
|
+
#
|
192
|
+
# module sample1
|
193
|
+
# :
|
194
|
+
# interface generic_name_procedures
|
195
|
+
# !
|
196
|
+
# ! This INTERFACE statement redefines "top_display" and
|
197
|
+
# ! "bottom_display" as an generic name "generic_name_procedures".
|
198
|
+
# !
|
199
|
+
# ! RDoc orders two "generic_name_procedures" by argument keywords
|
200
|
+
# ! essentially. Therefore "generic_name_procedures" that
|
201
|
+
# ! the original entity is "top_display" is displayed above because
|
202
|
+
# ! an argument keyword of the procedure begins 'c'.
|
203
|
+
# ! (The name of the original entity is ignored).
|
204
|
+
# !
|
205
|
+
# ! In the following example, because 'doc-priority' is written,
|
206
|
+
# ! "generic_name_procedures" that
|
207
|
+
# ! the original entity is "bottom_display" is displayed above because
|
208
|
+
# ! the numerical value is smaller.
|
209
|
+
# !
|
210
|
+
# module procedure bottom_display !:doc-priority 40:
|
211
|
+
# module procedure top_display !:doc-priority 60:
|
212
|
+
# end interface
|
213
|
+
# :
|
214
|
+
# contains
|
215
|
+
# :
|
216
|
+
# subroutine top_display(arg) !:doc-priority -10:
|
217
|
+
# !
|
218
|
+
# ! In a normal situation, this entity is displayed below 'bottom_display'.
|
219
|
+
# ! But because priority is -10, this entity is displayed above.
|
220
|
+
# !
|
221
|
+
# ....
|
222
|
+
# end subroutine top_display
|
223
|
+
#
|
224
|
+
# subroutine bottom_display(arg) !:doc-priority 110:
|
225
|
+
# !
|
226
|
+
# ! In a normal situation, this entity is displayed above 'top_display'.
|
227
|
+
# ! But because priority is 110, this entity is displayed below.
|
228
|
+
# !
|
229
|
+
# ....
|
230
|
+
# end subroutine bottom_display
|
231
|
+
# :
|
232
|
+
# end module sample1
|
233
|
+
#
|
234
|
+
#
|
235
|
+
|
236
|
+
require "rdoc-f95/code_objects"
|
237
|
+
|
238
|
+
module RDocF95
|
239
|
+
|
240
|
+
class Token
|
241
|
+
|
242
|
+
NO_TEXT = "??".freeze
|
243
|
+
|
244
|
+
def initialize(line_no, char_no)
|
245
|
+
@line_no = line_no
|
246
|
+
@char_no = char_no
|
247
|
+
@text = NO_TEXT
|
248
|
+
end
|
249
|
+
# Because we're used in contexts that expect to return a token,
|
250
|
+
# we set the text string and then return ourselves
|
251
|
+
def set_text(text)
|
252
|
+
@text = text
|
253
|
+
self
|
254
|
+
end
|
255
|
+
|
256
|
+
attr_reader :line_no, :char_no, :text
|
257
|
+
|
258
|
+
end
|
259
|
+
|
260
|
+
|
261
|
+
# Extend Context class for parse_f95.rb
|
262
|
+
# Original class is defined in code_objects.rb.
|
263
|
+
# * The case of names of classes or modules or methods are ignored
|
264
|
+
# * Includes modules can be refered.
|
265
|
+
|
266
|
+
class Context
|
267
|
+
|
268
|
+
def add_method(a_method)
|
269
|
+
if !(a_method.visibility == :public) &&
|
270
|
+
!(a_method.visibility == :private) &&
|
271
|
+
!(a_method.visibility == :protected)
|
272
|
+
a_method.visibility = @visibility
|
273
|
+
end
|
274
|
+
puts "Adding #{a_method.visibility} method #{a_method.name} to #@name" if $DEBUG_RDOC
|
275
|
+
add_to(@method_list, a_method)
|
276
|
+
end
|
277
|
+
|
278
|
+
def add_alias(an_alias, ignore_case=nil)
|
279
|
+
meth = find_instance_method_named(an_alias.old_name, ignore_case)
|
280
|
+
if meth
|
281
|
+
new_meth = AnyMethod.new(an_alias.text, an_alias.new_name)
|
282
|
+
new_meth.is_alias_for = meth
|
283
|
+
new_meth.singleton = meth.singleton
|
284
|
+
new_meth.params = meth.params
|
285
|
+
new_meth.comment = "Alias for \##{meth.name}"
|
286
|
+
meth.add_alias(new_meth)
|
287
|
+
add_method(new_meth)
|
288
|
+
else
|
289
|
+
add_to(@aliases, an_alias)
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
# Find a named module
|
294
|
+
def find_module_named(name, ignore_case=nil)
|
295
|
+
res = nil
|
296
|
+
if !ignore_case
|
297
|
+
return self if self.name == name
|
298
|
+
else
|
299
|
+
return self if self.name.upcase == name.upcase
|
300
|
+
end
|
301
|
+
if !ignore_case
|
302
|
+
res = @modules[name] || @classes[name]
|
303
|
+
else
|
304
|
+
@modules.each{ |n, v|
|
305
|
+
if n.upcase == name.upcase
|
306
|
+
res = v ; break
|
307
|
+
end
|
308
|
+
}
|
309
|
+
@classes.each{ |n, v|
|
310
|
+
if n.upcase == name.upcase
|
311
|
+
res = v ; break
|
312
|
+
end
|
313
|
+
} if !res
|
314
|
+
end
|
315
|
+
return res if res
|
316
|
+
find_enclosing_module_named(name, ignore_case)
|
317
|
+
end
|
318
|
+
|
319
|
+
# find a module at a higher scope
|
320
|
+
def find_enclosing_module_named(name, ignore_case=nil)
|
321
|
+
parent && parent.find_module_named(name, ignore_case)
|
322
|
+
end
|
323
|
+
|
324
|
+
def each_includes
|
325
|
+
@includes.each {|i| yield i}
|
326
|
+
end
|
327
|
+
|
328
|
+
# Look up the given filename.
|
329
|
+
def find_file(file, method=nil, ignore_case=nil)
|
330
|
+
find_file_named(file, method, ignore_case)
|
331
|
+
end
|
332
|
+
|
333
|
+
# Look up the given symbol. If method is non-nil, then
|
334
|
+
# we assume the symbol references a module that
|
335
|
+
# contains that method
|
336
|
+
def find_symbol(symbol, method=nil, ignore_case=nil)
|
337
|
+
result = nil
|
338
|
+
case symbol
|
339
|
+
when /^::(.*)/
|
340
|
+
result = toplevel.find_symbol($1, nil, ignore_case)
|
341
|
+
when /::/
|
342
|
+
modules = symbol.split(/::/)
|
343
|
+
unless modules.empty?
|
344
|
+
module_name = modules.shift
|
345
|
+
result = find_module_named(module_name, ignore_case)
|
346
|
+
if result
|
347
|
+
modules.each do |module_name|
|
348
|
+
result = result.find_module_named(module_name, ignore_case)
|
349
|
+
break unless result
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
353
|
+
else
|
354
|
+
# if a method is specified, then we're definitely looking for
|
355
|
+
# a module, otherwise it could be any symbol
|
356
|
+
if method
|
357
|
+
result = find_module_named(symbol, ignore_case)
|
358
|
+
else
|
359
|
+
result = find_local_symbol(symbol, ignore_case)
|
360
|
+
if result.nil?
|
361
|
+
if symbol =~ /^[A-Z]/ ||
|
362
|
+
symbol =~ /^[A-Za-z]/ && ignore_case
|
363
|
+
result = parent
|
364
|
+
while result && result.name != symbol
|
365
|
+
result = result.parent
|
366
|
+
end
|
367
|
+
end
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
371
|
+
if result && method
|
372
|
+
if !result.respond_to?(:find_local_symbol)
|
373
|
+
p result.name
|
374
|
+
p method
|
375
|
+
fail
|
376
|
+
end
|
377
|
+
result = result.find_local_symbol(method, ignore_case)
|
378
|
+
end
|
379
|
+
result
|
380
|
+
end
|
381
|
+
|
382
|
+
def find_local_symbol(symbol, ignore_case=nil)
|
383
|
+
res = find_method_named(symbol, ignore_case) ||
|
384
|
+
find_constant_named(symbol, ignore_case) ||
|
385
|
+
find_attribute_named(symbol, ignore_case) ||
|
386
|
+
find_module_named(symbol, ignore_case)
|
387
|
+
end
|
388
|
+
|
389
|
+
def include_requires?(name, ignore_case=nil)
|
390
|
+
if self.kind_of? TopLevel
|
391
|
+
self.requires.each{|r|
|
392
|
+
if r.name == name ||
|
393
|
+
r.name.upcase == name.upcase && ignore_case
|
394
|
+
return true
|
395
|
+
end
|
396
|
+
}
|
397
|
+
return false
|
398
|
+
else
|
399
|
+
parent.include_requires?(name)
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
def include_includes?(name, ignore_case=nil)
|
404
|
+
self.includes.each{|i|
|
405
|
+
if i.name == name ||
|
406
|
+
i.name.upcase == name.upcase && ignore_case
|
407
|
+
return true
|
408
|
+
end
|
409
|
+
}
|
410
|
+
return false
|
411
|
+
end
|
412
|
+
|
413
|
+
# Find a named method, or return nil
|
414
|
+
def find_method_named(name, ignore_case=nil)
|
415
|
+
if !ignore_case
|
416
|
+
@method_list.find {|meth| meth.name == name}
|
417
|
+
else
|
418
|
+
@method_list.find {|meth| meth.name.upcase == name.upcase}
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
422
|
+
# Find a named instance method, or return nil
|
423
|
+
def find_instance_method_named(name, ignore_case=nil)
|
424
|
+
if !ignore_case
|
425
|
+
@method_list.find {|meth| meth.name == name && !meth.singleton}
|
426
|
+
else
|
427
|
+
@method_list.find {|meth|
|
428
|
+
meth.name.upcase == name.upcase && !meth.singleton
|
429
|
+
}
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
# Find a named constant, or return nil
|
434
|
+
def find_constant_named(name, ignore_case=nil)
|
435
|
+
if !ignore_case
|
436
|
+
@constants.find {|m| m.name == name}
|
437
|
+
else
|
438
|
+
@constants.find {|m| m.name.upcase == name.upcase}
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
# Find a named attribute, or return nil
|
443
|
+
def find_attribute_named(name, ignore_case=nil)
|
444
|
+
if !ignore_case
|
445
|
+
@attributes.find {|m| m.name == name}
|
446
|
+
else
|
447
|
+
@attributes.find {|m| m.name.upcase == name.upcase}
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
end
|
452
|
+
|
453
|
+
|
454
|
+
|
455
|
+
# Extend TopLevel class for parse_f95.rb.
|
456
|
+
# Original class is defined in code_objects.rb.
|
457
|
+
# * Cross-reference of files are enabled
|
458
|
+
# * The case of names of classes or modules or methods are ignored
|
459
|
+
|
460
|
+
class TopLevel
|
461
|
+
@@all_files = {}
|
462
|
+
|
463
|
+
def TopLevel::reset
|
464
|
+
@@all_classes = {}
|
465
|
+
@@all_modules = {}
|
466
|
+
@@all_files = {}
|
467
|
+
end
|
468
|
+
|
469
|
+
def initialize(file_name)
|
470
|
+
super()
|
471
|
+
@name = "TopLevel"
|
472
|
+
@file_relative_name = file_name
|
473
|
+
@file_absolute_name = file_name
|
474
|
+
@file_stat = File.stat(file_name)
|
475
|
+
@diagram = nil
|
476
|
+
@@all_files[file_name] = self
|
477
|
+
end
|
478
|
+
|
479
|
+
def TopLevel.all_files
|
480
|
+
@@all_files
|
481
|
+
end
|
482
|
+
|
483
|
+
def find_local_symbol(symbol, ignore_case=nil)
|
484
|
+
find_class_or_module_named(symbol, ignore_case) || super
|
485
|
+
end
|
486
|
+
|
487
|
+
def find_class_or_module_named(symbol, ignore_case=nil)
|
488
|
+
if !ignore_case
|
489
|
+
@@all_classes.each_value {|c| return c if c.name == symbol}
|
490
|
+
@@all_modules.each_value {|m| return m if m.name == symbol}
|
491
|
+
else
|
492
|
+
@@all_classes.each_value {|c| return c if c.name.upcase == symbol.upcase}
|
493
|
+
@@all_modules.each_value {|m| return m if m.name.upcase == symbol.upcase}
|
494
|
+
end
|
495
|
+
nil
|
496
|
+
end
|
497
|
+
|
498
|
+
# Find a named module
|
499
|
+
def find_module_named(name, ignore_case=nil)
|
500
|
+
find_class_or_module_named(name, ignore_case) || find_enclosing_module_named(name, ignore_case)
|
501
|
+
end
|
502
|
+
|
503
|
+
# Find a named file
|
504
|
+
def find_file_named(name, method=nil, ignore_case=nil)
|
505
|
+
return nil unless name
|
506
|
+
result = nil
|
507
|
+
@@all_files.each{|file_name, toplevel|
|
508
|
+
result = toplevel if file_name == name
|
509
|
+
}
|
510
|
+
dir = File.dirname(@file_relative_name)
|
511
|
+
@@all_files.each{|file_name, toplevel|
|
512
|
+
if /^#{dir}\/(.*)/ =~ file_name
|
513
|
+
result = toplevel if $1 == name
|
514
|
+
end
|
515
|
+
}
|
516
|
+
if result
|
517
|
+
if method
|
518
|
+
result_method = result.find_local_symbol(method, ignore_case)
|
519
|
+
return result_method
|
520
|
+
else
|
521
|
+
return result
|
522
|
+
end
|
523
|
+
else
|
524
|
+
return nil
|
525
|
+
end
|
526
|
+
end
|
527
|
+
|
528
|
+
end
|
529
|
+
|
530
|
+
|
531
|
+
# Extend ClassModule class for parse_f95.rb
|
532
|
+
# Original class is defined in code_objects.rb.
|
533
|
+
# * The case of names of classes or modules or methods are ignored
|
534
|
+
|
535
|
+
class ClassModule
|
536
|
+
def find_file_named(name, method=nil, ignore_case=nil)
|
537
|
+
parent.find_file_named(name, method, ignore_case)
|
538
|
+
end
|
539
|
+
end
|
540
|
+
|
541
|
+
# Extend AnyMethod class for parse_f95.rb
|
542
|
+
# Original class is defined in code_objects.rb.
|
543
|
+
# * A method "<=>" is modified.
|
544
|
+
|
545
|
+
class AnyMethod < CodeObject
|
546
|
+
|
547
|
+
attr_reader :doc_priority
|
548
|
+
|
549
|
+
def initialize(text, name)
|
550
|
+
super()
|
551
|
+
@text = text
|
552
|
+
@name = name
|
553
|
+
@token_stream = nil
|
554
|
+
@visibility = :public
|
555
|
+
@dont_rename_initialize = false
|
556
|
+
@block_params = nil
|
557
|
+
@aliases = []
|
558
|
+
@is_alias_for = nil
|
559
|
+
@comment = ""
|
560
|
+
@call_seq = nil
|
561
|
+
@doc_priority = 50
|
562
|
+
end
|
563
|
+
|
564
|
+
def set_priority(doc_priority)
|
565
|
+
if doc_priority.class.to_s == 'Fixnum'
|
566
|
+
@doc_priority = doc_priority
|
567
|
+
end
|
568
|
+
end
|
569
|
+
|
570
|
+
def <=>(other)
|
571
|
+
if @doc_priority < 1 && other.doc_priority < 1
|
572
|
+
t = @doc_priority <=> other.doc_priority
|
573
|
+
return t if t != 0
|
574
|
+
elsif @doc_priority < 1 && other.doc_priority >= 1
|
575
|
+
return -1
|
576
|
+
elsif @doc_priority >= 1 && other.doc_priority < 1
|
577
|
+
return 1
|
578
|
+
end
|
579
|
+
|
580
|
+
if @doc_priority > 99 && other.doc_priority > 99
|
581
|
+
t = @doc_priority <=> other.doc_priority
|
582
|
+
return t if t != 0
|
583
|
+
elsif @doc_priority > 99 && other.doc_priority <= 99
|
584
|
+
return 1
|
585
|
+
elsif @doc_priority <= 99 && other.doc_priority > 99
|
586
|
+
return -1
|
587
|
+
end
|
588
|
+
|
589
|
+
t = @name <=> other.name
|
590
|
+
return t if t != 0
|
591
|
+
t = @doc_priority <=> other.doc_priority
|
592
|
+
return t if t != 0
|
593
|
+
t = @params <=> other.params
|
594
|
+
return t if t != 0
|
595
|
+
t = @comment <=> other.comment
|
596
|
+
end
|
597
|
+
end
|
598
|
+
|
599
|
+
|
600
|
+
#See rdoc/parsers/parse_f95.rb
|
601
|
+
#
|
602
|
+
class Fortran95parser
|
603
|
+
|
604
|
+
extend ParserFactory
|
605
|
+
parse_files_matching(/\.((f|F)9(0|5)|F)$/)
|
606
|
+
|
607
|
+
@@external_aliases = []
|
608
|
+
@@public_methods = []
|
609
|
+
|
610
|
+
# "false":: Comments are below source code
|
611
|
+
# "true" :: Comments are upper source code
|
612
|
+
COMMENTS_ARE_UPPER = false
|
613
|
+
|
614
|
+
# Internal alias message
|
615
|
+
INTERNAL_ALIAS_MES = "Alias for"
|
616
|
+
|
617
|
+
# External alias message
|
618
|
+
EXTERNAL_ALIAS_MES = "Original external subprogram is"
|
619
|
+
|
620
|
+
# Provided modules message
|
621
|
+
PROVIDED_MODULES_MES = "This file provides the following module"
|
622
|
+
|
623
|
+
# Repository of NAMELIST statements
|
624
|
+
NAMELIST_REPOSITORY_NAME = "NAMELIST"
|
625
|
+
|
626
|
+
# Ignored marker
|
627
|
+
IGNORED_MARKER_REGEXP = /^:nodoc:/
|
628
|
+
|
629
|
+
# Document priority marker
|
630
|
+
DOC_PRIORITY_REGEXP = /^:doc\-priority\s+([\-\+]?\d+):\s*/
|
631
|
+
|
632
|
+
# prepare to parse a Fortran 95 file
|
633
|
+
def initialize(top_level, file_name, body, options, stats)
|
634
|
+
@body = body
|
635
|
+
@stats = stats
|
636
|
+
@file_name = file_name
|
637
|
+
@options = options
|
638
|
+
@top_level = top_level
|
639
|
+
@progress = $stderr unless options.quiet
|
640
|
+
|
641
|
+
begin
|
642
|
+
@options_ignore_case = options.ignore_case
|
643
|
+
rescue
|
644
|
+
@options_ignore_case = true
|
645
|
+
end
|
646
|
+
|
647
|
+
end
|
648
|
+
|
649
|
+
# devine code constructs
|
650
|
+
def scan
|
651
|
+
|
652
|
+
# remove private comment
|
653
|
+
remaining_code = remove_private_comments(@body)
|
654
|
+
|
655
|
+
# continuation lines are united to one line
|
656
|
+
remaining_code = united_to_one_line(remaining_code)
|
657
|
+
|
658
|
+
# semicolons are replaced to line feed
|
659
|
+
remaining_code = semicolon_to_linefeed(remaining_code)
|
660
|
+
|
661
|
+
# collect comment for file entity
|
662
|
+
whole_comment, remaining_code = collect_first_comment(remaining_code)
|
663
|
+
@top_level.comment = whole_comment
|
664
|
+
|
665
|
+
# String "remaining_code" is converted to Array "remaining_lines"
|
666
|
+
remaining_lines = remaining_code.split("\n")
|
667
|
+
|
668
|
+
# "module" or "program" parts are parsed (new)
|
669
|
+
#
|
670
|
+
level_depth = 0
|
671
|
+
block_searching_flag = nil
|
672
|
+
block_searching_lines = []
|
673
|
+
pre_comment = []
|
674
|
+
module_program_trailing = ""
|
675
|
+
module_program_name = ""
|
676
|
+
other_block_level_depth = 0
|
677
|
+
other_block_searching_flag = nil
|
678
|
+
remaining_lines.collect!{|line|
|
679
|
+
if !block_searching_flag && !other_block_searching_flag
|
680
|
+
if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i
|
681
|
+
block_searching_flag = :module
|
682
|
+
block_searching_lines << line
|
683
|
+
module_program_name = $1
|
684
|
+
module_program_trailing = find_comments($2)
|
685
|
+
next false
|
686
|
+
elsif line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i ||
|
687
|
+
line =~ /^\s*?\w/ && !block_start?(line)
|
688
|
+
block_searching_flag = :program
|
689
|
+
block_searching_lines << line
|
690
|
+
module_program_name = $1 || ""
|
691
|
+
module_program_trailing = find_comments($2)
|
692
|
+
next false
|
693
|
+
|
694
|
+
elsif block_start?(line)
|
695
|
+
other_block_searching_flag = true
|
696
|
+
next line
|
697
|
+
|
698
|
+
elsif line =~ /^\s*?!\s?(.*)/
|
699
|
+
pre_comment << line
|
700
|
+
next line
|
701
|
+
else
|
702
|
+
pre_comment = []
|
703
|
+
next line
|
704
|
+
end
|
705
|
+
elsif other_block_searching_flag
|
706
|
+
other_block_level_depth += 1 if block_start?(line)
|
707
|
+
other_block_level_depth -= 1 if block_end?(line)
|
708
|
+
if other_block_level_depth < 0
|
709
|
+
other_block_level_depth = 0
|
710
|
+
other_block_searching_flag = nil
|
711
|
+
end
|
712
|
+
next line
|
713
|
+
end
|
714
|
+
|
715
|
+
block_searching_lines << line
|
716
|
+
level_depth += 1 if block_start?(line)
|
717
|
+
level_depth -= 1 if block_end?(line)
|
718
|
+
if level_depth >= 0
|
719
|
+
next false
|
720
|
+
end
|
721
|
+
|
722
|
+
# "module_program_code" is formatted.
|
723
|
+
# ":nodoc:" flag is checked.
|
724
|
+
#
|
725
|
+
module_program_code = block_searching_lines.join("\n")
|
726
|
+
module_program_code = remove_empty_head_lines(module_program_code)
|
727
|
+
if module_program_trailing =~ IGNORED_MARKER_REGEXP
|
728
|
+
# next loop to search next block
|
729
|
+
level_depth = 0
|
730
|
+
block_searching_flag = false
|
731
|
+
block_searching_lines = []
|
732
|
+
pre_comment = []
|
733
|
+
next false
|
734
|
+
end
|
735
|
+
|
736
|
+
# NormalClass is created, and added to @top_level
|
737
|
+
#
|
738
|
+
if block_searching_flag == :module
|
739
|
+
module_name = module_program_name
|
740
|
+
module_code = module_program_code
|
741
|
+
module_trailing = module_program_trailing
|
742
|
+
progress "m"
|
743
|
+
@stats.num_modules += 1
|
744
|
+
f9x_module = @top_level.add_module NormalClass, module_name
|
745
|
+
f9x_module.record_location @top_level
|
746
|
+
|
747
|
+
#
|
748
|
+
# Add provided modules information to @top_level comment
|
749
|
+
#
|
750
|
+
provided_modules = []
|
751
|
+
provided_mes_line_num = nil
|
752
|
+
top_level_comment_lines = []
|
753
|
+
line_num = 0
|
754
|
+
@top_level.comment.split("\n").each{|line|
|
755
|
+
top_level_comment_lines << line
|
756
|
+
line_num += 1
|
757
|
+
next if line.empty?
|
758
|
+
if !provided_mes_line_num && /^\s?#{PROVIDED_MODULES_MES}/ =~ line
|
759
|
+
provided_mes_line_num = line_num
|
760
|
+
next
|
761
|
+
end
|
762
|
+
if provided_mes_line_num
|
763
|
+
if /^\s?\*\s+<b>(\w+)<\/b>/ =~ line
|
764
|
+
provided_modules << $1
|
765
|
+
else
|
766
|
+
provided_mes_line_num = nil
|
767
|
+
end
|
768
|
+
end
|
769
|
+
}
|
770
|
+
line_num = 0
|
771
|
+
if provided_mes_line_num
|
772
|
+
top_level_comment_lines.collect!{ |line|
|
773
|
+
line_num += 1
|
774
|
+
if line_num < provided_mes_line_num
|
775
|
+
line
|
776
|
+
else
|
777
|
+
nil
|
778
|
+
end
|
779
|
+
}
|
780
|
+
top_level_comment_lines.delete_if{|line| !line }
|
781
|
+
end
|
782
|
+
top_level_comment_lines << "\n" + PROVIDED_MODULES_MES + "."
|
783
|
+
if provided_mes_line_num
|
784
|
+
top_level_comment_lines[-1].sub!(/\.$/, '')
|
785
|
+
top_level_comment_lines[-1] << "s."
|
786
|
+
end
|
787
|
+
provided_modules.each{ |mod|
|
788
|
+
top_level_comment_lines << "* <b>" + mod + "</b>"
|
789
|
+
}
|
790
|
+
top_level_comment_lines << "* <b>" + module_name + "</b>"
|
791
|
+
@top_level.comment = top_level_comment_lines.join("\n")
|
792
|
+
|
793
|
+
#
|
794
|
+
# Information about the module is parsed
|
795
|
+
#
|
796
|
+
f9x_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) +
|
797
|
+
"\n" + module_trailing : module_trailing + "\n" +
|
798
|
+
find_comments(module_code.sub(/^.*$\n/i, ''))
|
799
|
+
f9x_module.comment = f9x_comment
|
800
|
+
parse_program_or_module(f9x_module, module_code)
|
801
|
+
|
802
|
+
TopLevel.all_files.each do |name, toplevel|
|
803
|
+
if toplevel.include_includes?(module_name, @options_ignore_case)
|
804
|
+
if !toplevel.include_requires?(@file_name, @options_ignore_case)
|
805
|
+
toplevel.add_require(Require.new(@file_name, ""))
|
806
|
+
end
|
807
|
+
end
|
808
|
+
toplevel.each_classmodule{|m|
|
809
|
+
if m.include_includes?(module_name, @options_ignore_case)
|
810
|
+
if !m.include_requires?(@file_name, @options_ignore_case)
|
811
|
+
m.add_require(Require.new(@file_name, ""))
|
812
|
+
end
|
813
|
+
end
|
814
|
+
}
|
815
|
+
end
|
816
|
+
|
817
|
+
namelist_comment =
|
818
|
+
find_namelists(f9x_module, before_contains(module_code))
|
819
|
+
f9x_module.comment << namelist_comment if namelist_comment
|
820
|
+
|
821
|
+
elsif block_searching_flag == :program
|
822
|
+
program_name = module_program_name
|
823
|
+
program_name = "main_program" if program_name.empty?
|
824
|
+
program_code = module_program_code
|
825
|
+
program_trailing = module_program_trailing
|
826
|
+
program_priority, program_trailing = doc_priority_from_trailing(program_trailing)
|
827
|
+
|
828
|
+
program_comment = COMMENTS_ARE_UPPER ? find_comments(pre_comment.join("\n")) +
|
829
|
+
"\n" + program_trailing : program_trailing + "\n" +
|
830
|
+
find_comments(program_code.sub(/^.*$\n/i, ''))
|
831
|
+
|
832
|
+
progress "p"
|
833
|
+
@stats.num_methods += 1
|
834
|
+
f9x_mainprogram = AnyMethod.new("main_program", program_name)
|
835
|
+
f9x_mainprogram.singleton = false
|
836
|
+
f9x_mainprogram.comment = "<b><em> Main Program </em></b> :: <tt></tt>\n"
|
837
|
+
f9x_mainprogram.comment << program_comment
|
838
|
+
f9x_mainprogram.params = ""
|
839
|
+
f9x_mainprogram.set_priority(program_priority) if program_priority
|
840
|
+
|
841
|
+
# For output source code
|
842
|
+
f9x_mainprogram.start_collecting_tokens
|
843
|
+
f9x_mainprogram.add_token Token.new(1,1).set_text(program_code)
|
844
|
+
|
845
|
+
@top_level.add_method f9x_mainprogram
|
846
|
+
parse_program_or_module(@top_level, program_code, :private)
|
847
|
+
|
848
|
+
namelist_comment = find_namelists(f9x_mainprogram, program_code)
|
849
|
+
f9x_mainprogram.comment << namelist_comment if namelist_comment
|
850
|
+
end
|
851
|
+
|
852
|
+
# next loop to search next block
|
853
|
+
level_depth = 0
|
854
|
+
block_searching_flag = false
|
855
|
+
block_searching_lines = []
|
856
|
+
pre_comment = []
|
857
|
+
next false
|
858
|
+
}
|
859
|
+
|
860
|
+
remaining_lines.delete_if{ |line|
|
861
|
+
line == false
|
862
|
+
}
|
863
|
+
|
864
|
+
# External subprograms and functions are parsed
|
865
|
+
#
|
866
|
+
parse_program_or_module(@top_level, remaining_lines.join("\n"),
|
867
|
+
:public, true)
|
868
|
+
|
869
|
+
@top_level
|
870
|
+
end # End of scan
|
871
|
+
|
872
|
+
private
|
873
|
+
|
874
|
+
def parse_program_or_module(container, code,
|
875
|
+
visibility=:public, external=nil)
|
876
|
+
return unless container
|
877
|
+
return unless code
|
878
|
+
remaining_lines = code.split("\n")
|
879
|
+
remaining_code = "#{code}"
|
880
|
+
|
881
|
+
#
|
882
|
+
# Parse variables before "contains" in module
|
883
|
+
#
|
884
|
+
before_contains_code = before_contains(remaining_code)
|
885
|
+
|
886
|
+
#
|
887
|
+
# Parse global "use"
|
888
|
+
#
|
889
|
+
use_check_code = "#{before_contains_code}"
|
890
|
+
cascaded_modules_list = []
|
891
|
+
while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i
|
892
|
+
use_check_code = $~.pre_match
|
893
|
+
use_check_code << $~.post_match
|
894
|
+
used_mod_name = $1.strip.chomp
|
895
|
+
used_list = $2 || ""
|
896
|
+
used_trailing = $3 || ""
|
897
|
+
next if used_trailing.sub(/^!/, '') =~ IGNORED_MARKER_REGEXP
|
898
|
+
if !container.include_includes?(used_mod_name, @options_ignore_case)
|
899
|
+
progress "."
|
900
|
+
container.add_include Include.new(used_mod_name, "")
|
901
|
+
end
|
902
|
+
if ! (used_list =~ /\,\s*?only\s*?:/i )
|
903
|
+
cascaded_modules_list << "\#" + used_mod_name
|
904
|
+
end
|
905
|
+
end
|
906
|
+
|
907
|
+
#
|
908
|
+
# Parse public and private, and store information.
|
909
|
+
# This information is used when "add_method" and
|
910
|
+
# "set_visibility_for" are called.
|
911
|
+
#
|
912
|
+
visibility_default, visibility_info =
|
913
|
+
parse_visibility(remaining_lines.join("\n"), visibility, container)
|
914
|
+
@@public_methods.concat visibility_info
|
915
|
+
if visibility_default == :public
|
916
|
+
if !cascaded_modules_list.empty?
|
917
|
+
cascaded_modules =
|
918
|
+
Attr.new("Cascaded Modules",
|
919
|
+
"Imported modules all of whose components are published again",
|
920
|
+
"",
|
921
|
+
cascaded_modules_list.join(", "))
|
922
|
+
container.add_attribute(cascaded_modules)
|
923
|
+
end
|
924
|
+
end
|
925
|
+
|
926
|
+
#
|
927
|
+
# Check rename elements
|
928
|
+
#
|
929
|
+
use_check_code = "#{before_contains_code}"
|
930
|
+
while use_check_code =~ /^\s*?use\s+(\w+)\s*?\,(.+)$/i
|
931
|
+
use_check_code = $~.pre_match
|
932
|
+
use_check_code << $~.post_match
|
933
|
+
used_mod_name = $1.strip.chomp
|
934
|
+
used_elements = $2.sub(/\s*?only\s*?:\s*?/i, '')
|
935
|
+
used_elements.split(",").each{ |used|
|
936
|
+
if /\s*?(\w+)\s*?=>\s*?(\w+)\s*?/ =~ used
|
937
|
+
local = $1
|
938
|
+
org = $2
|
939
|
+
@@public_methods.collect!{ |pub_meth|
|
940
|
+
if local == pub_meth["name"] ||
|
941
|
+
local.upcase == pub_meth["name"].upcase &&
|
942
|
+
@options_ignore_case
|
943
|
+
pub_meth["name"] = org
|
944
|
+
pub_meth["local_name"] = local
|
945
|
+
end
|
946
|
+
pub_meth
|
947
|
+
}
|
948
|
+
end
|
949
|
+
}
|
950
|
+
end
|
951
|
+
|
952
|
+
#
|
953
|
+
# Parse private "use"
|
954
|
+
#
|
955
|
+
use_check_code = remaining_lines.join("\n")
|
956
|
+
while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i
|
957
|
+
use_check_code = $~.pre_match
|
958
|
+
use_check_code << $~.post_match
|
959
|
+
used_mod_name = $1.strip.chomp
|
960
|
+
used_trailing = $3 || ""
|
961
|
+
next if used_trailing.sub(/^!/, '') =~ IGNORED_MARKER_REGEXP
|
962
|
+
if !container.include_includes?(used_mod_name, @options_ignore_case)
|
963
|
+
progress "."
|
964
|
+
container.add_include Include.new(used_mod_name, "")
|
965
|
+
end
|
966
|
+
end
|
967
|
+
|
968
|
+
container.each_includes{ |inc|
|
969
|
+
TopLevel.all_files.each do |name, toplevel|
|
970
|
+
indicated_mod = toplevel.find_symbol(inc.name,
|
971
|
+
nil, @options_ignore_case)
|
972
|
+
if indicated_mod
|
973
|
+
indicated_name = indicated_mod.parent.file_relative_name
|
974
|
+
if !container.include_requires?(indicated_name, @options_ignore_case)
|
975
|
+
container.add_require(Require.new(indicated_name, ""))
|
976
|
+
end
|
977
|
+
break
|
978
|
+
end
|
979
|
+
end
|
980
|
+
}
|
981
|
+
|
982
|
+
#
|
983
|
+
# Parse derived types definitions
|
984
|
+
#
|
985
|
+
derived_types_comment = ""
|
986
|
+
remaining_code = remaining_lines.join("\n")
|
987
|
+
while remaining_code =~ /^\s*?
|
988
|
+
type[\s\,]+(public|private)?\s*?(::)?\s*?
|
989
|
+
(\w+)\s*?(!.*?)?$
|
990
|
+
(.*?)
|
991
|
+
^\s*?end\s+type.*?$
|
992
|
+
/imx
|
993
|
+
remaining_code = $~.pre_match
|
994
|
+
remaining_code << $~.post_match
|
995
|
+
typename = $3.chomp.strip
|
996
|
+
type_elements = $5 || ""
|
997
|
+
type_code = remove_empty_head_lines($&)
|
998
|
+
type_trailing = find_comments($4)
|
999
|
+
type_visibility = $1
|
1000
|
+
pre_match = $~.pre_match
|
1001
|
+
next if type_trailing =~ IGNORED_MARKER_REGEXP
|
1002
|
+
type_priority, type_trailing = doc_priority_from_trailing(type_trailing)
|
1003
|
+
type_comment = COMMENTS_ARE_UPPER ?
|
1004
|
+
find_comments(pre_match) + "\n" + type_trailing :
|
1005
|
+
type_trailing + "\n" + find_comments(type_code.sub(/^.*$\n/i, ''))
|
1006
|
+
type_element_visibility_public = true
|
1007
|
+
type_code.split("\n").each{ |line|
|
1008
|
+
if /^\s*?private\s*?$/ =~ line
|
1009
|
+
type_element_visibility_public = nil
|
1010
|
+
break
|
1011
|
+
end
|
1012
|
+
} if type_code
|
1013
|
+
|
1014
|
+
args_comment = ""
|
1015
|
+
type_args_info = nil
|
1016
|
+
|
1017
|
+
if @options.show_all
|
1018
|
+
args_comment = find_arguments(nil, type_code, true)
|
1019
|
+
else
|
1020
|
+
type_public_args_list = []
|
1021
|
+
type_args_info = definition_info(type_code)
|
1022
|
+
type_args_info.each{ |arg|
|
1023
|
+
arg_is_public = type_element_visibility_public
|
1024
|
+
arg_is_public = true if arg.include_attr?("public")
|
1025
|
+
arg_is_public = nil if arg.include_attr?("private")
|
1026
|
+
type_public_args_list << arg.varname if arg_is_public
|
1027
|
+
}
|
1028
|
+
args_comment = find_arguments(type_public_args_list, type_code)
|
1029
|
+
end
|
1030
|
+
|
1031
|
+
type = AnyMethod.new("type #{typename}", typename)
|
1032
|
+
type.singleton = false
|
1033
|
+
type.params = ""
|
1034
|
+
type.comment = "<b><em> Derived Type </em></b> :: <tt></tt>\n"
|
1035
|
+
type.comment << args_comment if args_comment
|
1036
|
+
type.comment << type_comment if type_comment
|
1037
|
+
type.set_priority(type_priority) if type_priority
|
1038
|
+
progress "t"
|
1039
|
+
@stats.num_methods += 1
|
1040
|
+
container.add_method type
|
1041
|
+
|
1042
|
+
set_visibility(container, typename, visibility_default, @@public_methods)
|
1043
|
+
|
1044
|
+
if type_visibility
|
1045
|
+
type_visibility.gsub!(/\s/,'')
|
1046
|
+
type_visibility.gsub!(/\,/,'')
|
1047
|
+
type_visibility.gsub!(/:/,'')
|
1048
|
+
type_visibility.downcase!
|
1049
|
+
if type_visibility == "public"
|
1050
|
+
container.set_visibility_for([typename], :public)
|
1051
|
+
elsif type_visibility == "private"
|
1052
|
+
container.set_visibility_for([typename], :private)
|
1053
|
+
end
|
1054
|
+
end
|
1055
|
+
|
1056
|
+
check_public_methods(type, container.name)
|
1057
|
+
|
1058
|
+
if @options.show_all
|
1059
|
+
derived_types_comment << ", " unless derived_types_comment.empty?
|
1060
|
+
derived_types_comment << typename
|
1061
|
+
else
|
1062
|
+
if type.visibility == :public
|
1063
|
+
derived_types_comment << ", " unless derived_types_comment.empty?
|
1064
|
+
derived_types_comment << typename
|
1065
|
+
end
|
1066
|
+
end
|
1067
|
+
|
1068
|
+
end
|
1069
|
+
|
1070
|
+
if !derived_types_comment.empty?
|
1071
|
+
derived_types_table =
|
1072
|
+
Attr.new("Derived Types", "Derived_Types", "",
|
1073
|
+
derived_types_comment)
|
1074
|
+
container.add_attribute(derived_types_table)
|
1075
|
+
end
|
1076
|
+
|
1077
|
+
#
|
1078
|
+
# move interface scope
|
1079
|
+
#
|
1080
|
+
interface_code = ""
|
1081
|
+
while remaining_code =~ /^\s*?
|
1082
|
+
interface(
|
1083
|
+
\s+\w+ |
|
1084
|
+
\s+operator\s*?\(.*?\) |
|
1085
|
+
\s+assignment\s*?\(\s*?=\s*?\)
|
1086
|
+
)?\s*?$
|
1087
|
+
(.*?)
|
1088
|
+
^\s*?end\s+interface.*?$
|
1089
|
+
/imx
|
1090
|
+
interface_code << remove_empty_head_lines($&) + "\n"
|
1091
|
+
remaining_code = $~.pre_match
|
1092
|
+
remaining_code << $~.post_match
|
1093
|
+
end
|
1094
|
+
|
1095
|
+
#
|
1096
|
+
# Parse global constants or variables in modules
|
1097
|
+
#
|
1098
|
+
const_var_defs = definition_info(before_contains_code)
|
1099
|
+
const_var_defs.each{|defitem|
|
1100
|
+
next if defitem.nodoc
|
1101
|
+
const_or_var_type = "Variable"
|
1102
|
+
const_or_var_progress = "v"
|
1103
|
+
if defitem.include_attr?("parameter")
|
1104
|
+
const_or_var_type = "Constant"
|
1105
|
+
const_or_var_progress = "c"
|
1106
|
+
end
|
1107
|
+
const_or_var = AnyMethod.new(const_or_var_type, defitem.varname)
|
1108
|
+
const_or_var.set_priority(defitem.doc_priority) if defitem.doc_priority
|
1109
|
+
const_or_var.singleton = false
|
1110
|
+
const_or_var.params = ""
|
1111
|
+
self_comment = find_arguments([defitem.varname], before_contains_code)
|
1112
|
+
const_or_var.comment = "<b><em>" + const_or_var_type + "</em></b> :: <tt></tt>\n"
|
1113
|
+
const_or_var.comment << self_comment if self_comment
|
1114
|
+
progress const_or_var_progress
|
1115
|
+
@stats.num_methods += 1
|
1116
|
+
container.add_method const_or_var
|
1117
|
+
|
1118
|
+
set_visibility(container, defitem.varname, visibility_default, @@public_methods)
|
1119
|
+
|
1120
|
+
if defitem.include_attr?("public")
|
1121
|
+
container.set_visibility_for([defitem.varname], :public)
|
1122
|
+
elsif defitem.include_attr?("private")
|
1123
|
+
container.set_visibility_for([defitem.varname], :private)
|
1124
|
+
end
|
1125
|
+
|
1126
|
+
check_public_methods(const_or_var, container.name)
|
1127
|
+
|
1128
|
+
} if const_var_defs
|
1129
|
+
|
1130
|
+
remaining_lines = remaining_code.split("\n")
|
1131
|
+
|
1132
|
+
# "subroutine" or "function" parts are parsed (new)
|
1133
|
+
#
|
1134
|
+
level_depth = 0
|
1135
|
+
block_searching_flag = nil
|
1136
|
+
block_searching_lines = []
|
1137
|
+
pre_comment = []
|
1138
|
+
procedure_trailing = ""
|
1139
|
+
procedure_name = ""
|
1140
|
+
procedure_params = ""
|
1141
|
+
procedure_prefix = ""
|
1142
|
+
procedure_result_arg = ""
|
1143
|
+
procedure_type = ""
|
1144
|
+
contains_lines = []
|
1145
|
+
contains_flag = nil
|
1146
|
+
remaining_lines.collect!{|line|
|
1147
|
+
if !block_searching_flag
|
1148
|
+
# subroutine
|
1149
|
+
if line =~ /^\s*?
|
1150
|
+
(recursive|pure|elemental)?\s*?
|
1151
|
+
subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
|
1152
|
+
/ix
|
1153
|
+
block_searching_flag = :subroutine
|
1154
|
+
block_searching_lines << line
|
1155
|
+
|
1156
|
+
procedure_name = $2.chomp.strip
|
1157
|
+
procedure_params = $3 || ""
|
1158
|
+
procedure_prefix = $1 || ""
|
1159
|
+
procedure_trailing = $4 || "!"
|
1160
|
+
next false
|
1161
|
+
|
1162
|
+
# function
|
1163
|
+
elsif line =~ /^\s*?
|
1164
|
+
(recursive|pure|elemental)?\s*?
|
1165
|
+
(
|
1166
|
+
character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
|
1167
|
+
| type\s*?\([\w\s]+?\)\s+
|
1168
|
+
| integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
|
1169
|
+
| real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
|
1170
|
+
| double\s+precision\s+
|
1171
|
+
| logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
|
1172
|
+
| complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
|
1173
|
+
)?
|
1174
|
+
function\s+(\w+)\s*?
|
1175
|
+
(\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
|
1176
|
+
/ix
|
1177
|
+
block_searching_flag = :function
|
1178
|
+
block_searching_lines << line
|
1179
|
+
|
1180
|
+
procedure_prefix = $1 || ""
|
1181
|
+
procedure_type = $2 ? $2.chomp.strip : nil
|
1182
|
+
procedure_name = $8.chomp.strip
|
1183
|
+
procedure_params = $9 || ""
|
1184
|
+
procedure_result_arg = $11 ? $11.chomp.strip : procedure_name
|
1185
|
+
procedure_trailing = $12 || "!"
|
1186
|
+
next false
|
1187
|
+
elsif line =~ /^\s*?!\s?(.*)/
|
1188
|
+
pre_comment << line
|
1189
|
+
next line
|
1190
|
+
else
|
1191
|
+
pre_comment = []
|
1192
|
+
next line
|
1193
|
+
end
|
1194
|
+
end
|
1195
|
+
contains_flag = true if line =~ /^\s*?contains\s*?(!.*?)?$/
|
1196
|
+
block_searching_lines << line
|
1197
|
+
contains_lines << line if contains_flag
|
1198
|
+
|
1199
|
+
level_depth += 1 if block_start?(line)
|
1200
|
+
level_depth -= 1 if block_end?(line)
|
1201
|
+
if level_depth >= 0
|
1202
|
+
next false
|
1203
|
+
end
|
1204
|
+
|
1205
|
+
# "procedure_code" is formatted.
|
1206
|
+
# ":nodoc:" flag is checked.
|
1207
|
+
#
|
1208
|
+
procedure_code = block_searching_lines.join("\n")
|
1209
|
+
procedure_code = remove_empty_head_lines(procedure_code)
|
1210
|
+
if procedure_trailing.sub(/^!/, '') =~ IGNORED_MARKER_REGEXP
|
1211
|
+
# next loop to search next block
|
1212
|
+
level_depth = 0
|
1213
|
+
block_searching_flag = nil
|
1214
|
+
block_searching_lines = []
|
1215
|
+
pre_comment = []
|
1216
|
+
procedure_trailing = ""
|
1217
|
+
procedure_name = ""
|
1218
|
+
procedure_params = ""
|
1219
|
+
procedure_prefix = ""
|
1220
|
+
procedure_result_arg = ""
|
1221
|
+
procedure_type = ""
|
1222
|
+
contains_lines = []
|
1223
|
+
contains_flag = nil
|
1224
|
+
next false
|
1225
|
+
end
|
1226
|
+
|
1227
|
+
# AnyMethod is created, and added to container
|
1228
|
+
#
|
1229
|
+
subroutine_function = nil
|
1230
|
+
if block_searching_flag == :subroutine
|
1231
|
+
subroutine_prefix = procedure_prefix
|
1232
|
+
subroutine_name = procedure_name
|
1233
|
+
subroutine_params = procedure_params
|
1234
|
+
subroutine_trailing = procedure_trailing
|
1235
|
+
subroutine_code = procedure_code
|
1236
|
+
subroutine_priority, subroutine_trailing = doc_priority_from_trailing(subroutine_trailing)
|
1237
|
+
|
1238
|
+
subroutine_comment = COMMENTS_ARE_UPPER ?
|
1239
|
+
pre_comment.join("\n") + "\n" + subroutine_trailing :
|
1240
|
+
subroutine_trailing + "\n" + subroutine_code.sub(/^.*$\n/i, '')
|
1241
|
+
subroutine = AnyMethod.new("subroutine", subroutine_name)
|
1242
|
+
parse_subprogram(subroutine, subroutine_params,
|
1243
|
+
subroutine_comment, subroutine_code,
|
1244
|
+
before_contains_code, nil, subroutine_prefix)
|
1245
|
+
subroutine.set_priority(subroutine_priority) if subroutine_priority
|
1246
|
+
progress "s"
|
1247
|
+
@stats.num_methods += 1
|
1248
|
+
container.add_method subroutine
|
1249
|
+
subroutine_function = subroutine
|
1250
|
+
|
1251
|
+
namelist_comment =
|
1252
|
+
find_namelists(subroutine, subroutine_code, before_contains_code)
|
1253
|
+
subroutine.comment << namelist_comment if namelist_comment
|
1254
|
+
|
1255
|
+
elsif block_searching_flag == :function
|
1256
|
+
function_prefix = procedure_prefix
|
1257
|
+
function_type = procedure_type
|
1258
|
+
function_name = procedure_name
|
1259
|
+
function_params_org = procedure_params
|
1260
|
+
function_result_arg = procedure_result_arg
|
1261
|
+
function_trailing = procedure_trailing
|
1262
|
+
function_code_org = procedure_code
|
1263
|
+
function_priority, function_trailing = doc_priority_from_trailing(function_trailing)
|
1264
|
+
|
1265
|
+
function_comment = COMMENTS_ARE_UPPER ?
|
1266
|
+
pre_comment.join("\n") + "\n" + function_trailing :
|
1267
|
+
function_trailing + "\n " + function_code_org.sub(/^.*$\n/i, '')
|
1268
|
+
|
1269
|
+
function_code = "#{function_code_org}"
|
1270
|
+
if function_type
|
1271
|
+
function_code << "\n" + function_type + " :: " + function_result_arg
|
1272
|
+
end
|
1273
|
+
|
1274
|
+
if function_params_org =~ /^\s*\(\s*\)\s*$/
|
1275
|
+
function_params =
|
1276
|
+
function_params_org.sub(/^\(/, "\(#{function_result_arg}")
|
1277
|
+
else
|
1278
|
+
function_params =
|
1279
|
+
function_params_org.sub(/^\(/, "\(#{function_result_arg}, ")
|
1280
|
+
end
|
1281
|
+
|
1282
|
+
function = AnyMethod.new("function", function_name)
|
1283
|
+
parse_subprogram(function, function_params,
|
1284
|
+
function_comment, function_code,
|
1285
|
+
before_contains_code, true, function_prefix)
|
1286
|
+
function.set_priority(function_priority) if function_priority
|
1287
|
+
|
1288
|
+
# Specific modification due to function
|
1289
|
+
function.params.sub!(/\(\s*?#{function_result_arg}\s*?,?\s*?/, "\( ")
|
1290
|
+
function.params << " result(" + function_result_arg + ")"
|
1291
|
+
function.start_collecting_tokens
|
1292
|
+
function.add_token Token.new(1,1).set_text(function_code_org)
|
1293
|
+
|
1294
|
+
progress "f"
|
1295
|
+
@stats.num_methods += 1
|
1296
|
+
container.add_method function
|
1297
|
+
subroutine_function = function
|
1298
|
+
|
1299
|
+
namelist_comment =
|
1300
|
+
find_namelists(function, function_code, before_contains_code)
|
1301
|
+
function.comment << namelist_comment if namelist_comment
|
1302
|
+
|
1303
|
+
end
|
1304
|
+
|
1305
|
+
# The visibility of procedure is specified
|
1306
|
+
#
|
1307
|
+
set_visibility(container, procedure_name,
|
1308
|
+
visibility_default, @@public_methods)
|
1309
|
+
|
1310
|
+
# The alias for this procedure from external modules
|
1311
|
+
#
|
1312
|
+
check_external_aliases(procedure_name,
|
1313
|
+
subroutine_function.params,
|
1314
|
+
subroutine_function.comment, subroutine_function) if external
|
1315
|
+
check_public_methods(subroutine_function, container.name)
|
1316
|
+
|
1317
|
+
|
1318
|
+
# contains_lines are parsed as private procedures
|
1319
|
+
if contains_flag
|
1320
|
+
parse_program_or_module(container,
|
1321
|
+
contains_lines.join("\n"), :private)
|
1322
|
+
end
|
1323
|
+
|
1324
|
+
# next loop to search next block
|
1325
|
+
level_depth = 0
|
1326
|
+
block_searching_flag = nil
|
1327
|
+
block_searching_lines = []
|
1328
|
+
pre_comment = []
|
1329
|
+
procedure_trailing = ""
|
1330
|
+
procedure_name = ""
|
1331
|
+
procedure_params = ""
|
1332
|
+
procedure_prefix = ""
|
1333
|
+
procedure_result_arg = ""
|
1334
|
+
contains_lines = []
|
1335
|
+
contains_flag = nil
|
1336
|
+
next false
|
1337
|
+
} # End of remaining_lines.collect!{|line|
|
1338
|
+
|
1339
|
+
# Array remains_lines is converted to String remains_code again
|
1340
|
+
#
|
1341
|
+
remaining_code = remaining_lines.join("\n")
|
1342
|
+
|
1343
|
+
#
|
1344
|
+
# Parse interface
|
1345
|
+
#
|
1346
|
+
interface_scope = false
|
1347
|
+
generic_name = ""
|
1348
|
+
interface_code.split("\n").each{ |line|
|
1349
|
+
if /^\s*?
|
1350
|
+
interface(
|
1351
|
+
\s+\w+|
|
1352
|
+
\s+operator\s*?\(.*?\)|
|
1353
|
+
\s+assignment\s*?\(\s*?=\s*?\)
|
1354
|
+
)?
|
1355
|
+
\s*?(!.*?)?$
|
1356
|
+
/ix =~ line
|
1357
|
+
generic_name = $1 ? $1.strip.chomp : nil
|
1358
|
+
interface_trailing = $2 || "!"
|
1359
|
+
interface_scope = true
|
1360
|
+
interface_scope = false if interface_trailing.sub(/^!/, '') =~ IGNORED_MARKER_REGEXP
|
1361
|
+
# if generic_name =~ /operator\s*?\((.*?)\)/i
|
1362
|
+
# operator_name = $1
|
1363
|
+
# if operator_name && !operator_name.empty?
|
1364
|
+
# generic_name = "#{operator_name}"
|
1365
|
+
# end
|
1366
|
+
# end
|
1367
|
+
# if generic_name =~ /assignment\s*?\((.*?)\)/i
|
1368
|
+
# assignment_name = $1
|
1369
|
+
# if assignment_name && !assignment_name.empty?
|
1370
|
+
# generic_name = "#{assignment_name}"
|
1371
|
+
# end
|
1372
|
+
# end
|
1373
|
+
end
|
1374
|
+
if /^\s*?end\s+interface/i =~ line
|
1375
|
+
interface_scope = false
|
1376
|
+
generic_name = nil
|
1377
|
+
end
|
1378
|
+
# internal alias
|
1379
|
+
if interface_scope && /^\s*?module\s+procedure\s+(.*?)(!.*?)?$/i =~ line
|
1380
|
+
procedures = $1.strip.chomp
|
1381
|
+
procedures_trailing = $2 || "!"
|
1382
|
+
next if procedures_trailing.sub(/^!/, '') =~ IGNORED_MARKER_REGEXP
|
1383
|
+
procedures_priority, procedures_trailing = doc_priority_from_trailing(procedures_trailing)
|
1384
|
+
|
1385
|
+
procedures.split(",").each{ |proc|
|
1386
|
+
proc.strip!
|
1387
|
+
proc.chomp!
|
1388
|
+
next if generic_name == proc || !generic_name
|
1389
|
+
old_meth = container.find_symbol(proc, nil, @options_ignore_case)
|
1390
|
+
next if !old_meth
|
1391
|
+
nolink = old_meth.visibility == :private ? true : nil
|
1392
|
+
nolink = nil if @options.show_all
|
1393
|
+
new_meth =
|
1394
|
+
initialize_external_method(generic_name, proc,
|
1395
|
+
old_meth.params, nil,
|
1396
|
+
old_meth.comment,
|
1397
|
+
old_meth.clone.token_stream[0].text,
|
1398
|
+
true, nolink)
|
1399
|
+
new_meth.singleton = old_meth.singleton
|
1400
|
+
new_meth.set_priority(procedures_priority) if procedures_priority
|
1401
|
+
|
1402
|
+
progress "i"
|
1403
|
+
@stats.num_methods += 1
|
1404
|
+
container.add_method new_meth
|
1405
|
+
|
1406
|
+
set_visibility(container, generic_name, visibility_default, @@public_methods)
|
1407
|
+
|
1408
|
+
check_public_methods(new_meth, container.name)
|
1409
|
+
|
1410
|
+
}
|
1411
|
+
end
|
1412
|
+
|
1413
|
+
# external aliases
|
1414
|
+
if interface_scope
|
1415
|
+
# subroutine
|
1416
|
+
proc = nil
|
1417
|
+
params = nil
|
1418
|
+
procedures_trailing = nil
|
1419
|
+
if line =~ /^\s*?
|
1420
|
+
(recursive|pure|elemental)?\s*?
|
1421
|
+
subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
|
1422
|
+
/ix
|
1423
|
+
proc = $2.chomp.strip
|
1424
|
+
proc_name = generic_name || proc
|
1425
|
+
params = $3 || ""
|
1426
|
+
procedures_trailing = $4 || "!"
|
1427
|
+
|
1428
|
+
# function
|
1429
|
+
elsif line =~ /^\s*?
|
1430
|
+
(recursive|pure|elemental)?\s*?
|
1431
|
+
(
|
1432
|
+
character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
|
1433
|
+
| type\s*?\([\w\s]+?\)\s+
|
1434
|
+
| integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
|
1435
|
+
| real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
|
1436
|
+
| double\s+precision\s+
|
1437
|
+
| logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
|
1438
|
+
| complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
|
1439
|
+
)?
|
1440
|
+
function\s+(\w+)\s*?
|
1441
|
+
(\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
|
1442
|
+
/ix
|
1443
|
+
proc = $8.chomp.strip
|
1444
|
+
proc_name = generic_name || proc
|
1445
|
+
params = $9 || ""
|
1446
|
+
procedures_trailing = $12 || "!"
|
1447
|
+
else
|
1448
|
+
next
|
1449
|
+
end
|
1450
|
+
next if procedures_trailing.sub(/^!/, '') =~ IGNORED_MARKER_REGEXP
|
1451
|
+
procedures_priority, procedures_trailing = doc_priority_from_trailing(procedures_trailing)
|
1452
|
+
indicated_method = nil
|
1453
|
+
indicated_file = nil
|
1454
|
+
TopLevel.all_files.each do |name, toplevel|
|
1455
|
+
indicated_method = toplevel.find_local_symbol(proc, @options_ignore_case)
|
1456
|
+
indicated_file = name
|
1457
|
+
break if indicated_method
|
1458
|
+
end
|
1459
|
+
|
1460
|
+
if indicated_method
|
1461
|
+
external_method =
|
1462
|
+
initialize_external_method(proc_name, proc,
|
1463
|
+
indicated_method.params,
|
1464
|
+
indicated_file,
|
1465
|
+
indicated_method.comment)
|
1466
|
+
external_method.set_priority(procedures_priority) if procedures_priority
|
1467
|
+
|
1468
|
+
progress "e"
|
1469
|
+
@stats.num_methods += 1
|
1470
|
+
container.add_method external_method
|
1471
|
+
set_visibility(container, proc_name, visibility_default, @@public_methods)
|
1472
|
+
if !container.include_requires?(indicated_file, @options_ignore_case)
|
1473
|
+
container.add_require(Require.new(indicated_file, ""))
|
1474
|
+
end
|
1475
|
+
check_public_methods(external_method, container.name)
|
1476
|
+
|
1477
|
+
else
|
1478
|
+
@@external_aliases << {
|
1479
|
+
"new_name" => proc_name,
|
1480
|
+
"old_name" => proc,
|
1481
|
+
"file_or_module" => container,
|
1482
|
+
"visibility" => find_visibility(container, proc_name, @@public_methods) || visibility_default,
|
1483
|
+
"doc_priority" => procedures_priority
|
1484
|
+
}
|
1485
|
+
end
|
1486
|
+
end
|
1487
|
+
|
1488
|
+
} if interface_code # End of interface_code.split("\n").each ...
|
1489
|
+
|
1490
|
+
#
|
1491
|
+
# Already imported methods are removed from @@public_methods.
|
1492
|
+
# Remainders are assumed to be imported from other modules.
|
1493
|
+
#
|
1494
|
+
@@public_methods.delete_if{ |method| method["entity_is_discovered"]}
|
1495
|
+
|
1496
|
+
@@public_methods.each{ |pub_meth|
|
1497
|
+
next unless pub_meth["file_or_module"].name == container.name
|
1498
|
+
pub_meth["used_modules"].each{ |used_mod|
|
1499
|
+
TopLevel.all_classes_and_modules.each{ |modules|
|
1500
|
+
if modules.name == used_mod ||
|
1501
|
+
modules.name.upcase == used_mod.upcase &&
|
1502
|
+
@options_ignore_case
|
1503
|
+
modules.method_list.each{ |meth|
|
1504
|
+
if meth.name == pub_meth["name"] ||
|
1505
|
+
meth.name.upcase == pub_meth["name"].upcase &&
|
1506
|
+
@options_ignore_case
|
1507
|
+
new_meth = initialize_public_method(meth,
|
1508
|
+
modules.name)
|
1509
|
+
if pub_meth["local_name"]
|
1510
|
+
new_meth.name = pub_meth["local_name"]
|
1511
|
+
end
|
1512
|
+
progress "e"
|
1513
|
+
@stats.num_methods += 1
|
1514
|
+
container.add_method new_meth
|
1515
|
+
end
|
1516
|
+
}
|
1517
|
+
end
|
1518
|
+
}
|
1519
|
+
}
|
1520
|
+
}
|
1521
|
+
|
1522
|
+
container
|
1523
|
+
end # End of parse_program_or_module
|
1524
|
+
|
1525
|
+
#
|
1526
|
+
# Parse arguments, comment, code of subroutine and function.
|
1527
|
+
# Return AnyMethod object.
|
1528
|
+
#
|
1529
|
+
def parse_subprogram(subprogram, params, comment, code,
|
1530
|
+
before_contains=nil, function=nil, prefix=nil)
|
1531
|
+
subprogram.singleton = false
|
1532
|
+
prefix = "" if !prefix
|
1533
|
+
arguments = params.sub(/\(/, "").sub(/\)/, "").split(",") if params
|
1534
|
+
args_comment, params_opt =
|
1535
|
+
find_arguments(arguments, code.sub(/^s*?contains\s*?(!.*?)?$.*/im, ""),
|
1536
|
+
nil, nil, true)
|
1537
|
+
params_opt = "( " + params_opt + " ) " if params_opt
|
1538
|
+
subprogram.params = params_opt || ""
|
1539
|
+
|
1540
|
+
block_comment = find_comments comment
|
1541
|
+
if function
|
1542
|
+
subprogram.comment = "<b><em> Function </em></b> :: <em>#{prefix}</em>\n"
|
1543
|
+
else
|
1544
|
+
subprogram.comment = "<b><em> Subroutine </em></b> :: <em>#{prefix}</em>\n"
|
1545
|
+
end
|
1546
|
+
subprogram.comment << args_comment if args_comment
|
1547
|
+
subprogram.comment << block_comment if block_comment
|
1548
|
+
|
1549
|
+
# For output source code
|
1550
|
+
subprogram.start_collecting_tokens
|
1551
|
+
subprogram.add_token Token.new(1,1).set_text(code)
|
1552
|
+
|
1553
|
+
subprogram
|
1554
|
+
end
|
1555
|
+
|
1556
|
+
def doc_priority_from_trailing(trailing)
|
1557
|
+
prefix = ''
|
1558
|
+
if trailing =~ /^(\s*!)(.*)$/
|
1559
|
+
prefix = $1
|
1560
|
+
trailing = $2
|
1561
|
+
end
|
1562
|
+
if trailing =~ DOC_PRIORITY_REGEXP
|
1563
|
+
priority = $1.to_i
|
1564
|
+
trailing.sub!(DOC_PRIORITY_REGEXP, '')
|
1565
|
+
else
|
1566
|
+
priority = false
|
1567
|
+
end
|
1568
|
+
trailing = prefix + trailing
|
1569
|
+
return priority, trailing
|
1570
|
+
end
|
1571
|
+
|
1572
|
+
#
|
1573
|
+
# Return lines before "contains" statement in modules.
|
1574
|
+
# "interface", "type" statements are removed.
|
1575
|
+
#
|
1576
|
+
def before_contains(code)
|
1577
|
+
level_depth = 0
|
1578
|
+
before_contains_lines = []
|
1579
|
+
before_contains_code = nil
|
1580
|
+
before_contains_flag = nil
|
1581
|
+
code.split("\n").each{ |line|
|
1582
|
+
if !before_contains_flag
|
1583
|
+
if line =~ /^\s*?module\s+\w+\s*?(!.*?)?$/i
|
1584
|
+
before_contains_flag = true
|
1585
|
+
end
|
1586
|
+
else
|
1587
|
+
break if line =~ /^\s*?contains\s*?(!.*?)?$/i
|
1588
|
+
level_depth += 1 if block_start?(line)
|
1589
|
+
level_depth -= 1 if block_end?(line)
|
1590
|
+
break if level_depth < 0
|
1591
|
+
before_contains_lines << line
|
1592
|
+
end
|
1593
|
+
|
1594
|
+
}
|
1595
|
+
before_contains_code = before_contains_lines.join("\n")
|
1596
|
+
if before_contains_code
|
1597
|
+
before_contains_code.gsub!(/^\s*?interface\s+.*?\s+end\s+interface.*?$/im, "")
|
1598
|
+
before_contains_code.gsub!(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
|
1599
|
+
end
|
1600
|
+
|
1601
|
+
before_contains_code
|
1602
|
+
end
|
1603
|
+
|
1604
|
+
#
|
1605
|
+
# Collect comment for file entity
|
1606
|
+
#
|
1607
|
+
def collect_first_comment(body)
|
1608
|
+
comment = ""
|
1609
|
+
not_comment = ""
|
1610
|
+
comment_start = false
|
1611
|
+
comment_end = false
|
1612
|
+
body.split("\n").each{ |line|
|
1613
|
+
if comment_end
|
1614
|
+
not_comment << line
|
1615
|
+
not_comment << "\n"
|
1616
|
+
elsif /^\s*?!\s?(.*)$/i =~ line
|
1617
|
+
comment_start = true
|
1618
|
+
comment << $1
|
1619
|
+
comment << "\n"
|
1620
|
+
elsif /^\s*?$/i =~ line
|
1621
|
+
comment_end = true if comment_start && COMMENTS_ARE_UPPER
|
1622
|
+
else
|
1623
|
+
comment_end = true
|
1624
|
+
not_comment << line
|
1625
|
+
not_comment << "\n"
|
1626
|
+
end
|
1627
|
+
}
|
1628
|
+
return comment, not_comment
|
1629
|
+
end
|
1630
|
+
|
1631
|
+
|
1632
|
+
# Return comments of definitions of arguments
|
1633
|
+
#
|
1634
|
+
# If "all" argument is true, information of all arguments are returned.
|
1635
|
+
# If "modified_params" is true, list of arguments are decorated,
|
1636
|
+
# for exameple, optional arguments are parenthetic as "[arg]".
|
1637
|
+
#
|
1638
|
+
def find_arguments(args, text, all=nil, indent=nil, modified_params=nil)
|
1639
|
+
return unless args || all
|
1640
|
+
indent = "" unless indent
|
1641
|
+
args = ["all"] if all
|
1642
|
+
params = "" if modified_params
|
1643
|
+
comma = ""
|
1644
|
+
return unless text
|
1645
|
+
args_rdocforms = "\n"
|
1646
|
+
remaining_lines = "#{text}"
|
1647
|
+
definitions = definition_info(remaining_lines)
|
1648
|
+
args.each{ |arg|
|
1649
|
+
arg.strip!
|
1650
|
+
arg.chomp!
|
1651
|
+
definitions.each { |defitem|
|
1652
|
+
if arg == defitem.varname.strip.chomp || all
|
1653
|
+
args_rdocforms << <<-"EOF"
|
1654
|
+
|
1655
|
+
#{indent}<b><tt>#{defitem.varname.chomp.strip}#{defitem.arraysuffix} </tt></b> <tt> #{defitem.inivalue}</tt> ::
|
1656
|
+
#{indent} <tt>#{defitem.types.chomp.strip}</tt>
|
1657
|
+
EOF
|
1658
|
+
if !defitem.comment.chomp.strip.empty?
|
1659
|
+
comment = ""
|
1660
|
+
defitem.comment.split("\n").each{ |line|
|
1661
|
+
comment << " " + line + "\n"
|
1662
|
+
}
|
1663
|
+
args_rdocforms << <<-"EOF"
|
1664
|
+
|
1665
|
+
#{indent} <tt></tt> ::
|
1666
|
+
#{indent} <tt></tt>
|
1667
|
+
#{indent} #{comment.chomp.strip}
|
1668
|
+
EOF
|
1669
|
+
end
|
1670
|
+
|
1671
|
+
if modified_params
|
1672
|
+
if defitem.include_attr?("optional")
|
1673
|
+
params << "#{comma}[#{arg}]"
|
1674
|
+
else
|
1675
|
+
params << "#{comma}#{arg}"
|
1676
|
+
end
|
1677
|
+
comma = ", "
|
1678
|
+
end
|
1679
|
+
end
|
1680
|
+
}
|
1681
|
+
}
|
1682
|
+
if modified_params
|
1683
|
+
return args_rdocforms, params
|
1684
|
+
else
|
1685
|
+
return args_rdocforms
|
1686
|
+
end
|
1687
|
+
end
|
1688
|
+
|
1689
|
+
#
|
1690
|
+
# Add namelist information to Repository (dummy module of each
|
1691
|
+
# @top_level) of NAMELIST statements.
|
1692
|
+
# And return comments about namelist group names
|
1693
|
+
#
|
1694
|
+
def find_namelists(container, text, before_contains=nil)
|
1695
|
+
return nil if !text
|
1696
|
+
top_level = find_toplevel(container)
|
1697
|
+
|
1698
|
+
if text =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)(!.*?)?$/i
|
1699
|
+
if top_level.include_includes?(NAMELIST_REPOSITORY_NAME)
|
1700
|
+
namelist_module =
|
1701
|
+
top_level.find_module_named(NAMELIST_REPOSITORY_NAME)
|
1702
|
+
else
|
1703
|
+
namelist_module =
|
1704
|
+
top_level.add_module NormalClass, NAMELIST_REPOSITORY_NAME
|
1705
|
+
namelist_module.record_location top_level
|
1706
|
+
namelist_module.comment = <<-"EOF"
|
1707
|
+
This is not a module but a repository of NAMELIST group names declared
|
1708
|
+
in all Fortran 90/95 files
|
1709
|
+
EOF
|
1710
|
+
end
|
1711
|
+
else
|
1712
|
+
return ""
|
1713
|
+
end
|
1714
|
+
|
1715
|
+
nml_group_name_lists = []
|
1716
|
+
lines = "#{text}"
|
1717
|
+
before_contains = "" if !before_contains
|
1718
|
+
while lines =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)(!.*?)?$/i
|
1719
|
+
lines = $~.post_match
|
1720
|
+
pre_match = $~.pre_match ; post_match = $~.post_match
|
1721
|
+
nml_group_name = $1
|
1722
|
+
trailing_comment = $3 || ""
|
1723
|
+
nml_vars_list = $2.split(",")
|
1724
|
+
nml_comment = COMMENTS_ARE_UPPER ?
|
1725
|
+
find_comments(pre_match.sub(/\n$/, '')) :
|
1726
|
+
find_comments(trailing_comment + post_match)
|
1727
|
+
if lines.split("\n")[0] =~ /^\//i
|
1728
|
+
lines = "namelist " + lines
|
1729
|
+
end
|
1730
|
+
|
1731
|
+
nml_meth = AnyMethod.new("NAMELIST", nml_group_name)
|
1732
|
+
nml_meth.singleton = false
|
1733
|
+
nml_meth.params = "( " + nml_vars_list.join(", ") + " )"
|
1734
|
+
nml_meth.comment = "<b><em> NAMELIST </em></b> :: <tt></tt>\n"
|
1735
|
+
nml_meth.comment << find_arguments(nml_vars_list, "#{text}" + "\n" + before_contains)
|
1736
|
+
nml_meth.comment << "\n" + nml_comment if nml_comment
|
1737
|
+
if container.parent.parent
|
1738
|
+
parent_object = container.parent.name
|
1739
|
+
else
|
1740
|
+
parent_object = container.parent.file_relative_name
|
1741
|
+
end
|
1742
|
+
nml_meth.comment << "\n\nThis namelist group name is input/output in "
|
1743
|
+
nml_meth.comment << parent_object + "#" + container.name
|
1744
|
+
|
1745
|
+
progress "n"
|
1746
|
+
@stats.num_methods += 1
|
1747
|
+
namelist_module.add_method nml_meth
|
1748
|
+
|
1749
|
+
nml_group_name_lists << NAMELIST_REPOSITORY_NAME + "#" + nml_group_name
|
1750
|
+
end
|
1751
|
+
|
1752
|
+
if !nml_group_name_lists.empty?
|
1753
|
+
comments_in_procedures = "\n\nThis procedure input/output "
|
1754
|
+
comments_in_procedures << nml_group_name_lists.join(", ") + " . "
|
1755
|
+
else
|
1756
|
+
comments_in_procedures = ""
|
1757
|
+
end
|
1758
|
+
|
1759
|
+
comments_in_procedures
|
1760
|
+
end
|
1761
|
+
|
1762
|
+
#
|
1763
|
+
# Return toplevel class of container
|
1764
|
+
#
|
1765
|
+
def find_toplevel(container)
|
1766
|
+
top_level = container
|
1767
|
+
while top_level.parent
|
1768
|
+
top_level = top_level.parent
|
1769
|
+
end
|
1770
|
+
top_level
|
1771
|
+
end
|
1772
|
+
|
1773
|
+
#
|
1774
|
+
# Comments just after module or subprogram, or arguments are
|
1775
|
+
# returnd. If "COMMENTS_ARE_UPPER" is true, comments just before
|
1776
|
+
# modules or subprograms are returnd
|
1777
|
+
#
|
1778
|
+
def find_comments text
|
1779
|
+
return "" unless text
|
1780
|
+
lines = text.split("\n")
|
1781
|
+
lines.reverse! if COMMENTS_ARE_UPPER
|
1782
|
+
comment_block = Array.new
|
1783
|
+
lines.each do |line|
|
1784
|
+
break if line =~ /^\s*?\w/ || line =~ /^\s*?$/
|
1785
|
+
if COMMENTS_ARE_UPPER
|
1786
|
+
comment_block.unshift line.sub(/^\s*?!\s?/,"")
|
1787
|
+
else
|
1788
|
+
comment_block.push line.sub(/^\s*?!\s?/,"")
|
1789
|
+
end
|
1790
|
+
end
|
1791
|
+
nice_lines = comment_block.join("\n").split "\n\s*?\n"
|
1792
|
+
nice_lines[0] ||= ""
|
1793
|
+
nice_lines.shift
|
1794
|
+
end
|
1795
|
+
|
1796
|
+
def progress(char)
|
1797
|
+
unless @options.quiet
|
1798
|
+
@progress.print(char)
|
1799
|
+
@progress.flush
|
1800
|
+
end
|
1801
|
+
end
|
1802
|
+
|
1803
|
+
#
|
1804
|
+
# Create method for internal alias
|
1805
|
+
#
|
1806
|
+
def initialize_public_method(method, parent)
|
1807
|
+
return if !method || !parent
|
1808
|
+
|
1809
|
+
new_meth = AnyMethod.new("External Alias for module", method.name)
|
1810
|
+
new_meth.singleton = method.singleton
|
1811
|
+
new_meth.params = method.params.clone
|
1812
|
+
new_meth.comment = remove_trailing_alias(method.comment.clone)
|
1813
|
+
new_meth.comment << "\n\n#{EXTERNAL_ALIAS_MES} #{parent.strip.chomp}\##{method.name}"
|
1814
|
+
|
1815
|
+
return new_meth
|
1816
|
+
end
|
1817
|
+
|
1818
|
+
#
|
1819
|
+
# Create method for external alias
|
1820
|
+
#
|
1821
|
+
# If argument "internal" is true, file is ignored.
|
1822
|
+
#
|
1823
|
+
def initialize_external_method(new, old, params, file, comment, token=nil,
|
1824
|
+
internal=nil, nolink=nil)
|
1825
|
+
return nil unless new || old
|
1826
|
+
|
1827
|
+
if internal
|
1828
|
+
external_alias_header = "#{INTERNAL_ALIAS_MES} "
|
1829
|
+
external_alias_text = external_alias_header + old
|
1830
|
+
elsif file
|
1831
|
+
external_alias_header = "#{EXTERNAL_ALIAS_MES} "
|
1832
|
+
external_alias_text = external_alias_header + file + "#" + old
|
1833
|
+
else
|
1834
|
+
return nil
|
1835
|
+
end
|
1836
|
+
external_meth = AnyMethod.new(external_alias_text, new)
|
1837
|
+
external_meth.singleton = false
|
1838
|
+
external_meth.params = params
|
1839
|
+
external_comment = remove_trailing_alias(comment) + "\n\n" if comment
|
1840
|
+
external_meth.comment = external_comment || ""
|
1841
|
+
if nolink && token
|
1842
|
+
external_meth.start_collecting_tokens
|
1843
|
+
external_meth.add_token Token.new(1,1).set_text(token)
|
1844
|
+
else
|
1845
|
+
external_meth.comment << external_alias_text
|
1846
|
+
end
|
1847
|
+
|
1848
|
+
return external_meth
|
1849
|
+
end
|
1850
|
+
|
1851
|
+
|
1852
|
+
|
1853
|
+
#
|
1854
|
+
# Parse visibility
|
1855
|
+
#
|
1856
|
+
def parse_visibility(code, default, container)
|
1857
|
+
result = []
|
1858
|
+
visibility_default = default || :public
|
1859
|
+
|
1860
|
+
used_modules = []
|
1861
|
+
container.includes.each{|i| used_modules << i.name} if container
|
1862
|
+
|
1863
|
+
remaining_code = code.gsub(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
|
1864
|
+
remaining_code.split("\n").each{ |line|
|
1865
|
+
if /^\s*?private\s*?$/ =~ line
|
1866
|
+
visibility_default = :private
|
1867
|
+
break
|
1868
|
+
end
|
1869
|
+
} if remaining_code
|
1870
|
+
|
1871
|
+
remaining_code.split("\n").each{ |line|
|
1872
|
+
if /^\s*?private\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
|
1873
|
+
methods = $2.sub(/!.*$/, '')
|
1874
|
+
methods.split(",").each{ |meth|
|
1875
|
+
meth.sub!(/!.*$/, '')
|
1876
|
+
meth.gsub!(/:/, '')
|
1877
|
+
result << {
|
1878
|
+
"name" => meth.chomp.strip,
|
1879
|
+
"visibility" => :private,
|
1880
|
+
"used_modules" => used_modules.clone,
|
1881
|
+
"file_or_module" => container,
|
1882
|
+
"entity_is_discovered" => nil,
|
1883
|
+
"local_name" => nil
|
1884
|
+
}
|
1885
|
+
}
|
1886
|
+
elsif /^\s*?public\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
|
1887
|
+
methods = $2.sub(/!.*$/, '')
|
1888
|
+
methods.split(",").each{ |meth|
|
1889
|
+
meth.sub!(/!.*$/, '')
|
1890
|
+
meth.gsub!(/:/, '')
|
1891
|
+
result << {
|
1892
|
+
"name" => meth.chomp.strip,
|
1893
|
+
"visibility" => :public,
|
1894
|
+
"used_modules" => used_modules.clone,
|
1895
|
+
"file_or_module" => container,
|
1896
|
+
"entity_is_discovered" => nil,
|
1897
|
+
"local_name" => nil
|
1898
|
+
}
|
1899
|
+
}
|
1900
|
+
end
|
1901
|
+
} if remaining_code
|
1902
|
+
|
1903
|
+
if container
|
1904
|
+
result.each{ |vis_info|
|
1905
|
+
vis_info["parent"] = container.name
|
1906
|
+
}
|
1907
|
+
end
|
1908
|
+
|
1909
|
+
return visibility_default, result
|
1910
|
+
end
|
1911
|
+
|
1912
|
+
#
|
1913
|
+
# Set visibility
|
1914
|
+
#
|
1915
|
+
# "subname" element of "visibility_info" is deleted.
|
1916
|
+
#
|
1917
|
+
def set_visibility(container, subname, visibility_default, visibility_info)
|
1918
|
+
return unless container || subname || visibility_default || visibility_info
|
1919
|
+
not_found = true
|
1920
|
+
visibility_info.collect!{ |info|
|
1921
|
+
if info["name"] == subname ||
|
1922
|
+
@options_ignore_case && info["name"].upcase == subname.upcase
|
1923
|
+
if info["file_or_module"].name == container.name
|
1924
|
+
container.set_visibility_for([subname], info["visibility"])
|
1925
|
+
info["entity_is_discovered"] = true
|
1926
|
+
not_found = false
|
1927
|
+
end
|
1928
|
+
end
|
1929
|
+
info
|
1930
|
+
}
|
1931
|
+
if not_found
|
1932
|
+
return container.set_visibility_for([subname], visibility_default)
|
1933
|
+
else
|
1934
|
+
return container
|
1935
|
+
end
|
1936
|
+
end
|
1937
|
+
|
1938
|
+
#
|
1939
|
+
# Find visibility
|
1940
|
+
#
|
1941
|
+
def find_visibility(container, subname, visibility_info)
|
1942
|
+
return nil if !subname || !visibility_info
|
1943
|
+
visibility_info.each{ |info|
|
1944
|
+
if info["name"] == subname ||
|
1945
|
+
@options_ignore_case && info["name"].upcase == subname.upcase
|
1946
|
+
if info["parent"] == container.name
|
1947
|
+
return info["visibility"]
|
1948
|
+
end
|
1949
|
+
end
|
1950
|
+
}
|
1951
|
+
return nil
|
1952
|
+
end
|
1953
|
+
|
1954
|
+
#
|
1955
|
+
# Check external aliases
|
1956
|
+
#
|
1957
|
+
def check_external_aliases(subname, params, comment, test=nil)
|
1958
|
+
@@external_aliases.each{ |alias_item|
|
1959
|
+
if subname == alias_item["old_name"] ||
|
1960
|
+
subname.upcase == alias_item["old_name"].upcase &&
|
1961
|
+
@options_ignore_case
|
1962
|
+
|
1963
|
+
new_meth = initialize_external_method(alias_item["new_name"],
|
1964
|
+
subname, params, @file_name,
|
1965
|
+
comment)
|
1966
|
+
new_meth.visibility = alias_item["visibility"]
|
1967
|
+
new_meth.set_priority(alias_item["doc_priority"]) if alias_item["doc_priority"]
|
1968
|
+
|
1969
|
+
progress "e"
|
1970
|
+
@stats.num_methods += 1
|
1971
|
+
alias_item["file_or_module"].add_method(new_meth)
|
1972
|
+
|
1973
|
+
if !alias_item["file_or_module"].include_requires?(@file_name, @options_ignore_case)
|
1974
|
+
alias_item["file_or_module"].add_require(Require.new(@file_name, ""))
|
1975
|
+
end
|
1976
|
+
end
|
1977
|
+
}
|
1978
|
+
end
|
1979
|
+
|
1980
|
+
#
|
1981
|
+
# Check public_methods
|
1982
|
+
#
|
1983
|
+
def check_public_methods(method, parent)
|
1984
|
+
return if !method || !parent
|
1985
|
+
@@public_methods.each{ |alias_item|
|
1986
|
+
parent_is_used_module = nil
|
1987
|
+
alias_item["used_modules"].each{ |used_module|
|
1988
|
+
if used_module == parent ||
|
1989
|
+
used_module.upcase == parent.upcase &&
|
1990
|
+
@options_ignore_case
|
1991
|
+
parent_is_used_module = true
|
1992
|
+
end
|
1993
|
+
}
|
1994
|
+
next if !parent_is_used_module
|
1995
|
+
|
1996
|
+
if method.name == alias_item["name"] ||
|
1997
|
+
method.name.upcase == alias_item["name"].upcase &&
|
1998
|
+
@options_ignore_case
|
1999
|
+
|
2000
|
+
new_meth = initialize_public_method(method, parent)
|
2001
|
+
if alias_item["local_name"]
|
2002
|
+
new_meth.name = alias_item["local_name"]
|
2003
|
+
end
|
2004
|
+
|
2005
|
+
progress "e"
|
2006
|
+
@stats.num_methods += 1
|
2007
|
+
alias_item["file_or_module"].add_method new_meth
|
2008
|
+
end
|
2009
|
+
}
|
2010
|
+
end
|
2011
|
+
|
2012
|
+
#
|
2013
|
+
# Continuous lines are united.
|
2014
|
+
#
|
2015
|
+
# Comments in continuous lines are removed.
|
2016
|
+
# If delete_space=false, spaces around "&" are not deleted.
|
2017
|
+
#
|
2018
|
+
# Example
|
2019
|
+
#
|
2020
|
+
# before
|
2021
|
+
#
|
2022
|
+
# subroutine func(a, b, c, d, e, & ! ignored comments
|
2023
|
+
# & f, g, h) ! valid comments
|
2024
|
+
#
|
2025
|
+
# after
|
2026
|
+
#
|
2027
|
+
# subroutine func(a, b, c, d, e, f, g, h) ! valid comments
|
2028
|
+
#
|
2029
|
+
def united_to_one_line(f90src, delete_space=true)
|
2030
|
+
return "" unless f90src
|
2031
|
+
lines = f90src.split("\n")
|
2032
|
+
previous_continuing = false
|
2033
|
+
now_continuing = false
|
2034
|
+
body = ""
|
2035
|
+
squote = false ; dquote = false
|
2036
|
+
lines.each{ |line|
|
2037
|
+
words = line.split("")
|
2038
|
+
next if words.empty? && previous_continuing
|
2039
|
+
commentout = false
|
2040
|
+
brank_flag = true ; brank_char = ""
|
2041
|
+
ignore = false
|
2042
|
+
words.collect! { |char|
|
2043
|
+
if previous_continuing && brank_flag
|
2044
|
+
now_continuing = true
|
2045
|
+
ignore = true
|
2046
|
+
case char
|
2047
|
+
when "!" ; break
|
2048
|
+
when " " ; brank_char << char ; next ""
|
2049
|
+
when "&"
|
2050
|
+
brank_flag = false
|
2051
|
+
now_continuing = false
|
2052
|
+
next ""
|
2053
|
+
else
|
2054
|
+
brank_flag = false
|
2055
|
+
now_continuing = false
|
2056
|
+
ignore = false
|
2057
|
+
next brank_char + char
|
2058
|
+
end
|
2059
|
+
end
|
2060
|
+
ignore = false
|
2061
|
+
|
2062
|
+
if now_continuing && !(squote) && !(dquote)
|
2063
|
+
next ""
|
2064
|
+
elsif !(squote) && !(dquote) && !(commentout)
|
2065
|
+
case char
|
2066
|
+
when "!" ; commentout = true ; next char
|
2067
|
+
when "\""; dquote = true ; next char
|
2068
|
+
when "\'"; squote = true ; next char
|
2069
|
+
when "&" ; now_continuing = true ; next ""
|
2070
|
+
else next char
|
2071
|
+
end
|
2072
|
+
elsif commentout
|
2073
|
+
next char
|
2074
|
+
elsif squote
|
2075
|
+
case char
|
2076
|
+
when "\'"; squote = false ; now_continuing = false ; next char
|
2077
|
+
when "&" ; now_continuing = true ; next ""
|
2078
|
+
else next char
|
2079
|
+
end
|
2080
|
+
elsif dquote
|
2081
|
+
case char
|
2082
|
+
when "\""; dquote = false ; now_continuing = false ; next char
|
2083
|
+
when "&" ; now_continuing = true ; next ""
|
2084
|
+
else next char
|
2085
|
+
end
|
2086
|
+
end
|
2087
|
+
}
|
2088
|
+
if !ignore && !previous_continuing || !brank_flag
|
2089
|
+
if previous_continuing
|
2090
|
+
if delete_space
|
2091
|
+
joined_words = words.join("")
|
2092
|
+
body = body.rstrip + " " + joined_words.lstrip
|
2093
|
+
else
|
2094
|
+
body << words.join("")
|
2095
|
+
end
|
2096
|
+
else
|
2097
|
+
body << "\n" + words.join("")
|
2098
|
+
end
|
2099
|
+
end
|
2100
|
+
previous_continuing = now_continuing ? true : false
|
2101
|
+
now_continuing = false
|
2102
|
+
}
|
2103
|
+
return body
|
2104
|
+
end
|
2105
|
+
|
2106
|
+
|
2107
|
+
#
|
2108
|
+
# Continuous line checker
|
2109
|
+
#
|
2110
|
+
def continuous_line?(line)
|
2111
|
+
continuous = false
|
2112
|
+
if /&\s*?(!.*)?$/ =~ line
|
2113
|
+
continuous = true
|
2114
|
+
if comment_out?($~.pre_match)
|
2115
|
+
continuous = false
|
2116
|
+
end
|
2117
|
+
end
|
2118
|
+
return continuous
|
2119
|
+
end
|
2120
|
+
|
2121
|
+
#
|
2122
|
+
# Comment out checker
|
2123
|
+
#
|
2124
|
+
def comment_out?(line)
|
2125
|
+
return nil unless line
|
2126
|
+
commentout = false
|
2127
|
+
squote = false ; dquote = false
|
2128
|
+
line.split("").each { |char|
|
2129
|
+
if !(squote) && !(dquote)
|
2130
|
+
case char
|
2131
|
+
when "!" ; commentout = true ; break
|
2132
|
+
when "\""; dquote = true
|
2133
|
+
when "\'"; squote = true
|
2134
|
+
else next
|
2135
|
+
end
|
2136
|
+
elsif squote
|
2137
|
+
case char
|
2138
|
+
when "\'"; squote = false
|
2139
|
+
else next
|
2140
|
+
end
|
2141
|
+
elsif dquote
|
2142
|
+
case char
|
2143
|
+
when "\""; dquote = false
|
2144
|
+
else next
|
2145
|
+
end
|
2146
|
+
end
|
2147
|
+
}
|
2148
|
+
return commentout
|
2149
|
+
end
|
2150
|
+
|
2151
|
+
#
|
2152
|
+
# Semicolons are replaced to line feed.
|
2153
|
+
#
|
2154
|
+
def semicolon_to_linefeed(text)
|
2155
|
+
return "" unless text
|
2156
|
+
lines = text.split("\n")
|
2157
|
+
lines.collect!{ |line|
|
2158
|
+
indent_space = ""
|
2159
|
+
if line =~ /^(\s+)/
|
2160
|
+
indent_space = $1
|
2161
|
+
end
|
2162
|
+
words = line.split("")
|
2163
|
+
commentout = false
|
2164
|
+
squote = false ; dquote = false
|
2165
|
+
words.collect! { |char|
|
2166
|
+
if !(squote) && !(dquote) && !(commentout)
|
2167
|
+
case char
|
2168
|
+
when "!" ; commentout = true ; next char
|
2169
|
+
when "\""; dquote = true ; next char
|
2170
|
+
when "\'"; squote = true ; next char
|
2171
|
+
when ";" ; "\n"+indent_space
|
2172
|
+
else next char
|
2173
|
+
end
|
2174
|
+
elsif commentout
|
2175
|
+
next char
|
2176
|
+
elsif squote
|
2177
|
+
case char
|
2178
|
+
when "\'"; squote = false ; next char
|
2179
|
+
else next char
|
2180
|
+
end
|
2181
|
+
elsif dquote
|
2182
|
+
case char
|
2183
|
+
when "\""; dquote = false ; next char
|
2184
|
+
else next char
|
2185
|
+
end
|
2186
|
+
end
|
2187
|
+
}
|
2188
|
+
words.join("")
|
2189
|
+
}
|
2190
|
+
return lines.join("\n")
|
2191
|
+
end
|
2192
|
+
|
2193
|
+
#
|
2194
|
+
# Which "line" is start of block (module, program, block data,
|
2195
|
+
# subroutine, function) statement ?
|
2196
|
+
#
|
2197
|
+
def block_start?(line)
|
2198
|
+
return nil if !line
|
2199
|
+
|
2200
|
+
if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i ||
|
2201
|
+
line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i ||
|
2202
|
+
line =~ /^\s*?block\s+data(\s+\w+)?\s*?(!.*?)?$/i ||
|
2203
|
+
line =~ \
|
2204
|
+
/^\s*?
|
2205
|
+
(recursive|pure|elemental)?\s*?
|
2206
|
+
subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
|
2207
|
+
/ix ||
|
2208
|
+
line =~ \
|
2209
|
+
/^\s*?
|
2210
|
+
(recursive|pure|elemental)?\s*?
|
2211
|
+
(
|
2212
|
+
character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
|
2213
|
+
| type\s*?\([\w\s]+?\)\s+
|
2214
|
+
| integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
|
2215
|
+
| real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
|
2216
|
+
| double\s+precision\s+
|
2217
|
+
| logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
|
2218
|
+
| complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
|
2219
|
+
)?
|
2220
|
+
function\s+(\w+)\s*?
|
2221
|
+
(\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
|
2222
|
+
/ix
|
2223
|
+
return true
|
2224
|
+
end
|
2225
|
+
|
2226
|
+
return nil
|
2227
|
+
end
|
2228
|
+
|
2229
|
+
#
|
2230
|
+
# Which "line" is end of block (module, program, block data,
|
2231
|
+
# subroutine, function) statement ?
|
2232
|
+
#
|
2233
|
+
def block_end?(line)
|
2234
|
+
return nil if !line
|
2235
|
+
|
2236
|
+
if line =~ /^\s*?end\s*?(!.*?)?$/i ||
|
2237
|
+
line =~ /^\s*?end\s+module(\s+\w+)?\s*?(!.*?)?$/i ||
|
2238
|
+
line =~ /^\s*?end\s+program(\s+\w+)?\s*?(!.*?)?$/i ||
|
2239
|
+
line =~ /^\s*?end\s+block\s+data(\s+\w+)?\s*?(!.*?)?$/i ||
|
2240
|
+
line =~ /^\s*?end\s+subroutine(\s+\w+)?\s*?(!.*?)?$/i ||
|
2241
|
+
line =~ /^\s*?end\s+function(\s+\w+)?\s*?(!.*?)?$/i
|
2242
|
+
return true
|
2243
|
+
end
|
2244
|
+
|
2245
|
+
return nil
|
2246
|
+
end
|
2247
|
+
|
2248
|
+
#
|
2249
|
+
# Remove "Alias for" in end of comments
|
2250
|
+
#
|
2251
|
+
def remove_trailing_alias(text)
|
2252
|
+
return "" if !text
|
2253
|
+
lines = text.split("\n").reverse
|
2254
|
+
comment_block = Array.new
|
2255
|
+
checked = false
|
2256
|
+
lines.each do |line|
|
2257
|
+
if !checked
|
2258
|
+
if /^\s?#{INTERNAL_ALIAS_MES}/ =~ line ||
|
2259
|
+
/^\s?#{EXTERNAL_ALIAS_MES}/ =~ line
|
2260
|
+
checked = true
|
2261
|
+
next
|
2262
|
+
end
|
2263
|
+
end
|
2264
|
+
comment_block.unshift line
|
2265
|
+
end
|
2266
|
+
nice_lines = comment_block.join("\n")
|
2267
|
+
nice_lines ||= ""
|
2268
|
+
return nice_lines
|
2269
|
+
end
|
2270
|
+
|
2271
|
+
# Empty lines in header are removed
|
2272
|
+
def remove_empty_head_lines(text)
|
2273
|
+
return "" unless text
|
2274
|
+
lines = text.split("\n")
|
2275
|
+
header = true
|
2276
|
+
lines.delete_if{ |line|
|
2277
|
+
header = false if /\S/ =~ line
|
2278
|
+
header && /^\s*?$/ =~ line
|
2279
|
+
}
|
2280
|
+
lines.join("\n")
|
2281
|
+
end
|
2282
|
+
|
2283
|
+
|
2284
|
+
# header marker "=", "==", ... are removed
|
2285
|
+
def remove_header_marker(text)
|
2286
|
+
return text.gsub(/^\s?(=+)/, '<tt></tt>\1')
|
2287
|
+
end
|
2288
|
+
|
2289
|
+
def remove_private_comments(body)
|
2290
|
+
body.gsub!(/^(\s*)!--\s*?$.*?^\s*!\+\+\s*?$/m, '\\1!')
|
2291
|
+
return body
|
2292
|
+
end
|
2293
|
+
|
2294
|
+
|
2295
|
+
#
|
2296
|
+
# Information of arguments of subroutines and functions in Fortran95
|
2297
|
+
#
|
2298
|
+
class Fortran95Definition
|
2299
|
+
|
2300
|
+
# Name of variable
|
2301
|
+
attr_reader :varname
|
2302
|
+
|
2303
|
+
# Types of variable
|
2304
|
+
attr_reader :types
|
2305
|
+
|
2306
|
+
# Initial Value
|
2307
|
+
attr_reader :inivalue
|
2308
|
+
|
2309
|
+
# Suffix of array
|
2310
|
+
attr_reader :arraysuffix
|
2311
|
+
|
2312
|
+
# Comments
|
2313
|
+
attr_accessor :comment
|
2314
|
+
|
2315
|
+
# Flag of non documentation
|
2316
|
+
attr_accessor :nodoc
|
2317
|
+
|
2318
|
+
# Priority of documentation
|
2319
|
+
attr_accessor :doc_priority
|
2320
|
+
|
2321
|
+
def initialize(varname, types, inivalue, arraysuffix, comment,
|
2322
|
+
nodoc=false, doc_priority=50)
|
2323
|
+
@varname = varname
|
2324
|
+
@types = types
|
2325
|
+
@inivalue = inivalue
|
2326
|
+
@arraysuffix = arraysuffix
|
2327
|
+
@comment = comment
|
2328
|
+
@nodoc = nodoc
|
2329
|
+
@doc_priority = doc_priority
|
2330
|
+
end
|
2331
|
+
|
2332
|
+
def to_s
|
2333
|
+
return <<-EOF
|
2334
|
+
<Fortran95Definition:
|
2335
|
+
varname=#{@varname}, types=#{types},
|
2336
|
+
inivalue=#{@inivalue}, arraysuffix=#{@arraysuffix}, nodoc=#{@nodoc},
|
2337
|
+
comment=
|
2338
|
+
#{@comment}
|
2339
|
+
>
|
2340
|
+
EOF
|
2341
|
+
end
|
2342
|
+
|
2343
|
+
#
|
2344
|
+
# If attr is included, true is returned
|
2345
|
+
#
|
2346
|
+
def include_attr?(attr)
|
2347
|
+
return if !attr
|
2348
|
+
@types.split(",").each{ |type|
|
2349
|
+
return true if type.strip.chomp.upcase == attr.strip.chomp.upcase
|
2350
|
+
}
|
2351
|
+
return nil
|
2352
|
+
end
|
2353
|
+
|
2354
|
+
end # End of Fortran95Definition
|
2355
|
+
|
2356
|
+
#
|
2357
|
+
# Parse string argument "text", and Return Array of
|
2358
|
+
# Fortran95Definition object
|
2359
|
+
#
|
2360
|
+
def definition_info(text)
|
2361
|
+
return nil unless text
|
2362
|
+
lines = "#{text}"
|
2363
|
+
defs = Array.new
|
2364
|
+
comment = ""
|
2365
|
+
trailing_comment = ""
|
2366
|
+
under_comment_valid = false
|
2367
|
+
lines.split("\n").each{ |line|
|
2368
|
+
if /^\s*?!\s?(.*)/ =~ line
|
2369
|
+
if COMMENTS_ARE_UPPER
|
2370
|
+
comment << remove_header_marker($1)
|
2371
|
+
comment << "\n"
|
2372
|
+
elsif defs[-1] && under_comment_valid
|
2373
|
+
defs[-1].comment << "\n"
|
2374
|
+
defs[-1].comment << remove_header_marker($1)
|
2375
|
+
end
|
2376
|
+
next
|
2377
|
+
elsif /^\s*?$/ =~ line
|
2378
|
+
comment = ""
|
2379
|
+
under_comment_valid = false
|
2380
|
+
next
|
2381
|
+
end
|
2382
|
+
type = ""
|
2383
|
+
characters = ""
|
2384
|
+
if line =~ /^\s*?
|
2385
|
+
(
|
2386
|
+
character\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
|
2387
|
+
| type\s*?\([\w\s]+?\)[\s\,]*
|
2388
|
+
| integer\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
|
2389
|
+
| real\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
|
2390
|
+
| double\s+precision[\s\,]*
|
2391
|
+
| logical\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
|
2392
|
+
| complex\s*?(\([\w\s\=\(\)\*]+?\))?[\s\,]*
|
2393
|
+
)
|
2394
|
+
(.*?::)?
|
2395
|
+
(.+)$
|
2396
|
+
/ix
|
2397
|
+
characters = $8
|
2398
|
+
type = $1
|
2399
|
+
type << $7.gsub(/::/, '').gsub(/^\s*?\,/, '') if $7
|
2400
|
+
else
|
2401
|
+
under_comment_valid = false
|
2402
|
+
next
|
2403
|
+
end
|
2404
|
+
squote = false ; dquote = false ; bracket = 0
|
2405
|
+
iniflag = false; commentflag = false
|
2406
|
+
varname = "" ; arraysuffix = "" ; inivalue = ""
|
2407
|
+
start_pos = defs.size
|
2408
|
+
characters.split("").each { |char|
|
2409
|
+
if !(squote) && !(dquote) && bracket <= 0 && !(iniflag) && !(commentflag)
|
2410
|
+
case char
|
2411
|
+
when "!" ; commentflag = true
|
2412
|
+
when "(" ; bracket += 1 ; arraysuffix = char
|
2413
|
+
when "\""; dquote = true
|
2414
|
+
when "\'"; squote = true
|
2415
|
+
when "=" ; iniflag = true ; inivalue << char
|
2416
|
+
when ","
|
2417
|
+
defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
|
2418
|
+
varname = "" ; arraysuffix = "" ; inivalue = ""
|
2419
|
+
under_comment_valid = true
|
2420
|
+
when " " ; next
|
2421
|
+
else ; varname << char
|
2422
|
+
end
|
2423
|
+
elsif commentflag
|
2424
|
+
comment << remove_header_marker(char)
|
2425
|
+
trailing_comment << remove_header_marker(char)
|
2426
|
+
elsif iniflag
|
2427
|
+
if dquote
|
2428
|
+
case char
|
2429
|
+
when "\"" ; dquote = false ; inivalue << char
|
2430
|
+
else ; inivalue << char
|
2431
|
+
end
|
2432
|
+
elsif squote
|
2433
|
+
case char
|
2434
|
+
when "\'" ; squote = false ; inivalue << char
|
2435
|
+
else ; inivalue << char
|
2436
|
+
end
|
2437
|
+
elsif bracket > 0
|
2438
|
+
case char
|
2439
|
+
when "(" ; bracket += 1 ; inivalue << char
|
2440
|
+
when ")" ; bracket -= 1 ; inivalue << char
|
2441
|
+
else ; inivalue << char
|
2442
|
+
end
|
2443
|
+
else
|
2444
|
+
case char
|
2445
|
+
when ","
|
2446
|
+
defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
|
2447
|
+
varname = "" ; arraysuffix = "" ; inivalue = ""
|
2448
|
+
iniflag = false
|
2449
|
+
under_comment_valid = true
|
2450
|
+
when "(" ; bracket += 1 ; inivalue << char
|
2451
|
+
when "\""; dquote = true ; inivalue << char
|
2452
|
+
when "\'"; squote = true ; inivalue << char
|
2453
|
+
when "!" ; commentflag = true
|
2454
|
+
else ; inivalue << char
|
2455
|
+
end
|
2456
|
+
end
|
2457
|
+
elsif !(squote) && !(dquote) && bracket > 0
|
2458
|
+
case char
|
2459
|
+
when "(" ; bracket += 1 ; arraysuffix << char
|
2460
|
+
when ")" ; bracket -= 1 ; arraysuffix << char
|
2461
|
+
else ; arraysuffix << char
|
2462
|
+
end
|
2463
|
+
elsif squote
|
2464
|
+
case char
|
2465
|
+
when "\'"; squote = false ; inivalue << char
|
2466
|
+
else ; inivalue << char
|
2467
|
+
end
|
2468
|
+
elsif dquote
|
2469
|
+
case char
|
2470
|
+
when "\""; dquote = false ; inivalue << char
|
2471
|
+
else ; inivalue << char
|
2472
|
+
end
|
2473
|
+
end
|
2474
|
+
}
|
2475
|
+
defs << Fortran95Definition.new(varname, type, inivalue, arraysuffix, comment)
|
2476
|
+
if trailing_comment =~ IGNORED_MARKER_REGEXP
|
2477
|
+
defs[start_pos..-1].collect!{ |defitem|
|
2478
|
+
defitem.nodoc = true
|
2479
|
+
}
|
2480
|
+
end
|
2481
|
+
if trailing_comment =~ DOC_PRIORITY_REGEXP
|
2482
|
+
doc_priority = $1.to_i
|
2483
|
+
defs[start_pos..-1].collect!{ |defitem|
|
2484
|
+
defitem.doc_priority = doc_priority
|
2485
|
+
defitem.comment.sub!(DOC_PRIORITY_REGEXP, '')
|
2486
|
+
}
|
2487
|
+
end
|
2488
|
+
varname = "" ; arraysuffix = "" ; inivalue = ""
|
2489
|
+
comment = ""
|
2490
|
+
under_comment_valid = true
|
2491
|
+
trailing_comment = ""
|
2492
|
+
}
|
2493
|
+
return defs
|
2494
|
+
end
|
2495
|
+
|
2496
|
+
|
2497
|
+
end # class Fortran95parser
|
2498
|
+
|
2499
|
+
end # module RDocF95
|