KCL: Fix cryptic error on unexpected tokens in fn call (#7295)
This program: ```kcl 1 |> extrude( length=depth, }) ``` was giving this bad error: ``` unexpected token |> ``` Now it gives ```kcl There was an unexpected }. Try removing it. ``` and it correctly puts the diagnostic on the extra }. Fixes https://github.com/KittyCAD/modeling-app/issues/6126
This commit is contained in:
@ -2072,8 +2072,8 @@ notPipeSub = 1 |> identity(!%))";
|
|||||||
// a runtime error instead.
|
// a runtime error instead.
|
||||||
parse_execute(code11).await.unwrap_err(),
|
parse_execute(code11).await.unwrap_err(),
|
||||||
KclError::Syntax(KclErrorDetails::new(
|
KclError::Syntax(KclErrorDetails::new(
|
||||||
"Unexpected token: |>".to_owned(),
|
"There was an unexpected !. Try removing it.".to_owned(),
|
||||||
vec![SourceRange::new(44, 46, ModuleId::default())],
|
vec![SourceRange::new(56, 57, ModuleId::default())],
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -3141,7 +3141,7 @@ fn binding_name(i: &mut TokenSlice) -> ModalResult<Node<Identifier>> {
|
|||||||
|
|
||||||
/// Either a positional or keyword function call.
|
/// Either a positional or keyword function call.
|
||||||
fn fn_call_pos_or_kw(i: &mut TokenSlice) -> ModalResult<Expr> {
|
fn fn_call_pos_or_kw(i: &mut TokenSlice) -> ModalResult<Expr> {
|
||||||
alt((fn_call_kw.map(Box::new).map(Expr::CallExpressionKw),)).parse_next(i)
|
fn_call_kw.map(Box::new).map(Expr::CallExpressionKw).parse_next(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn labelled_fn_call(i: &mut TokenSlice) -> ModalResult<Expr> {
|
fn labelled_fn_call(i: &mut TokenSlice) -> ModalResult<Expr> {
|
||||||
@ -3270,7 +3270,22 @@ fn fn_call_kw(i: &mut TokenSlice) -> ModalResult<Node<CallExpressionKw>> {
|
|||||||
)?;
|
)?;
|
||||||
ignore_whitespace(i);
|
ignore_whitespace(i);
|
||||||
opt(comma_sep).parse_next(i)?;
|
opt(comma_sep).parse_next(i)?;
|
||||||
let end = close_paren.parse_next(i)?.end;
|
let end = match close_paren.parse_next(i) {
|
||||||
|
Ok(tok) => tok.end,
|
||||||
|
Err(e) => {
|
||||||
|
if let Some(tok) = i.next_token() {
|
||||||
|
return Err(ErrMode::Cut(
|
||||||
|
CompilationError::fatal(
|
||||||
|
SourceRange::from(&tok),
|
||||||
|
format!("There was an unexpected {}. Try removing it.", tok.value),
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Validate there aren't any duplicate labels.
|
// Validate there aren't any duplicate labels.
|
||||||
let mut counted_labels = IndexMap::with_capacity(args.len());
|
let mut counted_labels = IndexMap::with_capacity(args.len());
|
||||||
@ -3391,8 +3406,7 @@ mod tests {
|
|||||||
fn kw_call_as_operand() {
|
fn kw_call_as_operand() {
|
||||||
let tokens = crate::parsing::token::lex("f(x = 1)", ModuleId::default()).unwrap();
|
let tokens = crate::parsing::token::lex("f(x = 1)", ModuleId::default()).unwrap();
|
||||||
let tokens = tokens.as_slice();
|
let tokens = tokens.as_slice();
|
||||||
let op = operand.parse(tokens).unwrap();
|
operand.parse(tokens).unwrap();
|
||||||
println!("{op:#?}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -4432,8 +4446,8 @@ z(-[["#,
|
|||||||
assert_err(
|
assert_err(
|
||||||
r#"z
|
r#"z
|
||||||
(--#"#,
|
(--#"#,
|
||||||
"Unexpected token: (",
|
"There was an unexpected -. Try removing it.",
|
||||||
[2, 3],
|
[3, 4],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5188,14 +5202,32 @@ bar = 1
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sensible_error_when_unexpected_token_in_fn_call() {
|
||||||
|
let program_source = "1
|
||||||
|
|> extrude(
|
||||||
|
length=depth,
|
||||||
|
})";
|
||||||
|
let expected_src_start = program_source.find("}").expect("Program should have an extraneous }");
|
||||||
|
let tokens = crate::parsing::token::lex(program_source, ModuleId::default()).unwrap();
|
||||||
|
ParseContext::init();
|
||||||
|
let err = program.parse(tokens.as_slice()).unwrap_err();
|
||||||
|
let cause = err
|
||||||
|
.inner()
|
||||||
|
.cause
|
||||||
|
.as_ref()
|
||||||
|
.expect("Found an error, but there was no cause. Add a cause.");
|
||||||
|
assert_eq!(cause.message, "There was an unexpected }. Try removing it.",);
|
||||||
|
assert_eq!(cause.source_range.start(), expected_src_start);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sensible_error_when_using_keyword_as_arg_label() {
|
fn test_sensible_error_when_using_keyword_as_arg_label() {
|
||||||
for (i, program) in ["pow(2, fn = 8)"].into_iter().enumerate() {
|
for (i, program) in ["pow(2, fn = 8)"].into_iter().enumerate() {
|
||||||
let tokens = crate::parsing::token::lex(program, ModuleId::default()).unwrap();
|
let tokens = crate::parsing::token::lex(program, ModuleId::default()).unwrap();
|
||||||
let err = match fn_call_kw.parse(tokens.as_slice()) {
|
let err = match fn_call_kw.parse(tokens.as_slice()) {
|
||||||
Err(e) => e,
|
Err(e) => e,
|
||||||
Ok(ast) => {
|
Ok(_ast) => {
|
||||||
eprintln!("{ast:#?}");
|
|
||||||
panic!("Expected this to error but it didn't");
|
panic!("Expected this to error but it didn't");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user