From 441b137307ba5fbc22d0d32dca6e5c0f9559dbf5 Mon Sep 17 00:00:00 2001 From: Melody Horn Date: Fri, 2 Apr 2021 20:37:54 -0600 Subject: implement define blocks --- src/makefile/mod.rs | 64 ++++++++++++++++++++++++++++++++++++++++++++++----- src/makefile/token.rs | 5 +--- 2 files changed, 59 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/makefile/mod.rs b/src/makefile/mod.rs index f4f0853..fb92a01 100644 --- a/src/makefile/mod.rs +++ b/src/makefile/mod.rs @@ -42,6 +42,10 @@ enum LineType { impl LineType { fn of(line_tokens: &TokenString) -> Self { + #[cfg(feature = "full")] + if line_tokens.starts_with("define ") { + return Self::Macro; + } for token in line_tokens.tokens() { if let Token::Text(text) = token { let colon_idx = text.find(':'); @@ -242,7 +246,9 @@ impl<'a> Makefile<'a> { match line_type { LineType::Rule => self.read_rule(&line_tokens, line_number, &mut lines_iter)?, - LineType::Macro => self.read_macro(&line_tokens, line_number)?, + LineType::Macro => { + self.read_macro(line_tokens, line_number, &mut lines_iter)? + } LineType::Unknown => { if !line_tokens.is_empty() { bail!( @@ -377,10 +383,37 @@ impl<'a> Makefile<'a> { Ok(()) } - fn read_macro(&mut self, line_tokens: &TokenString, line_number: usize) -> Result<()> { - let (name, mut value) = line_tokens - .split_once('=') - .ok_or_else(|| eyre!("read_rule couldn't find a ':' on line {}", line_number))?; + fn read_macro( + &mut self, + mut line_tokens: TokenString, + line_number: usize, + lines_iter: &mut Peekable)>>, + ) -> Result<()> { + let (name, mut value) = if cfg!(feature = "full") && line_tokens.starts_with("define ") { + line_tokens.strip_prefix("define "); + if line_tokens.ends_with("=") { + line_tokens.strip_suffix("="); + line_tokens.trim_end(); + } + let mut value = TokenString::from(vec![]); + for (_, line) in lines_iter { + let line = line?; + if line == "endef" { + break; + } + dbg!(&value, &line); + if !value.is_empty() { + value.extend(TokenString::text("\n")); + } + value.extend(line.parse()?); + dbg!(&value); + } + (line_tokens, value) + } else { + line_tokens + .split_once('=') + .ok_or_else(|| eyre!("read_rule couldn't find a ':' on line {}", line_number))? + }; let name = self.expand_macros(&name, None)?; // GNUisms are annoying, but popular let mut expand_value = false; @@ -762,8 +795,27 @@ endif Ok(()) } + #[cfg(feature = "full")] + #[test] + fn define_syntax() -> R { + let file = " +define foo = +bar +baz +endef + "; + let args = Args::empty(); + let mut makefile = empty_makefile(&args); + makefile.and_read(Cursor::new(file))?; + assert_eq!( + makefile.expand_macros(&TokenString::r#macro("foo"), None)?, + "bar\nbaz" + ); + Ok(()) + } + #[test] - #[ignore = "I still haven't implemented `eval` or `define` or %-based macro substitution."] + #[ignore = "I still haven't implemented `eval` or %-based macro substitution."] fn eval() -> R { // This, for the record, is a terrible misfeature. // If you need this, you probably shouldn't be using Make. diff --git a/src/makefile/token.rs b/src/makefile/token.rs index 271580a..3bb9f4e 100644 --- a/src/makefile/token.rs +++ b/src/makefile/token.rs @@ -63,7 +63,6 @@ impl TokenString { None } - #[cfg(feature = "full")] pub fn starts_with(&self, pattern: &str) -> bool { match self.0.first() { Some(Token::Text(t)) => t.starts_with(pattern), @@ -78,7 +77,6 @@ impl TokenString { } } - #[cfg(feature = "full")] pub fn strip_prefix(&mut self, suffix: &str) { if let Some(Token::Text(t)) = self.0.first_mut() { if let Some(x) = t.strip_prefix(suffix) { @@ -105,7 +103,6 @@ impl TokenString { } } - #[cfg(feature = "full")] pub fn trim_end(&mut self) { if let Some(Token::Text(t)) = self.0.last_mut() { *t = t.trim_end().into(); @@ -115,7 +112,7 @@ impl TokenString { pub fn is_empty(&self) -> bool { match self.0.get(0) { None => true, - Some(Token::Text(t)) if t.is_empty() => true, + Some(Token::Text(t)) if t.is_empty() && self.0.len() == 1 => true, _ => false, } } -- cgit v1.2.3