diff options
Diffstat (limited to 'src/makefile/input.rs')
-rw-r--r-- | src/makefile/input.rs | 63 |
1 files changed, 43 insertions, 20 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(()) } |