1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 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 131 132
//! Simple code generator for manual parsing
//!
//! ## Attributes
//!
//! ### Struct
//!
//! There are several attributes that control behaviour of parser
//! Each, attached to struct's field
//!
//! - `starts_with = <prefix>` - Specifies string with which next parse step should start(can be stacked). Errors if prefix is missing.
//! - `ends_with = <prefix>` - Specifies string with which parse step should end(can be stacked). Errors if suffix is missing. If empty, expects EOF.
//! - `skip = <chars>` - Specifies to skip characters, until not meeting character outside of specified in string.
//! - `skip(ws)` - Specifies to skip all white space characters.
//! - `format(<format>)` - Specifies list of characters that should contain value to parse from.
//! - `format(not(<format>))` - Specifies list of characters that should contain value to parse from.
//!
//! ##### Formats
//!
//! - Literal string - When string is specified as argument to `format`, it is used as set of characters.
//! - `numeric` - When specified, match using `char::is_numeric()`
//! - `digit(<base>)` - When specified, match using `char::is_digit(<base>)`
//! - `ascii` - When specified, match using `char::is_ascii()`
//! - `alphabetic` - When specified, match using `char::is_alphabetic()`
//!
//! ### Enum
//!
//! - `format = <format>` - Specifies string to match against.
//! - `case` - Specifies case sensitive match. By default it is insensitive.
//! - `default` - Specifies variant as taking default value. Should take only single `String` and
//! there can be only one
//!
//! ## Usage
//!
//! ### Struct
//!
//! ```rust
//! use std::str::FromStr;
//!
//! #[derive(banjin::Parser)]
//! pub struct Data {
//! #[starts_with = "prefix"]
//! #[skip(ws)]
//! #[starts_with = "+"]
//! #[skip(ws)]
//! #[format(ascii)]
//! #[format(digit(10))]
//! pub first: u32,
//! #[skip(ws)]
//! #[format(not("d"))]
//! #[format("13")]
//! #[ends_with = "d"]
//! #[ends_with = ""]
//! pub second: String,
//! }
//!
//! fn main() {
//! let data = Data::from_str("prefix + 666 13d").expect("Parse");
//! assert_eq!(data.first, 666);
//! assert_eq!(data.second, "13");
//!
//! let data = Data::from_str("prefix + 666 13");
//! assert!(data.is_err());
//!
//! let data = Data::from_str("prefix 666 13d");
//! assert!(data.is_err());
//!
//! let data = Data::from_str("prefix + 666 13dg");
//! assert!(data.is_err());
//!
//! let data = Data::from_str("");
//! assert!(data.is_err());
//! }
//!
//! ```
//!
//! ### Enum
//!
//! ```rust
//! use std::str::FromStr;
//!
//! #[derive(banjin::Parser, PartialEq, Eq, Debug)]
//! enum Gender {
//! Male,
//! #[case]
//! Female,
//! #[default]
//! Other(String)
//! }
//!
//! fn main() {
//! let gender = Gender::from_str("male").expect("Parse");
//! assert_eq!(gender, Gender::Male);
//!
//! let gender = Gender::from_str("female").expect("Parse");
//! match gender {
//! Gender::Other(text) => assert_eq!(text, "female"),
//! _ => panic!("Unexpected!")
//! }
//!
//! let gender = Gender::from_str("none").expect("Parse");
//! match gender {
//! Gender::Other(text) => assert_eq!(text, "none"),
//! _ => panic!("Unexpected!")
//! }
//! }
//! ```
extern crate proc_macro;
use proc_macro::TokenStream;
#[cfg(feature = "no_std")]
const FROM_STR: &'static str = "core::str::FromStr";
#[cfg(not(feature = "no_std"))]
const FROM_STR: &'static str = "std::str::FromStr";
mod from_struct;
mod from_enum;
fn generate(ast: syn::DeriveInput) -> String {
match ast.data {
syn::Data::Struct(ref data) => from_struct::parse(&ast, data),
syn::Data::Enum(ref data) => from_enum::parse(&ast, data),
_ => panic!("derive(Parser) is available for structs only"),
}
}
#[proc_macro_derive(Parser, attributes(skip, format, starts_with, ends_with, case, default))]
pub fn parser_derive(input: TokenStream) -> TokenStream {
let ast: syn::DeriveInput = syn::parse(input).unwrap();
generate(ast).parse().expect("To parse generate")
}