aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/makefile/functions.rs31
-rw-r--r--src/makefile/mod.rs4
-rw-r--r--src/makefile/token.rs96
3 files changed, 98 insertions, 33 deletions
diff --git a/src/makefile/functions.rs b/src/makefile/functions.rs
new file mode 100644
index 0000000..bc39886
--- /dev/null
+++ b/src/makefile/functions.rs
@@ -0,0 +1,31 @@
+use super::token::TokenString;
+
+pub(crate) fn call(name: &str, args: &[TokenString]) -> TokenString {
+ match name {
+ // Text Functions
+ "filter" => todo!(),
+ "filter-out" => todo!(),
+ "sort" => todo!(),
+
+ // File Name Functions
+ "notdir" => todo!(),
+ "basename" => todo!(),
+ "addprefix" => todo!(),
+ "wildcard" => todo!(),
+
+ // foreach
+ "foreach" => todo!(),
+
+ // call
+ "call" => todo!(),
+
+ // eval
+ "eval" => todo!(),
+
+ // shell
+ "shell" => todo!(),
+
+ // fallback
+ _ => panic!("function not implemented: {}", name),
+ }
+}
diff --git a/src/makefile/mod.rs b/src/makefile/mod.rs
index 0d4cded..1fc8303 100644
--- a/src/makefile/mod.rs
+++ b/src/makefile/mod.rs
@@ -14,6 +14,7 @@ use crate::args::Args;
mod command_line;
mod conditional;
+mod functions;
mod inference_rules;
mod target;
mod token;
@@ -592,6 +593,9 @@ impl<'a> Makefile<'a> {
};
result.push_str(&macro_value);
}
+ Token::FunctionCall { name, args } => {
+ result.push_str(&self.expand_macros(&functions::call(name, args), None));
+ }
}
}
result
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 {