create DecoratorMarker and DecoratorName

This commit is contained in:
PgBiel 2024-06-24 19:21:33 -03:00
parent d35a563b3c
commit 14dfb3f630
5 changed files with 56 additions and 17 deletions

View File

@ -80,6 +80,22 @@ impl<'a> Markup<'a> {
} }
} }
node! {
DecoratorName
}
impl<'a> DecoratorName<'a> {
/// Get the decorator name.
pub fn get(self) -> &'a EcoString {
self.0.text()
}
/// Get the decorator name as a string slice.
pub fn as_str(self) -> &'a str {
self.get()
}
}
node! { node! {
/// A decorator: `/! allow("warning")`. /// A decorator: `/! allow("warning")`.
Decorator Decorator
@ -87,7 +103,7 @@ node! {
impl<'a> Decorator<'a> { impl<'a> Decorator<'a> {
/// The name of the decorator, e.g. `allow`. /// The name of the decorator, e.g. `allow`.
pub fn name(self) -> Ident<'a> { pub fn name(self) -> DecoratorName<'a> {
self.0.cast_first_match().unwrap_or_default() self.0.cast_first_match().unwrap_or_default()
} }

View File

@ -287,6 +287,8 @@ pub fn highlight(node: &LinkedNode) -> Option<Tag> {
SyntaxKind::DestructAssignment => None, SyntaxKind::DestructAssignment => None,
SyntaxKind::Decorator => None, SyntaxKind::Decorator => None,
SyntaxKind::DecoratorMarker => None,
SyntaxKind::DecoratorName => None,
SyntaxKind::LineComment => Some(Tag::Comment), SyntaxKind::LineComment => Some(Tag::Comment),
SyntaxKind::BlockComment => Some(Tag::Comment), SyntaxKind::BlockComment => Some(Tag::Comment),

View File

@ -280,6 +280,11 @@ pub enum SyntaxKind {
Destructuring, Destructuring,
/// A destructuring assignment expression: `(x, y) = (1, 2)`. /// A destructuring assignment expression: `(x, y) = (1, 2)`.
DestructAssignment, DestructAssignment,
/// A decorator's marker: `/!`.
DecoratorMarker,
/// A decorator's name: `allow`.
DecoratorName,
} }
impl SyntaxKind { impl SyntaxKind {
@ -505,6 +510,8 @@ impl SyntaxKind {
Self::FuncReturn => "`return` expression", Self::FuncReturn => "`return` expression",
Self::Destructuring => "destructuring pattern", Self::Destructuring => "destructuring pattern",
Self::DestructAssignment => "destructuring assignment expression", Self::DestructAssignment => "destructuring assignment expression",
Self::DecoratorMarker => "decorator marker",
Self::DecoratorName => "decorator name",
} }
} }
} }

View File

@ -222,16 +222,18 @@ impl Lexer<'_> {
/// `/! decorator-name("string argument1", "string argument2")` /// `/! decorator-name("string argument1", "string argument2")`
/// with optional whitespaces and comments between arguments. /// with optional whitespaces and comments between arguments.
fn decorator(&mut self, start: usize) -> SyntaxNode { fn decorator(&mut self, start: usize) -> SyntaxNode {
// TODO: DecoratorMarker node // Start by lexing the marker.
let current_start = start; let marker = self.emit_token(SyntaxKind::DecoratorMarker, start);
let mut subtree = vec![]; let mut subtree = vec![marker];
let current_start = self.s.cursor();
// Ignore initial non-newline whitespaces // Ignore initial non-newline whitespaces
if !self.s.eat_while(is_inline_whitespace).is_empty() { if !self.s.eat_while(is_inline_whitespace).is_empty() {
subtree.push(self.emit_token(SyntaxKind::Space, current_start)); subtree.push(self.emit_token(SyntaxKind::Space, current_start));
} }
// Decorator's name // Lex the decorator name
let current_start = self.s.cursor(); let current_start = self.s.cursor();
if !self.s.eat_if(is_id_start) { if !self.s.eat_if(is_id_start) {
self.s.eat_until(is_newline); self.s.eat_until(is_newline);
@ -241,17 +243,8 @@ impl Lexer<'_> {
return SyntaxNode::inner(SyntaxKind::Decorator, subtree); return SyntaxNode::inner(SyntaxKind::Decorator, subtree);
} }
self.s.eat_while(is_id_continue); let decorator_name = self.decorator_name(current_start);
let ident = self.s.from(current_start); subtree.push(self.emit_token(decorator_name, current_start));
subtree.push(if ident == "allow" {
self.emit_token(SyntaxKind::Ident, current_start)
} else {
self.emit_error(
eco_format!("expected decorator name 'allow', found '{ident}'"),
current_start,
)
});
// Left parenthesis before decorator arguments // Left parenthesis before decorator arguments
let current_start = self.s.cursor(); let current_start = self.s.cursor();
@ -323,6 +316,26 @@ impl Lexer<'_> {
SyntaxNode::inner(SyntaxKind::Decorator, subtree) SyntaxNode::inner(SyntaxKind::Decorator, subtree)
} }
/// Lexes a decorator name.
/// A decorator name is an identifier within a specific subset of allowed
/// identifiers.
/// Currently, `allow` is the only valid decorator name.
fn decorator_name(&mut self, start: usize) -> SyntaxKind {
self.s.eat_while(is_id_continue);
let ident = self.s.from(start);
if ident == "allow" {
SyntaxKind::DecoratorName
} else {
let error = self.error(eco_format!("invalid decorator name"));
self.hint("must be 'allow'");
error
}
}
/// Lexes a string in a decorator.
/// Currently, such strings only allow a very restricted set of characters.
/// These restrictions may be lifted in the future.
fn decorator_string(&mut self) -> SyntaxKind { fn decorator_string(&mut self) -> SyntaxKind {
// TODO: Allow more characters in decorators' strings, perhaps allowing // TODO: Allow more characters in decorators' strings, perhaps allowing
// newlines somehow. // newlines somehow.

View File

@ -36,7 +36,8 @@ this is ok
/! allow("@some/thing-there123") /! allow("@some/thing-there123")
--- unknown-decorator --- --- unknown-decorator ---
// Error: 4-12 expected decorator name 'allow', found 'whatever' // Error: 4-12 invalid decorator name
// Hint: 4-12 must be 'allow'
/! whatever() /! whatever()
--- invalid-decorator-syntax --- --- invalid-decorator-syntax ---