parse_it_codegen/lexer/
frontend.rs1use 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}