rockit 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/BUGS +13 -0
  2. data/LICENSE +280 -0
  3. data/README +172 -0
  4. data/TODO +53 -0
  5. data/VERSION +1 -0
  6. data/lib/packrat/grammar.rb +537 -0
  7. data/lib/rockit/prettyprint/box.rb +60 -0
  8. data/lib/rockit/prettyprint/renderer.rb +41 -0
  9. data/lib/rockit/prettyprint/text_renderer.rb +47 -0
  10. data/lib/rockit/tree/base.rb +223 -0
  11. data/lib/rockit/tree/enter_leave_visitor.rb +12 -0
  12. data/lib/rockit/tree/graphviz.rb +69 -0
  13. data/lib/rockit/tree/visitor.rb +12 -0
  14. data/lib/util/array_alternatives.rb +20 -0
  15. data/lib/util/enter_leave_visitor.rb +69 -0
  16. data/lib/util/graphviz_dot.rb +182 -0
  17. data/lib/util/string_location.rb +42 -0
  18. data/lib/util/visitor.rb +49 -0
  19. data/lib/util/visitor_combinators.rb +14 -0
  20. data/rakefile +200 -0
  21. data/tests/acceptance/packrat/minibasic/atest_minibasic.rb +45 -0
  22. data/tests/acceptance/packrat/minibasic/minibasic.rb +137 -0
  23. data/tests/acceptance/rockit/dparser/atest_any_operator.rb +33 -0
  24. data/tests/acceptance/rockit/dparser/atest_arithmetic_grammar.rb +30 -0
  25. data/tests/acceptance/rockit/dparser/atest_list_operator.rb +57 -0
  26. data/tests/acceptance/rockit/dparser/atest_mult_operator.rb +60 -0
  27. data/tests/acceptance/rockit/dparser/atest_operator_grammar.rb +61 -0
  28. data/tests/acceptance/rockit/dparser/atest_plus_operator.rb +55 -0
  29. data/tests/acceptance/rockit/dparser/atest_samples_calculator.rb +14 -0
  30. data/tests/acceptance/rockit/dparser/atest_samples_minibasic.rb +20 -0
  31. data/tests/acceptance/rockit/dparser/atest_samples_multifunccalculator.rb +36 -0
  32. data/tests/acceptance/rockit/dparser/atest_simple_grammar.rb +34 -0
  33. data/tests/acceptance/rockit/dparser/atest_speculative_code_action.rb +128 -0
  34. data/tests/acceptance/rockit/dparser/calc_tests_common.rb +103 -0
  35. data/tests/unit/packrat/test_interpreting_parser.rb +296 -0
  36. data/tests/unit/parse/utest_ebnf_grammar.rb +50 -0
  37. data/tests/unit/parse/utest_expand_grammar.rb +23 -0
  38. data/tests/unit/parse/utest_grammar.rb +160 -0
  39. data/tests/unit/rockit/assembler/llvm/utest_instructions.rb +41 -0
  40. data/tests/unit/rockit/assembler/llvm/utest_module.rb +19 -0
  41. data/tests/unit/rockit/prettyprint/utest_box.rb +44 -0
  42. data/tests/unit/rockit/tree/utest_tree_base.rb +301 -0
  43. data/tests/unit/rockit/tree/utest_tree_enter_leave_visitor.rb +69 -0
  44. data/tests/unit/rockit/tree/utest_tree_visitor.rb +63 -0
  45. data/tests/unit/rockit/utest_grammar.rb +145 -0
  46. data/tests/unit/rockit/utest_grammar_symbol.rb +11 -0
  47. data/tests/unit/rockit/utest_maybe_operator.rb +12 -0
  48. data/tests/unit/rockit/utest_regexp_terminal.rb +45 -0
  49. data/tests/unit/rockit/utest_repetition_operators.rb +35 -0
  50. data/tests/unit/rockit/utest_rule.rb +23 -0
  51. data/tests/unit/rockit/utest_string_terminal.rb +40 -0
  52. data/tests/unit/util/utest_array_alternatives.rb +23 -0
  53. data/tests/unit/util/utest_enter_leave_visitor.rb +89 -0
  54. data/tests/unit/util/utest_string_location.rb +42 -0
  55. data/tests/unit/util/utest_visitor.rb +92 -0
  56. data/tests/unit/util/utest_visitor_combinators.rb +64 -0
  57. metadata +112 -0
