diff --git a/crates/typst-syntax/src/lexer.rs b/crates/typst-syntax/src/lexer.rs index ecbf0ea66..d13fc5278 100644 --- a/crates/typst-syntax/src/lexer.rs +++ b/crates/typst-syntax/src/lexer.rs @@ -283,7 +283,7 @@ impl Lexer<'_> { // After we finished specifying arguments, there must only // be whitespaces until the line ends. self.s.eat_until(char::is_whitespace); - self.error("expected end of annotation") + self.error("unexpected characters after end of annotation") } Some(c) if is_id_start(c) => { self.s.eat_while(is_id_continue); @@ -294,9 +294,32 @@ impl Lexer<'_> { found_closing_paren = true; SyntaxKind::RightParen } - Some(c) => self.error(eco_format!( - "the character '{c}' is not valid in an annotation" - )), + // Explicitly detect comments for more helpful errors + Some('/') if self.s.at(['/', '*']) => { + if self.s.eat() == Some('*') { + // Found a block comment. Advance until the next + // newline or '*/' just for a more accurate error span. + while !self.s.eat_if("*/") && !self.s.at(is_newline) { + self.s.eat(); + } + } else { + self.s.eat_until(is_newline); + } + self.error(eco_format!("unexpected comment inside annotation")) + } + Some(_) => { + self.s.eat_until(|c: char| { + c.is_whitespace() || has_opening_paren && c == ')' + }); + self.error(eco_format!( + "expected identifier{} in annotation", + if has_opening_paren { + ", string or closing paren" + } else { + " or string" + } + )) + } None => break, }; @@ -308,7 +331,12 @@ impl Lexer<'_> { // Right parenthesis (covered above) if has_opening_paren && !found_closing_paren { - subtree.push(self.emit_error("expected closing paren", self.s.cursor())); + subtree.push( + self.emit_error( + "expected closing paren after annotation", + self.s.cursor(), + ), + ); } SyntaxNode::inner(SyntaxKind::Annotation, subtree) diff --git a/tests/suite/syntax/annotation.typ b/tests/suite/syntax/annotation.typ index 930ef7e2d..8f5ae862d 100644 --- a/tests/suite/syntax/annotation.typ +++ b/tests/suite/syntax/annotation.typ @@ -21,28 +21,21 @@ $ --- annotation-comments --- -// Error: 2:17-2:18 the character '/' is not valid in an annotation -// Error: 2:18-2:19 the character '/' is not valid in an annotation +// Error: 2:17-2:27 unexpected comment inside annotation // @allow "abc" // comment -// Error: 2:17-2:18 the character '/' is not valid in an annotation -// Error: 2:18-2:19 the character '*' is not valid in an annotation -// Error: 2:28-2:29 the character '*' is not valid in an annotation -// Error: 2:29-2:30 the character '/' is not valid in an annotation +// Error: 2:17-2:30 unexpected comment inside annotation // @allow "abc" /* comment */ -// Error: 2:17-2:18 the character '/' is not valid in an annotation -// Error: 2:18-2:19 the character '*' is not valid in an annotation -// Error: 2:28-2:29 the character '*' is not valid in an annotation -// Error: 2:29-2:30 the character '/' is not valid in an annotation +// Error: 2:17-2:30 unexpected comment inside annotation // @allow "abc" /* comment */ "abc" --- annotation-strings --- -// @allow("@some/thing-there123") +// @allow "@some/thing-there123" --- unknown-annotation --- // Error: 2:5-2:13 invalid annotation name @@ -51,11 +44,11 @@ $ // @whatever A --- invalid-annotation-syntax --- -// Error: 2:11-2:12 the character '*' is not valid in an annotation +// Error: 2:11-2:12 expected identifier or string in annotation // @allow * -// Error: 2:11-2:12 the character '5' is not valid in an annotation +// Error: 2:11-2:12 expected identifier or string in annotation // @allow 5 @@ -63,21 +56,20 @@ $ // @555!**INVALID! -// Error: 2:10-2:11 the character ')' is not valid in an annotation -// Error: 2:11-2:13 unclosed string +// Error: 2:10-2:13 expected identifier or string in annotation // @allow)") // Error: 2:11-2:15 unclosed string -// Error: 2:15 expected closing paren +// Error: 2:15 expected closing paren after annotation // @allow("abc -// Error: 2:16-2:19 expected end of annotation +// Error: 2:16-2:19 unexpected characters after end of annotation // @allow(abc) abc -// Error: 2:18-2:19 the character ',' is not valid in an annotation +// Error: 2:18-2:19 expected identifier, string or closing paren in annotation // @allow(abc abc, "abc") @@ -97,11 +89,7 @@ $ // @allow "aaaaa\" --- invalid-annotation-in-annotation --- -// Error: 2:17-2:18 the character '/' is not valid in an annotation -// Error: 2:18-2:19 the character '/' is not valid in an annotation -// Error: 2:20-2:21 the character '@' is not valid in an annotation -// Error: 2:26-2:27 the character '(' is not valid in an annotation -// Error: 2:32-2:33 the character ')' is not valid in an annotation +// Error: 2:17-2:33 unexpected comment inside annotation // @allow "aaa" // @allow("bbb")