@@ -2,7 +2,6 @@ use std::fmt;
2
2
3
3
use ruff_text_size:: TextRange ;
4
4
5
- use crate :: lexer:: { LexicalError , LexicalErrorType } ;
6
5
use crate :: TokenKind ;
7
6
8
7
/// Represents represent errors that occur during parsing and are
@@ -295,3 +294,135 @@ impl std::fmt::Display for ParseErrorType {
295
294
}
296
295
}
297
296
}
297
+
298
+ /// Represents an error that occur during lexing and are
299
+ /// returned by the `parse_*` functions in the iterator in the
300
+ /// [lexer] implementation.
301
+ ///
302
+ /// [lexer]: crate::lexer
303
+ #[ derive( Debug , Clone , PartialEq ) ]
304
+ pub struct LexicalError {
305
+ /// The type of error that occurred.
306
+ error : LexicalErrorType ,
307
+ /// The location of the error.
308
+ location : TextRange ,
309
+ }
310
+
311
+ impl LexicalError {
312
+ /// Creates a new `LexicalError` with the given error type and location.
313
+ pub fn new ( error : LexicalErrorType , location : TextRange ) -> Self {
314
+ Self { error, location }
315
+ }
316
+
317
+ pub fn error ( & self ) -> & LexicalErrorType {
318
+ & self . error
319
+ }
320
+
321
+ pub fn into_error ( self ) -> LexicalErrorType {
322
+ self . error
323
+ }
324
+
325
+ pub fn location ( & self ) -> TextRange {
326
+ self . location
327
+ }
328
+ }
329
+
330
+ impl std:: ops:: Deref for LexicalError {
331
+ type Target = LexicalErrorType ;
332
+
333
+ fn deref ( & self ) -> & Self :: Target {
334
+ self . error ( )
335
+ }
336
+ }
337
+
338
+ impl std:: error:: Error for LexicalError {
339
+ fn source ( & self ) -> Option < & ( dyn std:: error:: Error + ' static ) > {
340
+ Some ( self . error ( ) )
341
+ }
342
+ }
343
+
344
+ impl std:: fmt:: Display for LexicalError {
345
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter ) -> std:: fmt:: Result {
346
+ write ! (
347
+ f,
348
+ "{} at byte offset {}" ,
349
+ self . error( ) ,
350
+ u32 :: from( self . location( ) . start( ) )
351
+ )
352
+ }
353
+ }
354
+
355
+ /// Represents the different types of errors that can occur during lexing.
356
+ #[ derive( Debug , Clone , PartialEq ) ]
357
+ pub enum LexicalErrorType {
358
+ // TODO: Can probably be removed, the places it is used seem to be able
359
+ // to use the `UnicodeError` variant instead.
360
+ #[ doc( hidden) ]
361
+ StringError ,
362
+ /// A string literal without the closing quote.
363
+ UnclosedStringError ,
364
+ /// Decoding of a unicode escape sequence in a string literal failed.
365
+ UnicodeError ,
366
+ /// Missing the `{` for unicode escape sequence.
367
+ MissingUnicodeLbrace ,
368
+ /// Missing the `}` for unicode escape sequence.
369
+ MissingUnicodeRbrace ,
370
+ /// The indentation is not consistent.
371
+ IndentationError ,
372
+ /// An unrecognized token was encountered.
373
+ UnrecognizedToken { tok : char } ,
374
+ /// An f-string error containing the [`FStringErrorType`].
375
+ FStringError ( FStringErrorType ) ,
376
+ /// Invalid character encountered in a byte literal.
377
+ InvalidByteLiteral ,
378
+ /// An unexpected character was encountered after a line continuation.
379
+ LineContinuationError ,
380
+ /// An unexpected end of file was encountered.
381
+ Eof ,
382
+ /// An unexpected error occurred.
383
+ OtherError ( Box < str > ) ,
384
+ }
385
+
386
+ impl std:: error:: Error for LexicalErrorType { }
387
+
388
+ impl std:: fmt:: Display for LexicalErrorType {
389
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter ) -> std:: fmt:: Result {
390
+ match self {
391
+ LexicalErrorType :: StringError => write ! ( f, "Got unexpected string" ) ,
392
+ LexicalErrorType :: FStringError ( error) => write ! ( f, "f-string: {error}" ) ,
393
+ LexicalErrorType :: InvalidByteLiteral => {
394
+ write ! ( f, "bytes can only contain ASCII literal characters" )
395
+ }
396
+ LexicalErrorType :: UnicodeError => write ! ( f, "Got unexpected unicode" ) ,
397
+ LexicalErrorType :: IndentationError => {
398
+ write ! ( f, "unindent does not match any outer indentation level" )
399
+ }
400
+ LexicalErrorType :: UnrecognizedToken { tok } => {
401
+ write ! ( f, "Got unexpected token {tok}" )
402
+ }
403
+ LexicalErrorType :: LineContinuationError => {
404
+ write ! ( f, "unexpected character after line continuation character" )
405
+ }
406
+ LexicalErrorType :: Eof => write ! ( f, "unexpected EOF while parsing" ) ,
407
+ LexicalErrorType :: OtherError ( msg) => write ! ( f, "{msg}" ) ,
408
+ LexicalErrorType :: UnclosedStringError => {
409
+ write ! ( f, "missing closing quote in string literal" )
410
+ }
411
+ LexicalErrorType :: MissingUnicodeLbrace => {
412
+ write ! ( f, "Missing `{{` in Unicode escape sequence" )
413
+ }
414
+ LexicalErrorType :: MissingUnicodeRbrace => {
415
+ write ! ( f, "Missing `}}` in Unicode escape sequence" )
416
+ }
417
+ }
418
+ }
419
+ }
420
+
421
+ #[ cfg( target_pointer_width = "64" ) ]
422
+ mod sizes {
423
+ use crate :: error:: { LexicalError , LexicalErrorType } ;
424
+ use static_assertions:: assert_eq_size;
425
+
426
+ assert_eq_size ! ( LexicalErrorType , [ u8 ; 24 ] ) ;
427
+ assert_eq_size ! ( LexicalError , [ u8 ; 32 ] ) ;
428
+ }
0 commit comments