1use std::fmt::{self, Display};
2
3use ruff_python_ast::token::TokenKind;
4use ruff_python_ast::{ConstantValue, Expr, PythonVersion};
5use ruff_text_size::{Ranged, TextRange};
6
7use crate::string::InterpolatedStringKind;
8
9#[derive(Debug, PartialEq, Eq, Clone, get_size2::GetSize)]
12pub struct ParseError {
13 pub error: ParseErrorType,
14 pub location: TextRange,
15}
16
17impl std::ops::Deref for ParseError {
18 type Target = ParseErrorType;
19
20 fn deref(&self) -> &Self::Target {
21 &self.error
22 }
23}
24
25impl std::error::Error for ParseError {
26 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
27 Some(&self.error)
28 }
29}
30
31impl fmt::Display for ParseError {
32 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
33 write!(f, "{} at byte range {:?}", self.error, self.location)
34 }
35}
36
37impl From<LexicalError> for ParseError {
38 fn from(error: LexicalError) -> Self {
39 ParseError {
40 location: error.location(),
41 error: ParseErrorType::Lexical(error.into_error()),
42 }
43 }
44}
45
46impl Ranged for ParseError {
47 fn range(&self) -> TextRange {
48 self.location
49 }
50}
51
52impl ParseError {
53 pub fn error(self) -> ParseErrorType {
54 self.error
55 }
56}
57
58#[derive(Debug, Clone, Copy, PartialEq, Eq, get_size2::GetSize)]
60pub enum UnicodeEscapeErrorKind {
61 TruncatedHexByte,
63 TruncatedShortUnicode,
65 TruncatedLongUnicode,
67 IllegalCharacter,
69 MalformedName,
71 UnknownName,
73}
74
75impl Display for UnicodeEscapeErrorKind {
76 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77 f.write_str(match self {
78 Self::TruncatedHexByte => "truncated \\xXX escape",
79 Self::TruncatedShortUnicode => "truncated \\uXXXX escape",
80 Self::TruncatedLongUnicode => "truncated \\UXXXXXXXX escape",
81 Self::IllegalCharacter => "illegal Unicode character",
82 Self::MalformedName => "malformed \\N character escape",
83 Self::UnknownName => "unknown Unicode character name",
84 })
85 }
86}
87
88#[derive(Debug, Clone, PartialEq, Eq, get_size2::GetSize)]
90pub enum InterpolatedStringErrorType {
91 UnclosedLbrace,
93 InvalidConversionFlag,
95 SingleRbrace,
97 UnterminatedString { detected_line: u32 },
99 UnterminatedTripleQuotedString { detected_line: u32 },
101 LambdaWithoutParentheses,
103 ConversionFlagNotImmediatelyAfterExclamation,
105 NewlineInFormatSpec,
107 ExpressionRequiredBefore(char),
109 ExpectedExpressionAfterLbrace,
111 ExpectedSeparatorAfterExpression,
113 ExpectedSeparatorAfterDebug,
115 ExpectedSeparatorAfterConversion,
117 UnclosedFormatSpec,
119 MissingConversionFlag,
121 UnmatchedBracket(char),
123}
124
125impl std::fmt::Display for InterpolatedStringErrorType {
126 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
127 match self {
128 Self::UnclosedLbrace => f.write_str("expecting '}'"),
129 Self::InvalidConversionFlag => write!(f, "invalid conversion character"),
130 Self::SingleRbrace => f.write_str("single '}' is not allowed"),
131 Self::UnterminatedString { .. } => write!(f, "unterminated string"),
132 Self::UnterminatedTripleQuotedString { .. } => {
133 write!(f, "unterminated triple-quoted string")
134 }
135 Self::LambdaWithoutParentheses => {
136 write!(f, "lambda expressions are not allowed without parentheses")
137 }
138 Self::ConversionFlagNotImmediatelyAfterExclamation => write!(
139 f,
140 "conversion type must come right after the exclamation mark"
141 ),
142 Self::NewlineInFormatSpec => {
143 write!(
144 f,
145 "newlines are not allowed in format specifiers when using single quotes"
146 )
147 }
148 Self::ExpressionRequiredBefore(separator) => {
149 write!(f, "valid expression required before '{separator}'")
150 }
151 Self::ExpectedExpressionAfterLbrace => {
152 f.write_str("expecting a valid expression after '{'")
153 }
154 Self::ExpectedSeparatorAfterExpression => {
155 f.write_str("expecting '=', or '!', or ':', or '}'")
156 }
157 Self::ExpectedSeparatorAfterDebug => f.write_str("expecting '!', or ':', or '}'"),
158 Self::ExpectedSeparatorAfterConversion => f.write_str("expecting ':' or '}'"),
159 Self::UnclosedFormatSpec => f.write_str("expecting '}', or format specs"),
160 Self::MissingConversionFlag => f.write_str("missing conversion character"),
161 Self::UnmatchedBracket(closing) => write!(f, "unmatched '{closing}'"),
162 }
163 }
164}
165
166fn write_interpolated_string_error(
167 f: &mut std::fmt::Formatter,
168 kind: InterpolatedStringKind,
169 error: &InterpolatedStringErrorType,
170) -> std::fmt::Result {
171 match error {
172 InterpolatedStringErrorType::UnterminatedString { detected_line } => {
173 write!(
174 f,
175 "unterminated {kind} literal (detected at line {detected_line})"
176 )
177 }
178 InterpolatedStringErrorType::UnterminatedTripleQuotedString { detected_line } => {
179 write!(
180 f,
181 "unterminated triple-quoted {kind} literal (detected at line {detected_line})"
182 )
183 }
184 InterpolatedStringErrorType::NewlineInFormatSpec => write!(
185 f,
186 "{kind}: newlines are not allowed in format specifiers for single quoted {kind}s"
187 ),
188 _ => write!(f, "{kind}: {error}"),
189 }
190}
191
192#[derive(Debug, PartialEq, Eq, Clone, get_size2::GetSize)]
194pub enum ParseErrorType {
195 OtherError(String),
197
198 StringAnnotationError(&'static str),
200
201 EmptySlice,
203 EmptyGlobalNames,
205 EmptyNonlocalNames,
207 EmptyDeleteTargets,
209 EmptyImportNames,
211 EmptyTypeParams,
213
214 UnparenthesizedNamedExpression,
216 UnparenthesizedTupleExpression,
218 UnparenthesizedGeneratorExpression,
220
221 InvalidLambdaExpressionUsage,
223 InvalidYieldExpressionUsage,
225 InvalidStarredExpressionUsage,
227 InvalidStarPatternUsage,
229 InvalidMatchPatternTarget,
231
232 ParamAfterVarKeywordParam,
234 NonDefaultParamAfterDefaultParam,
236 VarParameterWithDefault,
238 VarKeywordParameterWithDefault,
240 ExpectedColonAfterDictionaryKey,
243
244 InvalidAssignmentTarget {
247 kind: ExpressionKind,
248 maybe_comparison: bool,
249 },
250 AssignmentInsteadOfComparison,
252 AssignmentToYield,
254 InvalidNamedAssignmentTarget(ExpressionKind),
256 InvalidAnnotatedAssignmentTarget,
258 InvalidAugmentedAssignmentTarget(ExpressionKind),
260 InvalidDeleteTarget(ExpressionKind),
262 InvalidImportTarget(ExpressionKind),
264 InvalidPatternTarget(ExpressionKind),
266 InvalidExceptTarget { kind: ExpressionKind, star: bool },
268
269 PositionalAfterKeywordArgument,
271 PositionalAfterKeywordUnpacking,
273 InvalidArgumentUnpackingOrder,
275 IterableUnpackingInComprehension,
277
278 SimpleStatementsOnSameLine,
280 SimpleAndCompoundStatementOnSameLine,
282
283 ExpectedKeywordParam,
285 ExpectedRealNumber,
287 ExpectedImaginaryNumber,
289 ExpectedExpression,
291 ExpectedIdentifier,
293 ExpectedToken {
295 expected: TokenKind,
296 found: TokenKind,
297 },
298
299 ExpectedIndentedBlock { clause: BlockClause, line: u32 },
302 UnexpectedIndentation,
304 UnexpectedTokenAfterAsync(TokenKind),
306 UnexpectedIpythonEscapeCommand,
308 UnexpectedExpressionToken,
310
311 FStringError(InterpolatedStringErrorType),
313 TStringError(InterpolatedStringErrorType),
315 Lexical(LexicalErrorType),
317}
318
319#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, get_size2::GetSize)]
321pub enum ExpressionKind {
322 Attribute,
323 Subscript,
324 Starred,
325 Name,
326 List,
327 Tuple,
328 Lambda,
329 FunctionCall,
330 Expression,
331 GeneratorExpression,
332 YieldExpression,
333 AwaitExpression,
334 ListComprehension,
335 SetComprehension,
336 DictComprehension,
337 DictLiteral,
338 SetDisplay,
339 FStringExpression,
340 TStringExpression,
341 None,
342 False,
343 True,
344 Ellipsis,
345 Literal,
346 Comparison,
347 ConditionalExpression,
348 NamedExpression,
349}
350
351impl ExpressionKind {
352 pub fn of(expr: &Expr) -> Self {
353 match expr {
354 Expr::Attribute(_) => Self::Attribute,
355 Expr::Subscript(_) => Self::Subscript,
356 Expr::Starred(_) => Self::Starred,
357 Expr::Name(_) => Self::Name,
358 Expr::List(_) => Self::List,
359 Expr::Tuple(_) => Self::Tuple,
360 Expr::Lambda(_) => Self::Lambda,
361 Expr::Call(_) => Self::FunctionCall,
362 Expr::BoolOp(_)
363 | Expr::BinOp(_)
364 | Expr::UnaryOp(_)
365 | Expr::Slice(_)
366 | Expr::IpyEscapeCommand(_) => Self::Expression,
367 Expr::Generator(_) => Self::GeneratorExpression,
368 Expr::Yield(_) | Expr::YieldFrom(_) => Self::YieldExpression,
369 Expr::Await(_) => Self::AwaitExpression,
370 Expr::ListComp(_) => Self::ListComprehension,
371 Expr::SetComp(_) => Self::SetComprehension,
372 Expr::DictComp(_) => Self::DictComprehension,
373 Expr::Dict(_) => Self::DictLiteral,
374 Expr::Set(_) => Self::SetDisplay,
375 Expr::FString(_) => Self::FStringExpression,
376 Expr::TString(_) => Self::TStringExpression,
377 Expr::NoneLiteral(_) => Self::None,
378 Expr::BooleanLiteral(literal) if literal.value => Self::True,
379 Expr::BooleanLiteral(_) => Self::False,
380 Expr::EllipsisLiteral(_) => Self::Ellipsis,
381 Expr::StringLiteral(_) | Expr::BytesLiteral(_) | Expr::NumberLiteral(_) => {
382 Self::Literal
383 }
384 Expr::Compare(_) => Self::Comparison,
385 Expr::If(_) => Self::ConditionalExpression,
386 Expr::Named(_) => Self::NamedExpression,
387 Expr::Constant(constant) => match constant.value {
388 ConstantValue::None => Self::None,
389 ConstantValue::Boolean(true) => Self::True,
390 ConstantValue::Boolean(false) => Self::False,
391 ConstantValue::Ellipsis => Self::Ellipsis,
392 _ => Self::Literal,
393 },
394 }
395 }
396}
397
398impl std::fmt::Display for ExpressionKind {
399 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
400 f.write_str(match self {
401 Self::Attribute => "attribute",
402 Self::Subscript => "subscript",
403 Self::Starred => "starred",
404 Self::Name => "name",
405 Self::List => "list",
406 Self::Tuple => "tuple",
407 Self::Lambda => "lambda",
408 Self::FunctionCall => "function call",
409 Self::Expression => "expression",
410 Self::GeneratorExpression => "generator expression",
411 Self::YieldExpression => "yield expression",
412 Self::AwaitExpression => "await expression",
413 Self::ListComprehension => "list comprehension",
414 Self::SetComprehension => "set comprehension",
415 Self::DictComprehension => "dict comprehension",
416 Self::DictLiteral => "dict literal",
417 Self::SetDisplay => "set display",
418 Self::FStringExpression => "f-string expression",
419 Self::TStringExpression => "t-string expression",
420 Self::None => "None",
421 Self::False => "False",
422 Self::True => "True",
423 Self::Ellipsis => "ellipsis",
424 Self::Literal => "literal",
425 Self::Comparison => "comparison",
426 Self::ConditionalExpression => "conditional expression",
427 Self::NamedExpression => "named expression",
428 })
429 }
430}
431
432#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, get_size2::GetSize)]
434pub enum BlockClause {
435 If,
436 Elif,
437 Else,
438 For,
439 With,
440 While,
441 Try,
442 Except,
443 ExceptStar,
444 Finally,
445 Match,
446 Case,
447 Class,
448 FunctionDef,
449}
450
451impl std::fmt::Display for BlockClause {
452 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
453 f.write_str(match self {
454 Self::If => "'if' statement",
455 Self::Elif => "'elif' statement",
456 Self::Else => "'else' statement",
457 Self::For => "'for' statement",
458 Self::With => "'with' statement",
459 Self::While => "'while' statement",
460 Self::Try => "'try' statement",
461 Self::Except => "'except' statement",
462 Self::ExceptStar => "'except*' statement",
463 Self::Finally => "'finally' statement",
464 Self::Match => "'match' statement",
465 Self::Case => "'case' statement",
466 Self::Class => "class definition",
467 Self::FunctionDef => "function definition",
468 })
469 }
470}
471
472impl ParseErrorType {
473 pub(crate) fn from_interpolated_string_error(
474 error: InterpolatedStringErrorType,
475 string_kind: InterpolatedStringKind,
476 ) -> Self {
477 match string_kind {
478 InterpolatedStringKind::FString => Self::FStringError(error),
479 InterpolatedStringKind::TString => Self::TStringError(error),
480 }
481 }
482}
483
484impl std::error::Error for ParseErrorType {}
485
486impl std::fmt::Display for ParseErrorType {
487 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
488 match self {
489 ParseErrorType::OtherError(msg) => f.write_str(msg),
490 ParseErrorType::ExpectedIndentedBlock { clause, line } => {
491 write!(
492 f,
493 "expected an indented block after {clause} on line {line}"
494 )
495 }
496 ParseErrorType::StringAnnotationError(msg) => f.write_str(msg),
497 ParseErrorType::ExpectedToken { found, expected } => match (*expected, *found) {
498 (TokenKind::Colon, TokenKind::Newline) => f.write_str("expected ':'"),
499 (TokenKind::Lpar, _) => f.write_str("expected '('"),
500 (TokenKind::Else, found) if found != TokenKind::Colon => {
501 f.write_str("expected 'else' after 'if' expression")
502 }
503 _ => f.write_str("invalid syntax"),
504 },
505 ParseErrorType::Lexical(lex_error) => write!(f, "{lex_error}"),
506 ParseErrorType::SimpleStatementsOnSameLine => f.write_str("invalid syntax"),
507 ParseErrorType::SimpleAndCompoundStatementOnSameLine => f.write_str("invalid syntax"),
508 ParseErrorType::UnexpectedTokenAfterAsync(kind) => {
509 write!(
510 f,
511 "expected `def`, `with` or `for` to follow `async`, found {kind}",
512 )
513 }
514 ParseErrorType::InvalidArgumentUnpackingOrder => {
515 f.write_str("iterable argument unpacking follows keyword argument unpacking")
516 }
517 ParseErrorType::IterableUnpackingInComprehension => {
518 f.write_str("iterable unpacking cannot be used in a comprehension")
519 }
520 ParseErrorType::UnparenthesizedNamedExpression => {
521 f.write_str("unparenthesized named expression cannot be used here")
522 }
523 ParseErrorType::UnparenthesizedTupleExpression => {
524 f.write_str("unparenthesized tuple expression cannot be used here")
525 }
526 ParseErrorType::UnparenthesizedGeneratorExpression => {
527 f.write_str("Generator expression must be parenthesized")
528 }
529 ParseErrorType::InvalidYieldExpressionUsage => {
530 f.write_str("yield expression cannot be used here")
531 }
532 ParseErrorType::InvalidLambdaExpressionUsage => {
533 f.write_str("lambda expression cannot be used here")
534 }
535 ParseErrorType::InvalidStarredExpressionUsage => f.write_str("invalid syntax"),
536 ParseErrorType::PositionalAfterKeywordArgument => {
537 f.write_str("positional argument follows keyword argument")
538 }
539 ParseErrorType::PositionalAfterKeywordUnpacking => {
540 f.write_str("positional argument follows keyword argument unpacking")
541 }
542 ParseErrorType::EmptySlice => f.write_str("expected index or slice expression"),
543 ParseErrorType::EmptyGlobalNames => {
544 f.write_str("global statement must have at least one name")
545 }
546 ParseErrorType::EmptyNonlocalNames => {
547 f.write_str("nonlocal statement must have at least one name")
548 }
549 ParseErrorType::EmptyDeleteTargets => {
550 f.write_str("delete statement must have at least one target")
551 }
552 ParseErrorType::EmptyImportNames => {
553 f.write_str("Expected one or more names after 'import'")
554 }
555 ParseErrorType::EmptyTypeParams => f.write_str("Type parameter list cannot be empty"),
556 ParseErrorType::ParamAfterVarKeywordParam => {
557 f.write_str("arguments cannot follow var-keyword argument")
558 }
559 ParseErrorType::NonDefaultParamAfterDefaultParam => {
560 f.write_str("parameter without a default follows parameter with a default")
561 }
562 ParseErrorType::ExpectedKeywordParam => {
563 f.write_str("named arguments must follow bare *")
564 }
565 ParseErrorType::VarKeywordParameterWithDefault => {
566 f.write_str("var-keyword argument cannot have default value")
567 }
568 ParseErrorType::ExpectedColonAfterDictionaryKey => {
569 f.write_str("':' expected after dictionary key")
570 }
571 ParseErrorType::VarParameterWithDefault => {
572 f.write_str("var-positional argument cannot have default value")
573 }
574 ParseErrorType::InvalidStarPatternUsage => {
575 f.write_str("cannot use starred expression here")
576 }
577 ParseErrorType::InvalidMatchPatternTarget => f.write_str("cannot use '_' as a target"),
578 ParseErrorType::ExpectedRealNumber => {
579 f.write_str("expected a real number in complex literal pattern")
580 }
581 ParseErrorType::ExpectedImaginaryNumber => {
582 f.write_str("expected an imaginary number in complex literal pattern")
583 }
584 ParseErrorType::ExpectedExpression | ParseErrorType::ExpectedIdentifier => {
585 f.write_str("invalid syntax")
586 }
587 ParseErrorType::UnexpectedIndentation => f.write_str("unexpected indent"),
588 ParseErrorType::InvalidAssignmentTarget {
589 kind,
590 maybe_comparison: false,
591 } => write!(f, "cannot assign to {kind}"),
592 ParseErrorType::InvalidAssignmentTarget {
593 kind,
594 maybe_comparison: true,
595 } => write!(
596 f,
597 "cannot assign to {kind} here. Maybe you meant '==' instead of '='?"
598 ),
599 ParseErrorType::AssignmentInsteadOfComparison => {
600 f.write_str("invalid syntax. Maybe you meant '==' or ':=' instead of '='?")
601 }
602 ParseErrorType::AssignmentToYield => {
603 f.write_str("assignment to yield expression not possible")
604 }
605 ParseErrorType::InvalidAnnotatedAssignmentTarget => {
606 f.write_str("illegal target for annotation")
607 }
608 ParseErrorType::InvalidNamedAssignmentTarget(kind) => {
609 write!(f, "cannot use assignment expressions with {kind}")
610 }
611 ParseErrorType::InvalidAugmentedAssignmentTarget(kind) => {
612 write!(
613 f,
614 "'{kind}' is an illegal expression for augmented assignment"
615 )
616 }
617 ParseErrorType::InvalidDeleteTarget(kind) => write!(f, "cannot delete {kind}"),
618 ParseErrorType::InvalidImportTarget(kind) => {
619 write!(f, "cannot use {kind} as import target")
620 }
621 ParseErrorType::InvalidPatternTarget(kind) => {
622 write!(f, "cannot use {kind} as pattern target")
623 }
624 ParseErrorType::InvalidExceptTarget { kind, star } => {
625 let clause = if *star { "except*" } else { "except" };
626 write!(f, "cannot use {clause} statement with {kind}")
627 }
628 ParseErrorType::UnexpectedIpythonEscapeCommand => {
629 f.write_str("IPython escape commands are only allowed in `Mode::Ipython`")
630 }
631 ParseErrorType::FStringError(error) => {
632 write_interpolated_string_error(f, InterpolatedStringKind::FString, error)
633 }
634 ParseErrorType::TStringError(error) => {
635 write_interpolated_string_error(f, InterpolatedStringKind::TString, error)
636 }
637 ParseErrorType::UnexpectedExpressionToken => f.write_str("invalid syntax"),
638 }
639 }
640}
641
642#[derive(Debug, Clone, PartialEq)]
648pub struct LexicalError {
649 error: LexicalErrorType,
651 location: TextRange,
653}
654
655impl LexicalError {
656 pub fn new(error: LexicalErrorType, location: TextRange) -> Self {
658 Self { error, location }
659 }
660
661 pub fn error(&self) -> &LexicalErrorType {
662 &self.error
663 }
664
665 pub fn into_error(self) -> LexicalErrorType {
666 self.error
667 }
668
669 pub fn location(&self) -> TextRange {
670 self.location
671 }
672}
673
674impl std::ops::Deref for LexicalError {
675 type Target = LexicalErrorType;
676
677 fn deref(&self) -> &Self::Target {
678 self.error()
679 }
680}
681
682impl std::error::Error for LexicalError {
683 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
684 Some(self.error())
685 }
686}
687
688impl std::fmt::Display for LexicalError {
689 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
690 write!(
691 f,
692 "{} at byte offset {}",
693 self.error(),
694 u32::from(self.location().start())
695 )
696 }
697}
698
699#[derive(Debug, Clone, PartialEq, Eq, get_size2::GetSize)]
701pub enum LexicalErrorType {
702 #[doc(hidden)]
705 StringError,
706 UnclosedStringError {
708 triple_quoted: bool,
709 escaped_end_quote: bool,
711 detected_line: u32,
712 },
713 UnicodeEscapeError {
717 kind: UnicodeEscapeErrorKind,
718 start: u32,
719 end: u32,
720 },
721 BytesEscapeError { position: u32 },
724 IndentationError,
726 TabError,
728 TooDeepIndentation,
730 UnrecognizedToken { tok: char },
732 FStringError(InterpolatedStringErrorType),
734 TStringError(InterpolatedStringErrorType),
736 InvalidByteLiteral,
738 LineContinuationError,
740 Eof,
742 UnmatchedBracket { closing: char },
744 MismatchedBracket {
747 closing: char,
748 opening: char,
749 opening_line: Option<u32>,
750 },
751 UnclosedBracket { opening: char, incomplete: bool },
757 TooDeeplyNestedBrackets,
759 InvalidNumberLiteral { kind: NumberLiteralKind },
761 InvalidDigit {
763 digit: char,
764 kind: NumberLiteralKind,
765 },
766 LeadingZerosInDecimalInteger,
768 IncompatibleStringPrefixes { first: char, second: char },
770 OtherError(Box<str>),
772}
773
774impl std::error::Error for LexicalErrorType {}
775
776#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, get_size2::GetSize)]
778pub enum NumberLiteralKind {
779 Decimal,
780 Hexadecimal,
781 Octal,
782 Binary,
783 Imaginary,
784}
785
786impl std::fmt::Display for NumberLiteralKind {
787 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
788 f.write_str(match self {
789 Self::Decimal => "decimal",
790 Self::Hexadecimal => "hexadecimal",
791 Self::Octal => "octal",
792 Self::Binary => "binary",
793 Self::Imaginary => "imaginary",
794 })
795 }
796}
797
798fn is_printable(c: char) -> bool {
801 use icu_properties::props::{EnumeratedProperty, GeneralCategory};
802
803 c == ' '
804 || !matches!(
805 GeneralCategory::for_char(c),
806 GeneralCategory::SpaceSeparator
807 | GeneralCategory::LineSeparator
808 | GeneralCategory::ParagraphSeparator
809 | GeneralCategory::Control
810 | GeneralCategory::Format
811 | GeneralCategory::Surrogate
812 | GeneralCategory::PrivateUse
813 | GeneralCategory::Unassigned
814 )
815}
816
817impl LexicalErrorType {
818 pub(crate) fn is_unclosed_string_error(&self) -> bool {
820 matches!(
821 self,
822 Self::UnclosedStringError { .. }
823 | Self::FStringError(InterpolatedStringErrorType::UnclosedLbrace)
824 | Self::TStringError(InterpolatedStringErrorType::UnclosedLbrace)
825 )
826 }
827
828 pub fn is_tokenizer_error(&self) -> bool {
831 match self {
832 Self::StringError
833 | Self::UnicodeEscapeError { .. }
834 | Self::BytesEscapeError { .. }
835 | Self::InvalidByteLiteral
836 | Self::OtherError(_) => false,
837 Self::UnrecognizedToken { tok } => !tok.is_ascii() || !is_printable(*tok),
839 Self::FStringError(error) | Self::TStringError(error) => matches!(
840 error,
841 InterpolatedStringErrorType::UnterminatedString { .. }
842 | InterpolatedStringErrorType::UnterminatedTripleQuotedString { .. }
843 | InterpolatedStringErrorType::SingleRbrace
844 | InterpolatedStringErrorType::NewlineInFormatSpec
845 | InterpolatedStringErrorType::UnclosedLbrace
846 | InterpolatedStringErrorType::UnmatchedBracket(_)
847 ),
848 Self::UnclosedStringError { .. }
849 | Self::IndentationError
850 | Self::TabError
851 | Self::TooDeepIndentation
852 | Self::LineContinuationError
853 | Self::Eof
854 | Self::UnmatchedBracket { .. }
855 | Self::MismatchedBracket { .. }
856 | Self::UnclosedBracket { .. }
857 | Self::TooDeeplyNestedBrackets
858 | Self::InvalidNumberLiteral { .. }
859 | Self::InvalidDigit { .. }
860 | Self::LeadingZerosInDecimalInteger
861 | Self::IncompatibleStringPrefixes { .. } => true,
862 }
863 }
864
865 pub(crate) fn from_interpolated_string_error(
866 error: InterpolatedStringErrorType,
867 string_kind: InterpolatedStringKind,
868 ) -> Self {
869 match string_kind {
870 InterpolatedStringKind::FString => Self::FStringError(error),
871 InterpolatedStringKind::TString => Self::TStringError(error),
872 }
873 }
874}
875
876impl std::fmt::Display for LexicalErrorType {
877 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
878 match self {
879 Self::StringError => write!(f, "got unexpected string"),
880 Self::FStringError(error) => {
881 write_interpolated_string_error(f, InterpolatedStringKind::FString, error)
882 }
883 Self::TStringError(error) => {
884 write_interpolated_string_error(f, InterpolatedStringKind::TString, error)
885 }
886 Self::InvalidByteLiteral => {
887 write!(f, "bytes can only contain ASCII literal characters")
888 }
889 Self::UnicodeEscapeError { kind, start, end } => write!(
890 f,
891 "(unicode error) 'unicodeescape' codec can't decode bytes in position {start}-{end}: {kind}"
892 ),
893 Self::BytesEscapeError { position } => {
894 write!(f, "(value error) invalid \\x escape at position {position}")
895 }
896 Self::IndentationError => {
897 write!(f, "unindent does not match any outer indentation level")
898 }
899 Self::TabError => write!(f, "inconsistent use of tabs and spaces in indentation"),
900 Self::TooDeepIndentation => write!(f, "too many levels of indentation"),
901 Self::UnrecognizedToken { tok } if !is_printable(*tok) => {
902 write!(
903 f,
904 "invalid non-printable character U+{:04X}",
905 u32::from(*tok)
906 )
907 }
908 Self::UnrecognizedToken { tok } if !tok.is_ascii() => {
909 write!(f, "invalid character '{tok}' (U+{:04X})", u32::from(*tok))
910 }
911 Self::UnrecognizedToken { .. } => f.write_str("invalid syntax"),
912 Self::InvalidNumberLiteral { kind } => write!(f, "invalid {kind} literal"),
913 Self::InvalidDigit { digit, kind } => {
914 write!(f, "invalid digit '{digit}' in {kind} literal")
915 }
916 Self::LeadingZerosInDecimalInteger => f.write_str(
917 "leading zeros in decimal integer literals are not permitted; use an 0o prefix for octal integers",
918 ),
919 Self::IncompatibleStringPrefixes { first, second } => {
920 write!(f, "'{first}' and '{second}' prefixes are incompatible")
921 }
922 Self::LineContinuationError => {
923 write!(f, "unexpected character after line continuation character")
924 }
925 Self::Eof => write!(f, "unexpected EOF while parsing"),
926 Self::UnmatchedBracket { closing } => write!(f, "unmatched '{closing}'"),
927 Self::MismatchedBracket {
928 closing,
929 opening,
930 opening_line,
931 } => {
932 write!(
933 f,
934 "closing parenthesis '{closing}' does not match opening parenthesis '{opening}'"
935 )?;
936 if let Some(line) = opening_line {
937 write!(f, " on line {line}")?;
938 }
939 Ok(())
940 }
941 Self::UnclosedBracket { opening, .. } => write!(f, "'{opening}' was never closed"),
942 Self::TooDeeplyNestedBrackets => f.write_str("too many nested parentheses"),
943 Self::OtherError(msg) => write!(f, "{msg}"),
944 Self::UnclosedStringError {
945 triple_quoted: true,
946 detected_line,
947 ..
948 } => write!(
949 f,
950 "unterminated triple-quoted string literal (detected at line {detected_line})"
951 ),
952 Self::UnclosedStringError {
953 escaped_end_quote,
954 detected_line,
955 ..
956 } => {
957 write!(
958 f,
959 "unterminated string literal (detected at line {detected_line})"
960 )?;
961 if *escaped_end_quote {
962 f.write_str("; perhaps you escaped the end quote?")?;
963 }
964 Ok(())
965 }
966 }
967 }
968}
969
970#[derive(Debug, PartialEq, Clone, get_size2::GetSize)]
975pub struct UnsupportedSyntaxError {
976 pub kind: UnsupportedSyntaxErrorKind,
977 pub range: TextRange,
978 pub target_version: PythonVersion,
980}
981
982impl Ranged for UnsupportedSyntaxError {
983 fn range(&self) -> TextRange {
984 self.range
985 }
986}
987
988#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, get_size2::GetSize)]
990pub enum StarTupleKind {
991 Return,
992 Yield,
993}
994
995#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, get_size2::GetSize)]
997pub enum FStringKind {
998 Backslash,
999 Comment,
1000 LineBreak,
1001 NestedQuote,
1002}
1003
1004#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, get_size2::GetSize)]
1007pub enum ComprehensionUnpackingKind {
1008 IterableInList,
1009 IterableInSet,
1010 IterableInGenerator,
1011 DictInDict,
1012}
1013
1014#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, get_size2::GetSize)]
1015pub enum UnparenthesizedNamedExprKind {
1016 SequenceIndex,
1017 SetLiteral,
1018 SetComprehension,
1019}
1020
1021#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, get_size2::GetSize)]
1022pub enum UnsupportedSyntaxErrorKind {
1023 Match,
1024 Walrus,
1025 ExceptStar,
1026 UnparenthesizedNamedExpr(UnparenthesizedNamedExprKind),
1063
1064 ParenthesizedKeywordArgumentName,
1083
1084 StarTuple(StarTupleKind),
1132
1133 RelaxedDecorator(RelaxedDecoratorError),
1164
1165 PositionalOnlyParameter,
1191
1192 TypeParameterList,
1220 LazyImportStatement,
1221 TypeAliasStatement,
1222 TypeParamDefault,
1223
1224 Pep701FString(FStringKind),
1256
1257 ParenthesizedContextManager,
1296
1297 StarExpressionInIndex,
1324
1325 StarAnnotation,
1351
1352 UnpackingInComprehension(ComprehensionUnpackingKind),
1378
1379 UnparenthesizedUnpackInFor,
1405 UnparenthesizedExceptionTypes,
1440 TemplateStrings,
1446
1447 UnaryPlusMatchPattern,
1457}
1458
1459impl Display for UnsupportedSyntaxError {
1460 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1461 let kind = match self.kind {
1462 UnsupportedSyntaxErrorKind::Match => "cannot use `match` statement",
1463 UnsupportedSyntaxErrorKind::Walrus => "cannot use named assignment expression (`:=`)",
1464 UnsupportedSyntaxErrorKind::ExceptStar => "cannot use `except*`",
1465 UnsupportedSyntaxErrorKind::UnparenthesizedNamedExpr(
1466 UnparenthesizedNamedExprKind::SequenceIndex,
1467 ) => "cannot use unparenthesized assignment expression in a sequence index",
1468 UnsupportedSyntaxErrorKind::UnparenthesizedNamedExpr(
1469 UnparenthesizedNamedExprKind::SetLiteral,
1470 ) => "cannot use unparenthesized assignment expression as an element in a set literal",
1471 UnsupportedSyntaxErrorKind::UnparenthesizedNamedExpr(
1472 UnparenthesizedNamedExprKind::SetComprehension,
1473 ) => {
1474 "cannot use unparenthesized assignment expression as an element in a set comprehension"
1475 }
1476 UnsupportedSyntaxErrorKind::ParenthesizedKeywordArgumentName => {
1477 "cannot use parenthesized keyword argument name"
1478 }
1479 UnsupportedSyntaxErrorKind::StarTuple(StarTupleKind::Return) => {
1480 "cannot use iterable unpacking in return statements"
1481 }
1482 UnsupportedSyntaxErrorKind::StarTuple(StarTupleKind::Yield) => {
1483 "cannot use iterable unpacking in yield expressions"
1484 }
1485 UnsupportedSyntaxErrorKind::RelaxedDecorator(relaxed_decorator_error) => {
1486 return match relaxed_decorator_error {
1487 RelaxedDecoratorError::CallExpression => {
1488 write!(
1489 f,
1490 "cannot use a call expression in a decorator on Python {} \
1491 unless it is the top-level expression or it occurs \
1492 in the argument list of a top-level call expression \
1493 (relaxed decorator syntax was {changed})",
1494 self.target_version,
1495 changed = self.kind.changed_version(),
1496 )
1497 }
1498 RelaxedDecoratorError::Other(description) => write!(
1499 f,
1500 "cannot use {description} outside function call arguments in a decorator on Python {} \
1501 (syntax was {changed})",
1502 self.target_version,
1503 changed = self.kind.changed_version(),
1504 ),
1505 };
1506 }
1507 UnsupportedSyntaxErrorKind::PositionalOnlyParameter => {
1508 "cannot use positional-only parameter separator"
1509 }
1510 UnsupportedSyntaxErrorKind::TypeParameterList => "cannot use type parameter lists",
1511 UnsupportedSyntaxErrorKind::LazyImportStatement => "cannot use `lazy` import statement",
1512 UnsupportedSyntaxErrorKind::TypeAliasStatement => "cannot use `type` alias statement",
1513 UnsupportedSyntaxErrorKind::TypeParamDefault => {
1514 "cannot set default type for a type parameter"
1515 }
1516 UnsupportedSyntaxErrorKind::Pep701FString(FStringKind::Backslash) => {
1517 "cannot use an escape sequence (backslash) in f-strings"
1518 }
1519 UnsupportedSyntaxErrorKind::Pep701FString(FStringKind::Comment) => {
1520 "cannot use comments in f-strings"
1521 }
1522 UnsupportedSyntaxErrorKind::Pep701FString(FStringKind::LineBreak) => {
1523 "cannot use line breaks in non-triple-quoted f-string replacement fields"
1524 }
1525 UnsupportedSyntaxErrorKind::Pep701FString(FStringKind::NestedQuote) => {
1526 "cannot reuse outer quote character in f-strings"
1527 }
1528 UnsupportedSyntaxErrorKind::ParenthesizedContextManager => {
1529 "cannot use parentheses within a `with` statement"
1530 }
1531 UnsupportedSyntaxErrorKind::StarExpressionInIndex => {
1532 "cannot use star expression in index"
1533 }
1534 UnsupportedSyntaxErrorKind::StarAnnotation => "cannot use star annotation",
1535 UnsupportedSyntaxErrorKind::UnpackingInComprehension(
1536 ComprehensionUnpackingKind::IterableInList,
1537 ) => "cannot use iterable unpacking in a list comprehension",
1538 UnsupportedSyntaxErrorKind::UnpackingInComprehension(
1539 ComprehensionUnpackingKind::IterableInSet,
1540 ) => "cannot use iterable unpacking in a set comprehension",
1541 UnsupportedSyntaxErrorKind::UnpackingInComprehension(
1542 ComprehensionUnpackingKind::IterableInGenerator,
1543 ) => "cannot use iterable unpacking in a generator expression",
1544 UnsupportedSyntaxErrorKind::UnpackingInComprehension(
1545 ComprehensionUnpackingKind::DictInDict,
1546 ) => "cannot use dictionary unpacking in a dict comprehension",
1547 UnsupportedSyntaxErrorKind::UnparenthesizedUnpackInFor => {
1548 "cannot use iterable unpacking in `for` statements"
1549 }
1550 UnsupportedSyntaxErrorKind::UnparenthesizedExceptionTypes => {
1551 "multiple exception types must be parenthesized"
1552 }
1553 UnsupportedSyntaxErrorKind::TemplateStrings => "cannot use t-strings",
1554 UnsupportedSyntaxErrorKind::UnaryPlusMatchPattern => {
1555 "unary '+' is not allowed in a literal pattern"
1556 }
1557 };
1558
1559 write!(
1560 f,
1561 "{kind} on Python {} (syntax was {changed})",
1562 self.target_version,
1563 changed = self.kind.changed_version(),
1564 )
1565 }
1566}
1567
1568#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, get_size2::GetSize)]
1569pub enum RelaxedDecoratorError {
1570 CallExpression,
1571 Other(&'static str),
1572}
1573
1574enum Change {
1576 Added(PythonVersion),
1577 Removed(PythonVersion),
1578}
1579
1580impl Display for Change {
1581 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1582 match self {
1583 Change::Added(version) => write!(f, "added in Python {version}"),
1584 Change::Removed(version) => write!(f, "removed in Python {version}"),
1585 }
1586 }
1587}
1588
1589impl UnsupportedSyntaxErrorKind {
1590 const fn changed_version(self) -> Change {
1593 match self {
1594 UnsupportedSyntaxErrorKind::Match => Change::Added(PythonVersion::PY310),
1595 UnsupportedSyntaxErrorKind::Walrus => Change::Added(PythonVersion::PY38),
1596 UnsupportedSyntaxErrorKind::ExceptStar => Change::Added(PythonVersion::PY311),
1597 UnsupportedSyntaxErrorKind::UnparenthesizedNamedExpr(_) => {
1598 Change::Added(PythonVersion::PY39)
1599 }
1600 UnsupportedSyntaxErrorKind::StarTuple(_) => Change::Added(PythonVersion::PY38),
1601 UnsupportedSyntaxErrorKind::RelaxedDecorator { .. } => {
1602 Change::Added(PythonVersion::PY39)
1603 }
1604 UnsupportedSyntaxErrorKind::PositionalOnlyParameter => {
1605 Change::Added(PythonVersion::PY38)
1606 }
1607 UnsupportedSyntaxErrorKind::ParenthesizedKeywordArgumentName => {
1608 Change::Removed(PythonVersion::PY38)
1609 }
1610 UnsupportedSyntaxErrorKind::TypeParameterList => Change::Added(PythonVersion::PY312),
1611 UnsupportedSyntaxErrorKind::LazyImportStatement => Change::Added(PythonVersion::PY315),
1612 UnsupportedSyntaxErrorKind::TypeAliasStatement => Change::Added(PythonVersion::PY312),
1613 UnsupportedSyntaxErrorKind::TypeParamDefault => Change::Added(PythonVersion::PY313),
1614 UnsupportedSyntaxErrorKind::Pep701FString(_) => Change::Added(PythonVersion::PY312),
1615 UnsupportedSyntaxErrorKind::ParenthesizedContextManager => {
1616 Change::Added(PythonVersion::PY39)
1617 }
1618 UnsupportedSyntaxErrorKind::StarExpressionInIndex => {
1619 Change::Added(PythonVersion::PY311)
1620 }
1621 UnsupportedSyntaxErrorKind::StarAnnotation => Change::Added(PythonVersion::PY311),
1622 UnsupportedSyntaxErrorKind::UnpackingInComprehension(_) => {
1623 Change::Added(PythonVersion::PY315)
1624 }
1625 UnsupportedSyntaxErrorKind::UnparenthesizedUnpackInFor => {
1626 Change::Added(PythonVersion::PY39)
1627 }
1628 UnsupportedSyntaxErrorKind::UnparenthesizedExceptionTypes => {
1629 Change::Added(PythonVersion::PY314)
1630 }
1631 UnsupportedSyntaxErrorKind::TemplateStrings => Change::Added(PythonVersion::PY314),
1632 UnsupportedSyntaxErrorKind::UnaryPlusMatchPattern => {
1633 Change::Added(PythonVersion::PY315)
1634 }
1635 }
1636 }
1637
1638 pub(crate) fn is_unsupported(self, target_version: PythonVersion) -> bool {
1640 match self.changed_version() {
1641 Change::Added(version) => target_version < version,
1642 Change::Removed(version) => target_version >= version,
1643 }
1644 }
1645
1646 pub(crate) fn is_supported(self, target_version: PythonVersion) -> bool {
1648 !self.is_unsupported(target_version)
1649 }
1650}
1651
1652#[cfg(target_pointer_width = "64")]
1653mod sizes {
1654 use crate::error::{LexicalError, LexicalErrorType};
1655 use static_assertions::assert_eq_size;
1656
1657 assert_eq_size!(LexicalErrorType, [u8; 24]);
1658 assert_eq_size!(LexicalError, [u8; 32]);
1659}