From fc83bbbdd51b82fad6293f06c377be0409d6db26 Mon Sep 17 00:00:00 2001 From: Melody Horn Date: Mon, 5 Apr 2021 16:09:12 -0600 Subject: allow for fucking horrifying crimes fuck you linux for making me support this after all --- src/makefile/macro.rs | 8 ++++--- src/makefile/token.rs | 64 +++++++++++++++++++++++++++++++++------------------ 2 files changed, 47 insertions(+), 25 deletions(-) (limited to 'src') 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) -> 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, }, } @@ -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) -> Token { Token::MacroExpansion { - name: name.into(), + name: TokenString::text(name), replacement: None, } } @@ -346,7 +340,7 @@ mod test { subst2: impl Into, ) -> 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, args: Vec>) -> 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(()) + } } -- cgit v1.2.3