mirror of
https://github.com/typst/typst
synced 2025-05-13 20:46:23 +08:00
parent
20b8d2c121
commit
ad4ef68a11
@ -4,7 +4,7 @@ use unicode_script::{Script, UnicodeScript};
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
use unscanny::Scanner;
|
||||
|
||||
use crate::SyntaxKind;
|
||||
use crate::{SyntaxError, SyntaxKind};
|
||||
|
||||
/// Splits up a string of source code into tokens.
|
||||
#[derive(Clone)]
|
||||
@ -19,7 +19,7 @@ pub(super) struct Lexer<'s> {
|
||||
/// The state held by raw line lexing.
|
||||
raw: Vec<(SyntaxKind, usize)>,
|
||||
/// An error for the last token.
|
||||
error: Option<EcoString>,
|
||||
error: Option<SyntaxError>,
|
||||
}
|
||||
|
||||
/// What kind of tokens to emit.
|
||||
@ -75,7 +75,7 @@ impl<'s> Lexer<'s> {
|
||||
}
|
||||
|
||||
/// Take out the last error, if any.
|
||||
pub fn take_error(&mut self) -> Option<EcoString> {
|
||||
pub fn take_error(&mut self) -> Option<SyntaxError> {
|
||||
self.error.take()
|
||||
}
|
||||
}
|
||||
@ -83,9 +83,16 @@ impl<'s> Lexer<'s> {
|
||||
impl Lexer<'_> {
|
||||
/// Construct a full-positioned syntax error.
|
||||
fn error(&mut self, message: impl Into<EcoString>) -> SyntaxKind {
|
||||
self.error = Some(message.into());
|
||||
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`].
|
||||
@ -109,7 +116,12 @@ impl Lexer<'_> {
|
||||
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.error("unexpected end of block comment")
|
||||
let kind = self.error("unexpected end of block comment");
|
||||
self.hint(
|
||||
"consider escaping the `*` with a backslash or \
|
||||
opening the block comment with `/*`",
|
||||
);
|
||||
kind
|
||||
}
|
||||
|
||||
Some(c) => match self.mode {
|
||||
|
@ -35,8 +35,8 @@ impl SyntaxNode {
|
||||
}
|
||||
|
||||
/// Create a new error node.
|
||||
pub fn error(message: impl Into<EcoString>, text: impl Into<EcoString>) -> Self {
|
||||
Self(Repr::Error(Arc::new(ErrorNode::new(message, text))))
|
||||
pub fn error(error: SyntaxError, text: impl Into<EcoString>) -> Self {
|
||||
Self(Repr::Error(Arc::new(ErrorNode::new(error, text))))
|
||||
}
|
||||
|
||||
/// Create a dummy node of the given kind.
|
||||
@ -209,7 +209,7 @@ impl SyntaxNode {
|
||||
pub(super) fn convert_to_error(&mut self, message: impl Into<EcoString>) {
|
||||
if !self.kind().is_error() {
|
||||
let text = std::mem::take(self).into_text();
|
||||
*self = SyntaxNode::error(message, text);
|
||||
*self = SyntaxNode::error(SyntaxError::new(message), text);
|
||||
}
|
||||
}
|
||||
|
||||
@ -628,15 +628,8 @@ struct ErrorNode {
|
||||
|
||||
impl ErrorNode {
|
||||
/// Create new error node.
|
||||
fn new(message: impl Into<EcoString>, text: impl Into<EcoString>) -> Self {
|
||||
Self {
|
||||
text: text.into(),
|
||||
error: SyntaxError {
|
||||
span: Span::detached(),
|
||||
message: message.into(),
|
||||
hints: eco_vec![],
|
||||
},
|
||||
}
|
||||
fn new(error: SyntaxError, text: impl Into<EcoString>) -> Self {
|
||||
Self { text: text.into(), error }
|
||||
}
|
||||
|
||||
/// The byte length of the node in the source text.
|
||||
@ -674,6 +667,15 @@ pub struct SyntaxError {
|
||||
}
|
||||
|
||||
impl SyntaxError {
|
||||
/// Create a new detached syntax error.
|
||||
pub fn new(message: impl Into<EcoString>) -> Self {
|
||||
Self {
|
||||
span: Span::detached(),
|
||||
message: message.into(),
|
||||
hints: eco_vec![],
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the two errors are the same apart from spans.
|
||||
fn spanless_eq(&self, other: &Self) -> bool {
|
||||
self.message == other.message && self.hints == other.hints
|
||||
|
@ -6,7 +6,9 @@ use ecow::{eco_format, EcoString};
|
||||
use unicode_math_class::MathClass;
|
||||
|
||||
use crate::set::SyntaxSet;
|
||||
use crate::{ast, is_ident, is_newline, set, LexMode, Lexer, SyntaxKind, SyntaxNode};
|
||||
use crate::{
|
||||
ast, is_ident, is_newline, set, LexMode, Lexer, SyntaxError, SyntaxKind, SyntaxNode,
|
||||
};
|
||||
|
||||
/// Parses a source file.
|
||||
pub fn parse(text: &str) -> SyntaxNode {
|
||||
@ -1760,8 +1762,8 @@ impl<'s> Parser<'s> {
|
||||
fn save(&mut self) {
|
||||
let text = self.current_text();
|
||||
if self.at(SyntaxKind::Error) {
|
||||
let message = self.lexer.take_error().unwrap();
|
||||
self.nodes.push(SyntaxNode::error(message, text));
|
||||
let error = self.lexer.take_error().unwrap();
|
||||
self.nodes.push(SyntaxNode::error(error, text));
|
||||
} else {
|
||||
self.nodes.push(SyntaxNode::leaf(self.current, text));
|
||||
}
|
||||
@ -1838,7 +1840,8 @@ impl<'s> Parser<'s> {
|
||||
/// Produce an error that the given `thing` was expected at the position
|
||||
/// of the marker `m`.
|
||||
fn expected_at(&mut self, m: Marker, thing: &str) {
|
||||
let error = SyntaxNode::error(eco_format!("expected {thing}"), "");
|
||||
let error =
|
||||
SyntaxNode::error(SyntaxError::new(eco_format!("expected {thing}")), "");
|
||||
self.nodes.insert(m.0, error);
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
--- array-bad-token ---
|
||||
// Error: 4-6 unexpected end of block comment
|
||||
// Hint: 4-6 consider escaping the `*` with a backslash or opening the block comment with `/*`
|
||||
#(1*/2)
|
||||
|
||||
--- array-bad-number-suffix ---
|
||||
|
@ -80,6 +80,7 @@
|
||||
|
||||
--- call-args-bad-token ---
|
||||
// Error: 10-12 unexpected end of block comment
|
||||
// Hint: 10-12 consider escaping the `*` with a backslash or opening the block comment with `/*`
|
||||
#func(a:1*/)
|
||||
|
||||
--- call-args-missing-comma ---
|
||||
|
@ -37,6 +37,7 @@ Second part
|
||||
--- comment-block-unclosed ---
|
||||
// End should not appear without start.
|
||||
// Error: 7-9 unexpected end of block comment
|
||||
// Hint: 7-9 consider escaping the `*` with a backslash or opening the block comment with `/*`
|
||||
/* */ */
|
||||
|
||||
// Unterminated is okay.
|
||||
|
Loading…
x
Reference in New Issue
Block a user