forked from mirrors/jj
templater: report invalid argument count as error
We'll probably need a helper to extract N..M arguments, but let's revisit it later.
This commit is contained in:
parent
baf911459f
commit
45a018ec6b
2 changed files with 62 additions and 16 deletions
|
@ -53,6 +53,11 @@ pub enum TemplateParseErrorKind {
|
|||
NoSuchFunction(String),
|
||||
#[error(r#"Method "{name}" doesn't exist for type "{type_name}""#)]
|
||||
NoSuchMethod { type_name: String, name: String },
|
||||
#[error(
|
||||
"Expected {} arguments",
|
||||
if min == max { format!("{min}") } else { format!("{min} to {max}") },
|
||||
)]
|
||||
InvalidArgumentCount { min: usize, max: usize },
|
||||
#[error(r#"Expected argument of type "{0}""#)]
|
||||
InvalidArgumentType(String),
|
||||
}
|
||||
|
@ -92,6 +97,13 @@ impl TemplateParseError {
|
|||
)
|
||||
}
|
||||
|
||||
fn invalid_argument_count(min: usize, max: usize, span: pest::Span<'_>) -> Self {
|
||||
TemplateParseError::with_span(
|
||||
TemplateParseErrorKind::InvalidArgumentCount { min, max },
|
||||
span,
|
||||
)
|
||||
}
|
||||
|
||||
fn invalid_argument_type(expected_type_name: impl Into<String>, span: pest::Span<'_>) -> Self {
|
||||
TemplateParseError::with_span(
|
||||
TemplateParseErrorKind::InvalidArgumentType(expected_type_name.into()),
|
||||
|
@ -452,26 +464,25 @@ fn parse_commit_term<'a>(
|
|||
Ok(Expression::Property(property))
|
||||
}
|
||||
Rule::function => {
|
||||
let (name, mut args) = {
|
||||
let (name, args_span, mut args) = {
|
||||
let mut inner = expr.into_inner();
|
||||
let name = inner.next().unwrap();
|
||||
let args_pair = inner.next().unwrap();
|
||||
assert_eq!(name.as_rule(), Rule::identifier);
|
||||
assert_eq!(args_pair.as_rule(), Rule::function_arguments);
|
||||
(name, args_pair.into_inner())
|
||||
(name, args_pair.as_span(), args_pair.into_inner())
|
||||
};
|
||||
let expression = match name.as_str() {
|
||||
"label" => {
|
||||
let label_pair = args.next().unwrap();
|
||||
let arg_count_error =
|
||||
|| TemplateParseError::invalid_argument_count(2, 2, args_span);
|
||||
let label_pair = args.next().ok_or_else(arg_count_error)?;
|
||||
let label_property =
|
||||
parse_commit_template_rule(repo, workspace_id, label_pair)?
|
||||
.into_plain_text();
|
||||
let arg_template = match args.next() {
|
||||
None => panic!("label() requires two arguments"),
|
||||
Some(pair) => pair,
|
||||
};
|
||||
let arg_template = args.next().ok_or_else(arg_count_error)?;
|
||||
if args.next().is_some() {
|
||||
panic!("label() accepts only two arguments")
|
||||
return Err(arg_count_error());
|
||||
}
|
||||
let content = parse_commit_template_rule(repo, workspace_id, arg_template)?
|
||||
.into_template();
|
||||
|
@ -482,7 +493,9 @@ fn parse_commit_term<'a>(
|
|||
Expression::Template(template)
|
||||
}
|
||||
"if" => {
|
||||
let condition_pair = args.next().unwrap();
|
||||
let arg_count_error =
|
||||
|| TemplateParseError::invalid_argument_count(2, 3, args_span);
|
||||
let condition_pair = args.next().ok_or_else(arg_count_error)?;
|
||||
let condition_span = condition_pair.as_span();
|
||||
let condition = parse_commit_template_rule(repo, workspace_id, condition_pair)?
|
||||
.try_into_boolean()
|
||||
|
@ -490,19 +503,18 @@ fn parse_commit_term<'a>(
|
|||
TemplateParseError::invalid_argument_type("Boolean", condition_span)
|
||||
})?;
|
||||
|
||||
let true_template = match args.next() {
|
||||
None => panic!("if() requires at least two arguments"),
|
||||
Some(pair) => {
|
||||
parse_commit_template_rule(repo, workspace_id, pair)?.into_template()
|
||||
}
|
||||
};
|
||||
let true_template = args
|
||||
.next()
|
||||
.ok_or_else(arg_count_error)
|
||||
.and_then(|pair| parse_commit_template_rule(repo, workspace_id, pair))?
|
||||
.into_template();
|
||||
let false_template = args
|
||||
.next()
|
||||
.map(|pair| parse_commit_template_rule(repo, workspace_id, pair))
|
||||
.transpose()?
|
||||
.map(|x| x.into_template());
|
||||
if args.next().is_some() {
|
||||
panic!("if() accepts at most three arguments")
|
||||
return Err(arg_count_error());
|
||||
}
|
||||
let template = Box::new(ConditionalTemplate::new(
|
||||
condition,
|
||||
|
|
|
@ -148,6 +148,40 @@ fn test_templater_parse_error() {
|
|||
= Method "foo" doesn't exist for type "String"
|
||||
"###);
|
||||
|
||||
insta::assert_snapshot!(render_err(r#"label()"#), @r###"
|
||||
Error: Failed to parse template: --> 1:7
|
||||
|
|
||||
1 | label()
|
||||
| ^
|
||||
|
|
||||
= Expected 2 arguments
|
||||
"###);
|
||||
insta::assert_snapshot!(render_err(r#"label("foo", "bar", "baz")"#), @r###"
|
||||
Error: Failed to parse template: --> 1:7
|
||||
|
|
||||
1 | label("foo", "bar", "baz")
|
||||
| ^-----------------^
|
||||
|
|
||||
= Expected 2 arguments
|
||||
"###);
|
||||
|
||||
insta::assert_snapshot!(render_err(r#"if()"#), @r###"
|
||||
Error: Failed to parse template: --> 1:4
|
||||
|
|
||||
1 | if()
|
||||
| ^
|
||||
|
|
||||
= Expected 2 to 3 arguments
|
||||
"###);
|
||||
insta::assert_snapshot!(render_err(r#"if("foo", "bar", "baz", "quux")"#), @r###"
|
||||
Error: Failed to parse template: --> 1:4
|
||||
|
|
||||
1 | if("foo", "bar", "baz", "quux")
|
||||
| ^-------------------------^
|
||||
|
|
||||
= Expected 2 to 3 arguments
|
||||
"###);
|
||||
|
||||
insta::assert_snapshot!(render_err(r#"if(label("foo", "bar"), "baz")"#), @r###"
|
||||
Error: Failed to parse template: --> 1:4
|
||||
|
|
||||
|
|
Loading…
Reference in a new issue