1use proc_macro2::{Span, TokenStream, TokenTree};
2use quote::quote;
3use std::borrow::Cow;
4use syn::spanned::Spanned;
5use syn::{Attribute, GenericParam, Ident, Lit, LitBool, Meta, Type};
6
7use crate::error::Errors;
8use crate::leaf::{Callback, InlineCallback};
9use crate::util::{expect_punct, MaybeVoid};
10use crate::LOGOS_ATTR;
11
12mod definition;
13mod error_type;
14mod ignore_flags;
15mod nested;
16mod subpattern;
17mod type_params;
18
19pub use self::definition::{Definition, Literal};
20pub use self::error_type::ErrorType;
21pub use self::ignore_flags::IgnoreFlags;
22use self::nested::{AttributeParser, Nested, NestedValue};
23pub use self::subpattern::Subpatterns;
24use self::type_params::{replace_lifetime, traverse_type, TypeParams};
25
26#[derive(Default)]
27pub struct Parser {
28 pub errors: Errors,
29 pub utf8_mode: Option<LitBool>,
30 pub skips: Vec<Definition>,
31 pub extras: MaybeVoid,
32 pub subpatterns: Vec<(Ident, Literal)>,
33 pub error_type: Option<ErrorType>,
34 pub logos_path: Option<TokenStream>,
35 pub export_path: Option<String>,
36 types: TypeParams,
37}
38
39impl Parser {
40 pub fn parse_generic(&mut self, param: GenericParam) {
41 match param {
42 GenericParam::Lifetime(lt) => {
43 self.types.explicit_lifetime(lt, &mut self.errors);
44 }
45 GenericParam::Type(ty) => {
46 self.types.add(ty.ident);
47 }
48 GenericParam::Const(c) => {
49 self.err("Logos doesn't support const generics.", c.span());
50 }
51 }
52 }
53
54 pub fn generics(&mut self) -> Option<TokenStream> {
55 self.types.generics(&mut self.errors)
56 }
57
58 fn parse_attr(&mut self, attr: &mut Attribute) -> Option<AttributeParser> {
59 match &mut attr.meta {
60 Meta::List(list) => {
61 let tokens = std::mem::replace(&mut list.tokens, TokenStream::new());
62
63 Some(AttributeParser::new(tokens))
64 }
65 _ => None,
66 }
67 }
68
69 pub fn try_parse_logos(&mut self, attr: &mut Attribute) {
72 if !attr.path().is_ident(LOGOS_ATTR) {
73 return;
74 }
75
76 let nested = match self.parse_attr(attr) {
77 Some(tokens) => tokens,
78 None => {
79 self.err("Expected #[logos(...)]", attr.span());
80 return;
81 }
82 };
83
84 for nested in nested {
85 let (name, value) = match nested {
86 Nested::Named(name, value) => (name, value),
87 Nested::Unexpected(tokens) | Nested::Unnamed(tokens) => {
88 self.err("Invalid nested attribute", tokens.span());
89 continue;
90 }
91 };
92
93 let span = name.span();
94
95 match name.to_string().as_str() {
96 "crate" => match value {
97 NestedValue::Assign(logos_path) => self.logos_path = Some(logos_path),
98 _ => {
99 self.err("Expected: #[logos(crate = path::to::logos)]", span);
100 }
101 },
102 "error" => match value {
103 NestedValue::Assign(value) => {
104 let span = value.span();
105
106 let error_ty = ErrorType::new(value);
107
108 if let Some(previous) = self.error_type.replace(error_ty) {
109 self.err("Error type can be defined only once", span)
110 .err("Previous definition here", previous.span());
111 }
112 }
113 NestedValue::Group(value) => {
114 let span = value.span();
115 let mut nested = AttributeParser::new(value);
116 let ty = match nested.parsed::<Type>() {
117 Some(Ok(ty)) => ty,
118 Some(Err(e)) => {
119 self.err(e.to_string(), e.span());
120 return;
121 }
122 None => {
123 self.err("Expected #[logos(error(SomeType))]", span);
124 return;
125 }
126 };
127
128 let mut error_type = {
129 use quote::ToTokens;
130 ErrorType::new(ty.into_token_stream())
131 };
132
133 for (position, next) in nested.enumerate() {
134 match next {
135 Nested::Unexpected(tokens) => {
136 self.err("Unexpected token in attribute", tokens.span());
137 }
138 Nested::Unnamed(tokens) => match position {
139 0 => error_type.callback = self.parse_callback(tokens),
140 _ => {
141 self.err(
142 "\
143 Expected a named argument at this position\n\
144 \n\
145 hint: If you are trying to define a callback here use: callback = ...\
146 ",
147 tokens.span(),
148 );
149 }
150 },
151 Nested::Named(name, value) => {
152 error_type.named_attr(name, value, self);
153 }
154 }
155 }
156
157 if let Some(previous) = self.error_type.replace(error_type) {
158 self.err("Error type can be defined only once", span)
159 .err("Previous definition here", previous.span());
160 }
161 }
162 _ => {
163 self.err(
164 concat!(
165 "Expected: #[logos(error = SomeType)] or ",
166 "#[logos(error(SomeType[, callback))]"
167 ),
168 span,
169 );
170 }
171 },
172 "export_dir" => match value {
173 NestedValue::Assign(value) => {
174 let span = value.span();
175
176 match syn::parse2::<Literal>(value) {
177 Ok(Literal::Utf8(str)) => {
178 if let Some(previous) = self.export_path.replace(str.value()) {
179 self.err("Export path can be defined only once", span)
180 .err("Previous definition here", previous.span());
181 }
182 }
183 Ok(_) => {
184 self.err("Expected a &str", span);
185 }
186 Err(e) => {
187 self.err(e.to_string(), span);
188 }
189 }
190 }
191 _ => {
192 self.err(
193 "Expected #[logos(export_dir = \"path/to/export/dir\")]",
194 span,
195 );
196 }
197 },
198 "extras" => match value {
199 NestedValue::Assign(value) => {
200 let span = value.span();
201
202 if let MaybeVoid::Some(previous) = self.extras.replace(value) {
203 self.err("Extras can be defined only once", span)
204 .err("Previous definition here", previous.span());
205 }
206 }
207 _ => {
208 self.err("Expected: #[logos(extras = SomeType)]", span);
209 }
210 },
211 "skip" => match value {
212 NestedValue::Literal(lit) => {
213 if let Some(literal) = self.parse_literal(Lit::new(lit)) {
214 self.skips.push(Definition::new(literal));
215 }
216 }
217 NestedValue::Group(tokens) => {
218 let token_span = tokens.span();
219 if let Some(skip) = self.parse_definition(AttributeParser::new(tokens)) {
220 self.skips.push(skip);
221 } else {
222 self.err(
223 "Expected #[logos(skip(\"regex literal\"[, [callback = ] callback, priority = priority]))]",
224 token_span,
225 );
226 }
227 }
228 _ => {
229 self.err(
230 "Expected: #[logos(skip \"regex literal\")] or #[logos(skip(...))]",
231 span,
232 );
233 }
234 },
235 "source" => {
236 self.err(
237 "The `source` attribute is deprecated. Use the `utf8` attribute instead",
238 span,
239 );
240 }
241 "subpattern" => match value {
242 NestedValue::KeywordAssign(name, value) => {
243 match syn::parse2::<Literal>(value) {
244 Ok(lit) => {
245 self.subpatterns.push((name, lit));
246 }
247 Err(e) => {
248 self.errors.err(e.to_string(), e.span());
249 }
250 };
251 }
252 _ => {
253 self.err(r#"Expected: #[logos(subpattern name = r"regex")]"#, span);
254 }
255 },
256 "type" => match value {
257 NestedValue::KeywordAssign(generic, ty) => {
258 self.types.set(generic, ty, &mut self.errors);
259 }
260 _ => {
261 self.err("Expected: #[logos(type T = SomeType)]", span);
262 }
263 },
264 "utf8" => match value {
265 NestedValue::Assign(value) => {
266 let span = value.span();
267
268 match syn::parse2::<LitBool>(value) {
269 Ok(lit) => {
270 if let Some(previous) = self.utf8_mode.replace(lit) {
271 self.err("Utf8 mode can be defined only once", span)
272 .err("Previous definition here", previous.span());
273 }
274 }
275 Err(e) => {
276 self.err(format!("Expected a boolean literal: {e}"), span);
277 }
278 }
279 }
280 _ => {
281 self.err("Expected: #[logos(utf8 = true)]", span);
282 }
283 },
284 name => {
285 self.err(format!("Unknown nested attribute #[logos({name})]",), span);
286 }
287 }
288 }
289 }
290
291 pub fn parse_literal(&mut self, lit: Lit) -> Option<Literal> {
292 match lit {
293 Lit::Str(string) => Some(Literal::Utf8(string)),
294 Lit::ByteStr(bytes) => Some(Literal::Bytes(bytes)),
295 _ => {
296 self.err("Expected a &str or &[u8] slice", lit.span());
297
298 None
299 }
300 }
301 }
302
303 pub fn parse_definition_attr(&mut self, attr: &mut Attribute) -> Option<Definition> {
308 let nested = self.parse_attr(attr)?;
309
310 self.parse_definition(nested)
311 }
312
313 fn parse_definition(&mut self, mut nested: AttributeParser) -> Option<Definition> {
314 let literal = match nested.parsed::<Lit>()? {
315 Ok(lit) => self.parse_literal(lit)?,
316 Err(err) => {
317 self.err(err.to_string(), err.span());
318
319 return None;
320 }
321 };
322
323 let mut def = Definition::new(literal);
324
325 for (position, next) in nested.enumerate() {
326 match next {
327 Nested::Unexpected(tokens) => {
328 self.err("Unexpected token in attribute", tokens.span());
329 }
330 Nested::Unnamed(tokens) => match position {
331 0 => def.callback = self.parse_callback(tokens),
332 _ => {
333 self.err(
334 "\
335 Expected a named argument at this position\n\
336 \n\
337 hint: If you are trying to define a callback here use: callback = ...\
338 ",
339 tokens.span(),
340 );
341 }
342 },
343 Nested::Named(name, value) => {
344 def.named_attr(name, value, self);
345 }
346 }
347 }
348
349 Some(def)
350 }
351
352 fn parse_callback(&mut self, tokens: TokenStream) -> Option<Callback> {
353 let span = tokens.span();
354 let mut tokens = tokens.into_iter();
355
356 if let Some(tt) = expect_punct(tokens.next(), '|') {
357 let mut label = TokenStream::from(tt);
358
359 label.extend(tokens);
360
361 return Some(Callback::Label(label));
362 }
363
364 let first = tokens.next();
365 let error = expect_punct(tokens.next(), '|');
366
367 let arg = match (error, first) {
368 (None, Some(TokenTree::Ident(arg))) => arg,
369 _ => {
370 self.err(
371 "Inline callbacks must use closure syntax with exactly one parameter",
372 span,
373 );
374 return None;
375 }
376 };
377
378 let body = match tokens.next() {
379 Some(TokenTree::Group(group)) => group.stream(),
380 Some(first) => {
381 let mut body = TokenStream::from(first);
382
383 body.extend(tokens);
384 body
385 }
386 None => {
387 self.err("Callback missing a body", span);
388 return None;
389 }
390 };
391
392 let inline = InlineCallback { arg, body, span };
393
394 Some(inline.into())
395 }
396
397 pub fn get_type(&self, ty: &mut Type) -> TokenStream {
403 traverse_type(ty, &mut |ty| {
404 if let Type::Path(tp) = ty {
405 if tp.qself.is_none() {
407 if let Some(substitute) = self.types.find(&tp.path) {
410 *ty = substitute;
411 }
412 }
413 }
414 replace_lifetime(ty);
416 });
417
418 quote!(#ty)
419 }
420
421 pub fn err<M>(&mut self, message: M, span: Span) -> &mut Errors
422 where
423 M: Into<Cow<'static, str>>,
424 {
425 self.errors.err(message, span)
426 }
427}