parse_it_codegen/lexer/
frontend.rs

1use std::rc::Rc;
2
3use proc_macro2::TokenStream;
4use quote::{quote, quote_spanned};
5use syn::visit_mut::VisitMut;
6
7use crate::{
8    hash::HashMap,
9    lexer::middle::{Action, LexerImpl, Middle, Rule},
10    syntax::{Lexer, LexerMod, LexerPattern, LexerRule},
11    utils::RewriteSelfVisitor,
12};
13
14#[derive(Default)]
15struct Context {
16    pub parse_macros: Rc<Vec<syn::Path>>,
17}
18
19impl LexerMod {
20    pub fn compile(self) -> Result<Middle, TokenStream> {
21        let ctx = Context {
22            parse_macros: self.config.parse_macros.clone(),
23        };
24        let crate_name = match &self.config.crate_name {
25            Some(crate_name) => quote! { #crate_name },
26            None => quote! { ::parse_it },
27        };
28
29        let lexers = self
30            .lexers
31            .iter()
32            .map(|lexer| (lexer.name.clone(), lexer))
33            .collect::<HashMap<_, _>>();
34        let lexers = self
35            .lexers
36            .iter()
37            .map(|lexer| lexer.compile(&lexers, &ctx))
38            .collect::<Result<Vec<_>, _>>()?;
39
40        let middle = Middle {
41            attrs: self.attrs,
42            crate_name,
43            mod_name: self.mod_name,
44            items: self.items,
45            lexers,
46            debug: self.config.debug,
47        };
48        Ok(middle)
49    }
50}
51
52impl Lexer {
53    fn full_rules(
54        &self,
55        lexers: &HashMap<syn::Ident, &Lexer>,
56        stack: &mut Vec<syn::Ident>,
57        ctx: &Context,
58    ) -> Result<Vec<Rule>, TokenStream> {
59        stack.push(self.name.clone());
60        let mut rules = vec![];
61        for rule in &self.rules {
62            match &rule.pattern {
63                LexerPattern::Regex(lit_str) => {
64                    if let Err(e) = regex_syntax::parse(&lit_str.value()) {
65                        let e = format!("Invalid regex pattern: {e}");
66                        return Err(quote_spanned! { lit_str.span() => compile_error!(#e); });
67                    }
68                    rules.push(Rule {
69                        pattern: lit_str.clone(),
70                        actions: (rule.compile(self.ty.clone(), ctx), vec![]),
71                    });
72                }
73                LexerPattern::Name(ident) => {
74                    if stack.contains(ident) {
75                        let e = format!("Recursive inclusion of lexer `{ident}`");
76                        return Err(quote_spanned! { ident.span() => compile_error!(#e); });
77                    }
78                    let lexer = lexers.get(ident).ok_or_else(|| {
79                        let e = format!("Lexer `{ident}` not found");
80                        quote_spanned! { ident.span() => compile_error!(#e); }
81                    })?;
82                    if !lexer.inputs.is_empty() {
83                        let e = format!("Cannot include lexer `{ident}` in another lexer, it has inputs defined");
84                        return Err(quote_spanned! { ident.span() => compile_error!(#e); });
85                    }
86                    let action = rule.compile(self.ty.clone(), ctx);
87                    rules.extend(lexer.full_rules(lexers, stack, ctx)?.into_iter().map(
88                        |mut rule| {
89                            rule.actions.1.push(action.clone());
90                            rule
91                        },
92                    ));
93                }
94            }
95        }
96        stack.pop();
97        Ok(rules)
98    }
99
100    fn compile(
101        &self,
102        lexers: &HashMap<syn::Ident, &Lexer>,
103        ctx: &Context,
104    ) -> Result<LexerImpl, TokenStream> {
105        if self.rules.is_empty() {
106            let e = format!("Lexer `{}` has no rules defined", self.name);
107            return Err(quote_spanned! { self.name.span() => compile_error!(#e); });
108        }
109        let rules = self.full_rules(lexers, &mut vec![], ctx)?;
110        let inputs = self.inputs.iter().cloned().collect();
111        Ok(LexerImpl {
112            name: self.name.clone(),
113            rules,
114            vis: self.vis.clone(),
115            inputs,
116            ret_ty: self.ty.clone(),
117        })
118    }
119}
120
121impl LexerRule {
122    fn compile(&self, ret_ty: Option<syn::Type>, ctx: &Context) -> Action {
123        let mut action = self.action.clone();
124
125        let mut visitor = RewriteSelfVisitor::new(ctx.parse_macros.clone());
126        visitor.visit_expr_mut(&mut action);
127        let self_ident = visitor.self_ident;
128
129        Action {
130            action,
131            ret_ty,
132            self_ident,
133        }
134    }
135}