3 // the template is parsed using a state machine
7 // the u32 keeps track of brace nesting
13 use self::ParsingState::*;
15 pub struct TemplateParser {
26 parsed: "^".to_owned(),
27 buffer: String::new(),
30 // keeps track of last line on which a regex placeholder was started
35 /// Convert a license template into a string which can be turned into a regex.
37 /// The license template could use regex syntax directly, but that would require a lot of manual
38 /// escaping, which is inconvenient. It is therefore literal by default, with optional regex
39 /// subparts delimited by `{` and `}`. Additionally:
41 /// - to insert literal `{`, `}` or `\`, escape it with `\`
42 /// - an empty regex placeholder (`{}`) is shorthand for `{.*?}`
44 /// This function parses this input format and builds a properly escaped *string* representation
45 /// of the equivalent regular expression. It **does not** however guarantee that the returned
46 /// string is a syntactically valid regular expression.
51 /// # use rustfmt_config::license::TemplateParser;
53 /// TemplateParser::parse(
55 /// // Copyright {\d+} The \} Rust \\ Project \{ Developers. See the {([A-Z]+)}
56 /// // file at the top-level directory of this distribution and at
59 /// // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
60 /// // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
61 /// // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
62 /// // option. This file may not be copied, modified, or distributed
63 /// // except according to those terms.
67 /// // Copyright \d+ The \} Rust \\ Project \{ Developers\. See the ([A-Z]+)
68 /// // file at the top\-level directory of this distribution and at
71 /// // Licensed under the Apache License, Version 2\.0 <LICENSE\-APACHE or
72 /// // http://www\.apache\.org/licenses/LICENSE\-2\.0> or the MIT license
73 /// // <LICENSE\-MIT or http://opensource\.org/licenses/MIT>, at your
74 /// // option\. This file may not be copied, modified, or distributed
75 /// // except according to those terms\.
79 pub fn parse(template: &str) -> Result<String, String> {
80 let mut parser = Self::new();
81 for chr in template.chars() {
85 parser.state = match parser.state {
86 Lit => parser.trans_from_lit(chr),
87 LitEsc => parser.trans_from_litesc(chr),
88 Re(brace_nesting) => parser.trans_from_re(chr, brace_nesting),
89 ReEsc(brace_nesting) => parser.trans_from_reesc(chr, brace_nesting),
90 Abort(msg) => return Err(msg),
93 // check if we've ended parsing in a valid state
95 Abort(msg) => return Err(msg),
98 "escape or balance opening brace on l. {}",
99 parser.open_brace_line
102 LitEsc => return Err(format!("incomplete escape sequence on l. {}", parser.linum)),
105 parser.parsed.push_str(®ex::escape(&parser.buffer));
110 fn trans_from_lit(&mut self, chr: char) -> ParsingState {
113 self.parsed.push_str(®ex::escape(&self.buffer));
115 self.open_brace_line = self.linum;
118 '}' => Abort(format!(
119 "escape or balance closing brace on l. {}",
124 self.buffer.push(chr);
130 fn trans_from_litesc(&mut self, chr: char) -> ParsingState {
131 self.buffer.push(chr);
135 fn trans_from_re(&mut self, chr: char, brace_nesting: u32) -> ParsingState {
138 self.buffer.push(chr);
139 Re(brace_nesting + 1)
142 match brace_nesting {
144 // default regex for empty placeholder {}
145 if self.buffer.is_empty() {
146 self.parsed.push_str(".*?");
148 self.parsed.push_str(&self.buffer);
154 self.buffer.push(chr);
155 Re(brace_nesting - 1)
160 self.buffer.push(chr);
164 self.buffer.push(chr);
170 fn trans_from_reesc(&mut self, chr: char, brace_nesting: u32) -> ParsingState {
171 self.buffer.push(chr);
178 use super::TemplateParser;
181 fn test_parse_license_template() {
183 TemplateParser::parse("literal (.*)").unwrap(),
187 TemplateParser::parse(r"escaping \}").unwrap(),
190 assert!(TemplateParser::parse("unbalanced } without escape").is_err());
192 TemplateParser::parse(r"{\d+} place{-?}holder{s?}").unwrap(),
193 r"^\d+ place-?holders?"
195 assert_eq!(TemplateParser::parse("default {}").unwrap(), "^default .*?");
197 TemplateParser::parse(r"unbalanced nested braces {\{{3}}").unwrap(),
198 r"^unbalanced nested braces \{{3}"
201 TemplateParser::parse("parsing error }").unwrap_err(),
202 "escape or balance closing brace on l. 1"
205 TemplateParser::parse("parsing error {\nsecond line").unwrap_err(),
206 "escape or balance opening brace on l. 1"
209 TemplateParser::parse(r"parsing error \").unwrap_err(),
210 "incomplete escape sequence on l. 1"