mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-02 06:41:23 +00:00
Auto generate ast expression nodes (#16285)
## Summary Part of https://github.com/astral-sh/ruff/issues/15655 - Auto generate AST nodes using definitions in `ast.toml`. I added attributes similar to [`Field`](https://github.com/python/cpython/blob/main/Parser/asdl.py#L67) in ASDL to hold field information ## Test Plan Nothing outside the `ruff_python_ast` package should change. --------- Co-authored-by: Douglas Creager <dcreager@dcreager.net>
This commit is contained in:
parent
cc324abcc2
commit
23fd4927ae
6 changed files with 719 additions and 360 deletions
|
@ -26,18 +26,36 @@
|
||||||
# Controls the name of the AnyNodeRef::is_foo_bar method. The default is the
|
# Controls the name of the AnyNodeRef::is_foo_bar method. The default is the
|
||||||
# group name in snake_case.
|
# group name in snake_case.
|
||||||
#
|
#
|
||||||
# rustdoc:
|
# doc:
|
||||||
# A rustdoc comment that is added to the group's enums.
|
# A doc comment that is added to the group's enums.
|
||||||
#
|
#
|
||||||
# The following syntax node options are available:
|
# The following syntax node options are available:
|
||||||
#
|
#
|
||||||
|
# doc:
|
||||||
|
# A doc comment that is added to the syntax node struct.
|
||||||
|
#
|
||||||
|
# derives:
|
||||||
|
# List of derives to add to the syntax node struct. Clone, Debug, PartialEq are added by default.
|
||||||
|
#
|
||||||
|
# fields:
|
||||||
|
# List of fields in the syntax node struct. Each field is a table with the
|
||||||
|
# following keys:
|
||||||
|
# * name - The name of the field.
|
||||||
|
# * type - The type of the field. This can be a simple type name, or a type
|
||||||
|
# type field uses a special syntax to describe the rust type:
|
||||||
|
# * `Expr` - A single expression.
|
||||||
|
# * `Expr?` - Option type.
|
||||||
|
# * `Expr*` - A vector of Expr.
|
||||||
|
# * `&Expr*` - A boxed slice of Expr.
|
||||||
|
# These properties cannot be nested, for example we cannot create a vector of option types.
|
||||||
|
#
|
||||||
# variant:
|
# variant:
|
||||||
# The name of the enum variant for this syntax node. Defaults to the node
|
# The name of the enum variant for this syntax node. Defaults to the node
|
||||||
# name with the group prefix removed. (That is, `StmtIf` becomes `If`.)
|
# name with the group prefix removed. (That is, `StmtIf` becomes `If`.)
|
||||||
|
|
||||||
[Mod]
|
[Mod]
|
||||||
anynode_is_label = "module"
|
anynode_is_label = "module"
|
||||||
rustdoc = "/// See also [mod](https://docs.python.org/3/library/ast.html#ast.mod)"
|
doc = "See also [mod](https://docs.python.org/3/library/ast.html#ast.mod)"
|
||||||
|
|
||||||
[Mod.nodes]
|
[Mod.nodes]
|
||||||
ModModule = {}
|
ModModule = {}
|
||||||
|
@ -46,7 +64,7 @@ ModExpression = {}
|
||||||
[Stmt]
|
[Stmt]
|
||||||
add_suffix_to_is_methods = true
|
add_suffix_to_is_methods = true
|
||||||
anynode_is_label = "statement"
|
anynode_is_label = "statement"
|
||||||
rustdoc = "/// See also [stmt](https://docs.python.org/3/library/ast.html#ast.stmt)"
|
doc = "See also [stmt](https://docs.python.org/3/library/ast.html#ast.stmt)"
|
||||||
|
|
||||||
[Stmt.nodes]
|
[Stmt.nodes]
|
||||||
StmtFunctionDef = {}
|
StmtFunctionDef = {}
|
||||||
|
@ -78,44 +96,247 @@ StmtIpyEscapeCommand = {}
|
||||||
[Expr]
|
[Expr]
|
||||||
add_suffix_to_is_methods = true
|
add_suffix_to_is_methods = true
|
||||||
anynode_is_label = "expression"
|
anynode_is_label = "expression"
|
||||||
rustdoc = "/// See also [expr](https://docs.python.org/3/library/ast.html#ast.expr)"
|
doc = "See also [expr](https://docs.python.org/3/library/ast.html#ast.expr)"
|
||||||
|
|
||||||
[Expr.nodes]
|
[Expr.nodes.ExprBoolOp]
|
||||||
ExprBoolOp = {}
|
doc = "See also [BoolOp](https://docs.python.org/3/library/ast.html#ast.BoolOp)"
|
||||||
ExprNamed = {}
|
fields = [
|
||||||
ExprBinOp = {}
|
{ name = "op", type = "BoolOp" },
|
||||||
ExprUnaryOp = {}
|
{ name = "values", type = "Expr*" }
|
||||||
ExprLambda = {}
|
]
|
||||||
ExprIf = {}
|
|
||||||
ExprDict = {}
|
[Expr.nodes.ExprNamed]
|
||||||
ExprSet = {}
|
doc = "See also [NamedExpr](https://docs.python.org/3/library/ast.html#ast.NamedExpr)"
|
||||||
ExprListComp = {}
|
fields = [
|
||||||
ExprSetComp = {}
|
{ name = "target", type = "Expr" },
|
||||||
ExprDictComp = {}
|
{ name = "value", type = "Expr" }
|
||||||
ExprGenerator = {}
|
]
|
||||||
ExprAwait = {}
|
|
||||||
ExprYield = {}
|
[Expr.nodes.ExprBinOp]
|
||||||
ExprYieldFrom = {}
|
doc = "See also [BinOp](https://docs.python.org/3/library/ast.html#ast.BinOp)"
|
||||||
ExprCompare = {}
|
fields = [
|
||||||
ExprCall = {}
|
{ name = "left", type = "Expr" },
|
||||||
ExprFString = {}
|
{ name = "op", type = "Operator" },
|
||||||
ExprStringLiteral = {}
|
{ name = "right", type = "Expr" }
|
||||||
ExprBytesLiteral = {}
|
]
|
||||||
ExprNumberLiteral = {}
|
|
||||||
ExprBooleanLiteral = {}
|
[Expr.nodes.ExprUnaryOp]
|
||||||
ExprNoneLiteral = {}
|
doc = "See also [UnaryOp](https://docs.python.org/3/library/ast.html#ast.UnaryOp)"
|
||||||
ExprEllipsisLiteral = {}
|
fields = [
|
||||||
ExprAttribute = {}
|
{ name = "op", type = "UnaryOp" },
|
||||||
ExprSubscript = {}
|
{ name = "operand", type = "Expr" }
|
||||||
ExprStarred = {}
|
]
|
||||||
ExprName = {}
|
|
||||||
ExprList = {}
|
[Expr.nodes.ExprLambda]
|
||||||
ExprTuple = {}
|
doc = "See also [Lambda](https://docs.python.org/3/library/ast.html#ast.Lambda)"
|
||||||
ExprSlice = {}
|
fields = [
|
||||||
ExprIpyEscapeCommand = {}
|
{ name = "parameters", type = "Box<crate::Parameters>?" },
|
||||||
|
{ name = "body", type = "Expr" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[Expr.nodes.ExprIf]
|
||||||
|
doc = "See also [IfExp](https://docs.python.org/3/library/ast.html#ast.IfExp)"
|
||||||
|
fields = [
|
||||||
|
{ name = "test", type = "Expr" },
|
||||||
|
{ name = "body", type = "Expr" },
|
||||||
|
{ name = "orelse", type = "Expr" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[Expr.nodes.ExprDict]
|
||||||
|
doc = "See also [Dict](https://docs.python.org/3/library/ast.html#ast.Dict)"
|
||||||
|
fields = [
|
||||||
|
{ name = "items", type = "DictItem*" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[Expr.nodes.ExprSet]
|
||||||
|
doc = "See also [Set](https://docs.python.org/3/library/ast.html#ast.Set)"
|
||||||
|
fields = [
|
||||||
|
{ name = "elts", type = "Expr*" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[Expr.nodes.ExprListComp]
|
||||||
|
doc = "See also [ListComp](https://docs.python.org/3/library/ast.html#ast.ListComp)"
|
||||||
|
fields = [
|
||||||
|
{ name = "elt", type = "Expr" },
|
||||||
|
{ name = "generators", type = "Comprehension*" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[Expr.nodes.ExprSetComp]
|
||||||
|
doc = "See also [SetComp](https://docs.python.org/3/library/ast.html#ast.SetComp)"
|
||||||
|
fields = [
|
||||||
|
{ name = "elt", type = "Expr" },
|
||||||
|
{ name = "generators", type = "Comprehension*" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[Expr.nodes.ExprDictComp]
|
||||||
|
doc = "See also [DictComp](https://docs.python.org/3/library/ast.html#ast.DictComp)"
|
||||||
|
fields = [
|
||||||
|
{ name = "key", type = "Expr" },
|
||||||
|
{ name = "value", type = "Expr" },
|
||||||
|
{ name = "generators", type = "Comprehension*" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[Expr.nodes.ExprGenerator]
|
||||||
|
doc = "See also [GeneratorExp](https://docs.python.org/3/library/ast.html#ast.GeneratorExp)"
|
||||||
|
fields = [
|
||||||
|
{ name = "elt", type = "Expr" },
|
||||||
|
{ name = "generators", type = "Comprehension*" },
|
||||||
|
{ name = "parenthesized", type = "bool" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[Expr.nodes.ExprAwait]
|
||||||
|
doc = "See also [Await](https://docs.python.org/3/library/ast.html#ast.Await)"
|
||||||
|
fields = [
|
||||||
|
{ name = "value", type = "Expr" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[Expr.nodes.ExprYield]
|
||||||
|
doc = "See also [Yield](https://docs.python.org/3/library/ast.html#ast.Yield)"
|
||||||
|
fields = [
|
||||||
|
{ name = "value", type = "Expr?" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[Expr.nodes.ExprYieldFrom]
|
||||||
|
doc = "See also [YieldFrom](https://docs.python.org/3/library/ast.html#ast.YieldFrom)"
|
||||||
|
fields = [
|
||||||
|
{ name = "value", type = "Expr" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[Expr.nodes.ExprCompare]
|
||||||
|
doc = "See also [Compare](https://docs.python.org/3/library/ast.html#ast.Compare)"
|
||||||
|
fields = [
|
||||||
|
{ name = "left", type = "Expr" },
|
||||||
|
{ name = "ops", type = "&CmpOp*" },
|
||||||
|
{ name = "comparators", type = "&Expr*" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[Expr.nodes.ExprCall]
|
||||||
|
doc = "See also [Call](https://docs.python.org/3/library/ast.html#ast.Call)"
|
||||||
|
fields = [
|
||||||
|
{ name = "func", type = "Expr" },
|
||||||
|
{ name = "arguments", type = "Arguments" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[Expr.nodes.ExprFString]
|
||||||
|
doc = """An AST node that represents either a single-part f-string literal
|
||||||
|
or an implicitly concatenated f-string literal.
|
||||||
|
|
||||||
|
This type differs from the original Python AST `JoinedStr` in that it
|
||||||
|
doesn't join the implicitly concatenated parts into a single string. Instead,
|
||||||
|
it keeps them separate and provide various methods to access the parts.
|
||||||
|
|
||||||
|
See also [JoinedStr](https://docs.python.org/3/library/ast.html#ast.JoinedStr)"""
|
||||||
|
fields = [
|
||||||
|
{ name = "value", type = "FStringValue" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[Expr.nodes.ExprStringLiteral]
|
||||||
|
doc = """An AST node that represents either a single-part string literal
|
||||||
|
or an implicitly concatenated string literal."""
|
||||||
|
fields = [
|
||||||
|
{ name = "value", type = "StringLiteralValue" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[Expr.nodes.ExprBytesLiteral]
|
||||||
|
doc = """An AST node that represents either a single-part bytestring literal
|
||||||
|
or an implicitly concatenated bytestring literal."""
|
||||||
|
fields = [
|
||||||
|
{ name = "value", type = "BytesLiteralValue" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[Expr.nodes.ExprNumberLiteral]
|
||||||
|
fields = [
|
||||||
|
{ name = "value", type = "Number" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[Expr.nodes.ExprBooleanLiteral]
|
||||||
|
fields = [
|
||||||
|
{ name = "value", type = "bool" }
|
||||||
|
]
|
||||||
|
derives = ["Default"]
|
||||||
|
|
||||||
|
[Expr.nodes.ExprNoneLiteral]
|
||||||
|
fields = []
|
||||||
|
derives = ["Default"]
|
||||||
|
|
||||||
|
[Expr.nodes.ExprEllipsisLiteral]
|
||||||
|
fields = []
|
||||||
|
derives = ["Default"]
|
||||||
|
|
||||||
|
[Expr.nodes.ExprAttribute]
|
||||||
|
doc = "See also [Attribute](https://docs.python.org/3/library/ast.html#ast.Attribute)"
|
||||||
|
fields = [
|
||||||
|
{ name = "value", type = "Expr" },
|
||||||
|
{ name = "attr", type = "Identifier" },
|
||||||
|
{ name = "ctx", type = "ExprContext" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[Expr.nodes.ExprSubscript]
|
||||||
|
doc = "See also [Subscript](https://docs.python.org/3/library/ast.html#ast.Subscript)"
|
||||||
|
fields = [
|
||||||
|
{ name = "value", type = "Expr" },
|
||||||
|
{ name = "slice", type = "Expr" },
|
||||||
|
{ name = "ctx", type = "ExprContext" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[Expr.nodes.ExprStarred]
|
||||||
|
doc = "See also [Starred](https://docs.python.org/3/library/ast.html#ast.Starred)"
|
||||||
|
fields = [
|
||||||
|
{ name = "value", type = "Expr" },
|
||||||
|
{ name = "ctx", type = "ExprContext" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[Expr.nodes.ExprName]
|
||||||
|
doc = "See also [Name](https://docs.python.org/3/library/ast.html#ast.Name)"
|
||||||
|
fields = [
|
||||||
|
{ name = "id", type = "Name" },
|
||||||
|
{ name = "ctx", type = "ExprContext" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[Expr.nodes.ExprList]
|
||||||
|
doc = "See also [List](https://docs.python.org/3/library/ast.html#ast.List)"
|
||||||
|
fields = [
|
||||||
|
{ name = "elts", type = "Expr*" },
|
||||||
|
{ name = "ctx", type = "ExprContext" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[Expr.nodes.ExprTuple]
|
||||||
|
doc = "See also [Tuple](https://docs.python.org/3/library/ast.html#ast.Tuple)"
|
||||||
|
fields = [
|
||||||
|
{ name = "elts", type = "Expr*" },
|
||||||
|
{ name = "ctx", type = "ExprContext" },
|
||||||
|
{ name = "parenthesized", type = "bool" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[Expr.nodes.ExprSlice]
|
||||||
|
doc = "See also [Slice](https://docs.python.org/3/library/ast.html#ast.Slice)"
|
||||||
|
fields = [
|
||||||
|
{ name = "lower", type = "Expr?" },
|
||||||
|
{ name = "upper", type = "Expr?" },
|
||||||
|
{ name = "step", type = "Expr?" }
|
||||||
|
]
|
||||||
|
|
||||||
|
[Expr.nodes.ExprIpyEscapeCommand]
|
||||||
|
# TODO: Remove the crate:: prefix once StmtIpyEscapeCommand is moved to generated.rs
|
||||||
|
doc = """An AST node used to represent a IPython escape command at the expression level.
|
||||||
|
|
||||||
|
For example,
|
||||||
|
```python
|
||||||
|
dir = !pwd
|
||||||
|
```
|
||||||
|
|
||||||
|
Here, the escape kind can only be `!` or `%` otherwise it is a syntax error.
|
||||||
|
|
||||||
|
For more information related to terminology and syntax of escape commands,
|
||||||
|
see [`crate::StmtIpyEscapeCommand`]."""
|
||||||
|
|
||||||
|
fields = [
|
||||||
|
{ name = "kind", type = "IpyEscapeKind" },
|
||||||
|
{ name = "value", type = "Box<str>" }
|
||||||
|
]
|
||||||
|
|
||||||
[ExceptHandler]
|
[ExceptHandler]
|
||||||
rustdoc = "/// See also [excepthandler](https://docs.python.org/3/library/ast.html#ast.excepthandler)"
|
doc = "See also [excepthandler](https://docs.python.org/3/library/ast.html#ast.excepthandler)"
|
||||||
|
|
||||||
[ExceptHandler.nodes]
|
[ExceptHandler.nodes]
|
||||||
ExceptHandlerExceptHandler = {}
|
ExceptHandlerExceptHandler = {}
|
||||||
|
@ -125,7 +346,7 @@ FStringExpressionElement = {variant = "Expression"}
|
||||||
FStringLiteralElement = {variant = "Literal"}
|
FStringLiteralElement = {variant = "Literal"}
|
||||||
|
|
||||||
[Pattern]
|
[Pattern]
|
||||||
rustdoc = "/// See also [pattern](https://docs.python.org/3/library/ast.html#ast.pattern)"
|
doc = "See also [pattern](https://docs.python.org/3/library/ast.html#ast.pattern)"
|
||||||
|
|
||||||
[Pattern.nodes]
|
[Pattern.nodes]
|
||||||
PatternMatchValue = {}
|
PatternMatchValue = {}
|
||||||
|
@ -138,7 +359,7 @@ PatternMatchAs = {}
|
||||||
PatternMatchOr = {}
|
PatternMatchOr = {}
|
||||||
|
|
||||||
[TypeParam]
|
[TypeParam]
|
||||||
rustdoc = "/// See also [type_param](https://docs.python.org/3/library/ast.html#ast.type_param)"
|
doc = "See also [type_param](https://docs.python.org/3/library/ast.html#ast.type_param)"
|
||||||
|
|
||||||
[TypeParam.nodes]
|
[TypeParam.nodes]
|
||||||
TypeParamTypeVar = {}
|
TypeParamTypeVar = {}
|
||||||
|
|
|
@ -14,6 +14,24 @@ from typing import Any
|
||||||
|
|
||||||
import tomllib
|
import tomllib
|
||||||
|
|
||||||
|
# Types that require `crate::`. We can slowly remove these types as we move them to generate scripts.
|
||||||
|
types_requiring_create_prefix = [
|
||||||
|
"IpyEscapeKind",
|
||||||
|
"ExprContext",
|
||||||
|
"Identifier",
|
||||||
|
"Number",
|
||||||
|
"BytesLiteralValue",
|
||||||
|
"StringLiteralValue",
|
||||||
|
"FStringValue",
|
||||||
|
"Arguments",
|
||||||
|
"CmpOp",
|
||||||
|
"Comprehension",
|
||||||
|
"DictItem",
|
||||||
|
"UnaryOp",
|
||||||
|
"BoolOp",
|
||||||
|
"Operator",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def rustfmt(code: str) -> str:
|
def rustfmt(code: str) -> str:
|
||||||
return check_output(["rustfmt", "--emit=stdout"], input=code, text=True)
|
return check_output(["rustfmt", "--emit=stdout"], input=code, text=True)
|
||||||
|
@ -24,6 +42,11 @@ def to_snake_case(node: str) -> str:
|
||||||
return re.sub("([A-Z])", r"_\1", node).lower().lstrip("_")
|
return re.sub("([A-Z])", r"_\1", node).lower().lstrip("_")
|
||||||
|
|
||||||
|
|
||||||
|
def write_rustdoc(out: list[str], doc: str) -> None:
|
||||||
|
for line in doc.split("\n"):
|
||||||
|
out.append(f"/// {line}")
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Read AST description
|
# Read AST description
|
||||||
|
|
||||||
|
@ -71,7 +94,7 @@ class Group:
|
||||||
|
|
||||||
add_suffix_to_is_methods: bool
|
add_suffix_to_is_methods: bool
|
||||||
anynode_is_label: str
|
anynode_is_label: str
|
||||||
rustdoc: str | None
|
doc: str | None
|
||||||
|
|
||||||
def __init__(self, group_name: str, group: dict[str, Any]) -> None:
|
def __init__(self, group_name: str, group: dict[str, Any]) -> None:
|
||||||
self.name = group_name
|
self.name = group_name
|
||||||
|
@ -79,7 +102,7 @@ class Group:
|
||||||
self.ref_enum_ty = group_name + "Ref"
|
self.ref_enum_ty = group_name + "Ref"
|
||||||
self.add_suffix_to_is_methods = group.get("add_suffix_to_is_methods", False)
|
self.add_suffix_to_is_methods = group.get("add_suffix_to_is_methods", False)
|
||||||
self.anynode_is_label = group.get("anynode_is_label", to_snake_case(group_name))
|
self.anynode_is_label = group.get("anynode_is_label", to_snake_case(group_name))
|
||||||
self.rustdoc = group.get("rustdoc")
|
self.doc = group.get("doc")
|
||||||
self.nodes = [
|
self.nodes = [
|
||||||
Node(self, node_name, node) for node_name, node in group["nodes"].items()
|
Node(self, node_name, node) for node_name, node in group["nodes"].items()
|
||||||
]
|
]
|
||||||
|
@ -90,11 +113,74 @@ class Node:
|
||||||
name: str
|
name: str
|
||||||
variant: str
|
variant: str
|
||||||
ty: str
|
ty: str
|
||||||
|
doc: str | None
|
||||||
|
fields: list[Field] | None
|
||||||
|
derives: list[str]
|
||||||
|
|
||||||
def __init__(self, group: Group, node_name: str, node: dict[str, Any]) -> None:
|
def __init__(self, group: Group, node_name: str, node: dict[str, Any]) -> None:
|
||||||
self.name = node_name
|
self.name = node_name
|
||||||
self.variant = node.get("variant", node_name.removeprefix(group.name))
|
self.variant = node.get("variant", node_name.removeprefix(group.name))
|
||||||
self.ty = f"crate::{node_name}"
|
self.ty = f"crate::{node_name}"
|
||||||
|
self.fields = None
|
||||||
|
fields = node.get("fields")
|
||||||
|
if fields is not None:
|
||||||
|
self.fields = [Field(f) for f in fields]
|
||||||
|
self.derives = node.get("derives", [])
|
||||||
|
self.doc = node.get("doc")
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Field:
|
||||||
|
name: str
|
||||||
|
ty: str
|
||||||
|
parsed_ty: FieldType
|
||||||
|
|
||||||
|
def __init__(self, field: dict[str, Any]) -> None:
|
||||||
|
self.name = field["name"]
|
||||||
|
self.ty = field["type"]
|
||||||
|
self.parsed_ty = FieldType(self.ty)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class FieldType:
|
||||||
|
rule: str
|
||||||
|
name: str
|
||||||
|
seq: bool = False
|
||||||
|
optional: bool = False
|
||||||
|
slice_: bool = False
|
||||||
|
|
||||||
|
def __init__(self, rule: str) -> None:
|
||||||
|
self.rule = rule
|
||||||
|
self.name = ""
|
||||||
|
|
||||||
|
# The following cases are the limitations of this parser(and not used in the ast.toml):
|
||||||
|
# * Rules that involve declaring a sequence with optional items e.g. Vec<Option<...>>
|
||||||
|
last_pos = len(rule) - 1
|
||||||
|
for i, ch in enumerate(rule):
|
||||||
|
if ch == "?":
|
||||||
|
if i == last_pos:
|
||||||
|
self.optional = True
|
||||||
|
else:
|
||||||
|
raise ValueError(f"`?` must be at the end: {rule}")
|
||||||
|
elif ch == "*":
|
||||||
|
if self.slice_: # The * after & is a slice
|
||||||
|
continue
|
||||||
|
if i == last_pos:
|
||||||
|
self.seq = True
|
||||||
|
else:
|
||||||
|
raise ValueError(f"`*` must be at the end: {rule}")
|
||||||
|
elif ch == "&":
|
||||||
|
if i == 0 and rule.endswith("*"):
|
||||||
|
self.slice_ = True
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
f"`&` must be at the start and end with `*`: {rule}"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.name += ch
|
||||||
|
|
||||||
|
if self.optional and (self.seq or self.slice_):
|
||||||
|
raise ValueError(f"optional field cannot be sequence or slice: {rule}")
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
@ -105,6 +191,8 @@ def write_preamble(out: list[str]) -> None:
|
||||||
out.append("""
|
out.append("""
|
||||||
// This is a generated file. Don't modify it by hand!
|
// This is a generated file. Don't modify it by hand!
|
||||||
// Run `crates/ruff_python_ast/generate.py` to re-generate the file.
|
// Run `crates/ruff_python_ast/generate.py` to re-generate the file.
|
||||||
|
|
||||||
|
use crate::name::Name;
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
@ -137,8 +225,8 @@ def write_owned_enum(out: list[str], ast: Ast) -> None:
|
||||||
|
|
||||||
for group in ast.groups:
|
for group in ast.groups:
|
||||||
out.append("")
|
out.append("")
|
||||||
if group.rustdoc is not None:
|
if group.doc is not None:
|
||||||
out.append(group.rustdoc)
|
write_rustdoc(out, group.doc)
|
||||||
out.append("#[derive(Clone, Debug, PartialEq)]")
|
out.append("#[derive(Clone, Debug, PartialEq)]")
|
||||||
out.append(f"pub enum {group.owned_enum_ty} {{")
|
out.append(f"pub enum {group.owned_enum_ty} {{")
|
||||||
for node in group.nodes:
|
for node in group.nodes:
|
||||||
|
@ -313,8 +401,8 @@ def write_ref_enum(out: list[str], ast: Ast) -> None:
|
||||||
|
|
||||||
for group in ast.groups:
|
for group in ast.groups:
|
||||||
out.append("")
|
out.append("")
|
||||||
if group.rustdoc is not None:
|
if group.doc is not None:
|
||||||
out.append(group.rustdoc)
|
write_rustdoc(out, group.doc)
|
||||||
out.append("""#[derive(Clone, Copy, Debug, PartialEq, is_macro::Is)]""")
|
out.append("""#[derive(Clone, Copy, Debug, PartialEq, is_macro::Is)]""")
|
||||||
out.append(f"""pub enum {group.ref_enum_ty}<'a> {{""")
|
out.append(f"""pub enum {group.ref_enum_ty}<'a> {{""")
|
||||||
for node in group.nodes:
|
for node in group.nodes:
|
||||||
|
@ -547,6 +635,49 @@ def write_nodekind(out: list[str], ast: Ast) -> None:
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Node structs
|
||||||
|
|
||||||
|
|
||||||
|
def write_node(out: list[str], ast: Ast) -> None:
|
||||||
|
group_names = [group.name for group in ast.groups]
|
||||||
|
for group in ast.groups:
|
||||||
|
for node in group.nodes:
|
||||||
|
if node.fields is None:
|
||||||
|
continue
|
||||||
|
if node.doc is not None:
|
||||||
|
write_rustdoc(out, node.doc)
|
||||||
|
out.append(
|
||||||
|
"#[derive(Clone, Debug, PartialEq"
|
||||||
|
+ "".join(f", {derive}" for derive in node.derives)
|
||||||
|
+ ")]"
|
||||||
|
)
|
||||||
|
name = node.name
|
||||||
|
out.append(f"pub struct {name} {{")
|
||||||
|
out.append("pub range: ruff_text_size::TextRange,")
|
||||||
|
for field in node.fields:
|
||||||
|
field_str = f"pub {field.name}: "
|
||||||
|
ty = field.parsed_ty
|
||||||
|
|
||||||
|
rust_ty = f"{field.parsed_ty.name}"
|
||||||
|
if ty.name in types_requiring_create_prefix:
|
||||||
|
rust_ty = f"crate::{rust_ty}"
|
||||||
|
if ty.slice_:
|
||||||
|
rust_ty = f"[{rust_ty}]"
|
||||||
|
if (ty.name in group_names or ty.slice_) and ty.seq is False:
|
||||||
|
rust_ty = f"Box<{rust_ty}>"
|
||||||
|
|
||||||
|
if ty.seq:
|
||||||
|
rust_ty = f"Vec<{rust_ty}>"
|
||||||
|
elif ty.optional:
|
||||||
|
rust_ty = f"Option<{rust_ty}>"
|
||||||
|
|
||||||
|
field_str += rust_ty + ","
|
||||||
|
out.append(field_str)
|
||||||
|
out.append("}")
|
||||||
|
out.append("")
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Format and write output
|
# Format and write output
|
||||||
|
|
||||||
|
@ -558,6 +689,7 @@ def generate(ast: Ast) -> list[str]:
|
||||||
write_ref_enum(out, ast)
|
write_ref_enum(out, ast)
|
||||||
write_anynoderef(out, ast)
|
write_anynoderef(out, ast)
|
||||||
write_nodekind(out, ast)
|
write_nodekind(out, ast)
|
||||||
|
write_node(out, ast)
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
|
268
crates/ruff_python_ast/src/generated.rs
generated
268
crates/ruff_python_ast/src/generated.rs
generated
|
@ -1,6 +1,8 @@
|
||||||
// This is a generated file. Don't modify it by hand!
|
// This is a generated file. Don't modify it by hand!
|
||||||
// Run `crates/ruff_python_ast/generate.py` to re-generate the file.
|
// Run `crates/ruff_python_ast/generate.py` to re-generate the file.
|
||||||
|
|
||||||
|
use crate::name::Name;
|
||||||
|
|
||||||
/// See also [mod](https://docs.python.org/3/library/ast.html#ast.mod)
|
/// See also [mod](https://docs.python.org/3/library/ast.html#ast.mod)
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum Mod {
|
pub enum Mod {
|
||||||
|
@ -6445,3 +6447,269 @@ impl AnyNodeRef<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// See also [BoolOp](https://docs.python.org/3/library/ast.html#ast.BoolOp)
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprBoolOp {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub op: crate::BoolOp,
|
||||||
|
pub values: Vec<Expr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [NamedExpr](https://docs.python.org/3/library/ast.html#ast.NamedExpr)
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprNamed {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub target: Box<Expr>,
|
||||||
|
pub value: Box<Expr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [BinOp](https://docs.python.org/3/library/ast.html#ast.BinOp)
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprBinOp {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub left: Box<Expr>,
|
||||||
|
pub op: crate::Operator,
|
||||||
|
pub right: Box<Expr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [UnaryOp](https://docs.python.org/3/library/ast.html#ast.UnaryOp)
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprUnaryOp {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub op: crate::UnaryOp,
|
||||||
|
pub operand: Box<Expr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [Lambda](https://docs.python.org/3/library/ast.html#ast.Lambda)
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprLambda {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub parameters: Option<Box<crate::Parameters>>,
|
||||||
|
pub body: Box<Expr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [IfExp](https://docs.python.org/3/library/ast.html#ast.IfExp)
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprIf {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub test: Box<Expr>,
|
||||||
|
pub body: Box<Expr>,
|
||||||
|
pub orelse: Box<Expr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [Dict](https://docs.python.org/3/library/ast.html#ast.Dict)
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprDict {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub items: Vec<crate::DictItem>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [Set](https://docs.python.org/3/library/ast.html#ast.Set)
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprSet {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub elts: Vec<Expr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [ListComp](https://docs.python.org/3/library/ast.html#ast.ListComp)
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprListComp {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub elt: Box<Expr>,
|
||||||
|
pub generators: Vec<crate::Comprehension>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [SetComp](https://docs.python.org/3/library/ast.html#ast.SetComp)
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprSetComp {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub elt: Box<Expr>,
|
||||||
|
pub generators: Vec<crate::Comprehension>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [DictComp](https://docs.python.org/3/library/ast.html#ast.DictComp)
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprDictComp {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub key: Box<Expr>,
|
||||||
|
pub value: Box<Expr>,
|
||||||
|
pub generators: Vec<crate::Comprehension>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [GeneratorExp](https://docs.python.org/3/library/ast.html#ast.GeneratorExp)
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprGenerator {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub elt: Box<Expr>,
|
||||||
|
pub generators: Vec<crate::Comprehension>,
|
||||||
|
pub parenthesized: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [Await](https://docs.python.org/3/library/ast.html#ast.Await)
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprAwait {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub value: Box<Expr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [Yield](https://docs.python.org/3/library/ast.html#ast.Yield)
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprYield {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub value: Option<Box<Expr>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [YieldFrom](https://docs.python.org/3/library/ast.html#ast.YieldFrom)
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprYieldFrom {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub value: Box<Expr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [Compare](https://docs.python.org/3/library/ast.html#ast.Compare)
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprCompare {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub left: Box<Expr>,
|
||||||
|
pub ops: Box<[crate::CmpOp]>,
|
||||||
|
pub comparators: Box<[Expr]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [Call](https://docs.python.org/3/library/ast.html#ast.Call)
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprCall {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub func: Box<Expr>,
|
||||||
|
pub arguments: crate::Arguments,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An AST node that represents either a single-part f-string literal
|
||||||
|
/// or an implicitly concatenated f-string literal.
|
||||||
|
///
|
||||||
|
/// This type differs from the original Python AST `JoinedStr` in that it
|
||||||
|
/// doesn't join the implicitly concatenated parts into a single string. Instead,
|
||||||
|
/// it keeps them separate and provide various methods to access the parts.
|
||||||
|
///
|
||||||
|
/// See also [JoinedStr](https://docs.python.org/3/library/ast.html#ast.JoinedStr)
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprFString {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub value: crate::FStringValue,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An AST node that represents either a single-part string literal
|
||||||
|
/// or an implicitly concatenated string literal.
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprStringLiteral {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub value: crate::StringLiteralValue,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An AST node that represents either a single-part bytestring literal
|
||||||
|
/// or an implicitly concatenated bytestring literal.
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprBytesLiteral {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub value: crate::BytesLiteralValue,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprNumberLiteral {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub value: crate::Number,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Default)]
|
||||||
|
pub struct ExprBooleanLiteral {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub value: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Default)]
|
||||||
|
pub struct ExprNoneLiteral {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Default)]
|
||||||
|
pub struct ExprEllipsisLiteral {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [Attribute](https://docs.python.org/3/library/ast.html#ast.Attribute)
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprAttribute {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub value: Box<Expr>,
|
||||||
|
pub attr: crate::Identifier,
|
||||||
|
pub ctx: crate::ExprContext,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [Subscript](https://docs.python.org/3/library/ast.html#ast.Subscript)
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprSubscript {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub value: Box<Expr>,
|
||||||
|
pub slice: Box<Expr>,
|
||||||
|
pub ctx: crate::ExprContext,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [Starred](https://docs.python.org/3/library/ast.html#ast.Starred)
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprStarred {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub value: Box<Expr>,
|
||||||
|
pub ctx: crate::ExprContext,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [Name](https://docs.python.org/3/library/ast.html#ast.Name)
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprName {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub id: Name,
|
||||||
|
pub ctx: crate::ExprContext,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [List](https://docs.python.org/3/library/ast.html#ast.List)
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprList {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub elts: Vec<Expr>,
|
||||||
|
pub ctx: crate::ExprContext,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [Tuple](https://docs.python.org/3/library/ast.html#ast.Tuple)
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprTuple {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub elts: Vec<Expr>,
|
||||||
|
pub ctx: crate::ExprContext,
|
||||||
|
pub parenthesized: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [Slice](https://docs.python.org/3/library/ast.html#ast.Slice)
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprSlice {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub lower: Option<Box<Expr>>,
|
||||||
|
pub upper: Option<Box<Expr>>,
|
||||||
|
pub step: Option<Box<Expr>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An AST node used to represent a IPython escape command at the expression level.
|
||||||
|
///
|
||||||
|
/// For example,
|
||||||
|
/// ```python
|
||||||
|
/// dir = !pwd
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Here, the escape kind can only be `!` or `%` otherwise it is a syntax error.
|
||||||
|
///
|
||||||
|
/// For more information related to terminology and syntax of escape commands,
|
||||||
|
/// see [`crate::StmtIpyEscapeCommand`].
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ExprIpyEscapeCommand {
|
||||||
|
pub range: ruff_text_size::TextRange,
|
||||||
|
pub kind: crate::IpyEscapeKind,
|
||||||
|
pub value: Box<str>,
|
||||||
|
}
|
||||||
|
|
|
@ -3,7 +3,8 @@ use std::fmt::{Debug, Display, Formatter, Write};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use crate::{nodes, Expr};
|
use crate::generated::ExprName;
|
||||||
|
use crate::Expr;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
@ -387,16 +388,14 @@ impl<'a> UnqualifiedName<'a> {
|
||||||
let attr1 = match expr {
|
let attr1 = match expr {
|
||||||
Expr::Attribute(attr1) => attr1,
|
Expr::Attribute(attr1) => attr1,
|
||||||
// Ex) `foo`
|
// Ex) `foo`
|
||||||
Expr::Name(nodes::ExprName { id, .. }) => {
|
Expr::Name(ExprName { id, .. }) => return Some(Self::from_slice(&[id.as_str()])),
|
||||||
return Some(Self::from_slice(&[id.as_str()]))
|
|
||||||
}
|
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let attr2 = match attr1.value.as_ref() {
|
let attr2 = match attr1.value.as_ref() {
|
||||||
Expr::Attribute(attr2) => attr2,
|
Expr::Attribute(attr2) => attr2,
|
||||||
// Ex) `foo.bar`
|
// Ex) `foo.bar`
|
||||||
Expr::Name(nodes::ExprName { id, .. }) => {
|
Expr::Name(ExprName { id, .. }) => {
|
||||||
return Some(Self::from_slice(&[id.as_str(), attr1.attr.as_str()]))
|
return Some(Self::from_slice(&[id.as_str(), attr1.attr.as_str()]))
|
||||||
}
|
}
|
||||||
_ => return None,
|
_ => return None,
|
||||||
|
@ -405,7 +404,7 @@ impl<'a> UnqualifiedName<'a> {
|
||||||
let attr3 = match attr2.value.as_ref() {
|
let attr3 = match attr2.value.as_ref() {
|
||||||
Expr::Attribute(attr3) => attr3,
|
Expr::Attribute(attr3) => attr3,
|
||||||
// Ex) `foo.bar.baz`
|
// Ex) `foo.bar.baz`
|
||||||
Expr::Name(nodes::ExprName { id, .. }) => {
|
Expr::Name(ExprName { id, .. }) => {
|
||||||
return Some(Self::from_slice(&[
|
return Some(Self::from_slice(&[
|
||||||
id.as_str(),
|
id.as_str(),
|
||||||
attr2.attr.as_str(),
|
attr2.attr.as_str(),
|
||||||
|
@ -418,7 +417,7 @@ impl<'a> UnqualifiedName<'a> {
|
||||||
let attr4 = match attr3.value.as_ref() {
|
let attr4 = match attr3.value.as_ref() {
|
||||||
Expr::Attribute(attr4) => attr4,
|
Expr::Attribute(attr4) => attr4,
|
||||||
// Ex) `foo.bar.baz.bop`
|
// Ex) `foo.bar.baz.bop`
|
||||||
Expr::Name(nodes::ExprName { id, .. }) => {
|
Expr::Name(ExprName { id, .. }) => {
|
||||||
return Some(Self::from_slice(&[
|
return Some(Self::from_slice(&[
|
||||||
id.as_str(),
|
id.as_str(),
|
||||||
attr3.attr.as_str(),
|
attr3.attr.as_str(),
|
||||||
|
@ -432,7 +431,7 @@ impl<'a> UnqualifiedName<'a> {
|
||||||
let attr5 = match attr4.value.as_ref() {
|
let attr5 = match attr4.value.as_ref() {
|
||||||
Expr::Attribute(attr5) => attr5,
|
Expr::Attribute(attr5) => attr5,
|
||||||
// Ex) `foo.bar.baz.bop.bap`
|
// Ex) `foo.bar.baz.bop.bap`
|
||||||
Expr::Name(nodes::ExprName { id, .. }) => {
|
Expr::Name(ExprName { id, .. }) => {
|
||||||
return Some(Self::from_slice(&[
|
return Some(Self::from_slice(&[
|
||||||
id.as_str(),
|
id.as_str(),
|
||||||
attr4.attr.as_str(),
|
attr4.attr.as_str(),
|
||||||
|
@ -447,7 +446,7 @@ impl<'a> UnqualifiedName<'a> {
|
||||||
let attr6 = match attr5.value.as_ref() {
|
let attr6 = match attr5.value.as_ref() {
|
||||||
Expr::Attribute(attr6) => attr6,
|
Expr::Attribute(attr6) => attr6,
|
||||||
// Ex) `foo.bar.baz.bop.bap.bab`
|
// Ex) `foo.bar.baz.bop.bap.bab`
|
||||||
Expr::Name(nodes::ExprName { id, .. }) => {
|
Expr::Name(ExprName { id, .. }) => {
|
||||||
return Some(Self::from_slice(&[
|
return Some(Self::from_slice(&[
|
||||||
id.as_str(),
|
id.as_str(),
|
||||||
attr5.attr.as_str(),
|
attr5.attr.as_str(),
|
||||||
|
@ -463,7 +462,7 @@ impl<'a> UnqualifiedName<'a> {
|
||||||
let attr7 = match attr6.value.as_ref() {
|
let attr7 = match attr6.value.as_ref() {
|
||||||
Expr::Attribute(attr7) => attr7,
|
Expr::Attribute(attr7) => attr7,
|
||||||
// Ex) `foo.bar.baz.bop.bap.bab.bob`
|
// Ex) `foo.bar.baz.bop.bap.bab.bob`
|
||||||
Expr::Name(nodes::ExprName { id, .. }) => {
|
Expr::Name(ExprName { id, .. }) => {
|
||||||
return Some(Self::from_slice(&[
|
return Some(Self::from_slice(&[
|
||||||
id.as_str(),
|
id.as_str(),
|
||||||
attr6.attr.as_str(),
|
attr6.attr.as_str(),
|
||||||
|
@ -480,7 +479,7 @@ impl<'a> UnqualifiedName<'a> {
|
||||||
let attr8 = match attr7.value.as_ref() {
|
let attr8 = match attr7.value.as_ref() {
|
||||||
Expr::Attribute(attr8) => attr8,
|
Expr::Attribute(attr8) => attr8,
|
||||||
// Ex) `foo.bar.baz.bop.bap.bab.bob.bib`
|
// Ex) `foo.bar.baz.bop.bap.bab.bob.bib`
|
||||||
Expr::Name(nodes::ExprName { id, .. }) => {
|
Expr::Name(ExprName { id, .. }) => {
|
||||||
return Some(Self(SegmentsVec::from([
|
return Some(Self(SegmentsVec::from([
|
||||||
id.as_str(),
|
id.as_str(),
|
||||||
attr7.attr.as_str(),
|
attr7.attr.as_str(),
|
||||||
|
@ -505,7 +504,7 @@ impl<'a> UnqualifiedName<'a> {
|
||||||
segments.push(attr.attr.as_str());
|
segments.push(attr.attr.as_str());
|
||||||
&*attr.value
|
&*attr.value
|
||||||
}
|
}
|
||||||
Expr::Name(nodes::ExprName { id, .. }) => {
|
Expr::Name(ExprName { id, .. }) => {
|
||||||
segments.push(id.as_str());
|
segments.push(id.as_str());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
#![allow(clippy::derive_partial_eq_without_eq)]
|
#![allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
|
||||||
|
use crate::generated::{
|
||||||
|
ExprBytesLiteral, ExprDict, ExprFString, ExprList, ExprName, ExprSet, ExprStringLiteral,
|
||||||
|
ExprTuple,
|
||||||
|
};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
@ -120,6 +124,7 @@ pub struct StmtClassDef {
|
||||||
pub decorator_list: Vec<Decorator>,
|
pub decorator_list: Vec<Decorator>,
|
||||||
pub name: Identifier,
|
pub name: Identifier,
|
||||||
pub type_params: Option<Box<TypeParams>>,
|
pub type_params: Option<Box<TypeParams>>,
|
||||||
|
// TODO: can remove?
|
||||||
pub arguments: Option<Box<Arguments>>,
|
pub arguments: Option<Box<Arguments>>,
|
||||||
pub body: Vec<Stmt>,
|
pub body: Vec<Stmt>,
|
||||||
}
|
}
|
||||||
|
@ -379,74 +384,6 @@ impl ExprRef<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An AST node used to represent a IPython escape command at the expression level.
|
|
||||||
///
|
|
||||||
/// For example,
|
|
||||||
/// ```python
|
|
||||||
/// dir = !pwd
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Here, the escape kind can only be `!` or `%` otherwise it is a syntax error.
|
|
||||||
///
|
|
||||||
/// For more information related to terminology and syntax of escape commands,
|
|
||||||
/// see [`StmtIpyEscapeCommand`].
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprIpyEscapeCommand {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub kind: IpyEscapeKind,
|
|
||||||
pub value: Box<str>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [BoolOp](https://docs.python.org/3/library/ast.html#ast.BoolOp)
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprBoolOp {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub op: BoolOp,
|
|
||||||
pub values: Vec<Expr>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [NamedExpr](https://docs.python.org/3/library/ast.html#ast.NamedExpr)
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprNamed {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub target: Box<Expr>,
|
|
||||||
pub value: Box<Expr>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [BinOp](https://docs.python.org/3/library/ast.html#ast.BinOp)
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprBinOp {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub left: Box<Expr>,
|
|
||||||
pub op: Operator,
|
|
||||||
pub right: Box<Expr>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [UnaryOp](https://docs.python.org/3/library/ast.html#ast.UnaryOp)
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprUnaryOp {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub op: UnaryOp,
|
|
||||||
pub operand: Box<Expr>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [Lambda](https://docs.python.org/3/library/ast.html#ast.Lambda)
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprLambda {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub parameters: Option<Box<Parameters>>,
|
|
||||||
pub body: Box<Expr>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [IfExp](https://docs.python.org/3/library/ast.html#ast.IfExp)
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprIf {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub test: Box<Expr>,
|
|
||||||
pub body: Box<Expr>,
|
|
||||||
pub orelse: Box<Expr>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents an item in a [dictionary literal display][1].
|
/// Represents an item in a [dictionary literal display][1].
|
||||||
///
|
///
|
||||||
/// Consider the following Python dictionary literal:
|
/// Consider the following Python dictionary literal:
|
||||||
|
@ -495,13 +432,6 @@ impl Ranged for DictItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See also [Dict](https://docs.python.org/3/library/ast.html#ast.Dict)
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprDict {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub items: Vec<DictItem>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ExprDict {
|
impl ExprDict {
|
||||||
/// Returns an `Iterator` over the AST nodes representing the
|
/// Returns an `Iterator` over the AST nodes representing the
|
||||||
/// dictionary's keys.
|
/// dictionary's keys.
|
||||||
|
@ -637,13 +567,6 @@ impl DoubleEndedIterator for DictValueIterator<'_> {
|
||||||
impl FusedIterator for DictValueIterator<'_> {}
|
impl FusedIterator for DictValueIterator<'_> {}
|
||||||
impl ExactSizeIterator for DictValueIterator<'_> {}
|
impl ExactSizeIterator for DictValueIterator<'_> {}
|
||||||
|
|
||||||
/// See also [Set](https://docs.python.org/3/library/ast.html#ast.Set)
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprSet {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub elts: Vec<Expr>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ExprSet {
|
impl ExprSet {
|
||||||
pub fn iter(&self) -> std::slice::Iter<'_, Expr> {
|
pub fn iter(&self) -> std::slice::Iter<'_, Expr> {
|
||||||
self.elts.iter()
|
self.elts.iter()
|
||||||
|
@ -667,78 +590,6 @@ impl<'a> IntoIterator for &'a ExprSet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See also [ListComp](https://docs.python.org/3/library/ast.html#ast.ListComp)
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprListComp {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub elt: Box<Expr>,
|
|
||||||
pub generators: Vec<Comprehension>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [SetComp](https://docs.python.org/3/library/ast.html#ast.SetComp)
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprSetComp {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub elt: Box<Expr>,
|
|
||||||
pub generators: Vec<Comprehension>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [DictComp](https://docs.python.org/3/library/ast.html#ast.DictComp)
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprDictComp {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub key: Box<Expr>,
|
|
||||||
pub value: Box<Expr>,
|
|
||||||
pub generators: Vec<Comprehension>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [GeneratorExp](https://docs.python.org/3/library/ast.html#ast.GeneratorExp)
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprGenerator {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub elt: Box<Expr>,
|
|
||||||
pub generators: Vec<Comprehension>,
|
|
||||||
pub parenthesized: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [Await](https://docs.python.org/3/library/ast.html#ast.Await)
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprAwait {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub value: Box<Expr>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [Yield](https://docs.python.org/3/library/ast.html#ast.Yield)
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprYield {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub value: Option<Box<Expr>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [YieldFrom](https://docs.python.org/3/library/ast.html#ast.YieldFrom)
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprYieldFrom {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub value: Box<Expr>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [Compare](https://docs.python.org/3/library/ast.html#ast.Compare)
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprCompare {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub left: Box<Expr>,
|
|
||||||
pub ops: Box<[CmpOp]>,
|
|
||||||
pub comparators: Box<[Expr]>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [Call](https://docs.python.org/3/library/ast.html#ast.Call)
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprCall {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub func: Box<Expr>,
|
|
||||||
pub arguments: Arguments,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct FStringFormatSpec {
|
pub struct FStringFormatSpec {
|
||||||
pub range: TextRange,
|
pub range: TextRange,
|
||||||
|
@ -811,20 +662,6 @@ pub struct DebugText {
|
||||||
pub trailing: String,
|
pub trailing: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An AST node that represents either a single-part f-string literal
|
|
||||||
/// or an implicitly concatenated f-string literal.
|
|
||||||
///
|
|
||||||
/// This type differs from the original Python AST ([JoinedStr]) in that it
|
|
||||||
/// doesn't join the implicitly concatenated parts into a single string. Instead,
|
|
||||||
/// it keeps them separate and provide various methods to access the parts.
|
|
||||||
///
|
|
||||||
/// [JoinedStr]: https://docs.python.org/3/library/ast.html#ast.JoinedStr
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprFString {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub value: FStringValue,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ExprFString {
|
impl ExprFString {
|
||||||
/// Returns the single [`FString`] if the f-string isn't implicitly concatenated, [`None`]
|
/// Returns the single [`FString`] if the f-string isn't implicitly concatenated, [`None`]
|
||||||
/// otherwise.
|
/// otherwise.
|
||||||
|
@ -1286,14 +1123,6 @@ impl fmt::Debug for FStringElements {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An AST node that represents either a single-part string literal
|
|
||||||
/// or an implicitly concatenated string literal.
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprStringLiteral {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub value: StringLiteralValue,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ExprStringLiteral {
|
impl ExprStringLiteral {
|
||||||
/// Return `Some(literal)` if the string only consists of a single `StringLiteral` part
|
/// Return `Some(literal)` if the string only consists of a single `StringLiteral` part
|
||||||
/// (indicating that it is not implicitly concatenated). Otherwise, return `None`.
|
/// (indicating that it is not implicitly concatenated). Otherwise, return `None`.
|
||||||
|
@ -1738,14 +1567,6 @@ impl Debug for ConcatenatedStringLiteral {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An AST node that represents either a single-part bytestring literal
|
|
||||||
/// or an implicitly concatenated bytestring literal.
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprBytesLiteral {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub value: BytesLiteralValue,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ExprBytesLiteral {
|
impl ExprBytesLiteral {
|
||||||
/// Return `Some(literal)` if the bytestring only consists of a single `BytesLiteral` part
|
/// Return `Some(literal)` if the bytestring only consists of a single `BytesLiteral` part
|
||||||
/// (indicating that it is not implicitly concatenated). Otherwise, return `None`.
|
/// (indicating that it is not implicitly concatenated). Otherwise, return `None`.
|
||||||
|
@ -2347,12 +2168,6 @@ impl From<FStringFlags> for AnyStringFlags {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprNumberLiteral {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub value: Number,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, is_macro::Is)]
|
#[derive(Clone, Debug, PartialEq, is_macro::Is)]
|
||||||
pub enum Number {
|
pub enum Number {
|
||||||
Int(int::Int),
|
Int(int::Int),
|
||||||
|
@ -2360,70 +2175,12 @@ pub enum Number {
|
||||||
Complex { real: f64, imag: f64 },
|
Complex { real: f64, imag: f64 },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
|
||||||
pub struct ExprBooleanLiteral {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub value: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
|
||||||
pub struct ExprNoneLiteral {
|
|
||||||
pub range: TextRange,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
|
||||||
pub struct ExprEllipsisLiteral {
|
|
||||||
pub range: TextRange,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [Attribute](https://docs.python.org/3/library/ast.html#ast.Attribute)
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprAttribute {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub value: Box<Expr>,
|
|
||||||
pub attr: Identifier,
|
|
||||||
pub ctx: ExprContext,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [Subscript](https://docs.python.org/3/library/ast.html#ast.Subscript)
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprSubscript {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub value: Box<Expr>,
|
|
||||||
pub slice: Box<Expr>,
|
|
||||||
pub ctx: ExprContext,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [Starred](https://docs.python.org/3/library/ast.html#ast.Starred)
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprStarred {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub value: Box<Expr>,
|
|
||||||
pub ctx: ExprContext,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [Name](https://docs.python.org/3/library/ast.html#ast.Name)
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprName {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub id: Name,
|
|
||||||
pub ctx: ExprContext,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ExprName {
|
impl ExprName {
|
||||||
pub fn id(&self) -> &Name {
|
pub fn id(&self) -> &Name {
|
||||||
&self.id
|
&self.id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See also [List](https://docs.python.org/3/library/ast.html#ast.List)
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprList {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub elts: Vec<Expr>,
|
|
||||||
pub ctx: ExprContext,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ExprList {
|
impl ExprList {
|
||||||
pub fn iter(&self) -> std::slice::Iter<'_, Expr> {
|
pub fn iter(&self) -> std::slice::Iter<'_, Expr> {
|
||||||
self.elts.iter()
|
self.elts.iter()
|
||||||
|
@ -2447,17 +2204,6 @@ impl<'a> IntoIterator for &'a ExprList {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See also [Tuple](https://docs.python.org/3/library/ast.html#ast.Tuple)
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprTuple {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub elts: Vec<Expr>,
|
|
||||||
pub ctx: ExprContext,
|
|
||||||
|
|
||||||
/// Whether the tuple is parenthesized in the source code.
|
|
||||||
pub parenthesized: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ExprTuple {
|
impl ExprTuple {
|
||||||
pub fn iter(&self) -> std::slice::Iter<'_, Expr> {
|
pub fn iter(&self) -> std::slice::Iter<'_, Expr> {
|
||||||
self.elts.iter()
|
self.elts.iter()
|
||||||
|
@ -2481,15 +2227,6 @@ impl<'a> IntoIterator for &'a ExprTuple {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See also [Slice](https://docs.python.org/3/library/ast.html#ast.Slice)
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct ExprSlice {
|
|
||||||
pub range: TextRange,
|
|
||||||
pub lower: Option<Box<Expr>>,
|
|
||||||
pub upper: Option<Box<Expr>>,
|
|
||||||
pub step: Option<Box<Expr>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See also [expr_context](https://docs.python.org/3/library/ast.html#ast.expr_context)
|
/// See also [expr_context](https://docs.python.org/3/library/ast.html#ast.expr_context)
|
||||||
#[derive(Clone, Debug, PartialEq, is_macro::Is, Copy, Hash, Eq)]
|
#[derive(Clone, Debug, PartialEq, is_macro::Is, Copy, Hash, Eq)]
|
||||||
pub enum ExprContext {
|
pub enum ExprContext {
|
||||||
|
@ -3625,6 +3362,7 @@ mod tests {
|
||||||
#[allow(clippy::wildcard_imports)]
|
#[allow(clippy::wildcard_imports)]
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
use crate::generated::*;
|
||||||
use crate::Mod;
|
use crate::Mod;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
|
|
||||||
use crate::visitor::transformer::{walk_expr, walk_keyword, Transformer};
|
use crate::visitor::transformer::{walk_expr, walk_keyword, Transformer};
|
||||||
use crate::{nodes, Expr, Keyword};
|
use crate::{self as ast};
|
||||||
|
use crate::{Expr, Keyword};
|
||||||
|
|
||||||
/// Change an expression's location (recursively) to match a desired, fixed
|
/// Change an expression's location (recursively) to match a desired, fixed
|
||||||
/// range.
|
/// range.
|
||||||
|
@ -17,100 +18,100 @@ struct Relocator {
|
||||||
impl Transformer for Relocator {
|
impl Transformer for Relocator {
|
||||||
fn visit_expr(&self, expr: &mut Expr) {
|
fn visit_expr(&self, expr: &mut Expr) {
|
||||||
match expr {
|
match expr {
|
||||||
Expr::BoolOp(nodes::ExprBoolOp { range, .. }) => {
|
Expr::BoolOp(ast::ExprBoolOp { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::Named(nodes::ExprNamed { range, .. }) => {
|
Expr::Named(ast::ExprNamed { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::BinOp(nodes::ExprBinOp { range, .. }) => {
|
Expr::BinOp(ast::ExprBinOp { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::UnaryOp(nodes::ExprUnaryOp { range, .. }) => {
|
Expr::UnaryOp(ast::ExprUnaryOp { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::Lambda(nodes::ExprLambda { range, .. }) => {
|
Expr::Lambda(ast::ExprLambda { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::If(nodes::ExprIf { range, .. }) => {
|
Expr::If(ast::ExprIf { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::Dict(nodes::ExprDict { range, .. }) => {
|
Expr::Dict(ast::ExprDict { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::Set(nodes::ExprSet { range, .. }) => {
|
Expr::Set(ast::ExprSet { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::ListComp(nodes::ExprListComp { range, .. }) => {
|
Expr::ListComp(ast::ExprListComp { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::SetComp(nodes::ExprSetComp { range, .. }) => {
|
Expr::SetComp(ast::ExprSetComp { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::DictComp(nodes::ExprDictComp { range, .. }) => {
|
Expr::DictComp(ast::ExprDictComp { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::Generator(nodes::ExprGenerator { range, .. }) => {
|
Expr::Generator(ast::ExprGenerator { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::Await(nodes::ExprAwait { range, .. }) => {
|
Expr::Await(ast::ExprAwait { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::Yield(nodes::ExprYield { range, .. }) => {
|
Expr::Yield(ast::ExprYield { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::YieldFrom(nodes::ExprYieldFrom { range, .. }) => {
|
Expr::YieldFrom(ast::ExprYieldFrom { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::Compare(nodes::ExprCompare { range, .. }) => {
|
Expr::Compare(ast::ExprCompare { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::Call(nodes::ExprCall { range, .. }) => {
|
Expr::Call(ast::ExprCall { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::FString(nodes::ExprFString { range, .. }) => {
|
Expr::FString(ast::ExprFString { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::StringLiteral(nodes::ExprStringLiteral { range, .. }) => {
|
Expr::StringLiteral(ast::ExprStringLiteral { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::BytesLiteral(nodes::ExprBytesLiteral { range, .. }) => {
|
Expr::BytesLiteral(ast::ExprBytesLiteral { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::NumberLiteral(nodes::ExprNumberLiteral { range, .. }) => {
|
Expr::NumberLiteral(ast::ExprNumberLiteral { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::BooleanLiteral(nodes::ExprBooleanLiteral { range, .. }) => {
|
Expr::BooleanLiteral(ast::ExprBooleanLiteral { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::NoneLiteral(nodes::ExprNoneLiteral { range }) => {
|
Expr::NoneLiteral(ast::ExprNoneLiteral { range }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::EllipsisLiteral(nodes::ExprEllipsisLiteral { range }) => {
|
Expr::EllipsisLiteral(ast::ExprEllipsisLiteral { range }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::Attribute(nodes::ExprAttribute { range, .. }) => {
|
Expr::Attribute(ast::ExprAttribute { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::Subscript(nodes::ExprSubscript { range, .. }) => {
|
Expr::Subscript(ast::ExprSubscript { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::Starred(nodes::ExprStarred { range, .. }) => {
|
Expr::Starred(ast::ExprStarred { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::Name(nodes::ExprName { range, .. }) => {
|
Expr::Name(ast::ExprName { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::List(nodes::ExprList { range, .. }) => {
|
Expr::List(ast::ExprList { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::Tuple(nodes::ExprTuple { range, .. }) => {
|
Expr::Tuple(ast::ExprTuple { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::Slice(nodes::ExprSlice { range, .. }) => {
|
Expr::Slice(ast::ExprSlice { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
Expr::IpyEscapeCommand(nodes::ExprIpyEscapeCommand { range, .. }) => {
|
Expr::IpyEscapeCommand(ast::ExprIpyEscapeCommand { range, .. }) => {
|
||||||
*range = self.range;
|
*range = self.range;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue