diff --git a/rust/kcl-lib/src/execution/mod.rs b/rust/kcl-lib/src/execution/mod.rs index 8523fc272..231a338d5 100644 --- a/rust/kcl-lib/src/execution/mod.rs +++ b/rust/kcl-lib/src/execution/mod.rs @@ -2072,8 +2072,8 @@ notPipeSub = 1 |> identity(!%))"; // a runtime error instead. parse_execute(code11).await.unwrap_err(), KclError::Syntax(KclErrorDetails::new( - "Unexpected token: |>".to_owned(), - vec![SourceRange::new(44, 46, ModuleId::default())], + "There was an unexpected !. Try removing it.".to_owned(), + vec![SourceRange::new(56, 57, ModuleId::default())], )) ); diff --git a/rust/kcl-lib/src/parsing/parser.rs b/rust/kcl-lib/src/parsing/parser.rs index 20c24250d..8f0deda50 100644 --- a/rust/kcl-lib/src/parsing/parser.rs +++ b/rust/kcl-lib/src/parsing/parser.rs @@ -3141,7 +3141,7 @@ fn binding_name(i: &mut TokenSlice) -> ModalResult> { /// Either a positional or keyword function call. fn fn_call_pos_or_kw(i: &mut TokenSlice) -> ModalResult { - 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 { @@ -3270,7 +3270,22 @@ fn fn_call_kw(i: &mut TokenSlice) -> ModalResult> { )?; ignore_whitespace(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. let mut counted_labels = IndexMap::with_capacity(args.len()); @@ -3391,8 +3406,7 @@ mod tests { fn kw_call_as_operand() { let tokens = crate::parsing::token::lex("f(x = 1)", ModuleId::default()).unwrap(); let tokens = tokens.as_slice(); - let op = operand.parse(tokens).unwrap(); - println!("{op:#?}"); + operand.parse(tokens).unwrap(); } #[test] @@ -4432,8 +4446,8 @@ z(-[["#, assert_err( r#"z (--#"#, - "Unexpected token: (", - [2, 3], + "There was an unexpected -. Try removing it.", + [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] fn test_sensible_error_when_using_keyword_as_arg_label() { for (i, program) in ["pow(2, fn = 8)"].into_iter().enumerate() { let tokens = crate::parsing::token::lex(program, ModuleId::default()).unwrap(); let err = match fn_call_kw.parse(tokens.as_slice()) { Err(e) => e, - Ok(ast) => { - eprintln!("{ast:#?}"); + Ok(_ast) => { panic!("Expected this to error but it didn't"); } };