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.
- data.tar.gz.sig +1 -0
- data/History.txt +30 -0
- data/Manifest.txt +18 -6
- data/Rakefile +52 -0
- data/lib/rdoc.rb +69 -69
- data/lib/rdoc/code_objects.rb +331 -112
- data/lib/rdoc/generator.rb +172 -144
- data/lib/rdoc/generator/html.rb +45 -18
- data/lib/rdoc/generator/html/frameless.rb +795 -0
- data/lib/rdoc/generator/html/hefss.rb +11 -11
- data/lib/rdoc/generator/html/html.rb +81 -87
- data/lib/rdoc/generator/html/kilmer.rb +10 -10
- data/lib/rdoc/generator/html/one_page_html.rb +9 -9
- data/lib/rdoc/generator/ri.rb +5 -8
- data/lib/rdoc/generator/texinfo.rb +84 -0
- data/lib/rdoc/generator/texinfo/class.texinfo.erb +44 -0
- data/lib/rdoc/generator/texinfo/file.texinfo.erb +6 -0
- data/lib/rdoc/generator/texinfo/method.texinfo.erb +6 -0
- data/lib/rdoc/generator/texinfo/texinfo.erb +28 -0
- data/lib/rdoc/known_classes.rb +69 -0
- data/lib/rdoc/markup.rb +3 -3
- data/lib/rdoc/markup/attribute_manager.rb +0 -9
- data/lib/rdoc/markup/fragments.rb +1 -1
- data/lib/rdoc/markup/preprocess.rb +10 -6
- data/lib/rdoc/markup/to_html.rb +55 -8
- data/lib/rdoc/markup/to_html_crossref.rb +21 -5
- data/lib/rdoc/markup/to_texinfo.rb +69 -0
- data/lib/rdoc/options.rb +37 -14
- data/lib/rdoc/parser.rb +109 -0
- data/lib/rdoc/parser/c.rb +656 -0
- data/lib/rdoc/parser/f95.rb +1835 -0
- data/lib/rdoc/{parsers/parse_rb.rb → parser/ruby.rb} +1436 -1191
- data/lib/rdoc/parser/simple.rb +38 -0
- data/lib/rdoc/rdoc.rb +48 -32
- data/lib/rdoc/ri.rb +5 -1
- data/lib/rdoc/ri/descriptions.rb +8 -5
- data/lib/rdoc/ri/driver.rb +148 -49
- data/lib/rdoc/stats.rb +94 -4
- data/test/test_rdoc_info_formatting.rb +175 -0
- data/test/test_rdoc_info_sections.rb +136 -0
- data/test/test_rdoc_markup_to_html.rb +30 -0
- data/test/test_rdoc_markup_to_html_crossref.rb +18 -0
- data/test/{test_rdoc_c_parser.rb → test_rdoc_parser_c.rb} +8 -11
- data/test/test_rdoc_parser_ruby.rb +539 -0
- data/test/test_rdoc_ri_default_display.rb +17 -16
- data/test/test_rdoc_ri_driver.rb +92 -0
- metadata +54 -12
- metadata.gz.sig +0 -0
- data/lib/rdoc/parsers/parse_c.rb +0 -775
- data/lib/rdoc/parsers/parse_f95.rb +0 -1841
- data/lib/rdoc/parsers/parse_simple.rb +0 -40
- data/lib/rdoc/parsers/parserfactory.rb +0 -99
@@ -1,34 +1,28 @@
|
|
1
|
-
|
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
|
5
|
+
# ruby-lex.rb - ruby lexcal analyzer
|
12
6
|
# ruby-token.rb - ruby tokens
|
13
|
-
#
|
7
|
+
# by Keiju ISHITSUKA (Nippon Rational Inc.)
|
14
8
|
#
|
15
9
|
|
16
|
-
require
|
17
|
-
require
|
18
|
-
|
19
|
-
require "rdoc/code_objects"
|
20
|
-
require "rdoc/tokenstream"
|
10
|
+
require 'e2mmap'
|
11
|
+
require 'irb/slex'
|
21
12
|
|
22
|
-
require
|
23
|
-
|
24
|
-
require
|
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
|
-
|
51
|
-
|
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
|
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 =
|
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,
|
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,
|
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,
|
146
|
+
[:TkTHEN, TkKW, "then", EXPR_BEG],
|
144
147
|
[:TkELSIF, TkKW, "elsif", EXPR_BEG],
|
145
|
-
[:TkELSE,
|
146
|
-
[:TkCASE,
|
147
|
-
[:TkWHEN,
|
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,
|
153
|
+
[:TkFOR, TkKW, "for", EXPR_BEG],
|
151
154
|
[:TkBREAK, TkKW, "break", EXPR_END],
|
152
|
-
[:TkNEXT,
|
153
|
-
[:TkREDO,
|
155
|
+
[:TkNEXT, TkKW, "next", EXPR_END],
|
156
|
+
[:TkREDO, TkKW, "redo", EXPR_END],
|
154
157
|
[:TkRETRY, TkKW, "retry", EXPR_END],
|
155
|
-
[:TkIN,
|
156
|
-
[:TkDO,
|
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,
|
161
|
-
[:TkNIL,
|
162
|
-
[:TkTRUE,
|
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,
|
165
|
-
[:TkOR,
|
166
|
-
[:TkNOT,
|
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,
|
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,
|
180
|
-
[:TkGVAR,
|
181
|
-
[:TkIVAR,
|
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,
|
200
|
-
[:TkCMP,
|
201
|
-
[:TkEQ,
|
202
|
-
[:TkEQQ,
|
203
|
-
[:TkNEQ,
|
204
|
-
[:TkGEQ,
|
205
|
-
[:TkLEQ,
|
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,
|
210
|
+
[:TkOROP, TkOp, "||"],
|
208
211
|
[:TkMATCH, TkOp, "=~"],
|
209
212
|
[:TkNMATCH, TkOp, "!~"],
|
210
|
-
[:TkDOT2,
|
211
|
-
[:TkDOT3,
|
212
|
-
[:TkAREF,
|
213
|
-
[:TkASET,
|
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,
|
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,
|
231
|
-
[:TkLT,
|
232
|
-
[:TkPLUS,
|
233
|
+
[:TkGT, TkOp, ">"],
|
234
|
+
[:TkLT, TkOp, "<"],
|
235
|
+
[:TkPLUS, TkOp, "+"],
|
233
236
|
[:TkMINUS, TkOp, "-"],
|
234
|
-
[:TkMULT,
|
235
|
-
[:TkDIV,
|
236
|
-
[:TkMOD,
|
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,
|
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,
|
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
|
272
|
-
token_n = token_n.id2name unless token_n
|
273
|
-
|
274
|
-
|
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
|
-
|
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
|
-
|
288
|
+
TkReading2Token[reading] = [token_c]
|
287
289
|
else
|
288
|
-
|
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
|
-
|
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
|
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 ((
|
523
|
-
|
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
|
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
|
-
|
540
|
-
|
541
|
-
rescue SyntaxError
|
542
|
-
|
543
|
-
|
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
|
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
|
-
|
646
|
+
@continue = TRUE
|
643
647
|
else
|
644
|
-
|
645
|
-
|
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
|
-
|
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
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
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
|
-
|
690
|
+
Token(op).set_text(op)
|
687
691
|
else
|
688
|
-
|
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
|
-
|
696
|
-
|
699
|
+
@lex_state = EXPR_BEG
|
700
|
+
Token(TkQUESTION).set_text(op)
|
697
701
|
else
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
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
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
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
|
-
|
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
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
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
|
-
|
759
|
-
|
762
|
+
ungetc
|
763
|
+
identify_number("")
|
760
764
|
else
|
761
|
-
|
762
|
-
|
763
|
-
|
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
|
-
|
787
|
-
|
790
|
+
@lex_state = EXPR_BEG
|
791
|
+
tk = Token(TkCOLON)
|
788
792
|
else
|
789
|
-
|
790
|
-
|
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
|
-
|
799
|
-
|
801
|
+
@lex_state = EXPR_BEG
|
802
|
+
tk = Token(TkCOLON3)
|
800
803
|
else
|
801
|
-
|
802
|
-
|
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
|
-
|
813
|
+
identify_string(op)
|
811
814
|
elsif peek(0) == '='
|
812
|
-
|
813
|
-
|
814
|
-
|
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
|
-
|
819
|
+
identify_string(op)
|
817
820
|
else
|
818
|
-
|
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
|
-
|
853
|
-
|
850
|
+
@lex_state = EXPR_BEG
|
851
|
+
tk = Token(TkfLPAREN)
|
854
852
|
else
|
855
|
-
|
856
|
-
|
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
|
-
|
870
|
+
t = Token(TkfLBRACK)
|
873
871
|
else
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
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
|
-
|
887
|
+
t = Token(TkLBRACE)
|
890
888
|
else
|
891
|
-
|
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
|
-
|
900
|
-
|
901
|
-
|
897
|
+
@space_seen = true
|
898
|
+
@continue = true
|
899
|
+
Token(TkSPACE).set_text("\\\n")
|
902
900
|
else
|
903
|
-
|
904
|
-
|
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
|
-
|
909
|
+
identify_quotation('%')
|
912
910
|
elsif peek(0) == '='
|
913
|
-
|
914
|
-
|
911
|
+
getc
|
912
|
+
Token(TkOPASGN, "%").set_text("%=")
|
915
913
|
elsif @lex_state == EXPR_ARG and @space_seen and peek(0) !~ /\s/
|
916
|
-
|
914
|
+
identify_quotation('%')
|
917
915
|
else
|
918
|
-
|
919
|
-
|
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
|
-
|
930
|
-
|
927
|
+
ungetc
|
928
|
+
identify_identifier
|
931
929
|
else
|
932
|
-
|
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
|
-
|
942
|
+
t = identify_number("")
|
955
943
|
elsif peek(0) =~ /[\w_]/
|
956
|
-
|
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
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
1089
|
+
reserve << ch
|
1104
1090
|
elsif ch == "\n"
|
1105
|
-
|
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
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1167
|
+
type = TkFLOAT
|
1168
|
+
if peek(0) !~ /[0-9]/
|
1169
|
+
ungetc
|
1170
|
+
break
|
1171
|
+
end
|
1186
1172
|
str << ch
|
1187
|
-
|
1173
|
+
allow_point = false
|
1188
1174
|
|
1189
1175
|
when allow_e && "e", allow_e && "E"
|
1190
1176
|
str << ch
|
1191
|
-
|
1192
|
-
|
1193
|
-
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1177
|
+
type = TkFLOAT
|
1178
|
+
if peek(0) =~ /[+-]/
|
1179
|
+
str << getc
|
1180
|
+
end
|
1181
|
+
allow_e = false
|
1182
|
+
allow_point = false
|
1197
1183
|
else
|
1198
|
-
|
1199
|
-
|
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
|
-
|
1218
|
-
|
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
|
-
|
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
|
-
|
1235
|
-
|
1236
|
-
|
1220
|
+
elsif ch == '\\' #'
|
1221
|
+
str << read_escape
|
1222
|
+
end
|
1237
1223
|
end
|
1238
1224
|
if @ltype == "/"
|
1239
|
-
|
1240
|
-
|
1241
|
-
|
1225
|
+
if peek(0) =~ /i|o|n|e|s/
|
1226
|
+
str << getc
|
1227
|
+
end
|
1242
1228
|
end
|
1243
1229
|
if subtype
|
1244
|
-
|
1230
|
+
Token(DLtype2Token[ltype], str)
|
1245
1231
|
else
|
1246
|
-
|
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
|
-
|
1300
|
-
|
1301
|
-
|
1302
|
-
|
1303
|
-
|
1304
|
-
|
1305
|
-
|
1306
|
-
|
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
|
-
|
1314
|
-
|
1315
|
-
|
1316
|
-
|
1317
|
-
|
1318
|
-
|
1319
|
-
|
1320
|
-
|
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
|
-
|
1313
|
+
ungetc
|
1328
1314
|
else
|
1329
1315
|
res << ch
|
1330
|
-
|
1316
|
+
if (ch = getc) == "\\" #"
|
1331
1317
|
res << ch
|
1332
|
-
|
1318
|
+
res << read_escape
|
1333
1319
|
else
|
1334
1320
|
res << ch
|
1335
|
-
|
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
|
-
|
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
|
-
#
|
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::
|
1459
|
+
class RDoc::Parser::Ruby < RDoc::Parser
|
1365
1460
|
|
1366
|
-
|
1367
|
-
include RDoc::TokenStream
|
1461
|
+
parse_files_matching(/\.rbw?$/)
|
1368
1462
|
|
1369
|
-
|
1463
|
+
include RDoc::RubyToken
|
1464
|
+
include RDoc::TokenStream
|
1370
1465
|
|
1371
|
-
|
1466
|
+
NORMAL = "::"
|
1467
|
+
SINGLE = "<<"
|
1372
1468
|
|
1373
1469
|
def initialize(top_level, file_name, content, options, stats)
|
1374
|
-
|
1375
|
-
|
1470
|
+
super
|
1471
|
+
|
1376
1472
|
@size = 0
|
1377
1473
|
@token_listeners = nil
|
1378
|
-
@
|
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
|
-
|
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
|
-
|
1539
|
-
|
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
|
-
|
1546
|
-
|
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
|
-
|
1514
|
+
|
1515
|
+
unget_tk tk
|
1516
|
+
|
1553
1517
|
res
|
1554
1518
|
end
|
1555
1519
|
|
1556
|
-
def
|
1557
|
-
|
1558
|
-
|
1559
|
-
|
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
|
-
|
1564
|
-
|
1565
|
-
|
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
|
-
|
1575
|
-
|
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
|
-
|
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
|
-
|
1549
|
+
unget_tk tk
|
1550
|
+
true
|
1765
1551
|
end
|
1766
1552
|
end
|
1767
1553
|
|
1768
|
-
|
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
|
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
|
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
|
-
|
1811
|
-
|
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
|
-
|
1816
|
-
|
1817
|
-
|
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
|
-
|
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
|
-
|
1836
|
-
|
1837
|
-
|
1838
|
-
|
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
|
1857
|
-
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
|
-
|
1868
|
-
|
1869
|
-
|
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
|
-
|
1618
|
+
def get_constant
|
1619
|
+
res = ""
|
1878
1620
|
skip_tkspace(false)
|
1879
|
-
|
1880
|
-
back_tk = skip_tkspace
|
1881
|
-
meth = nil
|
1882
|
-
added_container = false
|
1621
|
+
tk = get_tk
|
1883
1622
|
|
1884
|
-
|
1885
|
-
|
1886
|
-
|
1887
|
-
|
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
|
-
|
1903
|
-
|
1904
|
-
|
1905
|
-
|
1628
|
+
# if res.empty?
|
1629
|
+
# warn("Unexpected token #{tk} in constant")
|
1630
|
+
# end
|
1631
|
+
unget_tk(tk)
|
1632
|
+
res
|
1633
|
+
end
|
1906
1634
|
|
1907
|
-
|
1908
|
-
|
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
|
-
|
1929
|
-
|
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
|
-
|
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
|
-
|
1945
|
-
|
1946
|
-
|
1947
|
-
|
1948
|
-
|
1949
|
-
|
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
|
-
|
1952
|
-
|
1953
|
-
|
1954
|
-
|
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
|
-
|
1958
|
-
|
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
|
1961
|
-
|
1962
|
-
|
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
|
-
|
1965
|
-
|
1966
|
-
meth.visibility = :public
|
1698
|
+
warn("':' not followed by identifier or operator")
|
1699
|
+
tk = tk1
|
1967
1700
|
end
|
1968
1701
|
end
|
1969
1702
|
|
1970
|
-
|
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
|
-
|
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
|
-
|
1975
|
-
|
1724
|
+
def look_for_directives_in(context, comment)
|
1725
|
+
preprocess = RDoc::Markup::PreProcess.new(@file_name,
|
1726
|
+
@options.rdoc_include)
|
1976
1727
|
|
1977
|
-
|
1978
|
-
|
1979
|
-
|
1980
|
-
|
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
|
-
|
1757
|
+
remove_private_comments(comment)
|
1984
1758
|
end
|
1985
1759
|
|
1986
|
-
def
|
1987
|
-
|
1988
|
-
|
1989
|
-
|
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
|
-
|
1993
|
-
|
1994
|
-
|
1995
|
-
|
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
|
-
|
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
|
2010
|
-
|
2011
|
-
|
2012
|
-
|
1790
|
+
def parse_attr_accessor(context, single, tk, comment)
|
1791
|
+
args = parse_symbol_arg
|
1792
|
+
read = get_tkread
|
1793
|
+
rw = "?"
|
2013
1794
|
|
2014
|
-
#
|
2015
|
-
|
2016
|
-
|
2017
|
-
|
2018
|
-
|
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
|
1862
|
+
when TkCOMMENT
|
2052
1863
|
unget_tk(tk)
|
2053
|
-
|
1864
|
+
break
|
2054
1865
|
end
|
2055
|
-
|
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
|
-
|
2063
|
-
|
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
|
-
|
2083
|
-
|
1876
|
+
case name_t
|
1877
|
+
when TkCONSTANT
|
1878
|
+
name = name_t.name
|
1879
|
+
superclass = "Object"
|
2084
1880
|
|
2085
|
-
|
2086
|
-
|
2087
|
-
|
2088
|
-
|
2089
|
-
|
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
|
-
|
2112
|
-
|
1888
|
+
cls_type = single == SINGLE ? RDoc::SingleClass : RDoc::NormalClass
|
1889
|
+
cls = container.add_class cls_type, name, superclass
|
2113
1890
|
|
2114
|
-
|
2115
|
-
tk = get_tk
|
2116
|
-
return "self" if tk.kind_of?(TkSELF)
|
1891
|
+
@stats.add_class cls
|
2117
1892
|
|
2118
|
-
|
2119
|
-
|
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
|
-
|
2124
|
-
|
2125
|
-
end
|
1896
|
+
parse_statements cls
|
1897
|
+
cls.comment = comment
|
2126
1898
|
|
2127
|
-
|
2128
|
-
|
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
|
-
|
1912
|
+
@stats.add_class other
|
2131
1913
|
|
2132
|
-
|
1914
|
+
read_documentation_modifiers other, RDoc::CLASS_MODIFIERS
|
1915
|
+
parse_statements(other, SINGLE)
|
1916
|
+
end
|
2133
1917
|
|
2134
|
-
|
2135
|
-
|
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
|
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
|
2165
|
-
|
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
|
-
|
2173
|
-
|
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
|
-
|
2183
|
-
|
1969
|
+
con = RDoc::Constant.new name, res, comment
|
1970
|
+
read_documentation_modifiers con, RDoc::CONSTANT_MODIFIERS
|
2184
1971
|
|
2185
|
-
|
2186
|
-
|
2187
|
-
|
2188
|
-
|
1972
|
+
if con.document_self
|
1973
|
+
container.add_constant(con)
|
1974
|
+
end
|
1975
|
+
end
|
2189
1976
|
|
2190
|
-
|
2191
|
-
|
2192
|
-
|
1977
|
+
def parse_comment(container, tk, comment)
|
1978
|
+
line_no = tk.line_no
|
1979
|
+
column = tk.char_no
|
2193
1980
|
|
2194
|
-
|
2195
|
-
|
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
|
-
|
2199
|
-
|
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
|
-
|
1992
|
+
@stats.add_method meth
|
2206
1993
|
|
2207
|
-
|
2208
|
-
|
2209
|
-
|
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
|
-
|
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
|
-
|
2219
|
-
|
2220
|
-
|
2221
|
-
|
2222
|
-
|
2223
|
-
|
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
|
-
|
2227
|
-
|
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
|
-
|
2238
|
-
|
2239
|
-
|
2240
|
-
|
2241
|
-
|
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
|
-
|
2255
|
-
|
2022
|
+
##
|
2023
|
+
# Parses a meta-programmed method
|
2256
2024
|
|
2257
|
-
|
2025
|
+
def parse_meta_method(container, single, tk, comment)
|
2026
|
+
line_no = tk.line_no
|
2027
|
+
column = tk.char_no
|
2258
2028
|
|
2259
|
-
|
2260
|
-
|
2029
|
+
start_collecting_tokens
|
2030
|
+
add_token tk
|
2031
|
+
add_token_listener self
|
2261
2032
|
|
2262
|
-
|
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
|
-
|
2269
|
-
context.document_self = true
|
2270
|
-
context.force_documentation = true
|
2035
|
+
singleton = !!comment.sub!(/(^# +:?)(singleton-)(method:)/, '\1\3')
|
2271
2036
|
|
2272
|
-
|
2273
|
-
unless
|
2274
|
-
|
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
|
-
|
2052
|
+
end
|
2277
2053
|
|
2278
|
-
|
2279
|
-
|
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
|
-
|
2291
|
-
preprocess = RDoc::Markup::PreProcess.new(@input_file_name,
|
2292
|
-
@options.rdoc_include)
|
2059
|
+
remove_token_listener self
|
2293
2060
|
|
2294
|
-
|
2295
|
-
|
2296
|
-
|
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
|
-
|
2305
|
-
|
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
|
-
|
2310
|
-
@options.main_page = param
|
2311
|
-
""
|
2069
|
+
add_token_listener meth
|
2312
2070
|
|
2313
|
-
|
2314
|
-
@options.title = param
|
2315
|
-
""
|
2071
|
+
meth.params = ''
|
2316
2072
|
|
2317
|
-
|
2318
|
-
context.set_current_section(param, comment)
|
2319
|
-
comment.replace ''
|
2320
|
-
break
|
2073
|
+
extract_call_seq comment, meth
|
2321
2074
|
|
2322
|
-
|
2323
|
-
|
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
|
-
|
2329
|
-
end
|
2092
|
+
remove_token_listener meth
|
2330
2093
|
|
2331
|
-
|
2332
|
-
comment.gsub!(/^#--.*?^#\+\+/m, '')
|
2333
|
-
comment.sub!(/^#--.*/m, '')
|
2094
|
+
meth.comment = comment
|
2334
2095
|
end
|
2335
2096
|
|
2336
|
-
|
2337
|
-
|
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
|
2351
|
-
|
2352
|
-
|
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
|
-
|
2366
|
-
|
2367
|
-
|
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
|
-
|
2373
|
-
parse_method_or_yield_parameters
|
2374
|
-
end
|
2108
|
+
@scanner.instance_eval do @lex_state = EXPR_FNAME end
|
2375
2109
|
|
2376
|
-
|
2377
|
-
|
2378
|
-
|
2379
|
-
|
2380
|
-
|
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
|
-
|
2385
|
-
|
2386
|
-
|
2387
|
-
|
2388
|
-
|
2389
|
-
|
2390
|
-
|
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
|
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
|
2411
|
-
|
2412
|
-
|
2413
|
-
|
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
|
-
|
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
|
-
|
2437
|
-
|
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
|
-
|
2459
|
-
|
2460
|
-
|
2461
|
-
|
2462
|
-
|
2463
|
-
|
2464
|
-
|
2465
|
-
|
2466
|
-
|
2467
|
-
|
2468
|
-
|
2469
|
-
|
2470
|
-
|
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
|
-
|
2474
|
-
|
2475
|
-
|
2476
|
-
|
2477
|
-
|
2478
|
-
|
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
|
-
|
2490
|
-
|
2491
|
-
read = get_tkread
|
2492
|
-
rw = "?"
|
2357
|
+
unless comment.empty? then
|
2358
|
+
look_for_directives_in container, comment
|
2493
2359
|
|
2494
|
-
|
2360
|
+
if container.done_documenting then
|
2361
|
+
container.ongoing_visibility = save_visibility
|
2362
|
+
end
|
2363
|
+
end
|
2495
2364
|
|
2496
|
-
|
2497
|
-
|
2498
|
-
|
2365
|
+
keep_comment = true
|
2366
|
+
else
|
2367
|
+
non_comment_seen = true
|
2368
|
+
end
|
2499
2369
|
|
2500
|
-
|
2501
|
-
|
2502
|
-
|
2503
|
-
|
2504
|
-
|
2505
|
-
|
2506
|
-
|
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
|
-
|
2509
|
-
att = RDoc::Attr.new get_tkread, name, rw, comment
|
2510
|
-
context.add_attribute att
|
2511
|
-
end
|
2512
|
-
end
|
2465
|
+
end
|
2513
2466
|
|
2514
|
-
|
2515
|
-
|
2516
|
-
|
2517
|
-
|
2518
|
-
|
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
|
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
|
|