Repository: typst/typst
File: crates/typst-syntax/src/lexer.rs (Rust)

Code before:
        self.newline
    }

    /// Take out the last error, if any.
    pub fn take_error(&mut self) -> Option<SyntaxError> {
        self.error.take()
    }
}

impl Lexer<'_> {
    /// Construct a full-positioned syntax error.
    fn error(&mut self, message: impl Into<EcoString>) -> SyntaxKind {
        self.error = Some(SyntaxError {
            span: Span::detached(),
            message: message.into(),
            hints: eco_vec![],
        });
        SyntaxKind::Error
    }

    /// If the current node is an error, adds a hint.
    fn hint(&mut self, message: impl Into<EcoString>) {
        if let Some(mut e) = self.take_error() {
            e.hints.push(message.into());
            self.error = Some(e);
        }
    }
}

/// Shared methods with all [`LexMode`].
impl Lexer<'_> {
    /// Proceed to the next token and return its [`SyntaxKind`]. Note the
    /// token could be a [trivia](SyntaxKind::is_trivia).
    pub fn next(&mut self) -> SyntaxKind {
        if self.mode == LexMode::Raw {
            let Some((kind, end)) = self.raw.pop() else {
                return SyntaxKind::End;
            };
            self.s.jump(end);
            return kind;
        }

        self.newline = false;
        self.error = None;
        let start = self.s.cursor();
        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('*') => self.block_comment(),
            Some('*') if self.s.eat_if('/') => {
                let kind = self.error("unexpected end of block comment");

Review comment (suggestion):
```suggestion
        if let Some(error) = &mut self.error {
            error.hints.push(message.into());
        }
```

Code after:
        self.newline
    }

    /// Take out the last error, if any.
    pub fn take_error(&mut self) -> Option<SyntaxError> {
        self.error.take()
    }
}

impl Lexer<'_> {
    /// Construct a full-positioned syntax error.
    fn error(&mut self, message: impl Into<EcoString>) -> SyntaxKind {
        self.error = Some(SyntaxError::new(message));
        SyntaxKind::Error
    }

    /// If the current node is an error, adds a hint.
    fn hint(&mut self, message: impl Into<EcoString>) {
        if let Some(error) = &mut self.error {
            error.hints.push(message.into());
        }
    }
}

/// Shared methods with all [`LexMode`].
impl Lexer<'_> {
    /// Proceed to the next token and return its [`SyntaxKind`]. Note the
    /// token could be a [trivia](SyntaxKind::is_trivia).
    pub fn next(&mut self) -> SyntaxKind {
        if self.mode == LexMode::Raw {
            let Some((kind, end)) = self.raw.pop() else {
                return SyntaxKind::End;
            };
            self.s.jump(end);
            return kind;
        }

        self.newline = false;
        self.error = None;
        let start = self.s.cursor();
        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('*') => self.block_comment(),
            Some('*') if self.s.eat_if('/') => {
                let kind = self.error("unexpected end of block comment");
                self.hint(
                    "consider escaping the `*` with a backslash or \
                     opening the block comment with `/*`",
                );
                kind