From f73d0b2256f2afc05995929c930b2eeab6800ecf Mon Sep 17 00:00:00 2001 From: Melody Horn Date: Sat, 3 Apr 2021 18:01:04 -0600 Subject: implement GNUish '%'-based inference rules --- src/makefile/inference_rules.rs | 55 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 6 deletions(-) (limited to 'src/makefile/inference_rules.rs') diff --git a/src/makefile/inference_rules.rs b/src/makefile/inference_rules.rs index 3d18730..dfbb07c 100644 --- a/src/makefile/inference_rules.rs +++ b/src/makefile/inference_rules.rs @@ -1,19 +1,62 @@ use std::fmt; -use crate::makefile::command_line::CommandLine; +use eyre::{eyre, Result}; +use regex::Captures; + +use super::command_line::CommandLine; +use super::pattern::r#match; #[derive(PartialEq, Eq, Clone, Debug)] pub struct InferenceRule { - /// POSIX calls this ".s1" but that's not useful. - pub product: String, - /// POSIX calls this ".s2" but that's not useful. - pub prereq: String, + pub products: Vec, + pub prerequisites: Vec, pub commands: Vec, } +impl InferenceRule { + /// s1 is the product, s2 is the prereq + pub fn new_suffix(s1: String, s2: String, commands: Vec) -> Self { + Self { + products: vec![format!("%.{}", s1)], + prerequisites: vec![format!("%.{}", s2)], + commands, + } + } + + fn first_match<'s, 't: 's>(&'s self, target_name: &'t str) -> Result>> { + self.products + .iter() + .map(|pattern| r#match(pattern, target_name)) + .try_fold(None, |x, y| y.map(|y| x.or(y))) + } + + pub fn matches(&self, target_name: &str) -> Result { + self.first_match(target_name).map(|x| x.is_some()) + } + + pub fn prereqs<'s>( + &'s self, + target_name: &'s str, + ) -> Result + 's> { + let capture = self + .first_match(target_name)? + .ok_or_else(|| eyre!("asked non-matching inference rule for prerequisites"))?; + let percent_expansion = capture.get(1).expect("should've matched the %").as_str(); + Ok(self + .prerequisites + .iter() + .map(move |p| p.replace('%', percent_expansion))) + } +} + impl fmt::Display for InferenceRule { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - writeln!(f, "{}{}:", &self.prereq, &self.product)?; + writeln!( + f, + "{}: {}", + self.products.join(" "), + self.prerequisites.join(" ") + )?; for command in &self.commands { writeln!(f, "\t{}", command)?; } -- cgit v1.2.3