From 23fd4927ae72ab20c8e1d5a29f476bdae58a49be Mon Sep 17 00:00:00 2001 From: Shaygan Hooshyari Date: Wed, 5 Mar 2025 14:25:55 +0100 Subject: [PATCH] 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 --- crates/ruff_python_ast/ast.toml | 303 ++++++++++++++++++++---- crates/ruff_python_ast/generate.py | 144 ++++++++++- crates/ruff_python_ast/src/generated.rs | 268 +++++++++++++++++++++ crates/ruff_python_ast/src/name.rs | 23 +- crates/ruff_python_ast/src/nodes.rs | 274 +-------------------- crates/ruff_python_ast/src/relocate.rs | 67 +++--- 6 files changed, 719 insertions(+), 360 deletions(-) diff --git a/crates/ruff_python_ast/ast.toml b/crates/ruff_python_ast/ast.toml index 10c9cd9132..95fcfb7bc2 100644 --- a/crates/ruff_python_ast/ast.toml +++ b/crates/ruff_python_ast/ast.toml @@ -26,18 +26,36 @@ # Controls the name of the AnyNodeRef::is_foo_bar method. The default is the # group name in snake_case. # -# rustdoc: -# A rustdoc comment that is added to the group's enums. +# doc: +# A doc comment that is added to the group's enums. # # 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: # 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`.) [Mod] 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] ModModule = {} @@ -46,7 +64,7 @@ ModExpression = {} [Stmt] add_suffix_to_is_methods = true 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] StmtFunctionDef = {} @@ -78,44 +96,247 @@ StmtIpyEscapeCommand = {} [Expr] add_suffix_to_is_methods = true 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] -ExprBoolOp = {} -ExprNamed = {} -ExprBinOp = {} -ExprUnaryOp = {} -ExprLambda = {} -ExprIf = {} -ExprDict = {} -ExprSet = {} -ExprListComp = {} -ExprSetComp = {} -ExprDictComp = {} -ExprGenerator = {} -ExprAwait = {} -ExprYield = {} -ExprYieldFrom = {} -ExprCompare = {} -ExprCall = {} -ExprFString = {} -ExprStringLiteral = {} -ExprBytesLiteral = {} -ExprNumberLiteral = {} -ExprBooleanLiteral = {} -ExprNoneLiteral = {} -ExprEllipsisLiteral = {} -ExprAttribute = {} -ExprSubscript = {} -ExprStarred = {} -ExprName = {} -ExprList = {} -ExprTuple = {} -ExprSlice = {} -ExprIpyEscapeCommand = {} +[Expr.nodes.ExprBoolOp] +doc = "See also [BoolOp](https://docs.python.org/3/library/ast.html#ast.BoolOp)" +fields = [ + { name = "op", type = "BoolOp" }, + { name = "values", type = "Expr*" } +] + +[Expr.nodes.ExprNamed] +doc = "See also [NamedExpr](https://docs.python.org/3/library/ast.html#ast.NamedExpr)" +fields = [ + { name = "target", type = "Expr" }, + { name = "value", type = "Expr" } +] + +[Expr.nodes.ExprBinOp] +doc = "See also [BinOp](https://docs.python.org/3/library/ast.html#ast.BinOp)" +fields = [ + { name = "left", type = "Expr" }, + { name = "op", type = "Operator" }, + { name = "right", type = "Expr" } +] + +[Expr.nodes.ExprUnaryOp] +doc = "See also [UnaryOp](https://docs.python.org/3/library/ast.html#ast.UnaryOp)" +fields = [ + { name = "op", type = "UnaryOp" }, + { name = "operand", type = "Expr" } +] + +[Expr.nodes.ExprLambda] +doc = "See also [Lambda](https://docs.python.org/3/library/ast.html#ast.Lambda)" +fields = [ + { name = "parameters", type = "Box?" }, + { 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" } +] [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] ExceptHandlerExceptHandler = {} @@ -125,7 +346,7 @@ FStringExpressionElement = {variant = "Expression"} FStringLiteralElement = {variant = "Literal"} [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] PatternMatchValue = {} @@ -138,7 +359,7 @@ PatternMatchAs = {} PatternMatchOr = {} [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] TypeParamTypeVar = {} diff --git a/crates/ruff_python_ast/generate.py b/crates/ruff_python_ast/generate.py index 35ce26cc5d..59088034f9 100644 --- a/crates/ruff_python_ast/generate.py +++ b/crates/ruff_python_ast/generate.py @@ -14,6 +14,24 @@ from typing import Any 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: 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("_") +def write_rustdoc(out: list[str], doc: str) -> None: + for line in doc.split("\n"): + out.append(f"/// {line}") + + # ------------------------------------------------------------------------------ # Read AST description @@ -71,7 +94,7 @@ class Group: add_suffix_to_is_methods: bool anynode_is_label: str - rustdoc: str | None + doc: str | None def __init__(self, group_name: str, group: dict[str, Any]) -> None: self.name = group_name @@ -79,7 +102,7 @@ class Group: self.ref_enum_ty = group_name + "Ref" 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.rustdoc = group.get("rustdoc") + self.doc = group.get("doc") self.nodes = [ Node(self, node_name, node) for node_name, node in group["nodes"].items() ] @@ -90,11 +113,74 @@ class Node: name: str variant: 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: self.name = node_name self.variant = node.get("variant", node_name.removeprefix(group.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> + 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(""" // This is a generated file. Don't modify it by hand! // 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: out.append("") - if group.rustdoc is not None: - out.append(group.rustdoc) + if group.doc is not None: + write_rustdoc(out, group.doc) out.append("#[derive(Clone, Debug, PartialEq)]") out.append(f"pub enum {group.owned_enum_ty} {{") for node in group.nodes: @@ -313,8 +401,8 @@ def write_ref_enum(out: list[str], ast: Ast) -> None: for group in ast.groups: out.append("") - if group.rustdoc is not None: - out.append(group.rustdoc) + if group.doc is not None: + write_rustdoc(out, group.doc) out.append("""#[derive(Clone, Copy, Debug, PartialEq, is_macro::Is)]""") out.append(f"""pub enum {group.ref_enum_ty}<'a> {{""") 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 @@ -558,6 +689,7 @@ def generate(ast: Ast) -> list[str]: write_ref_enum(out, ast) write_anynoderef(out, ast) write_nodekind(out, ast) + write_node(out, ast) return out diff --git a/crates/ruff_python_ast/src/generated.rs b/crates/ruff_python_ast/src/generated.rs index c33073da48..7238eb204f 100644 --- a/crates/ruff_python_ast/src/generated.rs +++ b/crates/ruff_python_ast/src/generated.rs @@ -1,6 +1,8 @@ // This is a generated file. Don't modify it by hand! // 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) #[derive(Clone, Debug, PartialEq)] 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, +} + +/// 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, + pub value: Box, +} + +/// 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, + pub op: crate::Operator, + pub right: Box, +} + +/// 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, +} + +/// 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>, + pub body: Box, +} + +/// 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, + pub body: Box, + pub orelse: Box, +} + +/// 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, +} + +/// 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, +} + +/// 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, + pub generators: Vec, +} + +/// 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, + pub generators: Vec, +} + +/// 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, + pub value: Box, + pub generators: Vec, +} + +/// 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, + pub generators: Vec, + 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, +} + +/// 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>, +} + +/// 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, +} + +/// 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, + 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, + 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, + 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, + pub slice: Box, + 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, + 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, + 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, + 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>, + pub upper: Option>, + pub step: Option>, +} + +/// 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, +} diff --git a/crates/ruff_python_ast/src/name.rs b/crates/ruff_python_ast/src/name.rs index 2cc8843ab2..6765f2aacf 100644 --- a/crates/ruff_python_ast/src/name.rs +++ b/crates/ruff_python_ast/src/name.rs @@ -3,7 +3,8 @@ use std::fmt::{Debug, Display, Formatter, Write}; use std::hash::{Hash, Hasher}; use std::ops::Deref; -use crate::{nodes, Expr}; +use crate::generated::ExprName; +use crate::Expr; #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -387,16 +388,14 @@ impl<'a> UnqualifiedName<'a> { let attr1 = match expr { Expr::Attribute(attr1) => attr1, // Ex) `foo` - Expr::Name(nodes::ExprName { id, .. }) => { - return Some(Self::from_slice(&[id.as_str()])) - } + Expr::Name(ExprName { id, .. }) => return Some(Self::from_slice(&[id.as_str()])), _ => return None, }; let attr2 = match attr1.value.as_ref() { Expr::Attribute(attr2) => attr2, // 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 None, @@ -405,7 +404,7 @@ impl<'a> UnqualifiedName<'a> { let attr3 = match attr2.value.as_ref() { Expr::Attribute(attr3) => attr3, // Ex) `foo.bar.baz` - Expr::Name(nodes::ExprName { id, .. }) => { + Expr::Name(ExprName { id, .. }) => { return Some(Self::from_slice(&[ id.as_str(), attr2.attr.as_str(), @@ -418,7 +417,7 @@ impl<'a> UnqualifiedName<'a> { let attr4 = match attr3.value.as_ref() { Expr::Attribute(attr4) => attr4, // Ex) `foo.bar.baz.bop` - Expr::Name(nodes::ExprName { id, .. }) => { + Expr::Name(ExprName { id, .. }) => { return Some(Self::from_slice(&[ id.as_str(), attr3.attr.as_str(), @@ -432,7 +431,7 @@ impl<'a> UnqualifiedName<'a> { let attr5 = match attr4.value.as_ref() { Expr::Attribute(attr5) => attr5, // Ex) `foo.bar.baz.bop.bap` - Expr::Name(nodes::ExprName { id, .. }) => { + Expr::Name(ExprName { id, .. }) => { return Some(Self::from_slice(&[ id.as_str(), attr4.attr.as_str(), @@ -447,7 +446,7 @@ impl<'a> UnqualifiedName<'a> { let attr6 = match attr5.value.as_ref() { Expr::Attribute(attr6) => attr6, // Ex) `foo.bar.baz.bop.bap.bab` - Expr::Name(nodes::ExprName { id, .. }) => { + Expr::Name(ExprName { id, .. }) => { return Some(Self::from_slice(&[ id.as_str(), attr5.attr.as_str(), @@ -463,7 +462,7 @@ impl<'a> UnqualifiedName<'a> { let attr7 = match attr6.value.as_ref() { Expr::Attribute(attr7) => attr7, // Ex) `foo.bar.baz.bop.bap.bab.bob` - Expr::Name(nodes::ExprName { id, .. }) => { + Expr::Name(ExprName { id, .. }) => { return Some(Self::from_slice(&[ id.as_str(), attr6.attr.as_str(), @@ -480,7 +479,7 @@ impl<'a> UnqualifiedName<'a> { let attr8 = match attr7.value.as_ref() { Expr::Attribute(attr8) => attr8, // Ex) `foo.bar.baz.bop.bap.bab.bob.bib` - Expr::Name(nodes::ExprName { id, .. }) => { + Expr::Name(ExprName { id, .. }) => { return Some(Self(SegmentsVec::from([ id.as_str(), attr7.attr.as_str(), @@ -505,7 +504,7 @@ impl<'a> UnqualifiedName<'a> { segments.push(attr.attr.as_str()); &*attr.value } - Expr::Name(nodes::ExprName { id, .. }) => { + Expr::Name(ExprName { id, .. }) => { segments.push(id.as_str()); break; } diff --git a/crates/ruff_python_ast/src/nodes.rs b/crates/ruff_python_ast/src/nodes.rs index e48349997c..dcd8b0632f 100644 --- a/crates/ruff_python_ast/src/nodes.rs +++ b/crates/ruff_python_ast/src/nodes.rs @@ -1,5 +1,9 @@ #![allow(clippy::derive_partial_eq_without_eq)] +use crate::generated::{ + ExprBytesLiteral, ExprDict, ExprFString, ExprList, ExprName, ExprSet, ExprStringLiteral, + ExprTuple, +}; use std::borrow::Cow; use std::fmt; use std::fmt::Debug; @@ -120,6 +124,7 @@ pub struct StmtClassDef { pub decorator_list: Vec, pub name: Identifier, pub type_params: Option>, + // TODO: can remove? pub arguments: Option>, pub body: Vec, } @@ -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, -} - -/// 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, -} - -/// 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, - pub value: Box, -} - -/// 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, - pub op: Operator, - pub right: Box, -} - -/// 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, -} - -/// 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>, - pub body: Box, -} - -/// 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, - pub body: Box, - pub orelse: Box, -} - /// Represents an item in a [dictionary literal display][1]. /// /// 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, -} - impl ExprDict { /// Returns an `Iterator` over the AST nodes representing the /// dictionary's keys. @@ -637,13 +567,6 @@ impl DoubleEndedIterator for DictValueIterator<'_> { impl FusedIterator 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, -} - impl ExprSet { pub fn iter(&self) -> std::slice::Iter<'_, Expr> { 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, - pub generators: Vec, -} - -/// 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, - pub generators: Vec, -} - -/// 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, - pub value: Box, - pub generators: Vec, -} - -/// 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, - pub generators: Vec, - 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, -} - -/// 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>, -} - -/// 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, -} - -/// 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, - 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, - pub arguments: Arguments, -} - #[derive(Clone, Debug, PartialEq)] pub struct FStringFormatSpec { pub range: TextRange, @@ -811,20 +662,6 @@ pub struct DebugText { 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 { /// Returns the single [`FString`] if the f-string isn't implicitly concatenated, [`None`] /// 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 { /// Return `Some(literal)` if the string only consists of a single `StringLiteral` part /// (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 { /// Return `Some(literal)` if the bytestring only consists of a single `BytesLiteral` part /// (indicating that it is not implicitly concatenated). Otherwise, return `None`. @@ -2347,12 +2168,6 @@ impl From for AnyStringFlags { } } -#[derive(Clone, Debug, PartialEq)] -pub struct ExprNumberLiteral { - pub range: TextRange, - pub value: Number, -} - #[derive(Clone, Debug, PartialEq, is_macro::Is)] pub enum Number { Int(int::Int), @@ -2360,70 +2175,12 @@ pub enum Number { 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, - 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, - pub slice: Box, - 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, - 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 { pub fn id(&self) -> &Name { &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, - pub ctx: ExprContext, -} - impl ExprList { pub fn iter(&self) -> std::slice::Iter<'_, Expr> { 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, - pub ctx: ExprContext, - - /// Whether the tuple is parenthesized in the source code. - pub parenthesized: bool, -} - impl ExprTuple { pub fn iter(&self) -> std::slice::Iter<'_, Expr> { 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>, - pub upper: Option>, - pub step: Option>, -} - /// 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)] pub enum ExprContext { @@ -3625,6 +3362,7 @@ mod tests { #[allow(clippy::wildcard_imports)] use super::*; + use crate::generated::*; use crate::Mod; #[test] diff --git a/crates/ruff_python_ast/src/relocate.rs b/crates/ruff_python_ast/src/relocate.rs index f4f327d073..803aea06f0 100644 --- a/crates/ruff_python_ast/src/relocate.rs +++ b/crates/ruff_python_ast/src/relocate.rs @@ -1,7 +1,8 @@ use ruff_text_size::TextRange; 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 /// range. @@ -17,100 +18,100 @@ struct Relocator { impl Transformer for Relocator { fn visit_expr(&self, expr: &mut Expr) { match expr { - Expr::BoolOp(nodes::ExprBoolOp { range, .. }) => { + Expr::BoolOp(ast::ExprBoolOp { range, .. }) => { *range = self.range; } - Expr::Named(nodes::ExprNamed { range, .. }) => { + Expr::Named(ast::ExprNamed { range, .. }) => { *range = self.range; } - Expr::BinOp(nodes::ExprBinOp { range, .. }) => { + Expr::BinOp(ast::ExprBinOp { range, .. }) => { *range = self.range; } - Expr::UnaryOp(nodes::ExprUnaryOp { range, .. }) => { + Expr::UnaryOp(ast::ExprUnaryOp { range, .. }) => { *range = self.range; } - Expr::Lambda(nodes::ExprLambda { range, .. }) => { + Expr::Lambda(ast::ExprLambda { range, .. }) => { *range = self.range; } - Expr::If(nodes::ExprIf { range, .. }) => { + Expr::If(ast::ExprIf { range, .. }) => { *range = self.range; } - Expr::Dict(nodes::ExprDict { range, .. }) => { + Expr::Dict(ast::ExprDict { range, .. }) => { *range = self.range; } - Expr::Set(nodes::ExprSet { range, .. }) => { + Expr::Set(ast::ExprSet { range, .. }) => { *range = self.range; } - Expr::ListComp(nodes::ExprListComp { range, .. }) => { + Expr::ListComp(ast::ExprListComp { range, .. }) => { *range = self.range; } - Expr::SetComp(nodes::ExprSetComp { range, .. }) => { + Expr::SetComp(ast::ExprSetComp { range, .. }) => { *range = self.range; } - Expr::DictComp(nodes::ExprDictComp { range, .. }) => { + Expr::DictComp(ast::ExprDictComp { range, .. }) => { *range = self.range; } - Expr::Generator(nodes::ExprGenerator { range, .. }) => { + Expr::Generator(ast::ExprGenerator { range, .. }) => { *range = self.range; } - Expr::Await(nodes::ExprAwait { range, .. }) => { + Expr::Await(ast::ExprAwait { range, .. }) => { *range = self.range; } - Expr::Yield(nodes::ExprYield { range, .. }) => { + Expr::Yield(ast::ExprYield { range, .. }) => { *range = self.range; } - Expr::YieldFrom(nodes::ExprYieldFrom { range, .. }) => { + Expr::YieldFrom(ast::ExprYieldFrom { range, .. }) => { *range = self.range; } - Expr::Compare(nodes::ExprCompare { range, .. }) => { + Expr::Compare(ast::ExprCompare { range, .. }) => { *range = self.range; } - Expr::Call(nodes::ExprCall { range, .. }) => { + Expr::Call(ast::ExprCall { range, .. }) => { *range = self.range; } - Expr::FString(nodes::ExprFString { range, .. }) => { + Expr::FString(ast::ExprFString { range, .. }) => { *range = self.range; } - Expr::StringLiteral(nodes::ExprStringLiteral { range, .. }) => { + Expr::StringLiteral(ast::ExprStringLiteral { range, .. }) => { *range = self.range; } - Expr::BytesLiteral(nodes::ExprBytesLiteral { range, .. }) => { + Expr::BytesLiteral(ast::ExprBytesLiteral { range, .. }) => { *range = self.range; } - Expr::NumberLiteral(nodes::ExprNumberLiteral { range, .. }) => { + Expr::NumberLiteral(ast::ExprNumberLiteral { range, .. }) => { *range = self.range; } - Expr::BooleanLiteral(nodes::ExprBooleanLiteral { range, .. }) => { + Expr::BooleanLiteral(ast::ExprBooleanLiteral { range, .. }) => { *range = self.range; } - Expr::NoneLiteral(nodes::ExprNoneLiteral { range }) => { + Expr::NoneLiteral(ast::ExprNoneLiteral { range }) => { *range = self.range; } - Expr::EllipsisLiteral(nodes::ExprEllipsisLiteral { range }) => { + Expr::EllipsisLiteral(ast::ExprEllipsisLiteral { range }) => { *range = self.range; } - Expr::Attribute(nodes::ExprAttribute { range, .. }) => { + Expr::Attribute(ast::ExprAttribute { range, .. }) => { *range = self.range; } - Expr::Subscript(nodes::ExprSubscript { range, .. }) => { + Expr::Subscript(ast::ExprSubscript { range, .. }) => { *range = self.range; } - Expr::Starred(nodes::ExprStarred { range, .. }) => { + Expr::Starred(ast::ExprStarred { range, .. }) => { *range = self.range; } - Expr::Name(nodes::ExprName { range, .. }) => { + Expr::Name(ast::ExprName { range, .. }) => { *range = self.range; } - Expr::List(nodes::ExprList { range, .. }) => { + Expr::List(ast::ExprList { range, .. }) => { *range = self.range; } - Expr::Tuple(nodes::ExprTuple { range, .. }) => { + Expr::Tuple(ast::ExprTuple { range, .. }) => { *range = self.range; } - Expr::Slice(nodes::ExprSlice { range, .. }) => { + Expr::Slice(ast::ExprSlice { range, .. }) => { *range = self.range; } - Expr::IpyEscapeCommand(nodes::ExprIpyEscapeCommand { range, .. }) => { + Expr::IpyEscapeCommand(ast::ExprIpyEscapeCommand { range, .. }) => { *range = self.range; } }