diff options
Diffstat (limited to 'src/makefile')
-rw-r--r-- | src/makefile/input.rs | 63 | ||||
-rw-r--r-- | src/makefile/macro.rs | 6 | ||||
-rw-r--r-- | src/makefile/mod.rs | 5 |
3 files changed, 49 insertions, 25 deletions
diff --git a/src/makefile/input.rs b/src/makefile/input.rs index aa744c8..42187f4 100644 --- a/src/makefile/input.rs +++ b/src/makefile/input.rs @@ -129,9 +129,9 @@ impl<T, E: StdError + Send + Sync + 'static, I: Iterator<Item = Result<T, E>>> I { } -pub struct MakefileReader<'a, R: BufRead> { +pub struct MakefileReader<'a, 'parent, R: BufRead> { pub inference_rules: Vec<InferenceRule>, - pub macros: MacroSet<'static, 'static>, + pub macros: MacroSet<'parent, 'static>, pub targets: HashMap<String, Target>, pub first_non_special_target: Option<String>, args: &'a Args, @@ -141,21 +141,25 @@ pub struct MakefileReader<'a, R: BufRead> { conditional_stack: Vec<ConditionalState>, } -impl<'a> MakefileReader<'a, BufReader<File>> { - pub fn read_file(args: &'a Args, path: impl AsRef<Path>) -> Result<Self> { +impl<'a, 'parent> MakefileReader<'a, 'parent, BufReader<File>> { + pub fn read_file( + args: &'a Args, + macros: MacroSet<'parent, 'static>, + path: impl AsRef<Path>, + ) -> Result<Self> { let file = File::open(path); // TODO handle errors let file = file.context("couldn't open makefile!")?; let file_reader = BufReader::new(file); - Self::read(args, file_reader) + Self::read(args, macros, file_reader) } } -impl<'a, R: BufRead> MakefileReader<'a, R> { - pub fn read(args: &'a Args, source: R) -> Result<Self> { +impl<'a, 'parent, R: BufRead> MakefileReader<'a, 'parent, R> { + pub fn read(args: &'a Args, macros: MacroSet<'parent, 'static>, source: R) -> Result<Self> { let mut reader = Self { inference_rules: Vec::new(), - macros: MacroSet::new(), + macros, targets: HashMap::new(), first_non_special_target: None, args, @@ -181,10 +185,11 @@ impl<'a, R: BufRead> MakefileReader<'a, R> { // POSIX says we only have to handle a single filename, but GNU make // handles arbitrarily many filenames, and it's not like that's more work for field in fields { - self.extend( - MakefileReader::read_file(self.args, field) - .with_context(|| format!("while including {}", field))?, - ); + let child_macros = self.macros.with_overlay(); + let child = MakefileReader::read_file(self.args, child_macros, field) + .with_context(|| format!("while including {}", field))? + .finish(); + self.extend(child); } continue; } @@ -211,10 +216,12 @@ impl<'a, R: BufRead> MakefileReader<'a, R> { { let eval = self.macros.to_eval.take(); for eval in eval { - self.extend( - MakefileReader::read(self.args, Cursor::new(eval)) - .context("while evaling")?, - ); + let child_macros = self.macros.with_overlay(); + let child = + MakefileReader::read(self.args, child_macros, Cursor::new(eval)) + .context("while evaling")? + .finish(); + self.extend(child); } } let line_type = LineType::of(&line_tokens); @@ -501,7 +508,16 @@ impl<'a, R: BufRead> MakefileReader<'a, R> { self.macros.expand(text) } - fn extend<R2: BufRead>(&mut self, new: MakefileReader<R2>) { + pub fn finish(self) -> FinishedMakefileReader { + FinishedMakefileReader { + inference_rules: self.inference_rules, + macros: self.macros.data, + targets: self.targets, + first_non_special_target: self.first_non_special_target, + } + } + + fn extend(&mut self, new: FinishedMakefileReader) { self.inference_rules.extend(new.inference_rules); self.macros.extend(new.macros); self.targets.extend(new.targets); @@ -511,6 +527,13 @@ impl<'a, R: BufRead> MakefileReader<'a, R> { } } +pub struct FinishedMakefileReader { + pub inference_rules: Vec<InferenceRule>, + pub macros: HashMap<String, (MacroSource, TokenString)>, + pub targets: HashMap<String, Target>, + pub first_non_special_target: Option<String>, +} + #[cfg(test)] mod test { use super::*; @@ -530,7 +553,7 @@ worked = perhaps endif "; let args = Args::empty(); - let makefile = MakefileReader::read(&args, Cursor::new(file))?; + let makefile = MakefileReader::read(&args, MacroSet::new(), Cursor::new(file))?; assert_eq!( makefile.expand_macros(&TokenString::r#macro("worked"))?, "yes" @@ -548,7 +571,7 @@ baz endef "; let args = Args::empty(); - let makefile = MakefileReader::read(&args, Cursor::new(file))?; + let makefile = MakefileReader::read(&args, MacroSet::new(), Cursor::new(file))?; assert_eq!( makefile.expand_macros(&TokenString::r#macro("foo"))?, "bar\nbaz" @@ -593,7 +616,7 @@ clean: "; let args = Args::empty(); - let makefile = MakefileReader::read(&args, Cursor::new(file))?; + let makefile = MakefileReader::read(&args, MacroSet::new(), Cursor::new(file))?; assert!(makefile.targets.contains_key("server")); Ok(()) } diff --git a/src/makefile/macro.rs b/src/makefile/macro.rs index a1f2378..310994d 100644 --- a/src/makefile/macro.rs +++ b/src/makefile/macro.rs @@ -28,7 +28,7 @@ impl<F: for<'a> Fn(&'a str) -> Result<String>> LookupInternal for F {} #[derive(Clone)] pub struct Set<'parent, 'lookup> { parent: Option<&'parent Set<'parent, 'lookup>>, - data: HashMap<String, (Source, TokenString)>, + pub data: HashMap<String, (Source, TokenString)>, lookup_internal: Option<&'lookup dyn LookupInternal>, #[cfg(feature = "full")] pub to_eval: Rc<RefCell<Vec<String>>>, @@ -93,8 +93,8 @@ impl<'parent, 'lookup> Set<'parent, 'lookup> { self.data.remove(name) } - pub fn extend(&mut self, other: Set) { - self.data.extend(other.data); + pub fn extend(&mut self, other: HashMap<String, (Source, TokenString)>) { + self.data.extend(other); } pub fn expand(&self, text: &TokenString) -> Result<String> { diff --git a/src/makefile/mod.rs b/src/makefile/mod.rs index 88a3abb..3d824b9 100644 --- a/src/makefile/mod.rs +++ b/src/makefile/mod.rs @@ -24,6 +24,7 @@ mod token; use command_line::CommandLine; use inference_rules::InferenceRule; +use input::FinishedMakefileReader; pub use input::MakefileReader; use r#macro::{Set as MacroSet, Source as MacroSource}; use target::Target; @@ -31,7 +32,7 @@ use token::TokenString; pub struct Makefile<'a> { inference_rules: Vec<InferenceRule>, - macros: MacroSet<'static, 'static>, + pub macros: MacroSet<'static, 'static>, targets: RefCell<HashMap<String, Rc<RefCell<Target>>>>, pub first_non_special_target: Option<String>, args: &'a Args, @@ -76,7 +77,7 @@ impl<'a> Makefile<'a> { } } - pub fn extend<R: std::io::BufRead>(&mut self, new: MakefileReader<R>) { + pub fn extend(&mut self, new: FinishedMakefileReader) { self.inference_rules.extend(new.inference_rules); self.macros.extend(new.macros); self.targets.borrow_mut().extend( |