summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPgBiel <9021226+PgBiel@users.noreply.github.com>2024-07-15 18:23:56 -0300
committerPgBiel <9021226+PgBiel@users.noreply.github.com>2024-07-16 16:49:03 -0300
commitc1bb41dc9cadab596041d942bbaf7c7e8f8a14a5 (patch)
tree7c2dec35e747c3dffa955ef0a29cc5fc2249b7b9
parent2b442eae5e1bdedd29ee650e6a367c81a5ed9ce1 (diff)
new decorator syntax: '// @'
-rw-r--r--crates/typst-syntax/src/kind.rs4
-rw-r--r--crates/typst-syntax/src/lexer.rs28
-rw-r--r--tests/suite/syntax/decorator.typ124
3 files changed, 94 insertions, 62 deletions
diff --git a/crates/typst-syntax/src/kind.rs b/crates/typst-syntax/src/kind.rs
index 8f0e806c..fbe0b502 100644
--- a/crates/typst-syntax/src/kind.rs
+++ b/crates/typst-syntax/src/kind.rs
@@ -13,7 +13,7 @@ pub enum SyntaxKind {
LineComment,
/// A block comment: `/* ... */`.
BlockComment,
- /// A decorator: `/! allow("warning")`.
+ /// A decorator: `// @allow("warning")`.
Decorator,
/// The contents of a file or content block.
@@ -281,7 +281,7 @@ pub enum SyntaxKind {
/// A destructuring assignment expression: `(x, y) = (1, 2)`.
DestructAssignment,
- /// A decorator's marker: `/!`.
+ /// A decorator's marker: `// @`.
DecoratorMarker,
/// A decorator's name: `allow`.
DecoratorName,
diff --git a/crates/typst-syntax/src/lexer.rs b/crates/typst-syntax/src/lexer.rs
index 0e4b5b4b..fd057dc4 100644
--- a/crates/typst-syntax/src/lexer.rs
+++ b/crates/typst-syntax/src/lexer.rs
@@ -119,9 +119,10 @@ impl Lexer<'_> {
let start = self.s.cursor();
let token = match self.s.eat() {
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('!') => return self.decorator(start),
Some('*') if self.s.eat_if('/') => {
let kind = self.error("unexpected end of block comment");
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);
- SyntaxKind::LineComment
+ self.emit_token(SyntaxKind::LineComment, start)
}
fn block_comment(&mut self) -> SyntaxKind {
@@ -274,7 +283,16 @@ impl Lexer<'_> {
self.s.eat_while(is_inline_whitespace);
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 finished => {
// After we finished specifying arguments, there must only
diff --git a/tests/suite/syntax/decorator.typ b/tests/suite/syntax/decorator.typ
index 7faa49a3..b1df8195 100644
--- a/tests/suite/syntax/decorator.typ
+++ b/tests/suite/syntax/decorator.typ
@@ -2,102 +2,115 @@
--- basic-decorators ---
-/! allow()
-/! allow("A")
-/! allow("the")
+// @allow()
+// @allow("A")
+// @allow("the")
-/! allow("unnecessary-stars")
+// @allow("unnecessary-stars")
#h(0em)
-#{
- /! allow("unnecessary-stars")
- let _ = h(0em)
+#let _ = {
+ // @allow("unnecessary-stars")
+ h(0em)
}
#let _ = $
- /! allow("unnecessary-stars")
+ // @allow("unnecessary-stars")
h(#0em)
$
--- 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
*/, "abc")
--- decorator-strings ---
-/! allow("@some/thing-there123")
+// @allow("@some/thing-there123")
--- unknown-decorator ---
-// Error: 4-12 invalid decorator name
-// Hint: 4-12 must be 'allow'
-/! whatever()
+// Error: 2:5-2:13 invalid decorator name
+// Hint: 2:5-2:13 must be 'allow'
+
+// @whatever()
--- invalid-decorator-syntax ---
-// Error: 10-11 the character '*' is not valid in a decorator
-/! allow(*)
+// Error: 2:11-2:12 the character '*' is not valid in a decorator
+
+// @allow(*)
+
+// Error: 2:11-2:12 the character '5' is not valid in a decorator
+
+// @allow(5)
+
+// Error: 2:5-2:19 expected identifier
+
+// @555!**INVALID!
+
+// Error: 2:10-2:13 expected opening paren
-// Error: 10-11 the character '5' is not valid in a decorator
-/! allow(5)
+// @allow)")
-// Error: 4-18 expected identifier
-/! 555!**INVALID!
+// Error: 2:11-2:15 unclosed string
+// Error: 2:15 expected closing paren
-// Error: 9-12 expected opening paren
-/! allow)")
+// @allow("abc
-// Error: 10-14 unclosed string
-// Error: 14 expected closing paren
-/! allow("abc
+// Error: 2:18-2:21 expected end of decorator
-// Error: 17-20 expected end of decorator
-/! allow("abc") abc
+// @allow("abc") abc
-// Error: 16-21 expected comma
-// Error: 23-26 expected end of decorator
-/! allow("abc" "abc") abc
+// Error: 2:17-2:22 expected comma
+// Error: 2:24-2:27 expected end of decorator
-// Error: 16-21 expected comma
-/! allow("abc" "abc", "abc")
+// @allow("abc" "abc") abc
-// Error: 10-11 unexpected comma
-/! 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 ---
-// Error: 10-15 invalid character ' ' in a decorator's string
-/! allow("a b")
+// 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("aaaaa|")
+// Error: 2:11-2:19 invalid character '|' in a decorator's string
+
+// @allow("aaaaa|")
// TODO: Why does this print / instead of \?
-// Error: 10-18 invalid character '/' in a decorator's string
-/! allow("aaaaa\")
+// Error: 2:11-2:19 invalid character '/' in a decorator's string
+
+// @allow("aaaaa\")
--- 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 ---
@@ -109,19 +122,20 @@ this is ok
f()
}
-/! allow("unknown-font-families")
+// @allow("unknown-font-families")
#g()
--- allow-suppresses-line-below-but-not-same-line ---
// Warning: 3-5 no text within stars
// 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 ---
-// Warning: 3:3-3:5 no text within stars
-// Hint: 3:3-3:5 using multiple consecutive stars (e.g. **) has no additional effect
-/! allow("unnecessary-stars")
+// Warning: 4:3-4:5 no text within stars
+// Hint: 4:3-4:5 using multiple consecutive stars (e.g. **) has no additional effect
+
+// @allow("unnecessary-stars")
#[**]
@@ -129,7 +143,7 @@ this is ok
// Warning: 4:4-4:6 no text within stars
// 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
**
-/! allow("unnecessary-stars")
+// @allow("unnecessary-stars")
#h(0em)
// Warning: 3-5 no text within stars
// Hint: 3-5 using multiple consecutive stars (e.g. **) has no additional effect
@@ -152,10 +166,10 @@ this is ok
text(font: "Unbeknownst")[]
}
-/! allow("unknown-font-families")
+// @allow("unknown-font-families")
#f()
-/! allow("unknown-font-families")
+// @allow("unknown-font-families")
#context {
text(font: "Unbeknownst")[]
}