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.
- data/BUGS +13 -0
- data/LICENSE +280 -0
- data/README +172 -0
- data/TODO +53 -0
- data/VERSION +1 -0
- data/lib/packrat/grammar.rb +537 -0
- data/lib/rockit/prettyprint/box.rb +60 -0
- data/lib/rockit/prettyprint/renderer.rb +41 -0
- data/lib/rockit/prettyprint/text_renderer.rb +47 -0
- data/lib/rockit/tree/base.rb +223 -0
- data/lib/rockit/tree/enter_leave_visitor.rb +12 -0
- data/lib/rockit/tree/graphviz.rb +69 -0
- data/lib/rockit/tree/visitor.rb +12 -0
- data/lib/util/array_alternatives.rb +20 -0
- data/lib/util/enter_leave_visitor.rb +69 -0
- data/lib/util/graphviz_dot.rb +182 -0
- data/lib/util/string_location.rb +42 -0
- data/lib/util/visitor.rb +49 -0
- data/lib/util/visitor_combinators.rb +14 -0
- data/rakefile +200 -0
- data/tests/acceptance/packrat/minibasic/atest_minibasic.rb +45 -0
- data/tests/acceptance/packrat/minibasic/minibasic.rb +137 -0
- data/tests/acceptance/rockit/dparser/atest_any_operator.rb +33 -0
- data/tests/acceptance/rockit/dparser/atest_arithmetic_grammar.rb +30 -0
- data/tests/acceptance/rockit/dparser/atest_list_operator.rb +57 -0
- data/tests/acceptance/rockit/dparser/atest_mult_operator.rb +60 -0
- data/tests/acceptance/rockit/dparser/atest_operator_grammar.rb +61 -0
- data/tests/acceptance/rockit/dparser/atest_plus_operator.rb +55 -0
- data/tests/acceptance/rockit/dparser/atest_samples_calculator.rb +14 -0
- data/tests/acceptance/rockit/dparser/atest_samples_minibasic.rb +20 -0
- data/tests/acceptance/rockit/dparser/atest_samples_multifunccalculator.rb +36 -0
- data/tests/acceptance/rockit/dparser/atest_simple_grammar.rb +34 -0
- data/tests/acceptance/rockit/dparser/atest_speculative_code_action.rb +128 -0
- data/tests/acceptance/rockit/dparser/calc_tests_common.rb +103 -0
- data/tests/unit/packrat/test_interpreting_parser.rb +296 -0
- data/tests/unit/parse/utest_ebnf_grammar.rb +50 -0
- data/tests/unit/parse/utest_expand_grammar.rb +23 -0
- data/tests/unit/parse/utest_grammar.rb +160 -0
- data/tests/unit/rockit/assembler/llvm/utest_instructions.rb +41 -0
- data/tests/unit/rockit/assembler/llvm/utest_module.rb +19 -0
- data/tests/unit/rockit/prettyprint/utest_box.rb +44 -0
- data/tests/unit/rockit/tree/utest_tree_base.rb +301 -0
- data/tests/unit/rockit/tree/utest_tree_enter_leave_visitor.rb +69 -0
- data/tests/unit/rockit/tree/utest_tree_visitor.rb +63 -0
- data/tests/unit/rockit/utest_grammar.rb +145 -0
- data/tests/unit/rockit/utest_grammar_symbol.rb +11 -0
- data/tests/unit/rockit/utest_maybe_operator.rb +12 -0
- data/tests/unit/rockit/utest_regexp_terminal.rb +45 -0
- data/tests/unit/rockit/utest_repetition_operators.rb +35 -0
- data/tests/unit/rockit/utest_rule.rb +23 -0
- data/tests/unit/rockit/utest_string_terminal.rb +40 -0
- data/tests/unit/util/utest_array_alternatives.rb +23 -0
- data/tests/unit/util/utest_enter_leave_visitor.rb +89 -0
- data/tests/unit/util/utest_string_location.rb +42 -0
- data/tests/unit/util/utest_visitor.rb +92 -0
- data/tests/unit/util/utest_visitor_combinators.rb +64 -0
- 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,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
|