aboutsummaryrefslogtreecommitdiff
path: root/src/makefile/macro.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/makefile/macro.rs')
-rw-r--r--src/makefile/macro.rs173
1 files changed, 106 insertions, 67 deletions
diff --git a/src/makefile/macro.rs b/src/makefile/macro.rs
index 139903f..27cbc14 100644
--- a/src/makefile/macro.rs
+++ b/src/makefile/macro.rs
@@ -1,8 +1,6 @@
-use std::cell::RefCell;
use std::collections::HashMap;
use std::env;
use std::fmt;
-use std::rc::{Rc, Weak};
use regex::Regex;
@@ -21,29 +19,125 @@ pub(crate) trait LookupInternal: for<'a> Fn(&'a str) -> String {}
impl<F: for<'a> Fn(&'a str) -> String> LookupInternal for F {}
-fn lookup_fail(_: &str) -> String {
- panic!("internal variables not available!");
+pub(crate) trait MacroSetLike: Sized {
+ fn lookup_internal(&self, name: &str) -> String;
+ fn get(&self, name: &str) -> Option<&(MacroSource, TokenString)>;
+
+ fn expand(&self, text: &TokenString) -> String {
+ let mut result = String::new();
+ for token in text.tokens() {
+ match token {
+ Token::Text(t) => result.push_str(t),
+ Token::MacroExpansion { name, replacement } => {
+ let internal_macro_names = &['@', '?', '<', '*'][..];
+ let internal_macro_suffices = &['D', 'F'][..];
+ let just_internal = name.len() == 1 && name.starts_with(internal_macro_names);
+ let suffixed_internal = name.len() == 2
+ && name.starts_with(internal_macro_names)
+ && name.ends_with(internal_macro_suffices);
+ let macro_value = if just_internal || suffixed_internal {
+ self.lookup_internal(name)
+ } else {
+ self.get(name)
+ .map_or_else(String::new, |(_, macro_value)| self.expand(macro_value))
+ };
+ let macro_value = match replacement {
+ Some((subst1, subst2)) => {
+ let subst1 = self.expand(subst1);
+ let subst1_suffix = regex::escape(&subst1);
+ let subst1_suffix =
+ Regex::new(&format!(r"{}\b", subst1_suffix)).unwrap();
+ let subst2 = self.expand(subst2);
+ subst1_suffix.replace_all(&macro_value, subst2).to_string()
+ }
+ None => macro_value,
+ };
+ result.push_str(&macro_value);
+ }
+ Token::FunctionCall { name, args } => {
+ result.push_str(&functions::expand_call(name, args, self));
+ }
+ }
+ }
+ result
+ }
+
+ fn with_lookup<'a, 's: 'a>(
+ &'s self,
+ lookup: &'a dyn LookupInternal,
+ ) -> MacroSetLikeWithLookup<'a, Self> {
+ MacroSetLikeWithLookup {
+ parent: self,
+ lookup,
+ }
+ }
+
+ fn with_overlay(&self) -> MacroSetLikeWithOverlay<Self> {
+ MacroSetLikeWithOverlay {
+ parent: self,
+ data: HashMap::new(),
+ }
+ }
+}
+
+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))
+ }
}
-#[derive(Clone)]
+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)>,
- lookup_internal: RefCell<Weak<dyn LookupInternal>>,
+}
+
+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 {
- let lookup_fail: Rc<dyn LookupInternal> = Rc::new(lookup_fail);
Self {
data: HashMap::new(),
- lookup_internal: RefCell::new(Rc::downgrade(&lookup_fail)),
}
}
- pub(crate) fn lookup(&self, lookup: Weak<dyn LookupInternal>) {
- self.lookup_internal.replace(lookup);
- }
-
pub(crate) fn add_builtins(&mut self) {
for (k, v) in builtins() {
self.data.insert(k.into(), (MacroSource::Builtin, v));
@@ -67,65 +161,10 @@ impl MacroSet {
self.data.contains_key(name)
}
- pub(crate) fn get(&self, name: &str) -> Option<&(MacroSource, TokenString)> {
- self.data.get(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)
}
-
- pub(crate) fn expand(&self, text: &TokenString) -> String {
- let mut result = String::new();
- for token in text.tokens() {
- match token {
- Token::Text(t) => result.push_str(t),
- Token::MacroExpansion { name, replacement } => {
- let internal_macro_names = &['@', '?', '<', '*'][..];
- let internal_macro_suffices = &['D', 'F'][..];
- let just_internal = name.len() == 1 && name.starts_with(internal_macro_names);
- let suffixed_internal = name.len() == 2
- && name.starts_with(internal_macro_names)
- && name.ends_with(internal_macro_suffices);
- let macro_value = if just_internal || suffixed_internal {
- let lookup_internal = self.lookup_internal.borrow();
- let lookup_internal = match lookup_internal.upgrade() {
- Some(f) => f,
- None => Rc::new(lookup_fail),
- };
- lookup_internal(name)
- } else {
- self.data
- .get(name)
- .map_or_else(String::new, |(_, macro_value)| self.expand(macro_value))
- };
- let macro_value = match replacement {
- Some((subst1, subst2)) => {
- let subst1 = self.expand(subst1);
- let subst1_suffix = regex::escape(&subst1);
- let subst1_suffix =
- Regex::new(&format!(r"{}\b", subst1_suffix)).unwrap();
- let subst2 = self.expand(subst2);
- subst1_suffix.replace_all(&macro_value, subst2).to_string()
- }
- None => macro_value,
- };
- result.push_str(&macro_value);
- }
- Token::FunctionCall { name, args } => {
- result.push_str(&functions::call(name, args, &self));
- }
- }
- }
- result
- }
-}
-
-impl fmt::Debug for MacroSet {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{:?}", &self.data)
- }
}
impl fmt::Display for MacroSet {