PageRenderTime 176ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/jruby-1.1.6RC1/lib/ruby/1.8/rdoc/parsers/parse_f95.rb

https://bitbucket.org/nicksieger/advent-jruby
Ruby | 1841 lines | 1335 code | 165 blank | 341 comment | 253 complexity | b831c7aea5822f943f1f92eb79181fff MD5 | raw file
Possible License(s): CPL-1.0, AGPL-1.0, LGPL-2.1, JSON

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

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

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