rdoc 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rdoc might be problematic. Click here for more details.

Files changed (52) hide show
  1. data.tar.gz.sig +1 -0
  2. data/History.txt +30 -0
  3. data/Manifest.txt +18 -6
  4. data/Rakefile +52 -0
  5. data/lib/rdoc.rb +69 -69
  6. data/lib/rdoc/code_objects.rb +331 -112
  7. data/lib/rdoc/generator.rb +172 -144
  8. data/lib/rdoc/generator/html.rb +45 -18
  9. data/lib/rdoc/generator/html/frameless.rb +795 -0
  10. data/lib/rdoc/generator/html/hefss.rb +11 -11
  11. data/lib/rdoc/generator/html/html.rb +81 -87
  12. data/lib/rdoc/generator/html/kilmer.rb +10 -10
  13. data/lib/rdoc/generator/html/one_page_html.rb +9 -9
  14. data/lib/rdoc/generator/ri.rb +5 -8
  15. data/lib/rdoc/generator/texinfo.rb +84 -0
  16. data/lib/rdoc/generator/texinfo/class.texinfo.erb +44 -0
  17. data/lib/rdoc/generator/texinfo/file.texinfo.erb +6 -0
  18. data/lib/rdoc/generator/texinfo/method.texinfo.erb +6 -0
  19. data/lib/rdoc/generator/texinfo/texinfo.erb +28 -0
  20. data/lib/rdoc/known_classes.rb +69 -0
  21. data/lib/rdoc/markup.rb +3 -3
  22. data/lib/rdoc/markup/attribute_manager.rb +0 -9
  23. data/lib/rdoc/markup/fragments.rb +1 -1
  24. data/lib/rdoc/markup/preprocess.rb +10 -6
  25. data/lib/rdoc/markup/to_html.rb +55 -8
  26. data/lib/rdoc/markup/to_html_crossref.rb +21 -5
  27. data/lib/rdoc/markup/to_texinfo.rb +69 -0
  28. data/lib/rdoc/options.rb +37 -14
  29. data/lib/rdoc/parser.rb +109 -0
  30. data/lib/rdoc/parser/c.rb +656 -0
  31. data/lib/rdoc/parser/f95.rb +1835 -0
  32. data/lib/rdoc/{parsers/parse_rb.rb → parser/ruby.rb} +1436 -1191
  33. data/lib/rdoc/parser/simple.rb +38 -0
  34. data/lib/rdoc/rdoc.rb +48 -32
  35. data/lib/rdoc/ri.rb +5 -1
  36. data/lib/rdoc/ri/descriptions.rb +8 -5
  37. data/lib/rdoc/ri/driver.rb +148 -49
  38. data/lib/rdoc/stats.rb +94 -4
  39. data/test/test_rdoc_info_formatting.rb +175 -0
  40. data/test/test_rdoc_info_sections.rb +136 -0
  41. data/test/test_rdoc_markup_to_html.rb +30 -0
  42. data/test/test_rdoc_markup_to_html_crossref.rb +18 -0
  43. data/test/{test_rdoc_c_parser.rb → test_rdoc_parser_c.rb} +8 -11
  44. data/test/test_rdoc_parser_ruby.rb +539 -0
  45. data/test/test_rdoc_ri_default_display.rb +17 -16
  46. data/test/test_rdoc_ri_driver.rb +92 -0
  47. metadata +54 -12
  48. metadata.gz.sig +0 -0
  49. data/lib/rdoc/parsers/parse_c.rb +0 -775
  50. data/lib/rdoc/parsers/parse_f95.rb +0 -1841
  51. data/lib/rdoc/parsers/parse_simple.rb +0 -40
  52. data/lib/rdoc/parsers/parserfactory.rb +0 -99
@@ -1,34 +1,28 @@
1
- #!/usr/local/bin/ruby
2
-
3
- # Parse a Ruby source file, building a set of objects
4
- # representing the modules, classes, methods,
5
- # requires, and includes we find (these classes
6
- # are defined in code_objects.rb).
7
-
1
+ ##
8
2
  # This file contains stuff stolen outright from:
9
3
  #
10
4
  # rtags.rb -
11
- # ruby-lex.rb - ruby lexcal analizer
5
+ # ruby-lex.rb - ruby lexcal analyzer
12
6
  # ruby-token.rb - ruby tokens
13
- # by Keiju ISHITSUKA (Nippon Rational Inc.)
7
+ # by Keiju ISHITSUKA (Nippon Rational Inc.)
14
8
  #
15
9
 
16
- require "e2mmap"
17
- require "irb/slex"
18
-
19
- require "rdoc/code_objects"
20
- require "rdoc/tokenstream"
10
+ require 'e2mmap'
11
+ require 'irb/slex'
21
12
 
22
- require "rdoc/markup/preprocess"
23
-
24
- require "rdoc/parsers/parserfactory"
13
+ require 'rdoc/code_objects'
14
+ require 'rdoc/tokenstream'
15
+ require 'rdoc/markup/preprocess'
16
+ require 'rdoc/parser'
25
17
 
26
18
  $TOKEN_DEBUG ||= nil
27
19
  #$TOKEN_DEBUG = $DEBUG_RDOC
28
20
 
21
+ ##
29
22
  # Definitions of all tokens involved in the lexical analysis
30
23
 
31
- module RubyToken
24
+ module RDoc::RubyToken
25
+
32
26
  EXPR_BEG = :EXPR_BEG
33
27
  EXPR_MID = :EXPR_MID
34
28
  EXPR_END = :EXPR_END
@@ -39,7 +33,10 @@ module RubyToken
39
33
 
40
34
  class Token
41
35
  NO_TEXT = "??".freeze
36
+
42
37
  attr_accessor :text
38
+ attr_reader :line_no
39
+ attr_reader :char_no
43
40
 
44
41
  def initialize(line_no, char_no)
45
42
  @line_no = line_no
@@ -47,14 +44,22 @@ module RubyToken
47
44
  @text = NO_TEXT
48
45
  end
49
46
 
50
- # Because we're used in contexts that expect to return a token,
51
- # we set the text string and then return ourselves
47
+ def ==(other)
48
+ self.class == other.class and
49
+ other.line_no == @line_no and
50
+ other.char_no == @char_no and
51
+ other.text == @text
52
+ end
53
+
54
+ ##
55
+ # Because we're used in contexts that expect to return a token, we set the
56
+ # text string and then return ourselves
57
+
52
58
  def set_text(text)
53
59
  @text = text
54
60
  self
55
61
  end
56
62
 
57
- attr_reader :line_no, :char_no
58
63
  end
59
64
 
60
65
  class TkNode < Token
@@ -88,7 +93,7 @@ module RubyToken
88
93
  class TkOPASGN < TkOp
89
94
  def initialize(line_no, char_no, op)
90
95
  super(line_no, char_no)
91
- op = TkReading2Token[op] unless op.kind_of?(Symbol)
96
+ op = TkReading2Token[op] unless Symbol === op
92
97
  @op = op
93
98
  end
94
99
  attr :op
@@ -114,10 +119,8 @@ module RubyToken
114
119
  tk = nil
115
120
  case token
116
121
  when String, Symbol
117
- source = token.kind_of?(String) ? TkReading2Token : TkSymbol2Token
118
- if (tk = source[token]).nil?
119
- fail TkReading2TokenNoKey, token
120
- end
122
+ source = String === token ? TkReading2Token : TkSymbol2Token
123
+ raise TkReading2TokenNoKey, token if (tk = source[token]).nil?
121
124
  tk = Token(tk[0], value)
122
125
  else
123
126
  tk = if (token.ancestors & [TkId, TkVal, TkOPASGN, TkUnknownChar]).empty?
@@ -132,38 +135,38 @@ module RubyToken
132
135
  TokenDefinitions = [
133
136
  [:TkCLASS, TkKW, "class", EXPR_CLASS],
134
137
  [:TkMODULE, TkKW, "module", EXPR_BEG],
135
- [:TkDEF, TkKW, "def", EXPR_FNAME],
138
+ [:TkDEF, TkKW, "def", EXPR_FNAME],
136
139
  [:TkUNDEF, TkKW, "undef", EXPR_FNAME],
137
140
  [:TkBEGIN, TkKW, "begin", EXPR_BEG],
138
141
  [:TkRESCUE, TkKW, "rescue", EXPR_MID],
139
142
  [:TkENSURE, TkKW, "ensure", EXPR_BEG],
140
- [:TkEND, TkKW, "end", EXPR_END],
143
+ [:TkEND, TkKW, "end", EXPR_END],
141
144
  [:TkIF, TkKW, "if", EXPR_BEG, :TkIF_MOD],
142
145
  [:TkUNLESS, TkKW, "unless", EXPR_BEG, :TkUNLESS_MOD],
143
- [:TkTHEN, TkKW, "then", EXPR_BEG],
146
+ [:TkTHEN, TkKW, "then", EXPR_BEG],
144
147
  [:TkELSIF, TkKW, "elsif", EXPR_BEG],
145
- [:TkELSE, TkKW, "else", EXPR_BEG],
146
- [:TkCASE, TkKW, "case", EXPR_BEG],
147
- [:TkWHEN, TkKW, "when", EXPR_BEG],
148
+ [:TkELSE, TkKW, "else", EXPR_BEG],
149
+ [:TkCASE, TkKW, "case", EXPR_BEG],
150
+ [:TkWHEN, TkKW, "when", EXPR_BEG],
148
151
  [:TkWHILE, TkKW, "while", EXPR_BEG, :TkWHILE_MOD],
149
152
  [:TkUNTIL, TkKW, "until", EXPR_BEG, :TkUNTIL_MOD],
150
- [:TkFOR, TkKW, "for", EXPR_BEG],
153
+ [:TkFOR, TkKW, "for", EXPR_BEG],
151
154
  [:TkBREAK, TkKW, "break", EXPR_END],
152
- [:TkNEXT, TkKW, "next", EXPR_END],
153
- [:TkREDO, TkKW, "redo", EXPR_END],
155
+ [:TkNEXT, TkKW, "next", EXPR_END],
156
+ [:TkREDO, TkKW, "redo", EXPR_END],
154
157
  [:TkRETRY, TkKW, "retry", EXPR_END],
155
- [:TkIN, TkKW, "in", EXPR_BEG],
156
- [:TkDO, TkKW, "do", EXPR_BEG],
158
+ [:TkIN, TkKW, "in", EXPR_BEG],
159
+ [:TkDO, TkKW, "do", EXPR_BEG],
157
160
  [:TkRETURN, TkKW, "return", EXPR_MID],
158
161
  [:TkYIELD, TkKW, "yield", EXPR_END],
159
162
  [:TkSUPER, TkKW, "super", EXPR_END],
160
- [:TkSELF, TkKW, "self", EXPR_END],
161
- [:TkNIL, TkKW, "nil", EXPR_END],
162
- [:TkTRUE, TkKW, "true", EXPR_END],
163
+ [:TkSELF, TkKW, "self", EXPR_END],
164
+ [:TkNIL, TkKW, "nil", EXPR_END],
165
+ [:TkTRUE, TkKW, "true", EXPR_END],
163
166
  [:TkFALSE, TkKW, "false", EXPR_END],
164
- [:TkAND, TkKW, "and", EXPR_BEG],
165
- [:TkOR, TkKW, "or", EXPR_BEG],
166
- [:TkNOT, TkKW, "not", EXPR_BEG],
167
+ [:TkAND, TkKW, "and", EXPR_BEG],
168
+ [:TkOR, TkKW, "or", EXPR_BEG],
169
+ [:TkNOT, TkKW, "not", EXPR_BEG],
167
170
  [:TkIF_MOD, TkKW],
168
171
  [:TkUNLESS_MOD, TkKW],
169
172
  [:TkWHILE_MOD, TkKW],
@@ -171,14 +174,14 @@ module RubyToken
171
174
  [:TkALIAS, TkKW, "alias", EXPR_FNAME],
172
175
  [:TkDEFINED, TkKW, "defined?", EXPR_END],
173
176
  [:TklBEGIN, TkKW, "BEGIN", EXPR_END],
174
- [:TklEND, TkKW, "END", EXPR_END],
177
+ [:TklEND, TkKW, "END", EXPR_END],
175
178
  [:Tk__LINE__, TkKW, "__LINE__", EXPR_END],
176
179
  [:Tk__FILE__, TkKW, "__FILE__", EXPR_END],
177
180
 
178
181
  [:TkIDENTIFIER, TkId],
179
- [:TkFID, TkId],
180
- [:TkGVAR, TkId],
181
- [:TkIVAR, TkId],
182
+ [:TkFID, TkId],
183
+ [:TkGVAR, TkId],
184
+ [:TkIVAR, TkId],
182
185
  [:TkCONSTANT, TkId],
183
186
 
184
187
  [:TkINTEGER, TkVal],
@@ -196,28 +199,28 @@ module RubyToken
196
199
 
197
200
  [:TkUPLUS, TkOp, "+@"],
198
201
  [:TkUMINUS, TkOp, "-@"],
199
- [:TkPOW, TkOp, "**"],
200
- [:TkCMP, TkOp, "<=>"],
201
- [:TkEQ, TkOp, "=="],
202
- [:TkEQQ, TkOp, "==="],
203
- [:TkNEQ, TkOp, "!="],
204
- [:TkGEQ, TkOp, ">="],
205
- [:TkLEQ, TkOp, "<="],
202
+ [:TkPOW, TkOp, "**"],
203
+ [:TkCMP, TkOp, "<=>"],
204
+ [:TkEQ, TkOp, "=="],
205
+ [:TkEQQ, TkOp, "==="],
206
+ [:TkNEQ, TkOp, "!="],
207
+ [:TkGEQ, TkOp, ">="],
208
+ [:TkLEQ, TkOp, "<="],
206
209
  [:TkANDOP, TkOp, "&&"],
207
- [:TkOROP, TkOp, "||"],
210
+ [:TkOROP, TkOp, "||"],
208
211
  [:TkMATCH, TkOp, "=~"],
209
212
  [:TkNMATCH, TkOp, "!~"],
210
- [:TkDOT2, TkOp, ".."],
211
- [:TkDOT3, TkOp, "..."],
212
- [:TkAREF, TkOp, "[]"],
213
- [:TkASET, TkOp, "[]="],
213
+ [:TkDOT2, TkOp, ".."],
214
+ [:TkDOT3, TkOp, "..."],
215
+ [:TkAREF, TkOp, "[]"],
216
+ [:TkASET, TkOp, "[]="],
214
217
  [:TkLSHFT, TkOp, "<<"],
215
218
  [:TkRSHFT, TkOp, ">>"],
216
219
  [:TkCOLON2, TkOp],
217
220
  [:TkCOLON3, TkOp],
218
- # [:OPASGN, TkOp], # +=, -= etc. #
221
+ # [:OPASGN, TkOp], # +=, -= etc. #
219
222
  [:TkASSOC, TkOp, "=>"],
220
- [:TkQUESTION, TkOp, "?"], #?
223
+ [:TkQUESTION, TkOp, "?"], #?
221
224
  [:TkCOLON, TkOp, ":"], #:
222
225
 
223
226
  [:TkfLPAREN], # func( #
@@ -227,13 +230,13 @@ module RubyToken
227
230
  [:TkAMPER], # &arg #
228
231
  [:TkSYMBOL, TkId], # :SYMBOL
229
232
  [:TkSYMBEG, TkId],
230
- [:TkGT, TkOp, ">"],
231
- [:TkLT, TkOp, "<"],
232
- [:TkPLUS, TkOp, "+"],
233
+ [:TkGT, TkOp, ">"],
234
+ [:TkLT, TkOp, "<"],
235
+ [:TkPLUS, TkOp, "+"],
233
236
  [:TkMINUS, TkOp, "-"],
234
- [:TkMULT, TkOp, "*"],
235
- [:TkDIV, TkOp, "/"],
236
- [:TkMOD, TkOp, "%"],
237
+ [:TkMULT, TkOp, "*"],
238
+ [:TkDIV, TkOp, "/"],
239
+ [:TkMOD, TkOp, "%"],
237
240
  [:TkBITOR, TkOp, "|"],
238
241
  [:TkBITXOR, TkOp, "^"],
239
242
  [:TkBITAND, TkOp, "&"],
@@ -243,7 +246,7 @@ module RubyToken
243
246
  [:TkBACKQUOTE, TkOp, "`"],
244
247
 
245
248
  [:TkASSIGN, Token, "="],
246
- [:TkDOT, Token, "."],
249
+ [:TkDOT, Token, "."],
247
250
  [:TkLPAREN, Token, "("], #(exp)
248
251
  [:TkLBRACK, Token, "["], #[arry]
249
252
  [:TkLBRACE, Token, "{"], #{hash}
@@ -259,7 +262,7 @@ module RubyToken
259
262
  [:TkEND_OF_SCRIPT],
260
263
 
261
264
  [:TkBACKSLASH, TkUnknownChar, "\\"],
262
- [:TkAT, TkUnknownChar, "@"],
265
+ [:TkAT, TkUnknownChar, "@"],
263
266
  [:TkDOLLAR, TkUnknownChar, "\$"], #"
264
267
  ]
