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