aboutsummaryrefslogtreecommitdiff
path: root/src/makefile
diff options
context:
space:
mode:
Diffstat (limited to 'src/makefile')
-rw-r--r--src/makefile/eval_context.rs7
-rw-r--r--src/makefile/functions.rs218
-rw-r--r--src/makefile/input.rs49
-rw-r--r--src/makefile/macro.rs252
-rw-r--r--src/makefile/macro_scope.rs211
-rw-r--r--src/makefile/mod.rs16
6 files changed, 385 insertions, 368 deletions
diff --git a/src/makefile/eval_context.rs b/src/makefile/eval_context.rs
index 06f4fbf..ba5f4a0 100644
--- a/src/makefile/eval_context.rs
+++ b/src/makefile/eval_context.rs
@@ -2,8 +2,7 @@ use eyre::{Result, WrapErr};
use std::io::{BufRead, Cursor};
use std::rc::Rc;
-use crate::makefile::input::FinishedMakefileReader;
-use crate::makefile::MakefileReader;
+use super::{FinishedMakefileReader, MacroSet, MakefileReader};
pub struct DeferredEvalContext<'parent, 'args, 'grandparent, R: BufRead> {
parent: &'parent MakefileReader<'args, 'grandparent, R>,
@@ -25,9 +24,11 @@ impl<'parent, 'args, 'grandparent, R: BufRead>
}
pub fn eval(&mut self, to_eval: String) -> Result<()> {
- let child_macros = self.parent.macros.with_overlay();
+ let child_stack = self.parent.stack.with_scope(&self.parent.macros);
+ let child_macros = MacroSet::new();
let child = MakefileReader::read(
self.parent.args,
+ child_stack,
child_macros,
Cursor::new(to_eval),
"<eval>",
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 {
diff --git a/src/makefile/input.rs b/src/makefile/input.rs
index bbfdaee..40720c2 100644
--- a/src/makefile/input.rs
+++ b/src/makefile/input.rs
@@ -13,19 +13,19 @@ use regex::Regex;
use crate::args::Args;
-use super::command_line::CommandLine;
#[cfg(feature = "full")]
use super::conditional::{Line as ConditionalLine, State as ConditionalState};
#[cfg(feature = "full")]
use super::eval_context::DeferredEvalContext;
-use super::inference_rules::InferenceRule;
#[cfg(feature = "full")]
use super::r#macro::ExportConfig;
-use super::r#macro::{Macro, Set as MacroSet};
-use super::target::{StaticTargetSet, Target};
-use super::token::{Token, TokenString};
-use super::LookupInternal;
-use super::{builtin_targets, ItemSource};
+use super::r#macro::Macro;
+use super::target::StaticTargetSet;
+use super::token::Token;
+use super::{
+ builtin_targets, CommandLine, InferenceRule, ItemSource, LookupInternal, MacroScopeStack,
+ MacroSet, Target, TokenString,
+};
enum LineType {
Rule,
@@ -188,7 +188,8 @@ impl Default for NextLineSettings {
pub struct MakefileReader<'a, 'parent, R: BufRead> {
file_name: String,
pub inference_rules: Vec<InferenceRule>,
- pub macros: MacroSet<'parent, 'static>,
+ pub stack: MacroScopeStack<'parent>,
+ pub macros: MacroSet,
pub targets: StaticTargetSet,
built_in_targets: HashMap<String, Target>,
pub first_non_special_target: Option<String>,
@@ -205,10 +206,11 @@ pub struct MakefileReader<'a, 'parent, R: BufRead> {
impl<'a, 'parent> MakefileReader<'a, 'parent, BufReader<File>> {
pub fn read_file(
args: &'a Args,
- mut macros: MacroSet<'parent, 'static>,
+ stack: MacroScopeStack<'parent>,
path: impl AsRef<Path>,
file_names: Rc<RefCell<Vec<String>>>,
) -> Result<Self> {
+ let mut macros = MacroSet::new();
#[cfg(feature = "full")]
if let Some(mut old_makefile_list) = macros.pop("MAKEFILE_LIST") {
old_makefile_list.text.extend(TokenString::text(format!(
@@ -233,14 +235,15 @@ impl<'a, 'parent> MakefileReader<'a, 'parent, BufReader<File>> {
// TODO handle errors
let file = file.context("couldn't open makefile!")?;
let file_reader = BufReader::new(file);
- Self::read(args, macros, file_reader, file_name, file_names)
+ Self::read(args, stack, macros, file_reader, file_name, file_names)
}
}
impl<'a, 'parent, R: BufRead> MakefileReader<'a, 'parent, R> {
pub fn read(
args: &'a Args,
- macros: MacroSet<'parent, 'static>,
+ stack: MacroScopeStack<'parent>,
+ macros: MacroSet,
source: R,
name: impl Into<String>,
file_names: Rc<RefCell<Vec<String>>>,
@@ -249,6 +252,7 @@ impl<'a, 'parent, R: BufRead> MakefileReader<'a, 'parent, R> {
let mut reader = Self {
file_name: name.clone(),
inference_rules: Vec::new(),
+ stack,
macros,
targets: Default::default(),
built_in_targets: HashMap::new(),
@@ -525,10 +529,10 @@ impl<'a, 'parent, R: BufRead> MakefileReader<'a, 'parent, R> {
// handles arbitrarily many filenames, and it's not like that's more work
for field in fields {
log::trace!("{}:{}: including {}", &self.file_name, line_number, field);
- let child_macros = self.macros.with_overlay();
+ let child_stack = self.stack.with_scope(&self.macros);
let child = MakefileReader::read_file(
self.args,
- child_macros,
+ child_stack,
field,
Rc::clone(&self.file_names),
)
@@ -591,8 +595,9 @@ impl<'a, 'parent, R: BufRead> MakefileReader<'a, 'parent, R> {
#[cfg(feature = "full")]
let mut deferred_eval_context = DeferredEvalContext::new(self);
let prerequisites = self
- .macros
- .with_lookup(LookupInternal::new_partial(&targets))
+ .stack
+ .with_scope(&self.macros)
+ .with_scope(&LookupInternal::new_partial(&targets))
.expand(
&prerequisites,
#[cfg(feature = "full")]
@@ -890,7 +895,8 @@ impl<'a, 'parent, R: BufRead> MakefileReader<'a, 'parent, R> {
text: &TokenString,
#[cfg(feature = "full")] deferred_eval_context: &mut DeferredEvalContext<R>,
) -> Result<String> {
- self.macros
+ self.stack
+ .with_scope(&self.macros)
.expand(
text,
#[cfg(feature = "full")]
@@ -960,6 +966,7 @@ a: $(x) b \\
let args = Args::empty();
let makefile = MakefileReader::read(
&args,
+ MacroScopeStack::default(),
MacroSet::new(),
Cursor::new(file),
"",
@@ -988,6 +995,7 @@ endif
let args = Args::empty();
let mut makefile = MakefileReader::read(
&args,
+ MacroScopeStack::default(),
MacroSet::new(),
Cursor::new(file),
"",
@@ -1012,6 +1020,7 @@ endif
let args = Args::empty();
let makefile = MakefileReader::read(
&args,
+ MacroScopeStack::default(),
MacroSet::new(),
Cursor::new(file),
"",
@@ -1034,6 +1043,7 @@ endef
let args = Args::empty();
let mut makefile = MakefileReader::read(
&args,
+ MacroScopeStack::default(),
MacroSet::new(),
Cursor::new(file),
"",
@@ -1062,6 +1072,7 @@ FOO = bar
let args = Args::empty();
let mut makefile = MakefileReader::read(
&args,
+ MacroScopeStack::default(),
MacroSet::new(),
Cursor::new(file),
"",
@@ -1110,6 +1121,7 @@ clean:
let args = Args::empty();
let makefile = MakefileReader::read(
&args,
+ MacroScopeStack::default(),
MacroSet::new(),
Cursor::new(file),
"",
@@ -1131,6 +1143,7 @@ info:
let args = Args::empty();
let makefile = MakefileReader::read(
&args,
+ MacroScopeStack::default(),
MacroSet::new(),
Cursor::new(file),
"",
@@ -1181,6 +1194,7 @@ cursed:
let args = Args::empty();
let makefile = MakefileReader::read(
&args,
+ MacroScopeStack::default(),
MacroSet::new(),
Cursor::new(file),
"",
@@ -1205,6 +1219,7 @@ cursed:
let args = Args::empty();
let makefile = MakefileReader::read(
&args,
+ MacroScopeStack::default(),
MacroSet::new(),
Cursor::new(file),
"",
@@ -1226,6 +1241,7 @@ test: c
let args = Args::empty();
let makefile = MakefileReader::read(
&args,
+ MacroScopeStack::default(),
MacroSet::new(),
Cursor::new(file),
"",
@@ -1246,6 +1262,7 @@ test: c
let args = Args::empty();
let makefile = MakefileReader::read(
&args,
+ MacroScopeStack::default(),
MacroSet::new(),
Cursor::new(file),
"",
diff --git a/src/makefile/macro.rs b/src/makefile/macro.rs
index 4a82fe9..fb0367b 100644
--- a/src/makefile/macro.rs
+++ b/src/makefile/macro.rs
@@ -1,20 +1,16 @@
-use std::cell::RefCell;
use std::collections::HashMap;
use std::collections::HashSet;
use std::env;
use std::fmt;
#[cfg(feature = "full")]
use std::io::BufRead;
-use std::rc::Rc;
+
#[cfg(feature = "full")]
-use super::functions;
-use super::token::{Token, TokenString};
+use super::eval_context::DeferredEvalContext;
use super::ItemSource;
-use super::LookupInternal;
-#[cfg(feature = "full")]
-use crate::makefile::eval_context::DeferredEvalContext;
-use eyre::{bail, Result, WrapErr};
+use super::{MacroScopeStack, TokenString};
+use eyre::Result;
#[cfg(not(feature = "full"))]
use regex::Regex;
@@ -69,13 +65,6 @@ impl ExportConfig {
}
}
- fn same_type(&self) -> Self {
- match self {
- Self::Only(_) => Self::only(),
- Self::AllBut(_) => Self::all_but(),
- }
- }
-
fn should_export(&self, x: &str) -> bool {
match self {
Self::Only(exported) => exported.contains(x),
@@ -84,25 +73,19 @@ impl ExportConfig {
}
}
-#[derive(Clone)]
-pub struct Set<'parent, 'lookup> {
- parent: Option<&'parent Set<'parent, 'lookup>>,
+#[derive(Clone, Debug)]
+pub struct Set {
pub data: HashMap<String, Macro>,
- lookup_internal: Option<LookupInternal<'lookup>>,
#[cfg(feature = "full")]
pub exported: ExportConfig,
- warnings: Rc<RefCell<HashSet<String>>>,
}
-impl<'parent, 'lookup> Set<'parent, 'lookup> {
+impl Set {
pub fn new() -> Self {
Self {
- parent: None,
data: HashMap::new(),
- lookup_internal: None,
#[cfg(feature = "full")]
exported: ExportConfig::only(),
- warnings: Default::default(),
}
}
@@ -136,23 +119,8 @@ impl<'parent, 'lookup> Set<'parent, 'lookup> {
}
}
- fn lookup_internal(&self, name: &str) -> Result<String> {
- if let Some(lookup) = self.lookup_internal.as_ref() {
- lookup.lookup(name)
- } else if let Some(parent) = self.parent {
- parent.lookup_internal(name)
- } else {
- bail!(
- "tried to lookup {:?} but no lookup function is available",
- name
- )
- }
- }
-
pub fn get(&self, name: &str) -> Option<&Macro> {
- self.data
- .get(name)
- .or_else(|| self.parent.and_then(|parent| parent.get(name)))
+ self.data.get(name)
}
pub fn set(&mut self, name: String, r#macro: Macro) {
@@ -167,9 +135,7 @@ impl<'parent, 'lookup> Set<'parent, 'lookup> {
// `remove` is fine, but I think for "remove-and-return" `pop` is better
pub fn pop(&mut self, name: &str) -> Option<Macro> {
// TODO figure out a better way to handle inheritance
- self.data
- .remove(name)
- .or_else(|| self.parent.and_then(|p| p.get(name).cloned()))
+ self.data.remove(name)
}
pub fn extend(
@@ -195,171 +161,6 @@ impl<'parent, 'lookup> Set<'parent, 'lookup> {
self.data.extend(other);
}
- fn warn(&self, text: String) {
- if !self.warnings.borrow().contains(&text) {
- log::warn!("{}", &text);
- self.warnings.borrow_mut().insert(text);
- }
- }
-
- pub fn expand<#[cfg(feature = "full")] R: BufRead>(
- &self,
- text: &TokenString,
- #[cfg(feature = "full")] 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,
- #[cfg(feature = "full")]
- eval_context.as_deref_mut(),
- )
- .wrap_err_with(|| format!("while expanding \"{}\"", name))?;
- 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)
- .wrap_err_with(|| format!("while expanding $\"{}\"", name))?
- } else {
- self.get(&name).map_or_else(
- || {
- self.warn(format!("undefined macro {}", name));
- Ok(String::new())
- },
- |x| {
- self.expand(
- &x.text,
- #[cfg(feature = "full")]
- 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,
- #[cfg(feature = "full")]
- eval_context.as_deref_mut(),
- )?;
- #[cfg(feature = "full")]
- {
- let (subst1, subst2) = if subst1.contains('%') {
- (subst1, subst2.clone())
- } else {
- let mut real_subst2 = TokenString::text("%");
- real_subst2.extend(subst2.clone());
- (format!("%{}", subst1), real_subst2)
- };
- let args = [
- TokenString::text(subst1),
- subst2,
- TokenString::text(macro_value),
- ];
- functions::expand_call(
- "patsubst",
- &args,
- self,
- eval_context.as_deref_mut(),
- )?
- }
- #[cfg(not(feature = "full"))]
- {
- let subst1_suffix = regex::escape(&subst1);
- let subst1_suffix =
- Regex::new(&format!(r"{}(\s|$)", subst1_suffix))
- .context("formed invalid regex somehow")?;
- let subst2 = self.expand(subst2)?;
- subst1_suffix
- .replace_all(&macro_value, |c: &regex::Captures| {
- format!("{}{}", subst2, c.get(1).unwrap().as_str())
- })
- .to_string()
- }
- }
- None => macro_value,
- };
- log::trace!(
- "expanded {} (from {:?}) into \"{}\"",
- token,
- self.get(&name).map(|x| &x.source),
- &macro_value
- );
- result.push_str(&macro_value);
- }
- #[cfg(feature = "full")]
- Token::FunctionCall { name, args } => {
- let name = self.expand(name, eval_context.as_deref_mut())?;
- let fn_result =
- functions::expand_call(&name, args, self, eval_context.as_deref_mut())?;
- log::trace!("expanded {} into \"{}\"", token, &fn_result);
- result.push_str(&fn_result);
- }
- }
- }
- Ok(result)
- }
-
- #[cfg(feature = "full")]
- pub fn origin(&self, name: &str) -> &'static str {
- match self.data.get(name) {
- None => self.parent.map_or("undefined", |p| p.origin(name)),
- Some(Macro {
- source: ItemSource::Builtin,
- ..
- }) => "default",
- Some(Macro {
- source: ItemSource::Environment,
- ..
- }) => "environment",
- // TODO figure out when to return "environment override"
- Some(Macro {
- source: ItemSource::File { .. },
- ..
- }) => "file",
- Some(Macro {
- source: ItemSource::CommandLineOrMakeflags,
- ..
- }) => "command line",
- // TODO handle override
- Some(Macro {
- source: ItemSource::FunctionCall,
- ..
- }) => "automatic",
- }
- }
-
- pub fn with_lookup<'l, 's: 'l>(&'s self, lookup: LookupInternal<'l>) -> Set<'s, 'l> {
- Set {
- parent: Some(self),
- data: HashMap::new(),
- lookup_internal: Some(lookup),
- #[cfg(feature = "full")]
- exported: self.exported.same_type(),
- warnings: Rc::clone(&self.warnings),
- }
- }
-
- pub fn with_overlay<'s>(&'s self) -> Set<'s, 'lookup> {
- Set {
- parent: Some(self),
- data: HashMap::new(),
- lookup_internal: None,
- #[cfg(feature = "full")]
- exported: self.exported.same_type(),
- warnings: Rc::clone(&self.warnings),
- }
- }
-
#[cfg(feature = "full")]
pub fn resolve_exports<R: BufRead>(
&self,
@@ -370,37 +171,16 @@ impl<'parent, 'lookup> Set<'parent, 'lookup> {
.iter()
.filter(|(name, _)| self.exported.should_export(name))
.map(|(name, value)| {
- self.expand(&value.text, eval_context.as_deref_mut())
+ MacroScopeStack::from_scope(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(eval_context)?;
- parent_exports.extend(own_exports);
- parent_exports
- } else {
- own_exports
- })
- }
-}
-
-impl fmt::Debug for Set<'_, '_> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- let mut r#struct = f.debug_struct("Set");
- r#struct.field("parent", &self.parent);
- r#struct.field("data", &self.data);
- r#struct.field(
- "lookup_internal",
- &self.lookup_internal.as_ref().map(|_| ()),
- );
- #[cfg(feature = "full")]
- r#struct.field("exported", &self.exported);
- r#struct.field("warnings", &self.warnings);
- r#struct.finish()
+ Ok(own_exports)
}
}
-impl fmt::Display for Set<'_, '_> {
+impl fmt::Display for Set {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let pieces = self
.data
@@ -411,7 +191,7 @@ impl fmt::Display for Set<'_, '_> {
}
}
-impl Default for Set<'_, '_> {
+impl Default for Set {
fn default() -> Self {
Self::new()
}
@@ -489,7 +269,7 @@ mod test {
},
);
assert_eq!(
- macros.expand(
+ MacroScopeStack::from_scope(&macros).expand(
&"$(oof:;=?)".parse()?,
#[cfg(feature = "full")]
NO_EVAL
@@ -512,7 +292,7 @@ mod test {
},
);
assert_eq!(
- macros.expand(&"$(m:%=%-objs)".parse()?, NO_EVAL)?,
+ MacroScopeStack::from_scope(&macros).expand(&"$(m:%=%-objs)".parse()?, NO_EVAL)?,
"conf-objs"
);
Ok(())
diff --git a/src/makefile/macro_scope.rs b/src/makefile/macro_scope.rs
new file mode 100644
index 0000000..045d6f7
--- /dev/null
+++ b/src/makefile/macro_scope.rs
@@ -0,0 +1,211 @@
+use super::eval_context::DeferredEvalContext;
+use super::functions;
+use super::token::Token;
+use super::{ItemSource, LookupInternal, Macro, MacroSet, TokenString};
+use eyre::Context;
+use lazy_static::lazy_static;
+use std::borrow::Cow;
+use std::collections::HashSet;
+use std::io::BufRead;
+use std::iter;
+use std::sync::RwLock;
+
+pub trait MacroScope {
+ /// Looks up the macro with the given name and returns it if it exists.
+ ///
+ /// Uses [Cow] to allow for lazy macro definitions.
+ fn get(&self, name: &str) -> Option<Cow<Macro>>;
+}
+
+impl MacroScope for MacroSet {
+ fn get(&self, name: &str) -> Option<Cow<Macro>> {
+ self.get(name).map(Cow::Borrowed)
+ }
+}
+
+impl<'a> MacroScope for LookupInternal<'a> {
+ fn get(&self, name: &str) -> Option<Cow<Macro>> {
+ self.lookup(name).ok().map(|value| {
+ Cow::Owned(Macro {
+ source: ItemSource::Builtin,
+ text: TokenString::text(value),
+ #[cfg(feature = "full")]
+ eagerly_expanded: false,
+ })
+ })
+ }
+}
+
+// warning on undefined macros is useful but can get repetitive fast
+lazy_static! {
+ static ref WARNINGS_EMITTED: RwLock<HashSet<String>> = Default::default();
+}
+
+fn warn(text: String) {
+ let already_warned = WARNINGS_EMITTED
+ .read()
+ .map_or(true, |warnings| warnings.contains(&text));
+ if !already_warned {
+ log::warn!("{}", &text);
+ if let Ok(mut warnings) = WARNINGS_EMITTED.write() {
+ warnings.insert(text);
+ }
+ }
+}
+
+#[derive(Default)]
+pub struct MacroScopeStack<'a> {
+ scopes: Vec<&'a dyn MacroScope>,
+}
+
+impl<'a> MacroScopeStack<'a> {
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ pub fn from_scope(scope: &'a dyn MacroScope) -> Self {
+ Self {
+ scopes: vec![scope],
+ }
+ }
+
+ pub fn with_scope(&self, new_scope: &'a dyn MacroScope) -> Self {
+ Self {
+ scopes: iter::once(new_scope).chain(self.scopes.clone()).collect(),
+ }
+ }
+
+ fn get(&self, name: &str) -> Option<Cow<Macro>> {
+ for scope in &self.scopes {
+ if let Some(r#macro) = scope.get(name) {
+ return Some(r#macro);
+ }
+ }
+ None
+ }
+
+ pub fn expand<#[cfg(feature = "full")] R: BufRead>(
+ &self,
+ text: &TokenString,
+ #[cfg(feature = "full")] mut eval_context: Option<&mut DeferredEvalContext<R>>,
+ ) -> eyre::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,
+ #[cfg(feature = "full")]
+ eval_context.as_deref_mut(),
+ )
+ .wrap_err_with(|| format!("while expanding \"{}\"", name))?;
+ let macro_value = self.get(&name).map_or_else(
+ || {
+ warn(format!("undefined macro {}", name));
+ Ok(String::new())
+ },
+ |x| {
+ self.expand(
+ &x.text,
+ #[cfg(feature = "full")]
+ 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,
+ #[cfg(feature = "full")]
+ eval_context.as_deref_mut(),
+ )?;
+ #[cfg(feature = "full")]
+ {
+ let (subst1, subst2) = if subst1.contains('%') {
+ (subst1, subst2.clone())
+ } else {
+ let mut real_subst2 = TokenString::text("%");
+ real_subst2.extend(subst2.clone());
+ (format!("%{}", subst1), real_subst2)
+ };
+ let args = [
+ TokenString::text(subst1),
+ subst2,
+ TokenString::text(macro_value),
+ ];
+ functions::expand_call(
+ "patsubst",
+ &args,
+ self,
+ eval_context.as_deref_mut(),
+ )?
+ }
+ #[cfg(not(feature = "full"))]
+ {
+ let subst1_suffix = regex::escape(&subst1);
+ let subst1_suffix =
+ Regex::new(&format!(r"{}(\s|$)", subst1_suffix))
+ .context("formed invalid regex somehow")?;
+ let subst2 = self.expand(subst2)?;
+ subst1_suffix
+ .replace_all(&macro_value, |c: &regex::Captures| {
+ format!("{}{}", subst2, c.get(1).unwrap().as_str())
+ })
+ .to_string()
+ }
+ }
+ None => macro_value,
+ };
+ log::trace!(
+ "expanded {} (from {:?}) into \"{}\"",
+ token,
+ self.get(&name).map(|x| x.source.clone()),
+ &macro_value
+ );
+ result.push_str(&macro_value);
+ }
+ #[cfg(feature = "full")]
+ Token::FunctionCall { name, args } => {
+ let name = self.expand(name, eval_context.as_deref_mut())?;
+ let fn_result =
+ functions::expand_call(&name, args, self, eval_context.as_deref_mut())?;
+ log::trace!("expanded {} into \"{}\"", token, &fn_result);
+ result.push_str(&fn_result);
+ }
+ }
+ }
+ Ok(result)
+ }
+
+ #[cfg(feature = "full")]
+ pub fn origin(&self, name: &str) -> &'static str {
+ match self.get(name).as_deref() {
+ None => "undefined",
+ Some(Macro {
+ source: ItemSource::Builtin,
+ ..
+ }) => "default",
+ Some(Macro {
+ source: ItemSource::Environment,
+ ..
+ }) => "environment",
+ // TODO figure out when to return "environment override"
+ Some(Macro {
+ source: ItemSource::File { .. },
+ ..
+ }) => "file",
+ Some(Macro {
+ source: ItemSource::CommandLineOrMakeflags,
+ ..
+ }) => "command line",
+ // TODO handle override
+ Some(Macro {
+ source: ItemSource::FunctionCall,
+ ..
+ }) => "automatic",
+ }
+ }
+}
diff --git a/src/makefile/mod.rs b/src/makefile/mod.rs
index 9255ebf..ddfac6f 100644
--- a/src/makefile/mod.rs
+++ b/src/makefile/mod.rs
@@ -12,7 +12,9 @@ use inference_rules::InferenceRule;
use input::FinishedMakefileReader;
pub use input::MakefileReader;
use lookup_internal::LookupInternal;
-use r#macro::{Macro, Set as MacroSet};
+pub use macro_scope::MacroScopeStack;
+use r#macro::Macro;
+pub use r#macro::Set as MacroSet;
use target::{DynamicTargetSet, Target};
use token::TokenString;
@@ -31,6 +33,7 @@ mod inference_rules;
mod input;
mod lookup_internal;
mod r#macro;
+mod macro_scope;
mod pattern;
mod target;
mod token;
@@ -51,7 +54,7 @@ pub enum ItemSource {
pub struct Makefile<'a> {
inference_rules: Vec<InferenceRule>,
builtin_inference_rules: Vec<InferenceRule>,
- pub macros: MacroSet<'static, 'static>,
+ pub macros: MacroSet,
targets: DynamicTargetSet,
pub first_non_special_target: Option<String>,
args: &'a Args,
@@ -157,9 +160,9 @@ impl<'a> Makefile<'a> {
self.update_target(&failed_include).wrap_err_with(|| {
format!("while building missing included file {}", &failed_include)
})?;
- let macros = self.macros.with_overlay();
+ let stack = MacroScopeStack::default().with_scope(&self.macros);
let file =
- MakefileReader::read_file(self.args, macros, failed_include, Default::default())?
+ MakefileReader::read_file(self.args, stack, failed_include, Default::default())?
.finish();
self.extend(file)?;
}
@@ -349,8 +352,9 @@ impl<'a> Makefile<'a> {
}
fn expand_macros(&self, text: &TokenString, target: Option<&Target>) -> Result<String> {
- self.macros
- .with_lookup(LookupInternal::new(target, &|name| self.get_target(name)))
+ MacroScopeStack::default()
+ .with_scope(&self.macros)
+ .with_scope(&LookupInternal::new(target, &|name| self.get_target(name)))
.expand(
text,
#[cfg(feature = "full")]