aboutsummaryrefslogtreecommitdiff
path: root/src/makefile/macro.rs
diff options
context:
space:
mode:
authorMelody Horn <melody@boringcactus.com>2024-11-10 21:20:34 -0700
committerMelody Horn <melody@boringcactus.com>2024-11-10 21:20:34 -0700
commitfca10b517b448b4023ad8c3225e59dcefd4004e4 (patch)
tree7507e959d1f690044945dd6fcf34b5fef3385b14 /src/makefile/macro.rs
parentf945ff33f9312a534ae52f1c763b4150ae41dcf6 (diff)
downloadmakers-fca10b517b448b4023ad8c3225e59dcefd4004e4.tar.gz
makers-fca10b517b448b4023ad8c3225e59dcefd4004e4.zip
overhaul eval architecture
Diffstat (limited to 'src/makefile/macro.rs')
-rw-r--r--src/makefile/macro.rs60
1 files changed, 34 insertions, 26 deletions
diff --git a/src/makefile/macro.rs b/src/makefile/macro.rs
index 7b43b13..beae404 100644
--- a/src/makefile/macro.rs
+++ b/src/makefile/macro.rs
@@ -3,16 +3,17 @@ use std::collections::HashMap;
use std::collections::HashSet;
use std::env;
use std::fmt;
+use std::io::BufRead;
use std::rc::Rc;
-use eyre::{bail, Result, WrapErr};
-#[cfg(not(feature = "full"))]
-use regex::Regex;
-
#[cfg(feature = "full")]
use super::functions;
use super::token::{Token, TokenString};
use super::ItemSource;
+use crate::makefile::eval_context::DeferredEvalContext;
+use eyre::{bail, Result, WrapErr};
+#[cfg(not(feature = "full"))]
+use regex::Regex;
#[derive(Debug, Clone)]
pub struct Macro {
@@ -90,8 +91,6 @@ pub struct Set<'parent, 'lookup> {
pub data: HashMap<String, Macro>,
lookup_internal: Option<&'lookup dyn LookupInternal>,
#[cfg(feature = "full")]
- pub to_eval: Rc<RefCell<Vec<String>>>,
- #[cfg(feature = "full")]
pub exported: ExportConfig,
warnings: Rc<RefCell<HashSet<String>>>,
}
@@ -103,8 +102,6 @@ impl<'parent, 'lookup> Set<'parent, 'lookup> {
data: HashMap::new(),
lookup_internal: None,
#[cfg(feature = "full")]
- to_eval: Rc::new(RefCell::new(Vec::new())),
- #[cfg(feature = "full")]
exported: ExportConfig::only(),
warnings: Default::default(),
}
@@ -206,14 +203,18 @@ impl<'parent, 'lookup> Set<'parent, 'lookup> {
}
}
- pub fn expand(&self, text: &TokenString) -> Result<String> {
+ pub fn expand<R: BufRead>(
+ &self,
+ text: &TokenString,
+ mut eval_context: Option<&mut DeferredEvalContext<R>>,
+ ) -> Result<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 name = self
- .expand(name)
+ .expand(name, eval_context.as_deref_mut())
.wrap_err_with(|| format!("while expanding \"{}\"", name))?;
let internal_macro_names = &['@', '?', '<', '*', '^'][..];
let internal_macro_suffices = &['D', 'F'][..];
@@ -231,14 +232,14 @@ impl<'parent, 'lookup> Set<'parent, 'lookup> {
Ok(String::new())
},
|x| {
- self.expand(&x.text)
+ self.expand(&x.text, eval_context.as_deref_mut())
.wrap_err_with(|| format!("while expanding \"{}\"", &x.text))
},
)?
};
let macro_value = match replacement {
Some((subst1, subst2)) => {
- let subst1 = self.expand(subst1)?;
+ let subst1 = self.expand(subst1, eval_context.as_deref_mut())?;
#[cfg(feature = "full")]
{
let (subst1, subst2) = if subst1.contains('%') {
@@ -257,7 +258,7 @@ impl<'parent, 'lookup> Set<'parent, 'lookup> {
"patsubst",
&args,
self,
- Some(Rc::clone(&self.to_eval)),
+ eval_context.as_deref_mut(),
)?
}
#[cfg(not(feature = "full"))]
@@ -286,9 +287,9 @@ impl<'parent, 'lookup> Set<'parent, 'lookup> {
}
#[cfg(feature = "full")]
Token::FunctionCall { name, args } => {
- let name = self.expand(name)?;
+ let name = self.expand(name, eval_context.as_deref_mut())?;
let fn_result =
- functions::expand_call(&name, args, self, Some(Rc::clone(&self.to_eval)))?;
+ functions::expand_call(&name, args, self, eval_context.as_deref_mut())?;
log::trace!("expanded {} into \"{}\"", token, &fn_result);
result.push_str(&fn_result);
}
@@ -332,8 +333,6 @@ impl<'parent, 'lookup> Set<'parent, 'lookup> {
data: HashMap::new(),
lookup_internal: Some(lookup),
#[cfg(feature = "full")]
- to_eval: Rc::clone(&self.to_eval),
- #[cfg(feature = "full")]
exported: self.exported.same_type(),
warnings: Rc::clone(&self.warnings),
}
@@ -345,23 +344,27 @@ impl<'parent, 'lookup> Set<'parent, 'lookup> {
data: HashMap::new(),
lookup_internal: None,
#[cfg(feature = "full")]
- to_eval: Rc::clone(&self.to_eval),
- #[cfg(feature = "full")]
exported: self.exported.same_type(),
warnings: Rc::clone(&self.warnings),
}
}
#[cfg(feature = "full")]
- pub fn resolve_exports(&self) -> Result<Vec<(&str, String)>> {
+ pub fn resolve_exports<R: BufRead>(
+ &self,
+ mut eval_context: Option<&mut DeferredEvalContext<R>>,
+ ) -> Result<Vec<(&str, String)>> {
let own_exports = self
.data
.iter()
.filter(|(name, _)| self.exported.should_export(name))
- .map(|(name, value)| self.expand(&value.text).map(|text| (name.as_ref(), text)))
+ .map(|(name, value)| {
+ self.expand(&value.text, eval_context.as_deref_mut())
+ .map(|text| (name.as_ref(), text))
+ })
.collect::<Result<Vec<_>>>()?;
Ok(if let Some(parent) = self.parent {
- let mut parent_exports = parent.resolve_exports()?;
+ let mut parent_exports = parent.resolve_exports(eval_context)?;
parent_exports.extend(own_exports);
parent_exports
} else {
@@ -377,8 +380,6 @@ impl fmt::Debug for Set<'_, '_> {
r#struct.field("data", &self.data);
r#struct.field("lookup_internal", &self.lookup_internal.map(|_| ()));
#[cfg(feature = "full")]
- r#struct.field("to_eval", &self.to_eval);
- #[cfg(feature = "full")]
r#struct.field("exported", &self.exported);
r#struct.field("warnings", &self.warnings);
r#struct.finish()
@@ -456,6 +457,7 @@ fn builtins() -> Vec<(&'static str, TokenString)> {
#[cfg(test)]
mod test {
use super::*;
+ use crate::makefile::functions::NO_EVAL;
type R = Result<()>;
@@ -471,7 +473,10 @@ mod test {
eagerly_expanded: false,
},
);
- assert_eq!(macros.expand(&"$(oof:;=?)".parse()?)?, "bruh? swag? yeet?");
+ assert_eq!(
+ macros.expand(&"$(oof:;=?)".parse()?, NO_EVAL)?,
+ "bruh? swag? yeet?"
+ );
Ok(())
}
@@ -487,7 +492,10 @@ mod test {
eagerly_expanded: false,
},
);
- assert_eq!(macros.expand(&"$(m:%=%-objs)".parse()?)?, "conf-objs");
+ assert_eq!(
+ macros.expand(&"$(m:%=%-objs)".parse()?, NO_EVAL)?,
+ "conf-objs"
+ );
Ok(())
}
}