diff options
author | Melody Horn <melody@boringcactus.com> | 2024-11-10 21:20:34 -0700 |
---|---|---|
committer | Melody Horn <melody@boringcactus.com> | 2024-11-10 21:20:34 -0700 |
commit | fca10b517b448b4023ad8c3225e59dcefd4004e4 (patch) | |
tree | 7507e959d1f690044945dd6fcf34b5fef3385b14 /src/makefile/macro.rs | |
parent | f945ff33f9312a534ae52f1c763b4150ae41dcf6 (diff) | |
download | makers-fca10b517b448b4023ad8c3225e59dcefd4004e4.tar.gz makers-fca10b517b448b4023ad8c3225e59dcefd4004e4.zip |
overhaul eval architecture
Diffstat (limited to 'src/makefile/macro.rs')
-rw-r--r-- | src/makefile/macro.rs | 60 |
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(()) } } |