aboutsummaryrefslogtreecommitdiff
path: root/src/makefile/macro.rs
diff options
context:
space:
mode:
authorMelody Horn <melody@boringcactus.com>2021-03-28 18:17:10 -0600
committerMelody Horn <melody@boringcactus.com>2021-03-28 18:17:10 -0600
commit98fa3e5246e83f8121922281a822a8d76f501750 (patch)
treeeeb82d9f9ca14043e19244e9603342a9430a1ab9 /src/makefile/macro.rs
parent57e4222900de52da5ffe13933fbebe91fbd7bab9 (diff)
downloadmakers-98fa3e5246e83f8121922281a822a8d76f501750.tar.gz
makers-98fa3e5246e83f8121922281a822a8d76f501750.zip
fix the unbounded type recursion (thanks @Lucretiel!)
Diffstat (limited to 'src/makefile/macro.rs')
-rw-r--r--src/makefile/macro.rs171
1 files changed, 71 insertions, 100 deletions
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<F: for<'a> 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<String, (MacroSource, TokenString)>,
+ 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<Self> {
- 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<String, (MacroSource, TokenString)>,
-}
-
-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<String, (MacroSource, TokenString)>,
-}
-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