pub trait Rule<'input, SliceType: ?Sized + 'input>: NamedRule {
type Output;
Show 14 methods
// 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 take_sep<R: Rule<'input, SliceType>>(
self,
separator: R,
at_most: usize,
) -> Separated<'input, SliceType, Self, R>
where Self: Sized { ... }
fn hoard_sep<R: Rule<'input, SliceType>>(
self,
separator: R,
) -> Separated<'input, SliceType, Self, R>
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§
Required Methods§
Sourcefn parse_at<'cursor, 'this, 'index>(
&'this self,
input: &'cursor mut &'input SliceType,
index: &'index mut usize,
) -> Result<Self::Output, ParseError>where
'input: 'this,
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§
Sourcefn parse<'this>(
&'this self,
input: &'input SliceType,
) -> Result<(&'input SliceType, Self::Output), ParseError>where
'input: 'this,
fn parse<'this>(
&'this self,
input: &'input SliceType,
) -> Result<(&'input SliceType, Self::Output), ParseError>where
'input: 'this,
Examples found in repository?
89fn main() -> Result<(), std::io::Error> {
90 let mut lines = std::io::stdin().lines();
91 println!("Input a math expression below, `clear` to clear the console, or `exit` / `quit` to exit.");
92 println!("You can access the result of the last expression with `ans`.");
93 let mut last_ans = None;
94 'outer: loop {
95 print!("[?] ");
96 std::io::stdout().flush()?;
97 let Some(input) = lines.next().transpose()? else { break Ok(()) };
98 let input = input.trim_ascii();
99 if input.is_empty() { print!("\x1b[1A"); continue; }
100 match input {
101 "clear" => print!("\x1bc"),
102 "exit" | "quit" => break Ok(()),
103 _ => {
104 let (_, mut tokens) = match MathTokens::LangTokens.parse(&input) {
105 Ok(v) => v,
106 Err(err) => {
107 println!("[!] Failed to parse: {err}");
108 continue;
109 }
110 };
111 for ans in tokens.iter_mut().filter(|t| matches!(t, Token::Ans)) {
112 let Some(answer) = last_ans else {
113 println!("[!] No previous answer exists");
114 continue 'outer;
115 };
116 *ans = Token::Number(answer);
117 }
118 let (_, result) = match TokenMath::Expr.parse(tokens.as_ref()) {
119 Ok(v) => v,
120 Err(err) => {
121 println!("[!] Failed to parse: {err}");
122 continue;
123 }
124 };
125 last_ans = Some(result);
126 println!("[=] {result:.}")
127 }
128 }
129 }
130}Sourcefn map_parsed<Output, F: Fn(Self::Output) -> Output>(
self,
function: F,
) -> Map<'input, SliceType, Self, Output, F>where
Self: Sized,
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.
Sourcefn 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 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.
Sourcefn repeat_for<const REPS: usize>(
self,
) -> RepeatFor<'input, SliceType, Self, REPS>where
Self: Sized,
fn repeat_for<const REPS: usize>(
self,
) -> RepeatFor<'input, SliceType, Self, REPS>where
Self: Sized,
Repeats this rule a known amount of times.
Sourcefn repeat(self, reps: usize) -> Repeat<'input, SliceType, Self>where
Self: Sized,
fn repeat(self, reps: usize) -> Repeat<'input, SliceType, Self>where
Self: Sized,
Repeats this rule a set amount of times.
Sourcefn take(self, at_most: usize) -> Many<'input, SliceType, Self>where
Self: Sized,
fn take(self, at_most: usize) -> Many<'input, SliceType, Self>where
Self: Sized,
Repeats this rule at most a set amount of times.
Sourcefn hoard(self) -> Many<'input, SliceType, Self>where
Self: Sized,
fn hoard(self) -> Many<'input, SliceType, Self>where
Self: Sized,
Repeats this rule forever until it fails.
Sourcefn take_sep<R: Rule<'input, SliceType>>(
self,
separator: R,
at_most: usize,
) -> Separated<'input, SliceType, Self, R>where
Self: Sized,
fn take_sep<R: Rule<'input, SliceType>>(
self,
separator: R,
at_most: usize,
) -> Separated<'input, SliceType, Self, R>where
Self: Sized,
Repeats this rule at most a set amount of times, separated by another rule.
Sourcefn hoard_sep<R: Rule<'input, SliceType>>(
self,
separator: R,
) -> Separated<'input, SliceType, Self, R>where
Self: Sized,
fn hoard_sep<R: Rule<'input, SliceType>>(
self,
separator: R,
) -> Separated<'input, SliceType, Self, R>where
Self: Sized,
Repeats this rule forever until it fails, separated by another rule.
Sourcefn consume_all(self) -> Consume<'input, SliceType, Self>
fn consume_all(self) -> Consume<'input, SliceType, Self>
Repeats this rule until the end of input, failing if it ever does.
Examples found in repository?
18 pub LangTokens -> Vec<Token> = LangToken.consume_all()
19 .map_parsed(|v| v.into_iter().filter_map(|v| v).collect() );
20 LangToken -> Option<Token> =
21 Num : Plus : Minus : Asterisk : Slash : Percent : Carat
22 : LParen : RParen : Ans : _ Whitespace
23 : InvalidChar;
24 // Since Fail returns !, we can coerce from that to a token
25 InvalidChar -> Token from(|_, n| n) = Any, Fail::new(Unexpected::new(arg_0));
26
27 Plus -> Token = '+'.map_parsed(|_| Token::Plus);
28 Minus -> Token = '-'.map_parsed(|_| Token::Minus);
29 Asterisk -> Token = '*'.map_parsed(|_| Token::Asterisk);
30 Slash -> Token = '/'.map_parsed(|_| Token::Slash);
31 Percent -> Token = '%'.map_parsed(|_| Token::Percent);
32 Carat -> Token = '^'.map_parsed(|_| Token::Carat);
33 LParen -> Token = '('.map_parsed(|_| Token::LeftParen);
34 RParen -> Token = ')'.map_parsed(|_| Token::RightParen);
35
36 Ans -> Token = "ans".map_parsed(|_| Token::Ans);
37
38 Num -> Token from(|n| Token::Number(n)) =
39 ("nan", "NaN").map_parsed(|_| f64::NAN) :
40 ("inf", "Infinity").map_parsed(|_| f64::INFINITY) :
41 Float;
42 Float -> f64 try_from(f64::from_str) = FloatTokens.spanned().map_parsed(|span| span.source);
43
44 FloatTokens -> () = _ UInt, _ FloatFract.attempt(), _ FloatExp.attempt();
45 FloatFract -> () = _ '.', _ UInt;
46 FloatExp -> () = _ ('e', 'E'), _ ('-', '+').attempt(), _ UInt;
47
48 UInt -> &'input str = While::from(char::is_ascii_digit);
49 }
50}
51
52define! {
53 grammar TokenMath<[Token]> {
54 pub Expr -> f64 from(parse_expr) = Prod, SumSuf.consume_all();Implementations on Foreign Types§
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.
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.