rdoc 2.4.3 → 2.5

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 (139) hide show
  1. data.tar.gz.sig +0 -0
  2. data/.autotest +3 -1
  3. data/History.txt +68 -0
  4. data/LICENSE.txt +57 -0
  5. data/Manifest.txt +37 -19
  6. data/README.txt +2 -12
  7. data/Rakefile +12 -12
  8. data/bin/rdoc +4 -4
  9. data/lib/rdoc.rb +32 -9
  10. data/lib/rdoc/alias.rb +2 -2
  11. data/lib/rdoc/any_method.rb +108 -16
  12. data/lib/rdoc/attr.rb +87 -1
  13. data/lib/rdoc/class_module.rb +131 -5
  14. data/lib/rdoc/code_object.rb +28 -5
  15. data/lib/rdoc/constant.rb +22 -0
  16. data/lib/rdoc/context.rb +80 -37
  17. data/lib/rdoc/gauntlet.rb +48 -0
  18. data/lib/rdoc/generator/darkfish.rb +25 -23
  19. data/lib/rdoc/generator/markup.rb +6 -29
  20. data/lib/rdoc/generator/ri.rb +39 -189
  21. data/lib/rdoc/generator/template/darkfish/classpage.rhtml +17 -1
  22. data/lib/rdoc/generator/template/darkfish/filepage.rhtml +10 -0
  23. data/lib/rdoc/generator/template/darkfish/images/brick.png +0 -0
  24. data/lib/rdoc/generator/template/darkfish/images/brick_link.png +0 -0
  25. data/lib/rdoc/generator/template/darkfish/images/bullet_black.png +0 -0
  26. data/lib/rdoc/generator/template/darkfish/images/bullet_toggle_minus.png +0 -0
  27. data/lib/rdoc/generator/template/darkfish/images/bullet_toggle_plus.png +0 -0
  28. data/lib/rdoc/generator/template/darkfish/images/date.png +0 -0
  29. data/lib/rdoc/generator/template/darkfish/images/find.png +0 -0
  30. data/lib/rdoc/generator/template/darkfish/images/package.png +0 -0
  31. data/lib/rdoc/generator/template/darkfish/images/page_green.png +0 -0
  32. data/lib/rdoc/generator/template/darkfish/images/page_white_text.png +0 -0
  33. data/lib/rdoc/generator/template/darkfish/images/page_white_width.png +0 -0
  34. data/lib/rdoc/generator/template/darkfish/images/plugin.png +0 -0
  35. data/lib/rdoc/generator/template/darkfish/images/ruby.png +0 -0
  36. data/lib/rdoc/generator/template/darkfish/images/tag_green.png +0 -0
  37. data/lib/rdoc/generator/template/darkfish/images/wrench.png +0 -0
  38. data/lib/rdoc/generator/template/darkfish/images/wrench_orange.png +0 -0
  39. data/lib/rdoc/generator/template/darkfish/images/zoom.png +0 -0
  40. data/lib/rdoc/generator/template/darkfish/index.rhtml +2 -2
  41. data/lib/rdoc/generator/template/darkfish/rdoc.css +38 -33
  42. data/lib/rdoc/include.rb +22 -0
  43. data/lib/rdoc/markup.rb +10 -262
  44. data/lib/rdoc/markup/attribute_manager.rb +57 -50
  45. data/lib/rdoc/markup/blank_line.rb +19 -0
  46. data/lib/rdoc/markup/document.rb +72 -0
  47. data/lib/rdoc/markup/formatter.rb +118 -0
  48. data/lib/rdoc/markup/formatter_test_case.rb +341 -0
  49. data/lib/rdoc/markup/heading.rb +17 -0
  50. data/lib/rdoc/markup/inline.rb +6 -5
  51. data/lib/rdoc/markup/list.rb +78 -0
  52. data/lib/rdoc/markup/list_item.rb +83 -0
  53. data/lib/rdoc/markup/paragraph.rb +66 -0
  54. data/lib/rdoc/markup/parser.rb +528 -0
  55. data/lib/rdoc/markup/rule.rb +17 -0
  56. data/lib/rdoc/markup/to_ansi.rb +72 -0
  57. data/lib/rdoc/markup/to_bs.rb +74 -0
  58. data/lib/rdoc/markup/to_html.rb +106 -172
  59. data/lib/rdoc/markup/to_html_crossref.rb +10 -4
  60. data/lib/rdoc/markup/to_rdoc.rb +243 -0
  61. data/lib/rdoc/markup/to_test.rb +27 -16
  62. data/lib/rdoc/markup/verbatim.rb +42 -0
  63. data/lib/rdoc/normal_class.rb +38 -1
  64. data/lib/rdoc/normal_module.rb +38 -8
  65. data/lib/rdoc/options.rb +39 -151
  66. data/lib/rdoc/parser.rb +36 -18
  67. data/lib/rdoc/parser/c.rb +102 -109
  68. data/lib/rdoc/parser/ruby.rb +359 -1662
  69. data/lib/rdoc/parser/ruby_tools.rb +157 -0
  70. data/lib/rdoc/parser/simple.rb +0 -2
  71. data/lib/rdoc/rdoc.rb +142 -82
  72. data/lib/rdoc/ri.rb +10 -0
  73. data/lib/rdoc/ri/driver.rb +674 -444
  74. data/lib/rdoc/ri/formatter.rb +2 -651
  75. data/lib/rdoc/ri/paths.rb +70 -45
  76. data/lib/rdoc/ri/store.rb +248 -0
  77. data/lib/rdoc/ruby_lex.rb +1284 -0
  78. data/lib/rdoc/ruby_token.rb +416 -0
  79. data/lib/rdoc/single_class.rb +5 -0
  80. data/lib/rdoc/stats.rb +152 -83
  81. data/lib/rdoc/task.rb +27 -49
  82. data/lib/rdoc/text.rb +130 -0
  83. data/lib/rdoc/tokenstream.rb +28 -9
  84. data/lib/rdoc/top_level.rb +49 -43
  85. data/test/hidden.zip.txt +1 -0
  86. data/test/test_attribute_manager.rb +9 -16
  87. data/test/test_rdoc_any_method.rb +23 -0
  88. data/test/test_rdoc_attr.rb +40 -0
  89. data/test/test_rdoc_class_module.rb +100 -0
  90. data/test/test_rdoc_code_object.rb +18 -2
  91. data/test/test_rdoc_context.rb +41 -0
  92. data/test/test_rdoc_generator_ri.rb +56 -0
  93. data/test/test_rdoc_markup.rb +21 -610
  94. data/test/test_rdoc_markup_attribute_manager.rb +14 -17
  95. data/test/test_rdoc_markup_document.rb +51 -0
  96. data/test/test_rdoc_markup_paragraph.rb +27 -0
  97. data/test/test_rdoc_markup_parser.rb +1327 -0
  98. data/test/test_rdoc_markup_to_ansi.rb +426 -0
  99. data/test/test_rdoc_markup_to_bs.rb +443 -0
  100. data/test/test_rdoc_markup_to_html.rb +183 -18
  101. data/test/test_rdoc_markup_to_html_crossref.rb +1 -3
  102. data/test/test_rdoc_markup_to_rdoc.rb +426 -0
  103. data/test/test_rdoc_normal_class.rb +17 -0
  104. data/test/test_rdoc_normal_module.rb +6 -6
  105. data/test/test_rdoc_options.rb +41 -0
  106. data/test/test_rdoc_parser.rb +66 -13
  107. data/test/test_rdoc_parser_c.rb +93 -38
  108. data/test/test_rdoc_parser_perl.rb +2 -3
  109. data/test/test_rdoc_parser_ruby.rb +291 -28
  110. data/test/test_rdoc_parser_simple.rb +48 -0
  111. data/test/test_rdoc_rdoc.rb +66 -0
  112. data/test/test_rdoc_ri_driver.rb +752 -38
  113. data/test/test_rdoc_ri_paths.rb +39 -0
  114. data/test/test_rdoc_ri_store.rb +309 -0
  115. data/test/test_rdoc_text.rb +157 -0
  116. data/test/test_rdoc_top_level.rb +35 -9
  117. data/test/xref_data.rb +9 -1
  118. data/test/xref_test_case.rb +8 -3
  119. metadata +110 -38
  120. metadata.gz.sig +0 -0
  121. data/lib/rdoc/cache.rb +0 -41
  122. data/lib/rdoc/diagram.rb +0 -340
  123. data/lib/rdoc/dot.rb +0 -249
  124. data/lib/rdoc/markup/fragments.rb +0 -377
  125. data/lib/rdoc/markup/lines.rb +0 -156
  126. data/lib/rdoc/markup/to_flow.rb +0 -211
  127. data/lib/rdoc/markup/to_latex.rb +0 -328
  128. data/lib/rdoc/markup/to_texinfo.rb +0 -73
  129. data/lib/rdoc/ri/cache.rb +0 -187
  130. data/lib/rdoc/ri/descriptions.rb +0 -156
  131. data/lib/rdoc/ri/display.rb +0 -340
  132. data/lib/rdoc/ri/reader.rb +0 -106
  133. data/lib/rdoc/ri/util.rb +0 -79
  134. data/lib/rdoc/ri/writer.rb +0 -68
  135. data/test/test_rdoc_ri_attribute_formatter.rb +0 -44
  136. data/test/test_rdoc_ri_default_display.rb +0 -302
  137. data/test/test_rdoc_ri_formatter.rb +0 -320
  138. data/test/test_rdoc_ri_html_formatter.rb +0 -141
  139. data/test/test_rdoc_ri_overstrike_formatter.rb +0 -71
@@ -7,1339 +7,16 @@
7
7
  # by Keiju ISHITSUKA (Nippon Rational Inc.)
8
8
  #
9
9
 
10
- require 'e2mmap'
11
- require 'irb/slex'
10
+ require 'rdoc/ruby_token'
11
+ require 'rdoc/ruby_lex'
12
12
 
13
13
  require 'rdoc/code_objects'
14
14
  require 'rdoc/tokenstream'
15
15
  require 'rdoc/markup/preprocess'
16
16
  require 'rdoc/parser'
17
+ require 'rdoc/parser/ruby_tools'
17
18
 
18
19
  $TOKEN_DEBUG ||= nil
