diff options
author | Daniel Silverstone <dsilvers@digital-scurf.org> | 2020-12-15 14:18:32 +0000 |
---|---|---|
committer | Daniel Silverstone <dsilvers@digital-scurf.org> | 2020-12-18 17:50:19 +0000 |
commit | 1deb0e5227a7ff2bde1f0e218e44adc8ef43af4b (patch) | |
tree | 210d1daa9c558600b7ad87d804c656121a1f9fe9 /src/bindings.rs | |
parent | 4045e0164afd47a383d8a3177091887848be434f (diff) | |
download | subplot-1deb0e5227a7ff2bde1f0e218e44adc8ef43af4b.tar.gz |
bindings: Add check that captured text matches the kind patterns
Signed-off-by: Daniel Silverstone <dsilvers@digital-scurf.org>
Diffstat (limited to 'src/bindings.rs')
-rw-r--r-- | src/bindings.rs | 29 |
1 files changed, 27 insertions, 2 deletions
diff --git a/src/bindings.rs b/src/bindings.rs index c43a986..e0476c3 100644 --- a/src/bindings.rs +++ b/src/bindings.rs @@ -8,6 +8,7 @@ use serde::Deserialize; use serde_aux::prelude::*; use std::collections::HashMap; +use std::convert::identity; use std::fs::File; use std::io::Read; use std::path::Path; @@ -38,11 +39,21 @@ impl Binding { function: &str, cleanup: Option<&str>, case_sensitive: bool, - types: HashMap<String, String>, + mut types: HashMap<String, String>, ) -> Result<Binding> { let regex = RegexBuilder::new(&format!("^{}$", pattern)) .case_insensitive(!case_sensitive) .build()?; + // For every named capture, ensure we have a known type for it. + // If the type is missing from the map, we default to `text` which is + // the .* pattern + for capture in regex.capture_names().filter_map(identity) { + let tyname = &*types.entry(capture.into()).or_insert_with(|| "text".into()); + if !KIND_PATTERNS.contains_key(tyname.as_str()) { + return Err(SubplotError::UnknownTypeInBinding(tyname.clone())); + } + } + Ok(Binding { kind, pattern: pattern.to_owned(), @@ -124,7 +135,21 @@ impl Binding { let part = match capname { None => PartialStep::uncaptured(&step_text[prev_end..cap.start()]), - Some(name) => PartialStep::text(name, cap.as_str()), + Some(name) => { + // Before continuing, verify that the capture matches the + // pattern for this capture + let cap = cap.as_str(); + // These unwraps are safe because we ensured the map is complete + // in the constructor, and that all the types are known. + let tyname = self.types.get(name).unwrap(); + let rx = &KIND_PATTERNS.get(tyname.as_str()).unwrap().1; + if !rx.is_match(cap) { + // This capture doesn't match the kind so it's not + // valid for this binding. + return None; + } + PartialStep::text(name, cap) + } }; m.append_part(part); |