rockit 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- 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,160 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require 'parse/grammar'
|
4
|
+
include Parse::Grammar
|
5
|
+
|
6
|
+
class UT_Parse_Grammar < Test::Unit::TestCase
|
7
|
+
def test_01_Symbol
|
8
|
+
s = Parse::Grammar::GrammarSymbol.new "name"
|
9
|
+
assert_equal("name", s.name)
|
10
|
+
assert_equal("name", s.inspect)
|
11
|
+
assert_equal(s, s.to_grammar_symbol)
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_02_Symbol_name_not_needed
|
15
|
+
s = Parse::Grammar::GrammarSymbol.new
|
16
|
+
assert_equal(nil, s.name)
|
17
|
+
assert_equal(s, s.to_grammar_symbol)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_03_NonTerminal
|
21
|
+
s = NonTerminal.new :name
|
22
|
+
assert_equal(:name, s.name)
|
23
|
+
assert_equal("name", s.inspect)
|
24
|
+
assert_kind_of(Parse::Grammar::GrammarSymbol, s)
|
25
|
+
assert_equal(s, s.to_grammar_symbol)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_04_Terminal
|
29
|
+
s = Terminal.new
|
30
|
+
assert_kind_of(Parse::Grammar::GrammarSymbol, s)
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_05_Production
|
34
|
+
p = Production.new(n = NonTerminal.new(:N), [t = Terminal.new(:T)])
|
35
|
+
assert_equal(n, p.symbol)
|
36
|
+
assert_equal(t, p.rhs.first)
|
37
|
+
assert_equal(t, p.right_hand_side.first)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_06_Production_short_hand
|
41
|
+
p = Prod[n = NonTerminal.new(:N), [t = Terminal.new(:T)]]
|
42
|
+
assert_equal(n, p.symbol)
|
43
|
+
assert_equal(t, p.rhs.first)
|
44
|
+
assert_equal(t, p.right_hand_side.first)
|
45
|
+
|
46
|
+
p2 = Prod[:N, [t]]
|
47
|
+
assert_equal("N", p2.symbol.inspect)
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_07_nonterminal_equality
|
51
|
+
n1 = NonTerminal.new(:N)
|
52
|
+
n2 = NonTerminal.new(:N)
|
53
|
+
assert(n1 == n2)
|
54
|
+
assert(n2 == n1)
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_08_Rule
|
58
|
+
p1 = Prod[n = NonTerminal.new(:N), [Terminal.new(:T1)]]
|
59
|
+
p2 = Prod[:N, [Terminal.new(:T2)]]
|
60
|
+
r = Rule[p1]
|
61
|
+
|
62
|
+
assert(n == r.symbol)
|
63
|
+
assert_equal(1, r.productions.length)
|
64
|
+
|
65
|
+
r.add_production p2
|
66
|
+
assert_equal(n, r.symbol)
|
67
|
+
assert_equal(2, r.productions.length)
|
68
|
+
|
69
|
+
assert_raises(ArgumentError) {r.add_production(Prod[:N2, [Terminal[:T3]]])}
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_09_Grammar
|
73
|
+
g = Grammar.new(:name => "Test Grammar 1", :author => "Robert")
|
74
|
+
assert_kind_of(Grammar, g)
|
75
|
+
assert_equal("Test Grammar 1", g.meta[:name])
|
76
|
+
assert_equal("Robert", g.meta[:author])
|
77
|
+
assert_equal(0, g.rules.length)
|
78
|
+
assert_equal(0, g.nonterminals.length)
|
79
|
+
assert_equal(0, g.terminals.length)
|
80
|
+
assert_equal(0, g.symbols.length)
|
81
|
+
|
82
|
+
g.add_rule(Rule[Prod[:N, [Terminal[:T1]]]])
|
83
|
+
assert_equal(1, g.rules.length)
|
84
|
+
assert_equal(1, g.nonterminals.length)
|
85
|
+
assert_equal(1, g.terminals.length)
|
86
|
+
assert_equal(2, g.symbols.length)
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_10_symbol_predicates
|
90
|
+
nt = NonTerminal[:N]
|
91
|
+
assert_equal(true, nt.nonterminal?)
|
92
|
+
assert_equal(false, nt.terminal?)
|
93
|
+
assert_equal(false, nt.action?)
|
94
|
+
|
95
|
+
t = Terminal[:T]
|
96
|
+
assert_equal(false, t.nonterminal?)
|
97
|
+
assert_equal(true, t.terminal?)
|
98
|
+
assert_equal(false, t.action?)
|
99
|
+
|
100
|
+
a = Action[:A]
|
101
|
+
assert_equal(false, a.nonterminal?)
|
102
|
+
assert_equal(false, a.terminal?)
|
103
|
+
assert_equal(true, a.action?)
|
104
|
+
end
|
105
|
+
|
106
|
+
class TestGrammar < Grammar
|
107
|
+
r :S, [[:B]]
|
108
|
+
r :B, [
|
109
|
+
[Terminal.new(:T1)],
|
110
|
+
[Terminal.new(:T2), Terminal.new(:T3)],
|
111
|
+
]
|
112
|
+
t :CT1, ["A"]
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_11_embedded_grammar_def
|
116
|
+
t = TestGrammar.new
|
117
|
+
|
118
|
+
assert_equal(2, t.rules.length)
|
119
|
+
|
120
|
+
assert_equal(:S, t.rules.first.symbol.name)
|
121
|
+
assert_equal(1, t.rules.first.productions.length)
|
122
|
+
|
123
|
+
assert_equal(:B, t.rules.last.symbol.name)
|
124
|
+
assert_equal(2, t.rules.last.productions.length)
|
125
|
+
assert_equal(:T1, t.rules.last.productions.first.rhs.first.name)
|
126
|
+
assert_equal(:T2, t.rules.last.productions.last.rhs.first.name)
|
127
|
+
assert_equal(:T3, t.rules.last.productions.last.rhs.last.name)
|
128
|
+
|
129
|
+
assert_equal(1, t.complex_terminals.length)
|
130
|
+
|
131
|
+
assert_equal(:CT1, t.complex_terminals.first.name)
|
132
|
+
end
|
133
|
+
|
134
|
+
TestDeepClone = Struct.new(:a)
|
135
|
+
|
136
|
+
def test_12_deep_clone
|
137
|
+
a = [1,2,3]
|
138
|
+
t1 = TestDeepClone.new(a)
|
139
|
+
t1a = t1.clone
|
140
|
+
t1b = t1.deep_clone
|
141
|
+
assert_equal(t1.a.object_id, t1a.a.object_id)
|
142
|
+
assert_not_equal(t1.a.object_id, t1b.a.object_id)
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_13_define_grammar_in_a_block
|
146
|
+
g = Grammar.new do
|
147
|
+
r :S, [["a", :B]]
|
148
|
+
r :B, [["b"]]
|
149
|
+
end
|
150
|
+
assert_equal(2, g.nonterminals.length)
|
151
|
+
end
|
152
|
+
|
153
|
+
def test_14_extending_a_grammar_with_a_block
|
154
|
+
g = TestGrammar.new do
|
155
|
+
r :A, [["a"]]
|
156
|
+
end
|
157
|
+
# Two nonterminals in the original grammar and one new here => 3
|
158
|
+
assert_equal(3, g.nonterminals.length)
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require 'rockit/assembler/llvm/instructions'
|
4
|
+
include Rockit::Assembler::LLVM
|
5
|
+
|
6
|
+
class UTestLLVMInstructions < Test::Unit::TestCase
|
7
|
+
def test_01_NamedValue_valid
|
8
|
+
nv1 = NamedValue.new("foo")
|
9
|
+
assert_equal("%foo", nv1.to_llvm)
|
10
|
+
|
11
|
+
nv2 = NamedValue.new("DivByZero")
|
12
|
+
assert_equal("%DivByZero", nv2.to_llvm)
|
13
|
+
|
14
|
+
nv3 = NamedValue.new("a.really.long.identifier")
|
15
|
+
assert_equal("%a.really.long.identifier", nv3.to_llvm)
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_02_NamedValue_invalid
|
19
|
+
assert_raises(ArgumentError) {NamedValue.new("12")}
|
20
|
+
assert_raises(ArgumentError) {NamedValue.new("%")}
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_03_UnnamedValue_valid
|
24
|
+
u1 = UnnamedValue.new(0)
|
25
|
+
assert_equal("%0", u1.to_llvm)
|
26
|
+
|
27
|
+
u2 = UnnamedValue.new(12)
|
28
|
+
assert_equal("%12", u2.to_llvm)
|
29
|
+
|
30
|
+
u3 = UnnamedValue.new(2)
|
31
|
+
assert_equal("%2", u3.to_llvm)
|
32
|
+
|
33
|
+
u4 = UnnamedValue.new(44)
|
34
|
+
assert_equal("%44", u4.to_llvm)
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_04_UnnamedValue_invalid
|
38
|
+
assert_raises(ArgumentError) {UnnamedValue.new(-1)}
|
39
|
+
assert_raises(ArgumentError) {UnnamedValue.new(-18743)}
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require 'rockit/assembler/llvm/module'
|
4
|
+
include Rockit::Assembler::LLVM
|
5
|
+
|
6
|
+
class UTestLLVMInstructions < Test::Unit::TestCase
|
7
|
+
# Hello world example module
|
8
|
+
class TestModule1 < LLVM::Module
|
9
|
+
LC0 = internal constant '[13 x sbyte]' c("hello world\0A")
|
10
|
+
|
11
|
+
declare int "puts", [sbytep]
|
12
|
+
|
13
|
+
defmethod("main", int, []) do
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def te
|
19
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require 'rockit/prettyprint/box'
|
4
|
+
include Rockit::PrettyPrint
|
5
|
+
|
6
|
+
class UTestBox < Test::Unit::TestCase
|
7
|
+
def setup
|
8
|
+
@h = Box::H.new(1, "a")
|
9
|
+
@h1 = Box::H.new(1, "a", "b")
|
10
|
+
@h2 = Box::H.new(2, "a", "b")
|
11
|
+
@h3 = Box::H.new(3, "a", "b", "c")
|
12
|
+
@v = Box::V.new("a", "2 2", "c")
|
13
|
+
@e = Box::Epsilon.new("x", " ", ":=")
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_01_creation
|
17
|
+
assert_kind_of(Box::H, @h)
|
18
|
+
assert_equal(1, @h.num_spaces)
|
19
|
+
assert_equal(["a"], @h.elements)
|
20
|
+
|
21
|
+
assert_kind_of(Box::H, @h3)
|
22
|
+
assert_equal(3, @h3.num_spaces)
|
23
|
+
assert_equal(["a", "b", "c"], @h3.elements)
|
24
|
+
|
25
|
+
assert_kind_of(Box::V, @v)
|
26
|
+
assert_equal(["a", "2 2", "c"], @v.elements)
|
27
|
+
|
28
|
+
assert_kind_of(Box::Epsilon, @e)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_02_render
|
32
|
+
assert_equal("a", @h.render)
|
33
|
+
assert_equal("a b", @h1.render)
|
34
|
+
assert_equal("a b", @h2.render)
|
35
|
+
assert_equal("a b c", @h3.render)
|
36
|
+
assert_equal("a\n2 2\nc", @v.render)
|
37
|
+
assert_equal("x :=", @e.render)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_03_prepend
|
41
|
+
p = Box::Prepend["#", "A comment"]
|
42
|
+
assert_equal("# A comment", p.render)
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,301 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require 'rockit/tree/base'
|
4
|
+
require 'samples/rockit/ruby/sample_ruby_ast_trees/mr_1'
|
5
|
+
|
6
|
+
class UTestTreeBase < Test::Unit::TestCase
|
7
|
+
def setup
|
8
|
+
@a = Rockit::Tree::Base.new_tree_class(:A)
|
9
|
+
@b = Rockit::Tree::Base.new_tree_class(:B, [:c1])
|
10
|
+
@c = Rockit::Tree::Base.new_tree_class(:C, [:c1, :c2])
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_01_subclass_with_no_named_children
|
14
|
+
t = @a[1]
|
15
|
+
assert_kind_of(@a, t)
|
16
|
+
assert_equal(1, t.children.length)
|
17
|
+
assert_equal(1, t[0])
|
18
|
+
|
19
|
+
t2 = @a["1", 2]
|
20
|
+
assert_kind_of(@a, t2)
|
21
|
+
assert_equal(2, t2.children.length)
|
22
|
+
assert_equal("1", t2[0])
|
23
|
+
assert_equal(2, t2[1])
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_02_subclass_with_one_named_child
|
27
|
+
t = @b[:a]
|
28
|
+
assert_kind_of(@b, t)
|
29
|
+
assert_equal(1, t.children.length)
|
30
|
+
assert_equal(:a, t[0])
|
31
|
+
assert_equal(:a, t.c1)
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_03_subclass_with_two_named_children
|
35
|
+
t = @c[3.0, 4]
|
36
|
+
assert_kind_of(@c, t)
|
37
|
+
assert_equal(2, t.children.length)
|
38
|
+
assert_equal(3.0, t[0])
|
39
|
+
assert_equal(3.0, t.c1)
|
40
|
+
assert_equal(4, t[1])
|
41
|
+
assert_equal(4, t.c2)
|
42
|
+
|
43
|
+
t.c1 = 5
|
44
|
+
assert_equal(5, t[0])
|
45
|
+
assert_equal(5, t.c1)
|
46
|
+
|
47
|
+
t.c2 = 6
|
48
|
+
assert_equal(6, t[1])
|
49
|
+
assert_equal(6, t.c2)
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_04_complex_tree
|
53
|
+
t = @a[@b[@c[1, 2]], @c[3, 4]]
|
54
|
+
assert_kind_of(@a, t)
|
55
|
+
assert_kind_of(@b, t[0])
|
56
|
+
assert_kind_of(@c, t[1])
|
57
|
+
assert_kind_of(@c, t[0][0])
|
58
|
+
assert_equal(1, t[0][0][0])
|
59
|
+
assert_equal(2, t[0][0][1])
|
60
|
+
assert_equal(3, t[1][0])
|
61
|
+
assert_equal(4, t[1][1])
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_05_subclass_of_tree
|
65
|
+
@d = @a.new_tree_class(:D, [:d1, :d2])
|
66
|
+
|
67
|
+
t = @d["sub", /a/]
|
68
|
+
assert_kind_of(@d, t)
|
69
|
+
assert_kind_of(@a, t)
|
70
|
+
assert_equal("sub", t[0])
|
71
|
+
assert_equal("sub", t.d1)
|
72
|
+
assert_equal(/a/, t[1])
|
73
|
+
assert_equal(/a/, t.d2)
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_06_upcase_symbols_to_patternvar
|
77
|
+
t = @a[:X]
|
78
|
+
nt = t.upcase_symbols_to_pattern_vars
|
79
|
+
assert_kind_of(@a, nt)
|
80
|
+
pvar = nt[0]
|
81
|
+
assert_kind_of(Rockit::Tree::Base::PatternVar, pvar)
|
82
|
+
assert_equal(:X, pvar.name)
|
83
|
+
|
84
|
+
t2 = @c[@b[:X], @a[:Y, :Z]]
|
85
|
+
nt2 = t2.upcase_symbols_to_pattern_vars
|
86
|
+
assert_kind_of(@c, nt2)
|
87
|
+
xvar = nt2[0][0]
|
88
|
+
assert_kind_of(Rockit::Tree::Base::PatternVar, xvar)
|
89
|
+
assert_equal(:X, pvar.name)
|
90
|
+
yvar = nt2[1][0]
|
91
|
+
assert_kind_of(Rockit::Tree::Base::PatternVar, yvar)
|
92
|
+
assert_equal(:Y, yvar.name)
|
93
|
+
zvar = nt2[1][1]
|
94
|
+
assert_kind_of(Rockit::Tree::Base::PatternVar, zvar)
|
95
|
+
assert_equal(:Z, zvar.name)
|
96
|
+
end
|
97
|
+
|
98
|
+
def assert_match_result(expected, tree, pattern)
|
99
|
+
actual = pattern.upcase_symbols_to_pattern_vars.match_tree(tree)
|
100
|
+
assert_equal(expected, actual)
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_07_match_tree_simple
|
104
|
+
pattern = @a[:X].upcase_symbols_to_pattern_vars
|
105
|
+
tree = @a[1]
|
106
|
+
res = pattern.match_tree(tree)
|
107
|
+
assert_kind_of(Hash, res)
|
108
|
+
assert_equal(1, res[:X])
|
109
|
+
|
110
|
+
t2 = @a[t3 = @b[1]]
|
111
|
+
assert_match_result({:X => t3}, t2, pattern)
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_08_match_tree_complex
|
115
|
+
pattern = @c[@b[:X], @a[:Y]].upcase_symbols_to_pattern_vars
|
116
|
+
tree = @c[@b["23"], @a[/a/]]
|
117
|
+
res = pattern.match_tree(tree)
|
118
|
+
assert_kind_of(Hash, res)
|
119
|
+
assert_equal("23", res[:X])
|
120
|
+
assert_equal(/a/, res[:Y])
|
121
|
+
|
122
|
+
pattern = @b[@c[:L, :R]].upcase_symbols_to_pattern_vars
|
123
|
+
t2 = @b[t3 = @c[3, 4]]
|
124
|
+
res = pattern.match_tree(t2)
|
125
|
+
assert_equal({:L => 3, :R => 4}, res)
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_09_match_tree_complex_with_subtrees
|
129
|
+
pattern = @c[@b[:ARNE], @a[:STree]].upcase_symbols_to_pattern_vars
|
130
|
+
stree = @c[3, 4]
|
131
|
+
tree = @c[@b[1.4], @a[stree]]
|
132
|
+
res = pattern.match_tree(tree)
|
133
|
+
assert_kind_of(Hash, res)
|
134
|
+
assert_equal(1.4, res[:ARNE])
|
135
|
+
assert_equal(stree, res[:STree])
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_10_regexp_style_matching
|
139
|
+
stree = @a[]
|
140
|
+
res = @b[@c[stree, 2]] =~ @b[@c[:First, :Second]]
|
141
|
+
assert_kind_of(Hash, res)
|
142
|
+
assert_equal(2, res[:Second])
|
143
|
+
assert_equal(stree, res[:First])
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_11_failing_match_tree
|
147
|
+
assert_match_result(nil, @b[1], @a[])
|
148
|
+
assert_match_result(nil, @a[1], @b[])
|
149
|
+
assert_match_result(nil, @a[1], @a[2])
|
150
|
+
assert_match_result(nil, @c[@a[], 1], @c[@a[], 2])
|
151
|
+
assert_match_result(nil, @c[@a[], "1"], @c[@a[], "2"])
|
152
|
+
end
|
153
|
+
|
154
|
+
def assert_pp(expected, tree, width = 79)
|
155
|
+
actual = ""
|
156
|
+
PP.pp(tree, actual, width)
|
157
|
+
assert_equal(expected, actual)
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_12_pretty_print
|
161
|
+
assert_pp("A[1]\n", @a[1])
|
162
|
+
assert_pp("A[B[2]]\n", @a[@b[2]])
|
163
|
+
assert_pp("C[B[3.0], /a/]\n", @c[@b[3.0], /a/])
|
164
|
+
lstr = "." * 75
|
165
|
+
assert_pp("C[\n B[3.0],\n #{lstr.inspect}]\n", @c[@b[3.0], lstr])
|
166
|
+
end
|
167
|
+
|
168
|
+
def collect_trees(tree)
|
169
|
+
ary = []
|
170
|
+
tree.each_tree {|t| ary << t}
|
171
|
+
ary
|
172
|
+
end
|
173
|
+
|
174
|
+
def test_13_each_tree_simple
|
175
|
+
t = @a[]
|
176
|
+
assert_equal([t], collect_trees(t))
|
177
|
+
end
|
178
|
+
|
179
|
+
def test_14_each_tree_complex
|
180
|
+
t = @c[t2 = @b[t3 = @a[1]], t4 = @b[2]]
|
181
|
+
assert_equal([t, t2, t3, 1, t4, 2], collect_trees(t))
|
182
|
+
end
|
183
|
+
|
184
|
+
def collect_trees_of_class(tree, klass, recursive = false)
|
185
|
+
ary = []
|
186
|
+
tree.each_tree_of_class(klass, recursive) {|t| ary << t}
|
187
|
+
ary
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_15_each_tree_of_klass
|
191
|
+
t = @c[t2 = @b[t3 = @a[t4 = @b[1]]], t5 = @b[t6 = @c[3, 4]]]
|
192
|
+
assert_equal([t2, t5], collect_trees_of_class(t, @b))
|
193
|
+
assert_equal([t2, t4, t5], collect_trees_of_class(t, @b, true))
|
194
|
+
assert_equal([t3], collect_trees_of_class(t, @a))
|
195
|
+
assert_equal([t], collect_trees_of_class(t, @c))
|
196
|
+
assert_equal([t, t6], collect_trees_of_class(t, @c, true))
|
197
|
+
end
|
198
|
+
|
199
|
+
def test_16_set_parents_and_parent
|
200
|
+
t = @c[t2 = @b[t3 = @a[t4 = @b[1]]], t5 = @b[t6 = @c[3, 4]]]
|
201
|
+
|
202
|
+
assert_equal(nil, t.parent)
|
203
|
+
assert_equal(nil, t2.parent)
|
204
|
+
assert_equal(nil, t3.parent)
|
205
|
+
assert_equal(nil, t4.parent)
|
206
|
+
assert_equal(nil, t5.parent)
|
207
|
+
assert_equal(nil, t6.parent)
|
208
|
+
|
209
|
+
t.set_parents
|
210
|
+
|
211
|
+
assert_equal(nil, t.parent)
|
212
|
+
assert_equal(t, t2.parent)
|
213
|
+
assert_equal(t2, t3.parent)
|
214
|
+
assert_equal(t3, t4.parent)
|
215
|
+
assert_equal(t, t5.parent)
|
216
|
+
assert_equal(t5, t6.parent)
|
217
|
+
end
|
218
|
+
|
219
|
+
def test_17_all_matching_trees
|
220
|
+
t = @c[t2 = @b[t3 = @a[t4 = @b[1]]], t5 = @b[t6 = @c[3, 4]]]
|
221
|
+
|
222
|
+
pattern = @a[:X]
|
223
|
+
res = pattern.all_matching_trees(t)
|
224
|
+
assert_kind_of(Array, res)
|
225
|
+
assert_equal(1, res.length)
|
226
|
+
mapping, subtree = res[0]
|
227
|
+
assert_kind_of(Hash, mapping)
|
228
|
+
assert_equal({:X => t4}, mapping)
|
229
|
+
assert_kind_of(Rockit::Tree::Base, subtree)
|
230
|
+
assert_equal(t3, subtree)
|
231
|
+
|
232
|
+
pattern = @b[:X]
|
233
|
+
res = pattern.all_matching_trees(t)
|
234
|
+
assert_equal(3, res.length)
|
235
|
+
assert_equal({:X => t3}, res[0][0])
|
236
|
+
assert_equal(t2, res[0][1])
|
237
|
+
assert_equal({:X => 1}, res[1][0])
|
238
|
+
assert_equal(t4, res[1][1])
|
239
|
+
assert_equal({:X => t6}, res[2][0])
|
240
|
+
assert_equal(t5, res[2][1])
|
241
|
+
|
242
|
+
pattern = @c[:Left, :Right]
|
243
|
+
res = pattern.all_matching_trees(t)
|
244
|
+
assert_equal(2, res.length)
|
245
|
+
assert_equal({:Left => t2, :Right => t5}, res[0][0])
|
246
|
+
assert_equal(t, res[0][1])
|
247
|
+
assert_equal({:Left => 3, :Right => 4}, res[1][0])
|
248
|
+
assert_equal(t6, res[1][1])
|
249
|
+
|
250
|
+
pattern = @b[@a[:Z]]
|
251
|
+
res = pattern.all_matching_trees(t)
|
252
|
+
assert_equal(1, res.length)
|
253
|
+
assert_equal({:Z => t4}, res[0][0])
|
254
|
+
assert_equal(t2, res[0][1])
|
255
|
+
|
256
|
+
pattern = @b[@c[:L, :R]]
|
257
|
+
res = pattern.all_matching_trees(t)
|
258
|
+
assert_equal(1, res.length)
|
259
|
+
assert_equal({:L => 3, :R => 4}, res[0][0])
|
260
|
+
assert_equal(t5, res[0][1])
|
261
|
+
end
|
262
|
+
|
263
|
+
def test_18_bug_with_nested_string_child
|
264
|
+
t = @a["y", 1]
|
265
|
+
res = @a["y", :X].upcase_symbols_to_pattern_vars.match_tree(t)
|
266
|
+
assert_equal({:X => 1}, res)
|
267
|
+
|
268
|
+
t = @a[@b["y"], 1]
|
269
|
+
res = @a[@b["y"], :X].upcase_symbols_to_pattern_vars.match_tree(t)
|
270
|
+
assert_equal({:X => 1}, res)
|
271
|
+
|
272
|
+
res = @a[@b["y"], :X].all_matching_trees(t)
|
273
|
+
assert_equal(1, res.length)
|
274
|
+
end
|
275
|
+
|
276
|
+
def test_18_complex_tree_binop_bug
|
277
|
+
pattern = BinOpCall[:X, "-", :Y]
|
278
|
+
res = pattern.all_matching_trees(MR1Tree)
|
279
|
+
assert_equal(1, res.length)
|
280
|
+
|
281
|
+
res = BinOpCall[:X, "/", :Y].all_matching_trees(MR1Tree)
|
282
|
+
assert_equal(1, res.length)
|
283
|
+
|
284
|
+
res = BinOpCall[:X, "+", :Y].all_matching_trees(MR1Tree)
|
285
|
+
assert_equal(1, res.length)
|
286
|
+
|
287
|
+
res = BinOpCall[:X, "*", :Y].all_matching_trees(MR1Tree)
|
288
|
+
assert_equal(0, res.length)
|
289
|
+
|
290
|
+
res = Assign[LVar["y"], :X].all_matching_trees(MR1Tree)
|
291
|
+
assert_equal(4, res.length)
|
292
|
+
end
|
293
|
+
|
294
|
+
def test_19_should_traverse_into_arrays
|
295
|
+
# We need this since it is quite common that a collection of statements
|
296
|
+
# are simply given in an Array. It might be a design smell though!
|
297
|
+
tree = @a[[@b[1]]]
|
298
|
+
bs = tree.select_trees_of_class(@b)
|
299
|
+
assert_equal(1, bs.length)
|
300
|
+
end
|
301
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require 'rockit/tree/enter_leave_visitor'
|
4
|
+
|
5
|
+
class UTestTreeEnterLeaveVisitor < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@a = Rockit::Tree::Base.new_tree_class(:A)
|
8
|
+
@b = Rockit::Tree::Base.new_tree_class(:B, [:c1])
|
9
|
+
@c = Rockit::Tree::Base.new_tree_class(:C, [:c1, :c2])
|
10
|
+
@d = Rockit::Tree::Base.new_tree_class(:D)
|
11
|
+
@e = Rockit::Tree::Base.new_tree_class(:E)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Visits a node both on the way down in the tree and on the way up.
|
15
|
+
# Still a depth-first search.
|
16
|
+
class TreeELVisitor
|
17
|
+
include EnterLeaveVisitor
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
@visited = []
|
21
|
+
end
|
22
|
+
|
23
|
+
def [](index); @visited[index]; end
|
24
|
+
|
25
|
+
def enter_A(obj); @visited << obj; end
|
26
|
+
def leave_A(obj); @visited << obj; end
|
27
|
+
def enter_B(obj); @visited << obj; end
|
28
|
+
def leave_B(obj); @visited << obj; end
|
29
|
+
def enter_C(obj); @visited << obj; end
|
30
|
+
def leave_C(obj); @visited << obj; end
|
31
|
+
def visit_E(obj); @visited << obj; end
|
32
|
+
end
|
33
|
+
|
34
|
+
class TreeAndFixnumELVisitor < TreeELVisitor
|
35
|
+
def enter_Fixnum(obj); @visited << obj; end
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_01_visitor
|
39
|
+
tree = @c[tb1 = @b[ta = @a[@d[te = @e[]]]], tb2 = @b[t1 = 1]]
|
40
|
+
visitor = TreeELVisitor.new
|
41
|
+
tree.accept_visitor(visitor)
|
42
|
+
|
43
|
+
assert_equal(tree, visitor[0])
|
44
|
+
assert_equal(tb1, visitor[1])
|
45
|
+
assert_equal(ta, visitor[2])
|
46
|
+
# D is never visited sine we have no enter, visit or leave method for it.
|
47
|
+
# E is visited even though we only have a visit method but no enter or
|
48
|
+
# leave methods.
|
49
|
+
assert_equal(te, visitor[3])
|
50
|
+
assert_equal(ta, visitor[4])
|
51
|
+
assert_equal(tb1, visitor[5])
|
52
|
+
assert_equal(tb2, visitor[6])
|
53
|
+
assert_equal(tb2, visitor[7])
|
54
|
+
assert_equal(tree, visitor[8])
|
55
|
+
|
56
|
+
visitor2 = TreeAndFixnumELVisitor.new
|
57
|
+
tree.accept_visitor(visitor2)
|
58
|
+
assert_equal(tree, visitor2[0])
|
59
|
+
assert_equal(tb1, visitor2[1])
|
60
|
+
assert_equal(ta, visitor2[2])
|
61
|
+
assert_equal(te, visitor[3])
|
62
|
+
assert_equal(ta, visitor2[4])
|
63
|
+
assert_equal(tb1, visitor2[5])
|
64
|
+
assert_equal(tb2, visitor2[6])
|
65
|
+
assert_equal(1, visitor2[7])
|
66
|
+
assert_equal(tb2, visitor2[8])
|
67
|
+
assert_equal(tree, visitor2[9])
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require 'rockit/tree/visitor'
|
4
|
+
|
5
|
+
class UTestTreeVisitor < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@a = Rockit::Tree::Base.new_tree_class(:A)
|
8
|
+
@b = Rockit::Tree::Base.new_tree_class(:B, [:c1])
|
9
|
+
@c = Rockit::Tree::Base.new_tree_class(:C, [:c1, :c2])
|
10
|
+
end
|
11
|
+
|
12
|
+
class TreeVisitor
|
13
|
+
include Visitor
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@visited = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def [](index); @visited[index]; end
|
20
|
+
|
21
|
+
def visit_A(obj)
|
22
|
+
@visited << obj
|
23
|
+
end
|
24
|
+
|
25
|
+
def visit_B(obj)
|
26
|
+
@visited << obj
|
27
|
+
end
|
28
|
+
|
29
|
+
def visit_C(obj)
|
30
|
+
@visited << obj
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class TreeAndFixnumVisitor < TreeVisitor
|
35
|
+
def visit_Fixnum(obj)
|
36
|
+
@visited << obj
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_01_visitor
|
41
|
+
tree = @c[tb1 = @b[ta = @a[]], tb2 = @b[t1 = 1]]
|
42
|
+
visitor = TreeVisitor.new
|
43
|
+
tree.accept_visitor(visitor)
|
44
|
+
# The visitor pattern by default does a depth-first visit of the nodes
|
45
|
+
# in the tree. Note that the 1 is not in the visited list since the visitor
|
46
|
+
# has no method to visit Fixnums.
|
47
|
+
assert_equal(tree, visitor[0])
|
48
|
+
assert_equal(tb1, visitor[1])
|
49
|
+
assert_equal(ta, visitor[2])
|
50
|
+
assert_equal(tb2, visitor[3])
|
51
|
+
|
52
|
+
# This visitor has a method to visit Fixnums so it should have the same
|
53
|
+
# obj's in the visited array as the previous one but then followed by
|
54
|
+
# the 1 that is the child of the tb2 tree above.
|
55
|
+
visitor2 = TreeAndFixnumVisitor.new
|
56
|
+
tree.accept_visitor(visitor2)
|
57
|
+
assert_equal(tree, visitor2[0])
|
58
|
+
assert_equal(tb1, visitor2[1])
|
59
|
+
assert_equal(ta, visitor2[2])
|
60
|
+
assert_equal(tb2, visitor2[3])
|
61
|
+
assert_equal(t1, visitor2[4])
|
62
|
+
end
|
63
|
+
end
|