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),
|
NoSuchFunction(String),
|
||||||
#[error(r#"Method "{name}" doesn't exist for type "{type_name}""#)]
|
#[error(r#"Method "{name}" doesn't exist for type "{type_name}""#)]
|
||||||
NoSuchMethod { type_name: String, name: String },
|
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}""#)]
|
#[error(r#"Expected argument of type "{0}""#)]
|
||||||
InvalidArgumentType(String),
|
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 {
|
fn invalid_argument_type(expected_type_name: impl Into<String>, span: pest::Span<'_>) -> Self {
|
||||||
TemplateParseError::with_span(
|
TemplateParseError::with_span(
|
||||||
TemplateParseErrorKind::InvalidArgumentType(expected_type_name.into()),
|
TemplateParseErrorKind::InvalidArgumentType(expected_type_name.into()),
|
||||||
|
@ -452,26 +464,25 @@ fn parse_commit_term<'a>(
|
||||||
Ok(Expression::Property(property))
|
Ok(Expression::Property(property))
|
||||||
}
|
}
|
||||||
Rule::function => {
|
Rule::function => {
|
||||||
let (name, mut args) = {
|
let (name, args_span, mut args) = {
|
||||||
let mut inner = expr.into_inner();
|
let mut inner = expr.into_inner();
|
||||||
let name = inner.next().unwrap();
|
let name = inner.next().unwrap();
|
||||||
let args_pair = inner.next().unwrap();
|
let args_pair = inner.next().unwrap();
|
||||||
assert_eq!(name.as_rule(), Rule::identifier);
|
assert_eq!(name.as_rule(), Rule::identifier);
|
||||||
assert_eq!(args_pair.as_rule(), Rule::function_arguments);
|
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() {
|
let expression = match name.as_str() {
|
||||||
"label" => {
|
"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 =
|
let label_property =
|
||||||
parse_commit_template_rule(repo, workspace_id, label_pair)?
|
parse_commit_template_rule(repo, workspace_id, label_pair)?
|
||||||
.into_plain_text();
|
.into_plain_text();
|
||||||
let arg_template = match args.next() {
|
let arg_template = args.next().ok_or_else(arg_count_error)?;
|
||||||
None => panic!("label() requires two arguments"),
|
|
||||||
Some(pair) => pair,
|
|
||||||
};
|
|
||||||
if args.next().is_some() {
|
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)?
|
let content = parse_commit_template_rule(repo, workspace_id, arg_template)?
|
||||||
.into_template();
|
.into_template();
|
||||||
|
@ -482,7 +493,9 @@ fn parse_commit_term<'a>(
|
||||||
Expression::Template(template)
|
Expression::Template(template)
|
||||||
}
|
}
|
||||||
"if" => {
|
"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_span = condition_pair.as_span();
|
||||||
let condition = parse_commit_template_rule(repo, workspace_id, condition_pair)?
|
let condition = parse_commit_template_rule(repo, workspace_id, condition_pair)?
|
||||||
.try_into_boolean()
|
.try_into_boolean()
|
||||||
|
@ -490,19 +503,18 @@ fn parse_commit_term<'a>(
|
||||||
TemplateParseError::invalid_argument_type("Boolean", condition_span)
|
TemplateParseError::invalid_argument_type("Boolean", condition_span)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let true_template = match args.next() {
|
let true_template = args
|
||||||
None => panic!("if() requires at least two arguments"),
|
.next()
|
||||||
Some(pair) => {
|
.ok_or_else(arg_count_error)
|
||||||
parse_commit_template_rule(repo, workspace_id, pair)?.into_template()
|
.and_then(|pair| parse_commit_template_rule(repo, workspace_id, pair))?
|
||||||
}
|
.into_template();
|
||||||
};
|
|
||||||
let false_template = args
|
let false_template = args
|
||||||
.next()
|
.next()
|
||||||
.map(|pair| parse_commit_template_rule(repo, workspace_id, pair))
|
.map(|pair| parse_commit_template_rule(repo, workspace_id, pair))
|
||||||
.transpose()?
|
.transpose()?
|
||||||
.map(|x| x.into_template());
|
.map(|x| x.into_template());
|
||||||
if args.next().is_some() {
|
if args.next().is_some() {
|
||||||
panic!("if() accepts at most three arguments")
|
return Err(arg_count_error());
|
||||||
}
|
}
|
||||||
let template = Box::new(ConditionalTemplate::new(
|
let template = Box::new(ConditionalTemplate::new(
|
||||||
condition,
|
condition,
|
||||||
|
|
|
@ -148,6 +148,40 @@ fn test_templater_parse_error() {
|
||||||
= Method "foo" doesn't exist for type "String"
|
= 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###"
|
insta::assert_snapshot!(render_err(r#"if(label("foo", "bar"), "baz")"#), @r###"
|
||||||
Error: Failed to parse template: --> 1:4
|
Error: Failed to parse template: --> 1:4
|
||||||
|
|
|
|
||||||
|
|
Loading…
Reference in a new issue