Acceptor

The Accecptor is quite the same thing as the Recognizer but instead of taking Recognizable objects, it takes Visitor objects.

Let's define two visitors.

#![allow(unused)]
fn main() {
extern crate elyze;
#[derive(Default, Debug)]
struct OperatorPlus;
#[derive(Default, Debug)]
struct OperatorMinus;

impl Match<u8> for OperatorPlus {
    fn is_matching(&self, data: &[u8]) -> (bool, usize) {
        match_pattern(b"+", data)
    }
    fn size(&self) -> usize {
        1
    }
}
impl Match<u8> for OperatorMinus {
    fn is_matching(&self, data: &[u8]) -> (bool, usize) {
        match_pattern(b"-", data)
    }
    fn size(&self) -> usize {
        1
    }
}
}

And another more complex.

#![allow(unused)]
fn main() {
#[derive(Default)]
struct Hello;
#[derive(Default)]
struct Space;
#[derive(Default)]
struct World;

impl Match<u8> for Hello {
    fn is_matching(&self, data: &[u8]) -> (bool, usize) {
        (&data[..5] == b"hello", 5)
    }

    fn size(&self) -> usize {
        5
    }
}

impl Match<u8> for Space {
    fn is_matching(&self, data: &[u8]) -> (bool, usize) {
        (data[0] as char == ' ', 1)
    }

    fn size(&self) -> usize {
        1
    }
}

impl Match<u8> for World {
    fn is_matching(&self, data: &[u8]) -> (bool, usize) {
        (&data[..5] == b"world", 5)
    }

    fn size(&self) -> usize {
        5
    }
}

// define a structure to implement the `Visitor` trait
#[derive(Debug)]
struct HelloWorld;

impl<'a> Visitor<'a, u8> for HelloWorld {
    fn accept(scanner: &mut Scanner<'a, u8>) -> ParseResult<Self> {
        Hello::accept(scanner)?; // accept the word "hello"
        Space::accept(scanner)?; // accept the space character?; // recognize the space character
        World::accept(scanner)?; // accept the word "world"?; // recognize the word "world"
        // return the `HelloWorld` object
        Ok(HelloWorld)
    }
}
}

We have now, 3 visitors : OperatorPlus, OperatorMinus and HelloWorld.

Because all Acceptor result must be homogenous, we use an enumeration.

#![allow(unused)]
fn main() {
extern crate elyze;
#[derive(Debug)]
enum Operator {
    Plus(OperatorPlus),
    Minus(OperatorMinus),
    HelloWorld(HelloWorld),
}
}

Then we can use it.

extern crate elyze;
use elyze::acceptor::Acceptor;
fn main() -> ParseResult<()> {
    let data = b"+ 2";
    let mut scanner = Scanner::new(data);
    let accepted = Acceptor::new(&mut scanner)
        .try_or(Operator::Plus)?
        .try_or(Operator::HelloWorld)?
        .try_or(Operator::Minus)?
        .finish()
        .ok_or(ParseError::UnexpectedToken)?;

    println!("{:?}", accepted); // +

    let data = b"- 2";
    let mut scanner = Scanner::new(data);
    let accepted = Acceptor::new(&mut scanner)
        .try_or(Operator::Plus)?
        .try_or(Operator::HelloWorld)?
        .try_or(Operator::Minus)?
        .finish()
        .ok_or(ParseError::UnexpectedToken)?;

    println!("{:?}", accepted); // -

    let data = b"hello world 2";
    let mut scanner = Scanner::new(data);
    let accepted = Acceptor::new(&mut scanner)
        .try_or(Operator::Plus)?
        .try_or(Operator::HelloWorld)?
        .try_or(Operator::Minus)?
        .finish()
        .ok_or(ParseError::UnexpectedToken)?;

    println!("{:?}", accepted); // HelloWorld

    Ok(())
}

Reusable Acceptor

Likewise the Recognizer, an Acceptor can be embedded in a Visitor.

#![allow(unused)]
fn main() {
extern crate elyze;

impl<'a> Visitor<'a, u8> for Operator {
    fn accept(scanner: &mut Scanner<'a, u8>) -> ParseResult<Self> {
        Acceptor::new(scanner)
            .try_or(Operator::Plus)?
            .try_or(Operator::HelloWorld)?
            .try_or(Operator::Minus)?
            .finish()
            .ok_or(ParseError::UnexpectedToken)
    }
}
}

Which simplifies the code.

extern crate elyze;
fn main() -> ParseResult<()> {
    let data = b"+ 2";
    let mut scanner = Scanner::new(data);
    let accepted = Operator::accept(&mut scanner)?;

    println!("{:?}", accepted); // +

    let data = b"- 2";
    let mut scanner = Scanner::new(data);
    let accepted = Operator::accept(&mut scanner)?;

    println!("{:?}", accepted); // -

    let data = b"hello world 2";
    let mut scanner = Scanner::new(data);
    let accepted = Operator::accept(&mut scanner)?;

    println!("{:?}", accepted); // HelloWorld

    Ok(())
}