aboutsummaryrefslogtreecommitdiff
path: root/src/makefile/functions.rs
diff options
context:
space:
mode:
authorMelody Horn <melody@boringcactus.com>2024-11-11 00:07:33 -0700
committerMelody Horn <melody@boringcactus.com>2024-11-11 00:07:33 -0700
commitec2c18171cd316a8b1f69baf92f67980820dfc9a (patch)
tree007add1cd59aec07098134b018efededee463d97 /src/makefile/functions.rs
parent825ff799a2154ffb94ef21bbc14e2afe2afa2006 (diff)
downloadmakers-ec2c18171cd316a8b1f69baf92f67980820dfc9a.tar.gz
makers-ec2c18171cd316a8b1f69baf92f67980820dfc9a.zip
overhaul macro inheritance
i was really proud of the lifetimes i had going on in the previous code. i should not have been.
Diffstat (limited to 'src/makefile/functions.rs')
-rw-r--r--src/makefile/functions.rs218
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(&macros)
+ .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(&macros)
+ .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 {