aboutsummaryrefslogtreecommitdiff
path: root/src/makefile/inference_rules.rs
diff options
context:
space:
mode:
authorMelody Horn <melody@boringcactus.com>2024-11-11 17:15:08 -0700
committerMelody Horn <melody@boringcactus.com>2024-11-11 17:15:08 -0700
commit4f9299b4639802e05e1cb27d8eb40305ff8e110e (patch)
tree0da5529c68c82e97aed67d842e50f6285e79e6c2 /src/makefile/inference_rules.rs
parentfbbcf325b8bbe72f924da6a7cdb128d973ef0026 (diff)
downloadmakers-4f9299b4639802e05e1cb27d8eb40305ff8e110e.tar.gz
makers-4f9299b4639802e05e1cb27d8eb40305ff8e110e.zip
implement rule-specific macros for targets
Diffstat (limited to 'src/makefile/inference_rules.rs')
-rw-r--r--src/makefile/inference_rules.rs97
1 files changed, 91 insertions, 6 deletions
diff --git a/src/makefile/inference_rules.rs b/src/makefile/inference_rules.rs
index 8d4f3b6..d7db1e6 100644
--- a/src/makefile/inference_rules.rs
+++ b/src/makefile/inference_rules.rs
@@ -1,18 +1,18 @@
-use std::fmt;
+use std::collections::HashMap;
+use std::{fmt, mem};
+use super::pattern::r#match;
+use super::{CommandLine, ItemSource, MacroSet};
use eyre::{eyre, OptionExt, Result};
use regex::Captures;
-use super::command_line::CommandLine;
-use super::pattern::r#match;
-use super::ItemSource;
-
-#[derive(PartialEq, Eq, Clone, Debug)]
+#[derive(Clone, Debug)]
pub struct InferenceRule {
pub source: ItemSource,
pub products: Vec<String>,
pub prerequisites: Vec<String>,
pub commands: Vec<CommandLine>,
+ pub macros: MacroSet,
}
impl InferenceRule {
@@ -22,12 +22,14 @@ impl InferenceRule {
s1: String,
s2: String,
commands: Vec<CommandLine>,
+ macros: MacroSet,
) -> Self {
Self {
source,
products: vec![format!("%{}", s1)],
prerequisites: vec![format!("%{}", s2)],
commands,
+ macros,
}
}
@@ -58,6 +60,30 @@ impl InferenceRule {
.iter()
.map(move |p| p.replace('%', percent_expansion)))
}
+
+ fn extend(&mut self, other: Self) {
+ assert_eq!(&self.products, &other.products);
+ match (self.commands.is_empty(), other.commands.is_empty()) {
+ (false, false) => {
+ // both rules have commands, so replace this entirely
+ *self = other;
+ }
+ (true, false) => {
+ // this rule doesn't have commands, but the other one does,
+ // so it's the real one
+ let mut other = other;
+ mem::swap(self, &mut other);
+ self.extend(other);
+ }
+ (false, true) | (true, true) => {
+ // this rule might have commands, but the other one doesn't,
+ // so append non-command stuff
+ // TODO decide something smart about sources
+ self.prerequisites.extend(other.prerequisites);
+ self.macros.extend(other.macros);
+ }
+ }
+ }
}
impl fmt::Display for InferenceRule {
@@ -75,6 +101,63 @@ impl fmt::Display for InferenceRule {
}
}
+#[derive(Clone, Default)]
+pub struct InferenceRuleSet {
+ /// Maps from products to a map from prerequisites to rules.
+ data: HashMap<Vec<String>, HashMap<Vec<String>, InferenceRule>>,
+}
+
+impl InferenceRuleSet {
+ pub fn get(&self, products: &[String], prerequisites: &[String]) -> Option<&InferenceRule> {
+ self.data.get(products).and_then(|x| x.get(prerequisites))
+ }
+
+ fn get_mut(
+ &mut self,
+ products: &[String],
+ prerequisites: &[String],
+ ) -> Option<&mut InferenceRule> {
+ self.data
+ .get_mut(products)
+ .and_then(|x| x.get_mut(prerequisites))
+ }
+
+ pub fn put(&mut self, rule: InferenceRule) {
+ if let Some(existing_rule) = self.get_mut(&rule.products, &rule.prerequisites) {
+ existing_rule.extend(rule);
+ } else {
+ self.data
+ .entry(rule.products.clone())
+ .or_default()
+ .insert(rule.prerequisites.clone(), rule);
+ }
+ }
+
+ pub fn len(&self) -> usize {
+ self.data.len()
+ }
+
+ pub fn extend(&mut self, other: Self) {
+ for other in other.data.into_values().flat_map(HashMap::into_values) {
+ self.put(other);
+ }
+ }
+
+ pub fn iter(&self) -> impl Iterator<Item = &InferenceRule> {
+ self.data.values().flat_map(HashMap::values)
+ }
+}
+
+impl From<Vec<InferenceRule>> for InferenceRuleSet {
+ fn from(value: Vec<InferenceRule>) -> Self {
+ let mut result = Self::default();
+ for rule in value {
+ result.put(rule);
+ }
+ result
+ }
+}
+
#[cfg(test)]
mod test {
use super::*;
@@ -88,6 +171,7 @@ mod test {
".o".to_owned(),
".c".to_owned(),
vec![],
+ MacroSet::new(),
);
assert!(rule.matches("foo.o")?);
assert!(rule.matches("dir/foo.o")?);
@@ -107,6 +191,7 @@ mod test {
"goneall.gpg".to_owned(),
],
commands: vec![],
+ macros: MacroSet::new(),
};
assert!(rule.matches("licenseListPublisher-2.2.1.jar-valid")?);
Ok(())