From 98fa3e5246e83f8121922281a822a8d76f501750 Mon Sep 17 00:00:00 2001 From: Melody Horn Date: Sun, 28 Mar 2021 18:17:10 -0600 Subject: fix the unbounded type recursion (thanks @Lucretiel!) --- src/makefile/macro.rs | 171 +++++++++++++++++++++----------------------------- 1 file changed, 71 insertions(+), 100 deletions(-) (limited to 'src/makefile/macro.rs') diff --git a/src/makefile/macro.rs b/src/makefile/macro.rs index 27cbc14..79df339 100644 --- a/src/makefile/macro.rs +++ b/src/makefile/macro.rs @@ -19,11 +19,67 @@ pub(crate) trait LookupInternal: for<'a> Fn(&'a str) -> String {} impl Fn(&'a str) -> String> LookupInternal for F {} -pub(crate) trait MacroSetLike: Sized { - fn lookup_internal(&self, name: &str) -> String; - fn get(&self, name: &str) -> Option<&(MacroSource, TokenString)>; +#[derive(Clone)] +pub(crate) struct MacroSet<'parent, 'lookup> { + parent: Option<&'parent MacroSet<'parent, 'lookup>>, + data: HashMap, + lookup_internal: Option<&'lookup dyn LookupInternal>, +} + +impl<'parent, 'lookup> MacroSet<'parent, 'lookup> { + pub(crate) fn new() -> Self { + Self { + parent: None, + data: HashMap::new(), + lookup_internal: None, + } + } + + pub(crate) fn add_builtins(&mut self) { + for (k, v) in builtins() { + self.data.insert(k.into(), (MacroSource::Builtin, v)); + } + } + + pub(crate) fn add_env(&mut self) { + for (k, v) in env::vars() { + if k != "MAKEFLAGS" && k != "SHELL" { + self.data + .insert(k, (MacroSource::Environment, TokenString::text(v))); + } + } + } + + fn lookup_internal(&self, name: &str) -> String { + if let Some(lookup) = self.lookup_internal { + lookup(name) + } else if let Some(parent) = self.parent { + parent.lookup_internal(name) + } else { + panic!("no lookup possible"); + } + } + + pub(crate) fn get(&self, name: &str) -> Option<&(MacroSource, TokenString)> { + self.data + .get(name) + .or_else(|| self.parent.and_then(|parent| parent.get(name))) + } + + pub(crate) fn set(&mut self, name: String, source: MacroSource, text: TokenString) { + self.data.insert(name, (source, text)); + } + + pub(crate) fn is_defined(&self, name: &str) -> bool { + self.data.contains_key(name) + } + + // `remove` is fine, but I think for "remove-and-return" `pop` is better + pub(crate) fn pop(&mut self, name: &str) -> Option<(MacroSource, TokenString)> { + self.data.remove(name) + } - fn expand(&self, text: &TokenString) -> String { + pub(crate) fn expand(&self, text: &TokenString) -> String { let mut result = String::new(); for token in text.tokens() { match token { @@ -62,112 +118,27 @@ pub(crate) trait MacroSetLike: Sized { result } - fn with_lookup<'a, 's: 'a>( + pub(crate) fn with_lookup<'l, 's: 'l>( &'s self, - lookup: &'a dyn LookupInternal, - ) -> MacroSetLikeWithLookup<'a, Self> { - MacroSetLikeWithLookup { - parent: self, - lookup, - } - } - - fn with_overlay(&self) -> MacroSetLikeWithOverlay { - MacroSetLikeWithOverlay { - parent: self, + lookup: &'l dyn LookupInternal, + ) -> MacroSet<'s, 'l> { + MacroSet { + parent: Some(self), data: HashMap::new(), + lookup_internal: Some(lookup), } } -} - -pub(crate) struct MacroSetLikeWithLookup<'a, Parent: MacroSetLike> { - parent: &'a Parent, - lookup: &'a dyn LookupInternal, -} - -impl<'a, Parent: MacroSetLike> MacroSetLike for MacroSetLikeWithLookup<'a, Parent> { - fn lookup_internal(&self, name: &str) -> String { - (self.lookup)(name) - } - - fn get(&self, name: &str) -> Option<&(MacroSource, TokenString)> { - self.parent.get(name) - } -} - -pub(crate) struct MacroSetLikeWithOverlay<'a, Parent: MacroSetLike> { - parent: &'a Parent, - data: HashMap, -} - -impl<'a, Parent: MacroSetLike> MacroSetLike for MacroSetLikeWithOverlay<'a, Parent> { - fn lookup_internal(&self, name: &str) -> String { - self.parent.lookup_internal(name) - } - - fn get(&self, name: &str) -> Option<&(MacroSource, TokenString)> { - self.data.get(name).or_else(|| self.parent.get(name)) - } -} - -impl<'a, Parent: MacroSetLike> MacroSetLikeWithOverlay<'a, Parent> { - pub(crate) fn set(&mut self, name: String, text: TokenString) { - self.data.insert(name, (MacroSource::File, text)); - } -} - -#[derive(Clone, Debug)] -pub(crate) struct MacroSet { - data: HashMap, -} -impl MacroSetLike for MacroSet { - fn lookup_internal(&self, _: &str) -> String { - panic!("can't lookup an internal macro value from a plain MacroSet"); - } - - fn get(&self, name: &str) -> Option<&(MacroSource, TokenString)> { - self.data.get(name) - } -} - -impl MacroSet { - pub(crate) fn new() -> Self { - Self { + pub(crate) fn with_overlay<'s>(&'s self) -> MacroSet<'s, 'lookup> { + MacroSet { + parent: Some(self), data: HashMap::new(), + lookup_internal: None, } } - - pub(crate) fn add_builtins(&mut self) { - for (k, v) in builtins() { - self.data.insert(k.into(), (MacroSource::Builtin, v)); - } - } - - pub(crate) fn add_env(&mut self) { - for (k, v) in env::vars() { - if k != "MAKEFLAGS" && k != "SHELL" { - self.data - .insert(k, (MacroSource::Environment, TokenString::text(v))); - } - } - } - - pub(crate) fn set(&mut self, name: String, source: MacroSource, text: TokenString) { - self.data.insert(name, (source, text)); - } - - pub(crate) fn is_defined(&self, name: &str) -> bool { - self.data.contains_key(name) - } - - // `remove` is fine, but I think for "remove-and-return" `pop` is better - pub(crate) fn pop(&mut self, name: &str) -> Option<(MacroSource, TokenString)> { - self.data.remove(name) - } } -impl fmt::Display for MacroSet { +impl fmt::Display for MacroSet<'_, '_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let pieces = self .data -- cgit v1.2.3