initial decorator lexing

This commit is contained in:
PgBiel 2024-06-10 17:21:02 -03:00
parent 849bb632f7
commit 1623a9135d

View File

@ -18,6 +18,8 @@ pub(super) struct Lexer<'s> {
newline: bool, newline: bool,
/// The state held by raw line lexing. /// The state held by raw line lexing.
raw: Vec<(SyntaxKind, usize)>, raw: Vec<(SyntaxKind, usize)>,
/// The state held by decorator lexing.
decorator: Vec<(SyntaxKind, usize)>,
/// An error for the last token. /// An error for the last token.
error: Option<SyntaxError>, error: Option<SyntaxError>,
} }
@ -33,6 +35,8 @@ pub(super) enum LexMode {
Code, Code,
/// The contents of a raw block. /// The contents of a raw block.
Raw, Raw,
/// The contents of a decorator.
Decorator,
} }
impl<'s> Lexer<'s> { impl<'s> Lexer<'s> {
@ -45,6 +49,7 @@ impl<'s> Lexer<'s> {
newline: false, newline: false,
error: None, error: None,
raw: Vec::new(), raw: Vec::new(),
decorator: Vec::new(),
} }
} }
@ -108,6 +113,14 @@ impl Lexer<'_> {
return kind; return kind;
} }
if self.mode == LexMode::Decorator {
let Some((kind, end)) = self.decorator.pop() else {
return SyntaxKind::End;
};
self.s.jump(end);
return kind;
}
self.newline = false; self.newline = false;
self.error = None; self.error = None;
let start = self.s.cursor(); let start = self.s.cursor();
@ -115,6 +128,7 @@ impl Lexer<'_> {
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('/') => self.line_comment(),
Some('/') if self.s.eat_if('*') => self.block_comment(), Some('/') if self.s.eat_if('*') => self.block_comment(),
Some('/') if self.s.eat_if('!') => self.decorator(),
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(
@ -123,12 +137,12 @@ impl Lexer<'_> {
); );
kind kind
} }
Some(c) => match self.mode { Some(c) => match self.mode {
LexMode::Markup => self.markup(start, c), LexMode::Markup => self.markup(start, c),
LexMode::Math => self.math(start, c), LexMode::Math => self.math(start, c),
LexMode::Code => self.code(start, c), LexMode::Code => self.code(start, c),
LexMode::Raw => unreachable!(), LexMode::Raw => unreachable!(),
LexMode::Decorator => unreachable!(),
}, },
None => SyntaxKind::End, None => SyntaxKind::End,
@ -151,10 +165,6 @@ impl Lexer<'_> {
} }
} }
fn decorator(&mut self) -> SyntaxKind {
todo!()
}
fn line_comment(&mut self) -> SyntaxKind { fn line_comment(&mut self) -> SyntaxKind {
self.s.eat_until(is_newline); self.s.eat_until(is_newline);
SyntaxKind::LineComment SyntaxKind::LineComment
@ -186,6 +196,44 @@ impl Lexer<'_> {
} }
} }
/// Decorators.
impl Lexer<'_> {
fn decorator(&mut self) -> SyntaxKind {
let start = self.s.cursor() - 1;
self.decorator.clear();
while !self.s.eat_newline() {
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('/') => break,
Some('/') if self.s.eat_if('*') => self.block_comment(),
Some('(') => SyntaxKind::LeftParen,
Some(')') => SyntaxKind::RightParen,
Some('"') => self.string(),
Some(c @ '0'..='9') => self.number(start, c),
Some(',') => SyntaxKind::Comma,
Some(c) if is_id_start(c) => self.ident(start),
Some(c) => {
return self.error(eco_format!(
"the character {c} is not valid in a decorator"
))
}
None => break,
};
let end = self.s.cursor();
self.decorator.push((token, end));
}
// Already collected all we need from the decorator.
self.s.jump(start + 1);
SyntaxKind::Decorator
}
}
/// Markup. /// Markup.
impl Lexer<'_> { impl Lexer<'_> {
fn markup(&mut self, start: usize, c: char) -> SyntaxKind { fn markup(&mut self, start: usize, c: char) -> SyntaxKind {