diff --git a/lib/oga/xpath/lexer.rl b/lib/oga/xpath/lexer.rl index 5d29fa2..82c801d 100644 --- a/lib/oga/xpath/lexer.rl +++ b/lib/oga/xpath/lexer.rl @@ -23,6 +23,13 @@ module Oga '.' => 'self' } + ## + # Axes that require a separate `node()` call to be emitted. + # + # @return [Array] + # + AXIS_EMIT_NODE = %w{descendant-or-self parent self} + ## # @param [String] data The data to lex. # @@ -226,6 +233,17 @@ module Oga value = AXIS_MAPPING[slice_input(ts, te)] add_token(:T_AXIS, value) + + # Short axes that use node() as their default, implicit test. This is + # added on lexer level to make it easier to handle these cases on + # parser/evaluator level. + if AXIS_EMIT_NODE.include?(value) + add_token(:T_IDENT, 'node') + add_token(:T_LPAREN) + add_token(:T_RPAREN) + + add_token(:T_SLASH) unless te == eof + end } # Operators diff --git a/spec/oga/xpath/lexer/axes_spec.rb b/spec/oga/xpath/lexer/axes_spec.rb index 749f662..25327c8 100644 --- a/spec/oga/xpath/lexer/axes_spec.rb +++ b/spec/oga/xpath/lexer/axes_spec.rb @@ -120,6 +120,10 @@ describe Oga::XPath::Lexer do lex_xpath('//A').should == [ [:T_SLASH, nil], [:T_AXIS, 'descendant-or-self'], + [:T_IDENT, 'node'], + [:T_LPAREN, nil], + [:T_RPAREN, nil], + [:T_SLASH, nil], [:T_IDENT, 'A'] ] end @@ -127,14 +131,20 @@ describe Oga::XPath::Lexer do example 'lex the .. axis' do lex_xpath('/..').should == [ [:T_SLASH, nil], - [:T_AXIS, 'parent'] + [:T_AXIS, 'parent'], + [:T_IDENT, 'node'], + [:T_LPAREN, nil], + [:T_RPAREN, nil], ] end example 'lex the . axis' do lex_xpath('/.').should == [ [:T_SLASH, nil], - [:T_AXIS, 'self'] + [:T_AXIS, 'self'], + [:T_IDENT, 'node'], + [:T_LPAREN, nil], + [:T_RPAREN, nil], ] end end diff --git a/spec/oga/xpath/lexer/general_spec.rb b/spec/oga/xpath/lexer/general_spec.rb index bc44fbe..f027a48 100644 --- a/spec/oga/xpath/lexer/general_spec.rb +++ b/spec/oga/xpath/lexer/general_spec.rb @@ -37,6 +37,10 @@ describe Oga::XPath::Lexer do [:T_IDENT, 'wikimedia'], [:T_SLASH, nil], [:T_AXIS, 'descendant-or-self'], + [:T_IDENT, 'node'], + [:T_LPAREN, nil], + [:T_RPAREN, nil], + [:T_SLASH, nil], [:T_IDENT, 'editions'] ] end diff --git a/spec/oga/xpath/parser/axes_spec.rb b/spec/oga/xpath/parser/axes_spec.rb index 623bad3..77920e2 100644 --- a/spec/oga/xpath/parser/axes_spec.rb +++ b/spec/oga/xpath/parser/axes_spec.rb @@ -120,16 +120,23 @@ describe Oga::XPath::Parser do example 'parse the // axis' do parse_xpath('//A').should == s( :absolute_path, - s(:axis, 'descendant-or-self', s(:test, nil, 'A')) + s(:axis, 'descendant-or-self', s(:call, 'node')), + s(:test, nil, 'A') ) end example 'parse the .. axis' do - parse_xpath('/..').should == s(:absolute_path, s(:axis, 'parent')) + parse_xpath('/..').should == s( + :absolute_path, + s(:axis, 'parent', s(:call, 'node')) + ) end example 'parse the . axis' do - parse_xpath('/.').should == s(:absolute_path, s(:axis, 'self')) + parse_xpath('/.').should == s( + :absolute_path, + s(:axis, 'self', s(:call, 'node')) + ) end end end