diff options
author | Melody Horn <melody@boringcactus.com> | 2021-03-28 01:45:52 -0600 |
---|---|---|
committer | Melody Horn <melody@boringcactus.com> | 2021-03-28 01:45:52 -0600 |
commit | 82278c3a5aa93204c963a63cc3cfefea1d0fb3fd (patch) | |
tree | 88c7cb553025f98f5b3c81a1be174aaece9933af /src/makefile/token.rs | |
parent | 5b27bf30d0887bab761559113417de38597ba958 (diff) | |
download | makers-82278c3a5aa93204c963a63cc3cfefea1d0fb3fd.tar.gz makers-82278c3a5aa93204c963a63cc3cfefea1d0fb3fd.zip |
lay down boilerplate for function calls
of all the obnoxious GNUisms, this will probably wind up being the largest.
especially if huge makefiles (e.g. Linux) use most of the functions that GNU offers, meaning we have to implement most of them to be Linuxable
Diffstat (limited to 'src/makefile/token.rs')
-rw-r--r-- | src/makefile/token.rs | 96 |
1 files changed, 63 insertions, 33 deletions
diff --git a/src/makefile/token.rs b/src/makefile/token.rs index 86c442b..eca40ed 100644 --- a/src/makefile/token.rs +++ b/src/makefile/token.rs @@ -4,9 +4,9 @@ use std::str::FromStr; use nom::{ branch::alt, bytes::complete::{tag, take_till1, take_while1}, - character::complete::anychar, + character::complete::{anychar, space1}, combinator::{all_consuming, map, opt, verify}, - multi::many1, + multi::{many1, separated_list1}, sequence::{delimited, pair, preceded, separated_pair}, Finish, IResult, }; @@ -110,6 +110,10 @@ pub(crate) enum Token { name: String, replacement: Option<(TokenString, TokenString)>, }, + FunctionCall { + name: String, + args: Vec<TokenString>, + }, } impl fmt::Display for Token { @@ -124,34 +128,71 @@ impl fmt::Display for Token { name, replacement: Some((r1, r2)), } => write!(f, "$({}:{}={})", name, r1, r2), + Self::FunctionCall { name, args } => write!( + f, + "$({} {})", + name, + args.iter() + .map(|x| format!("{}", x)) + .collect::<Vec<_>>() + .join(", ") + ), } } } -fn macro_name(input: &str) -> IResult<&str, &str> { +fn macro_function_name(input: &str) -> IResult<&str, &str> { // POSIX says "periods, underscores, digits, and alphabetics from the portable character set" - take_while1(|c: char| c == '.' || c == '_' || c.is_alphanumeric())(input) + // one GNUism is a function with a - in the name + take_while1(|c: char| c == '.' || c == '_' || c.is_alphanumeric() || c == '-')(input) } -fn macro_expansion_body<'a>(end: char) -> impl FnMut(&'a str) -> IResult<&'a str, Token> { +fn macro_expansion_body<'a>(end: char) -> impl FnMut(&'a str) -> IResult<&'a str, Token> + 'a { let subst = preceded( tag(":"), - separated_pair(tokens_but_not('='), tag("="), tokens_but_not(end)), + separated_pair( + tokens_but_not(vec!['=']), + tag("="), + tokens_but_not(vec![end]), + ), ); - map(pair(macro_name, opt(subst)), |(name, replacement)| { - Token::MacroExpansion { + map( + pair(macro_function_name, opt(subst)), + |(name, replacement)| Token::MacroExpansion { name: name.into(), replacement, - } - }) + }, + ) +} + +fn function_call_body<'a>(end: char) -> impl FnMut(&'a str) -> IResult<&'a str, Token> { + map( + separated_pair( + macro_function_name, + space1, + separated_list1(tag(","), tokens_but_not(vec![',', end])), + ), + |(name, args)| Token::FunctionCall { + name: name.into(), + args, + }, + ) } fn parens_macro_expansion(input: &str) -> IResult<&str, Token> { - delimited(tag("$("), macro_expansion_body(')'), tag(")"))(input) + delimited( + tag("$("), + alt((macro_expansion_body(')'), function_call_body(')'))), + tag(")"), + )(input) } fn braces_macro_expansion(input: &str) -> IResult<&str, Token> { - delimited(tag("${"), macro_expansion_body('}'), tag("}"))(input) + delimited( + tag("${"), + alt((macro_expansion_body('}'), function_call_body(')'))), + tag("}"), + )(input) } fn tiny_macro_expansion(input: &str) -> IResult<&str, Token> { @@ -176,41 +217,30 @@ fn macro_expansion(input: &str) -> IResult<&str, Token> { ))(input) } -fn text(input: &str) -> IResult<&str, Token> { - map(take_till1(|c| c == '$'), |x: &str| Token::Text(x.into()))(input) -} - -fn text_but_not<'a>(end: char) -> impl FnMut(&'a str) -> IResult<&'a str, Token> { - map(take_till1(move |c| c == '$' || c == end), |x: &str| { - Token::Text(x.into()) - }) +fn text_but_not<'a>(ends: Vec<char>) -> impl FnMut(&'a str) -> IResult<&'a str, Token> { + map( + take_till1(move |c| c == '$' || ends.contains(&c)), + |x: &str| Token::Text(x.into()), + ) } -fn single_token(input: &str) -> IResult<&str, Token> { - alt((text, macro_expansion))(input) -} - -fn single_token_but_not<'a>(end: char) -> impl FnMut(&'a str) -> IResult<&'a str, Token> { - alt((text_but_not(end), macro_expansion)) +fn single_token_but_not<'a>(ends: Vec<char>) -> impl FnMut(&'a str) -> IResult<&'a str, Token> { + alt((text_but_not(ends), macro_expansion)) } fn empty_tokens(input: &str) -> IResult<&str, TokenString> { map(tag(""), |_| TokenString(vec![Token::Text(String::new())]))(input) } -fn tokens(input: &str) -> IResult<&str, TokenString> { - alt((map(many1(single_token), TokenString), empty_tokens))(input) -} - -fn tokens_but_not<'a>(end: char) -> impl FnMut(&'a str) -> IResult<&'a str, TokenString> { +fn tokens_but_not<'a>(ends: Vec<char>) -> impl FnMut(&'a str) -> IResult<&'a str, TokenString> { alt(( - map(many1(single_token_but_not(end)), TokenString), + map(many1(single_token_but_not(ends)), TokenString), empty_tokens, )) } fn full_text_tokens(input: &str) -> IResult<&str, TokenString> { - all_consuming(tokens)(input) + all_consuming(tokens_but_not(vec![]))(input) } pub(crate) fn tokenize(input: &str) -> TokenString { |