blob: b968b917b9d3018c243cc51bf4a94c573b8fbfaa [file] [log] [blame]
David Tolnay42342c82018-08-25 08:36:35 -04001use proc_macro2::{Delimiter, Span};
David Tolnay18c754c2018-08-21 23:26:58 -04002
David Tolnayad4b2472018-08-25 08:25:24 -04003use error::Result;
David Tolnayb6254182018-08-25 08:44:54 -04004use parse::ParseBuffer;
David Tolnay94f06632018-08-31 10:17:17 -07005use private;
David Tolnay776f8e02018-08-24 22:32:10 -04006use token;
David Tolnay18c754c2018-08-21 23:26:58 -04007
David Tolnay42342c82018-08-25 08:36:35 -04008pub struct Parens<'a> {
9 pub token: token::Paren,
10 pub content: ParseBuffer<'a>,
11}
12
David Tolnay18c754c2018-08-21 23:26:58 -040013pub struct Braces<'a> {
14 pub token: token::Brace,
15 pub content: ParseBuffer<'a>,
16}
17
David Tolnay42342c82018-08-25 08:36:35 -040018pub struct Brackets<'a> {
19 pub token: token::Bracket,
20 pub content: ParseBuffer<'a>,
21}
22
David Tolnaya7d69fc2018-08-26 13:30:24 -040023pub struct Group<'a> {
24 pub token: token::Group,
25 pub content: ParseBuffer<'a>,
26}
27
David Tolnay18c754c2018-08-21 23:26:58 -040028impl<'a> ParseBuffer<'a> {
David Tolnaya7d69fc2018-08-26 13:30:24 -040029 fn parse_delimited(&self, delimiter: Delimiter) -> Result<(Span, ParseBuffer<'a>)> {
David Tolnayb50c65a2018-08-30 21:14:57 -070030 self.step(|cursor| {
David Tolnay42342c82018-08-25 08:36:35 -040031 if let Some((content, span, rest)) = cursor.group(delimiter) {
David Tolnay94f06632018-08-31 10:17:17 -070032 let unexpected = private::<ParseBuffer>::get_unexpected(self);
David Tolnay4ac232d2018-08-31 10:18:03 -070033 let content =
34 private::<ParseBuffer>::new(span, cursor.advance(content), unexpected);
David Tolnay42342c82018-08-25 08:36:35 -040035 Ok(((span, content), rest))
David Tolnay18c754c2018-08-21 23:26:58 -040036 } else {
David Tolnay42342c82018-08-25 08:36:35 -040037 let message = match delimiter {
38 Delimiter::Parenthesis => "expected parentheses",
39 Delimiter::Brace => "expected curly braces",
40 Delimiter::Bracket => "expected square brackets",
David Tolnaya7d69fc2018-08-26 13:30:24 -040041 Delimiter::None => "expected invisible group",
David Tolnay42342c82018-08-25 08:36:35 -040042 };
43 Err(cursor.error(message))
David Tolnay18c754c2018-08-21 23:26:58 -040044 }
45 })
46 }
David Tolnay42342c82018-08-25 08:36:35 -040047
48 // Not public API.
49 #[doc(hidden)]
50 pub fn parse_parens(&self) -> Result<Parens<'a>> {
David Tolnaya7d69fc2018-08-26 13:30:24 -040051 self.parse_delimited(Delimiter::Parenthesis)
David Tolnay8c39ac52018-08-25 08:46:21 -040052 .map(|(span, content)| Parens {
53 token: token::Paren(span),
54 content: content,
55 })
David Tolnay42342c82018-08-25 08:36:35 -040056 }
57
58 // Not public API.
59 #[doc(hidden)]
60 pub fn parse_braces(&self) -> Result<Braces<'a>> {
David Tolnaya7d69fc2018-08-26 13:30:24 -040061 self.parse_delimited(Delimiter::Brace)
David Tolnay8c39ac52018-08-25 08:46:21 -040062 .map(|(span, content)| Braces {
63 token: token::Brace(span),
64 content: content,
65 })
David Tolnay42342c82018-08-25 08:36:35 -040066 }
67
68 // Not public API.
69 #[doc(hidden)]
70 pub fn parse_brackets(&self) -> Result<Brackets<'a>> {
David Tolnaya7d69fc2018-08-26 13:30:24 -040071 self.parse_delimited(Delimiter::Bracket)
David Tolnay8c39ac52018-08-25 08:46:21 -040072 .map(|(span, content)| Brackets {
73 token: token::Bracket(span),
74 content: content,
75 })
David Tolnay42342c82018-08-25 08:36:35 -040076 }
David Tolnaya7d69fc2018-08-26 13:30:24 -040077
78 // Not public API.
79 #[doc(hidden)]
80 pub fn parse_group(&self) -> Result<Group<'a>> {
81 self.parse_delimited(Delimiter::None)
82 .map(|(span, content)| Group {
83 token: token::Group(span),
84 content: content,
85 })
86 }
David Tolnay42342c82018-08-25 08:36:35 -040087}
88
89/// Parse a set of parentheses and expose their content to subsequent parsers.
90#[macro_export]
91macro_rules! parenthesized {
92 ($content:ident in $cursor:expr) => {
David Tolnayb6254182018-08-25 08:44:54 -040093 match $crate::parse::ParseBuffer::parse_parens(&$cursor) {
David Tolnay42342c82018-08-25 08:36:35 -040094 $crate::export::Ok(parens) => {
95 $content = parens.content;
96 parens.token
97 }
98 $crate::export::Err(error) => {
99 return $crate::export::Err(error);
100 }
101 }
102 };
David Tolnay18c754c2018-08-21 23:26:58 -0400103}
104
105/// Parse a set of curly braces and expose their content to subsequent parsers.
106///
107/// ```rust
David Tolnay6d67c742018-08-24 20:42:39 -0400108/// # extern crate syn;
David Tolnay18c754c2018-08-21 23:26:58 -0400109/// #
David Tolnayb6254182018-08-25 08:44:54 -0400110/// use syn::{braced, token, Ident, Token};
111/// use syn::parse::{Parse, ParseStream, Result};
David Tolnaye7635332018-08-26 08:16:18 -0400112/// use syn::punctuated::Punctuated;
David Tolnay6d67c742018-08-24 20:42:39 -0400113/// #
David Tolnaye7635332018-08-26 08:16:18 -0400114/// # type Field = Ident;
David Tolnay18c754c2018-08-21 23:26:58 -0400115///
116/// // Parse a simplified struct syntax like:
117/// //
118/// // struct S {
119/// // a: A,
120/// // b: B,
121/// // }
122/// struct Struct {
123/// pub struct_token: Token![struct],
124/// pub ident: Ident,
125/// pub brace_token: token::Brace,
David Tolnaye7635332018-08-26 08:16:18 -0400126/// pub fields: Punctuated<Field, Token![,]>,
David Tolnay18c754c2018-08-21 23:26:58 -0400127/// }
128///
129/// impl Parse for Struct {
130/// fn parse(input: ParseStream) -> Result<Self> {
131/// let content;
132/// Ok(Struct {
133/// struct_token: input.parse()?,
134/// ident: input.parse()?,
135/// brace_token: braced!(content in input),
David Tolnaye7635332018-08-26 08:16:18 -0400136/// fields: content.parse_terminated(Field::parse)?,
David Tolnay18c754c2018-08-21 23:26:58 -0400137/// })
138/// }
139/// }
140/// ```
141#[macro_export]
142macro_rules! braced {
143 ($content:ident in $cursor:expr) => {
David Tolnayb6254182018-08-25 08:44:54 -0400144 match $crate::parse::ParseBuffer::parse_braces(&$cursor) {
David Tolnay456c9822018-08-25 08:09:46 -0400145 $crate::export::Ok(braces) => {
David Tolnay18c754c2018-08-21 23:26:58 -0400146 $content = braces.content;
147 braces.token
148 }
David Tolnay456c9822018-08-25 08:09:46 -0400149 $crate::export::Err(error) => {
150 return $crate::export::Err(error);
David Tolnay18c754c2018-08-21 23:26:58 -0400151 }
152 }
153 };
154}
David Tolnay42342c82018-08-25 08:36:35 -0400155
156/// Parse a set of square brackets and expose their content to subsequent
157/// parsers.
158#[macro_export]
159macro_rules! bracketed {
160 ($content:ident in $cursor:expr) => {
David Tolnayb6254182018-08-25 08:44:54 -0400161 match $crate::parse::ParseBuffer::parse_brackets(&$cursor) {
David Tolnay42342c82018-08-25 08:36:35 -0400162 $crate::export::Ok(brackets) => {
163 $content = brackets.content;
164 brackets.token
165 }
166 $crate::export::Err(error) => {
167 return $crate::export::Err(error);
168 }
169 }
170 };
171}
David Tolnaya7d69fc2018-08-26 13:30:24 -0400172
173#[doc(hidden)]
174#[macro_export]
175macro_rules! grouped {
176 ($content:ident in $cursor:expr) => {
177 match $crate::parse::ParseBuffer::parse_group(&$cursor) {
178 $crate::export::Ok(group) => {
179 $content = group.content;
180 group.token
181 }
182 $crate::export::Err(error) => {
183 return $crate::export::Err(error);
184 }
185 }
186 };
187}