aboutsummaryrefslogtreecommitdiff
path: root/src/makefile/token.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/makefile/token.rs')
-rw-r--r--src/makefile/token.rs96
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 {