Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for visitors #136

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion src/axis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,11 +212,12 @@ mod test {
use crate::context::{self, Context};
use crate::node_test::NodeTest;
use crate::nodeset::{Node, OrderedNodes};
use crate::visitor::{Visitable, Visitor};

use super::Axis::*;
use super::*;

#[derive(Debug)]
#[derive(Debug, Clone)]
struct DummyNodeTest;
impl NodeTest for DummyNodeTest {
fn test<'c, 'd>(
Expand All @@ -226,6 +227,13 @@ mod test {
) {
result.add(context.node)
}

fn clone_box(&self) -> Box<dyn NodeTest + 'static> {
Box::new(self.clone())
}
}
impl Visitable for DummyNodeTest {
fn visit(&self, _visitor: &mut dyn Visitor) {}
}

fn execute<'n, N>(axis: Axis, node: N) -> OrderedNodes<'n>
Expand Down
114 changes: 111 additions & 3 deletions src/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::context;
use crate::function;
use crate::node_test::NodeTest;
use crate::nodeset::{Nodeset, OrderedNodes};
use crate::visitor::{Visitable, Visitor};
use crate::Value::{Boolean, Number};
use crate::{LiteralValue, OwnedPrefixedName, Value};

Expand Down Expand Up @@ -46,7 +47,7 @@ fn value_into_ordered_nodes(v: Value<'_>) -> Result<OrderedNodes<'_>, Error> {
}
}

pub trait Expression: fmt::Debug {
pub trait Expression: fmt::Debug + Visitable {
fn evaluate<'c, 'd>(&self, context: &context::Evaluation<'c, 'd>) -> Result<Value<'d>, Error>;
}

Expand Down Expand Up @@ -79,6 +80,12 @@ pub struct And {

binary_constructor!(And);

impl Visitable for And {
fn visit(&self, visitor: &mut dyn Visitor) {
visitor.visit_and(&self.left, &self.right);
}
}

impl Expression for And {
fn evaluate<'c, 'd>(&self, context: &context::Evaluation<'c, 'd>) -> Result<Value<'d>, Error> {
let left = self.left.evaluate(context)?.boolean();
Expand All @@ -91,6 +98,12 @@ impl Expression for And {
#[derive(Debug)]
pub struct ContextNode;

impl Visitable for ContextNode {
fn visit(&self, visitor: &mut dyn Visitor) {
visitor.visit_context_node();
}
}

impl Expression for ContextNode {
fn evaluate<'c, 'd>(&self, context: &context::Evaluation<'c, 'd>) -> Result<Value<'d>, Error> {
Ok(Value::Nodeset(nodeset![context.node]))
Expand Down Expand Up @@ -150,6 +163,12 @@ impl Equal {
}
}

impl Visitable for Equal {
fn visit(&self, visitor: &mut dyn Visitor) {
visitor.visit_equal(&self.left, &self.right);
}
}

impl Expression for Equal {
fn evaluate<'c, 'd>(&self, context: &context::Evaluation<'c, 'd>) -> Result<Value<'d>, Error> {
self.boolean_evaluate(context).map(Boolean)
Expand All @@ -169,6 +188,12 @@ impl NotEqual {
}
}

impl Visitable for NotEqual {
fn visit(&self, visitor: &mut dyn Visitor) {
visitor.visit_not_equal(&self.equal.left, &self.equal.right);
}
}

impl Expression for NotEqual {
fn evaluate<'c, 'd>(&self, context: &context::Evaluation<'c, 'd>) -> Result<Value<'d>, Error> {
self.equal.boolean_evaluate(context).map(|v| Boolean(!v))
Expand All @@ -181,6 +206,12 @@ pub struct Function {
pub arguments: Vec<SubExpression>,
}

impl Visitable for Function {
fn visit(&self, visitor: &mut dyn Visitor) {
visitor.visit_function(&self.name, &self.arguments);
}
}

impl Expression for Function {
fn evaluate<'c, 'd>(&self, context: &context::Evaluation<'c, 'd>) -> Result<Value<'d>, Error> {
let name = resolve_prefixed_name(context, &self.name)?;
Expand Down Expand Up @@ -209,6 +240,12 @@ impl From<LiteralValue> for Literal {
}
}

impl Visitable for Literal {
fn visit(&self, visitor: &mut dyn Visitor) {
visitor.visit_literal(&self.value);
}
}

impl Expression for Literal {
fn evaluate<'c, 'd>(&self, _: &context::Evaluation<'c, 'd>) -> Result<Value<'d>, Error> {
Ok(self.value.clone())
Expand Down Expand Up @@ -279,6 +316,12 @@ impl Math {
}
}

impl Visitable for Math {
fn visit(&self, visitor: &mut dyn Visitor) {
visitor.visit_math(&self.left, &self.right, &self.operation);
}
}

impl Expression for Math {
fn evaluate<'c, 'd>(&self, context: &context::Evaluation<'c, 'd>) -> Result<Value<'d>, Error> {
let left = self.left.evaluate(context)?;
Expand All @@ -303,6 +346,12 @@ pub struct Negation {
pub expression: SubExpression,
}

impl Visitable for Negation {
fn visit(&self, visitor: &mut dyn Visitor) {
visitor.visit_negation(&self.expression);
}
}

impl Expression for Negation {
fn evaluate<'c, 'd>(&self, context: &context::Evaluation<'c, 'd>) -> Result<Value<'d>, Error> {
self.expression
Expand All @@ -319,6 +368,12 @@ pub struct Or {

binary_constructor!(Or);

impl Visitable for Or {
fn visit(&self, visitor: &mut dyn Visitor) {
visitor.visit_or(&self.left, &self.right);
}
}

impl Expression for Or {
fn evaluate<'c, 'd>(&self, context: &context::Evaluation<'c, 'd>) -> Result<Value<'d>, Error> {
let left = self.left.evaluate(context)?.boolean();
Expand All @@ -339,6 +394,12 @@ impl Path {
}
}

impl Visitable for Path {
fn visit(&self, visitor: &mut dyn Visitor) {
visitor.visit_path(&self.start_point, &self.steps);
}
}

impl Expression for Path {
fn evaluate<'c, 'd>(&self, context: &context::Evaluation<'c, 'd>) -> Result<Value<'d>, Error> {
let result = self.start_point.evaluate(context)?;
Expand Down Expand Up @@ -370,6 +431,12 @@ impl Filter {
}
}

impl Visitable for Filter {
fn visit(&self, visitor: &mut dyn Visitor) {
visitor.visit_filter(&self.node_selector, &self.predicate);
}
}

impl Expression for Filter {
fn evaluate<'c, 'd>(&self, context: &context::Evaluation<'c, 'd>) -> Result<Value<'d>, Error> {
self.node_selector
Expand Down Expand Up @@ -433,6 +500,12 @@ impl Relational {
}
}

impl Visitable for Relational {
fn visit(&self, visitor: &mut dyn Visitor) {
visitor.visit_relational(&self.left, &self.right, &self.operation);
}
}

impl Expression for Relational {
fn evaluate<'c, 'd>(&self, context: &context::Evaluation<'c, 'd>) -> Result<Value<'d>, Error> {
let left_val = self.left.evaluate(context)?;
Expand All @@ -456,14 +529,20 @@ impl fmt::Debug for Relational {
#[derive(Debug)]
pub struct RootNode;

impl Visitable for RootNode {
fn visit(&self, visitor: &mut dyn Visitor) {
visitor.visit_root_node();
}
}

impl Expression for RootNode {
fn evaluate<'c, 'd>(&self, context: &context::Evaluation<'c, 'd>) -> Result<Value<'d>, Error> {
Ok(Value::Nodeset(nodeset![context.node.document().root()]))
}
}

#[derive(Debug)]
struct Predicate {
pub struct Predicate {
pub expression: SubExpression,
}

Expand Down Expand Up @@ -505,6 +584,12 @@ pub struct ParameterizedStep<A> {
predicates: Vec<Predicate>,
}

impl Visitable for Step {
fn visit(&self, visitor: &mut dyn Visitor) {
visitor.visit_step(&self.axis, &self.node_test, &self.predicates);
}
}

impl<A> ParameterizedStep<A>
where
A: AxisLike,
Expand Down Expand Up @@ -561,6 +646,12 @@ pub struct Union {

binary_constructor!(Union);

impl Visitable for Union {
fn visit(&self, visitor: &mut dyn Visitor) {
visitor.visit_union(&self.left, &self.right);
}
}

impl Expression for Union {
fn evaluate<'c, 'd>(&self, context: &context::Evaluation<'c, 'd>) -> Result<Value<'d>, Error> {
let as_nodes = |e: &SubExpression| e.evaluate(context).and_then(value_into_nodeset);
Expand Down Expand Up @@ -594,6 +685,12 @@ pub struct Variable {
pub name: OwnedPrefixedName,
}

impl Visitable for Variable {
fn visit(&self, visitor: &mut dyn Visitor) {
visitor.visit_variable(&self.name);
}
}

impl Expression for Variable {
fn evaluate<'c, 'd>(&self, context: &context::Evaluation<'c, 'd>) -> Result<Value<'d>, Error> {
let name = resolve_prefixed_name(context, &self.name)?;
Expand Down Expand Up @@ -625,6 +722,11 @@ mod test {

#[derive(Debug)]
struct FailExpression;
impl Visitable for FailExpression {
fn visit(&self, _visitor: &mut dyn Visitor) {
panic!("Should never be called");
}
}
impl Expression for FailExpression {
fn evaluate<'c, 'd>(&self, _: &context::Evaluation<'c, 'd>) -> Result<Value<'d>, Error> {
panic!("Should never be called");
Expand Down Expand Up @@ -1048,10 +1150,16 @@ mod test {
}
}

#[derive(Debug)]
#[derive(Debug, Clone)]
struct DummyNodeTest;
impl NodeTest for DummyNodeTest {
fn test(&self, _context: &context::Evaluation<'_, '_>, _result: &mut OrderedNodes<'_>) {}
fn clone_box(&self) -> Box<dyn NodeTest + 'static> {
Box::new(self.clone())
}
}
impl Visitable for DummyNodeTest {
fn visit(&self, _visitor: &mut dyn Visitor) {}
}

#[test]
Expand Down
8 changes: 8 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ use crate::parser::Parser;
use crate::tokenizer::{TokenDeabbreviator, Tokenizer};

pub use crate::context::Context;
pub use crate::visitor::{Visitable, Visitor};

#[macro_use]
pub mod macros;
Expand All @@ -121,6 +122,7 @@ pub mod nodeset;
mod parser;
mod token;
mod tokenizer;
pub mod visitor;

// These belong in the the document

Expand Down Expand Up @@ -374,6 +376,12 @@ impl XPath {
}
}

impl Visitable for XPath {
fn visit(&self, visitor: &mut dyn Visitor) {
visitor.visit_xpath(&self.0);
}
}

/// The primary entrypoint to convert an XPath represented as a string
/// to a structure that can be evaluated.
pub struct Factory {
Expand Down
Loading