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'
}
##
# 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

View File

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

View File

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

View File

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