PageRenderTime 57ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/ruby/1.9/rdoc/parser/f95.rb

https://bitbucket.org/nicksieger/jruby
Ruby | 1835 lines | 1305 code | 196 blank | 334 comment | 252 complexity | 4822b28ad22f2cdd8f9eb5d68dbaeed4 MD5 | raw file
Possible License(s): GPL-3.0, JSON

Large files files are truncated, but you can click here to view the full file

  1. require 'rdoc/parser'
  2. ##
  3. # = Fortran95 RDoc Parser
  4. #
  5. # == Overview
  6. #
  7. # This parser parses Fortran95 files with suffixes "f90", "F90", "f95" and
  8. # "F95". Fortran95 files are expected to be conformed to Fortran95 standards.
  9. #
  10. # == Rules
  11. #
  12. # Fundamental rules are same as that of the Ruby parser. But comment markers
  13. # are '!' not '#'.
  14. #
  15. # === Correspondence between RDoc documentation and Fortran95 programs
  16. #
  17. # F95 parses main programs, modules, subroutines, functions, derived-types,
  18. # public variables, public constants, defined operators and defined
  19. # assignments. These components are described in items of RDoc documentation,
  20. # as follows.
  21. #
  22. # Files :: Files (same as Ruby)
  23. # Classes:: Modules
  24. # Methods:: Subroutines, functions, variables, constants, derived-types,
  25. # defined operators, defined assignments
  26. # Required files:: Files in which imported modules, external subroutines and
  27. # external functions are defined.
  28. # Included Modules:: List of imported modules
  29. # Attributes:: List of derived-types, List of imported modules all of whose
  30. # components are published again
  31. #
  32. # Components listed in 'Methods' (subroutines, functions, ...) defined in
  33. # modules are described in the item of 'Classes'. On the other hand,
  34. # components defined in main programs or as external procedures are described
  35. # in the item of 'Files'.
  36. #
  37. # === Components parsed by default
  38. #
  39. # By default, documentation on public components (subroutines, functions,
  40. # variables, constants, derived-types, defined operators, defined assignments)
  41. # are generated.
  42. #
  43. # With "--all" option, documentation on all components are generated (almost
  44. # same as the Ruby parser).
  45. #
  46. # === Information parsed automatically
  47. #
  48. # The following information is automatically parsed.
  49. #
  50. # * Types of arguments
  51. # * Types of variables and constants
  52. # * Types of variables in the derived types, and initial values
  53. # * NAMELISTs and types of variables in them, and initial values
  54. #
  55. # Aliases by interface statement are described in the item of 'Methods'.
  56. #
  57. # Components which are imported from other modules and published again are
  58. # described in the item of 'Methods'.
  59. #
  60. # === Format of comment blocks
  61. #
  62. # Comment blocks should be written as follows.
  63. #
  64. # Comment blocks are considered to be ended when the line without '!' appears.
  65. #
  66. # The indentation is not necessary.
  67. #
  68. # ! (Top of file)
  69. # !
  70. # ! Comment blocks for the files.
  71. # !
  72. # !--
  73. # ! The comment described in the part enclosed by
  74. # ! "!--" and "!++" is ignored.
  75. # !++
  76. # !
  77. # module hogehoge
  78. # !
  79. # ! Comment blocks for the modules (or the programs).
  80. # !
  81. #
  82. # private
  83. #
  84. # logical :: a ! a private variable
  85. # real, public :: b ! a public variable
  86. # integer, parameter :: c = 0 ! a public constant
  87. #
  88. # public :: c
  89. # public :: MULTI_ARRAY
  90. # public :: hoge, foo
  91. #
  92. # type MULTI_ARRAY
  93. # !
  94. # ! Comment blocks for the derived-types.
  95. # !
  96. # real, pointer :: var(:) =>null() ! Comments block for the variables.
  97. # integer :: num = 0
  98. # end type MULTI_ARRAY
  99. #
  100. # contains
  101. #
  102. # subroutine hoge( in, & ! Comment blocks between continuation lines are ignored.
  103. # & out )
  104. # !
  105. # ! Comment blocks for the subroutines or functions
  106. # !
  107. # character(*),intent(in):: in ! Comment blocks for the arguments.
  108. # character(*),intent(out),allocatable,target :: in
  109. # ! Comment blocks can be
  110. # ! written under Fortran statements.
  111. #
  112. # character(32) :: file ! This comment parsed as a variable in below NAMELIST.
  113. # integer :: id
  114. #
  115. # namelist /varinfo_nml/ file, id
  116. # !
  117. # ! Comment blocks for the NAMELISTs.
  118. # ! Information about variables are described above.
  119. # !
  120. #
  121. # ....
  122. #
  123. # end subroutine hoge
  124. #
  125. # integer function foo( in )
  126. # !
  127. # ! This part is considered as comment block.
  128. #
  129. # ! Comment blocks under blank lines are ignored.
  130. # !
  131. # integer, intent(in):: inA ! This part is considered as comment block.
  132. #
  133. # ! This part is ignored.
  134. #
  135. # end function foo
  136. #
  137. # subroutine hide( in, &
  138. # & out ) !:nodoc:
  139. # !
  140. # ! If "!:nodoc:" is described at end-of-line in subroutine
  141. # ! statement as above, the subroutine is ignored.
  142. # ! This assignment can be used to modules, subroutines,
  143. # ! functions, variables, constants, derived-types,
  144. # ! defined operators, defined assignments,
  145. # ! list of imported modules ("use" statement).
  146. # !
  147. #
  148. # ....
  149. #
  150. # end subroutine hide
  151. #
  152. # end module hogehoge
  153. class RDoc::Parser::F95 < RDoc::Parser
  154. parse_files_matching(/\.((f|F)9(0|5)|F)$/)
  155. class Token
  156. NO_TEXT = "??".freeze
  157. def initialize(line_no, char_no)
  158. @line_no = line_no
  159. @char_no = char_no
  160. @text = NO_TEXT
  161. end
  162. # Because we're used in contexts that expect to return a token,
  163. # we set the text string and then return ourselves
  164. def set_text(text)
  165. @text = text
  166. self
  167. end
  168. attr_reader :line_no, :char_no, :text
  169. end
  170. @@external_aliases = []
  171. @@public_methods = []
  172. ##
  173. # "false":: Comments are below source code
  174. # "true" :: Comments are upper source code
  175. COMMENTS_ARE_UPPER = false
  176. ##
  177. # Internal alias message
  178. INTERNAL_ALIAS_MES = "Alias for"
  179. ##
  180. # External alias message
  181. EXTERNAL_ALIAS_MES = "The entity is"
  182. ##
  183. # Define code constructs
  184. def scan
  185. # remove private comment
  186. remaining_code = remove_private_comments(@content)
  187. # continuation lines are united to one line
  188. remaining_code = united_to_one_line(remaining_code)
  189. # semicolons are replaced to line feed
  190. remaining_code = semicolon_to_linefeed(remaining_code)
  191. # collect comment for file entity
  192. whole_comment, remaining_code = collect_first_comment(remaining_code)
  193. @top_level.comment = whole_comment
  194. # String "remaining_code" is converted to Array "remaining_lines"
  195. remaining_lines = remaining_code.split("\n")
  196. # "module" or "program" parts are parsed (new)
  197. #
  198. level_depth = 0
  199. block_searching_flag = nil
  200. block_searching_lines = []
  201. pre_comment = []
  202. module_program_trailing = ""
  203. module_program_name = ""
  204. other_block_level_depth = 0
  205. other_block_searching_flag = nil
  206. remaining_lines.collect!{|line|
  207. if !block_searching_flag && !other_block_searching_flag
  208. if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i
  209. block_searching_flag = :module
  210. block_searching_lines << line
  211. module_program_name = $1
  212. module_program_trailing = find_comments($2)
  213. next false
  214. elsif line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i ||
  215. line =~ /^\s*?\w/ && !block_start?(line)
  216. block_searching_flag = :program
  217. block_searching_lines << line
  218. module_program_name = $1 || ""
  219. module_program_trailing = find_comments($2)
  220. next false
  221. elsif block_start?(line)
  222. other_block_searching_flag = true
  223. next line
  224. elsif line =~ /^\s*?!\s?(.*)/
  225. pre_comment << line
  226. next line
  227. else
  228. pre_comment = []
  229. next line
  230. end
  231. elsif other_block_searching_flag
  232. other_block_level_depth += 1 if block_start?(line)
  233. other_block_level_depth -= 1 if block_end?(line)
  234. if other_block_level_depth < 0
  235. other_block_level_depth = 0
  236. other_block_searching_flag = nil
  237. end
  238. next line
  239. end
  240. block_searching_lines << line
  241. level_depth += 1 if block_start?(line)
  242. level_depth -= 1 if block_end?(line)
  243. if level_depth >= 0
  244. next false
  245. end
  246. # "module_program_code" is formatted.
  247. # ":nodoc:" flag is checked.
  248. #
  249. module_program_code = block_searching_lines.join("\n")
  250. module_program_code = remove_empty_head_lines(module_program_code)
  251. if module_program_trailing =~ /^:nodoc:/
  252. # next loop to search next block
  253. level_depth = 0
  254. block_searching_flag = false
  255. block_searching_lines = []
  256. pre_comment = []
  257. next false
  258. end
  259. # NormalClass is created, and added to @top_level
  260. #
  261. if block_searching_flag == :module
  262. module_name = module_program_name
  263. module_code = module_program_code
  264. module_trailing = module_program_trailing
  265. f9x_module = @top_level.add_module NormalClass, module_name
  266. f9x_module.record_location @top_level
  267. @stats.add_module f9x_module
  268. f9x_comment = COMMENTS_ARE_UPPER ?
  269. find_comments(pre_comment.join("\n")) + "\n" + module_trailing :
  270. module_trailing + "\n" + find_comments(module_code.sub(/^.*$\n/i, ''))
  271. f9x_module.comment = f9x_comment
  272. parse_program_or_module(f9x_module, module_code)
  273. TopLevel.all_files.each do |name, toplevel|
  274. if toplevel.include_includes?(module_name, @options.ignore_case)
  275. if !toplevel.include_requires?(@file_name, @options.ignore_case)
  276. toplevel.add_require(Require.new(@file_name, ""))
  277. end
  278. end
  279. toplevel.each_classmodule{|m|
  280. if m.include_includes?(module_name, @options.ignore_case)
  281. if !m.include_requires?(@file_name, @options.ignore_case)
  282. m.add_require(Require.new(@file_name, ""))
  283. end
  284. end
  285. }
  286. end
  287. elsif block_searching_flag == :program
  288. program_name = module_program_name
  289. program_code = module_program_code
  290. program_trailing = module_program_trailing
  291. # progress "p" # HACK what stats thingy does this correspond to?
  292. program_comment = COMMENTS_ARE_UPPER ?
  293. find_comments(pre_comment.join("\n")) + "\n" + program_trailing :
  294. program_trailing + "\n" + find_comments(program_code.sub(/^.*$\n/i, ''))
  295. program_comment = "\n\n= <i>Program</i> <tt>#{program_name}</tt>\n\n" \
  296. + program_comment
  297. @top_level.comment << program_comment
  298. parse_program_or_module(@top_level, program_code, :private)
  299. end
  300. # next loop to search next block
  301. level_depth = 0
  302. block_searching_flag = false
  303. block_searching_lines = []
  304. pre_comment = []
  305. next false
  306. }
  307. remaining_lines.delete_if{ |line|
  308. line == false
  309. }
  310. # External subprograms and functions are parsed
  311. #
  312. parse_program_or_module(@top_level, remaining_lines.join("\n"),
  313. :public, true)
  314. @top_level
  315. end # End of scan
  316. private
  317. def parse_program_or_module(container, code,
  318. visibility=:public, external=nil)
  319. return unless container
  320. return unless code
  321. remaining_lines = code.split("\n")
  322. remaining_code = "#{code}"
  323. #
  324. # Parse variables before "contains" in module
  325. #
  326. level_depth = 0
  327. before_contains_lines = []
  328. before_contains_code = nil
  329. before_contains_flag = nil
  330. remaining_lines.each{ |line|
  331. if !before_contains_flag
  332. if line =~ /^\s*?module\s+\w+\s*?(!.*?)?$/i
  333. before_contains_flag = true
  334. end
  335. else
  336. break if line =~ /^\s*?contains\s*?(!.*?)?$/i
  337. level_depth += 1 if block_start?(line)
  338. level_depth -= 1 if block_end?(line)
  339. break if level_depth < 0
  340. before_contains_lines << line
  341. end
  342. }
  343. before_contains_code = before_contains_lines.join("\n")
  344. if before_contains_code
  345. before_contains_code.gsub!(/^\s*?interface\s+.*?\s+end\s+interface.*?$/im, "")
  346. before_contains_code.gsub!(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
  347. end
  348. #
  349. # Parse global "use"
  350. #
  351. use_check_code = "#{before_contains_code}"
  352. cascaded_modules_list = []
  353. while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i
  354. use_check_code = $~.pre_match
  355. use_check_code << $~.post_match
  356. used_mod_name = $1.strip.chomp
  357. used_list = $2 || ""
  358. used_trailing = $3 || ""
  359. next if used_trailing =~ /!:nodoc:/
  360. if !container.include_includes?(used_mod_name, @options.ignore_case)
  361. # progress "." # HACK what stats thingy does this correspond to?
  362. container.add_include Include.new(used_mod_name, "")
  363. end
  364. if ! (used_list =~ /\,\s*?only\s*?:/i )
  365. cascaded_modules_list << "\#" + used_mod_name
  366. end
  367. end
  368. #
  369. # Parse public and private, and store information.
  370. # This information is used when "add_method" and
  371. # "set_visibility_for" are called.
  372. #
  373. visibility_default, visibility_info =
  374. parse_visibility(remaining_lines.join("\n"), visibility, container)
  375. @@public_methods.concat visibility_info
  376. if visibility_default == :public
  377. if !cascaded_modules_list.empty?
  378. cascaded_modules =
  379. Attr.new("Cascaded Modules",
  380. "Imported modules all of whose components are published again",
  381. "",
  382. cascaded_modules_list.join(", "))
  383. container.add_attribute(cascaded_modules)
  384. end
  385. end
  386. #
  387. # Check rename elements
  388. #
  389. use_check_code = "#{before_contains_code}"
  390. while use_check_code =~ /^\s*?use\s+(\w+)\s*?\,(.+)$/i
  391. use_check_code = $~.pre_match
  392. use_check_code << $~.post_match
  393. used_mod_name = $1.strip.chomp
  394. used_elements = $2.sub(/\s*?only\s*?:\s*?/i, '')
  395. used_elements.split(",").each{ |used|
  396. if /\s*?(\w+)\s*?=>\s*?(\w+)\s*?/ =~ used
  397. local = $1
  398. org = $2
  399. @@public_methods.collect!{ |pub_meth|
  400. if local == pub_meth["name"] ||
  401. local.upcase == pub_meth["name"].upcase &&
  402. @options.ignore_case
  403. pub_meth["name"] = org
  404. pub_meth["local_name"] = local
  405. end
  406. pub_meth
  407. }
  408. end
  409. }
  410. end
  411. #
  412. # Parse private "use"
  413. #
  414. use_check_code = remaining_lines.join("\n")
  415. while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i
  416. use_check_code = $~.pre_match
  417. use_check_code << $~.post_match
  418. used_mod_name = $1.strip.chomp
  419. used_trailing = $3 || ""
  420. next if used_trailing =~ /!:nodoc:/
  421. if !container.include_includes?(used_mod_name, @options.ignore_case)
  422. # progress "." # HACK what stats thingy does this correspond to?
  423. container.add_include Include.new(used_mod_name, "")
  424. end
  425. end
  426. container.each_includes{ |inc|
  427. TopLevel.all_files.each do |name, toplevel|
  428. indicated_mod = toplevel.find_symbol(inc.name,
  429. nil, @options.ignore_case)
  430. if indicated_mod
  431. indicated_name = indicated_mod.parent.file_relative_name
  432. if !container.include_requires?(indicated_name, @options.ignore_case)
  433. container.add_require(Require.new(indicated_name, ""))
  434. end
  435. break
  436. end
  437. end
  438. }
  439. #
  440. # Parse derived-types definitions
  441. #
  442. derived_types_comment = ""
  443. remaining_code = remaining_lines.join("\n")
  444. while remaining_code =~ /^\s*?
  445. type[\s\,]+(public|private)?\s*?(::)?\s*?
  446. (\w+)\s*?(!.*?)?$
  447. (.*?)
  448. ^\s*?end\s+type.*?$
  449. /imx
  450. remaining_code = $~.pre_match
  451. remaining_code << $~.post_match
  452. typename = $3.chomp.strip
  453. type_elements = $5 || ""
  454. type_code = remove_empty_head_lines($&)
  455. type_trailing = find_comments($4)
  456. next if type_trailing =~ /^:nodoc:/
  457. type_visibility = $1
  458. type_comment = COMMENTS_ARE_UPPER ?
  459. find_comments($~.pre_match) + "\n" + type_trailing :
  460. type_trailing + "\n" + find_comments(type_code.sub(/^.*$\n/i, ''))
  461. type_element_visibility_public = true
  462. type_code.split("\n").each{ |line|
  463. if /^\s*?private\s*?$/ =~ line
  464. type_element_visibility_public = nil
  465. break
  466. end
  467. } if type_code
  468. args_comment = ""
  469. type_args_info = nil
  470. if @options.show_all
  471. args_comment = find_arguments(nil, type_code, true)
  472. else
  473. type_public_args_list = []
  474. type_args_info = definition_info(type_code)
  475. type_args_info.each{ |arg|
  476. arg_is_public = type_element_visibility_public
  477. arg_is_public = true if arg.include_attr?("public")
  478. arg_is_public = nil if arg.include_attr?("private")
  479. type_public_args_list << arg.varname if arg_is_public
  480. }
  481. args_comment = find_arguments(type_public_args_list, type_code)
  482. end
  483. type = AnyMethod.new("type #{typename}", typename)
  484. type.singleton = false
  485. type.params = ""
  486. type.comment = "<b><em> Derived Type </em></b> :: <tt></tt>\n"
  487. type.comment << args_comment if args_comment
  488. type.comment << type_comment if type_comment
  489. @stats.add_method type
  490. container.add_method type
  491. set_visibility(container, typename, visibility_default, @@public_methods)
  492. if type_visibility
  493. type_visibility.gsub!(/\s/,'')
  494. type_visibility.gsub!(/\,/,'')
  495. type_visibility.gsub!(/:/,'')
  496. type_visibility.downcase!
  497. if type_visibility == "public"
  498. container.set_visibility_for([typename], :public)
  499. elsif type_visibility == "private"
  500. container.set_visibility_for([typename], :private)
  501. end
  502. end
  503. check_public_methods(type, container.name)
  504. if @options.show_all
  505. derived_types_comment << ", " unless derived_types_comment.empty?
  506. derived_types_comment << typename
  507. else
  508. if type.visibility == :public
  509. derived_types_comment << ", " unless derived_types_comment.empty?
  510. derived_types_comment << typename
  511. end
  512. end
  513. end
  514. if !derived_types_comment.empty?
  515. derived_types_table =
  516. Attr.new("Derived Types", "Derived_Types", "",
  517. derived_types_comment)
  518. container.add_attribute(derived_types_table)
  519. end
  520. #
  521. # move interface scope
  522. #
  523. interface_code = ""
  524. while remaining_code =~ /^\s*?
  525. interface(
  526. \s+\w+ |
  527. \s+operator\s*?\(.*?\) |
  528. \s+assignment\s*?\(\s*?=\s*?\)
  529. )?\s*?$
  530. (.*?)
  531. ^\s*?end\s+interface.*?$
  532. /imx
  533. interface_code << remove_empty_head_lines($&) + "\n"
  534. remaining_code = $~.pre_match
  535. remaining_code << $~.post_match
  536. end
  537. #
  538. # Parse global constants or variables in modules
  539. #
  540. const_var_defs = definition_info(before_contains_code)
  541. const_var_defs.each{|defitem|
  542. next if defitem.nodoc
  543. const_or_var_type = "Variable"
  544. const_or_var_progress = "v"
  545. if defitem.include_attr?("parameter")
  546. const_or_var_type = "Constant"
  547. const_or_var_progress = "c"
  548. end
  549. const_or_var = AnyMethod.new(const_or_var_type, defitem.varname)
  550. const_or_var.singleton = false
  551. const_or_var.params = ""
  552. self_comment = find_arguments([defitem.varname], before_contains_code)
  553. const_or_var.comment = "<b><em>" + const_or_var_type + "</em></b> :: <tt></tt>\n"
  554. const_or_var.comment << self_comment if self_comment
  555. @stats.add_method const_or_var_progress
  556. container.add_method const_or_var
  557. set_visibility(container, defitem.varname, visibility_default, @@public_methods)
  558. if defitem.include_attr?("public")
  559. container.set_visibility_for([defitem.varname], :public)
  560. elsif defitem.include_attr?("private")
  561. container.set_visibility_for([defitem.varname], :private)
  562. end
  563. check_public_methods(const_or_var, container.name)
  564. } if const_var_defs
  565. remaining_lines = remaining_code.split("\n")
  566. # "subroutine" or "function" parts are parsed (new)
  567. #
  568. level_depth = 0
  569. block_searching_flag = nil
  570. block_searching_lines = []
  571. pre_comment = []
  572. procedure_trailing = ""
  573. procedure_name = ""
  574. procedure_params = ""
  575. procedure_prefix = ""
  576. procedure_result_arg = ""
  577. procedure_type = ""
  578. contains_lines = []
  579. contains_flag = nil
  580. remaining_lines.collect!{|line|
  581. if !block_searching_flag
  582. # subroutine
  583. if line =~ /^\s*?
  584. (recursive|pure|elemental)?\s*?
  585. subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
  586. /ix
  587. block_searching_flag = :subroutine
  588. block_searching_lines << line
  589. procedure_name = $2.chomp.strip
  590. procedure_params = $3 || ""
  591. procedure_prefix = $1 || ""
  592. procedure_trailing = $4 || "!"
  593. next false
  594. # function
  595. elsif line =~ /^\s*?
  596. (recursive|pure|elemental)?\s*?
  597. (
  598. character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
  599. | type\s*?\([\w\s]+?\)\s+
  600. | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
  601. | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
  602. | double\s+precision\s+
  603. | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
  604. | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
  605. )?
  606. function\s+(\w+)\s*?
  607. (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
  608. /ix
  609. block_searching_flag = :function
  610. block_searching_lines << line
  611. procedure_prefix = $1 || ""
  612. procedure_type = $2 ? $2.chomp.strip : nil
  613. procedure_name = $8.chomp.strip
  614. procedure_params = $9 || ""
  615. procedure_result_arg = $11 ? $11.chomp.strip : procedure_name
  616. procedure_trailing = $12 || "!"
  617. next false
  618. elsif line =~ /^\s*?!\s?(.*)/
  619. pre_comment << line
  620. next line
  621. else
  622. pre_comment = []
  623. next line
  624. end
  625. end
  626. contains_flag = true if line =~ /^\s*?contains\s*?(!.*?)?$/
  627. block_searching_lines << line
  628. contains_lines << line if contains_flag
  629. level_depth += 1 if block_start?(line)
  630. level_depth -= 1 if block_end?(line)
  631. if level_depth >= 0
  632. next false
  633. end
  634. # "procedure_code" is formatted.
  635. # ":nodoc:" flag is checked.
  636. #
  637. procedure_code = block_searching_lines.join("\n")
  638. procedure_code = remove_empty_head_lines(procedure_code)
  639. if procedure_trailing =~ /^!:nodoc:/
  640. # next loop to search next block
  641. level_depth = 0
  642. block_searching_flag = nil
  643. block_searching_lines = []
  644. pre_comment = []
  645. procedure_trailing = ""
  646. procedure_name = ""
  647. procedure_params = ""
  648. procedure_prefix = ""
  649. procedure_result_arg = ""
  650. procedure_type = ""
  651. contains_lines = []
  652. contains_flag = nil
  653. next false
  654. end
  655. # AnyMethod is created, and added to container
  656. #
  657. subroutine_function = nil
  658. if block_searching_flag == :subroutine
  659. subroutine_prefix = procedure_prefix
  660. subroutine_name = procedure_name
  661. subroutine_params = procedure_params
  662. subroutine_trailing = procedure_trailing
  663. subroutine_code = procedure_code
  664. subroutine_comment = COMMENTS_ARE_UPPER ?
  665. pre_comment.join("\n") + "\n" + subroutine_trailing :
  666. subroutine_trailing + "\n" + subroutine_code.sub(/^.*$\n/i, '')
  667. subroutine = AnyMethod.new("subroutine", subroutine_name)
  668. parse_subprogram(subroutine, subroutine_params,
  669. subroutine_comment, subroutine_code,
  670. before_contains_code, nil, subroutine_prefix)
  671. @stats.add_method subroutine
  672. container.add_method subroutine
  673. subroutine_function = subroutine
  674. elsif block_searching_flag == :function
  675. function_prefix = procedure_prefix
  676. function_type = procedure_type
  677. function_name = procedure_name
  678. function_params_org = procedure_params
  679. function_result_arg = procedure_result_arg
  680. function_trailing = procedure_trailing
  681. function_code_org = procedure_code
  682. function_comment = COMMENTS_ARE_UPPER ?
  683. pre_comment.join("\n") + "\n" + function_trailing :
  684. function_trailing + "\n " + function_code_org.sub(/^.*$\n/i, '')
  685. function_code = "#{function_code_org}"
  686. if function_type
  687. function_code << "\n" + function_type + " :: " + function_result_arg
  688. end
  689. function_params =
  690. function_params_org.sub(/^\(/, "\(#{function_result_arg}, ")
  691. function = AnyMethod.new("function", function_name)
  692. parse_subprogram(function, function_params,
  693. function_comment, function_code,
  694. before_contains_code, true, function_prefix)
  695. # Specific modification due to function
  696. function.params.sub!(/\(\s*?#{function_result_arg}\s*?,\s*?/, "\( ")
  697. function.params << " result(" + function_result_arg + ")"
  698. function.start_collecting_tokens
  699. function.add_token Token.new(1,1).set_text(function_code_org)
  700. @stats.add_method function
  701. container.add_method function
  702. subroutine_function = function
  703. end
  704. # The visibility of procedure is specified
  705. #
  706. set_visibility(container, procedure_name,
  707. visibility_default, @@public_methods)
  708. # The alias for this procedure from external modules
  709. #
  710. check_external_aliases(procedure_name,
  711. subroutine_function.params,
  712. subroutine_function.comment, subroutine_function) if external
  713. check_public_methods(subroutine_function, container.name)
  714. # contains_lines are parsed as private procedures
  715. if contains_flag
  716. parse_program_or_module(container,
  717. contains_lines.join("\n"), :private)
  718. end
  719. # next loop to search next block
  720. level_depth = 0
  721. block_searching_flag = nil
  722. block_searching_lines = []
  723. pre_comment = []
  724. procedure_trailing = ""
  725. procedure_name = ""
  726. procedure_params = ""
  727. procedure_prefix = ""
  728. procedure_result_arg = ""
  729. contains_lines = []
  730. contains_flag = nil
  731. next false
  732. } # End of remaining_lines.collect!{|line|
  733. # Array remains_lines is converted to String remains_code again
  734. #
  735. remaining_code = remaining_lines.join("\n")
  736. #
  737. # Parse interface
  738. #
  739. interface_scope = false
  740. generic_name = ""
  741. interface_code.split("\n").each{ |line|
  742. if /^\s*?
  743. interface(
  744. \s+\w+|
  745. \s+operator\s*?\(.*?\)|
  746. \s+assignment\s*?\(\s*?=\s*?\)
  747. )?
  748. \s*?(!.*?)?$
  749. /ix =~ line
  750. generic_name = $1 ? $1.strip.chomp : nil
  751. interface_trailing = $2 || "!"
  752. interface_scope = true
  753. interface_scope = false if interface_trailing =~ /!:nodoc:/
  754. # if generic_name =~ /operator\s*?\((.*?)\)/i
  755. # operator_name = $1
  756. # if operator_name && !operator_name.empty?
  757. # generic_name = "#{operator_name}"
  758. # end
  759. # end
  760. # if generic_name =~ /assignment\s*?\((.*?)\)/i
  761. # assignment_name = $1
  762. # if assignment_name && !assignment_name.empty?
  763. # generic_name = "#{assignment_name}"
  764. # end
  765. # end
  766. end
  767. if /^\s*?end\s+interface/i =~ line
  768. interface_scope = false
  769. generic_name = nil
  770. end
  771. # internal alias
  772. if interface_scope && /^\s*?module\s+procedure\s+(.*?)(!.*?)?$/i =~ line
  773. procedures = $1.strip.chomp
  774. procedures_trailing = $2 || "!"
  775. next if procedures_trailing =~ /!:nodoc:/
  776. procedures.split(",").each{ |proc|
  777. proc.strip!
  778. proc.chomp!
  779. next if generic_name == proc || !generic_name
  780. old_meth = container.find_symbol(proc, nil, @options.ignore_case)
  781. next if !old_meth
  782. nolink = old_meth.visibility == :private ? true : nil
  783. nolink = nil if @options.show_all
  784. new_meth =
  785. initialize_external_method(generic_name, proc,
  786. old_meth.params, nil,
  787. old_meth.comment,
  788. old_meth.clone.token_stream[0].text,
  789. true, nolink)
  790. new_meth.singleton = old_meth.singleton
  791. @stats.add_method new_meth
  792. container.add_method new_meth
  793. set_visibility(container, generic_name, visibility_default, @@public_methods)
  794. check_public_methods(new_meth, container.name)
  795. }
  796. end
  797. # external aliases
  798. if interface_scope
  799. # subroutine
  800. proc = nil
  801. params = nil
  802. procedures_trailing = nil
  803. if line =~ /^\s*?
  804. (recursive|pure|elemental)?\s*?
  805. subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
  806. /ix
  807. proc = $2.chomp.strip
  808. generic_name = proc unless generic_name
  809. params = $3 || ""
  810. procedures_trailing = $4 || "!"
  811. # function
  812. elsif line =~ /^\s*?
  813. (recursive|pure|elemental)?\s*?
  814. (
  815. character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
  816. | type\s*?\([\w\s]+?\)\s+
  817. | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
  818. | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
  819. | double\s+precision\s+
  820. | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
  821. | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
  822. )?
  823. function\s+(\w+)\s*?
  824. (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
  825. /ix
  826. proc = $8.chomp.strip
  827. generic_name = proc unless generic_name
  828. params = $9 || ""
  829. procedures_trailing = $12 || "!"
  830. else
  831. next
  832. end
  833. next if procedures_trailing =~ /!:nodoc:/
  834. indicated_method = nil
  835. indicated_file = nil
  836. TopLevel.all_files.each do |name, toplevel|
  837. indicated_method = toplevel.find_local_symbol(proc, @options.ignore_case)
  838. indicated_file = name
  839. break if indicated_method
  840. end
  841. if indicated_method
  842. external_method =
  843. initialize_external_method(generic_name, proc,
  844. indicated_method.params,
  845. indicated_file,
  846. indicated_method.comment)
  847. @stats.add_method external_method
  848. container.add_method external_method
  849. set_visibility(container, generic_name, visibility_default, @@public_methods)
  850. if !container.include_requires?(indicated_file, @options.ignore_case)
  851. container.add_require(Require.new(indicated_file, ""))
  852. end
  853. check_public_methods(external_method, container.name)
  854. else
  855. @@external_aliases << {
  856. "new_name" => generic_name,
  857. "old_name" => proc,
  858. "file_or_module" => container,
  859. "visibility" => find_visibility(container, generic_name, @@public_methods) || visibility_default
  860. }
  861. end
  862. end
  863. } if interface_code # End of interface_code.split("\n").each ...
  864. #
  865. # Already imported methods are removed from @@public_methods.
  866. # Remainders are assumed to be imported from other modules.
  867. #
  868. @@public_methods.delete_if{ |method| method["entity_is_discovered"]}
  869. @@public_methods.each{ |pub_meth|
  870. next unless pub_meth["file_or_module"].name == container.name
  871. pub_meth["used_modules"].each{ |used_mod|
  872. TopLevel.all_classes_and_modules.each{ |modules|
  873. if modules.name == used_mod ||
  874. modules.name.upcase == used_mod.upcase &&
  875. @options.ignore_case
  876. modules.method_list.each{ |meth|
  877. if meth.name == pub_meth["name"] ||
  878. meth.name.upcase == pub_meth["name"].upcase &&
  879. @options.ignore_case
  880. new_meth = initialize_public_method(meth,
  881. modules.name)
  882. if pub_meth["local_name"]
  883. new_meth.name = pub_meth["local_name"]
  884. end
  885. @stats.add_method new_meth
  886. container.add_method new_meth
  887. end
  888. }
  889. end
  890. }
  891. }
  892. }
  893. container
  894. end # End of parse_program_or_module
  895. ##
  896. # Parse arguments, comment, code of subroutine and function. Return
  897. # AnyMethod object.
  898. def parse_subprogram(subprogram, params, comment, code,
  899. before_contains=nil, function=nil, prefix=nil)
  900. subprogram.singleton = false
  901. prefix = "" if !prefix
  902. arguments = params.sub(/\(/, "").sub(/\)/, "").split(",") if params
  903. args_comment, params_opt =
  904. find_arguments(arguments, code.sub(/^s*?contains\s*?(!.*?)?$.*/im, ""),
  905. nil, nil, true)
  906. params_opt = "( " + params_opt + " ) " if params_opt
  907. subprogram.params = params_opt || ""
  908. namelist_comment = find_namelists(code, before_contains)
  909. block_comment = find_comments comment
  910. if function
  911. subprogram.comment = "<b><em> Function </em></b> :: <em>#{prefix}</em>\n"
  912. else
  913. subprogram.comment = "<b><em> Subroutine </em></b> :: <em>#{prefix}</em>\n"
  914. end
  915. subprogram.comment << args_comment if args_comment
  916. subprogram.comment << block_comment if block_comment
  917. subprogram.comment << namelist_comment if namelist_comment
  918. # For output source code
  919. subprogram.start_collecting_tokens
  920. subprogram.add_token Token.new(1,1).set_text(code)
  921. subprogram
  922. end
  923. ##
  924. # Collect comment for file entity
  925. def collect_first_comment(body)
  926. comment = ""
  927. not_comment = ""
  928. comment_start = false
  929. comment_end = false
  930. body.split("\n").each{ |line|
  931. if comment_end
  932. not_comment << line
  933. not_comment << "\n"
  934. elsif /^\s*?!\s?(.*)$/i =~ line
  935. comment_start = true
  936. comment << $1
  937. comment << "\n"
  938. elsif /^\s*?$/i =~ line
  939. comment_end = true if comment_start && COMMENTS_ARE_UPPER
  940. else
  941. comment_end = true
  942. not_comment << line
  943. not_comment << "\n"
  944. end
  945. }
  946. return comment, not_comment
  947. end
  948. ##
  949. # Return comments of definitions of arguments
  950. #
  951. # If "all" argument is true, information of all arguments are returned.
  952. #
  953. # If "modified_params" is true, list of arguments are decorated, for
  954. # example, optional arguments are parenthetic as "[arg]".
  955. def find_arguments(args, text, all=nil, indent=nil, modified_params=nil)
  956. return unless args || all
  957. indent = "" unless indent
  958. args = ["all"] if all
  959. params = "" if modified_params
  960. comma = ""
  961. return unless text
  962. args_rdocforms = "\n"
  963. remaining_lines = "#{text}"
  964. definitions = definition_info(remaining_lines)
  965. args.each{ |arg|
  966. arg.strip!
  967. arg.chomp!
  968. definitions.each { |defitem|
  969. if arg == defitem.varname.strip.chomp || all
  970. args_rdocforms << <<-"EOF"
  971. #{indent}<tt><b>#{defitem.varname.chomp.strip}#{defitem.arraysuffix}</b> #{defitem.inivalue}</tt> ::
  972. #{indent} <tt>#{defitem.types.chomp.strip}</tt>
  973. EOF
  974. if !defitem.comment.chomp.strip.empty?
  975. comment = ""
  976. defitem.comment.split("\n").each{ |line|
  977. comment << " " + line + "\n"
  978. }
  979. args_rdocforms << <<-"EOF"
  980. #{indent} <tt></tt> ::
  981. #{indent} <tt></tt>
  982. #{indent} #{comment.chomp.strip}
  983. EOF
  984. end
  985. if modified_params
  986. if defitem.include_attr?("optional")
  987. params << "#{comma}[#{arg}]"
  988. else
  989. params << "#{comma}#{arg}"
  990. end
  991. comma = ", "
  992. end
  993. end
  994. }
  995. }
  996. if modified_params
  997. return args_rdocforms, params
  998. else
  999. return args_rdocforms
  1000. end
  1001. end
  1002. ##
  1003. # Return comments of definitions of namelists
  1004. def find_namelists(text, before_contains=nil)
  1005. return nil if !text
  1006. result = ""
  1007. lines = "#{text}"
  1008. before_contains = "" if !before_contains
  1009. while lines =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)$/i
  1010. lines = $~.post_match
  1011. nml_comment = COMMENTS_ARE_UPPER ?
  1012. find_comments($~.pre_match) : find_comments($~.post_match)
  1013. nml_name = $1
  1014. nml_args = $2.split(",")
  1015. result << "\n\n=== NAMELIST <tt><b>" + nml_name + "</tt></b>\n\n"
  1016. result << nml_comment + "\n" if nml_comment
  1017. if lines.split("\n")[0] =~ /^\//i
  1018. lines = "namelist " + lines
  1019. end
  1020. result << find_arguments(nml_args, "#{text}" + "\n" + before_contains)
  1021. end
  1022. return result
  1023. end
  1024. ##
  1025. # Comments just after module or subprogram, or arguments are returned. If
  1026. # "COMMENTS_ARE_UPPER" is true, comments just before modules or subprograms
  1027. # are returnd
  1028. def find_comments text
  1029. return "" unless text
  1030. lines = text.split("\n")
  1031. lines.reverse! if COMMENTS_ARE_UPPER
  1032. comment_block = Array.new
  1033. lines.each do |line|
  1034. break if line =~ /^\s*?\w/ || line =~ /^\s*?$/
  1035. if COMMENTS_ARE_UPPER
  1036. comment_block.unshift line.sub(/^\s*?!\s?/,"")
  1037. else
  1038. comment_block.push line.sub(/^\s*?!\s?/,"")
  1039. end
  1040. end
  1041. nice_lines = comment_block.join("\n").split "\n\s*?\n"
  1042. nice_lines[0] ||= ""
  1043. nice_lines.shift
  1044. end
  1045. ##
  1046. # Create method for internal alias
  1047. def initialize_public_method(method, parent)
  1048. return if !method || !parent
  1049. new_meth = AnyMethod.new("External Alias for module", method.name)
  1050. new_meth.singleton = method.singleton
  1051. new_meth.params = method.params.clone
  1052. new_meth.comment = remove_trailing_alias(method.comment.clone)
  1053. new_meth.comment << "\n\n#{EXTERNAL_ALIAS_MES} #{parent.strip.chomp}\##{method.name}"
  1054. return new_meth
  1055. end
  1056. ##
  1057. # Create method for external alias
  1058. #
  1059. # If argument "internal" is true, file is ignored.
  1060. def initialize_external_method(new, old, params, file, comment, token=nil,
  1061. internal=nil, nolink=nil)
  1062. return nil unless new || old
  1063. if internal
  1064. external_alias_header = "#{INTERNAL_ALIAS_MES} "
  1065. external_alias_text = external_alias_header + old
  1066. elsif file
  1067. external_alias_header = "#{EXTERNAL_ALIAS_MES} "
  1068. external_alias_text = external_alias_header + file + "#" + old
  1069. else
  1070. return nil
  1071. end
  1072. external_meth = AnyMethod.new(external_alias_text, new)
  1073. external_meth.singleton = false
  1074. external_meth.params = params
  1075. external_comment = remove_trailing_alias(comment) + "\n\n" if comment
  1076. external_meth.comment = external_comment || ""
  1077. if nolink && token
  1078. external_meth.start_collecting_tokens
  1079. external_meth.add_token Token.new(1,1).set_text(token)
  1080. else
  1081. external_meth.comment << external_alias_text
  1082. end
  1083. return external_meth
  1084. end
  1085. ##
  1086. # Parse visibility
  1087. def parse_visibility(code, default, container)
  1088. result = []
  1089. visibility_default = default || :public
  1090. used_modules = []
  1091. container.includes.each{|i| used_modules << i.name} if container
  1092. remaining_code = code.gsub(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "")
  1093. remaining_code.split("\n").each{ |line|
  1094. if /^\s*?private\s*?$/ =~ line
  1095. visibility_default = :private
  1096. break
  1097. end
  1098. } if remaining_code
  1099. remaining_code.split("\n").each{ |line|
  1100. if /^\s*?private\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
  1101. methods = $2.sub(/!.*$/, '')
  1102. methods.split(",").each{ |meth|
  1103. meth.sub!(/!.*$/, '')
  1104. meth.gsub!(/:/, '')
  1105. result << {
  1106. "name" => meth.chomp.strip,
  1107. "visibility" => :private,
  1108. "used_modules" => used_modules.clone,
  1109. "file_or_module" => container,
  1110. "entity_is_discovered" => nil,
  1111. "local_name" => nil
  1112. }
  1113. }
  1114. elsif /^\s*?public\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line
  1115. methods = $2.sub(/!.*$/, '')
  1116. methods.split(",").each{ |meth|
  1117. meth.sub!(/!.*$/, '')
  1118. meth.gsub!(/:/, '')
  1119. result << {
  1120. "name" => meth.chomp.strip,
  1121. "visibility" => :public,
  1122. "used_modules" => used_modules.clone,
  1123. "file_or_module" => container,
  1124. "entity_is_discovered" => nil,
  1125. "local_name" => nil
  1126. }
  1127. }
  1128. end
  1129. } if remaining_code
  1130. if container
  1131. result.each{ |vis_info|
  1132. vis_info["parent"] = container.name
  1133. }
  1134. end
  1135. return visibility_default, result
  1136. end
  1137. ##
  1138. # Set visibility
  1139. #
  1140. # "subname" element of "visibility_info" is deleted.
  1141. def set_visibility(container, subname, visibility_default, visibility_info)
  1142. return unless container || subname || visibility_default || visibility_info
  1143. not_found = true
  1144. visibility_info.collect!{ |info|
  1145. if info["name"] == subname ||
  1146. @options.ignore_case && info["name"].upcase == subname.upcase
  1147. if info["file_or_module"].name == container.name
  1148. container.set_visibility_for([subname], info["visibility"])
  1149. info["entity_is_discovered"] = true
  1150. not_found = false
  1151. end
  1152. end
  1153. info
  1154. }
  1155. if not_found
  1156. return container.set_visibility_for([subname], visibility_default)
  1157. else
  1158. return container
  1159. end
  1160. end
  1161. ##
  1162. # Find visibility
  1163. def find_visibility(container, subname, visibility_info)
  1164. return nil if !subname || !visibility_info
  1165. visibility_info.each{ |info|
  1166. if info["name"] == subname ||
  1167. @options.ignore_case && info["name"].upcase == subname.upcase
  1168. if info["parent"] == container.name
  1169. return info["visibility"]
  1170. end
  1171. end
  1172. }
  1173. return nil
  1174. end
  1175. ##
  1176. # Check external aliases
  1177. def check_external_aliases(subname, params, comment, test=nil)
  1178. @@external_aliases.each{ |alias_item|
  1179. if subname == alias_item["old_name"] ||
  1180. subname.upcase == alias_item["old_name"].upcase &&
  1181. @options.ignore_case
  1182. new_meth = initialize_external_method(alias_item["new_name"],
  1183. subname, params, @file_name,
  1184. comment)
  1185. new_meth.visibility = alias_item["visibility"]
  1186. @stats.add_method new_meth
  1187. alias_item["file_or_module"].add_method(new_meth)
  1188. if !alias_item["file_or_module"].include_requires?(@file_name, @options.ignore_case)
  1189. alias_item["file_or_module"].add_require(Require.new(@file_name, ""))
  1190. end
  1191. end
  1192. }
  1193. end
  1194. ##
  1195. # Check public_methods
  1196. def check_public_methods(method, parent)
  1197. return if !method || !parent
  1198. @@public_methods.each{ |alias_item|
  1199. parent_is_used_module = nil
  1200. alias_item["used_modules"].each{ |used_module|
  1201. if used_module == parent ||
  1202. used_module.upcase == parent.upcase &&
  1203. @options.ignore_case
  1204. parent_is_used_module = true
  1205. end
  1206. }
  1207. next if !parent_is_used_module
  1208. if method.name == alias_item["name"] ||
  1209. method.name.upcase == alias_item["name"].upcase &&
  1210. @options.ignore_case
  1211. new_meth = initialize_public_method(method, parent)
  1212. if alias_item["local_name"]
  1213. new_meth.name = alias_item["local_name"]
  1214. end
  1215. @stats.add_method new_meth
  1216. alias_item["file_or_module"].add_method new_meth
  1217. end
  1218. }
  1219. end
  1220. ##
  1221. # Continuous lines are united.
  1222. #
  1223. # Comments in continuous lines are removed.
  1224. def united_to_one_line(f90src)
  1225. return "" unless f90src
  1226. lines = f90src.split("\n")
  1227. previous_continuing = false
  1228. now_continuing = false
  1229. body = ""
  1230. lines.each{ |line|
  1231. words = line.split("")
  1232. next if words.empty? && previous_continuing
  1233. commentout = false
  1234. brank_flag = true ; brank_char = ""
  1235. squote = false ; dquote = false
  1236. ignore = false
  1237. words.collect! { |char|
  1238. if previous_continuing && brank_flag
  1239. now_continuing = true
  1240. ignore = true
  1241. case char
  1242. when "!" ; break
  1243. when " " ; brank_char << char ; next ""
  1244. when "&"
  1245. brank_flag = false
  1246. now_continuing = false
  1247. next ""
  1248. else
  1249. brank_flag = false
  1250. now_continuing = false
  1251. ignore = false
  1252. next brank_char + char
  1253. end
  1254. end
  1255. ignore = false
  1256. if now_continuing
  1257. next ""
  1258. elsif !(squote) && !(dquote) && !(commentout)
  1259. case char
  1260. when "!" ; commentout = true ; next char
  1261. when "\""; dquote = true ; next char
  1262. when "\'"; squote = true ; next char
  1263. when "&" ; now_continuing = true ; next ""
  1264. else next char
  1265. end
  1266. elsif commentout
  1267. next char
  1268. elsif squote
  1269. case char
  1270. when "\'"; squote = false ; next char
  1271. else next char
  1272. end
  1273. elsif dquote
  1274. case char
  1275. when "\""; dquote = false ; next char
  1276. else next char
  1277. end
  1278. end
  1279. }
  1280. if !ignore && !previous_continuing || !brank_flag
  1281. if previous_continuing
  1282. body << words.join("")
  1283. else
  1284. body << "\n" + words.join("")
  1285. end
  1286. end
  1287. previous_continuing = now_continuing ? true : nil
  1288. now_continuing = nil
  1289. }
  1290. return body
  1291. end
  1292. ##
  1293. # Continuous line checker
  1294. def continuous_line?(line)
  1295. continuous = false
  1296. if /&\s*?(!.*)?$/ =~ line
  1297. continuous = true
  1298. if comment_out?($~.pre_match)
  1299. continuous = false
  1300. end
  1301. end
  1302. return continuous
  1303. end
  1304. ##
  1305. # Comment out checker
  1306. def comment_out?(line)
  1307. return nil unless line
  1308. commentout = false
  1309. squote = false ; dquote = false
  1310. line.split("").each { |char|
  1311. if !(squote) && !(dquote)
  1312. case char
  1313. when "!" ; commentout = true ; break
  1314. when "\""; dquote = true
  1315. when "\'"; squote = true
  1316. else next
  1317. end
  1318. elsif squote
  1319. case char
  1320. when "\'"; squote = false
  1321. else next
  1322. end
  1323. elsif dquote
  1324. case char
  1325. when "\""; dquote = false
  1326. else next
  1327. end
  1328. end
  1329. }
  1330. return commentout
  1331. end
  1332. ##
  1333. # Semicolons are replaced to line feed.
  1334. def semicolon_to_linefeed(text)
  1335. return "" unless text
  1336. lines = text.split("\n")
  1337. lines.collect!{ |line|
  1338. words = line.split("")
  1339. commentout = false
  1340. squote = false ; dquote = false
  1341. words.collect! { |char|
  1342. if !(squote) && !(dquote) && !(commentout)
  1343. case char
  1344. when "!" ; commentout = true ; next char
  1345. when "\""; dquote = true ; next char
  1346. when "\'"; squote = true ; next char
  1347. when ";" ; "\n"
  1348. else next char
  1349. end
  1350. elsif commentout
  1351. next char
  1352. elsif squote
  1353. case char
  1354. when "\'"; squote = false ; next char
  1355. else next char
  1356. end
  1357. elsif dquote
  1358. case char
  1359. when "\""; dquote = false ; next char
  1360. else next char
  1361. end
  1362. end
  1363. }
  1364. words.join("")
  1365. }
  1366. return lines.join("\n")
  1367. end
  1368. ##
  1369. # Which "line" is start of block (module, program, block data, subroutine,
  1370. # function) statement ?
  1371. def block_start?(line)
  1372. return nil if !line
  1373. if line =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$/i ||
  1374. line =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$/i ||
  1375. line =~ /^\s*?block\s+data(\s+\w+)?\s*?(!.*?)?$/i ||
  1376. line =~ \
  1377. /^\s*?
  1378. (recursive|pure|elemental)?\s*?
  1379. subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$
  1380. /ix ||
  1381. line =~ \
  1382. /^\s*?
  1383. (recursive|pure|elemental)?\s*?
  1384. (
  1385. character\s*?(\([\w\s\=\(\)\*]+?\))?\s+
  1386. | type\s*?\([\w\s]+?\)\s+
  1387. | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+
  1388. | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+
  1389. | double\s+precision\s+
  1390. | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+
  1391. | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+
  1392. )?
  1393. function\s+(\w+)\s*?
  1394. (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$
  1395. /ix
  1396. return true
  1397. end
  1398. return nil
  1399. end
  1400. ##
  1401. # Which "line" is end of block (module, program, block data, subroutine,
  1402. # function) statement ?
  1403. def block_end?(line)
  1404. return nil if !line
  1405. if line =~ /^\s*?end\s*?(!.*?)?$/i ||
  1406. line =~ /^\s*?end\s+module(\s+\w+)?\s*?(!.*?)?$/i ||
  1407. line =

Large files files are truncated, but you can click here to view the full file