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,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
|