fn_bnf

Trait Rule

source
pub trait Rule<'input, SliceType: ?Sized + 'input>: NamedRule {
    type Output;

    // Required method
    fn parse_at<'cursor, 'this, 'index>(
        &'this self,
        input: &'cursor mut &'input SliceType,
        index: &'index mut usize,
    ) -> Result<Self::Output, ParseError>
       where 'input: 'this;

    // Provided methods
    fn parse<'this>(
        &'this self,
        input: &'input SliceType,
    ) -> Result<(&'input SliceType, Self::Output), ParseError>
       where 'input: 'this { ... }
    fn map_parsed<Output, F: Fn(Self::Output) -> Output>(
        self,
        function: F,
    ) -> Map<'input, SliceType, Self, Output, F>
       where Self: Sized { ... }
    fn try_map_parsed<Output, E: Error + 'static, F: Fn(Self::Output) -> Result<Output, E>>(
        self,
        function: F,
    ) -> TryMap<'input, SliceType, Self, Output, E, F>
       where Self: Sized { ... }
    fn prevent(self) -> Not<Self>
       where Self: Sized { ... }
    fn repeat_for<const REPS: usize>(
        self,
    ) -> RepeatFor<'input, SliceType, Self, REPS>
       where Self: Sized { ... }
    fn repeat(self, reps: usize) -> Repeat<'input, SliceType, Self>
       where Self: Sized { ... }
    fn take(self, at_most: usize) -> Many<'input, SliceType, Self>
       where Self: Sized { ... }
    fn hoard(self) -> Many<'input, SliceType, Self>
       where Self: Sized { ... }
    fn consume_all(self) -> Consume<'input, SliceType, Self>
       where Self: Sized,
             Consume<'input, SliceType, Self>: Rule<'input, SliceType, Output = Vec<Self::Output>> { ... }
    fn spanned(self) -> Spanned<'input, SliceType, Self>
       where Self: Sized,
             SliceType: Index<RangeTo<usize>, Output = SliceType> { ... }
    fn attempt(self) -> Attempt<'input, SliceType, Self>
       where Self: Sized { ... }
}
Expand description

Trait dictating that something can be used as a rule within a parsing grammar.

§Implementation

Imlpementing this trait means that anyone can use your struct as a rule in any of their their grammars with a supported slice type.

If you’re defining simple rules that don’t depend on the input, you can make rules generic over all slice types!

This is done for most of the “helper rules”, like Any, in this crate.

Required Associated Types§

source

type Output

The type of the value of a successful parse of this rule.

Required Methods§

source

fn parse_at<'cursor, 'this, 'index>( &'this self, input: &'cursor mut &'input SliceType, index: &'index mut usize, ) -> Result<Self::Output, ParseError>
where 'input: 'this,

Parses a rule at a given index with a given input.

§Errors

Errors if the rule fails to parse.

§Correctness

When a parse succeeds, you must replace the borrowed input and index with a slice of it past the index you stopped parsing at - for example,

*input = &input[2..];
*index += 2;

You also must reset the values of input and index if an error occurs.

For example, this can be done as follows:

let before = (*input, *index);
// later...
let res = match inner_rule.parse_at(input, index) {
    Ok(v) => v,
    Err(err) => {
        (*input, *index) = before;
        return Err(err);
    }
}

Fsilure to do uphold of these could cause other code using your rule to misbehave, potentially inducing panics and/or non-termination.

As this is not a safety contract, implementors cannot rely on this for soundness in unsafe code.

Provided Methods§

source

fn parse<'this>( &'this self, input: &'input SliceType, ) -> Result<(&'input SliceType, Self::Output), ParseError>
where 'input: 'this,

Parses a given rule at the start of some input.

§Errors

Errors if the rule fails to parse.

