Removed internal state of XPath::Evaluator.

Come to think of it it might actually be easier to implement the evaluator as
an actual VM. That is, instead of directly running on the AST it runs on some
flavour of bytecode. Alternatively it runs directly on the AST but behaves more
like a (stack based) VM. This would most likely be easier than passing a cursor
to every node processing method.
This commit is contained in:
Yorick Peterse 2014-07-08 19:19:59 +02:00
parent 54f0355ea9
commit 266c66569e
1 changed files with 61 additions and 16 deletions

View File

@ -10,42 +10,87 @@ module Oga
#
def initialize(document)
@document = document
@cursor = @document
end
def on_absolute(node)
if @cursor.is_a?(XML::Node)
@cursor = @cursor.root_node
def process(node, cursor)
return if node.nil?
node = node.to_ast
on_handler = :"on_#{node.type}"
if respond_to?(on_handler)
new_node = send(on_handler, node, cursor)
else
new_node = handler_missing(node)
end
return process_all(node.children)
node = new_node if new_node
return node
end
def on_path(node)
def process_all(nodes, cursor)
return nodes.to_a.map do |node|
process(node, cursor)
end
end
def evaluate(string)
ast = Parser.new(string).parse
cursor = move_cursor(@document)
return process(ast, cursor)
end
def on_absolute(node, cursor)
if @document.is_a?(XML::Node)
cursor = move_cursor(@document.root_node)
else
cursor = move_cursor(@document)
end
return process_all(node.children, cursor)
end
def on_path(node, cursor)
test, children = *node
current = process(test)
nodes = process(test, cursor)
if current
@cursor = current
current = process(children)
unless nodes.empty?
nodes = process_all(children, nodes)
end
return current
return nodes
end
def on_test(node)
nodes = []
def on_test(node, cursor)
ns, name = *node
nodes = XML::NodeSet.new
@cursor.children.each do |child|
if child.is_a?(XML::Element) and child.name == name and child.namespace == ns
nodes << child
cursor.each do |xml_node|
next unless xml_node.is_a?(XML::Element)
if xml_node.name == name and xml_node.namespace == ns
nodes << xml_node
end
end
return nodes
end
def move_cursor(location)
if location.is_a?(XML::Document)
return location.children
elsif location.is_a?(XML::Node)
return XML::NodeSet.new([location])
else
return location
end
end
end # Evaluator
end # XPath
end # Oga