rockit 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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