Examples found in repository?
examples/math.rs (line 104)
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
fn main() -> Result<(), std::io::Error> {
    let mut lines = std::io::stdin().lines();
    println!("Input a math expression below, `clear` to clear the console, or `exit` / `quit` to exit.");
    println!("You can access the result of the last expression with `ans`.");
    let mut last_ans = None;
    'outer: loop {
        print!("[?] ");
        std::io::stdout().flush()?;
        let Some(input) = lines.next().transpose()? else { break Ok(()) };
        let input = input.trim_ascii();
        if input.is_empty() { print!("\x1b[1A"); continue; }
        match input {
            "clear" => print!("\x1bc"),
            "exit" | "quit" => break Ok(()),
            _ => {
                let (_, mut tokens) = match MathTokens::LangTokens.parse(&input) {
                    Ok(v) => v,
                    Err(err) => {
                        println!("[!] Failed to parse: {err}");
                        continue;
                    }
                };
                for ans in tokens.iter_mut().filter(|t| matches!(t, Token::Ans)) {
                    let Some(answer) = last_ans else {
                        println!("[!] No previous answer exists");
                        continue 'outer;
                    };
                    *ans = Token::Number(answer);
                }
                let (_, result) = match TokenMath::Expr.parse(tokens.as_ref()) {
                    Ok(v) => v,
                    Err(err) => {
                        println!("[!] Failed to parse: {err}");
                        continue;
                    }
                };
                last_ans = Some(result);
                println!("[=] {result:.}")
            } 
        }
    }
}
source

fn map_parsed<Output, F: Fn(Self::Output) -> Output>( self, function: F, ) -> Map<'input, SliceType, Self, Output, F>
where Self: Sized,

Maps an infallible function onto the output of a rule.

Examples found in repository?
examples/math.rs (line 19)
18
19
        pub LangTokens -> Vec<Token> = LangToken.consume_all()
            .map_parsed(|v| v.into_iter().filter_map(|v| v).collect() );
source

fn try_map_parsed<Output, E: Error + 'static, F: Fn(Self::Output) -> Result<Output, E>>( self, function: F, ) -> TryMap<'input, SliceType, Self, Output, E, F>
where Self: Sized,

Maps a function onto the output of a rule, passing the error back if it fails.

source

fn prevent(self) -> Not<Self>
where Self: Sized,

Matches when this fails, and vice versa.

source

fn repeat_for<const REPS: usize>( self, ) -> RepeatFor<'input, SliceType, Self, REPS>
where Self: Sized,

Repeats this rule a known amount of times.

source

fn repeat(self, reps: usize) -> Repeat<'input, SliceType, Self>
where Self: Sized,

Repeats this rule a set amount of times.

source

fn take(self, at_most: usize) -> Many<'input, SliceType, Self>
where Self: Sized,

Repeats this rule at most a set amount of times.

source

fn hoard(self) -> Many<'input, SliceType, Self>
where Self: Sized,

Repeats this rule forever until it fails.

source

fn consume_all(self) -> Consume<'input, SliceType, Self>
where Self: Sized, Consume<'input, SliceType, Self>: Rule<'input, SliceType, Output = Vec<Self::Output>>,

Repeats this rule until the end of input, failing if it ever does.

