Attribute Macro pear_codegen::parser
source · #[parser]Expand description
The core attribute macro. Can only be applied to free functions with at least one parameter and a return value. To typecheck, the free function must meet the following typing requirements:
- The first parameter’s type must be a mutable reference to a [
Pear<I>] hereIimplements [Input]. This is the input parameter. - The return type must be
Result<O, I>whereIis the inner type of the input parameter andOcan be any type.
The following transformations are applied to the contents of the attributed function:
-
The functions first parameter (of type
&mut Pear<I>) is passed as the first parameter to every function call in the function with a posfix?. That is, every function call of the formfoo(a, b, c, ...)?is converted tofoo(input, a, b, c, ...)?whereinputis the input parameter. -
The inputs to every macro whose name starts with
parse_are prefixed with[PARSER_NAME, INPUT, MARKER, OUTPUT]wherePARSER_NAMEis the raw string literal of the functon’s name,INPUTis the input parameter expression,MARKERis the marker expression, andOUTPUTis the output type. Aditionally, if the input to the macro is a valid Rust expression, it is applied the same transformations as a function atributed with#[parser].Declare a
parse_macro as:ⓘmacro_rules! parse_my_macro { ([$n:expr; $i:expr; $m:expr; $T:ty] ..) => { /* .. */ } }
The following transformations are applied around the attributed function:
- The [
Input::mark()] method is called before the function executes. The returned mark, if any, is stored on the stack. - A return value of
Ois automatically converted (or “lifted”) into a type ofResult<O, I>by wrapping it inOk. - If the function returns an
Err, [Input::context()] is called with the current mark, and the returned context, if any, is pushed into the error via [ParseError::push_context()]. - The [
Input::unmark()] method is called after the function executes, passing in the current mark.
Example
use pear::input::{Pear, Text, Result};
use pear::macros::{parser, parse};
use pear::parsers::*;
#[parser]
fn ab_in_dots<'a, I: Input<'a>>(input: &mut Pear<I>) -> Result<&'a str, I> {
eat('.')?;
let inside = take_while(|&c| c == 'a' || c == 'b')?;
eat('.')?;
inside
}
let x = parse!(ab_in_dots: Text::from(".abba."));
assert_eq!(x.unwrap(), "abba");
let x = parse!(ab_in_dots: Text::from(".ba."));
assert_eq!(x.unwrap(), "ba");
let x = parse!(ab_in_dots: Text::from("..."));
assert!(x.is_err());