Skip to content

Commit b61cd31

Browse files
authored
KCL: Fix two cryptic error messages (#5745)
Firstly, before the code "{x = 1, y = }" would give the dreaded "unexpected token" error. Now it says "This property has a label, but no value. Put some value after the equals sign". And points to the = symbol with no matching right-hand side value. Yay! Second fix: before, in the code `f(1, x=)`, the error complained that an unlabeled arg was not permitted there. Now it says "This argument has a label, but no value. Put some value after the equals sign".
1 parent 865bf8a commit b61cd31

File tree

2 files changed

+73
-20
lines changed

2 files changed

+73
-20
lines changed

rust/Cargo.lock

Lines changed: 2 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/kcl-lib/src/parsing/parser.rs

Lines changed: 71 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -844,11 +844,23 @@ fn object_property(i: &mut TokenSlice) -> PResult<Node<ObjectProperty>> {
844844
))
845845
.parse_next(i)?;
846846
ignore_whitespace(i);
847-
let expr = expression
847+
let expr = match expression
848848
.context(expected(
849849
"the value which you're setting the property to, e.g. in 'height: 4', the value is 4",
850850
))
851-
.parse_next(i)?;
851+
.parse_next(i)
852+
{
853+
Ok(expr) => expr,
854+
Err(_) => {
855+
return Err(ErrMode::Cut(
856+
CompilationError::fatal(
857+
SourceRange::from(sep),
858+
"This property has a label, but no value. Put some value after the equals sign",
859+
)
860+
.into(),
861+
));
862+
}
863+
};
852864

853865
let result = Node {
854866
start: key.start,
@@ -2810,7 +2822,7 @@ fn fn_call_kw(i: &mut TokenSlice) -> PResult<Node<CallExpressionKw>> {
28102822
ignore_whitespace(i);
28112823

28122824
#[allow(clippy::large_enum_variant)]
2813-
pub enum ArgPlace {
2825+
enum ArgPlace {
28142826
NonCode(Node<NonCodeNode>),
28152827
LabeledArg(LabeledArg),
28162828
UnlabeledArg(Expr),
@@ -2827,22 +2839,34 @@ fn fn_call_kw(i: &mut TokenSlice) -> PResult<Node<CallExpressionKw>> {
28272839
.parse_next(i)?;
28282840
let (args, non_code_nodes): (Vec<_>, BTreeMap<usize, _>) = args.into_iter().enumerate().try_fold(
28292841
(Vec::new(), BTreeMap::new()),
2830-
|(mut args, mut non_code_nodes), (i, e)| {
2842+
|(mut args, mut non_code_nodes), (index, e)| {
28312843
match e {
28322844
ArgPlace::NonCode(x) => {
2833-
non_code_nodes.insert(i, vec![x]);
2845+
non_code_nodes.insert(index, vec![x]);
28342846
}
28352847
ArgPlace::LabeledArg(x) => {
28362848
args.push(x);
28372849
}
28382850
ArgPlace::UnlabeledArg(arg) => {
2839-
return Err(ErrMode::Cut(
2840-
CompilationError::fatal(
2841-
SourceRange::from(arg),
2842-
"This argument needs a label, but it doesn't have one",
2851+
let followed_by_equals = peek((opt(whitespace), equals)).parse_next(i).is_ok();
2852+
let err = if followed_by_equals {
2853+
ErrMode::Cut(
2854+
CompilationError::fatal(
2855+
SourceRange::from(arg),
2856+
"This argument has a label, but no value. Put some value after the equals sign",
2857+
)
2858+
.into(),
28432859
)
2844-
.into(),
2845-
));
2860+
} else {
2861+
ErrMode::Cut(
2862+
CompilationError::fatal(
2863+
SourceRange::from(arg),
2864+
"This argument needs a label, but it doesn't have one",
2865+
)
2866+
.into(),
2867+
)
2868+
};
2869+
return Err(err);
28462870
}
28472871
}
28482872
Ok((args, non_code_nodes))
@@ -4678,6 +4702,42 @@ baz = 2
46784702
);
46794703
}
46804704
}
4705+
4706+
#[test]
4707+
fn test_sensible_error_when_missing_rhs_of_kw_arg() {
4708+
for (i, program) in ["f(x, y=)"].into_iter().enumerate() {
4709+
let tokens = crate::parsing::token::lex(program, ModuleId::default()).unwrap();
4710+
let err = fn_call_kw.parse(tokens.as_slice()).unwrap_err();
4711+
let cause = err.inner().cause.as_ref().unwrap();
4712+
assert_eq!(
4713+
cause.message, "This argument has a label, but no value. Put some value after the equals sign",
4714+
"failed test {i}: {program}"
4715+
);
4716+
assert_eq!(
4717+
cause.source_range.start(),
4718+
program.find("y").unwrap(),
4719+
"failed test {i}: {program}"
4720+
);
4721+
}
4722+
}
4723+
4724+
#[test]
4725+
fn test_sensible_error_when_missing_rhs_of_obj_property() {
4726+
for (i, program) in ["{x = 1, y =}"].into_iter().enumerate() {
4727+
let tokens = crate::parsing::token::lex(program, ModuleId::default()).unwrap();
4728+
let err = object.parse(tokens.as_slice()).unwrap_err();
4729+
let cause = err.inner().cause.as_ref().unwrap();
4730+
assert_eq!(
4731+
cause.message, "This property has a label, but no value. Put some value after the equals sign",
4732+
"failed test {i}: {program}"
4733+
);
4734+
assert_eq!(
4735+
cause.source_range.start(),
4736+
program.rfind('=').unwrap(),
4737+
"failed test {i}: {program}"
4738+
);
4739+
}
4740+
}
46814741
}
46824742

46834743
#[cfg(test)]

0 commit comments

Comments
 (0)