@@ -0,0 +1,145 @@
1
+ require 'test/unit'
2
+
3
+ require 'rockit/grammar'
4
+ include Rockit
5
+
6
+ class UTestGrammar < Test::Unit::TestCase
7
+ def test_01_creation
8
+ g = Rockit::Grammar.new
9
+ assert_kind_of(Rockit::Grammar, g)
10
+ end
11
+
12
+ TestGrammar1 = Rockit::Grammar.new do
13
+ rule :A, [["1", :B, :C]]
14
+ rule :B, [["2", :D]]
15
+ term :C, "a"
16
+ term :D, "b"
17
+ end
18
+
19
+ def symbols_as_strings(symbols)
20
+ symbols.map {|s| s.to_s}.sort
21
+ end
22
+
23
+ def assert_symbols(expected, actual, msg = "")
24
+ assert_equal(symbols_as_strings(expected), symbols_as_strings(actual), msg)
25
+ end
26
+
27
+ def test_02_simple_grammar
28
+ assert_kind_of(Rockit::Grammar, TestGrammar1)
29
+
30
+ assert_equal(2, TestGrammar1.rules.length)
31
+ assert_symbols([:A, :B], TestGrammar1.nonterminals)
32
+ assert_equal(2, TestGrammar1.terms.length)
33
+ assert_symbols([:C, :D], TestGrammar1.terms.keys)
34
+
35
+ assert_kind_of(Rule, ra = TestGrammar1.rules.first)
36
+ assert_kind_of(Rule, rb = TestGrammar1.rules.last)
37
+
38
+ assert_kind_of(Terminal, TestGrammar1.terms[:C])
39
+ assert_kind_of(Terminal, TestGrammar1.terms[:D])
40
+
41
+ assert_equal(:A, ra.name)
42
+ assert_equal(3, (rarhs = ra.right_hand_side).length)
43
+ rarhs1, rarhs2, rarhs3 = rarhs
44
+ assert_kind_of(StringTerminal, rarhs1)
45
+ assert_kind_of(NonTerminal, rarhs2)
46
+ assert_kind_of(NonTerminal, rarhs3)
47
+ assert_equal("1", rarhs1.string)
48
+ assert_equal(:B, rarhs2.symbol)
49
+ assert_equal(:C, rarhs3.symbol)
50
+
51
+ assert_equal(:B, rb.name)
52
+ assert_equal(2, (rbrhs = rb.right_hand_side).length)
53
+ rbrhs1, rbrhs2 = rbrhs
54
+ assert_kind_of(StringTerminal, rbrhs1)
55
+ assert_kind_of(NonTerminal, rbrhs2)
56
+ assert_equal("2", rbrhs1.string)
57
+ assert_equal(:D, rbrhs2.symbol)
58
+ end
59
+
60
+ Arithmetic = Rockit::Grammar.new do
61
+ # Additive <- Multitive '+' Additive
62
+ # / Multitive
63
+ # Multitive <- Primary '*' Multitive
64
+ # / Primary
65
+ # Primary <- '(' Additive ')'
66
+ # / Decimal
67
+ # Decimal <- '0' / '1' / '2' / '3' / '4' / '5' / '6' / '7' / '8' / '9'
68
+
69
+ start :Additive, [
70
+ [:Multitive, '+', :Additive],
71
+ [:Multitive],
72
+ ]
73
+ rule :Multitive, [
74
+ [:Primary, '*', :Multitive],
75
+ [:Primary]
76
+ ]
77
+ rule :Primary, [
78
+ ['(', :Additive, ')'],
79
+ [:Decimal]
80
+ ]
81
+ term :Decimal, /[0-9]/
82
+ end
83
+
84
+ def test_03_arithmetic_grammar
85
+ assert_equal(6, Arithmetic.rules.length)
86
+ assert_symbols([:Additive, :Multitive, :Primary], Arithmetic.nonterminals)
87
+ assert_equal(1, Arithmetic.terms.length)
88
+ assert_symbols([:Decimal], Arithmetic.terms.keys)
89
+ assert_equal(:Additive, Arithmetic.start_symbol)
90
+ assert_raise(NotImplementedError) {Arithmetic.new_parser.parse("2")}
91
+
92
+ ras = Arithmetic.find_rules(:Additive)
93
+ assert_equal(2, ras.length)
94
+ ra1, ra2 = ras
95
+
96
+ assert_equal(:Additive, ra1.name)
97
+ assert_equal(3, (ra1rhs = ra1.right_hand_side).length)
98
+ assert_kind_of(NonTerminal, ra1rhs[0])
99
+ assert_kind_of(StringTerminal, ra1rhs[1])
100
+ assert_kind_of(NonTerminal, ra1rhs[2])
101
+ assert_equal(:Multitive, ra1rhs[0].symbol)
102
+ assert_equal("+", ra1rhs[1].string)
103
+ assert_equal(:Additive, ra1rhs[2].symbol)
104
+
105
+ assert_equal(:Additive, ra2.name)
106
+ assert_equal(1, (ra2rhs = ra2.right_hand_side).length)
107
+ assert_kind_of(NonTerminal, ra2rhs[0])
108
+ assert_equal(:Multitive, ra2rhs[0].symbol)
109
+
110
+ td = Arithmetic.terms[:Decimal]
111
+ assert_equal(:Decimal, td.name)
112
+ rdrhs1 = td.right_hand_side
113
+ assert_equal(1, rdrhs1.length)
114
+ assert_kind_of(RegexpTerminal, rdrhs1[0])
115
+ end
116
+
117
+ Operators = Rockit::Grammar.new do
118
+ start :Number, [
119
+ [plus(:Digit), maybe(/e|E/), maybe("-")],
120
+ [:Dummy]
121
+ ]
122
+ rule :Dummy, [[mult("a"), rep("b", 3, 6)]]
123
+ term :Digit, /[0-9]/
124
+ end
125
+
126
+ def test_04_operators
127
+ assert_equal(3, Operators.rules.length)
128
+ assert_symbols([:Number, :Dummy], Operators.nonterminals)
129
+ assert_equal(1, Operators.terms.length)
130
+ assert_symbols([:Digit], Operators.terms.keys)
131
+ assert_equal(:Number, Operators.start_symbol)
132
+
133
+ rn1, rn2 = Operators.find_rules(:Number)
134
+ assert_equal(:Number, rn1.name)
135
+
136
+ assert_equal(3, (rn1rhs = rn1.right_hand_side).length)
137
+ assert_kind_of(Plus, rn1rhs[0])
138
+ assert_kind_of(Maybe, rn1rhs[1])
139
+ assert_kind_of(Maybe, rn1rhs[2])
140
+
141
+ assert_kind_of(NonTerminal, rn1rhs[0].symbol)
142
+ assert_kind_of(RegexpTerminal, rn1rhs[1].symbol)
143
+ assert_kind_of(StringTerminal, rn1rhs[2].symbol)
144
+ end
145
+ end
@@ -0,0 +1,11 @@
1
+ require 'test/unit'
2
+
3
+ require 'rockit/grammar'
4
+ include Rockit
5
+
6
+ class UTestGrammarSymbol < Test::Unit::TestCase
7
+ def test_01_to_grammar_symbol
8
+ dummy = GrammarSymbol.new
9
+ assert_equal(dummy, dummy.to_grammar_symbol)
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ require 'test/unit'
2
+
3
+ require 'rockit/grammar'
4
+ include Rockit
5
+
6
+ class UTestRepetitionOperator < Test::Unit::TestCase
7
+ def test_01
8
+ m = Maybe.new(:A)
9
+ assert_kind_of(Maybe, m)
10
+ assert_kind_of(GrammarSymbol, m)
11
+ end
12
+ end
@@ -0,0 +1,45 @@
1
+ require 'test/unit'
2
+
3
+ require 'rockit/grammar'
4
+ include Rockit
5
+
6
+ require 'strscan'
7
+
8
+ class UTestRegexpTerminal < Test::Unit::TestCase
9
+ def setup
10
+ @ret = RegexpTerminal.new(/a/)
11
+ @retas = RegexpTerminal.new(/a+/)
12
+ end
13
+
14
+ def test_01_smoke
15
+ assert_kind_of(RegexpTerminal, @ret)
16
+ assert_kind_of(GrammarSymbol, @ret)
17
+ end
18
+
19
+ def test_02_inspect
20
+ assert_kind_of(String, @ret.inspect)
21
+ assert_equal("/a/", @ret.inspect)
22
+ end
23
+
24
+ def test_03_regexp
25
+ assert_kind_of(Regexp, @ret.regexp)
26
+ assert_equal(/\s*(a)/, @ret.regexp)
27
+ assert_equal(/\s*(a+)/, @retas.regexp)
28
+ end
29
+
30
+ def test_04_scan
31
+ s = StringScanner.new("a")
32
+ assert_equal("a", @ret.scan(s))
33
+ assert_equal(1, s.pos)
34
+
35
+ s = StringScanner.new("b")
36
+ assert_equal(nil, @ret.scan(s))
37
+ assert_equal(0, s.pos)
38
+ end
39
+
40
+ def test_05_dont_scan_over_whitespace
41
+ s = StringScanner.new("a b")
42
+ assert_equal("a", @ret.scan(s))
43
+ assert_equal(1, s.pos)
44
+ end
45
+ end
@@ -0,0 +1,35 @@
1
+ require 'test/unit'
2
+
3
+ require 'rockit/grammar'
4
+ include Rockit
5
+
6
+ class UTestRepetitionOperator < Test::Unit::TestCase
7
+ def test_01_creation_of_repetition
8
+ r = Repetition.new(:A, 2, 10)
9
+ assert_kind_of(Repetition, r)
10
+ assert_kind_of(Operator, r)
11
+ assert_kind_of(GrammarSymbol, r)
12
+ assert_equal(2, r.min)
13
+ assert_equal(10, r.max)
14
+ end
15
+
16
+ def test_02_creation_of_mult
17
+ r = Mult.new(:C)
18
+ assert_kind_of(Mult, r)
19
+ assert_kind_of(Repetition, r)
20
+ assert_kind_of(Operator, r)
21
+ assert_kind_of(GrammarSymbol, r)
22
+ assert_equal(0, r.min)
23
+ assert_equal((1.0/0.0), r.max)
24
+ end
25
+
26
+ def test_03_creation_of_plus
27
+ r = Plus.new(:C)
28
+ assert_kind_of(Plus, r)
29
+ assert_kind_of(Repetition, r)
30
+ assert_kind_of(Operator, r)
31
+ assert_kind_of(GrammarSymbol, r)
32
+ assert_equal(1, r.min)
33
+ assert_equal((1.0/0.0), r.max)
34
+ end
35
+ end
@@ -0,0 +1,23 @@
1
+ require 'test/unit'
2
+
3
+ require 'rockit/grammar'
4
+ include Rockit
5
+
6
+ class UTestRule < Test::Unit::TestCase
7
+ def test_01_empty_rule
8
+ r = Rule.new(:r1, [])
9
+ assert_equal(:r1, r.name)
10
+ assert_equal([], r.right_hand_side)
11
+ end
12
+
13
+ def test_02
14
+ r = Rule.new(:r1, [[:a, "B"]])
15
+ assert_equal(:r1, r.name)
16
+ assert_equal(2, r.right_hand_side.length)
17
+ s1, s2 = r.right_hand_side
18
+ assert_kind_of(NonTerminal, s1)
19
+ assert_kind_of(StringTerminal, s2)
20
+ assert_equal(:a, s1.symbol)
21
+ assert_equal("B", s2.string)
22
+ end
23
+ end
@@ -0,0 +1,40 @@
1
+ require 'test/unit'
2
+
3
+ require 'rockit/grammar'
4
+ include Rockit
5
+
6
+ require 'strscan'
7
+
8
+ class UTestStringTerminal < Test::Unit::TestCase
9
+ def setup
10
+ @sta = StringTerminal.new("a")
11
+ @stp = StringTerminal.new("+")
12
+ end
13
+
14
+ def test_01_smoke
15
+ assert_kind_of(StringTerminal, @sta)
16
+ assert_kind_of(GrammarSymbol, @sta)
17
+ assert_kind_of(StringTerminal, @stp)
18
+ assert_kind_of(GrammarSymbol, @stp)
19
+ end
20
+
21
+ def test_02_inspect
22
+ assert_kind_of(String, @sta.inspect)
23
+ assert_equal("a", @sta.inspect)
24
+ end
25
+
26
+ def test_03_string
27
+ assert_kind_of(String, @sta.string)
28
+ assert_equal("a", @sta.string)
29
+ assert_kind_of(String, @stp.string)
30
+ assert_equal("+", @stp.string)
31
+ end
32
+
33
+ def test_04_regexp
34
+ assert_kind_of(Regexp, @sta.regexp)
35
+ assert_equal(/\s*(a)/, @sta.regexp)
36
+ assert_kind_of(Regexp, @stp.regexp)
37
+ assert_equal(/\s*(\+)/, @stp.regexp)
38
+ assert_equal("/\\s*(\\+)/", @stp.regexp.inspect)
39
+ end
40
+ end
@@ -0,0 +1,23 @@
1
+ require 'test/unit'
2
+ require 'util/array_alternatives'
3
+
4
+ class UTestArrayAlternatives < Test::Unit::TestCase
5
+ def test_01_normal_use
6
+ first, second, third = [1], [2], [3, 4]
7
+ a = first / second / third
8
+ alts = a.assemble_alternatives
9
+ assert_kind_of(Array, alts)
10
+ assert_equal(3, alts.length)
11
+ assert_equal(first, alts[0])
12
+ assert_equal(second, alts[1])
13
+ assert_equal(third, alts[2])
14
+ end
15
+
16
+ def test_02_without_any_alternatives
17
+ a = [1]
18
+ alts = a.assemble_alternatives
19
+ assert_kind_of(Array, alts)
20
+ assert_equal(1, alts.length)
21
+ assert_equal(a, alts[0])
22
+ end
23
+ end
@@ -0,0 +1,89 @@
1
+ require 'test/unit'
2
+ require 'util/enter_leave_visitor'
3
+
4
+ class TestEnterLeaveVisitor < Test::Unit::TestCase
5
+ class Mock
6
+ end
7
+
8
+ class SuperMock
9
+ include EnterLeaveVisitable
10
+ end
11
+
12
+ class ELMock < SuperMock
13
+ end
14
+
15
+ class SuperTELVisitor
16
+ include EnterLeaveVisitor
17
+ attr_reader :calls
18
+ def initialize; @calls = []; end
19
+
20
+ def enter_SuperMock(obj); @calls << :enterSuperM; end
21
+ def visit_SuperMock(obj); @calls << :visitSuperM; end
22
+ def leave_SuperMock(obj); @calls << :leaveSuperM; end
23
+ end
24
+
25
+ class TELVisitor < SuperTELVisitor
26
+ def enter_Mock(obj); @calls << :enterM; end
27
+ def visit_Mock(obj); @calls << :visitM; end
28
+ def leave_Mock(obj); @calls << :leaveM; end
29
+
30
+ def enter_ELMock(obj); @calls << :enterELM; end
31
+ def visit_ELMock(obj); @calls << :visitELM; end
32
+ def leave_ELMock(obj); @calls << :leaveELM; end
33
+
34
+ def enter_SMock(obj); @calls << :enterSM; end
35
+ def visit_SMock(obj); @calls << :visitSM; end
36
+ def leave_SMock(obj); @calls << :leaveSM; end
37
+ end
38
+
39
+ class SMock
40
+ def initialize(c1, c2)
41
+ @c1, @c2 = c1, c2
42
+ end
43
+ def accept_visitor(v)
44
+ v.visit_me_then_children self, [@c1, @c2]
45
+ end
46
+ end
47
+
48
+ class EmptyVisitor
49
+ include EnterLeaveVisitor
50
+ end
51
+
52
+ def test_01_empty_visitor
53
+ visitor, m = EmptyVisitor.new, ELMock.new
54
+ assert_nothing_raised {m.accept_visitor(visitor)}
55
+ end
56
+
57
+ def test_02_visit_std_visitable
58
+ visitor, m = TELVisitor.new, Mock.new
59
+ visitor.visit m
60
+ assert_equal([:enterM, :visitM, :leaveM], visitor.calls)
61
+ end
62
+
63
+ def test_03_visit_enterleavevisitable
64
+ visitor, m = TELVisitor.new, ELMock.new
65
+ visitor.visit m
66
+ assert_equal([:enterELM, :visitELM, :leaveELM], visitor.calls)
67
+ end
68
+
69
+ def test_04_visit_nested_objects
70
+ visitor, sm = TELVisitor.new, SMock.new(c1 = ELMock.new, c2 = ELMock.new)
71
+ sm.accept_visitor(visitor)
72
+ assert_equal([:enterSM, :visitSM,
73
+ :enterELM, :visitELM, :leaveELM,
74
+ :enterELM, :visitELM, :leaveELM,
75
+ :leaveSM], visitor.calls)
76
+ end
77
+
78
+ def test_05_visit_superclass_visit_method
79
+ visitor, m1 = SuperTELVisitor.new, ELMock.new
80
+ m1.accept_visitor(visitor)
81
+ assert_equal([:enterSuperM, :visitSuperM, :leaveSuperM], visitor.calls)
82
+ end
83
+
84
+ def test_06_visit_our_visitmethod_if_available_both_for_us_and_for_superclass
85
+ visitor, m1 = TELVisitor.new, ELMock.new
86
+ m1.accept_visitor(visitor)
87
+ assert_equal([:enterELM, :visitELM, :leaveELM], visitor.calls)
88
+ end
89
+ end
@@ -0,0 +1,42 @@
1
+ require 'test/unit'
2
+
3
+ require 'util/string_location'
4
+
5
+ class UTestStringLocation < Test::Unit::TestCase
6
+ def setup
7
+ @sl = StringLocations.new "a\nb\nc\r\nd"
8
+ end
9
+
10
+ def test_01_creation
11
+ assert_kind_of(StringLocations, @sl)
12
+ end
13
+
14
+ def test_02_line
15
+ assert_equal(1, @sl.line(0))
16
+ assert_equal(1, @sl.line(1))
17
+ assert_equal(2, @sl.line(2))
18
+ assert_equal(2, @sl.line(3))
19
+ assert_equal(3, @sl.line(4))
20
+ assert_equal(3, @sl.line(5))
21
+ assert_equal(3, @sl.line(6))
22
+ assert_equal(4, @sl.line(7))
23
+ end
24
+
25
+ def test_03_column
26
+ assert_equal(0, @sl.column(0))
27
+ assert_equal(1, @sl.column(1))
28
+ assert_equal(0, @sl.column(2))
29
+ assert_equal(1, @sl.column(3))
30
+ assert_equal(0, @sl.column(4))
31
+ assert_equal(1, @sl.column(5))
32
+ assert_equal(2, @sl.column(6))
33
+ assert_equal(0, @sl.column(7))
34
+ end
35
+
36
+ def test_04_location
37
+ assert_equal([1, 0], @sl.location(0))
38
+ assert_equal([1, 1], @sl.location(1))
39
+ assert_equal([2, 0], @sl.location(2))
40
+ assert_equal([2, 1], @sl.location(3))
41
+ end
42
+ end
@@ -0,0 +1,92 @@
1
+ require 'test/unit'
2
+ require 'util/visitor'
3
+
4
+ class TestVisitor < Test::Unit::TestCase
5
+ class SuperMock
6
+ include Visitable
7
+ end
8
+
9
+ class Mock < SuperMock
10
+ attr_reader :children, :visited
11
+ def initialize
12
+ @children = []
13
+ end
14
+ def accept_visitor(visitor)
15
+ @visited = true
16
+ visitor.visit_me_then_children self, @children
17
+ end
18
+ end
19
+
20
+ class TVisitor
21
+ include Visitor
22
+ attr_reader :count
23
+ def initialize; @count = 0; end
24
+ def visit_Mock(obj); @count += 1; end
25
+ end
26
+
27
+ class EmptyVisitor
28
+ include Visitor
29
+ end
30
+
31
+ # To test whether super class visit method is used if there is no one
32
+ # for the actual class
33
+ class SuperMockVisitor
34
+ include Visitor
35
+ attr_reader :count
36
+ def initialize; @count = 0; end
37
+ def visit_SuperMock(obj); @count += 1; end
38
+ end
39
+
40
+ class MockAndSuperMockVisitor
41
+ include Visitor
42
+ attr_reader :countSM, :countM
43
+ def initialize; @countM = @countSM = 0; end
44
+ def visit_SuperMock(obj); @countSM += 1; end
45
+ def visit_Mock(obj); @countM += 1; end
46
+ end
47
+
48
+ def test_01_empty_visitor
49
+ visitor, m = EmptyVisitor.new, Mock.new
50
+ assert_nothing_raised {m.accept_visitor(visitor)}
51
+ assert(m.visited)
52
+ end
53
+
54
+ def test_02_visit
55
+ visitor, m = TVisitor.new, Mock.new
56
+ assert_equal(0, visitor.count)
57
+ visitor.visit(m)
58
+ assert_equal(1, visitor.count)
59
+ m.accept_visitor(visitor)
60
+ assert_equal(2, visitor.count)
61
+ end
62
+
63
+ def test_03_visit_nested
64
+ visitor, m1 = TVisitor.new, Mock.new
65
+ m1.children << (m2 = Mock.new)
66
+ m2.children << (m3 = Mock.new)
67
+ m1.accept_visitor(visitor)
68
+ assert_equal(3, visitor.count)
69
+ assert(m1.visited)
70
+ assert(m2.visited)
71
+ assert(m3.visited)
72
+ end
73
+
74
+ def test_04_visit_superclass_visit_method
75
+ visitor, m1 = SuperMockVisitor.new, Mock.new
76
+ m1.accept_visitor(visitor)
77
+ assert_equal(1, visitor.count)
78
+ end
79
+
80
+ def test_05_visit_our_visitmethod_if_available_both_for_us_and_for_superclass
81
+ visitor, m1 = MockAndSuperMockVisitor.new, Mock.new
82
+ m1.accept_visitor(visitor)
83
+ assert_equal(1, visitor.countM)
84
+ assert_equal(0, visitor.countSM)
85
+ end
86
+
87
+ def test_06_visit_each
88
+ visitor, a = TVisitor.new, [Mock.new, Mock.new]
89
+ visitor.visit_each(a)
90
+ assert_equal(2, visitor.count)
91
+ end
92
+ end
@@ -0,0 +1,64 @@
1
+ require 'test/unit'
2
+
3
+ require 'util/visitor_combinators'
4
+
5
+ require 'util/visitor'
6
+
7
+ class UTestVisitorCombinators < Test::Unit::TestCase
8
+ class Tree
9
+ attr_reader :children, :visitors
10
+ def initialize(*children)
11
+ @children, @visitors = children, []
12
+ end
13
+ def accept_visitor(visitor)
14
+ @visitors << visitor.object_id
15
+ visitor.visit_me_and_my_children(self, @children)
16
+ end
17
+ end
18
+
19
+ # Doesn't touch the visited nodes, just saves the fact that they have been
20
+ # visited
21
+ class TIdentityVisitor
22
+ include Visitor
23
+ attr_reader :visited
24
+ def initialize
25
+ @visited = []
26
+ end
27
+ def visit_Tree(tree)
28
+ @visited << tree
29
+ end
30
+ end
31
+
32
+ def setup
33
+ @l1, @l2, @l3 = Tree.new, Tree.new, Tree.new
34
+ @i = Tree.new(@l2, @l3)
35
+ @r = Tree.new(@l1, @i)
36
+ @nodes = [@r, @l1, @i, @l2, @l3]
37
+ end
38
+
39
+ def assert_topdown_leftright_visited(visitor)
40
+ assert_equal(@r, visitor.visited[0])
41
+ assert_equal(@l1, visitor.visited[1])
42
+ assert_equal(@i, visitor.visited[2])
43
+ assert_equal(@l2, visitor.visited[3])
44
+ assert_equal(@l3, visitor.visited[4])
45
+ end
46
+
47
+ def test_01_identity_visitor
48
+ @r.accept_visitor(iv = TIdentityVisitor.new)
49
+ assert_equal(5, iv.visited.length)
50
+ assert_topdown_leftright_visited(iv)
51
+ end
52
+
53
+ def test_02_sequence_visitor
54
+ sv = SequenceVisitor.new(iv1 = TIdentityVisitor.new, iv2 = TIdentityVisitor.new)
55
+ @r.accept_visitor(sv)
56
+ assert_topdown_leftright_visited(iv1)
57
+ assert_topdown_leftright_visited(iv2)
58
+ # Seems leaf nodes are visited many times by iv1 and iv2 so the assert
59
+ # does not hold.
60
+ # @nodes.each do |n|
61
+ # assert_equal([sv.id, iv1.id, iv2.id], n.visitors)
62
+ # end
63
+ end
64
+ end