new decorator syntax: '// @'

This commit is contained in:
PgBiel 2024-07-15 18:23:56 -03:00
parent 2b442eae5e
commit c1bb41dc9c
3 changed files with 94 additions and 62 deletions

View File

@ -13,7 +13,7 @@ pub enum SyntaxKind {
LineComment, LineComment,
/// A block comment: `/* ... */`. /// A block comment: `/* ... */`.
BlockComment, BlockComment,
/// A decorator: `/! allow("warning")`. /// A decorator: `// @allow("warning")`.
Decorator, Decorator,
/// The contents of a file or content block. /// The contents of a file or content block.
@ -281,7 +281,7 @@ pub enum SyntaxKind {
/// A destructuring assignment expression: `(x, y) = (1, 2)`. /// A destructuring assignment expression: `(x, y) = (1, 2)`.
DestructAssignment, DestructAssignment,
/// A decorator's marker: `/!`. /// A decorator's marker: `// @`.
DecoratorMarker, DecoratorMarker,
/// A decorator's name: `allow`. /// A decorator's name: `allow`.
DecoratorName, DecoratorName,

View File

@ -119,9 +119,10 @@ impl Lexer<'_> {
let start = self.s.cursor(); let start = self.s.cursor();
let token = match self.s.eat() { let token = match self.s.eat() {
Some(c) if is_space(c, self.mode) => self.whitespace(start, c), Some(c) if is_space(c, self.mode) => self.whitespace(start, c),
Some('/') if self.s.eat_if('/') => self.line_comment(), Some('/') if self.s.eat_if('/') => {
return self.line_comment_or_decorator(start);
}
Some('/') if self.s.eat_if('*') => self.block_comment(), Some('/') if self.s.eat_if('*') => self.block_comment(),
Some('/') if self.s.eat_if('!') => return self.decorator(start),
Some('*') if self.s.eat_if('/') => { Some('*') if self.s.eat_if('/') => {
let kind = self.error("unexpected end of block comment"); let kind = self.error("unexpected end of block comment");
self.hint( self.hint(
@ -184,9 +185,17 @@ impl Lexer<'_> {
} }
} }
fn line_comment(&mut self) -> SyntaxKind { /// Parses a decorator if the line comment has the form
/// `// @something`
///
/// Otherwise, parses a regular line comment.
fn line_comment_or_decorator(&mut self, start: usize) -> SyntaxNode {
self.s.eat_while(is_inline_whitespace);
if self.s.eat_if('@') {
return self.decorator(start);
}
self.s.eat_until(is_newline); self.s.eat_until(is_newline);
SyntaxKind::LineComment self.emit_token(SyntaxKind::LineComment, start)
} }
fn block_comment(&mut self) -> SyntaxKind { fn block_comment(&mut self) -> SyntaxKind {
@ -274,7 +283,16 @@ impl Lexer<'_> {
self.s.eat_while(is_inline_whitespace); self.s.eat_while(is_inline_whitespace);
SyntaxKind::Space SyntaxKind::Space
} }
Some('/') if self.s.eat_if('/') => self.line_comment(), Some('/') if self.s.eat_if('/') => {
let node = self.line_comment_or_decorator(current_start);
if node.kind() == SyntaxKind::Decorator {
self.error("cannot have multiple decorators per line")
} else {
subtree.push(node);
current_start = self.s.cursor();
continue;
}
}
Some('/') if self.s.eat_if('*') => self.block_comment(), Some('/') if self.s.eat_if('*') => self.block_comment(),
Some(_) if finished => { Some(_) if finished => {
// After we finished specifying arguments, there must only // After we finished specifying arguments, there must only

View File

@ -2,102 +2,115 @@
--- basic-decorators --- --- basic-decorators ---
/! allow() // @allow()
/! allow("A") // @allow("A")
/! allow("the") // @allow("the")
/! allow("unnecessary-stars") // @allow("unnecessary-stars")
#h(0em) #h(0em)
#{ #let _ = {
/! allow("unnecessary-stars") // @allow("unnecessary-stars")
let _ = h(0em) h(0em)
} }
#let _ = $ #let _ = $
/! allow("unnecessary-stars") // @allow("unnecessary-stars")
h(#0em) h(#0em)
$ $
--- decorator-comments --- --- decorator-comments ---
/! allow("abc") // this is ok // @allow("abc") // this is ok
/! allow("abc") /* this is ok */ // @allow("abc") /* this is ok */
/! allow("abc" /* this is ok */, "abc") // @allow("abc" /* this is ok */, "abc")
/! allow("abc" /* // @allow("abc" /*
this is ok this is ok
*/, "abc") */, "abc")
--- decorator-strings --- --- decorator-strings ---
/! allow("@some/thing-there123") // @allow("@some/thing-there123")
--- unknown-decorator --- --- unknown-decorator ---
// Error: 4-12 invalid decorator name // Error: 2:5-2:13 invalid decorator name
// Hint: 4-12 must be 'allow' // Hint: 2:5-2:13 must be 'allow'
/! whatever()
// @whatever()
--- invalid-decorator-syntax --- --- invalid-decorator-syntax ---
// Error: 10-11 the character '*' is not valid in a decorator // Error: 2:11-2:12 the character '*' is not valid in a decorator
/! allow(*)
// Error: 10-11 the character '5' is not valid in a decorator // @allow(*)
/! allow(5)
// Error: 4-18 expected identifier // Error: 2:11-2:12 the character '5' is not valid in a decorator
/! 555!**INVALID!
// Error: 9-12 expected opening paren // @allow(5)
/! allow)")
// Error: 10-14 unclosed string // Error: 2:5-2:19 expected identifier
// Error: 14 expected closing paren
/! allow("abc
// Error: 17-20 expected end of decorator // @555!**INVALID!
/! allow("abc") abc
// Error: 16-21 expected comma // Error: 2:10-2:13 expected opening paren
// Error: 23-26 expected end of decorator
/! allow("abc" "abc") abc
// Error: 16-21 expected comma // @allow)")
/! allow("abc" "abc", "abc")
// Error: 10-11 unexpected comma // Error: 2:11-2:15 unclosed string
/! allow(, "abc", "abc", "abc") // Error: 2:15 expected closing paren
// @allow("abc
// Error: 2:18-2:21 expected end of decorator
// @allow("abc") abc
// Error: 2:17-2:22 expected comma
// Error: 2:24-2:27 expected end of decorator
// @allow("abc" "abc") abc
// Error: 2:17-2:22 expected comma
// @allow("abc" "abc", "abc")
// Error: 2:11-2:12 unexpected comma
// @allow(, "abc", "abc", "abc")
--- invalid-decorator-strings --- --- invalid-decorator-strings ---
// Error: 10-15 invalid character ' ' in a decorator's string // Error: 2:11-2:16 invalid character ' ' in a decorator's string
/! allow("a b")
// Error: 10-18 invalid character '|' in a decorator's string // @allow("a b")
/! allow("aaaaa|")
// Error: 2:11-2:19 invalid character '|' in a decorator's string
// @allow("aaaaa|")
// TODO: Why does this print / instead of \? // TODO: Why does this print / instead of \?
// Error: 10-18 invalid character '/' in a decorator's string // Error: 2:11-2:19 invalid character '/' in a decorator's string
/! allow("aaaaa\")
// @allow("aaaaa\")
--- allow-suppresses-warns-below --- --- allow-suppresses-warns-below ---
/! allow("unnecessary-stars") // @allow("unnecessary-stars")
#[**] #[**]
/! allow("unnecessary-stars") // @allow("unnecessary-stars")
#{ #{
{ {
[**] [**]
} }
} }
/**/ /! allow("unnecessary-stars") /**/ // @allow("unnecessary-stars")
#[**] #[**]
/! allow("unnecessary-stars") // @allow("unnecessary-stars")
** **
--- allow-suppresses-warn-with-tracepoint --- --- allow-suppresses-warn-with-tracepoint ---
@ -109,19 +122,20 @@ this is ok
f() f()
} }
/! allow("unknown-font-families") // @allow("unknown-font-families")
#g() #g()
--- allow-suppresses-line-below-but-not-same-line --- --- allow-suppresses-line-below-but-not-same-line ---
// Warning: 3-5 no text within stars // Warning: 3-5 no text within stars
// Hint: 3-5 using multiple consecutive stars (e.g. **) has no additional effect // Hint: 3-5 using multiple consecutive stars (e.g. **) has no additional effect
#[**] /! allow("unnecessary-stars") #[**] // @allow("unnecessary-stars")
#[**] #[**]
--- allow-before-parbreak-doesnt-suppress-warn --- --- allow-before-parbreak-doesnt-suppress-warn ---
// Warning: 3:3-3:5 no text within stars // Warning: 4:3-4:5 no text within stars
// Hint: 3:3-3:5 using multiple consecutive stars (e.g. **) has no additional effect // Hint: 4:3-4:5 using multiple consecutive stars (e.g. **) has no additional effect
/! allow("unnecessary-stars")
// @allow("unnecessary-stars")
#[**] #[**]
@ -129,7 +143,7 @@ this is ok
// Warning: 4:4-4:6 no text within stars // Warning: 4:4-4:6 no text within stars
// Hint: 4:4-4:6 using multiple consecutive stars (e.g. **) has no additional effect // Hint: 4:4-4:6 using multiple consecutive stars (e.g. **) has no additional effect
#{ #{
/! allow("unnecessary-stars") // @allow("unnecessary-stars")
[**] [**]
} }
@ -140,7 +154,7 @@ this is ok
// Hint: 1-3 using multiple consecutive stars (e.g. **) has no additional effect // Hint: 1-3 using multiple consecutive stars (e.g. **) has no additional effect
** **
/! allow("unnecessary-stars") // @allow("unnecessary-stars")
#h(0em) #h(0em)
// Warning: 3-5 no text within stars // Warning: 3-5 no text within stars
// Hint: 3-5 using multiple consecutive stars (e.g. **) has no additional effect // Hint: 3-5 using multiple consecutive stars (e.g. **) has no additional effect
@ -152,10 +166,10 @@ this is ok
text(font: "Unbeknownst")[] text(font: "Unbeknownst")[]
} }
/! allow("unknown-font-families") // @allow("unknown-font-families")
#f() #f()
/! allow("unknown-font-families") // @allow("unknown-font-families")
#context { #context {
text(font: "Unbeknownst")[] text(font: "Unbeknownst")[]
} }