aboutsummaryrefslogtreecommitdiff
path: root/src/makefile/macro.rs
diff options
context:
space:
mode:
authorMelody Horn <melody@boringcactus.com>2021-04-06 14:11:43 -0600
committerMelody Horn <melody@boringcactus.com>2021-04-06 14:11:43 -0600
commit5a101a96ada9ddbd4be54c46cd7d0125825c2283 (patch)
treedd5b54a8b0917d53e17e9fbd31b7280669bcc0ec /src/makefile/macro.rs
parent1602ad07efa6d3c4170928537843a0d61a5cd5e7 (diff)
downloadmakers-5a101a96ada9ddbd4be54c46cd7d0125825c2283.tar.gz
makers-5a101a96ada9ddbd4be54c46cd7d0125825c2283.zip
eagerly expand when appending to eagerly-expanded macros
Diffstat (limited to 'src/makefile/macro.rs')
-rw-r--r--src/makefile/macro.rs80
1 files changed, 61 insertions, 19 deletions
diff --git a/src/makefile/macro.rs b/src/makefile/macro.rs
index a6dcb74..1c8bd01 100644
--- a/src/makefile/macro.rs
+++ b/src/makefile/macro.rs
@@ -21,6 +21,14 @@ pub enum Source {
Builtin,
}
+#[derive(Debug, Clone)]
+pub struct Macro {
+ pub source: Source,
+ pub text: TokenString,
+ #[cfg(feature = "full")]
+ pub eagerly_expanded: bool,
+}
+
pub trait LookupInternal: for<'a> Fn(&'a str) -> Result<String> {}
impl<F: for<'a> Fn(&'a str) -> Result<String>> LookupInternal for F {}
@@ -28,7 +36,7 @@ impl<F: for<'a> Fn(&'a str) -> Result<String>> LookupInternal for F {}
#[derive(Clone)]
pub struct Set<'parent, 'lookup> {
parent: Option<&'parent Set<'parent, 'lookup>>,
- pub data: HashMap<String, (Source, TokenString)>,
+ pub data: HashMap<String, Macro>,
lookup_internal: Option<&'lookup dyn LookupInternal>,
#[cfg(feature = "full")]
pub to_eval: Rc<RefCell<Vec<String>>>,
@@ -47,15 +55,30 @@ impl<'parent, 'lookup> Set<'parent, 'lookup> {
pub fn add_builtins(&mut self) {
for (k, v) in builtins() {
- self.data.insert(k.into(), (Source::Builtin, v));
+ self.data.insert(
+ k.into(),
+ Macro {
+ source: Source::Builtin,
+ text: v,
+ #[cfg(feature = "full")]
+ eagerly_expanded: false,
+ },
+ );
}
}
pub fn add_env(&mut self) {
for (k, v) in env::vars() {
if k != "MAKEFLAGS" && k != "SHELL" {
- self.data
- .insert(k, (Source::Environment, TokenString::text(v)));
+ self.data.insert(
+ k,
+ Macro {
+ source: Source::Environment,
+ text: TokenString::text(v),
+ #[cfg(feature = "full")]
+ eagerly_expanded: false,
+ },
+ );
}
}
}
@@ -73,27 +96,30 @@ impl<'parent, 'lookup> Set<'parent, 'lookup> {
}
}
- pub fn get(&self, name: &str) -> Option<&(Source, TokenString)> {
+ pub fn get(&self, name: &str) -> Option<&Macro> {
self.data
.get(name)
.or_else(|| self.parent.and_then(|parent| parent.get(name)))
}
- pub fn set(&mut self, name: String, source: Source, text: TokenString) {
- self.data.insert(name, (source, text));
+ pub fn set(&mut self, name: String, r#macro: Macro) {
+ self.data.insert(name, r#macro);
}
#[cfg(feature = "full")]
pub fn is_defined(&self, name: &str) -> bool {
- self.data.get(name).map_or(false, |(_, x)| !x.is_empty())
+ self.data.get(name).map_or(false, |x| !x.text.is_empty())
}
// `remove` is fine, but I think for "remove-and-return" `pop` is better
- pub fn pop(&mut self, name: &str) -> Option<(Source, TokenString)> {
- self.data.remove(name)
+ pub fn pop(&mut self, name: &str) -> Option<Macro> {
+ // TODO figure out a better way to handle inheritance
+ self.data
+ .remove(name)
+ .or_else(|| self.parent.and_then(|p| p.get(name).cloned()))
}
- pub fn extend(&mut self, other: HashMap<String, (Source, TokenString)>) {
+ pub fn extend(&mut self, other: HashMap<String, Macro>) {
self.data.extend(other);
}
@@ -118,7 +144,7 @@ impl<'parent, 'lookup> Set<'parent, 'lookup> {
log::warn!("undefined macro {}", name);
Ok(String::new())
},
- |(_, macro_value)| self.expand(macro_value),
+ |x| self.expand(&x.text),
)?
};
let macro_value = match replacement {
@@ -155,11 +181,23 @@ impl<'parent, 'lookup> Set<'parent, 'lookup> {
pub fn origin(&self, name: &str) -> &'static str {
match self.data.get(name) {
None => self.parent.map_or("undefined", |p| p.origin(name)),
- Some((Source::Builtin, _)) => "default",
- Some((Source::Environment, _)) => "environment",
+ Some(Macro {
+ source: Source::Builtin,
+ ..
+ }) => "default",
+ Some(Macro {
+ source: Source::Environment,
+ ..
+ }) => "environment",
// TODO figure out when to return "environment override"
- Some((Source::File, _)) => "file",
- Some((Source::CommandLineOrMakeflags, _)) => "command line",
+ Some(Macro {
+ source: Source::File,
+ ..
+ }) => "file",
+ Some(Macro {
+ source: Source::CommandLineOrMakeflags,
+ ..
+ }) => "command line",
// TODO handle override and automatic
}
}
@@ -190,7 +228,7 @@ impl fmt::Display for Set<'_, '_> {
let pieces = self
.data
.iter()
- .map(|(k, (_, v))| format!("{}={}", k, v))
+ .map(|(k, x)| format!("{}={}", k, &x.text))
.collect::<Vec<_>>();
write!(f, "{}", pieces.join("\n"))
}
@@ -259,8 +297,12 @@ mod test {
let mut macros = Set::new();
macros.set(
"oof".to_owned(),
- Source::File,
- TokenString::text("bruh; swag; yeet;"),
+ Macro {
+ source: Source::File,
+ text: TokenString::text("bruh; swag; yeet;"),
+ #[cfg(feature = "full")]
+ eagerly_expanded: false,
+ },
);
assert_eq!(
macros.expand(&"$(oof:;=?)".parse().unwrap())?,