diff --git a/README.md b/README.md index 442f5bca13c70bcb2838a2437a7dd99620679cff..5c5b7b9312c8362c5a695bc56a8505808cc59af9 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ # Writing parsers using `syn` and `nom` parser combinators -## Parsing a LitInt and rejecting invalid range +Disclaimer, I'm NOT the author of the `syn` and `nom` parsing frameworks, so no guarantee the text accurately conveys their idiomatic use. + +The same goes for all references to supporting crates and references to other Rust libraries, crates and the language itself, so use material at own risk :) + +## Parsing a `LitInt` and rejecting invalid range As a simple example let us start out with `mylit!(LitInt)`, where `LitInt` should be an intereger literal `x` in the range `10 <= x < 100`. @@ -71,7 +75,6 @@ The procedural macro is defined in the `src/lib.rs` as follows. #![feature(proc_macro)] extern crate proc_macro; -#[macro_use] extern crate quote; #[macro_use] extern crate syn; @@ -114,12 +117,14 @@ 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.) +`syn!(LitInt)`, and used in the right hand `MyLit { val }`. (As usal in Rust a struct can be constructed 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`). +The `syn!` macro simly applies the parser for `LitInt` (requires a type that 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.) +(On a side note, we did not implment `description` for `MyLit`, here we can rely on a default implemntation given by the `syn` crate.) + ``` rust fn parse(i: ::buffer::Cursor) -> ::synom::PResult<Self> { match <LitInt as ::synom::Synom>::parse(i) { @@ -132,15 +137,13 @@ fn parse(i: ::buffer::Cursor) -> ::synom::PResult<Self> { } ``` -(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; + let value = v.val.value(); if !(10 <= value && value < 100) { v.val .span() @@ -152,4 +155,6 @@ pub fn mylit(input: TokenStream) -> TokenStream { } ``` -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 +Besides just parsing an `IntLit` (that is a `u64`), we want at compile time to ensure that it is in a given range, (between 10 and 100 in this example), and report a sensible error message for illegal usage. + +The error message is presented as a `TokenStream` throught the `.emit()` function. \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index f42037dc9e142aea45df1b911c336efc0a43dd48..4c6cf70e195108446fc3194765f50b2c202d67ee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ #![feature(proc_macro)] extern crate proc_macro; -#[macro_use] +// #[macro_use] extern crate quote; #[macro_use] extern crate syn; @@ -13,7 +13,7 @@ use syn::LitInt; use quote::ToTokens; use std::convert::From; -use std::error::Error; +// use std::error::Error; /// MyLit struct MyLit { @@ -29,7 +29,7 @@ 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; + let value = v.val.value(); if !(10 <= value && value < 100) { v.val .span()