1 //! Generates an iterator type `Matcher` that looks roughly like
2 
3 use crate::grammar::parse_tree::{InternToken, MatchMapping};
4 use crate::grammar::repr::{Grammar, TerminalLiteral};
5 use crate::lexer::re;
6 use crate::rust::RustWrite;
7 use std::io::{self, Write};
8 
compile<W: Write>( grammar: &Grammar, intern_token: &InternToken, out: &mut RustWrite<W>, ) -> io::Result<()>9 pub fn compile<W: Write>(
10     grammar: &Grammar,
11     intern_token: &InternToken,
12     out: &mut RustWrite<W>,
13 ) -> io::Result<()> {
14     let prefix = &grammar.prefix;
15 
16     rust!(out, "#[cfg_attr(rustfmt, rustfmt_skip)]");
17     rust!(out, "mod {}intern_token {{", prefix);
18     rust!(out, "#![allow(unused_imports)]");
19     out.write_uses("super::", &grammar)?;
20     rust!(
21         out,
22         "pub fn new_builder() -> {}lalrpop_util::lexer::MatcherBuilder {{",
23         prefix
24     );
25 
26     // create a vector of rust string literals with the text of each
27     // regular expression
28     let regex_strings = intern_token
29         .match_entries
30         .iter()
31         .map(|match_entry| {
32             (
33                 match match_entry.match_literal {
34                     TerminalLiteral::Quoted(ref s) => re::parse_literal(&s),
35                     TerminalLiteral::Regex(ref s) => re::parse_regex(&s).unwrap(),
36                 },
37                 match match_entry.user_name {
38                     MatchMapping::Terminal(_) => false,
39                     MatchMapping::Skip => true,
40                 },
41             )
42         })
43         .map(|(regex, skip)| {
44             // make sure all regex are anchored at the beginning of the input
45             (format!("^({})", regex), skip)
46         })
47         .map(|(regex_str, skip)| {
48             // create a rust string with text of the regex; the Debug impl
49             // will add quotes and escape
50             (format!("{:?}", regex_str), skip)
51         });
52 
53     let mut contains_skip = false;
54 
55     rust!(out, "let {}strs: &[(&str, bool)] = &[", prefix);
56     for (literal, skip) in regex_strings {
57         rust!(out, "({}, {}),", literal, skip);
58         contains_skip |= skip;
59     }
60 
61     if !contains_skip {
62         rust!(out, r#"(r"^(\s*)", true),"#);
63     }
64 
65     rust!(out, "];");
66 
67     rust!(
68         out,
69         "{p}lalrpop_util::lexer::MatcherBuilder::new({p}strs.iter().copied()).unwrap()",
70         p = prefix
71     );
72 
73     rust!(out, "}}"); // fn
74     rust!(out, "}}"); // mod
75     Ok(())
76 }
77