Examples found in repository?
examples/math.rs (line 18)
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
        pub LangTokens -> Vec<Token> = LangToken.consume_all()
            .map_parsed(|v| v.into_iter().filter_map(|v| v).collect() );
        LangToken -> Option<Token> = 
            Num : Plus : Minus : Asterisk : Slash : Percent : Carat
            : LParen : RParen : Ans : _ Whitespace 
            : InvalidChar;
        // Since Fail returns !, we can coerce from that to a token
        InvalidChar -> Token from(|_, n| n) = Any, Fail::new(Unexpected::new(arg_0));

        Plus -> Token = '+'.map_parsed(|_| Token::Plus);
        Minus -> Token = '-'.map_parsed(|_| Token::Minus);
        Asterisk -> Token = '*'.map_parsed(|_| Token::Asterisk);
        Slash -> Token = '/'.map_parsed(|_| Token::Slash);
        Percent -> Token = '%'.map_parsed(|_| Token::Percent);
        Carat -> Token = '^'.map_parsed(|_| Token::Carat);
        LParen -> Token = '('.map_parsed(|_| Token::LeftParen);
        RParen -> Token = ')'.map_parsed(|_| Token::RightParen);

        Ans -> Token = "ans".map_parsed(|_| Token::Ans);

        Num -> Token from(|n| Token::Number(n)) = 
            ("nan", "NaN").map_parsed(|_| f64::NAN) : 
            ("inf", "Infinity").map_parsed(|_| f64::INFINITY) : 
            Float;
        Float -> f64 try_from(f64::from_str) = FloatTokens.spanned().map_parsed(|span| span.source);
        
        FloatTokens -> () = _ UInt, _ FloatFract.attempt(), _ FloatExp.attempt();
        FloatFract -> () = _ '.', _ UInt;
        FloatExp -> () = _ ('e', 'E'), _ ('-', '+').attempt(), _ UInt;

        UInt -> &'input str = While::from(char::is_ascii_digit);
    }
}

