mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-31 23:57:35 +00:00
Add support for PEP 701 (#7376)
## Summary This PR adds support for PEP 701 in Ruff. This is a rollup PR of all the other individual PRs. The separate PRs were created for logic separation and code reviews. Refer to each pull request for a detail description on the change. Refer to the PR description for the list of pull requests within this PR. ## Test Plan ### Formatter ecosystem checks Explanation for the change in ecosystem check: https://github.com/astral-sh/ruff/pull/7597#issue-1908878183 #### `main` ``` | project | similarity index | total files | changed files | |--------------|------------------:|------------------:|------------------:| | cpython | 0.76083 | 1789 | 1631 | | django | 0.99983 | 2760 | 36 | | transformers | 0.99963 | 2587 | 319 | | twine | 1.00000 | 33 | 0 | | typeshed | 0.99983 | 3496 | 18 | | warehouse | 0.99967 | 648 | 15 | | zulip | 0.99972 | 1437 | 21 | ``` #### `dhruv/pep-701` ``` | project | similarity index | total files | changed files | |--------------|------------------:|------------------:|------------------:| | cpython | 0.76051 | 1789 | 1632 | | django | 0.99983 | 2760 | 36 | | transformers | 0.99963 | 2587 | 319 | | twine | 1.00000 | 33 | 0 | | typeshed | 0.99983 | 3496 | 18 | | warehouse | 0.99967 | 648 | 15 | | zulip | 0.99972 | 1437 | 21 | ```
This commit is contained in:
parent
78b8741352
commit
e62e245c61
115 changed files with 44780 additions and 31370 deletions
|
@ -3,19 +3,20 @@
|
|||
// See also: file:///usr/share/doc/python/html/reference/compound_stmts.html#function-definitions
|
||||
// See also: https://greentreesnakes.readthedocs.io/en/latest/nodes.html#keyword
|
||||
|
||||
use ruff_text_size::{Ranged, TextSize};
|
||||
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
|
||||
use ruff_python_ast::{self as ast, Int, IpyEscapeKind};
|
||||
use crate::{
|
||||
FStringErrorType,
|
||||
Mode,
|
||||
lexer::{LexicalError, LexicalErrorType},
|
||||
function::{ArgumentList, parse_arguments, validate_pos_params, validate_arguments},
|
||||
context::set_context,
|
||||
string::parse_strings,
|
||||
string::{StringType, concatenate_strings, parse_fstring_middle, parse_string_literal},
|
||||
token::{self, StringKind},
|
||||
};
|
||||
use lalrpop_util::ParseError;
|
||||
|
||||
grammar(mode: Mode);
|
||||
grammar(source_code: &str, mode: Mode);
|
||||
|
||||
// This is a hack to reduce the amount of lalrpop tables generated:
|
||||
// For each public entry point, a full parse table is generated.
|
||||
|
@ -667,8 +668,8 @@ LiteralPattern: ast::Pattern = {
|
|||
value: Box::new(value.into()),
|
||||
range: (location..end_location).into()
|
||||
}.into(),
|
||||
<location:@L> <s:(@L string @R)+> <end_location:@R> =>? Ok(ast::PatternMatchValue {
|
||||
value: Box::new(parse_strings(s)?),
|
||||
<location:@L> <strings:StringLiteralOrFString+> <end_location:@R> =>? Ok(ast::PatternMatchValue {
|
||||
value: Box::new(concatenate_strings(strings, (location..end_location).into())?),
|
||||
range: (location..end_location).into()
|
||||
}.into()),
|
||||
}
|
||||
|
@ -725,7 +726,7 @@ MappingKey: ast::Expr = {
|
|||
value: false.into(),
|
||||
range: (location..end_location).into()
|
||||
}.into(),
|
||||
<location:@L> <s:(@L string @R)+> =>? Ok(parse_strings(s)?),
|
||||
<location:@L> <strings:StringLiteralOrFString+> <end_location:@R> =>? Ok(concatenate_strings(strings, (location..end_location).into())?),
|
||||
}
|
||||
|
||||
MatchMappingEntry: (ast::Expr, ast::Pattern) = {
|
||||
|
@ -1349,7 +1350,13 @@ NamedExpression: ast::ParenthesizedExpr = {
|
|||
};
|
||||
|
||||
LambdaDef: ast::ParenthesizedExpr = {
|
||||
<location:@L> "lambda" <location_args:@L> <parameters:ParameterList<UntypedParameter, StarUntypedParameter, StarUntypedParameter>?> <end_location_args:@R> ":" <body:Test<"all">> <end_location:@R> =>? {
|
||||
<location:@L> "lambda" <location_args:@L> <parameters:ParameterList<UntypedParameter, StarUntypedParameter, StarUntypedParameter>?> <end_location_args:@R> ":" <fstring_middle:fstring_middle?> <body:Test<"all">> <end_location:@R> =>? {
|
||||
if fstring_middle.is_some() {
|
||||
return Err(LexicalError {
|
||||
error: LexicalErrorType::FStringError(FStringErrorType::LambdaWithoutParentheses),
|
||||
location,
|
||||
})?;
|
||||
}
|
||||
parameters.as_ref().map(validate_arguments).transpose()?;
|
||||
|
||||
Ok(ast::ExprLambda {
|
||||
|
@ -1572,8 +1579,105 @@ SliceOp: Option<ast::ParenthesizedExpr> = {
|
|||
<location:@L> ":" <e:Test<"all">?> => e,
|
||||
}
|
||||
|
||||
StringLiteralOrFString: StringType = {
|
||||
StringLiteral,
|
||||
FStringExpr,
|
||||
};
|
||||
|
||||
StringLiteral: StringType = {
|
||||
<start_location:@L> <string:string> =>? {
|
||||
let (source, kind, triple_quoted) = string;
|
||||
Ok(parse_string_literal(&source, kind, triple_quoted, start_location)?)
|
||||
}
|
||||
};
|
||||
|
||||
FStringExpr: StringType = {
|
||||
<location:@L> FStringStart <values:FStringMiddlePattern*> FStringEnd <end_location:@R> => {
|
||||
StringType::FString(ast::ExprFString {
|
||||
values,
|
||||
implicit_concatenated: false,
|
||||
range: (location..end_location).into()
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
FStringMiddlePattern: ast::Expr = {
|
||||
FStringReplacementField,
|
||||
<start_location:@L> <fstring_middle:fstring_middle> =>? {
|
||||
let (source, is_raw) = fstring_middle;
|
||||
Ok(parse_fstring_middle(&source, is_raw, start_location)?)
|
||||
}
|
||||
};
|
||||
|
||||
FStringReplacementField: ast::Expr = {
|
||||
<location:@L> "{" <value:TestListOrYieldExpr> <debug:"="?> <conversion:FStringConversion?> <format_spec:FStringFormatSpecSuffix?> "}" <end_location:@R> =>? {
|
||||
if value.expr.is_lambda_expr() && !value.is_parenthesized() {
|
||||
return Err(LexicalError {
|
||||
error: LexicalErrorType::FStringError(FStringErrorType::LambdaWithoutParentheses),
|
||||
location: value.start(),
|
||||
})?;
|
||||
}
|
||||
let debug_text = debug.map(|_| {
|
||||
let start_offset = location + "{".text_len();
|
||||
let end_offset = if let Some((conversion_start, _)) = conversion {
|
||||
conversion_start
|
||||
} else {
|
||||
format_spec.as_ref().map_or_else(
|
||||
|| end_location - "}".text_len(),
|
||||
|spec| spec.range().start() - ":".text_len(),
|
||||
)
|
||||
};
|
||||
ast::DebugText {
|
||||
leading: source_code[TextRange::new(start_offset, value.range().start())].to_string(),
|
||||
trailing: source_code[TextRange::new(value.range().end(), end_offset)].to_string(),
|
||||
}
|
||||
});
|
||||
Ok(
|
||||
ast::ExprFormattedValue {
|
||||
value: Box::new(value.into()),
|
||||
debug_text,
|
||||
conversion: conversion.map_or(ast::ConversionFlag::None, |(_, conversion_flag)| {
|
||||
conversion_flag
|
||||
}),
|
||||
format_spec: format_spec.map(Box::new),
|
||||
range: (location..end_location).into(),
|
||||
}
|
||||
.into()
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
FStringFormatSpecSuffix: ast::Expr = {
|
||||
":" <format_spec:FStringFormatSpec> => format_spec
|
||||
};
|
||||
|
||||
FStringFormatSpec: ast::Expr = {
|
||||
<location:@L> <values:FStringMiddlePattern*> <end_location:@R> => {
|
||||
ast::ExprFString {
|
||||
values,
|
||||
implicit_concatenated: false,
|
||||
range: (location..end_location).into()
|
||||
}.into()
|
||||
},
|
||||
};
|
||||
|
||||
FStringConversion: (TextSize, ast::ConversionFlag) = {
|
||||
<location:@L> "!" <s:name> =>? {
|
||||
let conversion = match s.as_str() {
|
||||
"s" => ast::ConversionFlag::Str,
|
||||
"r" => ast::ConversionFlag::Repr,
|
||||
"a" => ast::ConversionFlag::Ascii,
|
||||
_ => Err(LexicalError {
|
||||
error: LexicalErrorType::FStringError(FStringErrorType::InvalidConversionFlag),
|
||||
location,
|
||||
})?
|
||||
};
|
||||
Ok((location, conversion))
|
||||
}
|
||||
};
|
||||
|
||||
Atom<Goal>: ast::ParenthesizedExpr = {
|
||||
<location:@L> <s:(@L string @R)+> =>? Ok(parse_strings(s)?.into()),
|
||||
<location:@L> <strings:StringLiteralOrFString+> <end_location:@R> =>? Ok(concatenate_strings(strings, (location..end_location).into())?.into()),
|
||||
<location:@L> <value:Constant> <end_location:@R> => ast::ExprConstant {
|
||||
value,
|
||||
range: (location..end_location).into(),
|
||||
|
@ -1842,6 +1946,9 @@ extern {
|
|||
Dedent => token::Tok::Dedent,
|
||||
StartModule => token::Tok::StartModule,
|
||||
StartExpression => token::Tok::StartExpression,
|
||||
FStringStart => token::Tok::FStringStart,
|
||||
FStringEnd => token::Tok::FStringEnd,
|
||||
"!" => token::Tok::Exclamation,
|
||||
"?" => token::Tok::Question,
|
||||
"+" => token::Tok::Plus,
|
||||
"-" => token::Tok::Minus,
|
||||
|
@ -1935,6 +2042,10 @@ extern {
|
|||
kind: <StringKind>,
|
||||
triple_quoted: <bool>
|
||||
},
|
||||
fstring_middle => token::Tok::FStringMiddle {
|
||||
value: <String>,
|
||||
is_raw: <bool>
|
||||
},
|
||||
name => token::Tok::Name { name: <String> },
|
||||
ipy_escape_command => token::Tok::IpyEscapeCommand {
|
||||
kind: <IpyEscapeKind>,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue