summaryrefslogtreecommitdiff
path: root/src/bindings.rs
diff options
context:
space:
mode:
authorDaniel Silverstone <dsilvers@digital-scurf.org>2020-12-15 14:18:32 +0000
committerDaniel Silverstone <dsilvers@digital-scurf.org>2020-12-18 17:50:19 +0000
commit1deb0e5227a7ff2bde1f0e218e44adc8ef43af4b (patch)
tree210d1daa9c558600b7ad87d804c656121a1f9fe9 /src/bindings.rs
parent4045e0164afd47a383d8a3177091887848be434f (diff)
downloadsubplot-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.rs29
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);