mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-11 22:29:39 +00:00

This PR implements template strings (t-strings) in the parser and formatter for Ruff. Minimal changes necessary to compile were made in other parts of the code (e.g. ty, the linter, etc.). These will be covered properly in follow-up PRs.
104 lines
4.3 KiB
Rust
104 lines
4.3 KiB
Rust
use ruff_python_ast::{self as ast, CmpOp, Expr, ExprContext, Number};
|
|
use ruff_text_size::{Ranged, TextRange};
|
|
|
|
use crate::{TokenKind, error::RelaxedDecoratorError};
|
|
|
|
/// Set the `ctx` for `Expr::Id`, `Expr::Attribute`, `Expr::Subscript`, `Expr::Starred`,
|
|
/// `Expr::Tuple` and `Expr::List`. If `expr` is either `Expr::Tuple` or `Expr::List`,
|
|
/// recursively sets the `ctx` for their elements.
|
|
pub(super) fn set_expr_ctx(expr: &mut Expr, new_ctx: ExprContext) {
|
|
match expr {
|
|
Expr::Name(ast::ExprName { ctx, .. })
|
|
| Expr::Attribute(ast::ExprAttribute { ctx, .. })
|
|
| Expr::Subscript(ast::ExprSubscript { ctx, .. }) => *ctx = new_ctx,
|
|
Expr::Starred(ast::ExprStarred { value, ctx, .. }) => {
|
|
*ctx = new_ctx;
|
|
set_expr_ctx(value, new_ctx);
|
|
}
|
|
Expr::UnaryOp(ast::ExprUnaryOp { operand, .. }) => {
|
|
set_expr_ctx(operand, new_ctx);
|
|
}
|
|
Expr::List(ast::ExprList { elts, ctx, .. })
|
|
| Expr::Tuple(ast::ExprTuple { elts, ctx, .. }) => {
|
|
*ctx = new_ctx;
|
|
elts.iter_mut()
|
|
.for_each(|element| set_expr_ctx(element, new_ctx));
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
/// Converts a [`TokenKind`] array of size 2 to its correspondent [`CmpOp`].
|
|
pub(super) const fn token_kind_to_cmp_op(tokens: [TokenKind; 2]) -> Option<CmpOp> {
|
|
Some(match tokens {
|
|
[TokenKind::Is, TokenKind::Not] => CmpOp::IsNot,
|
|
[TokenKind::Is, _] => CmpOp::Is,
|
|
[TokenKind::Not, TokenKind::In] => CmpOp::NotIn,
|
|
[TokenKind::In, _] => CmpOp::In,
|
|
[TokenKind::EqEqual, _] => CmpOp::Eq,
|
|
[TokenKind::NotEqual, _] => CmpOp::NotEq,
|
|
[TokenKind::Less, _] => CmpOp::Lt,
|
|
[TokenKind::LessEqual, _] => CmpOp::LtE,
|
|
[TokenKind::Greater, _] => CmpOp::Gt,
|
|
[TokenKind::GreaterEqual, _] => CmpOp::GtE,
|
|
_ => return None,
|
|
})
|
|
}
|
|
|
|
/// Helper for `parse_decorators` to determine if `expr` is a [`dotted_name`] from the decorator
|
|
/// grammar before Python 3.9.
|
|
///
|
|
/// Returns `Some((error, range))` if `expr` is not a `dotted_name`, or `None` if it is a `dotted_name`.
|
|
///
|
|
/// [`dotted_name`]: https://docs.python.org/3.8/reference/compound_stmts.html#grammar-token-dotted-name
|
|
pub(super) fn detect_invalid_pre_py39_decorator_node(
|
|
expr: &Expr,
|
|
) -> Option<(RelaxedDecoratorError, TextRange)> {
|
|
let description = match expr {
|
|
Expr::Name(_) => return None,
|
|
|
|
Expr::Attribute(attribute) => {
|
|
return detect_invalid_pre_py39_decorator_node(&attribute.value);
|
|
}
|
|
|
|
Expr::Call(_) => return Some((RelaxedDecoratorError::CallExpression, expr.range())),
|
|
|
|
Expr::NumberLiteral(number) => match &number.value {
|
|
Number::Int(_) => "an int literal",
|
|
Number::Float(_) => "a float literal",
|
|
Number::Complex { .. } => "a complex literal",
|
|
},
|
|
|
|
Expr::BoolOp(_) => "boolean expression",
|
|
Expr::BinOp(_) => "binary-operation expression",
|
|
Expr::UnaryOp(_) => "unary-operation expression",
|
|
Expr::Await(_) => "`await` expression",
|
|
Expr::Lambda(_) => "lambda expression",
|
|
Expr::If(_) => "conditional expression",
|
|
Expr::Dict(_) => "a dict literal",
|
|
Expr::Set(_) => "a set literal",
|
|
Expr::List(_) => "a list literal",
|
|
Expr::Tuple(_) => "a tuple literal",
|
|
Expr::Starred(_) => "starred expression",
|
|
Expr::Slice(_) => "slice expression",
|
|
Expr::BytesLiteral(_) => "a bytes literal",
|
|
Expr::StringLiteral(_) => "a string literal",
|
|
Expr::EllipsisLiteral(_) => "an ellipsis literal",
|
|
Expr::NoneLiteral(_) => "a `None` literal",
|
|
Expr::BooleanLiteral(_) => "a boolean literal",
|
|
Expr::ListComp(_) => "a list comprehension",
|
|
Expr::SetComp(_) => "a set comprehension",
|
|
Expr::DictComp(_) => "a dict comprehension",
|
|
Expr::Generator(_) => "generator expression",
|
|
Expr::Yield(_) => "`yield` expression",
|
|
Expr::YieldFrom(_) => "`yield from` expression",
|
|
Expr::Compare(_) => "comparison expression",
|
|
Expr::FString(_) => "f-string",
|
|
Expr::TString(_) => "t-string",
|
|
Expr::Named(_) => "assignment expression",
|
|
Expr::Subscript(_) => "subscript expression",
|
|
Expr::IpyEscapeCommand(_) => "IPython escape command",
|
|
};
|
|
|
|
Some((RelaxedDecoratorError::Other(description), expr.range()))
|
|
}
|