1 # $Id: logical.rb,v 1.33 2011/12/10 18:18:17 machan Exp $
2
3 require 'stringio'
4
5 require 'tmdoc/tmstd'
6 require 'tmdoc/tmstd/treeable'
7 require 'tmdoc/constant'
8 require 'tmdoc/model/abstraction'
9
10
11 module TmDoc
12
13 module Model::Core
14
15 module Logical
16
17 module Path
18
19 class AbsolutePath < Model::Abstraction::Path::Absolute
20 LSM_ELEMENT_CLASS = String
21 PATH_SEPARATOR_STRING = '::'
22 end
23
24 ROOT_PATH = Path::AbsolutePath.new_root
25
26 class SetOfPath < Model::Abstraction::Path::SetOfPath
27 LSM_ELEMENT_CLASS = AbsolutePath
28 end
29
30
31 class RelativePath < Model::Abstraction::Path::Relative
32 LSM_ELEMENT_CLASS = String
33 PATH_SEPARATOR_STRING = '::'
34 ABSOLUTE_PATH_CLASS = AbsolutePath
35 end
36
37 end # TmDoc::Model::Core::Path
38
39
40
41 module Abstraction
42
43 class Subject < Model::Abstraction::Subject::GenericSubject
44 include TmStd::Treeable
45
46 attr_reader :line_num, :name_path, :seq_num
47 attr_reader :hash
48
49
50 def initialize(line_num, name_path = nil, seq_num = 0)
51 ASSERT.kind_of line_num, Integer
52 ASSERT.opt_kind_of(
53 name_path,
54 Model::Abstraction::Path::Abstract
55 )
56 ASSERT.kind_of seq_num, Integer
57
58 @line_num = line_num
59 @name_path = name_path
60 @seq_num = seq_num
61 if @name_path
62 @name_path.freeze_equality!
63 end
64
65 @hash = format(
66 "%d %s %d", @line_num, @name_path.to_s, @seq_num
67 ).hash
68 end
69
70
71 def name
72 str = self.name_path.to_s
73
74 ASSERT.kind_of str, String
75 end
76
77
78 def eql?(other)
79 ASSERT.kind_of other, self.class
80
81 result = if Subject >= other.class then true else false end &&
82 self.line_num == other.line_num &&
83 self.name_path == other.name_path &&
84 self.seq_num == other.seq_num
85
86 ASSERT.boolean result
87 end
88
89
90 def freeze_equality!
91 nil
92 end
93
94
95 def <=>(other)
96 ASSERT.kind_of other, Subject
97
98 result_line_num = self.line_num <=> other.line_num
99 if result_line_num != 0
100 return result_line_num
101 end
102
103 result_name = if self.name_path
104 if other.name_path
105 self.name_path <=> other.name_path
106 else
107 1
108 end
109 else
110 if other.name_path
111 -1
112 else
113 0
114 end
115 end
116
117 result = if result_name != 0
118 result_name
119 else
120 self.seq_num <=> other.seq_num
121 end
122
123 ASSERT.kind_of result, Integer
124 end
125 end
126
127
128 class SetOfSubject < Model::Abstraction::Subject::SetOfGenericSubject
129 LSM_ELEMENT_CLASS = Subject
130 end
131
132
133
134 class NodeSubject < Subject
135 attr_reader :below_subjects
136
137
138 def initialize(line_num, below_subjects, name_path = nil)
139 ASSERT.kind_of line_num, Integer
140 ASSERT.kind_of below_subjects, SetOfSubject
141 ASSERT.opt_kind_of(
142 name_path,
143 Model::Abstraction::Path::Abstract
144 )
145
146 super line_num, name_path
147
148 @below_subjects = below_subjects
149 end
150
151
152 def to_s(label, opt_str = nil)
153 str = format("%s %s -- #%d",
154 label,
155 if opt_str then opt_str else '' end,
156 self.line_num
157 )
158
159 ASSERT.kind_of str, String
160 end
161
162
163 def each(&block)
164 self.below_subjects.sort.each(&block)
165
166 nil
167 end
168
169
170 def children
171 subjects = self.below_subjects.sort
172
173 ASSERT.kind_of subjects, Array
174 end
175
176
177 def empty?
178 result = self.below_subjects.empty?
179
180 ASSERT.boolean result
181 end
182
183
184 def gather_module_funcs(below_subjects, env)
185 ASSERT.kind_of below_subjects, Abstraction::SetOfSubject
186 ASSERT.kind_of env, ENV::Environment
187
188 subjects = below_subjects.map { |below_subject|
189 case below_subject
190 when Node::Block
191 below_subject.gather_module_funcs(
192 below_subject.below_subjects, env
193 )
194 when Leaf::ModuleFunc
195 below_subject.func_name
196 else
197 nil
198 end
199 }.compact
200
201 ASSERT.kind_of subjects, Array
202 end
203 end
204
205
206
207 class LeafSubject < Subject
208 def initialize(line_num, name = nil, seq_num = 0)
209 ASSERT.kind_of line_num, Integer
210 ASSERT.opt_kind_of name, String
211 ASSERT.kind_of seq_num, Integer
212
213 name_path = if name then Path::RelativePath.new([name]) else nil end
214 super line_num, name_path, seq_num
215 end
216
217
218 def traverse(above_path, env)
219 ASSERT.kind_of above_path, Path::AbsolutePath
220 ASSERT.kind_of env, ENV::Environment
221
222 value = [ Logical::Record.new(above_path, self.name, self) ]
223
224 ASSERT.kind_of value, Array
225 end
226
227
228 def each(&block); nil; end # Nop
229 def children; []; end # No child
230 def empty?; true; end # Anytime empty
231
232
233 def to_s(label, opt_str = nil)
234 ASSERT.kind_of label, String
235 ASSERT.opt_kind_of opt_str, String
236
237 str = format("%s %s%s%s -- #%d",
238 label,
239
240 if self.name
241 self.name
242 else
243 ''
244 end,
245
246 if self.seq_num >= 1
247 format(" [#%d]", self.seq_num)
248 else
249 ''
250 end,
251
252 if opt_str
253 ' ' + opt_str
254 else
255 ''
256 end,
257
258 self.line_num
259 )
260
261 ASSERT.kind_of str, String
262 end
263 end
264
265
266
267 class Directive < LeafSubject
268 attr_reader :value
269
270
271 def initialize(line_num, seq_num, value = nil)
272 ASSERT.kind_of line_num, Integer
273 ASSERT.kind_of seq_num, Integer
274 ASSERT.opt_kind_of value, String
275
276 super line_num, nil, seq_num
277
278 @value = value
279 end
280
281
282 def path
283 p = self.above_path << self.label
284
285 ASSERT.kind_of p, Path::AbsolutePath
286 end
287
288
289 def to_s(label)
290 ASSERT.kind_of label, String
291
292 str = super(
293 label,
294 if self.value then format(" '%s'", self.value) else nil end
295 )
296
297 ASSERT.kind_of str, String
298 end
299 end
300
301
302
303 class Property < LeafSubject
304 attr_reader :does_attach_to_instance
305
306 alias attach_to_instance? does_attach_to_instance
307
308
309 def initialize(
310 line_num, name, seq_num, does_attach_to_instance = false
311 )
312 ASSERT.kind_of line_num, Integer
313 ASSERT.kind_of name, String
314 ASSERT.kind_of seq_num, Integer
315 ASSERT.boolean does_attach_to_instance
316
317 super line_num, name, seq_num
318
319 @does_attach_to_instance = does_attach_to_instance
320 end
321
322
323 def path
324 p = self.above_path << self.label
325
326 ASSERT.kind_of p, Path::AbsolutePath
327 end
328
329
330 def to_s(label, opt_str = nil)
331 ASSERT.kind_of label, String
332 ASSERT.opt_kind_of opt_str, String
333
334 str = super(
335 label,
336 format("%s%s",
337 if self.attach_to_instance?
338 ' [I]'
339 else
340 ''
341 end,
342
343 if opt_str
344 ' ' + opt_str
345 else
346 ''
347 end
348 )
349 )
350
351 ASSERT.kind_of str, String
352 end
353 end
354
355 end # TmDoc::Model::Core::Abstraction
356
357
358
359 class Record < TmStd::Lsm::Product::Abstract
360 attr_reader :path, :name, :subject, :module_func_names
361
362
363 def initialize(path, name, subject, module_func_names = nil)
364 ASSERT.kind_of path, Path::AbsolutePath
365 ASSERT.opt_kind_of name, String
366 ASSERT.kind_of subject, Abstraction::Subject
367 ASSERT.opt_kind_of(
368 module_func_names,
369 LSM::MutableSetOfString
370 )
371
372 @path = path
373 @name = name
374 @subject = subject
375 @module_func_names = module_func_names
376 end
377 end
378
379
380
381 module Leaf
382
383 class Require < Abstraction::Directive
384 alias require_file_name value
385
386
387 def initialize(line_num, require_file_name)
388 ASSERT.kind_of line_num, Integer
389 ASSERT.kind_of require_file_name, String
390
391 super line_num, 0, require_file_name
392 end
393
394
395 def to_s
396 str = super 'require'
397
398 ASSERT.kind_of str, String
399 end
400 end
401
402
403
404 class Extend < Abstraction::Directive
405 alias extendee_path_string value
406
407
408 def to_s
409 str = super 'extend'
410
411 ASSERT.kind_of str, String
412 end
413 end
414
415
416
417 class Include < Abstraction::Directive
418 alias includee_path_string value
419
420
421 def to_s
422 str = super 'include'
423
424 ASSERT.kind_of str, String
425 end
426 end
427
428
429
430 class ModuleFunc < Abstraction::Directive
431 alias func_name value
432
433
434 def to_s
435 str = super 'module_function'
436
437 ASSERT.kind_of str, String
438 end
439 end
440
441
442
443 class Constant < Abstraction::LeafSubject
444 attr_reader :value
445
446
447 def initialize(line_num, name, value)
448 ASSERT.kind_of line_num, Integer
449 ASSERT.kind_of name, String
450 ASSERT.kind_of value, String
451
452 super line_num, name
453
454 @value = value
455 end
456
457
458 def to_s
459 str = super 'constant', format("= %s", self.value)
460
461 ASSERT.kind_of str, String
462 end
463 end
464
465
466
467 class Alias < Abstraction::Property
468 attr_reader :orig_name
469
470
471 def initialize(
472 line_num, name, orig_name, does_attach_to_instance
473 )
474 ASSERT.kind_of line_num, Integer
475 ASSERT.kind_of name, String
476 ASSERT.kind_of orig_name, String
477 ASSERT.boolean does_attach_to_instance
478
479 super line_num, name, 0, does_attach_to_instance
480
481 @orig_name = orig_name
482 end
483
484
485 def to_s
486 str = super 'alias', format("<- '%s'", self.orig_name)
487
488 ASSERT.kind_of str, String
489 end
490 end
491
492
493
494 class Attribute < Abstraction::Property
495 attr_reader :accessor
496
497
498 def initialize(
499 line_num, name, seq_num, accessor, does_attach_to_instance
500 )
501 ASSERT.kind_of line_num, Integer
502 ASSERT.kind_of name, String
503 ASSERT.kind_of seq_num, Integer
504 ASSERT.kind_of accessor, Symbol
505 ASSERT.boolean does_attach_to_instance
506
507 super line_num, name, seq_num, does_attach_to_instance
508
509 @accessor = accessor
510 end
511
512
513 def to_s
514 str = super 'attribute', format("[%s]", self.accessor)
515
516 ASSERT.kind_of str, String
517 end
518 end
519
520 end # TmDoc::Model::Core::Logical::Leaf
521
522
523
524 module Node
525
526 class Module < Abstraction::NodeSubject
527 def to_s(label = 'module', opt_str = nil)
528 ASSERT.kind_of label, String
529 ASSERT.opt_kind_of opt_str, String
530
531 super(
532 label,
533 self.name_path.to_s + if opt_str then opt_str else '' end
534 )
535 end
536
537
538 def traverse(above_path, env)
539 ASSERT.kind_of above_path, Path::AbsolutePath
540 ASSERT.kind_of env, ENV::Environment
541
542 absolute_path =
543 if self.name_path.kind_of?(Path::AbsolutePath)
544 self.name_path
545 else
546 above_path + Path::RelativePath.new(self.name_path.to_a)
547 end
548 above_path, name = absolute_path.pop
549
550 module_func_names = self.gather_module_funcs below_subjects, env
551 LOG::Debug.log(
552 "module_func_names: %s -- #%d in %s",
553 module_func_names.inspect, __LINE__, __FILE__
554 ) if env.debug?
555
556 value = [
557 Logical::Record.new(above_path, name, self, module_func_names)
558 ] + (
559 self.below_subjects.map { |below_subject|
560 below_subject.traverse(absolute_path, env)
561 }
562 )
563
564 ASSERT.kind_of value, Array
565 end
566
567
568 def gather_module_funcs(below_subjects, env)
569 ASSERT.kind_of below_subjects, Abstraction::SetOfSubject
570 ASSERT.kind_of env, ENV::Environment
571
572 array_of_string = super.flatten
573 LOG::Debug.log(
574 "array_of_string: %s -- #%d in %s",
575 array_of_string.inspect, __LINE__, __FILE__
576 ) if env.debug?
577
578 LSM::MutableSetOfString.new array_of_string
579 end
580 end
581
582
583 class ToplevelModule < Module
584 def initialize(below_subjects)
585 ASSERT.kind_of below_subjects, Abstraction::SetOfSubject
586
587 super 0, below_subjects, Path::ROOT_PATH
588 end
589
590
591 def traverse(env)
592 ASSERT.kind_of env, ENV::Environment
593
594 value = super(
595 Path::ROOT_PATH, env
596 ).flatten.reject { |record|
597 record.subject.line_num <= 0
598 }.sort { |x, y|
599 x.subject <=> y.subject
600 }
601
602 ASSERT.kind_of value, Array
603 end
604
605
606 def print(file_name)
607 ASSERT.kind_of file_name, String
608
609 LOG::Debug.log "======== Core Model: %s ========", file_name
610 str_io = StringIO.new
611 self.print_tree(str_io)
612 LOG::Debug.log str_io.string
613 LOG::Debug.log
614
615 nil
616 end
617 end
618
619
620
621 class Class < Node::Module
622 attr_reader :inherit_path_string
623
624
625 def initialize(line_num, below_subjects, name_path, inherit_path_string)
626 ASSERT.kind_of line_num, Integer
627 ASSERT.kind_of(
628 below_subjects,
629 Abstraction::SetOfSubject
630 )
631 ASSERT.opt_kind_of(
632 name_path,
633 Model::Abstraction::Path::Abstract
634 )
635 ASSERT.opt_kind_of inherit_path_string, String
636
637 super line_num, below_subjects, name_path
638
639 @inherit_path_string = inherit_path_string
640 end
641
642
643 def to_s
644 str = super(
645 'class',
646 if self.inherit_path_string
647 ' < ' + self.inherit_path_string
648 else
649 ''
650 end
651 )
652
653 ASSERT.kind_of str, String
654 end
655 end
656
657
658
659 =begin
660 class UniqClass < Abstraction::NodeSubject
661 attr_reader :attach
662
663
664 def initialize(line_num, below_subjects, attach)
665 ASSERT.kind_of line_num, Integer
666 ASSERT.kind_of below_subjects, Abstraction::SetOfSubject
667 ASSERT.opt_kind_of attach, String
668
669 super line_num, below_subjects
670
671 @attach = attach
672 end
673
674
675 def to_s(opt_str = nil)
676 ASSERT.opt_kind_of opt_str, String
677
678 str = super(
679 'uniq-class',
680 (
681 if self.attach then self.attach else '' end
682 ) + (
683 if opt_str then opt_str else '' end
684 )
685 )
686
687 ASSERT.kind_of str, String
688 end
689
690
691 def traverse(above_path, env)
692 ASSERT.kind_of above_path, Path::AbsolutePath
693 ASSERT.kind_of env, ENV::Environment
694
695 value =
696 if (! self.attach) || self.attach == above_path.last
697 self.below_subjects.map { |below_subject|
698 below_subject.traverse(above_path, env)
699 }
700 else
701 LOG::Warning.log(
702 "The unique class definiation expected " +
703 "above class or module " +
704 "for attach class, but: <%s>.\n" +
705 "\t-- #%d",
706 self.attach,
707 self.line_num
708 )
709 CMD.test_sensitive_level env, LOG::Warning
710
711 []
712 end
713
714 ASSERT.kind_of value, Array
715 end
716 end
717 =end
718
719
720
721 class Method < Abstraction::NodeSubject
722 attr_reader :args, :attach_name,
723 :does_attach_to_instance, :is_module_func
724
725 alias attach_to_instance? does_attach_to_instance
726 alias module_func? is_module_func
727
728
729 def initialize(
730 line_num, name, below_subjects,
731 args, attach_name, does_attach_to_instance, is_module_func
732 )
733 ASSERT.kind_of line_num, Integer
734 ASSERT.kind_of name, String
735 ASSERT.kind_of below_subjects, Abstraction::SetOfSubject
736 ASSERT.kind_of args, LSM::SeqOfString
737 ASSERT.opt_kind_of attach_name, String
738 ASSERT.boolean does_attach_to_instance
739 ASSERT.boolean is_module_func
740
741 name_path = if name then Path::RelativePath.new([name]) else nil end
742 super line_num, below_subjects, name_path
743
744 @args = args
745 @attach_name = attach_name
746 @does_attach_to_instance = does_attach_to_instance
747 @is_module_func = is_module_func
748 end
749
750
751 def traverse(above_path, env)
752 ASSERT.kind_of above_path, Path::AbsolutePath
753 ASSERT.kind_of env, ENV::Environment
754
755 value = [
756 Logical::Record.new(above_path, self.name, self)
757 ] + (
758 self.below_subjects.map { |below_subject|
759 below_subject.traverse(above_path, env)
760 }
761 )
762
763 ASSERT.kind_of value, Array
764 end
765
766
767 def to_s
768 chars = [
769 if self.attach_to_instance? then 'I' else nil end,
770 ].compact
771
772 str = super(
773 'method',
774
775 [
776 if self.attach_name
777 self.attach_name + '$' + self.name_path.to_s
778 else
779 self.name_path.to_s
780 end,
781 unless self.args.empty?
782 format("(%s)", self.args.join(', '))
783 else
784 ''
785 end,
786 if self.module_func?
787 '[F]'
788 else
789 ''
790 end
791 ].join
792 )
793
794 ASSERT.kind_of str, String
795 end
796 end
797
798
799
800 class Block < Abstraction::NodeSubject
801 attr_reader :irb_token_class
802
803
804 def initialize(line_num, below_subjects, irb_token_class = nil)
805 ASSERT.kind_of line_num, Integer
806 ASSERT.kind_of below_subjects, Abstraction::SetOfSubject
807 if irb_token_class
808 ASSERT.subclass_of irb_token_class, RubyToken::Token
809 end
810
811 super line_num, below_subjects
812
813 @irb_token_class = irb_token_class
814 end
815
816
817 def traverse(above_path, env)
818 ASSERT.kind_of above_path, Path::AbsolutePath
819 ASSERT.kind_of env, ENV::Environment
820
821 value = self.below_subjects.map { |below_subject|
822 below_subject.traverse(above_path, env)
823 }
824
825 ASSERT.kind_of value, Array
826 end
827
828
829 def to_s
830 str = super(
831 'block',
832 if self.irb_token_class
833 self.irb_token_class.to_s
834 else
835 nil
836 end
837 )
838
839 ASSERT.kind_of str, String
840 end
841 end
842
843 end # TmDoc::Model::Core::Logical::Node
844
845 end # TmDoc::Model::Core::Logical
846
847 end # TmDoc::Model::Core
848
849 end # TmDoc