265
268
 
@@ -268,14 +271,13 @@ module RubyToken
268
271
  TkReading2Token = {}
269
272
  TkSymbol2Token = {}
270
273
 
271
- def RubyToken.def_token(token_n, super_token = Token, reading = nil, *opts)
272
- token_n = token_n.id2name unless token_n.kind_of?(String)
273
- if RubyToken.const_defined?(token_n)
274
- fail AlreadyDefinedToken, token_n
275
- end
274
+ def self.def_token(token_n, super_token = Token, reading = nil, *opts)
275
+ token_n = token_n.id2name unless String === token_n
276
+
277
+ fail AlreadyDefinedToken, token_n if const_defined?(token_n)
276
278
 
277
279
  token_c = Class.new super_token
278
- RubyToken.const_set token_n, token_c
280
+ const_set token_n, token_c
279
281
  # token_c.inspect
280
282
 
281
283
  if reading
@@ -283,9 +285,9 @@ module RubyToken
283
285
  fail TkReading2TokenDuplicateError, token_n, reading
284
286
  end
285
287
  if opts.empty?
286
- TkReading2Token[reading] = [token_c]
288
+ TkReading2Token[reading] = [token_c]
287
289
  else
288
- TkReading2Token[reading] = [token_c].concat(opts)
290
+ TkReading2Token[reading] = [token_c].concat(opts)
289
291
  end
290
292
  end
291
293
  TkSymbol2Token[token_n.intern] = token_c
@@ -306,12 +308,12 @@ module RubyToken
306
308
 
307
309
  end
308
310
 
311
+ ##
309
312
  # Lexical analyzer for Ruby source
310
313
 
311
- class RubyLex
314
+ class RDoc::RubyLex
312
315
 
313
- ######################################################################
314
- #
316
+ ##
315
317
  # Read an input stream character by character. We allow for unlimited
316
318
  # ungetting of characters just read.
317
319
  #
@@ -432,16 +434,16 @@ class RubyLex
432
434
  def_exception(:TkReading2TokenNoKey, "key nothing(key='%s')")
433
435
  def_exception(:TkSymbol2TokenNoKey, "key nothing(key='%s')")
434
436
  def_exception(:TkReading2TokenDuplicateError,
435
- "key duplicate(token_n='%s', key='%s')")
437
+ "key duplicate(token_n='%s', key='%s')")
436
438
  def_exception(:SyntaxError, "%s")
437
439
 
438
- include RubyToken
440
+ include RDoc::RubyToken
439
441
  include IRB
440
442
 
441
443
  attr_reader :continue
442
444
  attr_reader :lex_state
443
445
 
444
- def RubyLex.debug?
446
+ def self.debug?
445
447
  false
446
448
  end
447
449
 
@@ -519,13 +521,13 @@ class RubyLex
519
521
  end
520
522
 
521
523
  def lex
522
- until (((tk = token).kind_of?(TkNL) || tk.kind_of?(TkEND_OF_SCRIPT)) &&
523
- !@continue or
524
- tk.nil?)
524
+ until (TkNL === (tk = token) or TkEND_OF_SCRIPT === tk) and
525
+ not @continue or tk.nil?
525
526
  end
527
+
526
528
  line = get_read
527
529
 
528
- if line == "" and tk.kind_of?(TkEND_OF_SCRIPT) || tk.nil?
530
+ if line == "" and TkEND_OF_SCRIPT === tk or tk.nil? then
529
531
  nil
530
532
  else
531
533
  line
@@ -536,13 +538,15 @@ class RubyLex
536
538
  set_token_position(line_no, char_no)
537
539
  begin
538
540
  begin
539
- tk = @OP.match(self)
540
- @space_seen = tk.kind_of?(TkSPACE)
541
- rescue SyntaxError
542
- abort if @exception_on_syntax_error
543
- tk = TkError.new(line_no, char_no)
541
+ tk = @OP.match(self)
542
+ @space_seen = TkSPACE === tk
543
+ rescue SyntaxError => e
544
+ raise RDoc::Error, "syntax error: #{e.message}" if
545
+ @exception_on_syntax_error
546
+
547
+ tk = TkError.new(line_no, char_no)
544
548
  end
545
- end while @skip_space and tk.kind_of?(TkSPACE)
549
+ end while @skip_space and TkSPACE === tk
546
550
  if @read_auto_clean_up
547
551
  get_read
548
552
  end
@@ -636,23 +640,23 @@ class RubyLex
636
640
  end
637
641
 
638
642
  @OP.def_rule("\n") do
639
- print "\\n\n" if RubyLex.debug?
643
+ print "\\n\n" if RDoc::RubyLex.debug?
640
644
  case @lex_state
641
645
  when EXPR_BEG, EXPR_FNAME, EXPR_DOT
642
- @continue = TRUE
646
+ @continue = TRUE
643
647
  else
644
- @continue = FALSE
645
- @lex_state = EXPR_BEG
648
+ @continue = FALSE
649
+ @lex_state = EXPR_BEG
646
650
  end
647
651
  Token(TkNL).set_text("\n")
648
652
  end
649
653
 
650
654
  @OP.def_rules("*", "**",
651
- "!", "!=", "!~",
652
- "=", "==", "===",
653
- "=~", "<=>",
654
- "<", "<=",
655
- ">", ">=", ">>") do
655
+ "!", "!=", "!~",
656
+ "=", "==", "===",
657
+ "=~", "<=>",
658
+ "<", "<=",
659
+ ">", ">=", ">>") do
656
660
  |op, io|
657
661
  @lex_state = EXPR_BEG
658
662
  Token(op).set_text(op)
@@ -662,11 +666,11 @@ class RubyLex
662
666
  |op, io|
663
667
  tk = nil
664
668
  if @lex_state != EXPR_END && @lex_state != EXPR_CLASS &&
