diff options
| -rw-r--r-- | src/makefile/macro.rs | 8 | ||||
| -rw-r--r-- | src/makefile/token.rs | 64 | 
2 files changed, 47 insertions, 25 deletions
| diff --git a/src/makefile/macro.rs b/src/makefile/macro.rs index 43aff90..a6dcb74 100644 --- a/src/makefile/macro.rs +++ b/src/makefile/macro.rs @@ -103,6 +103,7 @@ impl<'parent, 'lookup> Set<'parent, 'lookup> {              match token {                  Token::Text(t) => result.push_str(t),                  Token::MacroExpansion { name, replacement } => { +                    let name = self.expand(name)?;                      let internal_macro_names = &['@', '?', '<', '*'][..];                      let internal_macro_suffices = &['D', 'F'][..];                      let just_internal = name.len() == 1 && name.starts_with(internal_macro_names); @@ -110,9 +111,9 @@ impl<'parent, 'lookup> Set<'parent, 'lookup> {                          && name.starts_with(internal_macro_names)                          && name.ends_with(internal_macro_suffices);                      let macro_value = if just_internal || suffixed_internal { -                        self.lookup_internal(name)? +                        self.lookup_internal(&name)?                      } else { -                        self.get(name).map_or_else( +                        self.get(&name).map_or_else(                              || {                                  log::warn!("undefined macro {}", name);                                  Ok(String::new()) @@ -139,8 +140,9 @@ impl<'parent, 'lookup> Set<'parent, 'lookup> {                  }                  #[cfg(feature = "full")]                  Token::FunctionCall { name, args } => { +                    let name = self.expand(name)?;                      let fn_result = -                        functions::expand_call(name, args, self, Some(Rc::clone(&self.to_eval)))?; +                        functions::expand_call(&name, args, self, Some(Rc::clone(&self.to_eval)))?;                      log::trace!("expanded {} into \"{}\"", token, &fn_result);                      result.push_str(&fn_result);                  } diff --git a/src/makefile/token.rs b/src/makefile/token.rs index 44d8c8b..b880700 100644 --- a/src/makefile/token.rs +++ b/src/makefile/token.rs @@ -4,7 +4,7 @@ use std::str::FromStr;  use eyre::WrapErr;  use nom::{      branch::alt, -    bytes::complete::{tag, take_till1, take_while1}, +    bytes::complete::{tag, take_till1},      character::complete::anychar,      combinator::{all_consuming, map, opt, verify},      error::{context, convert_error, ContextError, ParseError, VerboseError}, @@ -37,7 +37,7 @@ impl TokenString {      #[cfg(feature = "full")]      pub fn r#macro(name: impl Into<String>) -> Self {          Self(vec![Token::MacroExpansion { -            name: name.into(), +            name: Self::text(name),              replacement: None,          }])      } @@ -138,12 +138,12 @@ impl fmt::Display for TokenString {  pub enum Token {      Text(String),      MacroExpansion { -        name: String, +        name: TokenString,          replacement: Option<(TokenString, TokenString)>,      },      #[cfg(feature = "full")]      FunctionCall { -        name: String, +        name: TokenString,          args: Vec<TokenString>,      },  } @@ -174,10 +174,10 @@ impl fmt::Display for Token {      }  } -fn macro_function_name<'a, E: Err<'a>>(input: &'a str) -> IResult<&'a str, &'a str, E> { -    // POSIX says "periods, underscores, digits, and alphabetics from the portable character set" -    // one GNUism is a function with a - in the name -    take_while1(|c: char| c == '.' || c == '_' || c.is_alphanumeric() || c == '-')(input) +fn macro_function_name<'a, E: Err<'a>>( +    end: char, +) -> impl FnMut(&'a str) -> IResult<&'a str, TokenString, E> + 'a { +    tokens_but_not(vec![':', '#', '=', ' ', end])  }  fn macro_expansion_body<'a, E: Err<'a>>( @@ -194,11 +194,8 @@ fn macro_expansion_body<'a, E: Err<'a>>(      context(          "macro_expansion_body",          map( -            pair(macro_function_name, opt(subst)), -            |(name, replacement)| Token::MacroExpansion { -                name: name.into(), -                replacement, -            }, +            pair(macro_function_name(end), opt(subst)), +            |(name, replacement)| Token::MacroExpansion { name, replacement },          ),      )  } @@ -211,14 +208,11 @@ fn function_call_body<'a, E: Err<'a>>(          "function_call_body",          map(              separated_pair( -                macro_function_name, +                macro_function_name(end),                  space1,                  separated_list1(pair(tag(","), space0), tokens_but_not(vec![',', end])),              ), -            |(name, args)| Token::FunctionCall { -                name: name.into(), -                args, -            }, +            |(name, args)| Token::FunctionCall { name, args },          ),      )  } @@ -248,7 +242,7 @@ fn tiny_macro_expansion<'a, E: Err<'a>>(input: &'a str) -> IResult<&'a str, Toke              Token::Text("$".into())          } else {              Token::MacroExpansion { -                name: c.to_string(), +                name: TokenString::text(c),                  replacement: None,              }          } @@ -335,7 +329,7 @@ mod test {      fn token_macro_expansion(name: impl Into<String>) -> Token {          Token::MacroExpansion { -            name: name.into(), +            name: TokenString::text(name),              replacement: None,          }      } @@ -346,7 +340,7 @@ mod test {          subst2: impl Into<TokenString>,      ) -> Token {          Token::MacroExpansion { -            name: name.into(), +            name: TokenString::text(name),              replacement: Some((subst1.into(), subst2.into())),          }      } @@ -354,7 +348,7 @@ mod test {      #[cfg(feature = "full")]      fn token_function_call(name: impl Into<String>, args: Vec<impl Into<TokenString>>) -> Token {          Token::FunctionCall { -            name: name.into(), +            name: TokenString::text(name),              args: args.into_iter().map(|x| x.into()).collect(),          }      } @@ -468,4 +462,30 @@ mod test {          );          Ok(())      } + +    #[test] +    fn triple_mega_deluxe_super_hell() -> R { +        let text = "$($($(a)b)c)"; +        let tokens = tokenize(text)?; +        assert_eq!( +            tokens, +            TokenString(vec![Token::MacroExpansion { +                name: TokenString(vec![ +                    Token::MacroExpansion { +                        name: TokenString(vec![ +                            Token::MacroExpansion { +                                name: TokenString::text("a"), +                                replacement: None, +                            }, +                            token_text("b"), +                        ]), +                        replacement: None, +                    }, +                    token_text("c") +                ]), +                replacement: None, +            }]), +        ); +        Ok(()) +    }  } |