aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMelody Horn <melody@boringcactus.com>2021-04-02 20:37:54 -0600
committerMelody Horn <melody@boringcactus.com>2021-04-02 20:37:54 -0600
commit441b137307ba5fbc22d0d32dca6e5c0f9559dbf5 (patch)
tree67c43c4ee2d9cf95fea2f5902eade86d7a6ae385
parent8b70f19427db3307135b4d8b2a7bca31fc1d1a71 (diff)
downloadmakers-441b137307ba5fbc22d0d32dca6e5c0f9559dbf5.tar.gz
makers-441b137307ba5fbc22d0d32dca6e5c0f9559dbf5.zip
implement define blocks
-rw-r--r--src/makefile/mod.rs64
-rw-r--r--src/makefile/token.rs5
2 files changed, 59 insertions, 10 deletions
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<impl Iterator<Item = (usize, Result<String>)>>,
+ ) -> 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,
}
}