665
- (@lex_state != EXPR_ARG || @space_seen)
666
- c = peek(0)
667
- if /[-\w_\"\'\`]/ =~ c
668
- tk = identify_here_document
669
- end
669
+ (@lex_state != EXPR_ARG || @space_seen)
670
+ c = peek(0)
671
+ if /[-\w_\"\'\`]/ =~ c
672
+ tk = identify_here_document
673
+ end
670
674
  end
671
675
  if !tk
672
676
  @lex_state = EXPR_BEG
@@ -683,32 +687,32 @@ class RubyLex
683
687
  @OP.def_rules("`") do
684
688
  |op, io|
685
689
  if @lex_state == EXPR_FNAME
686
- Token(op).set_text(op)
690
+ Token(op).set_text(op)
687
691
  else
688
- identify_string(op)
692
+ identify_string(op)
689
693
  end
690
694
  end
691
695
 
692
696
  @OP.def_rules('?') do
693
697
  |op, io|
694
698
  if @lex_state == EXPR_END
695
- @lex_state = EXPR_BEG
696
- Token(TkQUESTION).set_text(op)
699
+ @lex_state = EXPR_BEG
700
+ Token(TkQUESTION).set_text(op)
697
701
  else
698
- ch = getc
699
- if @lex_state == EXPR_ARG && ch !~ /\s/
700
- ungetc
701
- @lex_state = EXPR_BEG;
702
- Token(TkQUESTION).set_text(op)
703
- else
702
+ ch = getc
703
+ if @lex_state == EXPR_ARG && ch !~ /\s/
704
+ ungetc
705
+ @lex_state = EXPR_BEG
706
+ Token(TkQUESTION).set_text(op)
707
+ else
704
708
  str = op
705
709
  str << ch
706
- if (ch == '\\') #'
707
- str << read_escape
708
- end
709
- @lex_state = EXPR_END
710
- Token(TkINTEGER).set_text(str)
711
- end
710
+ if (ch == '\\') #'
711
+ str << read_escape
712
+ end
713
+ @lex_state = EXPR_END
714
+ Token(TkINTEGER).set_text(str)
715
+ end
712
716
  end
713
717
  end
714
718
 
@@ -719,7 +723,7 @@ class RubyLex
719
723
  end
720
724
 
721
725
  @OP.def_rules("+=", "-=", "*=", "**=",
722
- "&=", "|=", "^=", "<<=", ">>=", "||=", "&&=") do
726
+ "&=", "|=", "^=", "<<=", ">>=", "||=", "&&=") do
723
727
  |op, io|
724
728
  @lex_state = EXPR_BEG
725
729
  op =~ /^(.*)=$/
@@ -737,30 +741,30 @@ class RubyLex
737
741
  @OP.def_rules("+", "-") do
738
742
  |op, io|
739
743
  catch(:RET) do
740
- if @lex_state == EXPR_ARG
741
- if @space_seen and peek(0) =~ /[0-9]/
742
- throw :RET, identify_number(op)
743
- else
744
- @lex_state = EXPR_BEG
745
- end
746
- elsif @lex_state != EXPR_END and peek(0) =~ /[0-9]/
747
- throw :RET, identify_number(op)
748
- else
749
- @lex_state = EXPR_BEG
750
- end
751
- Token(op).set_text(op)
744
+ if @lex_state == EXPR_ARG
745
+ if @space_seen and peek(0) =~ /[0-9]/
746
+ throw :RET, identify_number(op)
747
+ else
748
+ @lex_state = EXPR_BEG
749
+ end
750
+ elsif @lex_state != EXPR_END and peek(0) =~ /[0-9]/
751
+ throw :RET, identify_number(op)
752
+ else
753
+ @lex_state = EXPR_BEG
754
+ end
755
+ Token(op).set_text(op)
752
756
  end
753
757
  end
754
758
 
755
759
  @OP.def_rule(".") do
756
760
  @lex_state = EXPR_BEG
757
761
  if peek(0) =~ /[0-9]/
758
- ungetc
759
- identify_number("")
762
+ ungetc
763
+ identify_number("")
760
764
  else
761
- # for obj.if
762
- @lex_state = EXPR_DOT
763
- Token(TkDOT).set_text(".")
765
+ # for obj.if
766
+ @lex_state = EXPR_DOT
767
+ Token(TkDOT).set_text(".")
764
768
  end
765
769
  end
766
770
 
@@ -783,23 +787,22 @@ class RubyLex
783
787
 
784
788
  @OP.def_rule(":") do
785
789
  if @lex_state == EXPR_END || peek(0) =~ /\s/
786
- @lex_state = EXPR_BEG
787
- tk = Token(TkCOLON)
790
+ @lex_state = EXPR_BEG
791
+ tk = Token(TkCOLON)
788
792
  else
789
- @lex_state = EXPR_FNAME;
790
- tk = Token(TkSYMBEG)
793
+ @lex_state = EXPR_FNAME
794
+ tk = Token(TkSYMBEG)
791
795
  end
792
796
  tk.set_text(":")
793
797
  end
794
798
 
795
799
  @OP.def_rule("::") do
796
- # p @lex_state.id2name, @space_seen
797
800
  if @lex_state == EXPR_BEG or @lex_state == EXPR_ARG && @space_seen
798
- @lex_state = EXPR_BEG
799
- tk = Token(TkCOLON3)
801
+ @lex_state = EXPR_BEG
802
+ tk = Token(TkCOLON3)
800
803
  else
801
- @lex_state = EXPR_DOT
802
- tk = Token(TkCOLON2)
804
+ @lex_state = EXPR_DOT
805
+ tk = Token(TkCOLON2)
803
806
  end
804
807
  tk.set_text("::")
805
808
  end
@@ -807,15 +810,15 @@ class RubyLex
807
810
  @OP.def_rule("/") do
808
811
  |op, io|
809
812
  if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
810
- identify_string(op)
813
+ identify_string(op)
811
814
  elsif peek(0) == '='
812
- getc
813
- @lex_state = EXPR_BEG
814
- Token(TkOPASGN, :/).set_text("/=") #")
815
+ getc
816
+ @lex_state = EXPR_BEG
817
+ Token(TkOPASGN, :/).set_text("/=") #")
815
818
  elsif @lex_state == EXPR_ARG and @space_seen and peek(0) !~ /\s/
816
- identify_string(op)
819
+ identify_string(op)
817
820
  else
818
- @lex_state = EXPR_BEG
821
+ @lex_state = EXPR_BEG
819
822
  Token("/").set_text(op)
820
823
  end
821
824
  end
@@ -825,11 +828,6 @@ class RubyLex
825
828
  Token("^").set_text("^")
826
829
  end
827
830
 
828
- # @OP.def_rules("^=") do
829
- # @lex_state = EXPR_BEG
830
- # Token(TkOPASGN, :^)
831
- # end
832
-
833
831
  @OP.def_rules(",", ";") do
834
832
  |op, io|
835
833
  @lex_state = EXPR_BEG
@@ -849,11 +847,11 @@ class RubyLex
849
847
  @OP.def_rule("(") do
850
848
  @indent += 1
851
849
  if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
852
- @lex_state = EXPR_BEG
853
- tk = Token(TkfLPAREN)
850
+ @lex_state = EXPR_BEG
851
+ tk = Token(TkfLPAREN)
854
852
  else
855
- @lex_state = EXPR_BEG
856
- tk = Token(TkLPAREN)
853
+ @lex_state = EXPR_BEG
854
+ tk = Token(TkLPAREN)
857
855
  end
858
856
  tk.set_text("(")
859
857
  end
@@ -869,16 +867,16 @@ class RubyLex
869
867
  @OP.def_rule("[") do
870
868
  @indent += 1
871
869
  if @lex_state == EXPR_FNAME
872
- t = Token(TkfLBRACK)
870
+ t = Token(TkfLBRACK)
873
871
  else
874
- if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
875
- t = Token(TkLBRACK)
876
- elsif @lex_state == EXPR_ARG && @space_seen
877
- t = Token(TkLBRACK)
878
- else
879
- t = Token(TkfLBRACK)
880
- end
881
- @lex_state = EXPR_BEG
872
+ if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
873
+ t = Token(TkLBRACK)
874
+ elsif @lex_state == EXPR_ARG && @space_seen
875
+ t = Token(TkLBRACK)
876
+ else
877
+ t = Token(TkfLBRACK)
878
+ end
879
+ @lex_state = EXPR_BEG
882
880
  end
883
881
  t.set_text("[")
884
882
  end
@@ -886,9 +884,9 @@ class RubyLex
886
884
  @OP.def_rule("{") do
887
885
  @indent += 1
888
886
  if @lex_state != EXPR_END && @lex_state != EXPR_ARG
889
- t = Token(TkLBRACE)
887
+ t = Token(TkLBRACE)
890
888
  else
891
- t = Token(TkfLBRACE)
889
+ t = Token(TkfLBRACE)
892
890
  end
893
891
  @lex_state = EXPR_BEG
894
892
  t.set_text("{")
@@ -896,27 +894,27 @@ class RubyLex
896
894
 
897
895
  @OP.def_rule('\\') do #'
898
896
  if getc == "\n"
899
- @space_seen = true
900
- @continue = true
901
- Token(TkSPACE).set_text("\\\n")
897
+ @space_seen = true
898
+ @continue = true
899
+ Token(TkSPACE).set_text("\\\n")
902
900
  else
903
- ungetc
904
- Token("\\").set_text("\\") #"
901
+ ungetc
902
+ Token("\\").set_text("\\") #"
905
903
  end
906
904
  end
907
905
 
908
906
  @OP.def_rule('%') do
909
907
  |op, io|
910
908
  if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
911
- identify_quotation('%')
909
+ identify_quotation('%')
912
910
  elsif peek(0) == '='
913
- getc
914
- Token(TkOPASGN, "%").set_text("%=")
911
+ getc
912
+ Token(TkOPASGN, "%").set_text("%=")
915
913
  elsif @lex_state == EXPR_ARG and @space_seen and peek(0) !~ /\s/
916
- identify_quotation('%')
914
+ identify_quotation('%')
917
915
  else
918
- @lex_state = EXPR_BEG
919
- Token("%").set_text("%")
916
+ @lex_state = EXPR_BEG
917
+ Token("%").set_text("%")
920
918
  end
921
919
  end
922
920
 
@@ -926,40 +924,28 @@ class RubyLex
926
924
 
927
925
  @OP.def_rule('@') do
928
926
  if peek(0) =~ /[@\w_]/
929
- ungetc
930
- identify_identifier
927
+ ungetc
928
+ identify_identifier
931
929
  else
932
- Token("@").set_text("@")
930
+ Token("@").set_text("@")
933
931
  end
934
932
  end
935
933
 
936
- # @OP.def_rule("def", proc{|op, io| /\s/ =~ io.peek(0)}) do
937
- # |op, io|
938
- # @indent += 1
939
- # @lex_state = EXPR_FNAME
940
- # # @lex_state = EXPR_END
941
- # # until @rests[0] == "\n" or @rests[0] == ";"
942
- # # rests.shift
943
- # # end
944
- # end
945
-
946
934
  @OP.def_rule("__END__", proc{@prev_char_no == 0 && peek(0) =~ /[\r\n]/}) do
947
935
  throw :eof
948
936
  end
949
937
 
950
938
  @OP.def_rule("") do
951
939
  |op, io|
952
- printf "MATCH: start %s: %s\n", op, io.inspect if RubyLex.debug?
940
+ printf "MATCH: start %s: %s\n", op, io.inspect if RDoc::RubyLex.debug?
953
941
  if peek(0) =~ /[0-9]/
954
- t = identify_number("")
942
+ t = identify_number("")
955
943
  elsif peek(0) =~ /[\w_]/
956
- t = identify_identifier
944
+ t = identify_identifier
957
945
  end
958
- printf "MATCH: end %s: %s\n", op, io.inspect if RubyLex.debug?
946
+ printf "MATCH: end %s: %s\n", op, io.inspect if RDoc::RubyLex.debug?
959
947
  t
960
948
  end
961
-
962
- p @OP if RubyLex.debug?
963
949
  end
964
950
 
965
951
  def identify_gvar
@@ -1003,7 +989,7 @@ class RubyLex
1003
989
  token.concat getc if peek(0) == "@"
1004
990
 
1005
991
  while (ch = getc) =~ /\w|_/
1006
- print ":", ch, ":" if RubyLex.debug?
992
+ print ":", ch, ":" if RDoc::RubyLex.debug?
1007
993
  token.concat ch
1008
994
  end
1009
995
  ungetc
@@ -1024,38 +1010,38 @@ class RubyLex
1024
1010
  end
1025
1011
 
1026
1012
  if @lex_state != EXPR_DOT
1027
- print token, "\n" if RubyLex.debug?
1013
+ print token, "\n" if RDoc::RubyLex.debug?
1028
1014
 
1029
1015
  token_c, *trans = TkReading2Token[token]
1030
1016
  if token_c
1031
- # reserved word?
1032
-
1033
- if (@lex_state != EXPR_BEG &&
1034
- @lex_state != EXPR_FNAME &&
1035
- trans[1])
1036
- # modifiers
1037
- token_c = TkSymbol2Token[trans[1]]
1038
- @lex_state = trans[0]
1039
- else
1040
- if @lex_state != EXPR_FNAME
1041
- if ENINDENT_CLAUSE.include?(token)
1042
- @indent += 1
1043
- elsif DEINDENT_CLAUSE.include?(token)
1044
- @indent -= 1
1045
- end
1046
- @lex_state = trans[0]
1047
- else
1048
- @lex_state = EXPR_END
1049
- end
1050
- end
1051
- return Token(token_c, token).set_text(token)
1017
+ # reserved word?
1018
+
1019
+ if (@lex_state != EXPR_BEG &&
1020
+ @lex_state != EXPR_FNAME &&
1021
+ trans[1])
1022
+ # modifiers
1023
+ token_c = TkSymbol2Token[trans[1]]
1024
+ @lex_state = trans[0]
1025
+ else
1026
+ if @lex_state != EXPR_FNAME
1027
+ if ENINDENT_CLAUSE.include?(token)
1028
+ @indent += 1
1029
+ elsif DEINDENT_CLAUSE.include?(token)
1030
+ @indent -= 1
1031
+ end
1032
+ @lex_state = trans[0]
1033
+ else
1034
+ @lex_state = EXPR_END
1035
+ end
1036
+ end
1037
+ return Token(token_c, token).set_text(token)
1052
1038
  end
1053
1039
  end
1054
1040
 
1055
1041
  if @lex_state == EXPR_FNAME
1056
1042
  @lex_state = EXPR_END
1057
1043
  if peek(0) == '='
1058
- token.concat getc
1044
+ token.concat getc
1059
1045
  end
1060
1046
  elsif @lex_state == EXPR_BEG || @lex_state == EXPR_DOT
1061
1047
  @lex_state = EXPR_ARG
@@ -1082,13 +1068,13 @@ class RubyLex
1082
1068
  lt = ch
1083
1069
  quoted = ""
1084
1070
  while (c = getc) && c != lt
1085
- quoted.concat c
1071
+ quoted.concat c
1086
1072
  end
1087
1073
  else
1088
1074
  lt = '"'
1089
1075
  quoted = ch.dup
1090
1076
  while (c = getc) && c =~ /\w/
1091
- quoted.concat c
1077
+ quoted.concat c
1092
1078
  end
1093
1079
  ungetc
1094
1080
  end
@@ -1100,9 +1086,9 @@ class RubyLex
1100
1086
  reserve << ch
1101
1087
  if ch == "\\" #"
1102
1088
  ch = getc
1103
- reserve << ch
1089
+ reserve << ch
1104
1090
  elsif ch == "\n"
1105
- break
1091
+ break
1106
1092
  end
1107
1093
  end
1108
1094
 
@@ -1178,25 +1164,25 @@ class RubyLex
1178
1164
  str << ch
1179
1165
 
1180
1166
  when allow_point && "."
1181
- type = TkFLOAT
1182
- if peek(0) !~ /[0-9]/
1183
- ungetc
1184
- break
1185
- end
1167
+ type = TkFLOAT
1168
+ if peek(0) !~ /[0-9]/
1169
+ ungetc
1170
+ break
1171
+ end
1186
1172
  str << ch
1187
- allow_point = false
1173
+ allow_point = false
1188
1174
 
1189
1175
  when allow_e && "e", allow_e && "E"
1190
1176
  str << ch
1191
- type = TkFLOAT
1192
- if peek(0) =~ /[+-]/
1193
- str << getc
1194
- end
1195
- allow_e = false
1196
- allow_point = false
1177
+ type = TkFLOAT
1178
+ if peek(0) =~ /[+-]/
1179
+ str << getc
1180
+ end
1181
+ allow_e = false
1182
+ allow_point = false
1197
1183
  else
1198
- ungetc
1199
- break
1184
+ ungetc
1185
+ break
1200
1186
  end
1201
1187
  end
1202
1188
  Token(type).set_text(str)
@@ -1214,8 +1200,8 @@ class RubyLex
1214
1200
  nest = 0
1215
1201
  begin
1216
1202
  while ch = getc
1217
- str << ch
1218
- if @quoted == ch
1203
+ str << ch
1204
+ if @quoted == ch
1219
1205
  if nest == 0
1220
1206
  break
1221
1207
  else
@@ -1223,7 +1209,7 @@ class RubyLex
1223
1209
  end
1224
1210
  elsif opener == ch
1225
1211
  nest += 1
1226
- elsif @ltype != "'" && @ltype != "]" and ch == "#"
1212
+ elsif @ltype != "'" && @ltype != "]" and ch == "#"
1227
1213
  ch = getc
1228
1214
  if ch == "{"
1229
1215
  subtype = true
@@ -1231,19 +1217,19 @@ class RubyLex
1231
1217
  else
1232
1218
  ungetc(ch)
1233
1219
  end
1234
- elsif ch == '\\' #'
1235
- str << read_escape
1236
- end
1220
+ elsif ch == '\\' #'
1221
+ str << read_escape
1222
+ end
1237
1223
  end
1238
1224
  if @ltype == "/"
1239
- if peek(0) =~ /i|o|n|e|s/
1240
- str << getc
1241
- end
1225
+ if peek(0) =~ /i|o|n|e|s/
1226
+ str << getc
1227
+ end
1242
1228
  end
1243
1229
  if subtype
1244
- Token(DLtype2Token[ltype], str)
1230
+ Token(DLtype2Token[ltype], str)
1245
1231
  else
1246
- Token(Ltype2Token[ltype], str)
1232
+ Token(Ltype2Token[ltype], str)
1247
1233
  end.set_text(str)
1248
1234
  ensure
1249
1235
  @ltype = nil
@@ -1296,49 +1282,49 @@ class RubyLex
1296
1282
  when /[0-7]/
1297
1283
  ungetc ch
1298
1284
  3.times do
1299
- case ch = getc
1300
- when /[0-7]/
1301
- when nil
1302
- break
1303
- else
1304
- ungetc
1305
- break
1306
- end
1285
+ case ch = getc
1286
+ when /[0-7]/
1287
+ when nil
1288
+ break
1289
+ else
1290
+ ungetc
1291
+ break
1292
+ end
1307
1293
  res << ch
1308
1294
  end
1309
1295
 
1310
1296
  when "x"
1311
1297
  res << ch
1312
1298
  2.times do
1313
- case ch = getc
1314
- when /[0-9a-fA-F]/
1315
- when nil
1316
- break
1317
- else
1318
- ungetc
1319
- break
1320
- end
1299
+ case ch = getc
1300
+ when /[0-9a-fA-F]/
1301
+ when nil
1302
+ break
1303
+ else
1304
+ ungetc
1305
+ break
1306
+ end
1321
1307
  res << ch
1322
1308
  end
1323
1309
 
1324
1310
  when "M"
1325
1311
  res << ch
1326
1312
  if (ch = getc) != '-'
1327
- ungetc
1313
+ ungetc
1328
1314
  else
1329
1315
  res << ch
1330
- if (ch = getc) == "\\" #"
1316
+ if (ch = getc) == "\\" #"
1331
1317
  res << ch
1332
- res << read_escape
1318
+ res << read_escape
1333
1319
  else
1334
1320
  res << ch
1335
- end
1321
+ end
1336
1322
  end
1337
1323
 
1338
1324
  when "C", "c" #, "^"
1339
1325
  res << ch
1340
1326
  if ch == "C" and (ch = getc) != "-"
1341
- ungetc
1327
+ ungetc
1342
1328
  else
1343
1329
  res << ch
1344
1330
  if (ch = getc) == "\\" #"
@@ -1356,87 +1342,139 @@ class RubyLex
1356
1342
  end
1357
1343
 
1358
1344
  ##
1359
- # Extract code elements from a source file, returning a TopLevel object
1345
+ # Extracts code elements from a source file returning a TopLevel object
1360
1346
  # containing the constituent file elements.
1361
1347
  #
1362
1348
  # This file is based on rtags
1349
+ #
1350
+ # RubyParser understands how to document:
1351
+ # * classes
1352
+ # * modules
1353
+ # * methods
1354
+ # * constants
1355
+ # * aliases
1356
+ # * private, public, protected
1357
+ # * private_class_function, public_class_function
1358
+ # * module_function
1359
+ # * attr, attr_reader, attr_writer, attr_accessor
1360
+ # * extra accessors given on the command line
1361
+ # * metaprogrammed methods
1362
+ # * require
1363
+ # * include
1364
+ #
1365
+ # == Method Arguments
1366
+ #
1367
+ #--
1368
+ # NOTE: I don't think this works, needs tests, remove the paragraph following
1369
+ # this block when known to work
1370
+ #
1371
+ # The parser extracts the arguments from the method definition. You can
1372
+ # override this with a custom argument definition using the :args: directive:
1373
+ #
1374
+ # ##
1375
+ # # This method tries over and over until it is tired
1376
+ #
1377
+ # def go_go_go(thing_to_try, tries = 10) # :args: thing_to_try
1378
+ # puts thing_to_try
1379
+ # go_go_go thing_to_try, tries - 1
1380
+ # end
1381
+ #
1382
+ # If you have a more-complex set of overrides you can use the :call-seq:
1383
+ # directive:
1384
+ #++
1385
+ #
1386
+ # The parser extracts the arguments from the method definition. You can
1387
+ # override this with a custom argument definition using the :call-seq:
1388
+ # directive:
1389
+ #
1390
+ # ##
1391
+ # # This method can be called with a range or an offset and length
1392
+ # #
1393
+ # # :call-seq:
1394
+ # # my_method(Range)
1395
+ # # my_method(offset, length)
1396
+ #
1397
+ # def my_method(*args)
1398
+ # end
1399
+ #
1400
+ # The parser extracts +yield+ expressions from method bodies to gather the
1401
+ # yielded argument names. If your method manually calls a block instead of
1402
+ # yielding or you want to override the discovered argument names use
1403
+ # the :yields: directive:
1404
+ #
1405
+ # ##
1406
+ # # My method is awesome
1407
+ #
1408
+ # def my_method(&block) # :yields: happy, times
1409
+ # block.call 1, 2
1410
+ # end
1411
+ #
1412
+ # == Metaprogrammed Methods
1413
+ #
1414
+ # To pick up a metaprogrammed method, the parser looks for a comment starting
1415
+ # with '##' before an identifier:
1416
+ #
1417
+ # ##
1418
+ # # This is a meta-programmed method!
1419
+ #
1420
+ # add_my_method :meta_method, :arg1, :arg2
1421
+ #
1422
+ # The parser looks at the token after the identifier to determine the name, in
1423
+ # this example, :meta_method. If a name cannot be found, a warning is printed
1424
+ # and 'unknown is used.
1425
+ #
1426
+ # You can force the name of a method using the :method: directive:
1427
+ #
1428
+ # ##
1429
+ # # :method: woo_hoo!
1430
+ #
1431
+ # By default, meta-methods are instance methods. To indicate that a method is
1432
+ # a singleton method instead use the :singleton-method: directive:
1433
+ #
1434
+ # ##
1435
+ # # :singleton-method:
1436
+ #
1437
+ # You can also use the :singleton-method: directive with a name:
1438
+ #
1439
+ # ##
1440
+ # # :singleton-method: woo_hoo!
1441
+ #
1442
+ # == Hidden methods
1443
+ #
1444
+ # You can provide documentation for methods that don't appear using
1445
+ # the :method: and :singleton-method: directives:
1446
+ #
1447
+ # ##
1448
+ # # :method: ghost_method
1449
+ # # There is a method here, but you can't see it!
1450
+ #
1451
+ # ##
1452
+ # # this is a comment for a regular method
1453
+ #
1454
+ # def regular_method() end
1455
+ #
1456
+ # Note that by default, the :method: directive will be ignored if there is a
1457
+ # standard rdocable item following it.
1363
1458
 
1364
- class RDoc::RubyParser
1459
+ class RDoc::Parser::Ruby < RDoc::Parser
1365
1460
 
1366
- include RubyToken
1367
- include RDoc::TokenStream
1461
+ parse_files_matching(/\.rbw?$/)
1368
1462
 
1369
- extend RDoc::ParserFactory
1463
+ include RDoc::RubyToken
1464
+ include RDoc::TokenStream
1370
1465
 
1371
- parse_files_matching(/\.rbw?$/)
1466
+ NORMAL = "::"
1467
+ SINGLE = "<<"
1372
1468
 
1373
1469
  def initialize(top_level, file_name, content, options, stats)
1374
- @options = options
1375
- @stats = stats
1470
+ super
1471
+
1376
1472
  @size = 0
1377
1473
  @token_listeners = nil
1378
- @input_file_name = file_name
1379
- @scanner = RubyLex.new content, @options
1474
+ @scanner = RDoc::RubyLex.new content, @options
1380
1475
  @scanner.exception_on_syntax_error = false
1381
- @top_level = top_level
1382
- @progress = $stderr unless options.quiet
1383
- end
1384
-
1385
- def scan
1386
- @tokens = []
1387
- @unget_read = []
1388
- @read = []
1389
- catch(:eof) do
1390
- catch(:enddoc) do
1391
- begin
1392
- parse_toplevel_statements(@top_level)
1393
- rescue Exception => e
1394
- $stderr.puts "\n\n"
1395
- $stderr.puts "RDoc failure in #@input_file_name at or around " +
1396
- "line #{@scanner.line_no} column #{@scanner.char_no}"
1397
- $stderr.puts
1398
- $stderr.puts "Before reporting this, could you check that the file"
1399
- $stderr.puts "you're documenting compiles cleanly--RDoc is not a"
1400
- $stderr.puts "full Ruby parser, and gets confused easily if fed"
1401
- $stderr.puts "invalid programs."
1402
- $stderr.puts
1403
- $stderr.puts "The internal error was:\n\n"
1404
-
1405
- e.set_backtrace(e.backtrace[0,4])
1406
- raise
1407
- end
1408
- end
1409
- end
1410
- @top_level
1411
- end
1412
-
1413
- private
1414
-
1415
- def make_message(msg)
1416
- prefix = "\n" + @input_file_name + ":"
1417
- if @scanner
1418
- prefix << "#{@scanner.line_no}:#{@scanner.char_no}: "
1419
- end
1420
- return prefix + msg
1421
- end
1422
-
1423
- def warn(msg)
1424
- return if @options.quiet
1425
- msg = make_message msg
1426
- $stderr.puts msg
1427
- end
1428
1476
 
1429
- def error(msg)
1430
- msg = make_message msg
1431
- $stderr.puts msg
1432
- exit(1)
1433
- end
1434
-
1435
- def progress(char)
1436
- unless @options.quiet
1437
- @progress.print(char)
1438
- @progress.flush
1439
- end
1477
+ reset
1440
1478
  end
1441
1479
 
1442
1480
  def add_token_listener(obj)
@@ -1444,88 +1482,6 @@ class RDoc::RubyParser
1444
1482
  @token_listeners << obj
1445
1483
  end
1446
1484
 
1447
- def remove_token_listener(obj)
1448
- @token_listeners.delete(obj)
1449
- end
1450
-
1451
- def get_tk
1452
- tk = nil
1453
- if @tokens.empty?
1454
- tk = @scanner.token
1455
- @read.push @scanner.get_read
1456
- puts "get_tk1 => #{tk.inspect}" if $TOKEN_DEBUG
1457
- else
1458
- @read.push @unget_read.shift
1459
- tk = @tokens.shift
1460
- puts "get_tk2 => #{tk.inspect}" if $TOKEN_DEBUG
1461
- end
1462
-
1463
- if tk.kind_of?(TkSYMBEG)
1464
- set_token_position(tk.line_no, tk.char_no)
1465
- tk1 = get_tk
1466
- if tk1.kind_of?(TkId) || tk1.kind_of?(TkOp) || tk1.kind_of?(TkSTRING)
1467
- if tk1.respond_to?(:name)
1468
- tk = Token(TkSYMBOL).set_text(":" + tk1.name)
1469
- else
1470
- tk = Token(TkSYMBOL).set_text(":" + tk1.text)
1471
- end
1472
- # remove the identifier we just read (we're about to
1473
- # replace it with a symbol)
1474
- @token_listeners.each do |obj|
1475
- obj.pop_token
1476
- end if @token_listeners
1477
- else
1478
- warn("':' not followed by identifier or operator")
1479
- tk = tk1
1480
- end
1481
- end
1482
-
1483
- # inform any listeners of our shiny new token
1484
- @token_listeners.each do |obj|
1485
- obj.add_token(tk)
1486
- end if @token_listeners
1487
-
1488
- tk
1489
- end
1490
-
1491
- def peek_tk
1492
- unget_tk(tk = get_tk)
1493
- tk
1494
- end
1495
-
1496
- def unget_tk(tk)
1497
- @tokens.unshift tk
1498
- @unget_read.unshift @read.pop
1499
-
1500
- # Remove this token from any listeners
1501
- @token_listeners.each do |obj|
1502
- obj.pop_token
1503
- end if @token_listeners
1504
- end
1505
-
1506
- def skip_tkspace(skip_nl = true)
1507
- tokens = []
1508
- while ((tk = get_tk).kind_of?(TkSPACE) ||
1509
- (skip_nl && tk.kind_of?(TkNL)))
1510
- tokens.push tk
1511
- end
1512
- unget_tk(tk)
1513
- tokens
1514
- end
1515
-
1516
- def get_tkread
1517
- read = @read.join("")
1518
- @read = []
1519
- read
1520
- end
1521
-
1522
- def peek_read
1523
- @read.join('')
1524
- end
1525
-
1526
- NORMAL = "::"
1527
- SINGLE = "<<"
1528
-
1529
1485
  ##
1530
1486
  # Look for the first comment in a file that isn't a shebang line.
1531
1487
 
@@ -1535,249 +1491,67 @@ class RDoc::RubyParser
1535
1491
  first_line = true
1536
1492
 
1537
1493
  tk = get_tk
1538
- while tk.kind_of?(TkCOMMENT)
1539
- if first_line && tk.text[0,2] == "#!"
1494
+
1495
+ while TkCOMMENT === tk
1496
+ if first_line and tk.text =~ /\A#!/ then
1497
+ skip_tkspace
1498
+ tk = get_tk
1499
+ elsif first_line and tk.text =~ /\A#\s*-\*-/ then
1500
+ first_line = false
1540
1501
  skip_tkspace
1541
1502
  tk = get_tk
1542
1503
  else
1504
+ first_line = false
1543
1505
  res << tk.text << "\n"
1544
1506
  tk = get_tk
1545
- if tk.kind_of? TkNL
1546
- skip_tkspace(false)
1507
+
1508
+ if TkNL === tk then
1509
+ skip_tkspace false
1547
1510
  tk = get_tk
1548
1511
  end
1549
1512
  end
1550
- first_line = false
1551
1513
  end
1552
- unget_tk(tk)
1514
+
1515
+ unget_tk tk
1516
+
1553
1517
  res
1554
1518
  end
1555
1519
 
1556
- def parse_toplevel_statements(container)
1557
- comment = collect_first_comment
1558
- look_for_directives_in(container, comment)
1559
- container.comment = comment unless comment.empty?
1560
- parse_statements(container, NORMAL, nil, comment)
1520
+ def error(msg)
1521
+ msg = make_message msg
1522
+ $stderr.puts msg
1523
+ exit(1)
1561
1524
  end
1562
1525
 
1563
- def parse_statements(container, single=NORMAL, current_method=nil, comment='')
1564
- nest = 1
1565
- save_visibility = container.visibility
1566
-
1567
- # if container.kind_of?(TopLevel)
1568
- # else
1569
- # comment = ''
1570
- # end
1571
-
1572
- non_comment_seen = true
1526
+ ##
1527
+ # Look for a 'call-seq' in the comment, and override the normal parameter
1528
+ # stuff
1573
1529
 
1574
- while tk = get_tk
1575
- keep_comment = false
1530
+ def extract_call_seq(comment, meth)
1531
+ if comment.sub!(/:?call-seq:(.*?)^\s*\#?\s*$/m, '') then
1532
+ seq = $1
1533
+ seq.gsub!(/^\s*\#\s*/, '')
1534
+ meth.call_seq = seq
1535
+ end
1576
1536
 
1577
- non_comment_seen = true unless tk.kind_of?(TkCOMMENT)
1578
-
1579
- case tk
1580
- when TkNL
1581
- skip_tkspace(true) # Skip blanks and newlines
1582
- tk = get_tk
1583
- if tk.kind_of?(TkCOMMENT)
1584
- if non_comment_seen
1585
- comment = ''
1586
- non_comment_seen = false
1587
- end
1588
- while tk.kind_of?(TkCOMMENT)
1589
- comment << tk.text << "\n"
1590
- tk = get_tk # this is the newline
1591
- skip_tkspace(false) # leading spaces
1592
- tk = get_tk
1593
- end
1594
- unless comment.empty?
1595
- look_for_directives_in(container, comment)
1596
- if container.done_documenting
1597
- container.ongoing_visibility = save_visibility
1598
- # return
1599
- end
1600
- end
1601
- keep_comment = true
1602
- else
1603
- non_comment_seen = true
1604
- end
1605
- unget_tk(tk)
1606
- keep_comment = true
1607
-
1608
- when TkCLASS
1609
- if container.document_children
1610
- parse_class(container, single, tk, comment)
1611
- else
1612
- nest += 1
1613
- end
1614
-
1615
- when TkMODULE
1616
- if container.document_children
1617
- parse_module(container, single, tk, comment)
1618
- else
1619
- nest += 1
1620
- end
1621
-
1622
- when TkDEF
1623
- if container.document_self
1624
- parse_method(container, single, tk, comment)
1625
- else
1626
- nest += 1
1627
- end
1628
-
1629
- when TkCONSTANT
1630
- if container.document_self
1631
- parse_constant(container, single, tk, comment)
1632
- end
1633
-
1634
- when TkALIAS
1635
- if container.document_self
1636
- parse_alias(container, single, tk, comment)
1637
- end
1638
-
1639
- when TkYIELD
1640
- if current_method.nil?
1641
- warn("Warning: yield outside of method") if container.document_self
1642
- else
1643
- parse_yield(container, single, tk, current_method)
1644
- end
1645
-
1646
- # Until and While can have a 'do', which shouldn't increas
1647
- # the nesting. We can't solve the general case, but we can
1648
- # handle most occurrences by ignoring a do at the end of a line
1649
-
1650
- when TkUNTIL, TkWHILE
1651
- nest += 1
1652
- puts "Found #{tk.class} in #{container.name}, nest = #{nest}, " +
1653
- "line #{tk.line_no}" if $DEBUG_RDOC
1654
- skip_optional_do_after_expression
1655
-
1656
- # 'for' is trickier
1657
- when TkFOR
1658
- nest += 1
1659
- puts "Found #{tk.class} in #{container.name}, nest = #{nest}, " +
1660
- "line #{tk.line_no}" if $DEBUG_RDOC
1661
- skip_for_variable
1662
- skip_optional_do_after_expression
1663
-
1664
- when TkCASE, TkDO, TkIF, TkUNLESS, TkBEGIN
1665
- nest += 1
1666
- puts "Found #{tk.class} in #{container.name}, nest = #{nest}, " +
1667
- "line #{tk.line_no}" if $DEBUG_RDOC
1668
-
1669
- when TkIDENTIFIER
1670
- if nest == 1 and current_method.nil?
1671
- case tk.name
1672
- when "private", "protected", "public",
1673
- "private_class_method", "public_class_method"
1674
- parse_visibility(container, single, tk)
1675
- keep_comment = true
1676
- when "attr"
1677
- parse_attr(container, single, tk, comment)
1678
- when /^attr_(reader|writer|accessor)$/, @options.extra_accessors
1679
- parse_attr_accessor(container, single, tk, comment)
1680
- when "alias_method"
1681
- if container.document_self
1682
- parse_alias(container, single, tk, comment)
1683
- end
1684
- end
1685
- end
1686
-
1687
- case tk.name
1688
- when "require"
1689
- parse_require(container, comment)
1690
- when "include"
1691
- parse_include(container, comment)
1692
- end
1693
-
1694
-
1695
- when TkEND
1696
- nest -= 1
1697
- puts "Found 'end' in #{container.name}, nest = #{nest}, line #{tk.line_no}" if $DEBUG_RDOC
1698
- puts "Method = #{current_method.name}" if $DEBUG_RDOC and current_method
1699
- if nest == 0
1700
- read_documentation_modifiers container, RDoc::CLASS_MODIFIERS
1701
- container.ongoing_visibility = save_visibility
1702
- return
1703
- end
1704
-
1705
- end
1706
-
1707
- comment = '' unless keep_comment
1708
-
1709
- begin
1710
- get_tkread
1711
- skip_tkspace(false)
1712
- end while peek_tk == TkNL
1713
- end
1714
- end
1715
-
1716
- def parse_class(container, single, tk, comment, &block)
1717
- progress("c")
1718
-
1719
- @stats.num_classes += 1
1720
-
1721
- container, name_t = get_class_or_module(container)
1722
-
1723
- case name_t
1724
- when TkCONSTANT
1725
- name = name_t.name
1726
- superclass = "Object"
1727
-
1728
- if peek_tk.kind_of?(TkLT)
1729
- get_tk
1730
- skip_tkspace(true)
1731
- superclass = get_class_specification
1732
- superclass = "<unknown>" if superclass.empty?
1733
- end
1734
-
1735
- if single == SINGLE
1736
- cls_type = RDoc::SingleClass
1737
- else
1738
- cls_type = RDoc::NormalClass
1739
- end
1740
-
1741
- cls = container.add_class cls_type, name, superclass
1742
- read_documentation_modifiers cls, RDoc::CLASS_MODIFIERS
1743
- cls.record_location(@top_level)
1744
- parse_statements(cls)
1745
- cls.comment = comment
1746
-
1747
- when TkLSHFT
1748
- case name = get_class_specification
1749
- when "self", container.name
1750
- parse_statements(container, SINGLE, &block)
1751
- else
1752
- other = RDoc::TopLevel.find_class_named(name)
1753
- unless other
1754
- # other = @top_level.add_class(NormalClass, name, nil)
1755
- # other.record_location(@top_level)
1756
- # other.comment = comment
1757
- other = RDoc::NormalClass.new "Dummy", nil
1758
- end
1759
- read_documentation_modifiers other, RDoc::CLASS_MODIFIERS
1760
- parse_statements(other, SINGLE, &block)
1761
- end
1537
+ meth
1538
+ end
1762
1539
 
1540
+ def get_bool
1541
+ skip_tkspace
1542
+ tk = get_tk
1543
+ case tk
1544
+ when TkTRUE
1545
+ true
1546
+ when TkFALSE, TkNIL
1547
+ false
1763
1548
  else
1764
- warn("Expected class name or '<<'. Got #{name_t.class}: #{name_t.text.inspect}")
1549
+ unget_tk tk
1550
+ true
1765
1551
  end
1766
1552
  end
1767
1553
 
1768
- def parse_module(container, single, tk, comment)
1769
- progress("m")
1770
- @stats.num_modules += 1
1771
- container, name_t = get_class_or_module(container)
1772
- # skip_tkspace
1773
- name = name_t.name
1774
- mod = container.add_module RDoc::NormalModule, name
1775
- mod.record_location @top_level
1776
- read_documentation_modifiers mod, RDoc::CLASS_MODIFIERS
1777
- parse_statements(mod)
1778
- mod.comment = comment
1779
- end
1780
-
1554
+ ##
1781
1555
  # Look for the name of a class of module (optionally with a leading :: or
1782
1556
  # with :: separated named) and return the ultimate name and container
1783
1557
 
@@ -1786,14 +1560,14 @@ class RDoc::RubyParser
1786
1560
  name_t = get_tk
1787
1561
 
1788
1562
  # class ::A -> A is in the top level
1789
- if name_t.kind_of?(TkCOLON2)
1563
+ if TkCOLON2 === name_t then
1790
1564
  name_t = get_tk
1791
1565
  container = @top_level
1792
1566
  end
1793
1567
 
1794
1568
  skip_tkspace(false)
1795
1569
 
1796
- while peek_tk.kind_of?(TkCOLON2)
1570
+ while TkCOLON2 === peek_tk do
1797
1571
  prev_container = container
1798
1572
  container = container.find_module_named(name_t.name)
1799
1573
  if !container
@@ -1807,215 +1581,261 @@ class RDoc::RubyParser
1807
1581
  return [container, name_t]
1808
1582
  end
1809
1583
 
1810
- def parse_constant(container, single, tk, comment)
1811
- name = tk.name
1812
- skip_tkspace(false)
1813
- eq_tk = get_tk
1584
+ ##
1585
+ # Return a superclass, which can be either a constant of an expression
1814
1586
 
1815
- unless eq_tk.kind_of?(TkASSIGN)
1816
- unget_tk(eq_tk)
1817
- return
1587
+ def get_class_specification
1588
+ tk = get_tk
1589
+ return "self" if TkSELF === tk
1590
+
1591
+ res = ""
1592
+ while TkCOLON2 === tk or TkCOLON3 === tk or TkCONSTANT === tk do
1593
+ res += tk.text
1594
+ tk = get_tk
1818
1595
  end
1819
1596
 
1597
+ unget_tk(tk)
1598
+ skip_tkspace(false)
1820
1599
 
1821
- nest = 0
1822
- get_tkread
1600
+ get_tkread # empty out read buffer
1823
1601
 
1824
1602
  tk = get_tk
1825
- if tk.kind_of? TkGT
1826
- unget_tk(tk)
1827
- unget_tk(eq_tk)
1828
- return
1829
- end
1830
-
1831
- loop do
1832
- puts "Param: %p, %s %s %s" %
1833
- [tk.text, @scanner.continue, @scanner.lex_state, nest] if $DEBUG_RDOC
1834
1603
 
1835
- case tk
1836
- when TkSEMICOLON
1837
- break
1838
- when TkLPAREN, TkfLPAREN
1839
- nest += 1
1840
- when TkRPAREN
1841
- nest -= 1
1842
- when TkCOMMENT
1843
- if nest <= 0 && @scanner.lex_state == EXPR_END
1844
- unget_tk(tk)
1845
- break
1846
- end
1847
- when TkNL
1848
- if (@scanner.lex_state == EXPR_END and nest <= 0) || !@scanner.continue
1849
- unget_tk(tk)
1850
- break
1851
- end
1852
- end
1853
- tk = get_tk
1604
+ case tk
1605
+ when TkNL, TkCOMMENT, TkSEMICOLON then
1606
+ unget_tk(tk)
1607
+ return res
1854
1608
  end
1855
1609
 
1856
- res = get_tkread.tr("\n", " ").strip
1857
- res = "" if res == ";"
1858
-
1859
- con = RDoc::Constant.new name, res, comment
1860
- read_documentation_modifiers con, RDoc::CONSTANT_MODIFIERS
1861
-
1862
- if con.document_self
1863
- container.add_constant(con)
1864
- end
1610
+ res += parse_call_parameters(tk)
1611
+ res
1865
1612
  end
1866
1613
 
1867
- def parse_method(container, single, tk, comment)
1868
- progress(".")
1869
- @stats.num_methods += 1
1870
- line_no = tk.line_no
1871
- column = tk.char_no
1872
-
1873
- start_collecting_tokens
1874
- add_token(tk)
1875
- add_token_listener(self)
1614
+ ##
1615
+ # Parse a constant, which might be qualified by one or more class or module
1616
+ # names
1876
1617
 
1877
- @scanner.instance_eval{@lex_state = EXPR_FNAME}
1618
+ def get_constant
1619
+ res = ""
1878
1620
  skip_tkspace(false)
1879
- name_t = get_tk
1880
- back_tk = skip_tkspace
1881
- meth = nil
1882
- added_container = false
1621
+ tk = get_tk
1883
1622
 
1884
- dot = get_tk
1885
- if dot.kind_of?(TkDOT) or dot.kind_of?(TkCOLON2)
1886
- @scanner.instance_eval{@lex_state = EXPR_FNAME}
1887
- skip_tkspace
1888
- name_t2 = get_tk
1889
- case name_t
1890
- when TkSELF
1891
- name = name_t2.name
1892
- when TkCONSTANT
1893
- name = name_t2.name
1894
- prev_container = container
1895
- container = container.find_module_named(name_t.name)
1896
- if !container
1897
- added_container = true
1898
- obj = name_t.name.split("::").inject(Object) do |state, item|
1899
- state.const_get(item)
1900
- end rescue nil
1623
+ while TkCOLON2 === tk or TkCOLON3 === tk or TkCONSTANT === tk do
1624
+ res += tk.text
1625
+ tk = get_tk
1626
+ end
1901
1627
 
1902
- type = obj.class == Class ? RDoc::NormalClass : RDoc::NormalModule
1903
- if not [Class, Module].include?(obj.class)
1904
- warn("Couldn't find #{name_t.name}. Assuming it's a module")
1905
- end
1628
+ # if res.empty?
1629
+ # warn("Unexpected token #{tk} in constant")
1630
+ # end
1631
+ unget_tk(tk)
1632
+ res
1633
+ end
1906
1634
 
1907
- if type == RDoc::NormalClass then
1908
- container = prev_container.add_class(type, name_t.name, obj.superclass.name)
1909
- else
1910
- container = prev_container.add_module(type, name_t.name)
1911
- end
1912
- end
1913
- else
1914
- # warn("Unexpected token '#{name_t2.inspect}'")
1915
- # break
1916
- skip_method(container)
1917
- return
1918
- end
1919
- meth = RDoc::AnyMethod.new(get_tkread, name)
1920
- meth.singleton = true
1921
- else
1922
- unget_tk dot
1923
- back_tk.reverse_each do |token|
1924
- unget_tk token
1925
- end
1926
- name = name_t.name
1635
+ ##
1636
+ # Get a constant that may be surrounded by parens
1927
1637
 
1928
- meth = RDoc::AnyMethod.new get_tkread, name
1929
- meth.singleton = (single == SINGLE)
1638
+ def get_constant_with_optional_parens
1639
+ skip_tkspace(false)
1640
+ nest = 0
1641
+ while TkLPAREN === (tk = peek_tk) or TkfLPAREN === tk do
1642
+ get_tk
1643
+ skip_tkspace(true)
1644
+ nest += 1
1930
1645
  end
1931
1646
 
1932
- remove_token_listener(self)
1933
-
1934
- meth.start_collecting_tokens
1935
- indent = TkSPACE.new(1,1)
1936
- indent.set_text(" " * column)
1937
-
1938
- meth.add_tokens([TkCOMMENT.new(line_no,
1939
- 1,
1940
- "# File #{@top_level.file_absolute_name}, line #{line_no}"),
1941
- NEWLINE_TOKEN,
1942
- indent])
1647
+ name = get_constant
1943
1648
 
1944
- meth.add_tokens(@token_stream)
1945
-
1946
- add_token_listener(meth)
1947
-
1948
- @scanner.instance_eval{@continue = false}
1949
- parse_method_parameters(meth)
1649
+ while nest > 0
1650
+ skip_tkspace(true)
1651
+ tk = get_tk
1652
+ nest -= 1 if TkRPAREN === tk
1653
+ end
1654
+ name
1655
+ end
1950
1656
 
1951
- if meth.document_self
1952
- container.add_method(meth)
1953
- elsif added_container
1954
- container.document_self = false
1657
+ def get_symbol_or_name
1658
+ tk = get_tk
1659
+ case tk
1660
+ when TkSYMBOL
1661
+ tk.text.sub(/^:/, '')
1662
+ when TkId, TkOp
1663
+ tk.name
1664
+ when TkSTRING
1665
+ tk.text
1666
+ else
1667
+ raise "Name or symbol expected (got #{tk})"
1955
1668
  end
1669
+ end
1956
1670
 
1957
- # Having now read the method parameters and documentation modifiers, we
1958
- # now know whether we have to rename #initialize to ::new
1671
+ def get_tk
1672
+ tk = nil
1673
+ if @tokens.empty?
1674
+ tk = @scanner.token
1675
+ @read.push @scanner.get_read
1676
+ puts "get_tk1 => #{tk.inspect}" if $TOKEN_DEBUG
1677
+ else
1678
+ @read.push @unget_read.shift
1679
+ tk = @tokens.shift
1680
+ puts "get_tk2 => #{tk.inspect}" if $TOKEN_DEBUG
1681
+ end
1959
1682
 
1960
- if name == "initialize" && !meth.singleton
1961
- if meth.dont_rename_initialize
1962
- meth.visibility = :protected
1683
+ if TkSYMBEG === tk then
1684
+ set_token_position(tk.line_no, tk.char_no)
1685
+ tk1 = get_tk
1686
+ if TkId === tk1 or TkOp === tk1 or TkSTRING === tk1 then
1687
+ if tk1.respond_to?(:name)
1688
+ tk = Token(TkSYMBOL).set_text(":" + tk1.name)
1689
+ else
1690
+ tk = Token(TkSYMBOL).set_text(":" + tk1.text)
1691
+ end
1692
+ # remove the identifier we just read (we're about to
1693
+ # replace it with a symbol)
1694
+ @token_listeners.each do |obj|
1695
+ obj.pop_token
1696
+ end if @token_listeners
1963
1697
  else
1964
- meth.singleton = true
1965
- meth.name = "new"
1966
- meth.visibility = :public
1698
+ warn("':' not followed by identifier or operator")
1699
+ tk = tk1
1967
1700
  end
1968
1701
  end
1969
1702
 
1970
- parse_statements(container, single, meth)
1703
+ # inform any listeners of our shiny new token
1704
+ @token_listeners.each do |obj|
1705
+ obj.add_token(tk)
1706
+ end if @token_listeners
1971
1707
 
1972
- remove_token_listener(meth)
1708
+ tk
1709
+ end
1710
+
1711
+ def get_tkread
1712
+ read = @read.join("")
1713
+ @read = []
1714
+ read
1715
+ end
1716
+
1717
+ ##
1718
+ # Look for directives in a normal comment block:
1719
+ #
1720
+ # #-- - don't display comment from this point forward
1721
+ #
1722
+ # This routine modifies it's parameter
1973
1723
 
1974
- # Look for a 'call-seq' in the comment, and override the
1975
- # normal parameter stuff
1724
+ def look_for_directives_in(context, comment)
1725
+ preprocess = RDoc::Markup::PreProcess.new(@file_name,
1726
+ @options.rdoc_include)
1976
1727
 
1977
- if comment.sub!(/:?call-seq:(.*?)^\s*\#?\s*$/m, '')
1978
- seq = $1
1979
- seq.gsub!(/^\s*\#\s*/, '')
1980
- meth.call_seq = seq
1728
+ preprocess.handle(comment) do |directive, param|
1729
+ case directive
1730
+ when 'enddoc' then
1731
+ throw :enddoc
1732
+ when 'main' then
1733
+ @options.main_page = param
1734
+ ''
1735
+ when 'method', 'singleton-method' then
1736
+ false # ignore
1737
+ when 'section' then
1738
+ context.set_current_section(param, comment)
1739
+ comment.replace ''
1740
+ break
1741
+ when 'startdoc' then
1742
+ context.start_doc
1743
+ context.force_documentation = true
1744
+ ''
1745
+ when 'stopdoc' then
1746
+ context.stop_doc
1747
+ ''
1748
+ when 'title' then
1749
+ @options.title = param
1750
+ ''
1751
+ else
1752
+ warn "Unrecognized directive '#{directive}'"
1753
+ false
1754
+ end
1981
1755
  end
1982
1756
 
1983
- meth.comment = comment
1757
+ remove_private_comments(comment)
1984
1758
  end
1985
1759
 
1986
- def skip_method(container)
1987
- meth = RDoc::AnyMethod.new "", "anon"
1988
- parse_method_parameters(meth)
1989
- parse_statements(container, false, meth)
1760
+ def make_message(msg)
1761
+ prefix = "\n" + @file_name + ":"
1762
+ if @scanner
1763
+ prefix << "#{@scanner.line_no}:#{@scanner.char_no}: "
1764
+ end
1765
+ return prefix + msg
1990
1766
  end
1991
1767
 
1992
- # Capture the method's parameters. Along the way, look for a comment
1993
- # containing.
1994
- #
1995
- # # yields: ....
1996
- #
1997
- # and add this as the block_params for the method
1998
-
1999
- def parse_method_parameters(method)
2000
- res = parse_method_or_yield_parameters(method)
2001
- res = "(" + res + ")" unless res[0] == ?(
2002
- method.params = res unless method.params
2003
- if method.block_params.nil?
1768
+ def parse_attr(context, single, tk, comment)
1769
+ args = parse_symbol_arg(1)
1770
+ if args.size > 0
1771
+ name = args[0]
1772
+ rw = "R"
2004
1773
  skip_tkspace(false)
2005
- read_documentation_modifiers method, RDoc::METHOD_MODIFIERS
1774
+ tk = get_tk
1775
+ if TkCOMMA === tk then
1776
+ rw = "RW" if get_bool
1777
+ else
1778
+ unget_tk tk
1779
+ end
1780
+ att = RDoc::Attr.new get_tkread, name, rw, comment
1781
+ read_documentation_modifiers att, RDoc::ATTR_MODIFIERS
1782
+ if att.document_self
1783
+ context.add_attribute(att)
1784
+ end
1785
+ else
1786
+ warn("'attr' ignored - looks like a variable")
2006
1787
  end
2007
1788
  end
2008
1789
 
2009
- def parse_method_or_yield_parameters(method = nil,
2010
- modifiers = RDoc::METHOD_MODIFIERS)
2011
- skip_tkspace(false)
2012
- tk = get_tk
1790
+ def parse_attr_accessor(context, single, tk, comment)
1791
+ args = parse_symbol_arg
1792
+ read = get_tkread
1793
+ rw = "?"
2013
1794
 
2014
- # Little hack going on here. In the statement
2015
- # f = 2*(1+yield)
2016
- # We see the RPAREN as the next token, so we need
2017
- # to exit early. This still won't catch all cases
2018
- # (such as "a = yield + 1"
1795
+ # If nodoc is given, don't document any of them
1796
+
1797
+ tmp = RDoc::CodeObject.new
1798
+ read_documentation_modifiers tmp, RDoc::ATTR_MODIFIERS
1799
+ return unless tmp.document_self
1800
+
1801
+ case tk.name
1802
+ when "attr_reader" then rw = "R"
1803
+ when "attr_writer" then rw = "W"
1804
+ when "attr_accessor" then rw = "RW"
1805
+ else
1806
+ rw = @options.extra_accessor_flags[tk.name]
1807
+ rw = '?' if rw.nil?
1808
+ end
1809
+
1810
+ for name in args
1811
+ att = RDoc::Attr.new get_tkread, name, rw, comment
1812
+ context.add_attribute att
1813
+ end
1814
+ end
1815
+
1816
+ def parse_alias(context, single, tk, comment)
1817
+ skip_tkspace
1818
+ if TkLPAREN === peek_tk then
1819
+ get_tk
1820
+ skip_tkspace
1821
+ end
1822
+ new_name = get_symbol_or_name
1823
+ @scanner.instance_eval{@lex_state = EXPR_FNAME}
1824
+ skip_tkspace
1825
+ if TkCOMMA === peek_tk then
1826
+ get_tk
1827
+ skip_tkspace
1828
+ end
1829
+ old_name = get_symbol_or_name
1830
+
1831
+ al = RDoc::Alias.new get_tkread, old_name, new_name, comment
1832
+ read_documentation_modifiers al, RDoc::ATTR_MODIFIERS
1833
+ if al.document_self
1834
+ context.add_alias(al)
1835
+ end
1836
+ end
1837
+
1838
+ def parse_call_parameters(tk)
2019
1839
  end_token = case tk
2020
1840
  when TkLPAREN, TkfLPAREN
2021
1841
  TkRPAREN
@@ -2027,18 +1847,9 @@ class RDoc::RubyParser
2027
1847
  nest = 0
2028
1848
 
2029
1849
  loop do
2030
- puts "Param: %p, %s %s %s" %
2031
- [tk.text, @scanner.continue, @scanner.lex_state, nest] if $DEBUG_RDOC
2032
1850
  case tk
2033
1851
  when TkSEMICOLON
2034
1852
  break
2035
- when TkLBRACE
2036
- nest += 1
2037
- when TkRBRACE
2038
- # we might have a.each {|i| yield i }
2039
- unget_tk(tk) if nest.zero?
2040
- nest -= 1
2041
- break if nest <= 0
2042
1853
  when TkLPAREN, TkfLPAREN
2043
1854
  nest += 1
2044
1855
  when end_token
@@ -2048,346 +1859,449 @@ class RDoc::RubyParser
2048
1859
  else
2049
1860
  break unless @scanner.continue
2050
1861
  end
2051
- when method && method.block_params.nil? && TkCOMMENT
1862
+ when TkCOMMENT
2052
1863
  unget_tk(tk)
2053
- read_documentation_modifiers(method, modifiers)
1864
+ break
2054
1865
  end
2055
- tk = get_tk
1866
+ tk = get_tk
2056
1867
  end
2057
1868
  res = get_tkread.tr("\n", " ").strip
2058
1869
  res = "" if res == ";"
2059
1870
  res
2060
1871
  end
2061
1872
 
2062
- # skip the var [in] part of a 'for' statement
2063
- def skip_for_variable
2064
- skip_tkspace(false)
2065
- tk = get_tk
2066
- skip_tkspace(false)
2067
- tk = get_tk
2068
- unget_tk(tk) unless tk.kind_of?(TkIN)
2069
- end
2070
-
2071
- # while, until, and for have an optional
2072
- def skip_optional_do_after_expression
2073
- skip_tkspace(false)
2074
- tk = get_tk
2075
- case tk
2076
- when TkLPAREN, TkfLPAREN
2077
- end_token = TkRPAREN
2078
- else
2079
- end_token = TkNL
2080
- end
1873
+ def parse_class(container, single, tk, comment)
1874
+ container, name_t = get_class_or_module(container)
2081
1875
 
2082
- nest = 0
2083
- @scanner.instance_eval{@continue = false}
1876
+ case name_t
1877
+ when TkCONSTANT
1878
+ name = name_t.name
1879
+ superclass = "Object"
2084
1880
 
2085
- loop do
2086
- puts("\nWhile: #{tk.text.inspect}, #{@scanner.continue} " \
2087
- "#{@scanner.lex_state} #{nest}") if $DEBUG_RDOC
2088
- case tk
2089
- when TkSEMICOLON
2090
- break
2091
- when TkLPAREN, TkfLPAREN
2092
- nest += 1
2093
- when TkDO
2094
- break if nest.zero?
2095
- when end_token
2096
- if end_token == TkRPAREN
2097
- nest -= 1
2098
- break if @scanner.lex_state == EXPR_END and nest.zero?
2099
- else
2100
- break unless @scanner.continue
2101
- end
1881
+ if TkLT === peek_tk then
1882
+ get_tk
1883
+ skip_tkspace(true)
1884
+ superclass = get_class_specification
1885
+ superclass = "<unknown>" if superclass.empty?
2102
1886
  end
2103
- tk = get_tk
2104
- end
2105
- skip_tkspace(false)
2106
- if peek_tk.kind_of? TkDO
2107
- get_tk
2108
- end
2109
- end
2110
1887
 
2111
- # Return a superclass, which can be either a constant
2112
- # of an expression
1888
+ cls_type = single == SINGLE ? RDoc::SingleClass : RDoc::NormalClass
1889
+ cls = container.add_class cls_type, name, superclass
2113
1890
 
2114
- def get_class_specification
2115
- tk = get_tk
2116
- return "self" if tk.kind_of?(TkSELF)
1891
+ @stats.add_class cls
2117
1892
 
2118
- res = ""
2119
- while tk.kind_of?(TkCOLON2) ||
2120
- tk.kind_of?(TkCOLON3) ||
2121
- tk.kind_of?(TkCONSTANT)
1893
+ read_documentation_modifiers cls, RDoc::CLASS_MODIFIERS
1894
+ cls.record_location @top_level
2122
1895
 
2123
- res += tk.text
2124
- tk = get_tk
2125
- end
1896
+ parse_statements cls
1897
+ cls.comment = comment
2126
1898
 
2127
- unget_tk(tk)
2128
- skip_tkspace(false)
1899
+ when TkLSHFT
1900
+ case name = get_class_specification
1901
+ when "self", container.name
1902
+ parse_statements(container, SINGLE)
1903
+ else
1904
+ other = RDoc::TopLevel.find_class_named(name)
1905
+ unless other
1906
+ # other = @top_level.add_class(NormalClass, name, nil)
1907
+ # other.record_location(@top_level)
1908
+ # other.comment = comment
1909
+ other = RDoc::NormalClass.new "Dummy", nil
1910
+ end
2129
1911
 
2130
- get_tkread # empty out read buffer
1912
+ @stats.add_class other
2131
1913
 
2132
- tk = get_tk
1914
+ read_documentation_modifiers other, RDoc::CLASS_MODIFIERS
1915
+ parse_statements(other, SINGLE)
1916
+ end
2133
1917
 
2134
- case tk
2135
- when TkNL, TkCOMMENT, TkSEMICOLON
2136
- unget_tk(tk)
2137
- return res
1918
+ else
1919
+ warn("Expected class name or '<<'. Got #{name_t.class}: #{name_t.text.inspect}")
2138
1920
  end
2139
-
2140
- res += parse_call_parameters(tk)
2141
- res
2142
1921
  end
2143
1922
 
2144
- def parse_call_parameters(tk)
1923
+ def parse_constant(container, single, tk, comment)
1924
+ name = tk.name
1925
+ skip_tkspace(false)
1926
+ eq_tk = get_tk
1927
+
1928
+ unless TkASSIGN === eq_tk then
1929
+ unget_tk(eq_tk)
1930
+ return
1931
+ end
1932
+
2145
1933
 
2146
- end_token = case tk
2147
- when TkLPAREN, TkfLPAREN
2148
- TkRPAREN
2149
- when TkRPAREN
2150
- return ""
2151
- else
2152
- TkNL
2153
- end
2154
1934
  nest = 0
1935
+ get_tkread
1936
+
1937
+ tk = get_tk
1938
+ if TkGT === tk then
1939
+ unget_tk(tk)
1940
+ unget_tk(eq_tk)
1941
+ return
1942
+ end
2155
1943
 
2156
1944
  loop do
2157
- puts("Call param: #{tk}, #{@scanner.continue} " +
2158
- "#{@scanner.lex_state} #{nest}") if $DEBUG_RDOC
2159
1945
  case tk
2160
1946
  when TkSEMICOLON
2161
1947
  break
2162
1948
  when TkLPAREN, TkfLPAREN
2163
1949
  nest += 1
2164
- when end_token
2165
- if end_token == TkRPAREN
2166
- nest -= 1
2167
- break if @scanner.lex_state == EXPR_END and nest <= 0
2168
- else
2169
- break unless @scanner.continue
2170
- end
1950
+ when TkRPAREN
1951
+ nest -= 1
2171
1952
  when TkCOMMENT
2172
- unget_tk(tk)
2173
- break
1953
+ if nest <= 0 && @scanner.lex_state == EXPR_END
1954
+ unget_tk(tk)
1955
+ break
1956
+ end
1957
+ when TkNL
1958
+ if (@scanner.lex_state == EXPR_END and nest <= 0) || !@scanner.continue
1959
+ unget_tk(tk)
1960
+ break
1961
+ end
2174
1962
  end
2175
1963
  tk = get_tk
2176
1964
  end
1965
+
2177
1966
  res = get_tkread.tr("\n", " ").strip
2178
1967
  res = "" if res == ";"
2179
- res
2180
- end
2181
1968
 
2182
- # Parse a constant, which might be qualified by
2183
- # one or more class or module names
1969
+ con = RDoc::Constant.new name, res, comment
1970
+ read_documentation_modifiers con, RDoc::CONSTANT_MODIFIERS
2184
1971
 
2185
- def get_constant
2186
- res = ""
2187
- skip_tkspace(false)
2188
- tk = get_tk
1972
+ if con.document_self
1973
+ container.add_constant(con)
1974
+ end
1975
+ end
2189
1976
 
2190
- while tk.kind_of?(TkCOLON2) ||
2191
- tk.kind_of?(TkCOLON3) ||
2192
- tk.kind_of?(TkCONSTANT)
1977
+ def parse_comment(container, tk, comment)
1978
+ line_no = tk.line_no
1979
+ column = tk.char_no
2193
1980
 
2194
- res += tk.text
2195
- tk = get_tk
1981
+ singleton = !!comment.sub!(/(^# +:?)(singleton-)(method:)/, '\1\3')
1982
+
1983
+ if comment.sub!(/^# +:?method: *(\S*).*?\n/i, '') then
1984
+ name = $1 unless $1.empty?
1985
+ else
1986
+ return nil
2196
1987
  end
2197
1988
 
2198
- # if res.empty?
2199
- # warn("Unexpected token #{tk} in constant")
2200
- # end
2201
- unget_tk(tk)
2202
- res
2203
- end
1989
+ meth = RDoc::GhostMethod.new get_tkread, name
1990
+ meth.singleton = singleton
2204
1991
 
2205
- # Get a constant that may be surrounded by parens
1992
+ @stats.add_method meth
2206
1993
 
2207
- def get_constant_with_optional_parens
2208
- skip_tkspace(false)
2209
- nest = 0
2210
- while (tk = peek_tk).kind_of?(TkLPAREN) || tk.kind_of?(TkfLPAREN)
2211
- get_tk
2212
- skip_tkspace(true)
2213
- nest += 1
2214
- end
1994
+ meth.start_collecting_tokens
1995
+ indent = TkSPACE.new 1, 1
1996
+ indent.set_text " " * column
2215
1997
 
2216
- name = get_constant
1998
+ position_comment = TkCOMMENT.new(line_no, 1, "# File #{@top_level.file_absolute_name}, line #{line_no}")
1999
+ meth.add_tokens [position_comment, NEWLINE_TOKEN, indent]
2217
2000
 
2218
- while nest > 0
2219
- skip_tkspace(true)
2220
- tk = get_tk
2221
- nest -= 1 if tk.kind_of?(TkRPAREN)
2222
- end
2223
- name
2001
+ meth.params = ''
2002
+
2003
+ extract_call_seq comment, meth
2004
+
2005
+ container.add_method meth if meth.document_self
2006
+
2007
+ meth.comment = comment
2224
2008
  end
2225
2009
 
2226
- # Directives are modifier comments that can appear after class, module,
2227
- # or method names. For example:
2228
- #
2229
- # def fred # :yields: a, b
2230
- #
2231
- # or:
2232
- #
2233
- # class MyClass # :nodoc:
2234
- #
2235
- # We return the directive name and any parameters as a two element array
2010
+ def parse_include(context, comment)
2011
+ loop do
2012
+ skip_tkspace_comment
2236
2013
 
2237
- def read_directive(allowed)
2238
- tk = get_tk
2239
- puts "directive: #{tk.text.inspect}" if $DEBUG_RDOC
2240
- result = nil
2241
- if tk.kind_of?(TkCOMMENT)
2242
- if tk.text =~ /\s*:?(\w+):\s*(.*)/
2243
- directive = $1.downcase
2244
- if allowed.include?(directive)
2245
- result = [directive, $2]
2246
- end
2247
- end
2248
- else
2249
- unget_tk(tk)
2014
+ name = get_constant_with_optional_parens
2015
+ context.add_include RDoc::Include.new(name, comment) unless name.empty?
2016
+
2017
+ return unless TkCOMMA === peek_tk
2018
+ get_tk
2250
2019
  end
2251
- result
2252
2020
  end
2253
2021
 
2254
- def read_documentation_modifiers(context, allow)
2255
- dir = read_directive(allow)
2022
+ ##
2023
+ # Parses a meta-programmed method
2256
2024
 
2257
- case dir[0]
2025
+ def parse_meta_method(container, single, tk, comment)
2026
+ line_no = tk.line_no
2027
+ column = tk.char_no
2258
2028
 
2259
- when "notnew", "not_new", "not-new"
2260
- context.dont_rename_initialize = true
2029
+ start_collecting_tokens
2030
+ add_token tk
2031
+ add_token_listener self
2261
2032
 
2262
- when "nodoc"
2263
- context.document_self = false
2264
- if dir[1].downcase == "all"
2265
- context.document_children = false
2266
- end
2033
+ skip_tkspace false
2267
2034
 
2268
- when "doc"
2269
- context.document_self = true
2270
- context.force_documentation = true
2035
+ singleton = !!comment.sub!(/(^# +:?)(singleton-)(method:)/, '\1\3')
2271
2036
 
2272
- when "yield", "yields"
2273
- unless context.params.nil?
2274
- context.params.sub!(/(,|)\s*&\w+/,'') # remove parameter &proc
2037
+ if comment.sub!(/^# +:?method: *(\S*).*?\n/i, '') then
2038
+ name = $1 unless $1.empty?
2039
+ end
2040
+
2041
+ if name.nil? then
2042
+ name_t = get_tk
2043
+ case name_t
2044
+ when TkSYMBOL then
2045
+ name = name_t.text[1..-1]
2046
+ when TkSTRING then
2047
+ name = name_t.text[1..-2]
2048
+ else
2049
+ warn "#{container.top_level.file_relative_name}:#{name_t.line_no} unknown name token #{name_t.inspect} for meta-method"
2050
+ name = 'unknown'
2275
2051
  end
2276
- context.block_params = dir[1]
2052
+ end
2277
2053
 
2278
- when "arg", "args"
2279
- context.params = dir[1]
2280
- end if dir
2281
- end
2054
+ meth = RDoc::MetaMethod.new get_tkread, name
2055
+ meth.singleton = singleton
2282
2056
 
2283
- ##
2284
- # Look for directives in a normal comment block:
2285
- #
2286
- # #-- - don't display comment from this point forward
2287
- #
2288
- # This routine modifies it's parameter
2057
+ @stats.add_method meth
2289
2058
 
2290
- def look_for_directives_in(context, comment)
2291
- preprocess = RDoc::Markup::PreProcess.new(@input_file_name,
2292
- @options.rdoc_include)
2059
+ remove_token_listener self
2293
2060
 
2294
- preprocess.handle(comment) do |directive, param|
2295
- case directive
2296
- when "stopdoc"
2297
- context.stop_doc
2298
- ""
2299
- when "startdoc"
2300
- context.start_doc
2301
- context.force_documentation = true
2302
- ""
2061
+ meth.start_collecting_tokens
2062
+ indent = TkSPACE.new 1, 1
2063
+ indent.set_text " " * column
2303
2064
 
2304
- when "enddoc"
2305
- #context.done_documenting = true
2306
- #""
2307
- throw :enddoc
2065
+ position_comment = TkCOMMENT.new(line_no, 1, "# File #{@top_level.file_absolute_name}, line #{line_no}")
2066
+ meth.add_tokens [position_comment, NEWLINE_TOKEN, indent]
2067
+ meth.add_tokens @token_stream
2308
2068
 
2309
- when "main"
2310
- @options.main_page = param
2311
- ""
2069
+ add_token_listener meth
2312
2070
 
2313
- when "title"
2314
- @options.title = param
2315
- ""
2071
+ meth.params = ''
2316
2072
 
2317
- when "section"
2318
- context.set_current_section(param, comment)
2319
- comment.replace ''
2320
- break
2073
+ extract_call_seq comment, meth
2321
2074
 
2322
- else
2323
- warn "Unrecognized directive '#{directive}'"
2075
+ container.add_method meth if meth.document_self
2076
+
2077
+ last_tk = tk
2078
+
2079
+ while tk = get_tk do
2080
+ case tk
2081
+ when TkSEMICOLON then
2324
2082
  break
2083
+ when TkNL then
2084
+ break unless last_tk and TkCOMMA === last_tk
2085
+ when TkSPACE then
2086
+ # expression continues
2087
+ else
2088
+ last_tk = tk
2325
2089
  end
2326
2090
  end
2327
2091
 
2328
- remove_private_comments(comment)
2329
- end
2092
+ remove_token_listener meth
2330
2093
 
2331
- def remove_private_comments(comment)
2332
- comment.gsub!(/^#--.*?^#\+\+/m, '')
2333
- comment.sub!(/^#--.*/m, '')
2094
+ meth.comment = comment
2334
2095
  end
2335
2096
 
2336
- def get_symbol_or_name
2337
- tk = get_tk
2338
- case tk
2339
- when TkSYMBOL
2340
- tk.text.sub(/^:/, '')
2341
- when TkId, TkOp
2342
- tk.name
2343
- when TkSTRING
2344
- tk.text
2345
- else
2346
- raise "Name or symbol expected (got #{tk})"
2347
- end
2348
- end
2097
+ ##
2098
+ # Parses a method
2349
2099
 
2350
- def parse_alias(context, single, tk, comment)
2351
- skip_tkspace
2352
- if (peek_tk.kind_of? TkLPAREN)
2353
- get_tk
2354
- skip_tkspace
2355
- end
2356
- new_name = get_symbol_or_name
2357
- @scanner.instance_eval{@lex_state = EXPR_FNAME}
2358
- skip_tkspace
2359
- if (peek_tk.kind_of? TkCOMMA)
2360
- get_tk
2361
- skip_tkspace
2362
- end
2363
- old_name = get_symbol_or_name
2100
+ def parse_method(container, single, tk, comment)
2101
+ line_no = tk.line_no
2102
+ column = tk.char_no
2364
2103
 
2365
- al = RDoc::Alias.new get_tkread, old_name, new_name, comment
2366
- read_documentation_modifiers al, RDoc::ATTR_MODIFIERS
2367
- if al.document_self
2368
- context.add_alias(al)
2369
- end
2370
- end
2104
+ start_collecting_tokens
2105
+ add_token(tk)
2106
+ add_token_listener(self)
2371
2107
 
2372
- def parse_yield_parameters
2373
- parse_method_or_yield_parameters
2374
- end
2108
+ @scanner.instance_eval do @lex_state = EXPR_FNAME end
2375
2109
 
2376
- def parse_yield(context, single, tk, method)
2377
- if method.block_params.nil?
2378
- get_tkread
2379
- @scanner.instance_eval{@continue = false}
2380
- method.block_params = parse_yield_parameters
2381
- end
2382
- end
2110
+ skip_tkspace(false)
2111
+ name_t = get_tk
2112
+ back_tk = skip_tkspace
2113
+ meth = nil
2114
+ added_container = false
2383
2115
 
2384
- def parse_require(context, comment)
2385
- skip_tkspace_comment
2386
- tk = get_tk
2387
- if tk.kind_of? TkLPAREN
2388
- skip_tkspace_comment
2389
- tk = get_tk
2390
- end
2116
+ dot = get_tk
2117
+ if TkDOT === dot or TkCOLON2 === dot then
2118
+ @scanner.instance_eval do @lex_state = EXPR_FNAME end
2119
+ skip_tkspace
2120
+ name_t2 = get_tk
2121
+
2122
+ case name_t
2123
+ when TkSELF then
2124
+ name = name_t2.name
2125
+ when TkCONSTANT then
2126
+ name = name_t2.name
2127
+ prev_container = container
2128
+ container = container.find_module_named(name_t.name)
2129
+ unless container then
2130
+ added_container = true
2131
+ obj = name_t.name.split("::").inject(Object) do |state, item|
2132
+ state.const_get(item)
2133
+ end rescue nil
2134
+
2135
+ type = obj.class == Class ? RDoc::NormalClass : RDoc::NormalModule
2136
+
2137
+ unless [Class, Module].include?(obj.class) then
2138
+ warn("Couldn't find #{name_t.name}. Assuming it's a module")
2139
+ end
2140
+
2141
+ if type == RDoc::NormalClass then
2142
+ container = prev_container.add_class(type, name_t.name, obj.superclass.name)
2143
+ else
2144
+ container = prev_container.add_module(type, name_t.name)
2145
+ end
2146
+
2147
+ container.record_location @top_level
2148
+ end
2149
+ else
2150
+ # warn("Unexpected token '#{name_t2.inspect}'")
2151
+ # break
2152
+ skip_method(container)
2153
+ return
2154
+ end
2155
+
2156
+ meth = RDoc::AnyMethod.new(get_tkread, name)
2157
+ meth.singleton = true
2158
+ else
2159
+ unget_tk dot
2160
+ back_tk.reverse_each do |token|
2161
+ unget_tk token
2162
+ end
2163
+ name = name_t.name
2164
+
2165
+ meth = RDoc::AnyMethod.new get_tkread, name
2166
+ meth.singleton = (single == SINGLE)
2167
+ end
2168
+
2169
+ @stats.add_method meth
2170
+
2171
+ remove_token_listener self
2172
+
2173
+ meth.start_collecting_tokens
2174
+ indent = TkSPACE.new 1, 1
2175
+ indent.set_text " " * column
2176
+
2177
+ token = TkCOMMENT.new(line_no, 1, "# File #{@top_level.file_absolute_name}, line #{line_no}")
2178
+ meth.add_tokens [token, NEWLINE_TOKEN, indent]
2179
+ meth.add_tokens @token_stream
2180
+
2181
+ add_token_listener meth
2182
+
2183
+ @scanner.instance_eval do @continue = false end
2184
+ parse_method_parameters meth
2185
+
2186
+ if meth.document_self then
2187
+ container.add_method meth
2188
+ elsif added_container then
2189
+ container.document_self = false
2190
+ end
2191
+
2192
+ # Having now read the method parameters and documentation modifiers, we
2193
+ # now know whether we have to rename #initialize to ::new
2194
+
2195
+ if name == "initialize" && !meth.singleton then
2196
+ if meth.dont_rename_initialize then
2197
+ meth.visibility = :protected
2198
+ else
2199
+ meth.singleton = true
2200
+ meth.name = "new"
2201
+ meth.visibility = :public
2202
+ end
2203
+ end
2204
+
2205
+ parse_statements(container, single, meth)
2206
+
2207
+ remove_token_listener(meth)
2208
+
2209
+ extract_call_seq comment, meth
2210
+
2211
+ meth.comment = comment
2212
+ end
2213
+
2214
+ def parse_method_or_yield_parameters(method = nil,
2215
+ modifiers = RDoc::METHOD_MODIFIERS)
2216
+ skip_tkspace(false)
2217
+ tk = get_tk
2218
+
2219
+ # Little hack going on here. In the statement
2220
+ # f = 2*(1+yield)
2221
+ # We see the RPAREN as the next token, so we need
2222
+ # to exit early. This still won't catch all cases
2223
+ # (such as "a = yield + 1"
2224
+ end_token = case tk
2225
+ when TkLPAREN, TkfLPAREN
2226
+ TkRPAREN
2227
+ when TkRPAREN
2228
+ return ""
2229
+ else
2230
+ TkNL
2231
+ end
2232
+ nest = 0
2233
+
2234
+ loop do
2235
+ case tk
2236
+ when TkSEMICOLON
2237
+ break
2238
+ when TkLBRACE
2239
+ nest += 1
2240
+ when TkRBRACE
2241
+ # we might have a.each {|i| yield i }
2242
+ unget_tk(tk) if nest.zero?
2243
+ nest -= 1
2244
+ break if nest <= 0
2245
+ when TkLPAREN, TkfLPAREN
2246
+ nest += 1
2247
+ when end_token
2248
+ if end_token == TkRPAREN
2249
+ nest -= 1
2250
+ break if @scanner.lex_state == EXPR_END and nest <= 0
2251
+ else
2252
+ break unless @scanner.continue
2253
+ end
2254
+ when method && method.block_params.nil? && TkCOMMENT
2255
+ unget_tk(tk)
2256
+ read_documentation_modifiers(method, modifiers)
2257
+ end
2258
+ tk = get_tk
2259
+ end
2260
+ res = get_tkread.tr("\n", " ").strip
2261
+ res = "" if res == ";"
2262
+ res
2263
+ end
2264
+
2265
+ ##
2266
+ # Capture the method's parameters. Along the way, look for a comment
2267
+ # containing:
2268
+ #
2269
+ # # yields: ....
2270
+ #
2271
+ # and add this as the block_params for the method
2272
+
2273
+ def parse_method_parameters(method)
2274
+ res = parse_method_or_yield_parameters(method)
2275
+ res = "(" + res + ")" unless res[0] == ?(
2276
+ method.params = res unless method.params
2277
+ if method.block_params.nil?
2278
+ skip_tkspace(false)
2279
+ read_documentation_modifiers method, RDoc::METHOD_MODIFIERS
2280
+ end
2281
+ end
2282
+
2283
+ def parse_module(container, single, tk, comment)
2284
+ container, name_t = get_class_or_module(container)
2285
+
2286
+ name = name_t.name
2287
+
2288
+ mod = container.add_module RDoc::NormalModule, name
2289
+ mod.record_location @top_level
2290
+
2291
+ @stats.add_module mod
2292
+
2293
+ read_documentation_modifiers mod, RDoc::CLASS_MODIFIERS
2294
+ parse_statements(mod)
2295
+ mod.comment = comment
2296
+ end
2297
+
2298
+ def parse_require(context, comment)
2299
+ skip_tkspace_comment
2300
+ tk = get_tk
2301
+ if TkLPAREN === tk then
2302
+ skip_tkspace_comment
2303
+ tk = get_tk
2304
+ end
2391
2305
 
2392
2306
  name = nil
2393
2307
  case tk
@@ -2401,121 +2315,161 @@ class RDoc::RubyParser
2401
2315
  # warn "'require' used as variable"
2402
2316
  end
2403
2317
  if name
2404
- context.add_require(RDoc::Require.new(name, comment))
2318
+ context.add_require RDoc::Require.new(name, comment)
2405
2319
  else
2406
2320
  unget_tk(tk)
2407
2321
  end
2408
2322
  end
2409
2323
 
2410
- def parse_include(context, comment)
2411
- loop do
2412
- skip_tkspace_comment
2413
- name = get_constant_with_optional_parens
2414
- unless name.empty?
2415
- context.add_include RDoc::Include.new(name, comment)
2416
- end
2417
- return unless peek_tk.kind_of?(TkCOMMA)
2418
- get_tk
2419
- end
2420
- end
2324
+ def parse_statements(container, single = NORMAL, current_method = nil,
2325
+ comment = '')
2326
+ nest = 1
2327
+ save_visibility = container.visibility
2421
2328
 
2422
- def get_bool
2423
- skip_tkspace
2424
- tk = get_tk
2425
- case tk
2426
- when TkTRUE
2427
- true
2428
- when TkFALSE, TkNIL
2429
- false
2430
- else
2431
- unget_tk tk
2432
- true
2433
- end
2434
- end
2329
+ non_comment_seen = true
2435
2330
 
2436
- def parse_attr(context, single, tk, comment)
2437
- args = parse_symbol_arg(1)
2438
- if args.size > 0
2439
- name = args[0]
2440
- rw = "R"
2441
- skip_tkspace(false)
2442
- tk = get_tk
2443
- if tk.kind_of? TkCOMMA
2444
- rw = "RW" if get_bool
2445
- else
2446
- unget_tk tk
2447
- end
2448
- att = RDoc::Attr.new get_tkread, name, rw, comment
2449
- read_documentation_modifiers att, RDoc::ATTR_MODIFIERS
2450
- if att.document_self
2451
- context.add_attribute(att)
2452
- end
2453
- else
2454
- warn("'attr' ignored - looks like a variable")
2455
- end
2456
- end
2331
+ while tk = get_tk do
2332
+ keep_comment = false
2457
2333
 
2458
- def parse_visibility(container, single, tk)
2459
- singleton = (single == SINGLE)
2460
- vis = case tk.name
2461
- when "private" then :private
2462
- when "protected" then :protected
2463
- when "public" then :public
2464
- when "private_class_method"
2465
- singleton = true
2466
- :private
2467
- when "public_class_method"
2468
- singleton = true
2469
- :public
2470
- else raise "Invalid visibility: #{tk.name}"
2334
+ non_comment_seen = true unless TkCOMMENT === tk
2335
+
2336
+ case tk
2337
+ when TkNL then
2338
+ skip_tkspace true # Skip blanks and newlines
2339
+ tk = get_tk
2340
+
2341
+ if TkCOMMENT === tk then
2342
+ if non_comment_seen then
2343
+ # Look for RDoc in a comment about to be thrown away
2344
+ parse_comment container, tk, comment unless comment.empty?
2345
+
2346
+ comment = ''
2347
+ non_comment_seen = false
2471
2348
  end
2472
2349
 
2473
- skip_tkspace_comment(false)
2474
- case peek_tk
2475
- # Ryan Davis suggested the extension to ignore modifiers, because he
2476
- # often writes
2477
- #
2478
- # protected unless $TESTING
2479
- #
2480
- when TkNL, TkUNLESS_MOD, TkIF_MOD
2481
- # error("Missing argument") if singleton
2482
- container.ongoing_visibility = vis
2483
- else
2484
- args = parse_symbol_arg
2485
- container.set_visibility_for(args, vis, singleton)
2486
- end
2487
- end
2350
+ while TkCOMMENT === tk do
2351
+ comment << tk.text << "\n"
2352
+ tk = get_tk # this is the newline
2353
+ skip_tkspace(false) # leading spaces
2354
+ tk = get_tk
2355
+ end
2488
2356
 
2489
- def parse_attr_accessor(context, single, tk, comment)
2490
- args = parse_symbol_arg
2491
- read = get_tkread
2492
- rw = "?"
2357
+ unless comment.empty? then
2358
+ look_for_directives_in container, comment
2493
2359
 
2494
- # If nodoc is given, don't document any of them
2360
+ if container.done_documenting then
2361
+ container.ongoing_visibility = save_visibility
2362
+ end
2363
+ end
2495
2364
 
2496
- tmp = RDoc::CodeObject.new
2497
- read_documentation_modifiers tmp, RDoc::ATTR_MODIFIERS
2498
- return unless tmp.document_self
2365
+ keep_comment = true
2366
+ else
2367
+ non_comment_seen = true
2368
+ end
2499
2369
 
2500
- case tk.name
2501
- when "attr_reader" then rw = "R"
2502
- when "attr_writer" then rw = "W"
2503
- when "attr_accessor" then rw = "RW"
2504
- else
2505
- rw = @options.extra_accessor_flags[tk.name]
2506
- end
2370
+ unget_tk tk
2371
+ keep_comment = true
2372
+
2373
+ when TkCLASS then
2374
+ if container.document_children then
2375
+ parse_class container, single, tk, comment
2376
+ else
2377
+ nest += 1
2378
+ end
2379
+
2380
+ when TkMODULE then
2381
+ if container.document_children then
2382
+ parse_module container, single, tk, comment
2383
+ else
2384
+ nest += 1
2385
+ end
2386
+
2387
+ when TkDEF then
2388
+ if container.document_self then
2389
+ parse_method container, single, tk, comment
2390
+ else
2391
+ nest += 1
2392
+ end
2393
+
2394
+ when TkCONSTANT then
2395
+ if container.document_self then
2396
+ parse_constant container, single, tk, comment
2397
+ end
2398
+
2399
+ when TkALIAS then
2400
+ if container.document_self then
2401
+ parse_alias container, single, tk, comment
2402
+ end
2403
+
2404
+ when TkYIELD then
2405
+ if current_method.nil? then
2406
+ warn "Warning: yield outside of method" if container.document_self
2407
+ else
2408
+ parse_yield container, single, tk, current_method
2409
+ end
2410
+
2411
+ # Until and While can have a 'do', which shouldn't increase the nesting.
2412
+ # We can't solve the general case, but we can handle most occurrences by
2413
+ # ignoring a do at the end of a line.
2414
+
2415
+ when TkUNTIL, TkWHILE then
2416
+ nest += 1
2417
+ skip_optional_do_after_expression
2418
+
2419
+ # 'for' is trickier
2420
+ when TkFOR then
2421
+ nest += 1
2422
+ skip_for_variable
2423
+ skip_optional_do_after_expression
2424
+
2425
+ when TkCASE, TkDO, TkIF, TkUNLESS, TkBEGIN then
2426
+ nest += 1
2427
+
2428
+ when TkIDENTIFIER then
2429
+ if nest == 1 and current_method.nil? then
2430
+ case tk.name
2431
+ when 'private', 'protected', 'public', 'private_class_method',
2432
+ 'public_class_method', 'module_function' then
2433
+ parse_visibility container, single, tk
2434
+ keep_comment = true
2435
+ when 'attr' then
2436
+ parse_attr container, single, tk, comment
2437
+ when /^attr_(reader|writer|accessor)$/, @options.extra_accessors then
2438
+ parse_attr_accessor container, single, tk, comment
2439
+ when 'alias_method' then
2440
+ if container.document_self then
2441
+ parse_alias container, single, tk, comment
2442
+ end
2443
+ else
2444
+ if container.document_self and comment =~ /\A#\#$/ then
2445
+ parse_meta_method container, single, tk, comment
2446
+ end
2447
+ end
2448
+ end
2449
+
2450
+ case tk.name
2451
+ when "require" then
2452
+ parse_require container, comment
2453
+ when "include" then
2454
+ parse_include container, comment
2455
+ end
2456
+
2457
+ when TkEND then
2458
+ nest -= 1
2459
+ if nest == 0 then
2460
+ read_documentation_modifiers container, RDoc::CLASS_MODIFIERS
2461
+ container.ongoing_visibility = save_visibility
2462
+ return
2463
+ end
2507
2464
 
2508
- for name in args
2509
- att = RDoc::Attr.new get_tkread, name, rw, comment
2510
- context.add_attribute att
2511
- end
2512
- end
2465
+ end
2513
2466
 
2514
- def skip_tkspace_comment(skip_nl = true)
2515
- loop do
2516
- skip_tkspace(skip_nl)
2517
- return unless peek_tk.kind_of? TkCOMMENT
2518
- get_tk
2467
+ comment = '' unless keep_comment
2468
+
2469
+ begin
2470
+ get_tkread
2471
+ skip_tkspace(false)
2472
+ end while peek_tk == TkNL
2519
2473
  end
2520
2474
  end
2521
2475
 
@@ -2549,11 +2503,10 @@ class RDoc::RubyParser
2549
2503
  end
2550
2504
 
2551
2505
  loop do
2552
- # skip_tkspace_comment(false)
2553
2506
  skip_tkspace(false)
2554
2507
 
2555
2508
  tk1 = get_tk
2556
- unless tk1.kind_of?(TkCOMMA)
2509
+ unless TkCOMMA === tk1 then
2557
2510
  unget_tk tk1
2558
2511
  break
2559
2512
  end
@@ -2580,5 +2533,297 @@ class RDoc::RubyParser
2580
2533
  end
2581
2534
  end
2582
2535
 
2536
+ def parse_toplevel_statements(container)
2537
+ comment = collect_first_comment
2538
+ look_for_directives_in(container, comment)
2539
+ container.comment = comment unless comment.empty?
2540
+ parse_statements container, NORMAL, nil, comment
2541
+ end
2542
+
2543
+ def parse_visibility(container, single, tk)
2544
+ singleton = (single == SINGLE)
2545
+
2546
+ vis_type = tk.name
2547
+
2548
+ vis = case vis_type
2549
+ when 'private' then :private
2550
+ when 'protected' then :protected
2551
+ when 'public' then :public
2552
+ when 'private_class_method' then
2553
+ singleton = true
2554
+ :private
2555
+ when 'public_class_method' then
2556
+ singleton = true
2557
+ :public
2558
+ when 'module_function' then
2559
+ singleton = true
2560
+ :public
2561
+ else
2562
+ raise "Invalid visibility: #{tk.name}"
2563
+ end
2564
+
2565
+ skip_tkspace_comment false
2566
+
2567
+ case peek_tk
2568
+ # Ryan Davis suggested the extension to ignore modifiers, because he
2569
+ # often writes
2570
+ #
2571
+ # protected unless $TESTING
2572
+ #
2573
+ when TkNL, TkUNLESS_MOD, TkIF_MOD, TkSEMICOLON then
2574
+ container.ongoing_visibility = vis
2575
+ else
2576
+ if vis_type == 'module_function' then
2577
+ args = parse_symbol_arg
2578
+ container.set_visibility_for args, :private, false
2579
+
2580
+ module_functions = []
2581
+
2582
+ container.methods_matching args do |m|
2583
+ s_m = m.dup
2584
+ s_m.singleton = true if RDoc::AnyMethod === s_m
2585
+ s_m.visibility = :public
2586
+ module_functions << s_m
2587
+ end
2588
+
2589
+ module_functions.each do |s_m|
2590
+ case s_m
2591
+ when RDoc::AnyMethod then
2592
+ container.add_method s_m
2593
+ when RDoc::Attr then
2594
+ container.add_attribute s_m
2595
+ end
2596
+ end
2597
+ else
2598
+ args = parse_symbol_arg
2599
+ container.set_visibility_for args, vis, singleton
2600
+ end
2601
+ end
2602
+ end
2603
+
2604
+ def parse_yield_parameters
2605
+ parse_method_or_yield_parameters
2606
+ end
2607
+
2608
+ def parse_yield(context, single, tk, method)
2609
+ if method.block_params.nil?
2610
+ get_tkread
2611
+ @scanner.instance_eval{@continue = false}
2612
+ method.block_params = parse_yield_parameters
2613
+ end
2614
+ end
2615
+
2616
+ def peek_read
2617
+ @read.join('')
2618
+ end
2619
+
2620
+ ##
2621
+ # Peek at the next token, but don't remove it from the stream
2622
+
2623
+ def peek_tk
2624
+ unget_tk(tk = get_tk)
2625
+ tk
2626
+ end
2627
+
2628
+ ##
2629
+ # Directives are modifier comments that can appear after class, module, or
2630
+ # method names. For example:
2631
+ #
2632
+ # def fred # :yields: a, b
2633
+ #
2634
+ # or:
2635
+ #
2636
+ # class MyClass # :nodoc:
2637
+ #
2638
+ # We return the directive name and any parameters as a two element array
2639
+
2640
+ def read_directive(allowed)
2641
+ tk = get_tk
2642
+ result = nil
2643
+ if TkCOMMENT === tk
2644
+ if tk.text =~ /\s*:?(\w+):\s*(.*)/
2645
+ directive = $1.downcase
2646
+ if allowed.include?(directive)
2647
+ result = [directive, $2]
2648
+ end
2649
+ end
2650
+ else
2651
+ unget_tk(tk)
2652
+ end
2653
+ result
2654
+ end
2655
+
2656
+ def read_documentation_modifiers(context, allow)
2657
+ dir = read_directive(allow)
2658
+
2659
+ case dir[0]
2660
+ when "notnew", "not_new", "not-new" then
2661
+ context.dont_rename_initialize = true
2662
+
2663
+ when "nodoc" then
2664
+ context.document_self = false
2665
+ if dir[1].downcase == "all"
2666
+ context.document_children = false
2667
+ end
2668
+
2669
+ when "doc" then
2670
+ context.document_self = true
2671
+ context.force_documentation = true
2672
+
2673
+ when "yield", "yields" then
2674
+ unless context.params.nil?
2675
+ context.params.sub!(/(,|)\s*&\w+/,'') # remove parameter &proc
2676
+ end
2677
+
2678
+ context.block_params = dir[1]
2679
+
2680
+ when "arg", "args" then
2681
+ context.params = dir[1]
2682
+ end if dir
2683
+ end
2684
+
2685
+ def remove_private_comments(comment)
2686
+ comment.gsub!(/^#--.*?^#\+\+/m, '')
2687
+ comment.sub!(/^#--.*/m, '')
2688
+ end
2689
+
2690
+ def remove_token_listener(obj)
2691
+ @token_listeners.delete(obj)
2692
+ end
2693
+
2694
+ def reset
2695
+ @tokens = []
2696
+ @unget_read = []
2697
+ @read = []
2698
+ end
2699
+
2700
+ def scan
2701
+ reset
2702
+
2703
+ catch(:eof) do
2704
+ catch(:enddoc) do
2705
+ begin
2706
+ parse_toplevel_statements(@top_level)
2707
+ rescue Exception => e
2708
+ $stderr.puts <<-EOF
2709
+
2710
+
2711
+ RDoc failure in #{@file_name} at or around line #{@scanner.line_no} column
2712
+ #{@scanner.char_no}
2713
+
2714
+ Before reporting this, could you check that the file you're documenting
2715
+ compiles cleanly--RDoc is not a full Ruby parser, and gets confused easily if
2716
+ fed invalid programs.
2717
+
2718
+ The internal error was:
2719
+
2720
+ EOF
2721
+
2722
+ e.set_backtrace(e.backtrace[0,4])
2723
+ raise
2724
+ end
2725
+ end
2726
+ end
2727
+
2728
+ @top_level
2729
+ end
2730
+
2731
+ ##
2732
+ # while, until, and for have an optional do
2733
+
2734
+ def skip_optional_do_after_expression
2735
+ skip_tkspace(false)
2736
+ tk = get_tk
2737
+ case tk
2738
+ when TkLPAREN, TkfLPAREN
2739
+ end_token = TkRPAREN
2740
+ else
2741
+ end_token = TkNL
2742
+ end
2743
+
2744
+ nest = 0
2745
+ @scanner.instance_eval{@continue = false}
2746
+
2747
+ loop do
2748
+ case tk
2749
+ when TkSEMICOLON
2750
+ break
2751
+ when TkLPAREN, TkfLPAREN
2752
+ nest += 1
2753
+ when TkDO
2754
+ break if nest.zero?
2755
+ when end_token
2756
+ if end_token == TkRPAREN
2757
+ nest -= 1
2758
+ break if @scanner.lex_state == EXPR_END and nest.zero?
2759
+ else
2760
+ break unless @scanner.continue
2761
+ end
2762
+ end
2763
+ tk = get_tk
2764
+ end
2765
+ skip_tkspace(false)
2766
+
2767
+ get_tk if TkDO === peek_tk
2768
+ end
2769
+
2770
+ ##
2771
+ # skip the var [in] part of a 'for' statement
2772
+
2773
+ def skip_for_variable
2774
+ skip_tkspace(false)
2775
+ tk = get_tk
2776
+ skip_tkspace(false)
2777
+ tk = get_tk
2778
+ unget_tk(tk) unless TkIN === tk
2779
+ end
2780
+
2781
+ def skip_method(container)
2782
+ meth = RDoc::AnyMethod.new "", "anon"
2783
+ parse_method_parameters(meth)
2784
+ parse_statements(container, false, meth)
2785
+ end
2786
+
2787
+ ##
2788
+ # Skip spaces
2789
+
2790
+ def skip_tkspace(skip_nl = true)
2791
+ tokens = []
2792
+
2793
+ while TkSPACE === (tk = get_tk) or (skip_nl and TkNL === tk) do
2794
+ tokens.push tk
2795
+ end
2796
+
2797
+ unget_tk(tk)
2798
+ tokens
2799
+ end
2800
+
2801
+ ##
2802
+ # Skip spaces until a comment is found
2803
+
2804
+ def skip_tkspace_comment(skip_nl = true)
2805
+ loop do
2806
+ skip_tkspace(skip_nl)
2807
+ return unless TkCOMMENT === peek_tk
2808
+ get_tk
2809
+ end
2810
+ end
2811
+
2812
+ def unget_tk(tk)
2813
+ @tokens.unshift tk
2814
+ @unget_read.unshift @read.pop
2815
+
2816
+ # Remove this token from any listeners
2817
+ @token_listeners.each do |obj|
2818
+ obj.pop_token
2819
+ end if @token_listeners
2820
+ end
2821
+
2822
+ def warn(msg)
2823
+ return if @options.quiet
2824
+ msg = make_message msg
2825
+ $stderr.puts msg
2826
+ end
2827
+
2583
2828
  end
2584
2829