XPath compiler support for absolute paths/integers

This commit is contained in:
Yorick Peterse 2015-07-08 01:45:15 +02:00
parent 94f7f85dc3
commit ebcadd1cb8
1 changed files with 45 additions and 7 deletions

View File

@ -31,8 +31,8 @@ module Oga
# @return [Proc] # @return [Proc]
# #
def compile(ast) def compile(ast)
document = literal('node') document = node_literal
matched = literal('matched') matched = matched_literal
if ast.type == :path if ast.type == :path
ruby_ast = process(ast, document) ruby_ast = process(ast, document)
@ -71,24 +71,43 @@ module Oga
# @return [Oga::Ruby::Node] # @return [Oga::Ruby::Node]
# #
def on_path(ast, input, &block) def on_path(ast, input, &block)
matched = literal('matched') matched = matched_literal
ruby_ast = nil ruby_ast = nil
var_name = node_literal
last_index = ast.children.length - 1
ast.children.reverse_each.with_index do |child, index| ast.children.reverse_each.with_index do |child, index|
# The first block should operate on the variable set in "input", all
# others should operate on the child variables ("node").
input_var = index == last_index ? input : var_name
# The last segment of the path should add the code that actually # The last segment of the path should add the code that actually
# pushes the matched node into the node set. # pushes the matched node into the node set.
if index == 0 if index == 0
ruby_ast = process(child, input) do |node| ruby_ast = process(child, input_var) do |node|
matched.push(node) matched.push(node)
end end
else else
ruby_ast = process(child, input) { ruby_ast } ruby_ast = process(child, input_var) { ruby_ast }
end end
end end
ruby_ast ruby_ast
end end
##
# @param [AST::Node] ast
# @param [Oga::Ruby::Node] input
# @return [Oga::Ruby::Node]
#
def on_absolute_path(ast, input, &block)
if ast.children.empty?
matched_literal.push(input.root_node)
else
on_path(ast, input.root_node, &block)
end
end
## ##
# Dispatches the processing of axes to dedicated methods. This works # Dispatches the processing of axes to dedicated methods. This works
# similar to {#process} except the handler names are "on_axis_X" with "X" # similar to {#process} except the handler names are "on_axis_X" with "X"
@ -112,7 +131,7 @@ module Oga
# @return [Oga::Ruby::Node] # @return [Oga::Ruby::Node]
# #
def on_axis_child(ast, input, &block) def on_axis_child(ast, input, &block)
child = literal('node') child = node_literal
condition = process(ast, child, &block) condition = process(ast, child, &block)
input.children.each.add_block(child) do input.children.each.add_block(child) do
@ -187,6 +206,15 @@ module Oga
string(ast.children[0]) string(ast.children[0])
end end
##
# @param [AST::Node] ast
# @param [Oga::Ruby::Node] input
# @return [Oga::Ruby::Node]
#
def on_int(ast, input)
literal(ast.children[0].to_s)
end
private private
## ##
@ -212,6 +240,16 @@ module Oga
def element_or_attribute(node) def element_or_attribute(node)
node.is_a?(XML::Attribute).or(node.is_a?(XML::Element)) node.is_a?(XML::Attribute).or(node.is_a?(XML::Element))
end end
# @return [Oga::Ruby::Node]
def matched_literal
literal('matched')
end
# @return [Oga::Ruby::Node]
def node_literal
literal('node')
end
end # Compiler end # Compiler
end # XPath end # XPath
end # Oga end # Oga