1 # $Id: leaf.rb,v 1.3 2011/11/30 21:48:43 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/types'
9 require 'tmdoc/reader/ruby1.8/parser/common'
10
11
12 module TmDoc
13
14 module Reader::Ruby18
15
16 module Parser
17
18 module Leaf
19 include RubyToken
20
21 module_function
22
23 def parse_constant(scanner, above_path, context, env, c_tk)
24 ASSERT.kind_of scanner, Scanner
25 ASSERT.kind_of above_path, MCLP::AbsolutePath
26 ASSERT.kind_of context, Context
27 ASSERT.kind_of env, ENV::Environment
28 ASSERT.kind_of c_tk, TkCONSTANT
29
30 LOG::Debug.msgout "CALLED " +
31 "above_path='#{above_path.to_s}', " +
32 "tk=#{c_tk.inspect}" if env.debug_parser?
33
34 scanner.skip_space!
35 eq_tk = scanner.get!
36
37 unless eq_tk.kind_of?(TkASSIGN)
38 scanner.unget! eq_tk
39 return nil
40 end
41
42 nest = 0
43 scanner.get_readed!
44
45 tk = scanner.get!
46 if tk.kind_of? TkGT
47 scanner.unget! tk
48 scanner.unget! eq_tk
49 return nil
50 end
51
52 loop do
53 LOG::Debug.log("Param: #{tk}, #{nest}") if env.debug_parser?
54
55 case tk
56 when TkNL, TkSEMICOLON, TkCOMMENT
57 break
58 when TkLPAREN, TkfLPAREN
59 nest += 1
60 when TkRPAREN
61 nest -= 1
62 else
63 break unless tk # when EOF
64 end
65 tk = scanner.get!
66 end
67 value = scanner.get_readed!.tr("\n", " ").strip
68
69 mc_constant =
70 if context.in_unique_class?
71 LOG::Warning.log(
72 "I can't parse the constant definiation: <%s> " +
73 "in unique class.\n" +
74 "\t-- #%d in '%s'",
75 c_tk.name,
76 c_tk.line_no, scanner.file_name
77 )
78 CMD.test_sensitive_level env, LOG::Warning
79
80 nil
81 else
82 LOG::Debug.msgout("ACCEPT %s",
83 mc_constant.to_s
84 ) if env.debug_parser?
85
86 MCLL::Constant.new c_tk.line_no, c_tk.name, value
87 end
88
89 ASSERT.opt_kind_of mc_constant, MCLL::Constant
90 end
91
92
93
94 def parse_alias(scanner, above_path, context, env, a_tk)
95 ASSERT.kind_of scanner, Scanner
96 ASSERT.kind_of above_path, MCLP::AbsolutePath
97 ASSERT.kind_of context, Context
98 ASSERT.kind_of env, ENV::Environment
99 ASSERT.kind_of a_tk, TkALIAS
100
101 LOG::Debug.msgout "CALLED " +
102 "above_path='#{above_path.to_s}', " +
103 "a_tk=#{a_tk.inspect}" if env.debug_parser?
104
105 scanner.skip_space_or_nl!
106 got_tk = scanner.get!
107 LOG::Debug.log "got_tk=#{got_tk.inspect} " +
108 "[##{__LINE__}]" if env.debug_parser?
109 name =
110 if got_tk.respond_to?(:name)
111 got_tk.name
112 elsif got_tk.respond_to?(:value)
113 got_tk.value
114 else
115 LOG::Warning.log(
116 "I can't recognize a token: %s<%s> for alias name.\n" +
117 "\t-- #%d in '%s'",
118 if got_tk.respond_to?(:name)
119 got_tk.name
120 else
121 ''
122 end,
123 got_tk.class.to_s,
124 got_tk.line_no, scanner.file_name
125 )
126 CMD.test_sensitive_level env, LOG::Warning
127
128 nil
129 end
130
131 scanner.skip_space_or_nl!
132 got_tk = scanner.get!
133 LOG::Debug.log "got_tk=#{got_tk.inspect} " +
134 "[##{__LINE__}]" if env.debug_parser?
135 if got_tk.kind_of?(TkCOLON)
136 got_tk = scanner.get!
137 LOG::Debug.log "got_tk=#{got_tk.inspect} " +
138 "[##{__LINE__}]" if env.debug_parser?
139 end
140
141 orig_name =
142 if got_tk.respond_to?(:name)
143 got_tk.name
144 elsif got_tk.respond_to?(:value)
145 got_tk.value
146 else
147 LOG::Warning.log(
148 "I can't recognize a token: %s<%s>" +
149 " for orignal name of alias.\n" +
150 "\t-- #%d in '%s'",
151 if got_tk.respond_to?(:name)
152 got_tk.name
153 else
154 ''
155 end,
156 got_tk.class.to_s,
157 got_tk.line_no, scanner.file_name
158 )
159 CMD.test_sensitive_level env, LOG::Warning
160
161 nil
162 end
163
164 mc_alias =
165 if name && orig_name
166 LOG::Debug.msgout(
167 "ACCEPT %s", mc_alias.to_s
168 ) if env.debug_parser?
169
170 MCLL::Alias.new(
171 a_tk.line_no,
172 name.gsub(/^:/, ''),
173 orig_name.gsub(/^:/, ''),
174 ! context.in_unique_class?
175 )
176 else
177 nil
178 end
179
180 ASSERT.opt_kind_of mc_alias, MCLL::Alias
181 end
182
183
184
185 def parse_attribute(scanner, above_path, context, env, a_tk, accessor)
186 ASSERT.kind_of scanner, Scanner
187 ASSERT.kind_of above_path, MCLP::AbsolutePath
188 ASSERT.kind_of context, Context
189 ASSERT.kind_of env, ENV::Environment
190 ASSERT.kind_of a_tk, TkIDENTIFIER
191 ASSERT.opt_kind_of accessor, String
192
193 LOG::Debug.msgout "CALLED " +
194 "above_path='#{above_path.to_s}', " +
195 "a_tk=#{a_tk.inspect}" if env.debug_parser?
196
197 args = SeqOfArgument.new
198 loop do
199 scanner.skip_space_or_nl!
200 tk = scanner.get!
201 case tk
202 when TkSYMBOL
203 args.add! Argument.new(tk.value, tk.line_no)
204 when TkSTRING
205 args.add! Argument.new(scanner.last_readed, tk.line_no)
206 else
207 break
208 end
209
210 scanner.skip_space!
211 tk1 = scanner.get!
212 case tk1
213 when TkCOMMA
214 ; # nop
215 when TkNL
216 scanner.unget! tk1
217 break
218 else
219 break
220 end
221 end
222 LOG::Debug.log "args='#{args.inspect}' " +
223 "[##{__LINE__}]" if env.debug_parser?
224
225 mc_attribute =
226 if accessor
227 mc_attributes = args.map_with_index { |arg, seq_num|
228 MCLL::Attribute.new(
229 arg.line_num,
230 arg.name.gsub(/^:/, ''),
231 seq_num,
232 accessor.to_sym,
233 ! context.in_unique_class?
234 )
235 }
236 if env.debug_parser?
237 for mc_attribute in mc_attributes
238 LOG::Debug.msgout("ACCEPT %s", mc_attributes.to_s)
239 end
240 end
241
242 MCLN::Block.new(
243 a_tk.line_no, MCLA::SetOfSubject.new(mc_attributes)
244 )
245 else
246 len_of_args = args.length
247
248 if len_of_args >= 1
249 first_arg = args.first
250
251 LOG::Debug.msgout("ACCEPT %s",
252 mc_attribute.to_s
253 ) if env.debug_parser?
254
255 MCLL::Attribute.new(
256 first_arg.line_num,
257 first_arg.name.gsub(/^:/, ''),
258 0,
259 if len_of_args == 1 then :reader else :unknown end,
260 ! context.in_unique_class?
261 )
262 else
263 LOG::Debug.log(
264 "Can't recognize a token: <%s> as attr -- #%d",
265 tk.class.to_s, tk.line_no
266 ) if env.debug_parser?
267
268 nil
269 end
270 end
271 # MCLN::Attribute, MCLN::Block, or nil
272 ASSERT.opt_kind_of mc_attribute, MCLA::Subject
273 end
274
275
276
277 def parse_require(scanner, above_path, env)
278 ASSERT.kind_of scanner, Scanner
279 ASSERT.kind_of above_path, MCLP::AbsolutePath
280 ASSERT.kind_of env, ENV::Environment
281
282 LOG::Debug.msgout "CALLED " +
283 "above_path=#{above_path}" if env.debug_parser?
284
285 scanner.skip_space_or_nl!
286 tk = scanner.get!
287
288 name = nil
289 case tk
290 when TkSTRING
291 name = scanner.last_readed
292 else
293 LOG::Warning.log(
294 "The 'require' expected string, but: %s<%s>.\n" +
295 "\t-- #%d in '%s'",
296 if tk.respond_to?(:name) then tk.name else '' end,
297 tk.class.to_s,
298 tk.line_no, scanner.file_name
299 )
300 CMD.test_sensitive_level env, LOG::Warning
301 end
302
303 mc_require =
304 if name
305 LOG::Debug.msgout("ACCEPT %s",
306 mc_require.to_s
307 ) if env.debug_parser?
308
309 MCLL::Require.new(tk.line_no, name)
310 else
311 scanner.unget! tk
312
313 nil
314 end
315
316 ASSERT.opt_kind_of mc_require, MCLL::Require
317 end
318
319
320
321 def parse_extend(scanner, above_path, env, e_tk)
322 ASSERT.kind_of scanner, Scanner
323 ASSERT.kind_of above_path, MCLP::AbsolutePath
324 ASSERT.kind_of env, ENV::Environment
325 ASSERT.kind_of e_tk, TkIDENTIFIER
326
327 LOG::Debug.msgout "CALLED " +
328 "above_path=#{above_path}" if env.debug_parser?
329
330 seq_num = 0
331 mc_extends = []
332 loop do
333 scanner.skip_space_or_nl!
334 tk = scanner.peek
335 case tk
336 when TkCONSTANT, TkCOLON2, TkCOLON3
337 name = Common.get_constant(scanner, env)
338
339 mc_extends << MCLL::Extend.new(tk.line_no, seq_num, name)
340 seq_num += 1
341
342 when TkLPAREN, TkfLPAREN
343 name =
344 Common.get_constant_with_optional_parens(scanner, env)
345
346 mc_extends << MCLL::Extend.new(tk.line_no, seq_num, name)
347 seq_num += 1
348
349 when TkSELF
350 mc_extends << MCLL::Extend.new(tk.line_no, seq_num, nil)
351 seq_num += 1
352
353 else
354 LOG::Warning.log(
355 "The 'extend' expected constant, but: %s<%s>.\n" +
356 "\t-- #%d in '%s'",
357 if tk.respond_to?(:name) then tk.name else '' end,
358 tk.class.to_s,
359 tk.line_no, scanner.file_name
360 )
361 CMD.test_sensitive_level env, LOG::Warning
362 end
363
364 unless scanner.peek.kind_of?(TkCOMMA)
365 break
366 end
367
368 scanner.get!
369 end
370 if env.debug_parser?
371 for mc_extend in mc_extends
372 LOG::Debug.msgout("ACCEPT %s", mc_extend.to_s)
373 end
374 end
375
376 mc_extend =
377 case mc_extends.size
378 when 0
379 nil
380 when 1
381 mc_extends[0]
382 else
383 MCLN::Block.new(
384 e_tk.line_no, MCLA::SetOfSubject.new(mc_extends)
385 )
386 end
387 # MCLN::Extend, MCLN::Block, or nil
388 ASSERT.opt_kind_of mc_extend, MCLA::Subject
389 end
390
391
392
393 def parse_include(scanner, above_path, env, i_tk)
394 ASSERT.kind_of scanner, Scanner
395 ASSERT.kind_of above_path, MCLP::AbsolutePath
396 ASSERT.kind_of env, ENV::Environment
397 ASSERT.kind_of i_tk, TkIDENTIFIER
398
399 LOG::Debug.msgout "CALLED " +
400 "above_path=#{above_path}" if env.debug_parser?
401
402 seq_num = 0
403 mc_includes = []
404 loop do
405 scanner.skip_space_or_nl!
406 tk = scanner.peek
407 case tk
408 when TkCONSTANT, TkCOLON2, TkCOLON3
409 name = Common.get_constant(scanner, env)
410
411 mc_includes << MCLL::Include.new(tk.line_no, seq_num, name)
412 seq_num += 1
413
414 when TkSELF
415 mc_includes << MCLL::Include.new(tk.line_no, seq_num, nil)
416 seq_num += 1
417
418 else
419 LOG::Warning.log(
420 "The 'include' expected constant, but: %s<%s>.\n" +
421 "\t-- #%d in '%s'",
422 if tk.respond_to?(:name) then tk.name else '' end,
423 tk.class.to_s,
424 tk.line_no, scanner.file_name
425 )
426 CMD.test_sensitive_level env, LOG::Warning
427 end
428
429 unless scanner.peek.kind_of?(TkCOMMA)
430 break
431 end
432
433 scanner.get!
434 end
435 if env.debug_parser?
436 for mc_include in mc_includes
437 LOG::Debug.msgout("ACCEPT %s", mc_include.to_s)
438 end
439 end
440
441 mc_include =
442 case mc_includes.size
443 when 0
444 nil
445 when 1
446 mc_includes[0]
447 else
448 MCLN::Block.new(
449 i_tk.line_no, MCLA::SetOfSubject.new(mc_includes)
450 )
451 end
452 # MCLN::Include, MCLN::Block, or nil
453 ASSERT.opt_kind_of mc_include, MCLA::Subject
454 end
455
456
457
458 def parse_module_func(scanner, above_path, context, env, m_tk)
459 ASSERT.kind_of scanner, Scanner
460 ASSERT.kind_of above_path, MCLP::AbsolutePath
461 ASSERT.kind_of context, Context
462 ASSERT.kind_of env, ENV::Environment
463 ASSERT.kind_of m_tk, TkIDENTIFIER
464
465 LOG::Debug.msgout "CALLED " +
466 "above_path='#{above_path.to_s}'" if env.debug_parser?
467
468 args = SeqOfArgument.new
469 loop do
470 scanner.skip_space_or_nl!
471 tk = scanner.get!
472 case tk
473 when TkSYMBOL
474 args.add! Argument.new(tk.value, tk.line_no)
475 else
476 scanner.unget! tk
477 break
478 end
479
480 scanner.skip_space!
481 tk1 = scanner.get!
482 case tk1
483 when TkCOMMA
484 ; # nop
485 when TkNL
486 scanner.unget! tk1
487 break
488 else
489 break
490 end
491 end
492 LOG::Debug.log(
493 "args: '%s' -- #%d in %",
494 format("[%s]", args.map { |arg| arg.name }.join(', ')),
495 __LINE__, __FILE__
496 ) if env.debug_parser?
497
498 mc_block =
499 if args.empty?
500 nil # None argument.
501 else
502 mc_module_funcs = args.map_with_index { |arg, seq_num|
503 MCLL::ModuleFunc.new(
504 arg.line_num, seq_num, arg.name.gsub(/^:/, '')
505 )
506 }
507 if env.debug_parser?
508 for mc_module_func in mc_module_funcs
509 LOG::Debug.msgout(
510 "ACCEPT %s", mc_module_func.to_s
511 )
512 end
513 end
514
515 MCLN::Block.new(
516 m_tk.line_no, MCLA::SetOfSubject.new(mc_module_funcs)
517 )
518 end
519
520 ASSERT.opt_kind_of mc_block, MCLN::Block
521 end
522 end
523
524 end # TmDoc::Reader::Ruby18::Parser
525
526 end # TmDoc::Reader::Ruby18
527
528 end # TmDoc