Skip to content

Commit

Permalink
Parse Quoted annotations as if parenthesized
Browse files Browse the repository at this point in the history
  • Loading branch information
Glyphack committed Jan 9, 2025
1 parent b33cf5b commit efbd25e
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 5 deletions.
15 changes: 15 additions & 0 deletions crates/ruff_linter/resources/test/fixtures/pyflakes/F722.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,18 @@ def g() -> "///":


X: """List[int]"""'☃' = []

y: """
int |
str
"""

z: """(
int |
str
)
"""
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ F722.py:13:4: F722 Syntax error in forward annotation: `List[int]☃`
|
13 | X: """List[int]"""'' = []
| ^^^^^^^^^^^^^^^^^^ F722
14 |
15 | y: """
|
16 changes: 14 additions & 2 deletions crates/ruff_python_parser/src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,22 @@ impl<'src> Lexer<'src> {
"Lexer only supports files with a size up to 4GB"
);

let nesting = u32::from(mode == Mode::ParenthesizedExpression);
let state = if mode == Mode::ParenthesizedExpression {
State::Other
} else {
State::AfterNewline
};

let mut lexer = Lexer {
source,
cursor: Cursor::new(source),
state: State::AfterNewline,
state,
current_kind: TokenKind::EndOfFile,
current_range: TextRange::empty(start_offset),
current_value: TokenValue::None,
current_flags: TokenFlags::empty(),
nesting: 0,
nesting,
indentations: Indentations::default(),
pending_indentation: None,
mode,
Expand Down Expand Up @@ -1307,6 +1314,11 @@ impl<'src> Lexer<'src> {
}

fn consume_end(&mut self) -> TokenKind {
// For Mode::ParenthesizedExpression we start with nesting level 1.
// So remove that extra nesting before checks.
if self.mode == Mode::ParenthesizedExpression {
self.nesting = self.nesting.saturating_sub(1);
}
// We reached end of file.
// First of all, we need all nestings to be finished.
if self.nesting > 0 {
Expand Down
12 changes: 12 additions & 0 deletions crates/ruff_python_parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,16 @@ pub fn parse_expression_range(
.into_result()
}

pub fn parse_parenthesized_expression_range(
source: &str,
range: TextRange,
) -> Result<Parsed<ModExpression>, ParseError> {
let source = &source[..range.end().to_usize()];
let parsed =
Parser::new_starts_at(source, Mode::ParenthesizedExpression, range.start()).parse();
parsed.try_into_expression().unwrap().into_result()
}

/// Parse the given Python source code using the specified [`Mode`].
///
/// This function is the most general function to parse Python code. Based on the [`Mode`] supplied,
Expand Down Expand Up @@ -599,6 +609,8 @@ pub enum Mode {
/// [System shell access]: https://ipython.readthedocs.io/en/stable/interactive/reference.html#system-shell-access
/// [Automatic parentheses and quotes]: https://ipython.readthedocs.io/en/stable/interactive/reference.html#automatic-parentheses-and-quotes
Ipython,

ParenthesizedExpression,
}

impl std::str::FromStr for Mode {
Expand Down
4 changes: 3 additions & 1 deletion crates/ruff_python_parser/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ impl<'src> Parser<'src> {
/// Consumes the [`Parser`] and returns the parsed [`Parsed`].
pub(crate) fn parse(mut self) -> Parsed<Mod> {
let syntax = match self.mode {
Mode::Expression => Mod::Expression(self.parse_single_expression()),
Mode::Expression | Mode::ParenthesizedExpression => {
Mod::Expression(self.parse_single_expression())
}
Mode::Module | Mode::Ipython => Mod::Module(self.parse_module()),
};

Expand Down
4 changes: 2 additions & 2 deletions crates/ruff_python_parser/src/typing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use ruff_python_ast::str::raw_contents;
use ruff_python_ast::{Expr, ExprStringLiteral, ModExpression, StringFlags, StringLiteral};
use ruff_text_size::Ranged;

use crate::{parse_expression, parse_expression_range, ParseError, Parsed};
use crate::{parse_expression, parse_parenthesized_expression_range, ParseError, Parsed};

type AnnotationParseResult = Result<ParsedAnnotation, ParseError>;

Expand Down Expand Up @@ -86,7 +86,7 @@ fn parse_simple_type_annotation(
.add_start(string_literal.flags.opener_len())
.sub_end(string_literal.flags.closer_len());
Ok(ParsedAnnotation {
parsed: parse_expression_range(source, range_excluding_quotes)?,
parsed: parse_parenthesized_expression_range(source, range_excluding_quotes)?,
kind: AnnotationKind::Simple,
})
}
Expand Down

0 comments on commit efbd25e

Please sign in to comment.