define! {
    grammar TokenMath<[Token]> {
        pub Expr -> f64 from(parse_expr) = Prod, SumSuf.consume_all();
source

fn spanned(self) -> Spanned<'input, SliceType, Self>
where Self: Sized, SliceType: Index<RangeTo<usize>, Output = SliceType>,

Captures the output and span of this rule, returning them along with the output in a Span.

source

fn attempt(self) -> Attempt<'input, SliceType, Self>
where Self: Sized,

Tries to capture this rule, returning None if it doesn’t match.

Implementations on Foreign Types§

source§

impl<'input> Rule<'input, str> for char

source§

type Output = char

source§

fn parse_at<'cursor, 'this, 'index>( &'this self, input: &'cursor mut &'input str, index: &'index mut usize, ) -> Result<Self::Output, ParseError>
where 'input: 'this,

source§

impl<'input> Rule<'input, str> for fn(_: &char) -> bool

source§

type Output = char

source§

fn parse_at<'cursor, 'this, 'index>( &'this self, input: &'cursor mut &'input str, index: &'index mut usize, ) -> Result<Self::Output, ParseError>
where 'input: 'this,

source§

impl<'input> Rule<'input, str> for str

source§

type Output = &'input str

source§

fn parse_at<'cursor, 'this, 'index>( &'this self, input: &'cursor mut &'input str, index: &'index mut usize, ) -> Result<Self::Output, ParseError>
where 'input: 'this,

source§

impl<'input, S: ?Sized + 'input, T: ?Sized + Rule<'input, S>> Rule<'input, S> for &T

source§

type Output = <T as Rule<'input, S>>::Output

source§

fn parse_at<'cursor, 'this, 'index>( &'this self, input: &'cursor mut &'input S, index: &'index mut usize, ) -> Result<Self::Output, ParseError>
where 'input: 'this,

source§

impl<'input, SliceType: ?Sized + 'input, Output, T> Rule<SliceType> for (T₁, T₂, …, Tₙ)
where T: Rule<'input, SliceType, Output = Output>,

For tuples up to arity 16, Rule is implemented as a sort of “anonymous group”, where each rule will be tried in sequence until one matches, or an error will be raised if none do.

The more_tuple_impls feature raises the implemented arity to 256, but massively increases compilation time. Use only when strictly necessary.

source§

type Output = Output

source§

fn parse_at<'cursor, 'this, 'index>( &'this self, input: &'cursor mut &'input SliceType, index: &'index mut usize, ) -> Result<Output, ParseError>
where 'input: 'this,

source§

impl<'input, T: 'input> Rule<'input, [T]> for for<'a> fn(_: &'a T) -> bool

source§

type Output = &'input T

source§

fn parse_at<'cursor, 'this, 'index>( &'this self, input: &'cursor mut &'input [T], index: &'index mut usize, ) -> Result<Self::Output, ParseError>
where 'input: 'this,

source§

impl<'input, T: PartialEq + 'input> Rule<'input, [T]> for [T]

source§

type Output = &'input [T]

source§

fn parse_at<'cursor, 'this, 'index>( &'this self, input: &'cursor mut &'input [T], index: &'index mut usize, ) -> Result<Self::Output, ParseError>
where 'input: 'this,

source§

impl<'input, const N: usize, T: PartialEq + 'input> Rule<'input, [T]> for [T; N]

source§

type Output = &'input [T]

source§

fn parse_at<'cursor, 'this, 'index>( &'this self, input: &'cursor mut &'input [T], index: &'index mut usize, ) -> Result<Self::Output, ParseError>
where 'input: 'this,

source§

impl<'ty, T, S: ?Sized> Rule<'ty, S> for for<'index, 'cursor> fn(_: &'cursor mut &'ty S, _: &'index mut usize) -> Result<T, ParseError>

source§

type Output = T

source§

fn parse_at<'cursor, 'this, 'index>( &'this self, input: &'cursor mut &'ty S, index: &'index mut usize, ) -> Result<T, ParseError>
where 'ty: 'this,

Implementors§

source§

impl<'input> Rule<'input, str> for Any

source§

impl<'input, F: Fn(&char) -> bool> Rule<'input, str> for While<F, char>

source§

type Output = &'input str

source§

impl<'input, R: Rule<'input, str>> Rule<'input, str> for Consume<'input, str, R>

source§

type Output = Vec<<R as Rule<'input, str>>::Output>

source§

impl<'input, SliceType: ?Sized, R: Rule<'input, SliceType>, O, E: Error + 'static, Func: Fn(R::Output) -> Result<O, E>> Rule<'input, SliceType> for TryMap<'input, SliceType, R, O, E, Func>

source§

impl<'input, SliceType: ?Sized, R: Rule<'input, SliceType>, O, Func: Fn(R::Output) -> O> Rule<'input, SliceType> for Map<'input, SliceType, R, O, Func>

source§

type Output = <Func as FnOnce(<R as Rule<'input, SliceType>>::Output)>::Output

source§

impl<'input, T: 'input + Index<RangeTo<usize>, Output = T> + ?Sized, R: Rule<'input, T>> Rule<'input, T> for Spanned<'input, T, R>

source§

type Output = Span<'input, T, <R as Rule<'input, T>>::Output>

source§

impl<'input, T: 'input + ?Sized, R: Rule<'input, T>> Rule<'input, T> for Attempt<'input, T, R>

source§

type Output = Result<<R as Rule<'input, T>>::Output, ParseError>

source§

impl<'input, T: 'input + ?Sized, R: Rule<'input, T>> Rule<'input, T> for Many<'input, T, R>

source§

type Output = Vec<<R as Rule<'input, T>>::Output>

source§

impl<'input, T: 'input + ?Sized, R: Rule<'input, T>> Rule<'input, T> for Repeat<'input, T, R>

source§

type Output = Vec<<R as Rule<'input, T>>::Output>

source§

impl<'input, T: 'input + ?Sized, R: Rule<'input, T>, const REPETITIONS: usize> Rule<'input, T> for RepeatFor<'input, T, R, REPETITIONS>

source§

type Output = [<R as Rule<'input, T>>::Output; REPETITIONS]

source§

impl<'input, T: 'input> Rule<'input, [T]> for Any

source§

impl<'input, T: 'input, F: Fn(&T) -> bool> Rule<'input, [T]> for While<F, T>

source§

type Output = &'input [T]

source§

impl<'input, T: 'input, R: Rule<'input, [T]>> Rule<'input, [T]> for Consume<'input, [T], R>

source§

type Output = Vec<<R as Rule<'input, [T]>>::Output>

source§

impl<'input, T: ?Sized + 'input, E: Error + Clone + 'static> Rule<'input, T> for Fail<E>

source§

type Output = <fn() -> ! as FnOnce<()>>::Output

source§

impl<'input, T: ?Sized + 'input, R: Rule<'input, T>> Rule<'input, T> for Not<R>