#!/usr/bin/ruby # encoding: utf-8 require 'antlr3' require 'test/unit' require 'spec' include ANTLR3 include ANTLR3::AST class TestTreeNodeStream < Test::Unit::TestCase def setup @adaptor = CommonTreeAdaptor.new end def new_stream(t) CommonTreeNodeStream.new(t) end def test_single_node t = CommonTree.new(CommonToken.new { |t| t.type = 101 }) stream = new_stream(t) expecting = '101' found = nodes_only_string(stream) found.should == expecting expecting = '' found = stream.inspect found.should == expecting end def test_two_children_of_nil_root v = Class.new(CommonTree) do def initialize(token = nil, type = nil, x = nil) @x = x super(token || (CommonToken.new { |t| t.type = type } if type)) end def to_s (@token.text rescue '') + '' end end root_0 = @adaptor.create_flat_list t = v.new(nil, 101, 2) u = v.new CommonToken.create(:type => 102, :text => '102') @adaptor.add_child(root_0, t) @adaptor.add_child(root_0, u) assert(root_0.parent.nil?) root_0.child_index.should == -1 t.child_index.should == 0 u.child_index.should == 1 end def test_4_nodes t = CommonTree.new CommonToken[101] t.add_child( CommonTree.new CommonToken[102] ) t.child(0).add_child(CommonTree.new CommonToken[103]) t.add_child(CommonTree.new CommonToken[104]) stream = new_stream(t) expecting = "101 102 103 104" found = nodes_only_string(stream) found.should == expecting expecting = " " found = stream.inspect found.should == expecting end def test_list root = CommonTree.new(nil) t = CommonTree.new CommonToken[101] t.add_child CommonTree.new(CommonToken[102]) t.child(0).add_child(CommonTree.new(CommonToken[103])) t.add_child(CommonTree.new(CommonToken[104])) u = CommonTree.new CommonToken[105] root.add_child(t) root.add_child(u) stream = CommonTreeNodeStream.new(root) expecting = '101 102 103 104 105' found = nodes_only_string(stream) found.should == expecting expecting = " " found = stream.inspect found.should == expecting end def test_flat_list root = CommonTree.new(nil) root.add_child CommonTree.new(CommonToken[101]) root.add_child(CommonTree.new(CommonToken[102])) root.add_child(CommonTree.new(CommonToken[103])) stream = CommonTreeNodeStream.new( root ) expecting = '101 102 103' found = nodes_only_string(stream) found.should == expecting expecting = ' ' found = stream.inspect found.should == expecting end def test_list_with_one_node root = CommonTree.new(nil) root.add_child(CommonTree.new(CommonToken[101])) stream = CommonTreeNodeStream.new(root) expecting = '101' found = nodes_only_string(stream) found.should == expecting expecting = "" found = stream.inspect found.should == expecting end def test_a_over_b t = CommonTree.new(CommonToken[101]) t.add_child(CommonTree.new(CommonToken[102])) stream = new_stream(t) expecting = '101 102' found = nodes_only_string(stream) found.should == expecting expecting = ' ' found = stream.inspect found.should == expecting end def test_LT # ^(101 ^(102 103) 104) t = CommonTree.new CommonToken[101] t.add_child CommonTree.new(CommonToken[102]) t.child(0).add_child(CommonTree.new(CommonToken[103])) t.add_child(CommonTree.new(CommonToken[104])) stream = new_stream(t) [101, DOWN, 102, DOWN, 103, UP, 104, UP, EOF].each_with_index do |type, index| stream.look(index + 1).type.should == type end stream.look(100).type.should == EOF end def test_mark_rewind_entire # ^(101 ^(102 103 ^(106 107)) 104 105) r0 = new_node new_token(101) r1 = new_node new_token(102) r0.add_child(r1) r1.add_child(new_node new_token(103)) r2 = new_node new_token(106) r2.add_child new_node( new_token 107 ) r1.add_child r2 r0.add_child new_node( new_token 104 ) r0.add_child new_node( new_token 105 ) stream = CommonTreeNodeStream.new(r0) m = stream.mark 13.times { stream.look(1); stream.consume } # consume until end stream.look(1).type.should == EOF stream.look(-1).type.should == UP stream.rewind(m) 13.times { stream.look(1); stream.consume } # consume until end stream.look(1).type.should == EOF stream.look(-1).type.should == UP end def test_mark_rewind_in_middle # ^(101 ^(102 103 ^(106 107)) 104 105) r0 = new_node new_token(101) r1 = new_node new_token(102) r0.add_child r1 r1.add_child new_node( new_token 103 ) r2 = new_node new_token(106) r2.add_child new_node( new_token 107 ) r1.add_child r2 r0.add_child new_node( new_token 104 ) r0.add_child new_node( new_token 105 ) stream = CommonTreeNodeStream.new(r0) 7.times { stream.consume } stream.look(1).type.should == 107 m = stream.mark 4.times { stream.consume } stream.rewind(m) [107, UP, UP, 104].each do |val| stream.look(1).type.should == val stream.consume end # past rewind position now [105, UP].each do |val| stream.look(1).type.should == val stream.consume end stream.look(1).type.should == EOF stream.look(-1).type.should == UP end def test_mark_rewind_nested # ^(101 ^(102 103 ^(106 107)) 104 105) r0 = new_node new_token(101) r1 = new_node new_token(102) r0.add_child r1 r1.add_child new_node( new_token 103 ) r2 = new_node new_token(106) r2.add_child new_node( new_token 107 ) r1.add_child r2 r0.add_child new_node( new_token 104 ) r0.add_child new_node( new_token 105 ) stream = CommonTreeNodeStream.new(r0) m = stream.mark 2.times { stream.consume } m2 = stream.mark 4.times { stream.consume } stream.rewind(m2) stream.look(1).type.should == 102 stream.consume stream.look(1).type.should == DOWN stream.consume stream.rewind(m) [101, DOWN, 102].each do |val| stream.look(1).type.should == val stream.consume end stream.look(1).type.should == DOWN end def test_seek # ^(101 ^(102 103 ^(106 107) ) 104 105) # stream has 7 real + 6 nav nodes # Sequence of types: 101 DN 102 DN 103 106 DN 107 UP UP 104 105 UP EOF r0 = new_node new_token(101) r1 = new_node new_token(102) r0.add_child r1 r1.add_child new_node( new_token 103 ) r2 = new_node new_token(106) r2.add_child new_node( new_token 107 ) r1.add_child r2 r0.add_child new_node( new_token 104 ) r0.add_child new_node( new_token 105 ) stream = CommonTreeNodeStream.new(r0) 3.times { stream.consume } stream.seek(7) stream.look(1).type.should == 107 3.times { stream.consume } stream.look(1).type.should == 104 end def test_seek_from_start r0 = new_node new_token(101) r1 = new_node new_token(102) r0.add_child r1 r1.add_child new_node( new_token 103 ) r2 = new_node new_token(106) r2.add_child new_node( new_token 107 ) r1.add_child r2 r0.add_child new_node( new_token 104 ) r0.add_child new_node( new_token 105 ) stream = CommonTreeNodeStream.new(r0) stream.seek(7) stream.look(1).type.should == 107 3.times { stream.consume } stream.look(1).type.should == 104 end def nodes_only_string(nodes) buffer = [] nodes.size.times do |index| t = nodes.look(index + 1) type = nodes.tree_adaptor.type_of(t) buffer << type.to_s unless type == DOWN or type == UP end return buffer.join(' ') end def new_token(type, opts = {}) opts[:type] = type CommonToken.create(opts) end def new_node(token) CommonTree.new(token) end end class TestCommonTreeNodeStream < Test::Unit::TestCase def setup # before-each-test code end def teardown # after-each-test code end # vvvvvvvv tests vvvvvvvvv def test_push_pop r0 = new_node new_token(101) r1 = new_node new_token(102) r1.add_child new_node( new_token 103 ) r0.add_child r1 r2 = new_node new_token(104) r2.add_child new_node( new_token 105 ) r0.add_child r2 r3 = new_node new_token(106) r3.add_child new_node( new_token 107 ) r0.add_child r3 r0.add_child new_node( new_token 108 ) r0.add_child new_node( new_token 109 ) stream = CommonTreeNodeStream.new(r0) expecting = ' ' + ' ' + ' ' found = stream.inspect found.should == expecting index_of_102 = 2 index_of_107 = 12 index_of_107.times { stream.consume } stream.look(1).type.should == 107 stream.push(index_of_102) stream.look(1).type.should == 102 stream.consume stream.look(1).type.should == DOWN stream.consume stream.look(1).type.should == 103 stream.consume stream.look(1).type.should == UP stream.pop stream.look(1).type.should == 107 end def test_nested_push_pop r0 = new_node new_token(101) r1 = new_node new_token(102) r1.add_child new_node( new_token 103 ) r0.add_child r1 r2 = new_node new_token(104) r2.add_child new_node( new_token 105 ) r0.add_child r2 r3 = new_node new_token(106) r3.add_child new_node( new_token 107 ) r0.add_child r3 r0.add_child new_node( new_token 108 ) r0.add_child new_node( new_token 109 ) stream = CommonTreeNodeStream.new(r0) index_of_102 = 2 index_of_107 = 12 index_of_107.times { stream.consume } stream.look(1).type.should == 107 stream.push(index_of_102) [102, DOWN, 103].each do |val| stream.look(1).type.should == val stream.consume end index_of_104 = 6 stream.push(index_of_104) [104,DOWN,105].each do |val| stream.look(1).type.should == val stream.consume end stream.look(1).type.should == UP stream.pop stream.look(1).type.should == UP stream.pop stream.look(1).type.should == 107 end def test_push_pop_from_eof r0 = new_node new_token(101) r1 = new_node new_token(102) r1.add_child new_node( new_token 103 ) r0.add_child r1 r2 = new_node new_token(104) r2.add_child new_node( new_token 105 ) r0.add_child r2 r3 = new_node new_token(106) r3.add_child new_node( new_token 107 ) r0.add_child r3 r0.add_child new_node( new_token 108 ) r0.add_child new_node( new_token 109 ) stream = CommonTreeNodeStream.new(r0) stream.consume until stream.peek(1) == EOF index_of_102 = 2 index_of_104 = 6 stream.look(1).type.should == EOF stream.push(index_of_102) [102, DOWN, 103].each do |val| stream.look(1).type.should == val stream.consume end stream.look(1).type.should == UP stream.pop stream.look(1).type.should == EOF stream.push(index_of_104) [104, DOWN, 105].each do |val| stream.look(1).type.should == val stream.consume end stream.look(1).type.should == UP stream.pop stream.look(1).type.should == EOF end def new_token(type, opts = {}) opts[:type] = type CommonToken.create(opts) end def new_node(token) CommonTree.new(token) end end class TestCommonTree < Test::Unit::TestCase def setup @adaptor = CommonTreeAdaptor.new end def teardown # after-each-test code end # vvvvvvvv tests vvvvvvvvv def test_single_node t = new_node( new_token 101 ) assert_nil t.parent t.child_index.should == -1 end def test_4_nodes # ^(101 ^(102 103) 104) r0 = new_node( new_token 101 ) r0.add_child new_node( new_token 102 ) r0.child(0).add_child new_node( new_token 103 ) r0.add_child new_node( new_token 104 ) assert_nil r0.parent r0.child_index.should == -1 end def test_list # ^(nil 101 102 103) r0 = CommonTree.new(nil) c0 = new_node( new_token 101 ) r0.add_child c0 c1 = new_node( new_token 102 ) r0.add_child c1 c2 = new_node( new_token 103 ) r0.add_child c2 assert_nil r0.parent r0.child_index.should == -1 c0.parent.should == r0 c0.child_index.should == 0 c1.parent.should == r0 c1.child_index.should == 1 c2.parent.should == r0 c2.child_index.should == 2 end def test_list2 # ^(nil 101 102 103) root = new_node( new_token 5 ) r0 = CommonTree.new(nil) c0 = new_node( new_token 101 ) r0.add_child c0 c1 = new_node( new_token 102 ) r0.add_child c1 c2 = new_node( new_token 103 ) r0.add_child c2 root.add_child r0 assert_nil root.parent root.child_index.should == -1 c0.parent.should == root c0.child_index.should == 0 c1.parent.should == root # note -- actual python tests all use c0 here, which i think might be wrong c1.child_index.should == 1 c2.parent.should == root # note -- actual python tests all use c0 here, which i think might be wrong c2.child_index.should == 2 end def test_add_list_to_exist_children root = new_node( new_token 5 ) root.add_child new_node( new_token 6 ) r0 = CommonTree.new(nil) c0 = new_node( new_token 101 ) r0.add_child c0 c1 = new_node( new_token 102 ) r0.add_child c1 c2 = new_node( new_token 103 ) r0.add_child c2 # ^(nil c0=101 c1=102 c2=103) root.add_child(r0) assert_nil root.parent root.child_index.should == -1 c0.parent.should == root c0.child_index.should == 1 c1.parent.should == root c1.child_index.should == 2 c2.parent.should == root c2.child_index.should == 3 end def test_copy_tree r0 = new_node( new_token 101 ) r1 = new_node( new_token 102 ) r2 = new_node( new_token 106 ) r0.add_child( r1 ) r1.add_child( new_node( new_token 103 ) ) r2.add_child( new_node( new_token 107 ) ) r1.add_child( r2 ) r0.add_child( new_node( new_token 104 ) ) r0.add_child( new_node( new_token 105 ) ) dup = @adaptor.copy_tree( r0 ) assert_nil dup.parent dup.child_index.should == -1 dup.sanity_check end def test_become_root new_root = new_node( new_token 5 ) old_root = new_node nil old_root.add_child( new_node( new_token 101 ) ) old_root.add_child( new_node( new_token 102 ) ) old_root.add_child( new_node( new_token 103 ) ) @adaptor.become_root(new_root, old_root) new_root.sanity_check end def test_become_root2 new_root = new_node( new_token 5 ) old_root = new_node( new_token 101 ) old_root.add_child( new_node( new_token 102 ) ) old_root.add_child( new_node( new_token 103 ) ) @adaptor.become_root(new_root, old_root) new_root.sanity_check end def test_become_root3 new_root = new_node nil new_root.add_child( new_node( new_token 5 ) ) old_root = new_node nil old_root.add_child( new_node( new_token 101 ) ) old_root.add_child( new_node( new_token 102 ) ) old_root.add_child( new_node( new_token 103 ) ) @adaptor.become_root(new_root, old_root) new_root.sanity_check end def test_become_root5 new_root = new_node nil new_root.add_child( new_node( new_token 5 ) ) old_root = new_node( new_token 101 ) old_root.add_child( new_node( new_token 102 ) ) old_root.add_child( new_node( new_token 103 ) ) @adaptor.become_root(new_root, old_root) new_root.sanity_check end def test_become_root6 root_0 = @adaptor.create_flat_list root_1 = @adaptor.create_flat_list root_1 = @adaptor.become_root( new_node( new_token 5 ), root_1 ) @adaptor.add_child( root_1, new_node( new_token 6 ) ) @adaptor.add_child( root_0, root_1 ) root_0.sanity_check end def test_replace_with_no_children t = new_node( new_token 101 ) new_child = new_node( new_token 5 ) error = false assert_raise(IndexError) do t.replace_children(0, 0, new_child) end end def test_replace_with_one_children t = new_node( new_token 99, :text => 'a' ) c0 = new_node( new_token 99, :text => 'b' ) t.add_child(c0) new_child = new_node( new_token 99, :text => 'c' ) t.replace_children(0,0,new_child) t.inspect.should == '(a c)' t.sanity_check end def test_replace_in_middle t = new_node( new_token 99, :text => 'a' ) t.add_child new_node( new_token 99, :text => 'b' ) t.add_child new_node( new_token 99, :text => 'c' ) t.add_child new_node( new_token 99, :text => 'd' ) new_child = new_node( new_token 99, :text => 'x' ) t.replace_children(1, 1, new_child) t.inspect.should == '(a b x d)' t.sanity_check end def test_replace_at_left t = new_node( new_token 99, :text => 'a' ) t.add_child new_node( new_token 99, :text => 'b' ) t.add_child new_node( new_token 99, :text => 'c' ) t.add_child new_node( new_token 99, :text => 'd' ) new_child = new_node( new_token 99, :text => 'x' ) t.replace_children(0, 0, new_child) t.inspect.should == '(a x c d)' t.sanity_check end def test_replace_at_left t = new_node( new_token 99, :text => 'a' ) t.add_child new_node( new_token 99, :text => 'b' ) t.add_child new_node( new_token 99, :text => 'c' ) t.add_child new_node( new_token 99, :text => 'd' ) new_child = new_node( new_token 99, :text => 'x' ) t.replace_children(2, 2, new_child) t.inspect.should == '(a b c x)' t.sanity_check end def test_replace_one_with_two_at_left t = new_node( new_token 99, :text => 'a' ) t.add_child new_node( new_token 99, :text => 'b' ) t.add_child new_node( new_token 99, :text => 'c' ) t.add_child new_node( new_token 99, :text => 'd' ) new_children = @adaptor.create_flat_list new_children.add_child new_node( new_token 99, :text => 'x' ) new_children.add_child new_node( new_token 99, :text => 'y' ) t.replace_children(0, 0, new_children) t.inspect.should == '(a x y c d)' t.sanity_check end def test_replace_one_with_two_at_right t = new_node( new_token 99, :text => 'a' ) t.add_child new_node( new_token 99, :text => 'b' ) t.add_child new_node( new_token 99, :text => 'c' ) t.add_child new_node( new_token 99, :text => 'd' ) new_children = @adaptor.create_flat_list new_children.add_child new_node( new_token 99, :text => 'x' ) new_children.add_child new_node( new_token 99, :text => 'y' ) t.replace_children(2, 2, new_children) t.inspect.should == '(a b c x y)' t.sanity_check end def test_replace_one_with_two_in_middle t = new_node( new_token 99, :text => 'a' ) t.add_child new_node( new_token 99, :text => 'b' ) t.add_child new_node( new_token 99, :text => 'c' ) t.add_child new_node( new_token 99, :text => 'd' ) new_children = @adaptor.create_flat_list new_children.add_child new_node( new_token 99, :text => 'x' ) new_children.add_child new_node( new_token 99, :text => 'y' ) t.replace_children(1, 1, new_children) t.inspect.should == '(a b x y d)' t.sanity_check end def test_replace_two_with_one_at_left t = new_node( new_token 99, :text => 'a' ) t.add_child new_node( new_token 99, :text => 'b' ) t.add_child new_node( new_token 99, :text => 'c' ) t.add_child new_node( new_token 99, :text => 'd' ) new_child = new_node( new_token 99, :text => 'x' ) t.replace_children(0, 1, new_child) t.inspect.should == '(a x d)' t.sanity_check end def test_replace_two_with_one_at_right t = new_node( new_token 99, :text => 'a' ) t.add_child new_node( new_token 99, :text => 'b' ) t.add_child new_node( new_token 99, :text => 'c' ) t.add_child new_node( new_token 99, :text => 'd' ) new_child = new_node( new_token 99, :text => 'x' ) t.replace_children(1, 2, new_child) t.inspect.should == '(a b x)' t.sanity_check end def test_replace_all_with_one t = new_node( new_token 99, :text => 'a' ) t.add_child new_node( new_token 99, :text => 'b' ) t.add_child new_node( new_token 99, :text => 'c' ) t.add_child new_node( new_token 99, :text => 'd' ) new_child = new_node( new_token 99, :text => 'x' ) t.replace_children(0, 2, new_child) t.inspect.should == '(a x)' t.sanity_check end def test_replace_all_with_two t = new_node( new_token 99, :text => 'a' ) t.add_child new_node( new_token 99, :text => 'b' ) t.add_child new_node( new_token 99, :text => 'c' ) t.add_child new_node( new_token 99, :text => 'd' ) new_children = @adaptor.create_flat_list new_children.add_child new_node( new_token 99, :text => 'x' ) new_children.add_child new_node( new_token 99, :text => 'y' ) t.replace_children(0, 1, new_children) t.inspect.should == '(a x y d)' t.sanity_check end def new_token(type, opts = {}) opts[:type] = type CommonToken.create(opts) end def new_node(token) CommonTree.new(token) end end class TestTreeContext < Test::Unit::TestCase TOKEN_NAMES = %w( VEC ASSIGN PRINT PLUS MULT DOT ID INT WS '[' ',' ']' ) Tokens = TokenScheme.build( TOKEN_NAMES ) def setup @wizard = Wizard.new( :token_scheme => Tokens ) end def teardown # after-each-test code end # vvvvvvvv tests vvvvvvvvv def test_simple_parent tree = @wizard.create( "(nil (ASSIGN ID[x] INT[3]) (PRINT (MULT ID[x] (VEC INT[1] INT[2] INT[3]))))" ) labels = @wizard.match( tree, "(nil (ASSIGN ID[x] INT[3]) (PRINT (MULT ID (VEC INT %x:INT INT))))" ) assert_kind_of( Hash, labels ) @wizard.in_context?( labels.fetch( 'x' ), 'VEC' ).should be_true end def test_no_parent tree = @wizard.create( '(PRINT (MULT ID[x] (VEC INT[1] INT[2] INT[3])))' ) labels = @wizard.match( tree, "(%x:PRINT (MULT ID (VEC INT INT INT)))" ) assert_kind_of( Hash, labels ) @wizard.in_context?( labels.fetch( 'x' ), 'VEC' ).should be_false end def test_parent_with_wildcard tree = @wizard.create( "(nil (ASSIGN ID[x] INT[3]) (PRINT (MULT ID[x] (VEC INT[1] INT[2] INT[3]))))" ) labels = @wizard.match( tree, "(nil (ASSIGN ID[x] INT[3]) (PRINT (MULT ID (VEC INT %x:INT INT))))" ) assert_kind_of( Hash, labels ) node = labels.fetch( 'x' ) @wizard.in_context?( node, 'VEC ...' ).should be_true end end