Emit node() calls for certain short axes.

An axes such as "." is the same as "self::node()". To simplify things on
parser/evaluator level we'll emit the corresponding tokens for a "node()"
function call for these axes.
This commit is contained in:
Yorick Peterse 2014-07-22 15:50:39 +02:00
parent f699b0d097
commit c43c38fab9
4 changed files with 44 additions and 5 deletions

View File

@ -23,6 +23,13 @@ module Oga
'.' => 'self' '.' => '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. # @param [String] data The data to lex.
# #
@ -226,6 +233,17 @@ module Oga
value = AXIS_MAPPING[slice_input(ts, te)] value = AXIS_MAPPING[slice_input(ts, te)]
add_token(:T_AXIS, value) 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 # Operators

View File

@ -120,6 +120,10 @@ describe Oga::XPath::Lexer do
lex_xpath('//A').should == [ lex_xpath('//A').should == [
[:T_SLASH, nil], [:T_SLASH, nil],
[:T_AXIS, 'descendant-or-self'], [:T_AXIS, 'descendant-or-self'],
[:T_IDENT, 'node'],
[:T_LPAREN, nil],
[:T_RPAREN, nil],
[:T_SLASH, nil],
[:T_IDENT, 'A'] [:T_IDENT, 'A']
] ]
end end
@ -127,14 +131,20 @@ describe Oga::XPath::Lexer do
example 'lex the .. axis' do example 'lex the .. axis' do
lex_xpath('/..').should == [ lex_xpath('/..').should == [
[:T_SLASH, nil], [:T_SLASH, nil],
[:T_AXIS, 'parent'] [:T_AXIS, 'parent'],
[:T_IDENT, 'node'],
[:T_LPAREN, nil],
[:T_RPAREN, nil],
] ]
end end
example 'lex the . axis' do example 'lex the . axis' do
lex_xpath('/.').should == [ lex_xpath('/.').should == [
[:T_SLASH, nil], [:T_SLASH, nil],
[:T_AXIS, 'self'] [:T_AXIS, 'self'],
[:T_IDENT, 'node'],
[:T_LPAREN, nil],
[:T_RPAREN, nil],
] ]
end end
end end

View File

@ -37,6 +37,10 @@ describe Oga::XPath::Lexer do
[:T_IDENT, 'wikimedia'], [:T_IDENT, 'wikimedia'],
[:T_SLASH, nil], [:T_SLASH, nil],
[:T_AXIS, 'descendant-or-self'], [:T_AXIS, 'descendant-or-self'],
[:T_IDENT, 'node'],
[:T_LPAREN, nil],
[:T_RPAREN, nil],
[:T_SLASH, nil],
[:T_IDENT, 'editions'] [:T_IDENT, 'editions']
] ]
end end

View File

@ -120,16 +120,23 @@ describe Oga::XPath::Parser do
example 'parse the // axis' do example 'parse the // axis' do
parse_xpath('//A').should == s( parse_xpath('//A').should == s(
:absolute_path, :absolute_path,
s(:axis, 'descendant-or-self', s(:test, nil, 'A')) s(:axis, 'descendant-or-self', s(:call, 'node')),
s(:test, nil, 'A')
) )
end end
example 'parse the .. axis' do 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 end
example 'parse the . axis' do 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 end
end end