changeset 43:0a19bc59e7d6

[intermediate] parse: Implement specific repetitions
author Lewin Bormann <lbo@spheniscida.de>
date Fri, 24 Nov 2017 18:30:31 +0000
parents 8932c5b37a89
children 11af4959e69a
files src/parse.rs
diffstat 1 files changed, 49 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/src/parse.rs	Wed Nov 08 19:17:19 2017 +0100
+++ b/src/parse.rs	Fri Nov 24 18:30:31 2017 +0000
@@ -4,7 +4,9 @@
 
 #![allow(dead_code)]
 
+use std::iter::FromIterator;
 use std::ops::{Index, Range, RangeFull};
+use std::str::FromStr;
 
 use repr::{AnchorLocation, Pattern, Repetition};
 
@@ -152,9 +154,15 @@
                 }
                 s = s.from(1);
             }
-            '+' => {
+            r @ '+' | r @ '*' | r @ '?' => {
                 if let Some(p) = stack.pop() {
-                    stack.push(Pattern::Repeated(Box::new(Repetition::OnceOrMore(p))));
+                    let rep = match r {
+                        '+' => Repetition::OnceOrMore(p),
+                        '*' => Repetition::ZeroOrMore(p),
+                        '?' => Repetition::ZeroOrOnce(p),
+                        _ => unimplemented!(),
+                    };
+                    stack.push(Pattern::Repeated(Box::new(rep)));
                     s = s.from(1);
                 } else {
                     return s.err("+ without pattern to repeat", 0);
@@ -194,6 +202,20 @@
                 }
             }
             ']' => return s.err("unopened ']'", 0),
+            '{' => {
+                match split_in_parens(s.clone(), CURLY_BRACKETS) {
+                    Some((rep, newst)) => {
+                        if let Some(p) = stack.pop() {
+                            let rep = parse_specific_repetition(rep, p)?;
+
+                            s = newst;
+                        } else {
+                            return s.err("repetition {} without pattern to repeat", 0);
+                        }
+                    }
+                    None => return s.err("unmatched {", s.len()),
+                };
+            }
             _ => {
                 return s.err("unimplemented pattern", 0);
             }
@@ -243,6 +265,31 @@
     }
 }
 
+// Parse a repetition spec inside curly braces: {1} | {1,} | {,1} | {1,2}
+fn parse_specific_repetition<'a>(rep: ParseState<'a>, p: Pattern) -> Result<Repetition, String> {
+    let mut nparts = 0;
+    let mut parts: [Option<&[char]>; 2] = Default::default();
+
+    for p in rep[..].split(|c| *c == ',') {
+        parts[nparts] = Some(p);
+        nparts += 1;
+        if nparts == 2 {
+            break;
+        }
+    }
+
+    if nparts == 1 {
+        // {1}
+        if let Ok(n) = u32::from_str(&String::from_iter(parts[0].unwrap().iter())) {
+            return Ok(Repetition::Specific(p, n, None));
+        } else {
+            return Err(format!("invalid repetition '{}'", String::from_iter(rep[..].iter())));
+        }
+    }
+
+    Err(String::from("abc"))
+}
+
 const ROUND_PARENS: (char, char) = ('(', ')');
 const SQUARE_BRACKETS: (char, char) = ('[', ']');
 const CURLY_BRACKETS: (char, char) = ('{', '}');