diff --git a/lib/oga/xpath/parser.y b/lib/oga/xpath/parser.y index 67c755f..c8baf8d 100644 --- a/lib/oga/xpath/parser.y +++ b/lib/oga/xpath/parser.y @@ -10,45 +10,45 @@ token T_PIPE T_AND T_OR T_ADD T_DIV T_MOD T_EQ T_NEQ T_LT T_GT T_LTE T_GTE options no_result_var prechigh - left T_EQ + left T_EQ T_AXIS right T_OR preclow rule xpath - : T_SLASH expression { s(:absolute, val[1]) } - | expression { val[0] } - | /* none */ { nil } + : T_SLASH path { s(:absolute, val[1]) } + | path { val[0] } + | /* none */ { nil } + ; + + path + : expression { s(:path, val[0]) } + | expression T_SLASH path { s(:path, val[0], val[2]) } ; expression - : node_tests + : node_test | operator | axis | string | number ; - node_tests - : node_test { val[0] } - | node_test T_SLASH node_tests { val[0].append(val[2]) } - ; - node_test - : node_name { s(:test, val[0]) } - | node_name predicate { s(:test, val[0], val[1]) } + : node_name { s(:test, *val[0]) } + | node_name predicate { s(:test, *val[0], val[1]) } ; node_name # foo - : T_IDENT { s(:name, nil, val[0]) } + : T_IDENT { [nil, val[0]] } # foo:bar - | T_IDENT T_COLON T_IDENT { s(:name, val[0], val[1]) } + | T_IDENT T_COLON T_IDENT { [val[0], val[2]] } ; predicate - : T_LBRACK xpath T_RBRACK { s(:predicate, val[1]) } + : T_LBRACK xpath T_RBRACK { val[1] } ; operator @@ -57,7 +57,8 @@ rule ; axis - : T_AXIS node_name { s(:axis, val[0], val[1]) } + : T_AXIS expression { s(:axis, val[0], val[1]) } + | T_AXIS { s(:axis, val[0]) } ; string diff --git a/spec/oga/xpath/parser/axes_spec.rb b/spec/oga/xpath/parser/axes_spec.rb index 35f27dd..9dbf444 100644 --- a/spec/oga/xpath/parser/axes_spec.rb +++ b/spec/oga/xpath/parser/axes_spec.rb @@ -5,91 +5,91 @@ describe Oga::XPath::Parser do example 'parse the ancestor axis' do parse_xpath('/ancestor::A').should == s( :absolute, - s(:test, s(:axis, 'ancestor', s(:name, nil, 'A'))) + s(:path, s(:axis, 'ancestor', s(:test, nil, 'A'))) ) end example 'parse the ancestor-or-self axis' do parse_xpath('/ancestor-or-self::A').should == s( :absolute, - s(:test, s(:axis, 'ancestor-or-self', s(:name, nil, 'A'))) + s(:path, s(:axis, 'ancestor-or-self', s(:test, nil, 'A'))) ) end example 'parse the attribute axis' do parse_xpath('/attribute::A').should == s( :absolute, - s(:test, s(:axis, 'attribute', s(:name, nil, 'A'))) + s(:path, s(:axis, 'attribute', s(:test, nil, 'A'))) ) end example 'parse the child axis' do parse_xpath('/child::A').should == s( :absolute, - s(:test, s(:axis, 'child', s(:name, nil, 'A'))) + s(:path, s(:axis, 'child', s(:test, nil, 'A'))) ) end example 'parse the descendant axis' do parse_xpath('/descendant::A').should == s( :absolute, - s(:test, s(:axis, 'descendant', s(:name, nil, 'A'))) + s(:path, s(:axis, 'descendant', s(:test, nil, 'A'))) ) end example 'parse the descendant-or-self axis' do parse_xpath('/descendant-or-self::A').should == s( :absolute, - s(:test, s(:axis, 'descendant-or-self', s(:name, nil, 'A'))) + s(:path, s(:axis, 'descendant-or-self', s(:test, nil, 'A'))) ) end example 'parse the following axis' do parse_xpath('/following::A').should == s( :absolute, - s(:test, s(:axis, 'following', s(:name, nil, 'A'))) + s(:path, s(:axis, 'following', s(:test, nil, 'A'))) ) end example 'parse the following-sibling axis' do parse_xpath('/following-sibling::A').should == s( :absolute, - s(:test, s(:axis, 'following-sibling', s(:name, nil, 'A'))) + s(:path, s(:axis, 'following-sibling', s(:test, nil, 'A'))) ) end example 'parse the namespace axis' do parse_xpath('/namespace::A').should == s( :absolute, - s(:test, s(:axis, 'namespace', s(:name, nil, 'A'))) + s(:path, s(:axis, 'namespace', s(:test, nil, 'A'))) ) end example 'parse the parent axis' do parse_xpath('/parent::A').should == s( :absolute, - s(:test, s(:axis, 'parent', s(:name, nil, 'A'))) + s(:path, s(:axis, 'parent', s(:test, nil, 'A'))) ) end example 'parse the preceding axis' do parse_xpath('/preceding::A').should == s( :absolute, - s(:test, s(:axis, 'preceding', s(:name, nil, 'A'))) + s(:path, s(:axis, 'preceding', s(:test, nil, 'A'))) ) end example 'parse the preceding-sibling axis' do parse_xpath('/preceding-sibling::A').should == s( :absolute, - s(:test, s(:axis, 'preceding-sibling', s(:name, nil, 'A'))) + s(:path, s(:axis, 'preceding-sibling', s(:test, nil, 'A'))) ) end example 'parse the self axis' do parse_xpath('/self::A').should == s( :absolute, - s(:test, s(:axis, 'self', s(:name, nil, 'A'))) + s(:path, s(:axis, 'self', s(:test, nil, 'A'))) ) end end @@ -98,28 +98,28 @@ describe Oga::XPath::Parser do example 'parse the @attribute axis' do parse_xpath('/@A').should == s( :absolute, - s(:test, s(:axis, 'attribute', s(:name, nil, 'A'))) + s(:path, s(:axis, 'attribute', s(:test, nil, 'A'))) ) end example 'parse the // axis' do parse_xpath('//A').should == s( :absolute, - s(:test, s(:axis, 'descendant-or-self', s(:name, nil, 'A'))) + s(:path, s(:axis, 'descendant-or-self', s(:test, nil, 'A'))) ) end example 'parse the .. axis' do parse_xpath('/..').should == s( :absolute, - s(:test, s(:axis, 'parent')) + s(:path, s(:axis, 'parent')) ) end example 'parse the . axis' do parse_xpath('/.').should == s( :absolute, - s(:test, s(:axis, 'self')) + s(:path, s(:axis, 'self')) ) end end diff --git a/spec/oga/xpath/parser/paths_spec.rb b/spec/oga/xpath/parser/paths_spec.rb index f6aafeb..7fe992f 100644 --- a/spec/oga/xpath/parser/paths_spec.rb +++ b/spec/oga/xpath/parser/paths_spec.rb @@ -3,17 +3,17 @@ require 'spec_helper' describe Oga::XPath::Parser do context 'paths' do example 'parse an absolute path' do - parse_xpath('/A').should == s(:absolute, s(:test, s(:name, nil, 'A'))) + parse_xpath('/A').should == s(:absolute, s(:path, s(:test, nil, 'A'))) end example 'parse a relative path' do - parse_xpath('A').should == s(:test, s(:name, nil, 'A')) + parse_xpath('A').should == s(:path, s(:test, nil, 'A')) end example 'parse an expression using two paths' do parse_xpath('/A/B').should == s( :absolute, - s(:test, s(:name, nil, 'A'), s(:test, s(:name, nil, 'B'))) + s(:path, s(:test, nil, 'A'), s(:path, s(:test, nil, 'B'))) ) end end diff --git a/spec/oga/xpath/parser/predicates_spec.rb b/spec/oga/xpath/parser/predicates_spec.rb index 9536a1d..ee1da97 100644 --- a/spec/oga/xpath/parser/predicates_spec.rb +++ b/spec/oga/xpath/parser/predicates_spec.rb @@ -6,14 +6,18 @@ describe Oga::XPath::Parser do parse_xpath('/foo[@class="bar"]').should == s( :absolute, s( - :test, - s(:name, nil, 'foo'), + :path, s( - :predicate, + :test, + nil, + 'foo', s( - :eq, - s(:axis, 'attribute', s(:name, nil, 'class')), - s(:string, 'bar') + :path, + s( + :eq, + s(:axis, 'attribute', s(:test, nil, 'class')), + s(:string, 'bar') + ) ) ) ) @@ -24,21 +28,25 @@ describe Oga::XPath::Parser do parse_xpath('/foo[@class="bar" or @class="baz"]').should == s( :absolute, s( - :test, - s(:name, nil, 'foo'), + :path, s( - :predicate, + :test, + nil, + 'foo', s( - :or, + :path, s( - :eq, - s(:axis, 'attribute', s(:name, nil, 'class')), - s(:string, 'bar') - ), - s( - :eq, - s(:axis, 'attribute', s(:name, nil, 'class')), - s(:string, 'baz') + :or, + s( + :eq, + s(:axis, 'attribute', s(:test, nil, 'class')), + s(:string, 'bar') + ), + s( + :eq, + s(:axis, 'attribute', s(:test, nil, 'class')), + s(:string, 'baz') + ) ) ) )