1 # $Id: parser.rb,v 1.3 2011/11/28 11:06:05 machan Exp $
2
3 require 'tmdoc/tmstd'
4 require 'tmdoc/constant'
5 require 'tmdoc/environment'
6 require 'tmdoc/model/core'
7 require 'tmdoc/reader/ruby1.8/scanner'
8 require 'tmdoc/reader/ruby1.8/parser/node'
9 require 'tmdoc/reader/ruby1.8/parser/leaf'
10
11
12 module TmDoc
13
14 module Reader::Ruby18
15
16 module Parser
17
18 module_function
19
20
21 def parse(scanner, env)
22 ASSERT.kind_of scanner, Scanner
23 ASSERT.kind_of env, ENV::Environment
24
25 mc_subjects = Statements.parse(
26 scanner,
27 MCLP::AbsolutePath.new_root,
28 Context.new,
29 env
30 )
31 ASSERT.kind_of mc_subjects, MCLA::SetOfSubject
32
33 MCLN::ToplevelModule.new(mc_subjects)
34 end
35
36
37
38 module Statements
39 include RubyToken
40
41 module_function
42
43 def parse(scanner, above_path, context, env)
44 ASSERT.kind_of scanner, Scanner
45 ASSERT.kind_of above_path, MCLP::AbsolutePath
46 ASSERT.kind_of context, Context
47 ASSERT.kind_of env, ENV::Environment
48
49 LOG::Debug.msgout "CALLED " +
50 "above_path='#{above_path}'" if env.debug_parser?
51
52 mc_subjects = MCLA::SetOfSubject.new
53 nest = 1
54 prev_tk = nil
55 while tk = scanner.get!
56 new_mc_subjects =
57 case tk
58
59 when TkMODULE # 'module'
60 if context.in_unique_class?
61 LOG::Warning.log(
62 "I can't parse module definiation " +
63 "in unique class definiation.\n" +
64 "\t-- #%d in '%s'",
65 name,
66 tk.line_no, scanner.file_name
67 )
68 CMD.test_sensitive_level env, LOG::Warning
69
70 skip_tokens(scanner, env)
71
72 mc_subjects
73 else
74 mc_module = Node::Module.parse(
75 scanner, above_path, context, env, tk
76 )
77
78 if mc_module
79 mc_subjects << mc_module
80 else
81 skip_tokens(scanner, env)
82
83 mc_subjects
84 end
85 end
86
87 when TkCLASS # 'class'
88 if context.in_unique_class?
89 LOG::Warning.log(
90 "I can't parse class definiation " +
91 "in unique class definiation.\n" +
92 "\t-- #%d in '%s'",
93 tk.line_no, scanner.file_name
94 )
95 CMD.test_sensitive_level env, LOG::Warning
96
97 skip_tokens(scanner, env)
98
99 mc_subjects
100 else
101 msub = Node::Class.parse(
102 scanner, above_path, context, env, tk
103 )
104
105 if msub
106 mc_subjects << msub
107 else
108 skip_tokens(scanner, env)
109
110 mc_subjects
111 end
112 end
113
114 when TkDEF # 'def'
115 mc_method = Node::Method.parse(
116 scanner, above_path, context, env, tk
117 )
118
119 if mc_method
120 mc_subjects << mc_method
121 else
122 skip_tokens(scanner, env)
123
124 mc_subjects
125 end
126
127 when TkCONSTANT
128 mc_constant = Leaf.parse_constant(
129 scanner, above_path, context, env, tk
130 )
131
132 if mc_constant
133 mc_subjects << mc_constant
134 else
135 mc_subjects
136 end
137
138 when TkALIAS # 'alias'
139 mc_alias = Leaf.parse_alias(
140 scanner, above_path, context, env, tk
141 )
142
143 if mc_alias
144 mc_subjects << mc_alias
145 else
146 mc_subjects
147 end
148
149 when TkIDENTIFIER
150 case prev_tk
151 when TkDOT
152 LOG::Debug.log(
153 "TkIDENTIFIER(%s) at #%d [#%d]",
154 tk.name,
155 tk.line_no,
156 __LINE__
157 ) if env.debug_parser?
158
159 mc_subjects
160
161 else
162 msub, context = parse_identifier(
163 tk, scanner, above_path, context, env
164 )
165
166 if msub
167 mc_subjects << msub
168 else
169 mc_subjects
170 end
171 end
172
173 when TkCASE, # 'case'
174 TkDO, # 'do'
175 TkFOR, # 'for'
176 TkIF, # 'if'
177 TkUNLESS, # 'unless'
178 TkUNTIL, # 'until'
179 TkWHILE, # 'while'
180 TkBEGIN # 'begin'
181 nest += 1
182
183 mc_subjects
184
185 when TkEND # 'end'
186 nest -= 1
187 LOG::Debug.log(
188 "Found 'end' on #{above_path.to_s}, " +
189 "nest=#{nest}, " +
190 "line #{tk.line_no}"
191 ) if env.debug_parser?
192 if nest <= 0
193 ASSERT.kind_of mc_subjects, MCLA::SetOfSubject
194
195 return mc_subjects
196 end
197
198 mc_subjects
199
200 else
201 LOG::Debug.log(
202 "%s at #%d [#%d]",
203 tk.class, tk.line_no, __LINE__
204 ) if env.debug_parser?
205
206 mc_subjects
207 end
208 mc_subjects = new_mc_subjects
209 prev_tk = tk
210
211 begin
212 scanner.get_readed!
213 scanner.skip_space!
214 end while scanner.peek == TkNL
215 end
216
217 ASSERT.kind_of mc_subjects, MCLA::SetOfSubject
218 end
219
220
221
222 def parse_identifier(tk, scanner, above_path, context, env)
223 ASSERT.kind_of tk, TkIDENTIFIER
224 ASSERT.kind_of scanner, Scanner
225 ASSERT.kind_of above_path, MCLP::AbsolutePath
226 ASSERT.kind_of context, Context
227 ASSERT.kind_of env, ENV::Environment
228
229 LOG::Debug.msgout "CALLED name #{tk.name}, " +
230 "above_path='#{above_path}'" if env.debug_parser?
231
232 mc_subject, new_context =
233 case tk.name
234 when 'require'
235 [Leaf.parse_require(scanner, above_path, env), context]
236
237 when 'extend'
238 if context.in_unique_class?
239 LOG::Warning.log(
240 "I can't parse module extending " +
241 "in unique class.\n" +
242 "\t-- #%d in '%s'",
243 name,
244 tk.line_no, scanner.file_name
245 )
246 CMD.test_sensitive_level env, LOG::Warning
247
248 [nil, context]
249 else
250 [
251 Leaf.parse_extend(scanner, above_path, env, tk),
252 context
253 ]
254 end
255
256 when 'include'
257 [
258 Leaf.parse_include(scanner, above_path, env, tk),
259 context
260 ]
261
262 when 'attr'
263 [
264 Leaf.parse_attribute(
265 scanner, above_path, context, env, tk, nil
266 ),
267 context
268 ]
269
270 when /^attr_(reader|writer|accessor)$/
271 [
272 Leaf.parse_attribute(
273 scanner, above_path, context, env, tk, $1
274 ),
275 context
276 ]
277
278 when /^module_function$/
279 msub = Leaf.parse_module_func(
280 scanner, above_path, context, env, tk
281 )
282
283 if msub
284 [msub, context]
285 else
286
287 [nil, context.update_module_func(true)]
288 end
289
290 else
291 LOG::Debug.log(
292 "TkIDENTIFIER(%s) at #%d [#%d]",
293 tk.name,
294 tk.line_no,
295 __LINE__
296 ) if env.debug_parser?
297
298 [nil, context]
299 end
300
301 ASSERT.opt_kind_of mc_subject, MCLA::Subject
302 ASSERT.kind_of new_context, Context
303 [mc_subject, new_context]
304 end
305
306
307
308 SKIPPED_TOKENS = [ :module,
309 :class,
310 :method,
311 :const,
312 :require,
313 :alias,
314 :extend,
315 :include,
316 :attr ]
317
318 def skip_tokens(scanner, env)
319 ASSERT.kind_of scanner, Scanner
320 ASSERT.kind_of env, ENV::Environment
321
322 LOG::Debug.msgout "CALLED" if env.debug_parser?
323 LOG::Debug.log "Begin skipping" if env.debug_parser?
324
325 map_of_skipping_token_sym_to_num = Hash[
326 *(
327 SKIPPED_TOKENS.map { |token_sym| [token_sym, 0] }
328 ).flatten
329 ]
330
331 skipping_nest = 1
332 while tk = scanner.get!
333 case tk
334 when TkMODULE
335 map_of_skipping_token_sym_to_num[:module] += 1
336 skipping_nest += 1
337
338 when TkCLASS
339 map_of_skipping_token_sym_to_num[:class] += 1
340 skipping_nest += 1
341
342 when TkDEF
343 map_of_skipping_token_sym_to_num[:method] += 1
344 skipping_nest += 1
345
346 when TkCONSTANT
347 map_of_skipping_token_sym_to_num[:const] += 1
348
349 when TkALIAS # 'alias'
350 map_of_skipping_token_sym_to_num[:alias] += 1
351
352 when TkIDENTIFIER
353 case tk.name
354 when "require"
355 map_of_skipping_token_sym_to_num[:require] += 1
356
357 when "extend"
358 map_of_skipping_token_sym_to_num[:extend] += 1
359
360 when "include"
361 map_of_skipping_token_sym_to_num[:include] += 1
362
363 when "attr", /^attr_(reader|writer|accessor)$/
364 map_of_skipping_token_sym_to_num[:attr] += 1
365
366 else
367 ; # Skip others ....
368 end
369
370 when TkCASE, # 'case'
371 TkDO, # 'do'
372 TkFOR, # 'for'
373 TkIF, # 'if'
374 TkUNLESS, # 'unless'
375 TkUNTIL, # 'until'
376 TkWHILE, # 'while'
377 TkBEGIN # 'begin'
378 skipping_nest += 1
379
380 when TkLBRACE, TkfLBRACE, TkLPAREN, TkfLPAREN
381 skipping_nest += 1
382
383 when TkRBRACE, TkRPAREN
384 skipping_nest -= 1
385
386 when TkEND # 'end'
387 skipping_nest -= 1
388 if skipping_nest <= 0
389 break
390 end
391
392 else
393 ; # Skip others ....
394 end
395 end
396
397 unless tk.kind_of?(TkEND)
398 scanner.unget! tk
399 end
400
401 if map_of_skipping_token_sym_to_num.values.any? { |num| num > 0 }
402 msg_args = map_of_skipping_token_sym_to_num.reject {
403 |sym, num|
404
405 num == 0
406 }.map { |sym, num| format("%s=%d", sym, num) }.join(', ')
407
408 LOG::Notice.log "==> Skipped tokens: %s", msg_args
409 CMD.test_sensitive_level env, LOG::Notice
410 end
411 LOG::Debug.log(
412 "End skipping[##{tk.line_no}]"
413 ) if env.debug_parser?
414
415 nil
416 end
417 end
418
419 end # TmDoc::Reader::Ruby18::Parser
420
421 end # TmDoc::Reader::Ruby18
422
423 end # TmDoc