Started updating Compiler for the new XPath AST

This also includes fixes for ancestor and ancestor-or-self so that these
axes can be used relative to documents and attributes.
This commit is contained in:
Yorick Peterse 2015-08-26 22:39:27 +02:00
parent 4fb7e2f6ce
commit 5e3b0a4023
1 changed files with 41 additions and 42 deletions

View File

@ -108,34 +108,6 @@ module Oga
send("on_#{ast.type}", ast, input, &block) send("on_#{ast.type}", ast, input, &block)
end end
# @param [AST::Node] ast
# @param [Oga::Ruby::Node] input
# @return [Oga::Ruby::Node]
def on_path(ast, input, &block)
ruby_ast = nil
var_name = node_literal
last_index = ast.children.length - 1
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").
#
# FIXME: this currently basically only works by accident due to
# various bits of code also using "node_literal".
input_var = index == last_index ? input : var_name
# The last segment of the path should add the code that actually
# pushes the matched node into the node set.
if index == 0
ruby_ast = process(child, input_var, &block)
else
ruby_ast = process(child, input_var) { ruby_ast }
end
end
ruby_ast
end
# @param [AST::Node] ast # @param [AST::Node] ast
# @param [Oga::Ruby::Node] input # @param [Oga::Ruby::Node] input
# @return [Oga::Ruby::Node] # @return [Oga::Ruby::Node]
@ -143,7 +115,7 @@ module Oga
if ast.children.empty? if ast.children.empty?
matched_literal.push(input.root_node) matched_literal.push(input.root_node)
else else
on_path(ast, input.root_node, &block) process(ast.children[0], input.root_node, &block)
end end
end end
@ -157,18 +129,20 @@ module Oga
# @return [Oga::Ruby::Node] # @return [Oga::Ruby::Node]
# #
def on_axis(ast, input, &block) def on_axis(ast, input, &block)
name, test = *ast name, test, following = *ast
handler = name.gsub('-', '_') handler = name.gsub('-', '_')
send(:"on_axis_#{handler}", test, input, &block) send(:"on_axis_#{handler}", test, input) do |matched|
process_following_or_yield(following, matched, &block)
end
end end
# @param [AST::Node] ast # @param [AST::Node] ast
# @param [Oga::Ruby::Node] input # @param [Oga::Ruby::Node] input
# @return [Oga::Ruby::Node] # @return [Oga::Ruby::Node]
def on_axis_child(ast, input) def on_axis_child(ast, input)
child = node_literal child = unique_literal(:child)
condition = process(ast, child) condition = process(ast, child)
input.children.each.add_block(child) do input.children.each.add_block(child) do
@ -199,27 +173,31 @@ module Oga
# @param [Oga::Ruby::Node] input # @param [Oga::Ruby::Node] input
# @return [Oga::Ruby::Node] # @return [Oga::Ruby::Node]
def on_axis_ancestor_or_self(ast, input) def on_axis_ancestor_or_self(ast, input)
parent = node_literal parent = unique_literal(:parent)
process(ast, input) process(ast, input)
.if_true { yield input } .if_true { yield input }
.followed_by do .followed_by do
node_or_attribute(input).if_true do
input.each_ancestor.add_block(parent) do input.each_ancestor.add_block(parent) do
process(ast, parent).if_true { yield parent } process(ast, parent).if_true { yield parent }
end end
end end
end end
end
# @param [AST::Node] ast # @param [AST::Node] ast
# @param [Oga::Ruby::Node] input # @param [Oga::Ruby::Node] input
# @return [Oga::Ruby::Node] # @return [Oga::Ruby::Node]
def on_axis_ancestor(ast, input) def on_axis_ancestor(ast, input)
parent = node_literal parent = unique_literal(:parent)
node_or_attribute(input).if_true do
input.each_ancestor.add_block(parent) do input.each_ancestor.add_block(parent) do
process(ast, parent).if_true { yield parent } process(ast, parent).if_true { yield parent }
end end
end end
end
# @param [AST::Node] ast # @param [AST::Node] ast
# @param [Oga::Ruby::Node] input # @param [Oga::Ruby::Node] input
@ -416,7 +394,7 @@ module Oga
# @param [Oga::Ruby::Node] input # @param [Oga::Ruby::Node] input
# @return [Oga::Ruby::Node] # @return [Oga::Ruby::Node]
def on_predicate(ast, input, &block) def on_predicate(ast, input, &block)
test, predicate = *ast test, predicate, following = *ast
index_var = unique_literal(:index) index_var = unique_literal(:index)
@ -431,7 +409,9 @@ module Oga
@predicate_indexes << index_var @predicate_indexes << index_var
ast = index_var.assign(literal(1)).followed_by do ast = index_var.assign(literal(1)).followed_by do
send(method, input, test, predicate, &block) send(method, input, test, predicate) do |matched|
process_following_or_yield(following, matched, &block)
end
end end
@predicate_indexes.pop @predicate_indexes.pop
@ -1289,11 +1269,13 @@ module Oga
# @return [Oga::Ruby::Node] # @return [Oga::Ruby::Node]
# #
def on_type_test(ast, input, &block) def on_type_test(ast, input, &block)
name = ast.children[0] name, followng = *ast
handler = name.gsub('-', '_') handler = name.gsub('-', '_')
send(:"on_type_test_#{handler}", input, &block) send(:"on_type_test_#{handler}", input) do |matched|
process_following_or_yield(following, matched, &block)
end
end end
# @param [Oga::Ruby::Node] input # @param [Oga::Ruby::Node] input
@ -1388,6 +1370,12 @@ module Oga
node.is_a?(XML::Attribute).or(node.is_a?(XML::Element)) node.is_a?(XML::Attribute).or(node.is_a?(XML::Element))
end end
# @param [Oga::Ruby::Node] node
# @return [Oga::Ruby::Node]
def node_or_attribute(node)
node.is_a?(XML::Attribute).or(node.is_a?(XML::Node))
end
# @param [AST::Node] ast # @param [AST::Node] ast
# @param [Oga::Ruby::Node] input # @param [Oga::Ruby::Node] input
# @return [Oga::Ruby::Node] # @return [Oga::Ruby::Node]
@ -1588,6 +1576,17 @@ module Oga
def predicate_nodeset def predicate_nodeset
@predicate_nodesets.last @predicate_nodesets.last
end end
# @param [AST::Node] following
# @param [Oga::Ruby::Node] matched
# @return [Oga::Ruby::Node]
def process_following_or_yield(following, matched, &block)
if following
process(following, matched, &block)
else
yield matched
end
end
end # Compiler end # Compiler
end # XPath end # XPath
end # Oga end # Oga