From 40920ea9d255f704116064d0b831666c7416caf2 Mon Sep 17 00:00:00 2001 From: Melody Horn Date: Sun, 28 Mar 2021 00:36:23 -0600 Subject: add (& somewhat test!) GNUful conditionals --- src/makefile/mod.rs | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'src/makefile/mod.rs') diff --git a/src/makefile/mod.rs b/src/makefile/mod.rs index 2f73c70..0d4cded 100644 --- a/src/makefile/mod.rs +++ b/src/makefile/mod.rs @@ -13,11 +13,13 @@ use regex::Regex; use crate::args::Args; mod command_line; +mod conditional; mod inference_rules; mod target; mod token; use command_line::CommandLine; +use conditional::{ConditionalLine, ConditionalState}; use inference_rules::InferenceRule; use target::Target; use token::{tokenize, Token, TokenString}; @@ -151,6 +153,7 @@ impl<'a> Makefile<'a> { pub(crate) fn and_read(&mut self, source: impl BufRead) { let mut lines_iter = source.lines().enumerate().peekable(); + let mut conditional_stack: Vec = vec![]; while let Some((line_number, line)) = lines_iter.next() { // TODO handle I/O errors at all let mut line = line.expect("failed to read line of makefile!"); @@ -170,6 +173,14 @@ impl<'a> Makefile<'a> { } let line = COMMENT.replace(&line, "").into_owned(); + // skip lines if we need to + if conditional_stack + .last() + .map_or(false, ConditionalState::skipping) + { + continue; + } + // handle include lines if let Some(line) = line.strip_prefix("include ") { // remove extra leading space @@ -181,6 +192,14 @@ impl<'a> Makefile<'a> { for field in fields { self.and_read_file(field); } + } else if let Some(line) = ConditionalLine::from(&line, |t| self.expand_macros(t, None)) + { + line.action( + conditional_stack.last(), + |name| self.macros.contains_key(name), + |t| self.expand_macros(t, None), + ) + .apply_to(&mut conditional_stack); } else if line.trim().is_empty() { // handle blank lines continue; @@ -728,3 +747,38 @@ fn builtin_targets() -> Vec { already_updated: Cell::new(false), }] } + +#[cfg(test)] +mod test { + use super::*; + + use std::io::Cursor; + + fn empty_makefile(args: &Args) -> Makefile { + Makefile { + inference_rules: vec![], + macros: HashMap::new(), + targets: RefCell::new(HashMap::new()), + first_non_special_target: None, + args, + } + } + + #[test] + fn basic_conditionals() { + let file = " +ifeq (1,1) +worked = yes +else ifeq (2,2) +worked = no +endif + "; + let args = Args::empty(); + let mut makefile = empty_makefile(&args); + makefile.and_read(Cursor::new(file)); + assert_eq!( + makefile.expand_macros(&"$(worked)".parse().unwrap(), None), + "yes" + ); + } +} -- cgit v1.2.3