1#![recursion_limit = "196"]
9#![doc(html_logo_url = "https://maciej.codes/kosz/logos.png")]
10
11mod error;
12mod generator;
13mod graph;
14mod leaf;
15mod mir;
16mod parser;
17mod util;
18
19use generator::Generator;
20use graph::{DisambiguationError, Fork, Graph, Rope};
21use leaf::Leaf;
22use parser::{Mode, Parser};
23use util::MaybeVoid;
24
25use proc_macro::TokenStream;
26use proc_macro2::Span;
27use quote::quote;
28use syn::spanned::Spanned;
29use syn::{Fields, ItemEnum};
30
31#[proc_macro_derive(Logos, attributes(logos, extras, error, end, token, regex))]
32pub fn logos(input: TokenStream) -> TokenStream {
33 let mut item: ItemEnum = syn::parse(input).expect("Logos can be only be derived for enums");
34
35 let name = &item.ident;
36
37 let mut error = None;
38 let mut parser = Parser::default();
39
40 for param in item.generics.params {
41 parser.parse_generic(param);
42 }
43
44 for attr in &mut item.attrs {
45 parser.try_parse_logos(attr);
46
47 if attr.path.is_ident("extras") {
49 parser.err(
50 "\
51 #[extras] attribute is deprecated. Use #[logos(extras = Type)] instead.\n\
52 \n\
53 For help with migration see release notes: \
54 https://github.com/maciejhirsz/logos/releases\
55 ",
56 attr.span(),
57 );
58 }
59 }
60
61 let mut ropes = Vec::new();
62 let mut regex_ids = Vec::new();
63 let mut graph = Graph::new();
64
65 for variant in &mut item.variants {
66 let field = match &mut variant.fields {
67 Fields::Unit => MaybeVoid::Void,
68 Fields::Unnamed(fields) => {
69 if fields.unnamed.len() != 1 {
70 parser.err(
71 format!(
72 "Logos currently only supports variants with one field, found {}",
73 fields.unnamed.len(),
74 ),
75 fields.span(),
76 );
77 }
78
79 let ty = &mut fields
80 .unnamed
81 .first_mut()
82 .expect("Already checked len; qed")
83 .ty;
84 let ty = parser.get_type(ty);
85
86 MaybeVoid::Some(ty)
87 }
88 Fields::Named(fields) => {
89 parser.err("Logos doesn't support named fields yet.", fields.span());
90
91 MaybeVoid::Void
92 }
93 };
94
95 let var_ident = &variant.ident;
97 let leaf = move |span| Leaf::new(var_ident, span).field(field.clone());
98
99 for attr in &mut variant.attrs {
100 let attr_name = match attr.path.get_ident() {
101 Some(ident) => ident.to_string(),
102 None => continue,
103 };
104
105 match attr_name.as_str() {
106 "error" => {
107 let span = variant.ident.span();
108 if let Some(previous) = error.replace(&variant.ident) {
109 parser
110 .err("Only one #[error] variant can be declared.", span)
111 .err("Previously declared #[error]:", previous.span());
112 }
113 }
114 "end" => {
115 parser.err(
117 "\
118 Since 0.11 Logos no longer requires the #[end] variant.\n\
119 \n\
120 For help with migration see release notes: \
121 https://github.com/maciejhirsz/logos/releases\
122 ",
123 attr.span(),
124 );
125 }
126 "token" => {
127 let definition = match parser.parse_definition(attr) {
128 Some(definition) => definition,
129 None => {
130 parser.err("Expected #[token(...)]", attr.span());
131 continue;
132 }
133 };
134
135 if definition.ignore_flags.is_empty() {
136 let bytes = definition.literal.to_bytes();
137 let then = graph.push(
138 leaf(definition.literal.span())
139 .priority(definition.priority.unwrap_or(bytes.len() * 2))
140 .callback(definition.callback),
141 );
142
143 ropes.push(Rope::new(bytes, then));
144 } else {
145 let mir = definition
146 .literal
147 .escape_regex()
148 .to_mir(
149 &Default::default(),
150 definition.ignore_flags,
151 &mut parser.errors,
152 )
153 .expect("The literal should be perfectly valid regex");
154
155 let then = graph.push(
156 leaf(definition.literal.span())
157 .priority(definition.priority.unwrap_or_else(|| mir.priority()))
158 .callback(definition.callback),
159 );
160 let id = graph.regex(mir, then);
161
162 regex_ids.push(id);
163 }
164 }
165 "regex" => {
166 let definition = match parser.parse_definition(attr) {
167 Some(definition) => definition,
168 None => {
169 parser.err("Expected #[regex(...)]", attr.span());
170 continue;
171 }
172 };
173 let mir = match definition.literal.to_mir(
174 &parser.subpatterns,
175 definition.ignore_flags,
176 &mut parser.errors,
177 ) {
178 Ok(mir) => mir,
179 Err(err) => {
180 parser.err(err, definition.literal.span());
181 continue;
182 }
183 };
184
185 let then = graph.push(
186 leaf(definition.literal.span())
187 .priority(definition.priority.unwrap_or_else(|| mir.priority()))
188 .callback(definition.callback),
189 );
190 let id = graph.regex(mir, then);
191
192 regex_ids.push(id);
193 }
194 _ => (),
195 }
196 }
197 }
198
199 let mut root = Fork::new();
200
201 let extras = parser.extras.take();
202 let source = match parser.mode {
203 Mode::Utf8 => quote!(str),
204 Mode::Binary => quote!([u8]),
205 };
206
207 let error_def = match error {
208 Some(error) => Some(quote!(const ERROR: Self = #name::#error;)),
209 None => {
210 parser.err("missing #[error] token variant.", Span::call_site());
211 None
212 }
213 };
214
215 let generics = parser.generics();
216 let this = quote!(#name #generics);
217
218 let impl_logos = |body| {
219 quote! {
220 impl<'s> ::logos::Logos<'s> for #this {
221 type Extras = #extras;
222
223 type Source = #source;
224
225 #error_def
226
227 fn lex(lex: &mut ::logos::Lexer<'s, Self>) {
228 #body
229 }
230 }
231 }
232 };
233
234 for id in regex_ids {
235 let fork = graph.fork_off(id);
236
237 root.merge(fork, &mut graph);
238 }
239 for rope in ropes {
240 root.merge(rope.into_fork(&mut graph), &mut graph);
241 }
242 while let Some(id) = root.miss.take() {
243 let fork = graph.fork_off(id);
244
245 if fork.branches().next().is_some() {
246 root.merge(fork, &mut graph);
247 } else {
248 break;
249 }
250 }
251
252 for &DisambiguationError(a, b) in graph.errors() {
253 let a = graph[a].unwrap_leaf();
254 let b = graph[b].unwrap_leaf();
255 let disambiguate = a.priority + 1;
256
257 let mut err = |a: &Leaf, b: &Leaf| {
258 parser.err(
259 format!(
260 "\
261 A definition of variant `{0}` can match the same input as another definition of variant `{1}`.\n\
262 \n\
263 hint: Consider giving one definition a higher priority: \
264 #[regex(..., priority = {2})]\
265 ",
266 a.ident,
267 b.ident,
268 disambiguate,
269 ),
270 a.span
271 );
272 };
273
274 err(a, b);
275 err(b, a);
276 }
277
278 if let Some(errors) = parser.errors.render() {
279 return impl_logos(errors).into();
280 }
281
282 let root = graph.push(root);
283
284 graph.shake(root);
285
286 let generator = Generator::new(name, &this, root, &graph);
289
290 let body = generator.generate();
291 let tokens = impl_logos(quote! {
292 use ::logos::internal::{LexerInternal, CallbackResult};
293
294 type Lexer<'s> = ::logos::Lexer<'s, #this>;
295
296 fn _end<'s>(lex: &mut Lexer<'s>) {
297 lex.end()
298 }
299
300 fn _error<'s>(lex: &mut Lexer<'s>) {
301 lex.bump_unchecked(1);
302
303 lex.error();
304 }
305
306 #body
307 });
308
309 TokenStream::from(tokens)
312}