diff options
author | Melody Horn <melody@boringcactus.com> | 2021-04-06 14:11:43 -0600 |
---|---|---|
committer | Melody Horn <melody@boringcactus.com> | 2021-04-06 14:11:43 -0600 |
commit | 5a101a96ada9ddbd4be54c46cd7d0125825c2283 (patch) | |
tree | dd5b54a8b0917d53e17e9fbd31b7280669bcc0ec /src/makefile/macro.rs | |
parent | 1602ad07efa6d3c4170928537843a0d61a5cd5e7 (diff) | |
download | makers-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.rs | 80 |
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())?, |