use lexer::re;
use grammar::parse_tree::InternToken;
use grammar::repr::{Grammar, TerminalLiteral};
use rust::RustWrite;
use std::io::{self, Write};
pub fn compile<W: Write>(
grammar: &Grammar,
intern_token: &InternToken,
out: &mut RustWrite<W>,
) -> io::Result<()> {
let prefix = &grammar.prefix;
rust!(out, "#[cfg_attr(rustfmt, rustfmt_skip)]");
rust!(out, "mod {}intern_token {{", prefix);
rust!(out, "#![allow(unused_imports)]");
try!(out.write_uses("", &grammar));
rust!(out, "extern crate regex as {}regex;", prefix);
rust!(out, "use std::fmt as {}fmt;", prefix);
rust!(out, "");
rust!(
out,
"#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]"
);
rust!(out, "pub struct Token<'input>(pub usize, pub &'input str);");
rust!(out, "impl<'a> {}fmt::Display for Token<'a> {{", prefix);
rust!(
out,
"fn fmt(&self, formatter: &mut {}fmt::Formatter) -> Result<(), {}fmt::Error> {{",
prefix,
prefix
);
rust!(out, "{}fmt::Display::fmt(self.1, formatter)", prefix);
rust!(out, "}}");
rust!(out, "}}");
rust!(out, "");
rust!(out, "pub struct {}MatcherBuilder {{", prefix);
rust!(out, "regex_set: {}regex::RegexSet,", prefix);
rust!(out, "regex_vec: Vec<{}regex::Regex>,", prefix);
rust!(out, "}}");
rust!(out, "");
rust!(out, "impl {}MatcherBuilder {{", prefix);
rust!(out, "pub fn new() -> {}MatcherBuilder {{", prefix);
let regex_strings: Vec<String> = {
intern_token
.match_entries
.iter()
.map(|match_entry| match match_entry.match_literal {
TerminalLiteral::Quoted(ref s) => re::parse_literal(&s),
TerminalLiteral::Regex(ref s) => re::parse_regex(&s).unwrap(),
})
.map(|regex| {
format!("^({})", regex)
})
.map(|regex_str| {
format!("{:?}", regex_str)
})
.collect()
};
rust!(out, "let {}strs: &[&str] = &[", prefix);
for literal in ®ex_strings {
rust!(out, "{},", literal);
}
rust!(out, "];");
rust!(
out,
"let {}regex_set = {}regex::RegexSet::new({}strs).unwrap();",
prefix,
prefix,
prefix
);
rust!(out, "let {}regex_vec = vec![", prefix);
for literal in ®ex_strings {
rust!(out, "{}regex::Regex::new({}).unwrap(),", prefix, literal);
}
rust!(out, "];");
rust!(
out,
"{0}MatcherBuilder {{ regex_set: {0}regex_set, regex_vec: {0}regex_vec }}",
prefix
);
rust!(out, "}}"); rust!(
out,
"pub fn matcher<'input, 'builder>(&'builder self, s: &'input str) \
-> {}Matcher<'input, 'builder> {{",
prefix
);
rust!(out, "{}Matcher {{", prefix);
rust!(out, "text: s,");
rust!(out, "consumed: 0,");
rust!(out, "regex_set: &self.regex_set,");
rust!(out, "regex_vec: &self.regex_vec,");
rust!(out, "}}"); rust!(out, "}}"); rust!(out, "}}"); rust!(out, "");
rust!(out, "pub struct {}Matcher<'input, 'builder> {{", prefix);
rust!(out, "text: &'input str,"); rust!(out, "consumed: usize,"); rust!(out, "regex_set: &'builder {}regex::RegexSet,", prefix);
rust!(out, "regex_vec: &'builder Vec<{}regex::Regex>,", prefix);
rust!(out, "}}");
rust!(out, "");
rust!(
out,
"impl<'input, 'builder> Iterator for {}Matcher<'input, 'builder> {{",
prefix
);
rust!(
out,
"type Item = Result<(usize, Token<'input>, usize), \
{}lalrpop_util::ParseError<usize,Token<'input>,{}>>;",
prefix,
grammar.types.error_type()
);
rust!(out, "");
rust!(out, "fn next(&mut self) -> Option<Self::Item> {{");
rust!(out, "let {}text = self.text.trim_left();", prefix);
rust!(
out,
"let {}whitespace = self.text.len() - {}text.len();",
prefix,
prefix
);
rust!(
out,
"let {}start_offset = self.consumed + {}whitespace;",
prefix,
prefix
);
rust!(out, "if {}text.is_empty() {{", prefix);
rust!(out, "self.text = {}text;", prefix);
rust!(out, "self.consumed = {}start_offset;", prefix);
rust!(out, "None");
rust!(out, "}} else {{");
rust!(
out,
"let {}matches = self.regex_set.matches({}text);",
prefix,
prefix
);
rust!(out, "if !{}matches.matched_any() {{", prefix);
rust!(
out,
"Some(Err({}lalrpop_util::ParseError::InvalidToken {{",
prefix
);
rust!(out, "location: {}start_offset,", prefix);
rust!(out, "}}))");
rust!(out, "}} else {{");
rust!(out, "let mut {}longest_match = 0;", prefix); rust!(out, "let mut {}index = 0;", prefix); rust!(
out,
"for {}i in 0 .. {} {{",
prefix,
intern_token.match_entries.len()
);
rust!(out, "if {}matches.matched({}i) {{", prefix, prefix);
rust!(
out,
"let {}match = self.regex_vec[{}i].find({}text).unwrap();",
prefix,
prefix,
prefix
);
rust!(out, "let {}len = {}match.end();", prefix, prefix);
rust!(out, "if {}len >= {}longest_match {{", prefix, prefix);
rust!(out, "{}longest_match = {}len;", prefix, prefix);
rust!(out, "{}index = {}i;", prefix, prefix);
rust!(out, "}}"); rust!(out, "}}"); rust!(out, "}}");
rust!(
out,
"let {}result = &{}text[..{}longest_match];",
prefix,
prefix,
prefix
);
rust!(
out,
"let {}remaining = &{}text[{}longest_match..];",
prefix,
prefix,
prefix
);
rust!(
out,
"let {}end_offset = {}start_offset + {}longest_match;",
prefix,
prefix,
prefix
);
rust!(out, "self.text = {}remaining;", prefix);
rust!(out, "self.consumed = {}end_offset;", prefix);
rust!(
out,
"Some(Ok(({}start_offset, Token({}index, {}result), {}end_offset)))",
prefix,
prefix,
prefix,
prefix
);
rust!(out, "}}"); rust!(out, "}}"); rust!(out, "}}"); rust!(out, "}}"); rust!(out, "}}"); Ok(())
}