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
//! A library that allows [proc_macro] function-like macros to be parsed using
//! the [combine] parser combinator crate.
//!
//! [proc_macro]: https://doc.rust-lang.org/stable/proc_macro/index.html
//! [combine]: https://docs.rs/crate/combine
//!
//! ## Motivation
//! When writing a `#[proc_macro_derive]` the input is Rust source code which is
//! well supported by the `syn` crate. However, when writing a `#[proc_macro]`
//! macro, it is common to want to define a custom domain specific language.
//!
//! This crate allows you to write a parser for your DSL using the `combine`
//! parser combinator library. It also preserves the source _span_ information
//! in the parsed result such that `rustc` can provide correct source locations
//! for identifiers and literals that are re-used in the output.
//!
//! ## Implementing a parser
//! This is a basic example using base `combine` parsers.
//!
//! ```rust
//! # extern crate proc_macro;
//! use combine::{ParseError, Parser, Stream};
//! use combine_proc_macro::{Token, Literal};
//! use combine_proc_macro::parser::{delim, keyword, literal, punct};
//!
//! /// Parses expressions like `{ hello "world"! }`.
//! fn hello_grammar<I>() -> impl Parser<Input = I, Output = Literal>
//! where
//! I: Stream<Item = Token>,
//! I::Error: ParseError<I::Item, I::Range, I::Position>,
//! {
//! ( delim('{')
//! , keyword("hello")
//! , literal()
//! , punct('!')
//! , delim('}')
//! ).map(|(_, _, greeting, _, _)| greeting)
//! }
//! ```
//!
//! Using the `parser!` macro can help remove boilerplate.
//!
//! ```rust
//! # extern crate proc_macro;
//! use combine::Parser;
//! use combine_proc_macro::Literal;
//! use combine_proc_macro::parser;
//! use combine_proc_macro::parser::{delim, keyword, literal, punct};
//!
//! parser!(fn hello_grammar() -> Literal {
//! ( delim('{')
//! , keyword("hello")
//! , literal()
//! , punct('!')
//! , delim('}')
//! ).map(|(_, _, greeting, _, _)| greeting)
//! });
//! ```
//!
//! ## Implementing a macro
//! A proc macro must be defined at the crate root within the `lib.rs` file.
//!
//! ```rust,ignore
//! extern crate proc_macro;
//!
//! use combine::parser::Parser;
//! use combine_proc_macro::{Input, Incomplete};
//! use proc_macro::TokenStream;
//!
//! #[proc_macro]
//! pub fn hello_macro(input: TokenStream) -> TokenStream {
//! let input = Input::from(input).with_lookahead(1);
//! let result = hello_grammar().easy_parse(input);
//! let (ast, trailing) = match result {
//! Ok(ok) => ok,
//! Err(err) => panic!("error parsing in `hello_macro` macro: {:#?}", err),
//! };
//! if let Some(diagnostic) = Incomplete::from_stream(trailing) {
//! panic!("unexpected tokens at end of input:\n\n{}", diagnostic);
//! }
//!
//! impl_hello_macro(&ast) // generate rust output; e.g. using the `quote` crate
//! }
//!
//! # use combine::{ParseError, Stream};
//! # use combine_proc_macro::Token;
//! # use combine_proc_macro::parser::literal;
//! # use proc_macro::Literal;
//! #
//! # fn hello_grammar<I>() -> impl Parser<Input = I, Output = Literal>
//! # where
//! # I: Stream<Item = Token>,
//! # I::Error: ParseError<I::Item, I::Range, I::Position> { literal() }
//! #
//! # fn impl_hello_macro(ast: &Literal) -> TokenStream { unimplemented!() }
//! ```
extern crate proc_macro;
extern crate proc_macro2;
pub use Incomplete;
pub use ;
pub use ;