Add variadic parameters that accept zero or more arguments (#645)
Add "star" variadic parameters that accept zero or more arguments, distinguished with a `*` in front of the parameter name.
This commit is contained in:
parent
63f51b5b48
commit
1ff619295c
@ -73,11 +73,14 @@ string : STRING
|
|||||||
sequence : expression ',' sequence
|
sequence : expression ',' sequence
|
||||||
| expression ','?
|
| expression ','?
|
||||||
|
|
||||||
recipe : '@'? NAME parameter* ('+' parameter)? ':' dependency* body?
|
recipe : '@'? NAME parameter* variadic? ':' dependency* body?
|
||||||
|
|
||||||
parameter : NAME
|
parameter : NAME
|
||||||
| NAME '=' value
|
| NAME '=' value
|
||||||
|
|
||||||
|
variadic : '*' parameter
|
||||||
|
| '+' parameter
|
||||||
|
|
||||||
dependency : NAME
|
dependency : NAME
|
||||||
| '(' NAME expression* ')
|
| '(' NAME expression* ')
|
||||||
|
|
||||||
|
15
README.adoc
15
README.adoc
@ -572,14 +572,14 @@ test triple=(arch + "-unknown-unknown"):
|
|||||||
./test {{triple}}
|
./test {{triple}}
|
||||||
```
|
```
|
||||||
|
|
||||||
The last parameter of a recipe may be variadic, indicated with a `+` before the argument name:
|
The last parameter of a recipe may be variadic, indicated with either a `+` or a `*` before the argument name:
|
||||||
|
|
||||||
```make
|
```make
|
||||||
backup +FILES:
|
backup +FILES:
|
||||||
scp {{FILES}} me@server.com:
|
scp {{FILES}} me@server.com:
|
||||||
```
|
```
|
||||||
|
|
||||||
Variadic parameters accept one or more arguments and expand to a string containing those arguments separated by spaces:
|
Variadic parameters prefixed with `+` accept _one or more_ arguments and expand to a string containing those arguments separated by spaces:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ just backup FAQ.md GRAMMAR.md
|
$ just backup FAQ.md GRAMMAR.md
|
||||||
@ -588,13 +588,20 @@ FAQ.md 100% 1831 1.8KB/s 00:00
|
|||||||
GRAMMAR.md 100% 1666 1.6KB/s 00:00
|
GRAMMAR.md 100% 1666 1.6KB/s 00:00
|
||||||
```
|
```
|
||||||
|
|
||||||
A variadic parameter with a default argument will accept zero or more arguments:
|
Variadic parameters prefixed with `*` accept _zero or more_ arguments and expand to a string containing those arguments separated by spaces, or an empty string if no arguments are present:
|
||||||
|
|
||||||
```make
|
```make
|
||||||
commit MESSAGE +FLAGS='':
|
commit MESSAGE *FLAGS:
|
||||||
git commit {{FLAGS}} -m "{{MESSAGE}}"
|
git commit {{FLAGS}} -m "{{MESSAGE}}"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Variadic parameters prefixed by `+` can be assigned default values. These are overridden by arguments passed on the command line:
|
||||||
|
|
||||||
|
```make
|
||||||
|
test +FLAGS='-q':
|
||||||
|
cargo test {{FLAGS}}
|
||||||
|
```
|
||||||
|
|
||||||
`{{...}}` substitutions may need to be quoted if they contains spaces. For example, if you have the following recipe:
|
`{{...}}` substitutions may need to be quoted if they contains spaces. For example, if you have the following recipe:
|
||||||
|
|
||||||
```make
|
```make
|
||||||
|
@ -56,11 +56,11 @@ pub(crate) use crate::{
|
|||||||
fragment::Fragment, function::Function, function_context::FunctionContext,
|
fragment::Fragment, function::Function, function_context::FunctionContext,
|
||||||
interrupt_guard::InterruptGuard, interrupt_handler::InterruptHandler, item::Item,
|
interrupt_guard::InterruptGuard, interrupt_handler::InterruptHandler, item::Item,
|
||||||
justfile::Justfile, lexer::Lexer, line::Line, list::List, load_error::LoadError, module::Module,
|
justfile::Justfile, lexer::Lexer, line::Line, list::List, load_error::LoadError, module::Module,
|
||||||
name::Name, output_error::OutputError, parameter::Parameter, parser::Parser, platform::Platform,
|
name::Name, output_error::OutputError, parameter::Parameter, parameter_kind::ParameterKind,
|
||||||
position::Position, positional::Positional, recipe::Recipe, recipe_context::RecipeContext,
|
parser::Parser, platform::Platform, position::Position, positional::Positional, recipe::Recipe,
|
||||||
recipe_resolver::RecipeResolver, runtime_error::RuntimeError, scope::Scope, search::Search,
|
recipe_context::RecipeContext, recipe_resolver::RecipeResolver, runtime_error::RuntimeError,
|
||||||
search_config::SearchConfig, search_error::SearchError, set::Set, setting::Setting,
|
scope::Scope, search::Search, search_config::SearchConfig, search_error::SearchError, set::Set,
|
||||||
settings::Settings, shebang::Shebang, show_whitespace::ShowWhitespace,
|
setting::Setting, settings::Settings, shebang::Shebang, show_whitespace::ShowWhitespace,
|
||||||
string_literal::StringLiteral, subcommand::Subcommand, suggestion::Suggestion, table::Table,
|
string_literal::StringLiteral, subcommand::Subcommand, suggestion::Suggestion, table::Table,
|
||||||
thunk::Thunk, token::Token, token_kind::TokenKind, unresolved_dependency::UnresolvedDependency,
|
thunk::Thunk, token::Token, token_kind::TokenKind, unresolved_dependency::UnresolvedDependency,
|
||||||
unresolved_recipe::UnresolvedRecipe, use_color::UseColor, variables::Variables,
|
unresolved_recipe::UnresolvedRecipe, use_color::UseColor, variables::Variables,
|
||||||
|
@ -192,12 +192,14 @@ impl<'src, 'run> Evaluator<'src, 'run> {
|
|||||||
let value = if rest.is_empty() {
|
let value = if rest.is_empty() {
|
||||||
if let Some(ref default) = parameter.default {
|
if let Some(ref default) = parameter.default {
|
||||||
evaluator.evaluate_expression(default)?
|
evaluator.evaluate_expression(default)?
|
||||||
|
} else if parameter.kind == ParameterKind::Star {
|
||||||
|
String::new()
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::Internal {
|
return Err(RuntimeError::Internal {
|
||||||
message: "missing parameter without default".to_string(),
|
message: "missing parameter without default".to_string(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if parameter.variadic {
|
} else if parameter.kind.is_variadic() {
|
||||||
let value = rest.to_vec().join(" ");
|
let value = rest.to_vec().join(" ");
|
||||||
rest = &[];
|
rest = &[];
|
||||||
value
|
value
|
||||||
|
@ -436,6 +436,7 @@ impl<'src> Lexer<'src> {
|
|||||||
/// Lex token beginning with `start` outside of a recipe body
|
/// Lex token beginning with `start` outside of a recipe body
|
||||||
fn lex_normal(&mut self, start: char) -> CompilationResult<'src, ()> {
|
fn lex_normal(&mut self, start: char) -> CompilationResult<'src, ()> {
|
||||||
match start {
|
match start {
|
||||||
|
'*' => self.lex_single(Asterisk),
|
||||||
'@' => self.lex_single(At),
|
'@' => self.lex_single(At),
|
||||||
'[' => self.lex_single(BracketL),
|
'[' => self.lex_single(BracketL),
|
||||||
']' => self.lex_single(BracketR),
|
']' => self.lex_single(BracketR),
|
||||||
@ -806,6 +807,7 @@ mod tests {
|
|||||||
fn default_lexeme(kind: TokenKind) -> &'static str {
|
fn default_lexeme(kind: TokenKind) -> &'static str {
|
||||||
match kind {
|
match kind {
|
||||||
// Fixed lexemes
|
// Fixed lexemes
|
||||||
|
Asterisk => "*",
|
||||||
At => "@",
|
At => "@",
|
||||||
BracketL => "[",
|
BracketL => "[",
|
||||||
BracketR => "]",
|
BracketR => "]",
|
||||||
|
@ -91,6 +91,7 @@ mod ordinal;
|
|||||||
mod output;
|
mod output;
|
||||||
mod output_error;
|
mod output_error;
|
||||||
mod parameter;
|
mod parameter;
|
||||||
|
mod parameter_kind;
|
||||||
mod parser;
|
mod parser;
|
||||||
mod platform;
|
mod platform;
|
||||||
mod platform_interface;
|
mod platform_interface;
|
||||||
|
@ -100,8 +100,8 @@ impl<'src> Node<'src> for UnresolvedRecipe<'src> {
|
|||||||
let mut params = Tree::atom("params");
|
let mut params = Tree::atom("params");
|
||||||
|
|
||||||
for parameter in &self.parameters {
|
for parameter in &self.parameters {
|
||||||
if parameter.variadic {
|
if let Some(prefix) = parameter.kind.prefix() {
|
||||||
params.push_mut("+");
|
params.push_mut(prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
params.push_mut(parameter.tree());
|
params.push_mut(parameter.tree());
|
||||||
|
@ -4,18 +4,18 @@ use crate::common::*;
|
|||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub(crate) struct Parameter<'src> {
|
pub(crate) struct Parameter<'src> {
|
||||||
/// The parameter name
|
/// The parameter name
|
||||||
pub(crate) name: Name<'src>,
|
pub(crate) name: Name<'src>,
|
||||||
/// Parameter is variadic
|
/// The kind of parameter
|
||||||
pub(crate) variadic: bool,
|
pub(crate) kind: ParameterKind,
|
||||||
/// An optional default expression
|
/// An optional default expression
|
||||||
pub(crate) default: Option<Expression<'src>>,
|
pub(crate) default: Option<Expression<'src>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'src> Display for Parameter<'src> {
|
impl<'src> Display for Parameter<'src> {
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
|
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
|
||||||
let color = Color::fmt(f);
|
let color = Color::fmt(f);
|
||||||
if self.variadic {
|
if let Some(prefix) = self.kind.prefix() {
|
||||||
write!(f, "{}", color.annotation().paint("+"))?;
|
write!(f, "{}", color.annotation().paint(prefix))?;
|
||||||
}
|
}
|
||||||
write!(f, "{}", color.parameter().paint(self.name.lexeme()))?;
|
write!(f, "{}", color.parameter().paint(self.name.lexeme()))?;
|
||||||
if let Some(ref default) = self.default {
|
if let Some(ref default) = self.default {
|
||||||
|
26
src/parameter_kind.rs
Normal file
26
src/parameter_kind.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
use crate::common::*;
|
||||||
|
|
||||||
|
/// Parameters can either be…
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
|
pub(crate) enum ParameterKind {
|
||||||
|
/// …singular, accepting a single argument
|
||||||
|
Singular,
|
||||||
|
/// …variadic, accepting one or more arguments
|
||||||
|
Plus,
|
||||||
|
/// …variadic, accepting zero or more arguments
|
||||||
|
Star,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParameterKind {
|
||||||
|
pub(crate) fn prefix(self) -> Option<&'static str> {
|
||||||
|
match self {
|
||||||
|
Self::Singular => None,
|
||||||
|
Self::Plus => Some("+"),
|
||||||
|
Self::Star => Some("*"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn is_variadic(self) -> bool {
|
||||||
|
self != Self::Singular
|
||||||
|
}
|
||||||
|
}
|
@ -494,11 +494,19 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
|
|||||||
let mut positional = Vec::new();
|
let mut positional = Vec::new();
|
||||||
|
|
||||||
while self.next_is(Identifier) {
|
while self.next_is(Identifier) {
|
||||||
positional.push(self.parse_parameter(false)?);
|
positional.push(self.parse_parameter(ParameterKind::Singular)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
let variadic = if self.accepted(Plus)? {
|
let kind = if self.accepted(Plus)? {
|
||||||
let variadic = self.parse_parameter(true)?;
|
ParameterKind::Plus
|
||||||
|
} else if self.accepted(Asterisk)? {
|
||||||
|
ParameterKind::Star
|
||||||
|
} else {
|
||||||
|
ParameterKind::Singular
|
||||||
|
};
|
||||||
|
|
||||||
|
let variadic = if kind.is_variadic() {
|
||||||
|
let variadic = self.parse_parameter(kind)?;
|
||||||
|
|
||||||
if let Some(identifier) = self.accept(Identifier)? {
|
if let Some(identifier) = self.accept(Identifier)? {
|
||||||
return Err(
|
return Err(
|
||||||
@ -560,7 +568,7 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a recipe parameter
|
/// Parse a recipe parameter
|
||||||
fn parse_parameter(&mut self, variadic: bool) -> CompilationResult<'src, Parameter<'src>> {
|
fn parse_parameter(&mut self, kind: ParameterKind) -> CompilationResult<'src, Parameter<'src>> {
|
||||||
let name = self.parse_name()?;
|
let name = self.parse_name()?;
|
||||||
|
|
||||||
let default = if self.accepted(Equals)? {
|
let default = if self.accepted(Equals)? {
|
||||||
@ -571,8 +579,8 @@ impl<'tokens, 'src> Parser<'tokens, 'src> {
|
|||||||
|
|
||||||
Ok(Parameter {
|
Ok(Parameter {
|
||||||
name,
|
name,
|
||||||
|
kind,
|
||||||
default,
|
default,
|
||||||
variadic,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -917,11 +925,17 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test! {
|
test! {
|
||||||
name: recipe_variadic,
|
name: recipe_plus_variadic,
|
||||||
text: r#"foo +bar:"#,
|
text: r#"foo +bar:"#,
|
||||||
tree: (justfile (recipe foo (params +(bar)))),
|
tree: (justfile (recipe foo (params +(bar)))),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test! {
|
||||||
|
name: recipe_star_variadic,
|
||||||
|
text: r#"foo *bar:"#,
|
||||||
|
tree: (justfile (recipe foo (params *(bar)))),
|
||||||
|
}
|
||||||
|
|
||||||
test! {
|
test! {
|
||||||
name: recipe_variadic_string_default,
|
name: recipe_variadic_string_default,
|
||||||
text: r#"foo +bar="baz":"#,
|
text: r#"foo +bar="baz":"#,
|
||||||
|
@ -44,12 +44,12 @@ impl<'src, D> Recipe<'src, D> {
|
|||||||
self
|
self
|
||||||
.parameters
|
.parameters
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|p| p.default.is_none())
|
.filter(|p| p.default.is_none() && p.kind != ParameterKind::Star)
|
||||||
.count()
|
.count()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn max_arguments(&self) -> usize {
|
pub(crate) fn max_arguments(&self) -> usize {
|
||||||
if self.parameters.iter().any(|p| p.variadic) {
|
if self.parameters.iter().any(|p| p.kind.is_variadic()) {
|
||||||
usize::max_value() - 1
|
usize::max_value() - 1
|
||||||
} else {
|
} else {
|
||||||
self.parameters.len()
|
self.parameters.len()
|
||||||
|
@ -2,6 +2,7 @@ use crate::common::*;
|
|||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy, Ord, PartialOrd, Eq)]
|
#[derive(Debug, PartialEq, Clone, Copy, Ord, PartialOrd, Eq)]
|
||||||
pub(crate) enum TokenKind {
|
pub(crate) enum TokenKind {
|
||||||
|
Asterisk,
|
||||||
At,
|
At,
|
||||||
Backtick,
|
Backtick,
|
||||||
BracketL,
|
BracketL,
|
||||||
@ -32,6 +33,7 @@ impl Display for TokenKind {
|
|||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
|
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
|
||||||
use TokenKind::*;
|
use TokenKind::*;
|
||||||
write!(f, "{}", match *self {
|
write!(f, "{}", match *self {
|
||||||
|
Asterisk => "'*'",
|
||||||
At => "'@'",
|
At => "'@'",
|
||||||
Backtick => "backtick",
|
Backtick => "backtick",
|
||||||
BracketL => "'['",
|
BracketL => "'['",
|
||||||
|
@ -35,6 +35,12 @@ macro_rules! tree {
|
|||||||
} => {
|
} => {
|
||||||
$crate::tree::Tree::atom("+")
|
$crate::tree::Tree::atom("+")
|
||||||
};
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
*
|
||||||
|
} => {
|
||||||
|
$crate::tree::Tree::atom("*")
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A `Tree` is either…
|
/// A `Tree` is either…
|
||||||
|
@ -1081,7 +1081,7 @@ test! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test! {
|
test! {
|
||||||
name: required_after_variadic,
|
name: required_after_plus_variadic,
|
||||||
justfile: "bar:\nhello baz +arg bar:",
|
justfile: "bar:\nhello baz +arg bar:",
|
||||||
stdout: "",
|
stdout: "",
|
||||||
stderr: "error: Parameter `bar` follows variadic parameter
|
stderr: "error: Parameter `bar` follows variadic parameter
|
||||||
@ -1092,6 +1092,18 @@ test! {
|
|||||||
status: EXIT_FAILURE,
|
status: EXIT_FAILURE,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test! {
|
||||||
|
name: required_after_star_variadic,
|
||||||
|
justfile: "bar:\nhello baz *arg bar:",
|
||||||
|
stdout: "",
|
||||||
|
stderr: "error: Parameter `bar` follows variadic parameter
|
||||||
|
|
|
||||||
|
2 | hello baz *arg bar:
|
||||||
|
| ^^^
|
||||||
|
",
|
||||||
|
status: EXIT_FAILURE,
|
||||||
|
}
|
||||||
|
|
||||||
test! {
|
test! {
|
||||||
name: use_string_default,
|
name: use_string_default,
|
||||||
justfile: r#"
|
justfile: r#"
|
||||||
@ -1781,7 +1793,7 @@ a b= ":
|
|||||||
}
|
}
|
||||||
|
|
||||||
test! {
|
test! {
|
||||||
name: variadic_recipe,
|
name: plus_variadic_recipe,
|
||||||
justfile: "
|
justfile: "
|
||||||
a x y +z:
|
a x y +z:
|
||||||
echo {{x}} {{y}} {{z}}
|
echo {{x}} {{y}} {{z}}
|
||||||
@ -1792,7 +1804,7 @@ a x y +z:
|
|||||||
}
|
}
|
||||||
|
|
||||||
test! {
|
test! {
|
||||||
name: variadic_ignore_default,
|
name: plus_variadic_ignore_default,
|
||||||
justfile: "
|
justfile: "
|
||||||
a x y +z='HELLO':
|
a x y +z='HELLO':
|
||||||
echo {{x}} {{y}} {{z}}
|
echo {{x}} {{y}} {{z}}
|
||||||
@ -1803,7 +1815,7 @@ a x y +z='HELLO':
|
|||||||
}
|
}
|
||||||
|
|
||||||
test! {
|
test! {
|
||||||
name: variadic_use_default,
|
name: plus_variadic_use_default,
|
||||||
justfile: "
|
justfile: "
|
||||||
a x y +z='HELLO':
|
a x y +z='HELLO':
|
||||||
echo {{x}} {{y}} {{z}}
|
echo {{x}} {{y}} {{z}}
|
||||||
@ -1814,7 +1826,7 @@ a x y +z='HELLO':
|
|||||||
}
|
}
|
||||||
|
|
||||||
test! {
|
test! {
|
||||||
name: variadic_too_few,
|
name: plus_variadic_too_few,
|
||||||
justfile: "
|
justfile: "
|
||||||
a x y +z:
|
a x y +z:
|
||||||
echo {{x}} {{y}} {{z}}
|
echo {{x}} {{y}} {{z}}
|
||||||
@ -1825,6 +1837,80 @@ a x y +z:
|
|||||||
status: EXIT_FAILURE,
|
status: EXIT_FAILURE,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test! {
|
||||||
|
name: star_variadic_recipe,
|
||||||
|
justfile: "
|
||||||
|
a x y *z:
|
||||||
|
echo {{x}} {{y}} {{z}}
|
||||||
|
",
|
||||||
|
args: ("a", "0", "1", "2", "3", " 4 "),
|
||||||
|
stdout: "0 1 2 3 4\n",
|
||||||
|
stderr: "echo 0 1 2 3 4 \n",
|
||||||
|
}
|
||||||
|
|
||||||
|
test! {
|
||||||
|
name: star_variadic_none,
|
||||||
|
justfile: "
|
||||||
|
a x y *z:
|
||||||
|
echo {{x}} {{y}} {{z}}
|
||||||
|
",
|
||||||
|
args: ("a", "0", "1"),
|
||||||
|
stdout: "0 1\n",
|
||||||
|
stderr: "echo 0 1 \n",
|
||||||
|
}
|
||||||
|
|
||||||
|
test! {
|
||||||
|
name: star_variadic_ignore_default,
|
||||||
|
justfile: "
|
||||||
|
a x y *z='HELLO':
|
||||||
|
echo {{x}} {{y}} {{z}}
|
||||||
|
",
|
||||||
|
args: ("a", "0", "1", "2", "3", " 4 "),
|
||||||
|
stdout: "0 1 2 3 4\n",
|
||||||
|
stderr: "echo 0 1 2 3 4 \n",
|
||||||
|
}
|
||||||
|
|
||||||
|
test! {
|
||||||
|
name: star_variadic_use_default,
|
||||||
|
justfile: "
|
||||||
|
a x y *z='HELLO':
|
||||||
|
echo {{x}} {{y}} {{z}}
|
||||||
|
",
|
||||||
|
args: ("a", "0", "1"),
|
||||||
|
stdout: "0 1 HELLO\n",
|
||||||
|
stderr: "echo 0 1 HELLO\n",
|
||||||
|
}
|
||||||
|
|
||||||
|
test! {
|
||||||
|
name: star_then_plus_variadic,
|
||||||
|
justfile: "
|
||||||
|
foo *a +b:
|
||||||
|
echo {{a}} {{b}}
|
||||||
|
",
|
||||||
|
stdout: "",
|
||||||
|
stderr: "error: Expected \':\' or \'=\', but found \'+\'
|
||||||
|
|
|
||||||
|
2 | foo *a +b:
|
||||||
|
| ^
|
||||||
|
",
|
||||||
|
status: EXIT_FAILURE,
|
||||||
|
}
|
||||||
|
|
||||||
|
test! {
|
||||||
|
name: plus_then_star_variadic,
|
||||||
|
justfile: "
|
||||||
|
foo +a *b:
|
||||||
|
echo {{a}} {{b}}
|
||||||
|
",
|
||||||
|
stdout: "",
|
||||||
|
stderr: "error: Expected \':\' or \'=\', but found \'*\'
|
||||||
|
|
|
||||||
|
2 | foo +a *b:
|
||||||
|
| ^
|
||||||
|
",
|
||||||
|
status: EXIT_FAILURE,
|
||||||
|
}
|
||||||
|
|
||||||
test! {
|
test! {
|
||||||
name: argument_grouping,
|
name: argument_grouping,
|
||||||
justfile: "
|
justfile: "
|
||||||
@ -2429,7 +2515,7 @@ test! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test! {
|
test! {
|
||||||
name: dependency_argument_variadic,
|
name: dependency_argument_plus_variadic,
|
||||||
justfile: "
|
justfile: "
|
||||||
foo: (bar 'A' 'B' 'C')
|
foo: (bar 'A' 'B' 'C')
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user