diff options
| -rw-r--r-- | src/makefile/token.rs | 91 | 
1 files changed, 54 insertions, 37 deletions
| diff --git a/src/makefile/token.rs b/src/makefile/token.rs index a79598a..ca50fe7 100644 --- a/src/makefile/token.rs +++ b/src/makefile/token.rs @@ -9,7 +9,7 @@ use nom::{      combinator::{all_consuming, map, opt, verify},      error::{context, convert_error, ContextError, ParseError, VerboseError},      multi::fold_many1, -    sequence::{delimited, pair, preceded, separated_pair}, +    sequence::{delimited, pair, preceded, separated_pair, tuple},      Finish, IResult,  };  #[cfg(feature = "full")] @@ -105,7 +105,15 @@ impl TokenString {      }      pub fn extend(&mut self, other: Self) { -        self.0.extend(other.0); +        let mut incoming = other.0.into_iter().peekable(); +        if let Some(Token::Text(text)) = self.0.last_mut() { +            while let Some(Token::Text(incoming_text)) = +                incoming.next_if(|x| matches!(x, Token::Text(_))) +            { +                text.push_str(&incoming_text); +            } +        } +        self.0.extend(incoming);      }      pub fn trim_start(&mut self) { @@ -192,6 +200,13 @@ impl Delimiter {          }      } +    fn start_char(&self) -> char { +        match self { +            Self::Parens => '(', +            Self::Braces => '{', +        } +    } +      fn end(&self) -> &'static str {          match self {              Self::Parens => ")", @@ -210,7 +225,7 @@ fn macro_function_name<'a, E: Err<'a>>(  fn macro_expansion_body<'a, E: Err<'a>>(      end: char,      delim: Delimiter, -) -> impl FnMut(&'a str) -> IResult<&'a str, Token, E> + 'a { +) -> impl FnMut(&'a str) -> IResult<&'a str, TokenString, E> + 'a {      let subst = preceded(          tag(":"),          separated_pair( @@ -223,7 +238,7 @@ fn macro_expansion_body<'a, E: Err<'a>>(          "macro_expansion_body",          map(              pair(macro_function_name(end, delim), opt(subst)), -            |(name, replacement)| Token::MacroExpansion { name, replacement }, +            |(name, replacement)| TokenString::just(Token::MacroExpansion { name, replacement }),          ),      )  } @@ -232,7 +247,7 @@ fn macro_expansion_body<'a, E: Err<'a>>(  fn function_call_body<'a, E: Err<'a>>(      end: char,      delim: Delimiter, -) -> impl FnMut(&'a str) -> IResult<&'a str, Token, E> { +) -> impl FnMut(&'a str) -> IResult<&'a str, TokenString, E> {      context(          "function_call_body",          map( @@ -244,7 +259,7 @@ fn function_call_body<'a, E: Err<'a>>(                      tokens_but_not(vec![',', end], delim),                  ),              ), -            |(name, args)| Token::FunctionCall { name, args }, +            |(name, args)| TokenString::just(Token::FunctionCall { name, args }),          ),      )  } @@ -253,7 +268,7 @@ fn function_call_body<'a, E: Err<'a>>(  fn macro_body<'a, E: Err<'a>>(      end: char,      context: Delimiter, -) -> impl FnMut(&'a str) -> IResult<&'a str, Token, E> { +) -> impl FnMut(&'a str) -> IResult<&'a str, TokenString, E> {      alt((          function_call_body(end, context),          macro_expansion_body(end, context), @@ -261,28 +276,27 @@ fn macro_body<'a, E: Err<'a>>(  }  #[cfg(not(feature = "full"))] -fn macro_body<'a, E: Err<'a>>(end: char) -> impl FnMut(&'a str) -> IResult<&'a str, Token, E> { +fn macro_body<'a, E: Err<'a>>( +    end: char, +) -> impl FnMut(&'a str) -> IResult<&'a str, TokenString, E> {      macro_expansion_body(end)  } -fn parens_macro_expansion<'a, E: Err<'a>>(input: &'a str) -> IResult<&'a str, Token, E> { +fn parens_macro_expansion<'a, E: Err<'a>>(input: &'a str) -> IResult<&'a str, TokenString, E> {      delimited(tag("$("), macro_body(')', Delimiter::Parens), tag(")"))(input)  } -fn braces_macro_expansion<'a, E: Err<'a>>(input: &'a str) -> IResult<&'a str, Token, E> { -    delimited(tag("${"), macro_body('}', Delimiter::Parens), tag("}"))(input) +fn braces_macro_expansion<'a, E: Err<'a>>(input: &'a str) -> IResult<&'a str, TokenString, E> { +    delimited(tag("${"), macro_body('}', Delimiter::Braces), tag("}"))(input)  } -fn tiny_macro_expansion<'a, E: Err<'a>>(input: &'a str) -> IResult<&'a str, Token, E> { +fn tiny_macro_expansion<'a, E: Err<'a>>(input: &'a str) -> IResult<&'a str, TokenString, E> {      let raw = preceded(tag("$"), verify(anychar, |&c| c != '(' && c != '{'));      map(raw, |c| {          if c == '$' { -            Token::Text("$".into()) +            TokenString::text("$")          } else { -            Token::MacroExpansion { -                name: TokenString::text(c), -                replacement: None, -            } +            TokenString::r#macro(c)          }      })(input)  } @@ -290,14 +304,11 @@ fn tiny_macro_expansion<'a, E: Err<'a>>(input: &'a str) -> IResult<&'a str, Toke  fn macro_expansion<'a, E: Err<'a>>(input: &'a str) -> IResult<&'a str, TokenString, E> {      context(          "macro_expansion", -        map( -            alt(( -                tiny_macro_expansion, -                parens_macro_expansion, -                braces_macro_expansion, -            )), -            TokenString::just, -        ), +        alt(( +            tiny_macro_expansion, +            parens_macro_expansion, +            braces_macro_expansion, +        )),      )(input)  } @@ -314,10 +325,18 @@ fn nested_delimiters<'a, E: Err<'a>>(      ends: Vec<char>,      context: Delimiter,  ) -> impl FnMut(&'a str) -> IResult<&'a str, TokenString, E> { -    delimited( -        tag(context.start()), -        tokens_but_not(ends, context), -        tag(context.end()), +    map( +        tuple(( +            tag(context.start()), +            move |x| tokens_but_not(ends.clone(), context)(x), +            tag(context.end()), +        )), +        |(left, center, right)| { +            let mut tokens = TokenString::text(left); +            tokens.extend(center); +            tokens.extend(TokenString::text(right)); +            tokens +        },      )  } @@ -325,10 +344,12 @@ fn single_token_but_not<'a, E: Err<'a>>(      ends: Vec<char>,      context: Delimiter,  ) -> impl FnMut(&'a str) -> IResult<&'a str, TokenString, E> { +    let mut tbn_ends = ends.clone(); +    tbn_ends.push(context.start_char());      alt(( -        text_but_not(ends.clone()), +        text_but_not(tbn_ends),          macro_expansion, -        nested_delimiters(ends, context), +        nested_delimiters(ends.clone(), context),      ))  } @@ -461,11 +482,7 @@ mod test {          let tokens = tokenize(text)?;          assert_eq!(              tokens, -            TokenString(vec![ -                token_text("This costs "), -                token_text("$"), -                token_text("2 to run, which isn't ideal"), -            ]) +            TokenString(vec![token_text("This costs $2 to run, which isn't ideal"),])          );          Ok(())      } @@ -573,7 +590,7 @@ mod test {              tokens,              TokenString(vec![Token::FunctionCall {                  name: TokenString::text("shell"), -                args: vec![TokenString::text("echo (hi) (bro) (yeet)")], +                args: vec![TokenString::text("echo (hi) (bro) yeet")],              }])          );          Ok(()) |