diff --git a/README.md b/README.md index 852134ce3b3a176060b8ff10449a835c6dd5d5ac..442f5bca13c70bcb2838a2437a7dd99620679cff 100644 --- a/README.md +++ b/README.md @@ -95,19 +95,6 @@ impl Synom for MyLit { )); } -#[proc_macro] -pub fn mylit(input: TokenStream) -> TokenStream { - let v: MyLit = syn::parse(input).unwrap(); - let value: u32 = v.val.value() as u32; - if !(10 <= value && value < 100) { - v.val - .span() - .unstable() - .error(format!("expected literal 10 <= x < 100, got {}", value,)) - .emit(); - } - From::from(v.val.into_tokens()) -} ``` So `MyLit` here is a structure for holding the parsed token. @@ -125,5 +112,44 @@ pub trait Synom: Sized { } ``` +The `do_parse!` processes a combination of parsers (in this case just a single one), +`val: syn!(LitInt) >> (MyLit { val })`, where `val` will be assigned the result of +`syn!(LitInt)`, and used in the right hand `MyLit {val}`. (As usal in Rust a struct can be contructed from varibles with matching field names, to make it more succint.) + +The `syn!` macro simly applies the parser for `LitInt` (requres a type itself implementing `Synom`). + +So now we have broken down the trait implmentation, we can see the expanded code. (As we see, the use of macros greately facilitates writing parsers.) + +``` rust +fn parse(i: ::buffer::Cursor) -> ::synom::PResult<Self> { + match <LitInt as ::synom::Synom>::parse(i) { + ::std::result::Result::Err(err) => ::std::result::Result::Err(err), + ::std::result::Result::Ok((o, i)) => { + let val = o; + ::std::result::Result::Ok(((MyLit { val }), i)) + } + } + } +``` + +(On a side note, we did not implment `description` for `MyLit`, here we can rely on a default implemntation given by the `syn` crate.) + +The parser is made accissible to the user by a procedural macro as follows. + +``` rust +#[proc_macro] +pub fn mylit(input: TokenStream) -> TokenStream { + let v: MyLit = syn::parse(input).unwrap(); + let value: u32 = v.val.value() as u32; + if !(10 <= value && value < 100) { + v.val + .span() + .unstable() + .error(format!("expected literal 10 <= x < 100, got {}", value,)) + .emit(); + } + From::from(v.val.into_tokens()) +} +``` -In order for `syn::parse` to be able to parse a `TokenStream` for +Besides just parsing an `IntLit` (that is a `u64`), we want at compile time to ensure that it is in a given range, say between 10 and 100, and report a sensible error message for illegal usage. The \ No newline at end of file