19
- #$TOKEN_DEBUG = $DEBUG_RDOC
20
-
21
- ##
22
- # Definitions of all tokens involved in the lexical analysis
23
-
24
- module RDoc::RubyToken
25
-
26
- EXPR_BEG = :EXPR_BEG
27
- EXPR_MID = :EXPR_MID
28
- EXPR_END = :EXPR_END
29
- EXPR_ARG = :EXPR_ARG
30
- EXPR_FNAME = :EXPR_FNAME
31
- EXPR_DOT = :EXPR_DOT
32
- EXPR_CLASS = :EXPR_CLASS
33
-
34
- class Token
35
- NO_TEXT = "??".freeze
36
-
37
- attr_accessor :text
38
- attr_reader :line_no
39
- attr_reader :char_no
40
-
41
- def initialize(line_no, char_no)
42
- @line_no = line_no
43
- @char_no = char_no
44
- @text = NO_TEXT
45
- end
46
-
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
-
58
- def set_text(text)
59
- @text = text
60
- self
61
- end
62
-
63
- end
64
-
65
- class TkNode < Token
66
- attr :node
67
- end
68
-
69
- class TkId < Token
70
- def initialize(line_no, char_no, name)
71
- super(line_no, char_no)
72
- @name = name
73
- end
74
- attr :name
75
- end
76
-
77
- class TkKW < TkId
78
- end
79
-
80
- class TkVal < Token
81
- def initialize(line_no, char_no, value = nil)
82
- super(line_no, char_no)
83
- set_text(value)
84
- end
85
- end
86
-
87
- class TkOp < Token
88
- def name
89
- self.class.op_name
90
- end
91
- end
92
-
93
- class TkOPASGN < TkOp
94
- def initialize(line_no, char_no, op)
95
- super(line_no, char_no)
96
- op = TkReading2Token[op] unless Symbol === op
97
- @op = op
98
- end
99
- attr :op
100
- end
101
-
102
- class TkUnknownChar < Token
103
- def initialize(line_no, char_no, id)
104
- super(line_no, char_no)
105
- @name = char_no.chr
106
- end
107
- attr :name
108
- end
109
-
110
- class TkError < Token
111
- end
112
-
113
- def set_token_position(line, char)
114
- @prev_line_no = line
115
- @prev_char_no = char
116
- end
117
-
118
- def Token(token, value = nil)
119
- tk = nil
120
- case token
121
- when String, Symbol
122
- source = String === token ? TkReading2Token : TkSymbol2Token
123
- raise TkReading2TokenNoKey, token if (tk = source[token]).nil?
124
- tk = Token(tk[0], value)
125
- else
126
- tk = if (token.ancestors & [TkId, TkVal, TkOPASGN, TkUnknownChar]).empty?
127
- token.new(@prev_line_no, @prev_char_no)
128
- else
129
- token.new(@prev_line_no, @prev_char_no, value)
130
- end
131
- end
132
- tk
133
- end
134
-
135
- TokenDefinitions = [
136
- [:TkCLASS, TkKW, "class", EXPR_CLASS],
137
- [:TkMODULE, TkKW, "module", EXPR_CLASS],
138
- [:TkDEF, TkKW, "def", EXPR_FNAME],
139
- [:TkUNDEF, TkKW, "undef", EXPR_FNAME],
140
- [:TkBEGIN, TkKW, "begin", EXPR_BEG],
141
- [:TkRESCUE, TkKW, "rescue", EXPR_MID],
142
- [:TkENSURE, TkKW, "ensure", EXPR_BEG],
143
- [:TkEND, TkKW, "end", EXPR_END],
144
- [:TkIF, TkKW, "if", EXPR_BEG, :TkIF_MOD],
145
- [:TkUNLESS, TkKW, "unless", EXPR_BEG, :TkUNLESS_MOD],
146
- [:TkTHEN, TkKW, "then", EXPR_BEG],
147
- [:TkELSIF, TkKW, "elsif", EXPR_BEG],
148
- [:TkELSE, TkKW, "else", EXPR_BEG],
149
- [:TkCASE, TkKW, "case", EXPR_BEG],
150
- [:TkWHEN, TkKW, "when", EXPR_BEG],
151
- [:TkWHILE, TkKW, "while", EXPR_BEG, :TkWHILE_MOD],
152
- [:TkUNTIL, TkKW, "until", EXPR_BEG, :TkUNTIL_MOD],
153
- [:TkFOR, TkKW, "for", EXPR_BEG],
154
- [:TkBREAK, TkKW, "break", EXPR_END],
155
- [:TkNEXT, TkKW, "next", EXPR_END],
156
- [:TkREDO, TkKW, "redo", EXPR_END],
157
- [:TkRETRY, TkKW, "retry", EXPR_END],
158
- [:TkIN, TkKW, "in", EXPR_BEG],
159
- [:TkDO, TkKW, "do", EXPR_BEG],
160
- [:TkRETURN, TkKW, "return", EXPR_MID],
161
- [:TkYIELD, TkKW, "yield", EXPR_END],
162
- [:TkSUPER, TkKW, "super", EXPR_END],
163
- [:TkSELF, TkKW, "self", EXPR_END],
164
- [:TkNIL, TkKW, "nil", EXPR_END],
165
- [:TkTRUE, TkKW, "true", EXPR_END],
166
- [:TkFALSE, TkKW, "false", EXPR_END],
167
- [:TkAND, TkKW, "and", EXPR_BEG],
168
- [:TkOR, TkKW, "or", EXPR_BEG],
169
- [:TkNOT, TkKW, "not", EXPR_BEG],
170
- [:TkIF_MOD, TkKW],
171
- [:TkUNLESS_MOD, TkKW],
172
- [:TkWHILE_MOD, TkKW],
173
- [:TkUNTIL_MOD, TkKW],
174
- [:TkALIAS, TkKW, "alias", EXPR_FNAME],
175
- [:TkDEFINED, TkKW, "defined?", EXPR_END],
176
- [:TklBEGIN, TkKW, "BEGIN", EXPR_END],
177
- [:TklEND, TkKW, "END", EXPR_END],
178
- [:Tk__LINE__, TkKW, "__LINE__", EXPR_END],
179
- [:Tk__FILE__, TkKW, "__FILE__", EXPR_END],
180
-
181
- [:TkIDENTIFIER, TkId],
182
- [:TkFID, TkId],
183
- [:TkGVAR, TkId],
184
- [:TkIVAR, TkId],
185
- [:TkCONSTANT, TkId],
186
-
187
- [:TkINTEGER, TkVal],
188
- [:TkFLOAT, TkVal],
189
- [:TkSTRING, TkVal],
190
- [:TkXSTRING, TkVal],
191
- [:TkREGEXP, TkVal],
192
- [:TkCOMMENT, TkVal],
193
-
194
- [:TkDSTRING, TkNode],
195
- [:TkDXSTRING, TkNode],
196
- [:TkDREGEXP, TkNode],
197
- [:TkNTH_REF, TkId],
198
- [:TkBACK_REF, TkId],
199
-
200
- [:TkUPLUS, TkOp, "+@"],
201
- [:TkUMINUS, TkOp, "-@"],
202
- [:TkPOW, TkOp, "**"],
203
- [:TkCMP, TkOp, "<=>"],
204
- [:TkEQ, TkOp, "=="],
205
- [:TkEQQ, TkOp, "==="],
206
- [:TkNEQ, TkOp, "!="],
207
- [:TkGEQ, TkOp, ">="],
208
- [:TkLEQ, TkOp, "<="],
209
- [:TkANDOP, TkOp, "&&"],
210
- [:TkOROP, TkOp, "||"],
211
- [:TkMATCH, TkOp, "=~"],
212
- [:TkNMATCH, TkOp, "!~"],
213
- [:TkDOT2, TkOp, ".."],
214
- [:TkDOT3, TkOp, "..."],
215
- [:TkAREF, TkOp, "[]"],
216
- [:TkASET, TkOp, "[]="],
217
- [:TkLSHFT, TkOp, "<<"],
218
- [:TkRSHFT, TkOp, ">>"],
219
- [:TkCOLON2, TkOp],
220
- [:TkCOLON3, TkOp],
221
- # [:OPASGN, TkOp], # +=, -= etc. #
222
- [:TkASSOC, TkOp, "=>"],
223
- [:TkQUESTION, TkOp, "?"], #?
224
- [:TkCOLON, TkOp, ":"], #:
225
-
226
- [:TkfLPAREN], # func( #
227
- [:TkfLBRACK], # func[ #
228
- [:TkfLBRACE], # func{ #
229
- [:TkSTAR], # *arg
230
- [:TkAMPER], # &arg #
231
- [:TkSYMBOL, TkId], # :SYMBOL
232
- [:TkSYMBEG, TkId],
233
- [:TkGT, TkOp, ">"],
234
- [:TkLT, TkOp, "<"],
235
- [:TkPLUS, TkOp, "+"],
236
- [:TkMINUS, TkOp, "-"],
237
- [:TkMULT, TkOp, "*"],
238
- [:TkDIV, TkOp, "/"],
239
- [:TkMOD, TkOp, "%"],
240
- [:TkBITOR, TkOp, "|"],
241
- [:TkBITXOR, TkOp, "^"],
242
- [:TkBITAND, TkOp, "&"],
243
- [:TkBITNOT, TkOp, "~"],
244
- [:TkNOTOP, TkOp, "!"],
245
-
246
- [:TkBACKQUOTE, TkOp, "`"],
247
-
248
- [:TkASSIGN, Token, "="],
249
- [:TkDOT, Token, "."],
250
- [:TkLPAREN, Token, "("], #(exp)
251
- [:TkLBRACK, Token, "["], #[arry]
252
- [:TkLBRACE, Token, "{"], #{hash}
253
- [:TkRPAREN, Token, ")"],
254
- [:TkRBRACK, Token, "]"],
255
- [:TkRBRACE, Token, "}"],
256
- [:TkCOMMA, Token, ","],
257
- [:TkSEMICOLON, Token, ";"],
258
-
259
- [:TkRD_COMMENT],
260
- [:TkSPACE],
261
- [:TkNL],
262
- [:TkEND_OF_SCRIPT],
263
-
264
- [:TkBACKSLASH, TkUnknownChar, "\\"],
265
- [:TkAT, TkUnknownChar, "@"],
266
- [:TkDOLLAR, TkUnknownChar, "\$"], #"
267
- ]
268
-
269
- # {reading => token_class}
270
- # {reading => [token_class, *opt]}
271
- TkReading2Token = {}
272
- TkSymbol2Token = {}
273
-
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)
278
-
279
- token_c = Class.new super_token
280
- const_set token_n, token_c
281
- # token_c.inspect
282
-
283
- if reading
284
- if TkReading2Token[reading]
285
- fail TkReading2TokenDuplicateError, token_n, reading
286
- end
287
- if opts.empty?
288
- TkReading2Token[reading] = [token_c]
289
- else
290
- TkReading2Token[reading] = [token_c].concat(opts)
291
- end
292
- end
293
- TkSymbol2Token[token_n.intern] = token_c
294
-
295
- if token_c <= TkOp
296
- token_c.class_eval %{
297
- def self.op_name; "#{reading}"; end
298
- }
299
- end
300
- end
301
-
302
- for defs in TokenDefinitions
303
- def_token(*defs)
304
- end
305
-
306
- NEWLINE_TOKEN = TkNL.new(0,0)
307
- NEWLINE_TOKEN.set_text("\n")
308
-
309
- end
310
-
311
- ##
312
- # Lexical analyzer for Ruby source
313
-
314
- class RDoc::RubyLex
315
-
316
- ##
317
- # Read an input stream character by character. We allow for unlimited
318
- # ungetting of characters just read.
319
- #
320
- # We simplify the implementation greatly by reading the entire input
321
- # into a buffer initially, and then simply traversing it using
322
- # pointers.
323
- #
324
- # We also have to allow for the <i>here document diversion</i>. This
325
- # little gem comes about when the lexer encounters a here
326
- # document. At this point we effectively need to split the input
327
- # stream into two parts: one to read the body of the here document,
328
- # the other to read the rest of the input line where the here
329
- # document was initially encountered. For example, we might have
330
- #
331
- # do_something(<<-A, <<-B)
332
- # stuff
333
- # for
334
- # A
335
- # stuff
336
- # for
337
- # B
338
- #
339
- # When the lexer encounters the <<A, it reads until the end of the
340
- # line, and keeps it around for later. It then reads the body of the
341
- # here document. Once complete, it needs to read the rest of the
342
- # original line, but then skip the here document body.
343
- #
344
-
345
- class BufferedReader
346
-
347
- attr_reader :line_num
348
-
349
- def initialize(content, options)
350
- @options = options
351
-
352
- if /\t/ =~ content
353
- tab_width = @options.tab_width
354
- content = content.split(/\n/).map do |line|
355
- 1 while line.gsub!(/\t+/) { ' ' * (tab_width*$&.length - $`.length % tab_width)} && $~ #`
356
- line
357
- end .join("\n")
358
- end
359
- @content = content
360
- @content << "\n" unless @content[-1,1] == "\n"
361
- @size = @content.size
362
- @offset = 0
363
- @hwm = 0
364
- @line_num = 1
365
- @read_back_offset = 0
366
- @last_newline = 0
367
- @newline_pending = false
368
- end
369
-
370
- def column
371
- @offset - @last_newline
372
- end
373
-
374
- def getc
375
- return nil if @offset >= @size
376
- ch = @content[@offset, 1]
377
-
378
- @offset += 1
379
- @hwm = @offset if @hwm < @offset
380
-
381
- if @newline_pending
382
- @line_num += 1
383
- @last_newline = @offset - 1
384
- @newline_pending = false
385
- end
386
-
387
- if ch == "\n"
388
- @newline_pending = true
389
- end
390
- ch
391
- end
392
-
393
- def getc_already_read
394
- getc
395
- end
396
-
397
- def ungetc(ch)
398
- raise "unget past beginning of file" if @offset <= 0
399
- @offset -= 1
400
- if @content[@offset] == ?\n
401
- @newline_pending = false
402
- end
403
- end
404
-
405
- def get_read
406
- res = @content[@read_back_offset...@offset]
407
- @read_back_offset = @offset
408
- res
409
- end
410
-
411
- def peek(at)
412
- pos = @offset + at
413
- if pos >= @size
414
- nil
415
- else
416
- @content[pos, 1]
417
- end
418
- end
419
-
420
- def peek_equal(str)
421
- @content[@offset, str.length] == str
422
- end
423
-
424
- def divert_read_from(reserve)
425
- @content[@offset, 0] = reserve
426
- @size = @content.size
427
- end
428
- end
429
-
430
- # end of nested class BufferedReader
431
-
432
- extend Exception2MessageMapper
433
- def_exception(:AlreadyDefinedToken, "Already defined token(%s)")
434
- def_exception(:TkReading2TokenNoKey, "key nothing(key='%s')")
435
- def_exception(:TkSymbol2TokenNoKey, "key nothing(key='%s')")
436
- def_exception(:TkReading2TokenDuplicateError,
437
- "key duplicate(token_n='%s', key='%s')")
438
- def_exception(:SyntaxError, "%s")
439
-
440
- include RDoc::RubyToken
441
- include IRB
442
-
443
- attr_reader :continue
444
- attr_reader :lex_state
445
-
446
- def self.debug?
447
- false
448
- end
449
-
450
- def initialize(content, options)
451
- lex_init
452
-
453
- @options = options
454
-
455
- @reader = BufferedReader.new content, @options
456
-
457
- @exp_line_no = @line_no = 1
458
- @base_char_no = 0
459
- @indent = 0
460
-
461
- @ltype = nil
462
- @quoted = nil
463
- @lex_state = EXPR_BEG
464
- @space_seen = false
465
-
466
- @continue = false
467
- @line = ""
468
-
469
- @skip_space = false
470
- @read_auto_clean_up = false
471
- @exception_on_syntax_error = true
472
- end
473
-
474
- attr_accessor :skip_space
475
- attr_accessor :read_auto_clean_up
476
- attr_accessor :exception_on_syntax_error
477
- attr_reader :indent
478
-
479
- # io functions
480
- def line_no
481
- @reader.line_num
482
- end
483
-
484
- def char_no
485
- @reader.column
486
- end
487
-
488
- def get_read
489
- @reader.get_read
490
- end
491
-
492
- def getc
493
- @reader.getc
494
- end
495
-
496
- def getc_of_rests
497
- @reader.getc_already_read
498
- end
499
-
500
- def gets
501
- c = getc or return
502
- l = ""
503
- begin
504
- l.concat c unless c == "\r"
505
- break if c == "\n"
506
- end while c = getc
507
- l
508
- end
509
-
510
-
511
- def ungetc(c = nil)
512
- @reader.ungetc(c)
513
- end
514
-
515
- def peek_equal?(str)
516
- @reader.peek_equal(str)
517
- end
518
-
519
- def peek(i = 0)
520
- @reader.peek(i)
521
- end
522
-
523
- def lex
524
- until (TkNL === (tk = token) or TkEND_OF_SCRIPT === tk) and
525
- not @continue or tk.nil?
526
- end
527
-
528
- line = get_read
529
-
530
- if line == "" and TkEND_OF_SCRIPT === tk or tk.nil? then
531
- nil
532
- else
533
- line
534
- end
535
- end
536
-
537
- def token
538
- set_token_position(line_no, char_no)
539
- begin
540
- begin
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)
548
- end
549
- end while @skip_space and TkSPACE === tk
550
- if @read_auto_clean_up
551
- get_read
552
- end
553
- # throw :eof unless tk
554
- tk
555
- end
556
-
557
- ENINDENT_CLAUSE = [
558
- "case", "class", "def", "do", "for", "if",
559
- "module", "unless", "until", "while", "begin" #, "when"
560
- ]
561
- DEINDENT_CLAUSE = ["end" #, "when"
562
- ]
563
-
564
- PERCENT_LTYPE = {
565
- "q" => "\'",
566
- "Q" => "\"",
567
- "x" => "\`",
568
- "r" => "/",
569
- "w" => "]"
570
- }
571
-
572
- PERCENT_PAREN = {
573
- "{" => "}",
574
- "[" => "]",
575
- "<" => ">",
576
- "(" => ")"
577
- }
578
-
579
- Ltype2Token = {
580
- "\'" => TkSTRING,
581
- "\"" => TkSTRING,
582
- "\`" => TkXSTRING,
583
- "/" => TkREGEXP,
584
- "]" => TkDSTRING
585
- }
586
- Ltype2Token.default = TkSTRING
587
-
588
- DLtype2Token = {
589
- "\"" => TkDSTRING,
590
- "\`" => TkDXSTRING,
591
- "/" => TkDREGEXP,
592
- }
593
-
594
- def lex_init()
595
- @OP = IRB::SLex.new
596
- @OP.def_rules("\0", "\004", "\032") do |chars, io|
597
- Token(TkEND_OF_SCRIPT).set_text(chars)
598
- end
599
-
600
- @OP.def_rules(" ", "\t", "\f", "\r", "\13") do |chars, io|
601
- @space_seen = TRUE
602
- while (ch = getc) =~ /[ \t\f\r\13]/
603
- chars << ch
604
- end
605
- ungetc
606
- Token(TkSPACE).set_text(chars)
607
- end
608
-
609
- @OP.def_rule("#") do
610
- |op, io|
611
- identify_comment
612
- end
613
-
614
- @OP.def_rule("=begin", proc{@prev_char_no == 0 && peek(0) =~ /\s/}) do
615
- |op, io|
616
- str = op
617
- @ltype = "="
618
-
619
-
620
- begin
621
- line = ""
622
- begin
623
- ch = getc
624
- line << ch
625
- end until ch == "\n"
626
- str << line
627
- end until line =~ /^=end/
628
-
629
- ungetc
630
-
631
- @ltype = nil
632
-
633
- if str =~ /\A=begin\s+rdoc/i
634
- str.sub!(/\A=begin.*\n/, '')
635
- str.sub!(/^=end.*/m, '')
636
- Token(TkCOMMENT).set_text(str)
637
- else
638
- Token(TkRD_COMMENT)#.set_text(str)
639
- end
640
- end
641
-
642
- @OP.def_rule("\n") do
643
- print "\\n\n" if RDoc::RubyLex.debug?
644
- case @lex_state
645
- when EXPR_BEG, EXPR_FNAME, EXPR_DOT
646
- @continue = TRUE
647
- else
648
- @continue = FALSE
649
- @lex_state = EXPR_BEG
650
- end
651
- Token(TkNL).set_text("\n")
652
- end
653
-
654
- @OP.def_rules("*", "**",
655
- "!", "!=", "!~",
656
- "=", "==", "===",
657
- "=~", "<=>",
658
- "<", "<=",
659
- ">", ">=", ">>") do
660
- |op, io|
661
- @lex_state = EXPR_BEG
662
- Token(op).set_text(op)
663
- end
664
-
665
- @OP.def_rules("<<") do
666
- |op, io|
667
- tk = nil
668
- if @lex_state != EXPR_END && @lex_state != EXPR_CLASS &&
669
- (@lex_state != EXPR_ARG || @space_seen)
670
- c = peek(0)
671
- if /[-\w_\"\'\`]/ =~ c
672
- tk = identify_here_document
673
- end
674
- end
675
- if !tk
676
- @lex_state = EXPR_BEG
677
- tk = Token(op).set_text(op)
678
- end
679
- tk
680
- end
681
-
682
- @OP.def_rules("'", '"') do
683
- |op, io|
684
- identify_string(op)
685
- end
686
-
687
- @OP.def_rules("`") do
688
- |op, io|
689
- if @lex_state == EXPR_FNAME
690
- Token(op).set_text(op)
691
- else
692
- identify_string(op)
693
- end
694
- end
695
-
696
- @OP.def_rules('?') do
697
- |op, io|
698
- if @lex_state == EXPR_END
699
- @lex_state = EXPR_BEG
700
- Token(TkQUESTION).set_text(op)
701
- 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
708
- str = op
709
- str << ch
710
- if (ch == '\\') #'
711
- str << read_escape
712
- end
713
- @lex_state = EXPR_END
714
- Token(TkINTEGER).set_text(str)
715
- end
716
- end
717
- end
718
-
719
- @OP.def_rules("&", "&&", "|", "||") do
720
- |op, io|
721
- @lex_state = EXPR_BEG
722
- Token(op).set_text(op)
723
- end
724
-
725
- @OP.def_rules("+=", "-=", "*=", "**=",
726
- "&=", "|=", "^=", "<<=", ">>=", "||=", "&&=") do
727
- |op, io|
728
- @lex_state = EXPR_BEG
729
- op =~ /^(.*)=$/
730
- Token(TkOPASGN, $1).set_text(op)
731
- end
732
-
733
- @OP.def_rule("+@", proc{@lex_state == EXPR_FNAME}) do |op, io|
734
- Token(TkUPLUS).set_text(op)
735
- end
736
-
737
- @OP.def_rule("-@", proc{@lex_state == EXPR_FNAME}) do |op, io|
738
- Token(TkUMINUS).set_text(op)
739
- end
740
-
741
- @OP.def_rules("+", "-") do
742
- |op, io|
743
- catch(:RET) do
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)
756
- end
757
- end
758
-
759
- @OP.def_rule(".") do
760
- @lex_state = EXPR_BEG
761
- if peek(0) =~ /[0-9]/
762
- ungetc
763
- identify_number("")
764
- else
765
- # for obj.if
766
- @lex_state = EXPR_DOT
767
- Token(TkDOT).set_text(".")
768
- end
769
- end
770
-
771
- @OP.def_rules("..", "...") do
772
- |op, io|
773
- @lex_state = EXPR_BEG
774
- Token(op).set_text(op)
775
- end
776
-
777
- lex_int2
778
- end
779
-
780
- def lex_int2
781
- @OP.def_rules("]", "}", ")") do
782
- |op, io|
783
- @lex_state = EXPR_END
784
- @indent -= 1
785
- Token(op).set_text(op)
786
- end
787
-
788
- @OP.def_rule(":") do
789
- if @lex_state == EXPR_END || peek(0) =~ /\s/
790
- @lex_state = EXPR_BEG
791
- tk = Token(TkCOLON)
792
- else
793
- @lex_state = EXPR_FNAME
794
- tk = Token(TkSYMBEG)
795
- end
796
- tk.set_text(":")
797
- end
798
-
799
- @OP.def_rule("::") do
800
- if @lex_state == EXPR_BEG or @lex_state == EXPR_ARG && @space_seen
801
- @lex_state = EXPR_BEG
802
- tk = Token(TkCOLON3)
803
- else
804
- @lex_state = EXPR_DOT
805
- tk = Token(TkCOLON2)
806
- end
807
- tk.set_text("::")
808
- end
809
-
810
- @OP.def_rule("/") do
811
- |op, io|
812
- if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
813
- identify_string(op)
814
- elsif peek(0) == '='
815
- getc
816
- @lex_state = EXPR_BEG
817
- Token(TkOPASGN, :/).set_text("/=") #")
818
- elsif @lex_state == EXPR_ARG and @space_seen and peek(0) !~ /\s/
819
- identify_string(op)
820
- else
821
- @lex_state = EXPR_BEG
822
- Token("/").set_text(op)
823
- end
824
- end
825
-
826
- @OP.def_rules("^") do
827
- @lex_state = EXPR_BEG
828
- Token("^").set_text("^")
829
- end
830
-
831
- @OP.def_rules(",", ";") do
832
- |op, io|
833
- @lex_state = EXPR_BEG
834
- Token(op).set_text(op)
835
- end
836
-
837
- @OP.def_rule("~") do
838
- @lex_state = EXPR_BEG
839
- Token("~").set_text("~")
840
- end
841
-
842
- @OP.def_rule("~@", proc{@lex_state = EXPR_FNAME}) do
843
- @lex_state = EXPR_BEG
844
- Token("~").set_text("~@")
845
- end
846
-
847
- @OP.def_rule("(") do
848
- @indent += 1
849
- if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
850
- @lex_state = EXPR_BEG
851
- tk = Token(TkfLPAREN)
852
- else
853
- @lex_state = EXPR_BEG
854
- tk = Token(TkLPAREN)
855
- end
856
- tk.set_text("(")
857
- end
858
-
859
- @OP.def_rule("[]", proc{@lex_state == EXPR_FNAME}) do
860
- Token("[]").set_text("[]")
861
- end
862
-
863
- @OP.def_rule("[]=", proc{@lex_state == EXPR_FNAME}) do
864
- Token("[]=").set_text("[]=")
865
- end
866
-
867
- @OP.def_rule("[") do
868
- @indent += 1
869
- if @lex_state == EXPR_FNAME
870
- t = Token(TkfLBRACK)
871
- else
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
880
- end
881
- t.set_text("[")
882
- end
883
-
884
- @OP.def_rule("{") do
885
- @indent += 1
886
- if @lex_state != EXPR_END && @lex_state != EXPR_ARG
887
- t = Token(TkLBRACE)
888
- else
889
- t = Token(TkfLBRACE)
890
- end
891
- @lex_state = EXPR_BEG
892
- t.set_text("{")
893
- end
894
-
895
- @OP.def_rule('\\') do #'
896
- if getc == "\n"
897
- @space_seen = true
898
- @continue = true
899
- Token(TkSPACE).set_text("\\\n")
900
- else
901
- ungetc
902
- Token("\\").set_text("\\") #"
903
- end
904
- end
905
-
906
- @OP.def_rule('%') do
907
- |op, io|
908
- if @lex_state == EXPR_BEG || @lex_state == EXPR_MID
909
- identify_quotation('%')
910
- elsif peek(0) == '='
911
- getc
912
- Token(TkOPASGN, "%").set_text("%=")
913
- elsif @lex_state == EXPR_ARG and @space_seen and peek(0) !~ /\s/
914
- identify_quotation('%')
915
- else
916
- @lex_state = EXPR_BEG
917
- Token("%").set_text("%")
918
- end
919
- end
920
-
921
- @OP.def_rule('$') do #'
922
- identify_gvar
923
- end
924
-
925
- @OP.def_rule('@') do
926
- if peek(0) =~ /[@\w_]/
927
- ungetc
928
- identify_identifier
929
- else
930
- Token("@").set_text("@")
931
- end
932
- end
933
-
934
- @OP.def_rule("__END__", proc{@prev_char_no == 0 && peek(0) =~ /[\r\n]/}) do
935
- throw :eof
936
- end
937
-
938
- @OP.def_rule("") do
939
- |op, io|
940
- printf "MATCH: start %s: %s\n", op, io.inspect if RDoc::RubyLex.debug?
941
- if peek(0) =~ /[0-9]/
942
- t = identify_number("")
943
- elsif peek(0) =~ /[\w_]/
944
- t = identify_identifier
945
- end
946
- printf "MATCH: end %s: %s\n", op, io.inspect if RDoc::RubyLex.debug?
947
- t
948
- end
949
- end
950
-
951
- def identify_gvar
952
- @lex_state = EXPR_END
953
- str = "$"
954
-
955
- tk = case ch = getc
956
- when /[~_*$?!@\/\\;,=:<>".]/ #"
957
- str << ch
958
- Token(TkGVAR, str)
959
-
960
- when "-"
961
- str << "-" << getc
962
- Token(TkGVAR, str)
963
-
964
- when "&", "`", "'", "+"
965
- str << ch
966
- Token(TkBACK_REF, str)
967
-
968
- when /[1-9]/
969
- str << ch
970
- while (ch = getc) =~ /[0-9]/
971
- str << ch
972
- end
973
- ungetc
974
- Token(TkNTH_REF)
975
- when /\w/
976
- ungetc
977
- ungetc
978
- return identify_identifier
979
- else
980
- ungetc
981
- Token("$")
982
- end
983
- tk.set_text(str)
984
- end
985
-
986
- def identify_identifier
987
- token = ""
988
- token.concat getc if peek(0) =~ /[$@]/
989
- token.concat getc if peek(0) == "@"
990
-
991
- while (ch = getc) =~ /\w|_/
992
- print ":", ch, ":" if RDoc::RubyLex.debug?
993
- token.concat ch
994
- end
995
- ungetc
996
-
997
- if ch == "!" or ch == "?"
998
- token.concat getc
999
- end
1000
- # fix token
1001
-
1002
- # $stderr.puts "identifier - #{token}, state = #@lex_state"
1003
-
1004
- case token
1005
- when /^\$/
1006
- return Token(TkGVAR, token).set_text(token)
1007
- when /^\@/
1008
- @lex_state = EXPR_END
1009
- return Token(TkIVAR, token).set_text(token)
1010
- end
1011
-
1012
- if @lex_state != EXPR_DOT
1013
- print token, "\n" if RDoc::RubyLex.debug?
1014
-
1015
- token_c, *trans = TkReading2Token[token]
1016
- if token_c
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)
1038
- end
1039
- end
1040
-
1041
- if @lex_state == EXPR_FNAME
1042
- @lex_state = EXPR_END
1043
- if peek(0) == '='
1044
- token.concat getc
1045
- end
1046
- elsif @lex_state == EXPR_BEG || @lex_state == EXPR_DOT
1047
- @lex_state = EXPR_ARG
1048
- else
1049
- @lex_state = EXPR_END
1050
- end
1051
-
1052
- if token[0, 1] =~ /[A-Z]/
1053
- return Token(TkCONSTANT, token).set_text(token)
1054
- elsif token[token.size - 1, 1] =~ /[!?]/
1055
- return Token(TkFID, token).set_text(token)
1056
- else
1057
- return Token(TkIDENTIFIER, token).set_text(token)
1058
- end
1059
- end
1060
-
1061
- def identify_here_document
1062
- ch = getc
1063
- if ch == "-"
1064
- ch = getc
1065
- indent = true
1066
- end
1067
- if /['"`]/ =~ ch # '
1068
- lt = ch
1069
- quoted = ""
1070
- while (c = getc) && c != lt
1071
- quoted.concat c
1072
- end
1073
- else
1074
- lt = '"'
1075
- quoted = ch.dup
1076
- while (c = getc) && c =~ /\w/
1077
- quoted.concat c
1078
- end
1079
- ungetc
1080
- end
1081
-
1082
- ltback, @ltype = @ltype, lt
1083
- reserve = ""
1084
-
1085
- while ch = getc
1086
- reserve << ch
1087
- if ch == "\\" #"
1088
- ch = getc
1089
- reserve << ch
1090
- elsif ch == "\n"
1091
- break
1092
- end
1093
- end
1094
-
1095
- str = ""
1096
- while (l = gets)
1097
- l.chomp!
1098
- l.strip! if indent
1099
- break if l == quoted
1100
- str << l.chomp << "\n"
1101
- end
1102
-
1103
- @reader.divert_read_from(reserve)
1104
-
1105
- @ltype = ltback
1106
- @lex_state = EXPR_END
1107
- Token(Ltype2Token[lt], str).set_text(str.dump)
1108
- end
1109
-
1110
- def identify_quotation(initial_char)
1111
- ch = getc
1112
- if lt = PERCENT_LTYPE[ch]
1113
- initial_char += ch
1114
- ch = getc
1115
- elsif ch =~ /\W/
1116
- lt = "\""
1117
- else
1118
- fail SyntaxError, "unknown type of %string ('#{ch}')"
1119
- end
1120
- # if ch !~ /\W/
1121
- # ungetc
1122
- # next
1123
- # end
1124
- #@ltype = lt
1125
- @quoted = ch unless @quoted = PERCENT_PAREN[ch]
1126
- identify_string(lt, @quoted, ch, initial_char)
1127
- end
1128
-
1129
- def identify_number(start)
1130
- str = start.dup
1131
-
1132
- if start == "+" or start == "-" or start == ""
1133
- start = getc
1134
- str << start
1135
- end
1136
-
1137
- @lex_state = EXPR_END
1138
-
1139
- if start == "0"
1140
- if peek(0) == "x"
1141
- ch = getc
1142
- str << ch
1143
- match = /[0-9a-f_]/
1144
- else
1145
- match = /[0-7_]/
1146
- end
1147
- while ch = getc
1148
- if ch !~ match
1149
- ungetc
1150
- break
1151
- else
1152
- str << ch
1153
- end
1154
- end
1155
- return Token(TkINTEGER).set_text(str)
1156
- end
1157
-
1158
- type = TkINTEGER
1159
- allow_point = TRUE
1160
- allow_e = TRUE
1161
- while ch = getc
1162
- case ch
1163
- when /[0-9_]/
1164
- str << ch
1165
-
1166
- when allow_point && "."
1167
- type = TkFLOAT
1168
- if peek(0) !~ /[0-9]/
1169
- ungetc
1170
- break
1171
- end
1172
- str << ch
1173
- allow_point = false
1174
-
1175
- when allow_e && "e", allow_e && "E"
1176
- str << ch
1177
- type = TkFLOAT
1178
- if peek(0) =~ /[+-]/
1179
- str << getc
1180
- end
1181
- allow_e = false
1182
- allow_point = false
1183
- else
1184
- ungetc
1185
- break
1186
- end
1187
- end
1188
- Token(type).set_text(str)
1189
- end
1190
-
1191
- def identify_string(ltype, quoted = ltype, opener=nil, initial_char = nil)
1192
- @ltype = ltype
1193
- @quoted = quoted
1194
- subtype = nil
1195
-
1196
- str = ""
1197
- str << initial_char if initial_char
1198
- str << (opener||quoted)
1199
-
1200
- nest = 0
1201
- begin
1202
- while ch = getc
1203
- str << ch
1204
- if @quoted == ch
1205
- if nest == 0
1206
- break
1207
- else
1208
- nest -= 1
1209
- end
1210
- elsif opener == ch
1211
- nest += 1
1212
- elsif @ltype != "'" && @ltype != "]" and ch == "#"
1213
- ch = getc
1214
- if ch == "{"
1215
- subtype = true
1216
- str << ch << skip_inner_expression
1217
- else
1218
- ungetc(ch)
1219
- end
1220
- elsif ch == '\\' #'
1221
- str << read_escape
1222
- end
1223
- end
1224
- if @ltype == "/"
1225
- if peek(0) =~ /i|o|n|e|s/
1226
- str << getc
1227
- end
1228
- end
1229
- if subtype
1230
- Token(DLtype2Token[ltype], str)
1231
- else
1232
- Token(Ltype2Token[ltype], str)
1233
- end.set_text(str)
1234
- ensure
1235
- @ltype = nil
1236
- @quoted = nil
1237
- @lex_state = EXPR_END
1238
- end
1239
- end
1240
-
1241
- def skip_inner_expression
1242
- res = ""
1243
- nest = 0
1244
- while (ch = getc)
1245
- res << ch
1246
- if ch == '}'
1247
- break if nest.zero?
1248
- nest -= 1
1249
- elsif ch == '{'
1250
- nest += 1
1251
- end
1252
- end
1253
- res
1254
- end
1255
-
1256
- def identify_comment
1257
- @ltype = "#"
1258
- comment = "#"
1259
- while ch = getc
1260
- if ch == "\\"
1261
- ch = getc
1262
- if ch == "\n"
1263
- ch = " "
1264
- else
1265
- comment << "\\"
1266
- end
1267
- else
1268
- if ch == "\n"
1269
- @ltype = nil
1270
- ungetc
1271
- break
1272
- end
1273
- end
1274
- comment << ch
1275
- end
1276
- return Token(TkCOMMENT).set_text(comment)
1277
- end
1278
-
1279
- def read_escape
1280
- res = ""
1281
- case ch = getc
1282
- when /[0-7]/
1283
- ungetc ch
1284
- 3.times do
1285
- case ch = getc
1286
- when /[0-7]/
1287
- when nil
1288
- break
1289
- else
1290
- ungetc
1291
- break
1292
- end
1293
- res << ch
1294
- end
1295
-
1296
- when "x"
1297
- res << ch
1298
- 2.times do
1299
- case ch = getc
1300
- when /[0-9a-fA-F]/
1301
- when nil
1302
- break
1303
- else
1304
- ungetc
1305
- break
1306
- end
1307
- res << ch
1308
- end
1309
-
1310
- when "M"
1311
- res << ch
1312
- if (ch = getc) != '-'
1313
- ungetc
1314
- else
1315
- res << ch
1316
- if (ch = getc) == "\\" #"
1317
- res << ch
1318
- res << read_escape
1319
- else
1320
- res << ch
1321
- end
1322
- end
1323
-
1324
- when "C", "c" #, "^"
1325
- res << ch
1326
- if ch == "C" and (ch = getc) != "-"
1327
- ungetc
1328
- else
1329
- res << ch
1330
- if (ch = getc) == "\\" #"
1331
- res << ch
1332
- res << read_escape
1333
- else
1334
- res << ch
1335
- end
1336
- end
1337
- else
1338
- res << ch
1339
- end
1340
- res
1341
- end
1342
- end
1343
20
 
1344
21
  ##
1345
22
  # Extracts code elements from a source file returning a TopLevel object
@@ -1473,8 +150,16 @@ class RDoc::Parser::Ruby < RDoc::Parser
1473
150
 
1474
151
  include RDoc::RubyToken
1475
152
  include RDoc::TokenStream
153
+ include RDoc::Parser::RubyTools
154
+
155
+ ##
156
+ # RDoc::NormalClass type
1476
157
 
1477
158
  NORMAL = "::"
159
+
160
+ ##
161
+ # RDoc::SingleClass type
162
+
1478
163
  SINGLE = "<<"
1479
164
 
1480
165
  def initialize(top_level, file_name, content, options, stats)
@@ -1484,21 +169,17 @@ class RDoc::Parser::Ruby < RDoc::Parser
1484
169
  @token_listeners = nil
1485
170
  @scanner = RDoc::RubyLex.new content, @options
1486
171
  @scanner.exception_on_syntax_error = false
172
+ @prev_seek = nil
1487
173
 
1488
174
  reset
1489
175
  end
1490
176
 
1491
- def add_token_listener(obj)
1492
- @token_listeners ||= []
1493
- @token_listeners << obj
1494
- end
1495
-
1496
177
  ##
1497
178
  # Look for the first comment in a file that isn't a shebang line.
1498
179
 
1499
180
  def collect_first_comment
1500
181
  skip_tkspace
1501
- res = ''
182
+ comment = ''
1502
183
  first_line = true
1503
184
 
1504
185
  tk = get_tk
@@ -1513,7 +194,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
1513
194
  tk = get_tk
1514
195
  else
1515
196
  first_line = false
1516
- res << tk.text << "\n"
197
+ comment << tk.text << "\n"
1517
198
  tk = get_tk
1518
199
 
1519
200
  if TkNL === tk then
@@ -1525,7 +206,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
1525
206
 
1526
207
  unget_tk tk
1527
208
 
1528
- res
209
+ comment
1529
210
  end
1530
211
 
1531
212
  def error(msg)
@@ -1571,24 +252,24 @@ class RDoc::Parser::Ruby < RDoc::Parser
1571
252
  name_t = get_tk
1572
253
 
1573
254
  # class ::A -> A is in the top level
1574
- if TkCOLON2 === name_t then
255
+ case name_t
256
+ when TkCOLON2, TkCOLON3 then # bug
1575
257
  name_t = get_tk
1576
258
  container = @top_level
1577
259
  end
1578
260
 
1579
- skip_tkspace(false)
261
+ skip_tkspace false
1580
262
 
1581
263
  while TkCOLON2 === peek_tk do
1582
264
  prev_container = container
1583
- container = container.find_module_named(name_t.name)
1584
- if !container
1585
- # warn("Couldn't find module #{name_t.name}")
265
+ container = container.find_module_named name_t.name
266
+ unless container then
1586
267
  container = prev_container.add_module RDoc::NormalModule, name_t.name
1587
268
  end
1588
269
  get_tk
1589
270
  name_t = get_tk
1590
271
  end
1591
- skip_tkspace(false)
272
+ skip_tkspace false
1592
273
  return [container, name_t]
1593
274
  end
1594
275
 
@@ -1601,12 +282,12 @@ class RDoc::Parser::Ruby < RDoc::Parser
1601
282
 
1602
283
  res = ""
1603
284
  while TkCOLON2 === tk or TkCOLON3 === tk or TkCONSTANT === tk do
1604
- res += tk.text
285
+ res += tk.name
1605
286
  tk = get_tk
1606
287
  end
1607
288
 
1608
289
  unget_tk(tk)
1609
- skip_tkspace(false)
290
+ skip_tkspace false
1610
291
 
1611
292
  get_tkread # empty out read buffer
1612
293
 
@@ -1628,11 +309,11 @@ class RDoc::Parser::Ruby < RDoc::Parser
1628
309
 
1629
310
  def get_constant
1630
311
  res = ""
1631
- skip_tkspace(false)
312
+ skip_tkspace false
1632
313
  tk = get_tk
1633
314
 
1634
315
  while TkCOLON2 === tk or TkCOLON3 === tk or TkCONSTANT === tk do
1635
- res += tk.text
316
+ res += tk.name
1636
317
  tk = get_tk
1637
318
  end
1638
319
 
@@ -1647,88 +328,51 @@ class RDoc::Parser::Ruby < RDoc::Parser
1647
328
  # Get a constant that may be surrounded by parens
1648
329
 
1649
330
  def get_constant_with_optional_parens
1650
- skip_tkspace(false)
331
+ skip_tkspace false
1651
332
  nest = 0
1652
333
  while TkLPAREN === (tk = peek_tk) or TkfLPAREN === tk do
1653
334
  get_tk
1654
- skip_tkspace(true)
335
+ skip_tkspace
1655
336
  nest += 1
1656
337
  end
1657
338
 
1658
339
  name = get_constant
1659
340
 
1660
341
  while nest > 0
1661
- skip_tkspace(true)
342
+ skip_tkspace
1662
343
  tk = get_tk
1663
344
  nest -= 1 if TkRPAREN === tk
1664
345
  end
346
+
1665
347
  name
1666
348
  end
1667
349
 
1668
350
  def get_symbol_or_name
1669
351
  tk = get_tk
1670
352
  case tk
1671
- when TkSYMBOL
1672
- tk.text.sub(/^:/, '')
1673
- when TkId, TkOp
353
+ when TkSYMBOL then
354
+ text = tk.text.sub(/^:/, '')
355
+
356
+ if TkASSIGN === peek_tk then
357
+ get_tk
358
+ text << '='
359
+ end
360
+
361
+ text
362
+ when TkId, TkOp then
1674
363
  tk.name
1675
- when TkSTRING
364
+ when TkSTRING, TkDSTRING then
1676
365
  tk.text
1677
366
  else
1678
- raise "Name or symbol expected (got #{tk})"
1679
- end
1680
- end
1681
-
1682
- def get_tk
1683
- tk = nil
1684
- if @tokens.empty?
1685
- tk = @scanner.token
1686
- @read.push @scanner.get_read
1687
- puts "get_tk1 => #{tk.inspect}" if $TOKEN_DEBUG
1688
- else
1689
- @read.push @unget_read.shift
1690
- tk = @tokens.shift
1691
- puts "get_tk2 => #{tk.inspect}" if $TOKEN_DEBUG
1692
- end
1693
-
1694
- if TkSYMBEG === tk then
1695
- set_token_position(tk.line_no, tk.char_no)
1696
- tk1 = get_tk
1697
- if TkId === tk1 or TkOp === tk1 or TkSTRING === tk1 or TkDSTRING === tk1 then
1698
- if tk1.respond_to?(:name)
1699
- tk = Token(TkSYMBOL).set_text(":" + tk1.name)
1700
- else
1701
- tk = Token(TkSYMBOL).set_text(":" + tk1.text)
1702
- end
1703
- # remove the identifier we just read (we're about to
1704
- # replace it with a symbol)
1705
- @token_listeners.each do |obj|
1706
- obj.pop_token
1707
- end if @token_listeners
1708
- else
1709
- warn("':' not followed by identifier or operator")
1710
- tk = tk1
1711
- end
367
+ raise RDoc::Error, "Name or symbol expected (got #{tk})"
1712
368
  end
1713
-
1714
- # inform any listeners of our shiny new token
1715
- @token_listeners.each do |obj|
1716
- obj.add_token(tk)
1717
- end if @token_listeners
1718
-
1719
- tk
1720
- end
1721
-
1722
- def get_tkread
1723
- read = @read.join("")
1724
- @read = []
1725
- read
1726
369
  end
1727
370
 
1728
371
  ##
1729
372
  # Look for directives in a normal comment block:
1730
373
  #
1731
- # #-- - don't display comment from this point forward
374
+ # # :stopdoc:
375
+ # # Don't display comment from this point forward
1732
376
  #
1733
377
  # This routine modifies it's parameter
1734
378
 
@@ -1743,8 +387,9 @@ class RDoc::Parser::Ruby < RDoc::Parser
1743
387
  when 'main' then
1744
388
  @options.main_page = param
1745
389
  ''
1746
- when 'method', 'singleton-method' then
1747
- false # ignore
390
+ when 'method', 'singleton-method',
391
+ 'attr', 'attr_accessor', 'attr_reader', 'attr_writer' then
392
+ false # handled elsewhere
1748
393
  when 'section' then
1749
394
  context.set_current_section(param, comment)
1750
395
  comment.replace ''
@@ -1765,15 +410,18 @@ class RDoc::Parser::Ruby < RDoc::Parser
1765
410
  end
1766
411
  end
1767
412
 
1768
- remove_private_comments(comment)
413
+ remove_private_comments comment
1769
414
  end
1770
415
 
1771
- def make_message(msg)
1772
- prefix = "\n" + @file_name + ":"
1773
- if @scanner
1774
- prefix << "#{@scanner.line_no}:#{@scanner.char_no}: "
1775
- end
1776
- return prefix + msg
416
+ ##
417
+ # Adds useful info about the parser to +message+
418
+
419
+ def make_message message
420
+ prefix = "\n#{@file_name}:"
421
+
422
+ prefix << "#{@scanner.line_no}:#{@scanner.char_no}:" if @scanner
423
+
424
+ "#{prefix} #{message}"
1777
425
  end
1778
426
 
1779
427
  ##
@@ -1785,7 +433,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
1785
433
  if args.size > 0
1786
434
  name = args[0]
1787
435
  rw = "R"
1788
- skip_tkspace(false)
436
+ skip_tkspace false
1789
437
  tk = get_tk
1790
438
  if TkCOMMA === tk then
1791
439
  rw = "RW" if get_bool
@@ -1838,19 +486,24 @@ class RDoc::Parser::Ruby < RDoc::Parser
1838
486
  skip_tkspace
1839
487
  end
1840
488
  new_name = get_symbol_or_name
1841
- @scanner.instance_eval{@lex_state = EXPR_FNAME}
489
+
490
+ @scanner.instance_eval { @lex_state = EXPR_FNAME }
491
+
1842
492
  skip_tkspace
1843
493
  if TkCOMMA === peek_tk then
1844
494
  get_tk
1845
495
  skip_tkspace
1846
496
  end
1847
- old_name = get_symbol_or_name
497
+
498
+ begin
499
+ old_name = get_symbol_or_name
500
+ rescue RDoc::Error
501
+ return
502
+ end
1848
503
 
1849
504
  al = RDoc::Alias.new get_tkread, old_name, new_name, comment
1850
505
  read_documentation_modifiers al, RDoc::ATTR_MODIFIERS
1851
- if al.document_self
1852
- context.add_alias(al)
1853
- end
506
+ context.add_alias al if al.document_self
1854
507
  end
1855
508
 
1856
509
  def parse_call_parameters(tk)
@@ -1865,23 +518,25 @@ class RDoc::Parser::Ruby < RDoc::Parser
1865
518
  nest = 0
1866
519
 
1867
520
  loop do
1868
- case tk
1869
- when TkSEMICOLON
1870
- break
1871
- when TkLPAREN, TkfLPAREN
1872
- nest += 1
1873
- when end_token
1874
- if end_token == TkRPAREN
1875
- nest -= 1
1876
- break if @scanner.lex_state == EXPR_END and nest <= 0
1877
- else
1878
- break unless @scanner.continue
1879
- end
1880
- when TkCOMMENT
1881
- unget_tk(tk)
1882
- break
521
+ case tk
522
+ when TkSEMICOLON
523
+ break
524
+ when TkLPAREN, TkfLPAREN
525
+ nest += 1
526
+ when end_token
527
+ if end_token == TkRPAREN
528
+ nest -= 1
529
+ break if @scanner.lex_state == EXPR_END and nest <= 0
530
+ else
531
+ break unless @scanner.continue
1883
532
  end
1884
- tk = get_tk
533
+ when TkCOMMENT
534
+ unget_tk(tk)
535
+ break
536
+ when nil then
537
+ break
538
+ end
539
+ tk = get_tk
1885
540
  end
1886
541
  res = get_tkread.tr("\n", " ").strip
1887
542
  res = "" if res == ";"
@@ -1898,7 +553,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
1898
553
 
1899
554
  if TkLT === peek_tk then
1900
555
  get_tk
1901
- skip_tkspace(true)
556
+ skip_tkspace
1902
557
  superclass = get_class_specification
1903
558
  superclass = "<unknown>" if superclass.empty?
1904
559
  end
@@ -1906,25 +561,24 @@ class RDoc::Parser::Ruby < RDoc::Parser
1906
561
  cls_type = single == SINGLE ? RDoc::SingleClass : RDoc::NormalClass
1907
562
  cls = container.add_class cls_type, name, superclass
1908
563
 
1909
- @stats.add_class cls
1910
-
1911
564
  read_documentation_modifiers cls, RDoc::CLASS_MODIFIERS
1912
565
  cls.record_location @top_level
1913
-
1914
- parse_statements cls
1915
566
  cls.comment = comment
1916
567
 
568
+ @stats.add_class cls
569
+
570
+ parse_statements cls
1917
571
  when TkLSHFT
1918
572
  case name = get_class_specification
1919
573
  when "self", container.name
1920
- parse_statements(container, SINGLE)
574
+ parse_statements container, SINGLE
1921
575
  else
1922
- other = RDoc::TopLevel.find_class_named(name)
1923
- unless other
1924
- # other = @top_level.add_class(NormalClass, name, nil)
1925
- # other.record_location(@top_level)
1926
- # other.comment = comment
1927
- other = RDoc::NormalClass.new "Dummy", nil
576
+ other = RDoc::TopLevel.find_class_named name
577
+
578
+ unless other then
579
+ other = container.add_module RDoc::NormalModule, name
580
+ other.record_location @top_level
581
+ other.comment = comment
1928
582
  end
1929
583
 
1930
584
  @stats.add_class other
@@ -1938,13 +592,13 @@ class RDoc::Parser::Ruby < RDoc::Parser
1938
592
  end
1939
593
  end
1940
594
 
1941
- def parse_constant(container, single, tk, comment)
595
+ def parse_constant(container, tk, comment)
1942
596
  name = tk.name
1943
- skip_tkspace(false)
597
+ skip_tkspace false
1944
598
  eq_tk = get_tk
1945
599
 
1946
600
  unless TkASSIGN === eq_tk then
1947
- unget_tk(eq_tk)
601
+ unget_tk eq_tk
1948
602
  return
1949
603
  end
1950
604
 
@@ -1952,12 +606,15 @@ class RDoc::Parser::Ruby < RDoc::Parser
1952
606
  get_tkread
1953
607
 
1954
608
  tk = get_tk
609
+
1955
610
  if TkGT === tk then
1956
- unget_tk(tk)
1957
- unget_tk(eq_tk)
611
+ unget_tk tk
612
+ unget_tk eq_tk
1958
613
  return
1959
614
  end
1960
615
 
616
+ rhs_name = ''
617
+
1961
618
  loop do
1962
619
  case tk
1963
620
  when TkSEMICOLON then
@@ -1972,12 +629,30 @@ class RDoc::Parser::Ruby < RDoc::Parser
1972
629
  unget_tk tk
1973
630
  break
1974
631
  end
632
+ when TkCONSTANT then
633
+ rhs_name << tk.name
634
+
635
+ if nest <= 0 and TkNL === peek_tk then
636
+ mod = if rhs_name =~ /^::/ then
637
+ RDoc::TopLevel.find_class_or_module rhs_name
638
+ else
639
+ container.find_module_named rhs_name
640
+ end
641
+
642
+ container.add_module_alias mod, name if mod
643
+ get_tk # TkNL
644
+ break
645
+ end
1975
646
  when TkNL then
1976
647
  if nest <= 0 &&
1977
648
  (@scanner.lex_state == EXPR_END || !@scanner.continue) then
1978
649
  unget_tk tk
1979
650
  break
1980
651
  end
652
+ when TkCOLON2, TkCOLON3 then
653
+ rhs_name << '::'
654
+ when nil then
655
+ break
1981
656
  end
1982
657
  tk = get_tk
1983
658
  end
@@ -1988,6 +663,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
1988
663
  con = RDoc::Constant.new name, res, comment
1989
664
  read_documentation_modifiers con, RDoc::CONSTANT_MODIFIERS
1990
665
 
666
+ @stats.add_constant con
1991
667
  container.add_constant con if con.document_self
1992
668
  end
1993
669
 
@@ -2008,22 +684,25 @@ class RDoc::Parser::Ruby < RDoc::Parser
2008
684
  meth = RDoc::GhostMethod.new get_tkread, name
2009
685
  meth.singleton = singleton
2010
686
 
2011
- @stats.add_method meth
2012
-
2013
687
  meth.start_collecting_tokens
2014
- indent = TkSPACE.new 1, 1
688
+ indent = TkSPACE.new nil, 1, 1
2015
689
  indent.set_text " " * column
2016
690
 
2017
- position_comment = TkCOMMENT.new(line_no, 1, "# File #{@top_level.absolute_name}, line #{line_no}")
691
+ position_comment = TkCOMMENT.new nil, line_no, 1
692
+ position_comment.set_text "# File #{@top_level.absolute_name}, line #{line_no}"
2018
693
  meth.add_tokens [position_comment, NEWLINE_TOKEN, indent]
2019
694
 
2020
695
  meth.params = ''
2021
696
 
2022
697
  extract_call_seq comment, meth
2023
698
 
699
+ return unless meth.name
700
+
2024
701
  container.add_method meth if meth.document_self
2025
702
 
2026
703
  meth.comment = comment
704
+
705
+ @stats.add_method meth
2027
706
  elsif comment.sub!(/# +:?(attr(_reader|_writer|_accessor)?:) *(\S*).*?\n/i, '') then
2028
707
  rw = case $1
2029
708
  when 'attr_reader' then 'R'
@@ -2035,6 +714,8 @@ class RDoc::Parser::Ruby < RDoc::Parser
2035
714
 
2036
715
  att = RDoc::Attr.new get_tkread, name, rw, comment
2037
716
  container.add_attribute att
717
+
718
+ @stats.add_method att
2038
719
  end
2039
720
  end
2040
721
 
@@ -2050,6 +731,35 @@ class RDoc::Parser::Ruby < RDoc::Parser
2050
731
  end
2051
732
  end
2052
733
 
734
+ ##
735
+ # Parses a meta-programmed attribute and creates an RDoc::Attr.
736
+ #
737
+ # To create foo and bar attributes on class C with comment "My attributes":
738
+ #
739
+ # class C
740
+ #
741
+ # ##
742
+ # # :attr:
743
+ # #
744
+ # # My attributes
745
+ #
746
+ # my_attr :foo, :bar
747
+ #
748
+ # end
749
+ #
750
+ # To create a foo attribute on class C with comment "My attribute":
751
+ #
752
+ # class C
753
+ #
754
+ # ##
755
+ # # :attr: foo
756
+ # #
757
+ # # My attribute
758
+ #
759
+ # my_attr :foo, :bar
760
+ #
761
+ # end
762
+
2053
763
  def parse_meta_attr(context, single, tk, comment)
2054
764
  args = parse_symbol_arg
2055
765
  read = get_tkread
@@ -2070,9 +780,14 @@ class RDoc::Parser::Ruby < RDoc::Parser
2070
780
  name = $3 unless $3.empty?
2071
781
  end
2072
782
 
2073
- for name in args
783
+ if name then
2074
784
  att = RDoc::Attr.new get_tkread, name, rw, comment
2075
785
  context.add_attribute att
786
+ else
787
+ args.each do |attr_name|
788
+ att = RDoc::Attr.new get_tkread, attr_name, rw, comment
789
+ context.add_attribute att
790
+ end
2076
791
  end
2077
792
  end
2078
793
 
@@ -2101,7 +816,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
2101
816
  when TkSYMBOL then
2102
817
  name = name_t.text[1..-1]
2103
818
  when TkSTRING then
2104
- name = name_t.text[1..-2]
819
+ name = name_t.value[1..-2]
2105
820
  when TkASSIGN then # ignore
2106
821
  remove_token_listener self
2107
822
  return
@@ -2114,173 +829,183 @@ class RDoc::Parser::Ruby < RDoc::Parser
2114
829
  meth = RDoc::MetaMethod.new get_tkread, name
2115
830
  meth.singleton = singleton
2116
831
 
2117
- @stats.add_method meth
2118
-
2119
832
  remove_token_listener self
2120
833
 
2121
834
  meth.start_collecting_tokens
2122
- indent = TkSPACE.new 1, 1
835
+ indent = TkSPACE.new nil, 1, 1
2123
836
  indent.set_text " " * column
2124
837
 
2125
- position_comment = TkCOMMENT.new(line_no, 1, "# File #{@top_level.absolute_name}, line #{line_no}")
838
+ position_comment = TkCOMMENT.new nil, line_no, 1
839
+ position_comment.value = "# File #{@top_level.absolute_name}, line #{line_no}"
2126
840
  meth.add_tokens [position_comment, NEWLINE_TOKEN, indent]
2127
841
  meth.add_tokens @token_stream
2128
842
 
2129
- add_token_listener meth
2130
-
2131
- meth.params = ''
843
+ token_listener meth do
844
+ meth.params = ''
2132
845
 
2133
- extract_call_seq comment, meth
846
+ extract_call_seq comment, meth
2134
847
 
2135
- container.add_method meth if meth.document_self
848
+ container.add_method meth if meth.document_self
2136
849
 
2137
- last_tk = tk
850
+ last_tk = tk
2138
851
 
2139
- while tk = get_tk do
2140
- case tk
2141
- when TkSEMICOLON then
2142
- break
2143
- when TkNL then
2144
- break unless last_tk and TkCOMMA === last_tk
2145
- when TkSPACE then
2146
- # expression continues
2147
- else
2148
- last_tk = tk
852
+ while tk = get_tk do
853
+ case tk
854
+ when TkSEMICOLON then
855
+ break
856
+ when TkNL then
857
+ break unless last_tk and TkCOMMA === last_tk
858
+ when TkSPACE then
859
+ # expression continues
860
+ else
861
+ last_tk = tk
862
+ end
2149
863
  end
2150
864
  end
2151
865
 
2152
- remove_token_listener meth
2153
-
2154
866
  meth.comment = comment
867
+
868
+ @stats.add_method meth
2155
869
  end
2156
870
 
2157
871
  ##
2158
- # Parses a method
872
+ # Parses a normal method defined by +def+
2159
873
 
2160
874
  def parse_method(container, single, tk, comment)
875
+ added_container = nil
876
+ meth = nil
877
+ name = nil
2161
878
  line_no = tk.line_no
2162
879
  column = tk.char_no
2163
880
 
2164
881
  start_collecting_tokens
2165
- add_token(tk)
2166
- add_token_listener(self)
882
+ add_token tk
2167
883
 
2168
- @scanner.instance_eval do @lex_state = EXPR_FNAME end
884
+ token_listener self do
885
+ @scanner.instance_eval do @lex_state = EXPR_FNAME end
2169
886
 
2170
- skip_tkspace(false)
2171
- name_t = get_tk
2172
- back_tk = skip_tkspace
2173
- meth = nil
2174
- added_container = false
887
+ skip_tkspace false
888
+ name_t = get_tk
889
+ back_tk = skip_tkspace
890
+ meth = nil
891
+ added_container = false
2175
892
 
2176
- dot = get_tk
2177
- if TkDOT === dot or TkCOLON2 === dot then
2178
- @scanner.instance_eval do @lex_state = EXPR_FNAME end
2179
- skip_tkspace
2180
- name_t2 = get_tk
893
+ dot = get_tk
894
+ if TkDOT === dot or TkCOLON2 === dot then
895
+ @scanner.instance_eval do @lex_state = EXPR_FNAME end
896
+ skip_tkspace
897
+ name_t2 = get_tk
898
+
899
+ case name_t
900
+ when TkSELF, TkMOD then
901
+ name = name_t2.name
902
+ when TkCONSTANT then
903
+ name = name_t2.name
904
+ prev_container = container
905
+ container = container.find_module_named(name_t.name)
906
+ unless container then
907
+ added_container = true
908
+ obj = name_t.name.split("::").inject(Object) do |state, item|
909
+ state.const_get(item)
910
+ end rescue nil
911
+
912
+ type = obj.class == Class ? RDoc::NormalClass : RDoc::NormalModule
913
+
914
+ unless [Class, Module].include?(obj.class) then
915
+ warn("Couldn't find #{name_t.name}. Assuming it's a module")
916
+ end
2181
917
 
2182
- case name_t
2183
- when TkSELF then
2184
- name = name_t2.name
2185
- when TkCONSTANT then
2186
- name = name_t2.name
2187
- prev_container = container
2188
- container = container.find_module_named(name_t.name)
2189
- unless container then
2190
- added_container = true
2191
- obj = name_t.name.split("::").inject(Object) do |state, item|
2192
- state.const_get(item)
2193
- end rescue nil
2194
-
2195
- type = obj.class == Class ? RDoc::NormalClass : RDoc::NormalModule
2196
-
2197
- unless [Class, Module].include?(obj.class) then
2198
- warn("Couldn't find #{name_t.name}. Assuming it's a module")
2199
- end
918
+ if type == RDoc::NormalClass then
919
+ sclass = obj.superclass ? obj.superclass.name : nil
920
+ container = prev_container.add_class type, name_t.name, sclass
921
+ else
922
+ container = prev_container.add_module type, name_t.name
923
+ end
2200
924
 
2201
- if type == RDoc::NormalClass then
2202
- container = prev_container.add_class(type, name_t.name, obj.superclass.name)
2203
- else
2204
- container = prev_container.add_module(type, name_t.name)
925
+ container.record_location @top_level
2205
926
  end
2206
-
2207
- container.record_location @top_level
927
+ when TkIDENTIFIER, TkIVAR then
928
+ dummy = RDoc::Context.new
929
+ dummy.parent = container
930
+ skip_method dummy
931
+ return
932
+ else
933
+ warn "unexpected method name token #{name_t.inspect}"
934
+ # break
935
+ skip_method container
936
+ return
2208
937
  end
938
+
939
+ meth = RDoc::AnyMethod.new(get_tkread, name)
940
+ meth.singleton = true
2209
941
  else
2210
- warn "unexpected method name token #{name_t2.inspect}"
2211
- # break
2212
- skip_method(container)
2213
- return
2214
- end
942
+ unget_tk dot
943
+ back_tk.reverse_each do |token|
944
+ unget_tk token
945
+ end
2215
946
 
2216
- meth = RDoc::AnyMethod.new(get_tkread, name)
2217
- meth.singleton = true
2218
- else
2219
- unget_tk dot
2220
- back_tk.reverse_each do |token|
2221
- unget_tk token
2222
- end
947
+ name = case name_t
948
+ when TkSTAR, TkAMPER then
949
+ name_t.text
950
+ else
951
+ unless name_t.respond_to? :name then
952
+ warn "expected method name token, . or ::, got #{name_t.inspect}"
953
+ skip_method container
954
+ return
955
+ end
956
+ name_t.name
957
+ end
2223
958
 
2224
- unless name_t.respond_to? :name then
2225
- warn "unexpected method name token #{name_t.inspect}"
2226
- skip_method container
2227
- return
959
+ meth = RDoc::AnyMethod.new get_tkread, name
960
+ meth.singleton = (single == SINGLE)
2228
961
  end
2229
-
2230
- name = name_t.name
2231
-
2232
- meth = RDoc::AnyMethod.new get_tkread, name
2233
- meth.singleton = (single == SINGLE)
2234
962
  end
2235
963
 
2236
- @stats.add_method meth
2237
-
2238
- remove_token_listener self
2239
-
2240
964
  meth.start_collecting_tokens
2241
- indent = TkSPACE.new 1, 1
965
+ indent = TkSPACE.new nil, 1, 1
2242
966
  indent.set_text " " * column
2243
967
 
2244
- token = TkCOMMENT.new(line_no, 1, "# File #{@top_level.absolute_name}, line #{line_no}")
968
+ token = TkCOMMENT.new nil, line_no, 1
969
+ token.set_text "# File #{@top_level.absolute_name}, line #{line_no}"
2245
970
  meth.add_tokens [token, NEWLINE_TOKEN, indent]
2246
971
  meth.add_tokens @token_stream
2247
972
 
2248
- add_token_listener meth
2249
-
2250
- @scanner.instance_eval do @continue = false end
2251
- parse_method_parameters meth
973
+ token_listener meth do
974
+ @scanner.instance_eval do @continue = false end
975
+ parse_method_parameters meth
2252
976
 
2253
- if meth.document_self then
2254
- container.add_method meth
2255
- elsif added_container then
2256
- container.document_self = false
2257
- end
977
+ if meth.document_self then
978
+ container.add_method meth
979
+ elsif added_container then
980
+ container.document_self = false
981
+ end
2258
982
 
2259
- # Having now read the method parameters and documentation modifiers, we
2260
- # now know whether we have to rename #initialize to ::new
983
+ # Having now read the method parameters and documentation modifiers, we
984
+ # now know whether we have to rename #initialize to ::new
2261
985
 
2262
- if name == "initialize" && !meth.singleton then
2263
- if meth.dont_rename_initialize then
2264
- meth.visibility = :protected
2265
- else
2266
- meth.singleton = true
2267
- meth.name = "new"
2268
- meth.visibility = :public
986
+ if name == "initialize" && !meth.singleton then
987
+ if meth.dont_rename_initialize then
988
+ meth.visibility = :protected
989
+ else
990
+ meth.singleton = true
991
+ meth.name = "new"
992
+ meth.visibility = :public
993
+ end
2269
994
  end
2270
- end
2271
995
 
2272
- parse_statements(container, single, meth)
2273
-
2274
- remove_token_listener(meth)
996
+ parse_statements container, single, meth
997
+ end
2275
998
 
2276
999
  extract_call_seq comment, meth
2277
1000
 
2278
1001
  meth.comment = comment
1002
+
1003
+ @stats.add_method meth
2279
1004
  end
2280
1005
 
2281
1006
  def parse_method_or_yield_parameters(method = nil,
2282
1007
  modifiers = RDoc::METHOD_MODIFIERS)
2283
- skip_tkspace(false)
1008
+ skip_tkspace false
2284
1009
  tk = get_tk
2285
1010
 
2286
1011
  # Little hack going on here. In the statement
@@ -2324,6 +1049,8 @@ class RDoc::Parser::Ruby < RDoc::Parser
2324
1049
  @read.pop
2325
1050
  when TkCOMMENT then
2326
1051
  @read.pop
1052
+ when nil then
1053
+ break
2327
1054
  end
2328
1055
  tk = get_tk
2329
1056
  end
@@ -2348,52 +1075,47 @@ class RDoc::Parser::Ruby < RDoc::Parser
2348
1075
  method.params = res unless method.params
2349
1076
 
2350
1077
  if method.block_params.nil? then
2351
- skip_tkspace(false)
1078
+ skip_tkspace false
2352
1079
  read_documentation_modifiers method, RDoc::METHOD_MODIFIERS
2353
1080
  end
2354
1081
  end
2355
1082
 
2356
1083
  def parse_module(container, single, tk, comment)
2357
- container, name_t = get_class_or_module(container)
1084
+ container, name_t = get_class_or_module container
2358
1085
 
2359
1086
  name = name_t.name
2360
1087
 
2361
1088
  mod = container.add_module RDoc::NormalModule, name
2362
1089
  mod.record_location @top_level
2363
1090
 
2364
- @stats.add_module mod
2365
-
2366
1091
  read_documentation_modifiers mod, RDoc::CLASS_MODIFIERS
2367
1092
  parse_statements(mod)
2368
1093
  mod.comment = comment
1094
+
1095
+ @stats.add_module mod
2369
1096
  end
2370
1097
 
2371
1098
  def parse_require(context, comment)
2372
1099
  skip_tkspace_comment
2373
1100
  tk = get_tk
1101
+
2374
1102
  if TkLPAREN === tk then
2375
1103
  skip_tkspace_comment
2376
1104
  tk = get_tk
2377
1105
  end
2378
1106
 
2379
- name = nil
2380
- case tk
2381
- when TkSTRING
2382
- name = tk.text
2383
- # when TkCONSTANT, TkIDENTIFIER, TkIVAR, TkGVAR
2384
- # name = tk.name
2385
- when TkDSTRING
2386
- warn "Skipping require of dynamic string: #{tk.text}"
2387
- # else
2388
- # warn "'require' used as variable"
2389
- end
2390
- if name
1107
+ name = tk.text if TkSTRING === tk
1108
+
1109
+ if name then
2391
1110
  context.add_require RDoc::Require.new(name, comment)
2392
1111
  else
2393
- unget_tk(tk)
1112
+ unget_tk tk
2394
1113
  end
2395
1114
  end
2396
1115
 
1116
+ ##
1117
+ # The core of the ruby parser.
1118
+
2397
1119
  def parse_statements(container, single = NORMAL, current_method = nil,
2398
1120
  comment = '')
2399
1121
  nest = 1
@@ -2408,7 +1130,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
2408
1130
 
2409
1131
  case tk
2410
1132
  when TkNL then
2411
- skip_tkspace true # Skip blanks and newlines
1133
+ skip_tkspace
2412
1134
  tk = get_tk
2413
1135
 
2414
1136
  if TkCOMMENT === tk then
@@ -2422,8 +1144,9 @@ class RDoc::Parser::Ruby < RDoc::Parser
2422
1144
 
2423
1145
  while TkCOMMENT === tk do
2424
1146
  comment << tk.text << "\n"
2425
- tk = get_tk # this is the newline
2426
- skip_tkspace(false) # leading spaces
1147
+
1148
+ tk = get_tk # this is the newline
1149
+ skip_tkspace false # leading spaces
2427
1150
  tk = get_tk
2428
1151
  end
2429
1152
 
@@ -2466,11 +1189,11 @@ class RDoc::Parser::Ruby < RDoc::Parser
2466
1189
 
2467
1190
  when TkCONSTANT then
2468
1191
  if container.document_self then
2469
- parse_constant container, single, tk, comment
1192
+ parse_constant container, tk, comment
2470
1193
  end
2471
1194
 
2472
1195
  when TkALIAS then
2473
- if container.document_self then
1196
+ if container.document_self and not current_method then
2474
1197
  parse_alias container, single, tk, comment
2475
1198
  end
2476
1199
 
@@ -2510,12 +1233,18 @@ class RDoc::Parser::Ruby < RDoc::Parser
2510
1233
  when /^attr_(reader|writer|accessor)$/ then
2511
1234
  parse_attr_accessor container, single, tk, comment
2512
1235
  when 'alias_method' then
2513
- if container.document_self then
2514
- parse_alias container, single, tk, comment
2515
- end
1236
+ parse_alias container, single, tk, comment if
1237
+ container.document_self
1238
+ when 'require', 'include' then
1239
+ # ignore
2516
1240
  else
2517
1241
  if container.document_self and comment =~ /\A#\#$/ then
2518
- parse_meta_method container, single, tk, comment
1242
+ case comment
1243
+ when /^# +:?attr(_reader|_writer|_accessor)?:/ then
1244
+ parse_meta_attr container, single, tk, comment
1245
+ else
1246
+ parse_meta_method container, single, tk, comment
1247
+ end
2519
1248
  end
2520
1249
  end
2521
1250
  end
@@ -2532,16 +1261,18 @@ class RDoc::Parser::Ruby < RDoc::Parser
2532
1261
  if nest == 0 then
2533
1262
  read_documentation_modifiers container, RDoc::CLASS_MODIFIERS
2534
1263
  container.ongoing_visibility = save_visibility
1264
+
1265
+ parse_comment container, tk, comment unless comment.empty?
1266
+
2535
1267
  return
2536
1268
  end
2537
-
2538
1269
  end
2539
1270
 
2540
1271
  comment = '' unless keep_comment
2541
1272
 
2542
1273
  begin
2543
1274
  get_tkread
2544
- skip_tkspace(false)
1275
+ skip_tkspace false
2545
1276
  end while peek_tk == TkNL
2546
1277
  end
2547
1278
  end
@@ -2576,7 +1307,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
2576
1307
  end
2577
1308
 
2578
1309
  loop do
2579
- skip_tkspace(false)
1310
+ skip_tkspace false
2580
1311
 
2581
1312
  tk1 = get_tk
2582
1313
  unless TkCOMMA === tk1 then
@@ -2632,7 +1363,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
2632
1363
  singleton = true
2633
1364
  :public
2634
1365
  else
2635
- raise "Invalid visibility: #{tk.name}"
1366
+ raise RDoc::Error, "Invalid visibility: #{tk.name}"
2636
1367
  end
2637
1368
 
2638
1369
  skip_tkspace_comment false
@@ -2686,18 +1417,6 @@ class RDoc::Parser::Ruby < RDoc::Parser
2686
1417
  end
2687
1418
  end
2688
1419
 
2689
- def peek_read
2690
- @read.join('')
2691
- end
2692
-
2693
- ##
2694
- # Peek at the next token, but don't remove it from the stream
2695
-
2696
- def peek_tk
2697
- unget_tk(tk = get_tk)
2698
- tk
2699
- end
2700
-
2701
1420
  ##
2702
1421
  # Directives are modifier comments that can appear after class, module, or
2703
1422
  # method names. For example:
@@ -2762,40 +1481,40 @@ class RDoc::Parser::Ruby < RDoc::Parser
2762
1481
  comment.sub!(/^#--\n.*/m, '')
2763
1482
  end
2764
1483
 
2765
- def remove_token_listener(obj)
2766
- @token_listeners.delete(obj)
2767
- end
2768
-
2769
- def reset
2770
- @tokens = []
2771
- @unget_read = []
2772
- @read = []
2773
- end
2774
-
2775
1484
  def scan
2776
1485
  reset
2777
1486
 
2778
- catch(:eof) do
2779
- catch(:enddoc) do
1487
+ catch :eof do
1488
+ catch :enddoc do
2780
1489
  begin
2781
- parse_top_level_statements(@top_level)
2782
- rescue Exception => e
2783
- $stderr.puts <<-EOF
2784
-
2785
-
2786
- RDoc failure in #{@file_name} at or around line #{@scanner.line_no} column
2787
- #{@scanner.char_no}
1490
+ parse_top_level_statements @top_level
1491
+ rescue StandardError => e
1492
+ bytes = ''
1493
+
1494
+ 20.times do @scanner.ungetc end
1495
+ count = 0
1496
+ 60.times do |i|
1497
+ count = i
1498
+ byte = @scanner.getc
1499
+ break unless byte
1500
+ bytes << byte
1501
+ end
1502
+ count -= 20
1503
+ count.times do @scanner.ungetc end
2788
1504
 
2789
- Before reporting this, could you check that the file you're documenting
2790
- compiles cleanly--RDoc is not a full Ruby parser, and gets confused easily if
2791
- fed invalid programs.
1505
+ $stderr.puts <<-EOF
2792
1506
 
2793
- The internal error was:
1507
+ #{self.class} failure around line #{@scanner.line_no} of
1508
+ #{@file_name}
2794
1509
 
2795
1510
  EOF
2796
1511
 
2797
- e.set_backtrace(e.backtrace[0,4])
2798
- raise
1512
+ unless bytes.empty? then
1513
+ $stderr.puts
1514
+ $stderr.puts bytes.inspect
1515
+ end
1516
+
1517
+ raise e
2799
1518
  end
2800
1519
  end
2801
1520
  end
@@ -2807,7 +1526,7 @@ The internal error was:
2807
1526
  # while, until, and for have an optional do
2808
1527
 
2809
1528
  def skip_optional_do_after_expression
2810
- skip_tkspace(false)
1529
+ skip_tkspace false
2811
1530
  tk = get_tk
2812
1531
  case tk
2813
1532
  when TkLPAREN, TkfLPAREN
@@ -2834,10 +1553,12 @@ The internal error was:
2834
1553
  else
2835
1554
  break unless @scanner.continue
2836
1555
  end
1556
+ when nil then
1557
+ break
2837
1558
  end
2838
1559
  tk = get_tk
2839
1560
  end
2840
- skip_tkspace(false)
1561
+ skip_tkspace false
2841
1562
 
2842
1563
  get_tk if TkDO === peek_tk
2843
1564
  end
@@ -2846,31 +1567,17 @@ The internal error was:
2846
1567
  # skip the var [in] part of a 'for' statement
2847
1568
 
2848
1569
  def skip_for_variable
2849
- skip_tkspace(false)
1570
+ skip_tkspace false
2850
1571
  tk = get_tk
2851
- skip_tkspace(false)
1572
+ skip_tkspace false
2852
1573
  tk = get_tk
2853
1574
  unget_tk(tk) unless TkIN === tk
2854
1575
  end
2855
1576
 
2856
- def skip_method(container)
1577
+ def skip_method container
2857
1578
  meth = RDoc::AnyMethod.new "", "anon"
2858
- parse_method_parameters(meth)
2859
- parse_statements(container, false, meth)
2860
- end
2861
-
2862
- ##
2863
- # Skip spaces
2864
-
2865
- def skip_tkspace(skip_nl = true)
2866
- tokens = []
2867
-
2868
- while TkSPACE === (tk = get_tk) or (skip_nl and TkNL === tk) do
2869
- tokens.push tk
2870
- end
2871
-
2872
- unget_tk(tk)
2873
- tokens
1579
+ parse_method_parameters meth
1580
+ parse_statements container, false, meth
2874
1581
  end
2875
1582
 
2876
1583
  ##
@@ -2878,22 +1585,12 @@ The internal error was:
2878
1585
 
2879
1586
  def skip_tkspace_comment(skip_nl = true)
2880
1587
  loop do
2881
- skip_tkspace(skip_nl)
1588
+ skip_tkspace skip_nl
2882
1589
  return unless TkCOMMENT === peek_tk
2883
1590
  get_tk
2884
1591
  end
2885
1592
  end
2886
1593
 
2887
- def unget_tk(tk)
2888
- @tokens.unshift tk
2889
- @unget_read.unshift @read.pop
2890
-
2891
- # Remove this token from any listeners
2892
- @token_listeners.each do |obj|
2893
- obj.pop_token
2894
- end if @token_listeners
2895
- end
2896
-
2897
1594
  def warn(msg)
2898
1595
  return if @options.quiet
2899
1596
  msg = make_message msg