diff options
Diffstat (limited to 'src/makefile/functions.rs')
-rw-r--r-- | src/makefile/functions.rs | 218 |
1 files changed, 111 insertions, 107 deletions
diff --git a/src/makefile/functions.rs b/src/makefile/functions.rs index 1f3c897..05f6750 100644 --- a/src/makefile/functions.rs +++ b/src/makefile/functions.rs @@ -6,9 +6,8 @@ use eyre::{bail, Result, WrapErr}; use super::eval_context::DeferredEvalContext; use super::pattern::r#match; -use super::r#macro::{Macro, Set as MacroSet}; -use super::token::TokenString; -use super::ItemSource; +use super::r#macro::Macro; +use super::{ItemSource, MacroScopeStack, MacroSet, TokenString}; pub const NO_EVAL: Option<&mut DeferredEvalContext<&[u8]>> = None; @@ -16,114 +15,114 @@ pub const NO_EVAL: Option<&mut DeferredEvalContext<&[u8]>> = None; pub fn expand_call( name: &str, args: &[TokenString], - macros: &MacroSet, + stack: &MacroScopeStack, mut eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, ) -> Result<String> { match name { "subst" => { assert_eq!(args.len(), 3); - text::subst(macros, &args[0], &args[1], &args[2], eval_context) + text::subst(stack, &args[0], &args[1], &args[2], eval_context) } "patsubst" => { assert_eq!(args.len(), 3); - text::patsubst(macros, &args[0], &args[1], &args[2], eval_context) + text::patsubst(stack, &args[0], &args[1], &args[2], eval_context) } "strip" => { assert_eq!(args.len(), 1); - text::strip(macros, &args[0], eval_context) + text::strip(stack, &args[0], eval_context) } "findstring" => { assert_eq!(args.len(), 2); - text::findstring(macros, &args[0], &args[1], eval_context) + text::findstring(stack, &args[0], &args[1], eval_context) } "filter" => { assert_eq!(args.len(), 2); - text::filter(macros, &args[0], &args[1], eval_context) + text::filter(stack, &args[0], &args[1], eval_context) } "filter-out" => { assert_eq!(args.len(), 2); - text::filter_out(macros, &args[0], &args[1], eval_context) + text::filter_out(stack, &args[0], &args[1], eval_context) } "sort" => { assert_eq!(args.len(), 1); - text::sort(macros, &args[0], eval_context) + text::sort(stack, &args[0], eval_context) } "word" => { assert_eq!(args.len(), 2); - text::word(macros, &args[0], &args[1], eval_context) + text::word(stack, &args[0], &args[1], eval_context) } "words" => { assert_eq!(args.len(), 1); - text::words(macros, &args[0], eval_context) + text::words(stack, &args[0], eval_context) } "firstword" => { assert_eq!(args.len(), 1); - text::firstword(macros, &args[0], eval_context) + text::firstword(stack, &args[0], eval_context) } "lastword" => { assert_eq!(args.len(), 1); - text::lastword(macros, &args[0], eval_context) + text::lastword(stack, &args[0], eval_context) } "dir" => { assert_eq!(args.len(), 1); - file_name::dir(macros, &args[0], eval_context) + file_name::dir(stack, &args[0], eval_context) } "notdir" => { assert_eq!(args.len(), 1); - file_name::notdir(macros, &args[0], eval_context) + file_name::notdir(stack, &args[0], eval_context) } "basename" => { assert_eq!(args.len(), 1); - file_name::basename(macros, &args[0], eval_context) + file_name::basename(stack, &args[0], eval_context) } "addsuffix" => { assert_eq!(args.len(), 2); - file_name::addsuffix(macros, &args[0], &args[1], eval_context) + file_name::addsuffix(stack, &args[0], &args[1], eval_context) } "addprefix" => { assert_eq!(args.len(), 2); - file_name::addprefix(macros, &args[0], &args[1], eval_context) + file_name::addprefix(stack, &args[0], &args[1], eval_context) } "wildcard" => { assert_eq!(args.len(), 1); - file_name::wildcard(macros, &args[0], eval_context) + file_name::wildcard(stack, &args[0], eval_context) } "realpath" => { assert_eq!(args.len(), 1); - file_name::realpath(macros, &args[0], eval_context) + file_name::realpath(stack, &args[0], eval_context) } "abspath" => { assert_eq!(args.len(), 1); - file_name::abspath(macros, &args[0], eval_context) + file_name::abspath(stack, &args[0], eval_context) } "if" => { assert!(args.len() == 2 || args.len() == 3); - conditional::r#if(macros, &args[0], &args[1], args.get(2), eval_context) + conditional::r#if(stack, &args[0], &args[1], args.get(2), eval_context) } "or" => { assert!(!args.is_empty()); - conditional::or(macros, args.iter(), eval_context) + conditional::or(stack, args.iter(), eval_context) } "and" => { assert!(!args.is_empty()); - conditional::and(macros, args.iter(), eval_context) + conditional::and(stack, args.iter(), eval_context) } "foreach" => { assert_eq!(args.len(), 3); - foreach(macros, &args[0], &args[1], &args[2], eval_context) + foreach(stack, &args[0], &args[1], &args[2], eval_context) } "call" => { assert!(!args.is_empty()); - call(macros, args.iter(), eval_context) + call(stack, args.iter(), eval_context) } "eval" => { assert_eq!(args.len(), 1); - let should_eval = eval(macros, &args[0], eval_context.as_deref_mut())?; + let should_eval = eval(stack, &args[0], eval_context.as_deref_mut())?; if let Some(eval_context) = eval_context { eval_context.eval(should_eval)?; } else { @@ -134,17 +133,17 @@ pub fn expand_call( "origin" => { assert_eq!(args.len(), 1); - origin(macros, &args[0], eval_context) + origin(stack, &args[0], eval_context) } "error" => { assert_eq!(args.len(), 1); - meta::error(macros, &args[0], eval_context) + meta::error(stack, &args[0], eval_context) } "shell" => { assert_eq!(args.len(), 1); - shell(macros, &args[0], eval_context) + shell(stack, &args[0], eval_context) } // fallback @@ -157,28 +156,28 @@ mod text { use super::*; pub fn subst( - macros: &MacroSet, + stack: &MacroScopeStack, from: &TokenString, to: &TokenString, text: &TokenString, mut eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, ) -> Result<String> { - let from = macros.expand(from, eval_context.as_deref_mut())?; - let to = macros.expand(to, eval_context.as_deref_mut())?; - let text = macros.expand(text, eval_context)?; + let from = stack.expand(from, eval_context.as_deref_mut())?; + let to = stack.expand(to, eval_context.as_deref_mut())?; + let text = stack.expand(text, eval_context)?; Ok(text.replace(&from, &to)) } pub fn patsubst( - macros: &MacroSet, + stack: &MacroScopeStack, from: &TokenString, to: &TokenString, text: &TokenString, mut eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, ) -> Result<String> { - let from = macros.expand(from, eval_context.as_deref_mut())?; - let to = macros.expand(to, eval_context.as_deref_mut())?; - let text = macros.expand(text, eval_context)?; + let from = stack.expand(from, eval_context.as_deref_mut())?; + let to = stack.expand(to, eval_context.as_deref_mut())?; + let text = stack.expand(text, eval_context)?; let words = text.split_whitespace() .map(|word| { @@ -191,24 +190,24 @@ mod text { } pub fn strip( - macros: &MacroSet, + stack: &MacroScopeStack, text: &TokenString, eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, ) -> Result<String> { - let text = macros.expand(text, eval_context)?; + let text = stack.expand(text, eval_context)?; // TODO don't allocate this vec let words = text.split_whitespace().collect::<Vec<_>>(); Ok(words.join(" ")) } pub fn findstring( - macros: &MacroSet, + stack: &MacroScopeStack, needle: &TokenString, haystack: &TokenString, mut eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, ) -> Result<String> { - let needle = macros.expand(needle, eval_context.as_deref_mut())?; - let haystack = macros.expand(haystack, eval_context)?; + let needle = stack.expand(needle, eval_context.as_deref_mut())?; + let haystack = stack.expand(haystack, eval_context)?; if haystack.contains(&needle) { Ok(needle) } else { @@ -217,14 +216,14 @@ mod text { } pub fn filter( - macros: &MacroSet, + stack: &MacroScopeStack, patterns: &TokenString, text: &TokenString, mut eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, ) -> Result<String> { - let patterns = macros.expand(patterns, eval_context.as_deref_mut())?; + let patterns = stack.expand(patterns, eval_context.as_deref_mut())?; let patterns = patterns.split_whitespace().collect::<Vec<_>>(); - let text = macros.expand(text, eval_context)?; + let text = stack.expand(text, eval_context)?; let text = text.split_whitespace(); let mut result_pieces = vec![]; for word in text { @@ -239,14 +238,14 @@ mod text { } pub fn filter_out( - macros: &MacroSet, + stack: &MacroScopeStack, patterns: &TokenString, text: &TokenString, mut eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, ) -> Result<String> { - let patterns = macros.expand(patterns, eval_context.as_deref_mut())?; + let patterns = stack.expand(patterns, eval_context.as_deref_mut())?; let patterns = patterns.split_whitespace().collect::<Vec<_>>(); - let text = macros.expand(text, eval_context)?; + let text = stack.expand(text, eval_context)?; let text = text.split_whitespace(); let mut result_pieces = vec![]; for word in text { @@ -261,11 +260,11 @@ mod text { } pub fn sort( - macros: &MacroSet, + stack: &MacroScopeStack, words: &TokenString, eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, ) -> Result<String> { - let words = macros.expand(words, eval_context)?; + let words = stack.expand(words, eval_context)?; let mut words = words.split_whitespace().collect::<Vec<_>>(); words.sort_unstable(); words.dedup(); @@ -273,14 +272,14 @@ mod text { } pub fn word( - macros: &MacroSet, + stack: &MacroScopeStack, n: &TokenString, text: &TokenString, mut eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, ) -> Result<String> { - let n = macros.expand(n, eval_context.as_deref_mut())?; + let n = stack.expand(n, eval_context.as_deref_mut())?; let n: usize = n.parse().wrap_err("while calling `word`")?; - let text = macros.expand(text, eval_context)?; + let text = stack.expand(text, eval_context)?; Ok(text .split_whitespace() .nth(n.saturating_add(1)) @@ -289,29 +288,29 @@ mod text { } pub fn words( - macros: &MacroSet, + stack: &MacroScopeStack, words: &TokenString, eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, ) -> Result<String> { - let words = macros.expand(words, eval_context)?; + let words = stack.expand(words, eval_context)?; Ok(words.split_whitespace().count().to_string()) } pub fn firstword( - macros: &MacroSet, + stack: &MacroScopeStack, words: &TokenString, eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, ) -> Result<String> { - let words = macros.expand(words, eval_context)?; + let words = stack.expand(words, eval_context)?; Ok(words.split_whitespace().next().unwrap_or("").to_owned()) } pub fn lastword( - macros: &MacroSet, + stack: &MacroScopeStack, words: &TokenString, eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, ) -> Result<String> { - let words = macros.expand(words, eval_context)?; + let words = stack.expand(words, eval_context)?; Ok(words.split_whitespace().last().unwrap_or("").to_owned()) } } @@ -329,11 +328,11 @@ mod file_name { use eyre::WrapErr; pub fn dir( - macros: &MacroSet, + stack: &MacroScopeStack, words: &TokenString, eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, ) -> Result<String> { - let words = macros.expand(words, eval_context)?; + let words = stack.expand(words, eval_context)?; let words = words .split_whitespace() .map(|word| { @@ -349,11 +348,11 @@ mod file_name { } pub fn notdir( - macros: &MacroSet, + stack: &MacroScopeStack, words: &TokenString, eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, ) -> Result<String> { - let words = macros.expand(words, eval_context)?; + let words = stack.expand(words, eval_context)?; let words = words .split_whitespace() .map(|word| { @@ -367,11 +366,11 @@ mod file_name { } pub fn basename( - macros: &MacroSet, + stack: &MacroScopeStack, words: &TokenString, eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, ) -> Result<String> { - let words = macros.expand(words, eval_context)?; + let words = stack.expand(words, eval_context)?; let words = words .split_whitespace() .map(|word| { @@ -385,13 +384,13 @@ mod file_name { } pub fn addsuffix( - macros: &MacroSet, + stack: &MacroScopeStack, suffix: &TokenString, targets: &TokenString, mut eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, ) -> Result<String> { - let suffix = macros.expand(suffix, eval_context.as_deref_mut())?; - let targets = macros.expand(targets, eval_context)?; + let suffix = stack.expand(suffix, eval_context.as_deref_mut())?; + let targets = stack.expand(targets, eval_context)?; let results = targets .split_whitespace() .map(|t| format!("{}{}", t, suffix)) @@ -400,13 +399,13 @@ mod file_name { } pub fn addprefix( - macros: &MacroSet, + stack: &MacroScopeStack, prefix: &TokenString, targets: &TokenString, mut eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, ) -> Result<String> { - let prefix = macros.expand(prefix, eval_context.as_deref_mut())?; - let targets = macros.expand(targets, eval_context)?; + let prefix = stack.expand(prefix, eval_context.as_deref_mut())?; + let targets = stack.expand(targets, eval_context)?; let results = targets .split_whitespace() .map(|t| format!("{}{}", prefix, t)) @@ -415,11 +414,11 @@ mod file_name { } pub fn wildcard( - macros: &MacroSet, + stack: &MacroScopeStack, pattern: &TokenString, eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, ) -> Result<String> { - let pattern = macros.expand(pattern, eval_context)?; + let pattern = stack.expand(pattern, eval_context)?; let home_dir = env::var("HOME") .ok() .or_else(|| dirs::home_dir().and_then(|p| p.to_str().map(String::from))); @@ -439,11 +438,11 @@ mod file_name { } pub fn realpath( - macros: &MacroSet, + stack: &MacroScopeStack, targets: &TokenString, eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, ) -> Result<String> { - let targets = macros.expand(targets, eval_context)?; + let targets = stack.expand(targets, eval_context)?; let results = targets .split_whitespace() .map(|x| { @@ -456,12 +455,12 @@ mod file_name { } pub fn abspath( - macros: &MacroSet, + stack: &MacroScopeStack, targets: &TokenString, eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, ) -> Result<String> { // TODO don't resolve symlinks - realpath(macros, targets, eval_context) + realpath(stack, targets, eval_context) } } @@ -470,7 +469,7 @@ mod conditional { use super::*; pub fn r#if( - macros: &MacroSet, + stack: &MacroScopeStack, condition: &TokenString, if_true: &TokenString, if_false: Option<&TokenString>, @@ -479,24 +478,24 @@ mod conditional { let mut condition = condition.clone(); condition.trim_start(); condition.trim_end(); - let condition = macros.expand(&condition, eval_context.as_deref_mut())?; + let condition = stack.expand(&condition, eval_context.as_deref_mut())?; if condition.is_empty() { if_false.map_or_else( || Ok(String::new()), - |if_false| macros.expand(if_false, eval_context), + |if_false| stack.expand(if_false, eval_context), ) } else { - macros.expand(if_true, eval_context) + stack.expand(if_true, eval_context) } } pub fn or<'a>( - macros: &MacroSet, + stack: &MacroScopeStack, args: impl Iterator<Item = &'a TokenString>, mut eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, ) -> Result<String> { for arg in args { - let arg = macros.expand(arg, eval_context.as_deref_mut())?; + let arg = stack.expand(arg, eval_context.as_deref_mut())?; if !arg.is_empty() { return Ok(arg); } @@ -505,13 +504,13 @@ mod conditional { } pub fn and<'a>( - macros: &MacroSet, + stack: &MacroScopeStack, args: impl Iterator<Item = &'a TokenString>, mut eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, ) -> Result<String> { let mut last = String::new(); for arg in args { - last = macros.expand(arg, eval_context.as_deref_mut())?; + last = stack.expand(arg, eval_context.as_deref_mut())?; if last.is_empty() { return Ok(String::new()); } @@ -521,19 +520,19 @@ mod conditional { } pub fn foreach( - macros: &MacroSet, + stack: &MacroScopeStack, var: &TokenString, list: &TokenString, text: &TokenString, mut eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, ) -> Result<String> { - let var = macros.expand(var, eval_context.as_deref_mut())?; - let list = macros.expand(list, eval_context.as_deref_mut())?; + let var = stack.expand(var, eval_context.as_deref_mut())?; + let list = stack.expand(list, eval_context.as_deref_mut())?; let words = list.split_whitespace(); - let mut macros = macros.with_overlay(); let results = words .map(|word| { + let mut macros = MacroSet::new(); macros.set( var.clone(), Macro { @@ -543,24 +542,26 @@ pub fn foreach( eagerly_expanded: false, }, ); - macros.expand(text, eval_context.as_deref_mut()) + stack + .with_scope(¯os) + .expand(text, eval_context.as_deref_mut()) }) .collect::<Result<Vec<_>, _>>()?; Ok(results.join(" ")) } pub fn call<'a>( - macros: &MacroSet, + stack: &MacroScopeStack, args: impl Iterator<Item = &'a TokenString>, mut eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, ) -> Result<String> { let args = args - .map(|arg| macros.expand(arg, eval_context.as_deref_mut())) + .map(|arg| stack.expand(arg, eval_context.as_deref_mut())) .collect::<Result<Vec<_>, _>>()?; let function = args[0].clone(); // TODO if function is a builtin, call the builtin instead - let mut macros = macros.with_overlay(); + let mut macros = MacroSet::new(); for (i, x) in args.into_iter().enumerate() { macros.set( i.to_string(), @@ -572,47 +573,49 @@ pub fn call<'a>( }, ); } - macros.expand(&TokenString::r#macro(function), eval_context) + stack + .with_scope(¯os) + .expand(&TokenString::r#macro(function), eval_context) } // TODO consider bringing eval logic in here since we put the Vec in MacroSet IIRC pub fn eval( - macros: &MacroSet, + stack: &MacroScopeStack, arg: &TokenString, eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, ) -> Result<String> { - macros.expand(arg, eval_context) + stack.expand(arg, eval_context) } pub fn origin( - macros: &MacroSet, + stack: &MacroScopeStack, variable: &TokenString, eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, ) -> Result<String> { - let variable = macros.expand(variable, eval_context)?; - Ok(macros.origin(&variable).to_owned()) + let variable = stack.expand(variable, eval_context)?; + Ok(stack.origin(&variable).to_owned()) } mod meta { use super::*; pub fn error( - macros: &MacroSet, + stack: &MacroScopeStack, text: &TokenString, eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, ) -> Result<String> { - let text = macros.expand(text, eval_context)?; + let text = stack.expand(text, eval_context)?; bail!("{}", text); } } pub fn shell( - macros: &MacroSet, + stack: &MacroScopeStack, command: &TokenString, eval_context: Option<&mut DeferredEvalContext<impl BufRead>>, ) -> Result<String> { // TODO bring this in from command_line - let command = macros.expand(command, eval_context)?; + let command = stack.expand(command, eval_context)?; let (program, args) = if cfg!(windows) { let cmd = env::var("COMSPEC").unwrap_or_else(|_| "cmd.exe".into()); let args = vec!["/c", &command]; @@ -641,7 +644,8 @@ mod test { type R = Result<()>; fn call(name: &str, args: &[TokenString], macros: &MacroSet) -> Result<String> { - expand_call(name, args, macros, NO_EVAL) + let stack = MacroScopeStack::default().with_scope(macros); + expand_call(name, args, &stack, NO_EVAL) } macro_rules! call { |