Skip to content

Commit

Permalink
Auto generate ast expression nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
Glyphack committed Feb 20, 2025
1 parent b385c7d commit 63f4777
Show file tree
Hide file tree
Showing 5 changed files with 240 additions and 104 deletions.
36 changes: 29 additions & 7 deletions crates/ruff_python_ast/ast.toml
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,6 @@ anynode_is_label = "expression"
rustdoc = "/// 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 = {}
Expand All @@ -113,6 +106,35 @@ ExprList = {}
ExprTuple = {}
ExprSlice = {}
ExprIpyEscapeCommand = {}
ExprBoolOp = { fields = [
{ name = "op", type = "BoolOp" },
{ name = "values", type = "Expr", seq = true }
]}
ExprNamed = { fields = [
{ name = "target", type = "Expr" },
{ name = "value", type = "Expr" }
]}
ExprBinOp = { fields = [
{ name = "left", type = "Expr" },
{ name = "op", type = "Operator" },
{ name = "right", type = "Expr" }
]}
ExprUnaryOp = { fields = [
{ name = "op", type = "UnaryOp" },
{ name = "operand", type = "Expr" }
]}
ExprLambda = { fields = [
{ name = "parameters", type = "Parameters", optional = true },
{ name = "body", type = "Expr" }
]}
ExprIf = { fields = [
{ name = "test", type = "Expr" },
{ name = "body", type = "Expr" },
{ name = "orelse", type = "Expr" }
]}
ExprDict = { fields = [
{ name = "items", type = "DictItem", seq = true },
]}

[ExceptHandler]
rustdoc = "/// See also [excepthandler](https://docs.python.org/3/library/ast.html#ast.excepthandler)"
Expand Down
64 changes: 64 additions & 0 deletions crates/ruff_python_ast/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,30 @@ class Node:
name: str
variant: str
ty: str
fields: list[Field] | None

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]


@dataclass
class Field:
name: str
ty: str
seq: bool
optional: bool

def __init__(self, field: dict[str, Any]) -> None:
self.name = field["name"]
self.ty = field["type"]
self.seq = field.get("seq", False)
self.optional = field.get("optional", False)


# ------------------------------------------------------------------------------
Expand Down Expand Up @@ -547,6 +566,50 @@ def write_nodekind(out: list[str], ast: Ast) -> None:
""")


# ------------------------------------------------------------------------------
# NodeKind


def write_node(out: list[str], ast: Ast) -> None:
write_node_list = [
"ExprBoolOp",
"ExprNamed",
"ExprBinOp",
"ExprUnaryOp",
"ExprLambda",
"ExprIf",
"ExprDict",
]
group_names = [group.name for group in ast.groups]
node_names = [node.name for node in ast.all_nodes]
for group in ast.groups:
for node in group.nodes:
if node.name not in write_node_list:
continue
if node.fields is not None:
out.append("#[derive(Clone, Debug, PartialEq)]")
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}: "
inner = f"crate::{field.ty}"
if field.ty in node_names or (
field.ty in group_names and (field.seq is False)
):
inner = f"Box<{inner}>"

if field.seq:
field_str += f"Vec<{inner}>,"
elif field.optional:
field_str += f"Option<{inner}>,"
else:
field_str += f"{inner},"
out.append(field_str)
out.append("}")
out.append("")


# ------------------------------------------------------------------------------
# Format and write output

Expand All @@ -558,6 +621,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


Expand Down
50 changes: 50 additions & 0 deletions crates/ruff_python_ast/src/generated.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

128 changes: 64 additions & 64 deletions crates/ruff_python_ast/src/nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -397,55 +397,55 @@ pub struct ExprIpyEscapeCommand {
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>,
}
// /// 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].
///
Expand Down Expand Up @@ -495,14 +495,14 @@ 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>,
}
// /// 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 crate::ExprDict {
/// Returns an `Iterator` over the AST nodes representing the
/// dictionary's keys.
pub fn iter_keys(&self) -> DictKeyIterator {
Expand Down Expand Up @@ -544,7 +544,7 @@ impl ExprDict {
}
}

impl<'a> IntoIterator for &'a ExprDict {
impl<'a> IntoIterator for &'a crate::ExprDict {
type IntoIter = std::slice::Iter<'a, DictItem>;
type Item = &'a DictItem;

Expand Down Expand Up @@ -3641,25 +3641,25 @@ mod tests {
assert_eq!(std::mem::size_of::<Expr>(), 64);
assert_eq!(std::mem::size_of::<ExprAttribute>(), 56);
assert_eq!(std::mem::size_of::<ExprAwait>(), 16);
assert_eq!(std::mem::size_of::<ExprBinOp>(), 32);
assert_eq!(std::mem::size_of::<ExprBoolOp>(), 40);
assert_eq!(std::mem::size_of::<crate::ExprBinOp>(), 32);
assert_eq!(std::mem::size_of::<crate::ExprBoolOp>(), 40);
assert_eq!(std::mem::size_of::<ExprBooleanLiteral>(), 12);
assert_eq!(std::mem::size_of::<ExprBytesLiteral>(), 40);
assert_eq!(std::mem::size_of::<ExprCall>(), 56);
assert_eq!(std::mem::size_of::<ExprCompare>(), 48);
assert_eq!(std::mem::size_of::<ExprDict>(), 32);
assert_eq!(std::mem::size_of::<crate::ExprDict>(), 32);
assert_eq!(std::mem::size_of::<ExprDictComp>(), 48);
assert_eq!(std::mem::size_of::<ExprEllipsisLiteral>(), 8);
// 56 for Rustc < 1.76
assert!(matches!(std::mem::size_of::<ExprFString>(), 48 | 56));
assert_eq!(std::mem::size_of::<ExprGenerator>(), 48);
assert_eq!(std::mem::size_of::<ExprIf>(), 32);
assert_eq!(std::mem::size_of::<crate::ExprIf>(), 32);
assert_eq!(std::mem::size_of::<ExprIpyEscapeCommand>(), 32);
assert_eq!(std::mem::size_of::<ExprLambda>(), 24);
assert_eq!(std::mem::size_of::<crate::ExprLambda>(), 24);
assert_eq!(std::mem::size_of::<ExprList>(), 40);
assert_eq!(std::mem::size_of::<ExprListComp>(), 40);
assert_eq!(std::mem::size_of::<ExprName>(), 40);
assert_eq!(std::mem::size_of::<ExprNamed>(), 24);
assert_eq!(std::mem::size_of::<crate::ExprNamed>(), 24);
assert_eq!(std::mem::size_of::<ExprNoneLiteral>(), 8);
assert_eq!(std::mem::size_of::<ExprNumberLiteral>(), 32);
assert_eq!(std::mem::size_of::<ExprSet>(), 32);
Expand All @@ -3669,7 +3669,7 @@ mod tests {
assert_eq!(std::mem::size_of::<ExprStringLiteral>(), 56);
assert_eq!(std::mem::size_of::<ExprSubscript>(), 32);
assert_eq!(std::mem::size_of::<ExprTuple>(), 40);
assert_eq!(std::mem::size_of::<ExprUnaryOp>(), 24);
assert_eq!(std::mem::size_of::<crate::ExprUnaryOp>(), 24);
assert_eq!(std::mem::size_of::<ExprYield>(), 16);
assert_eq!(std::mem::size_of::<ExprYieldFrom>(), 16);
}
Expand Down
Loading

0 comments on commit 63f4777

Please sign in to comment.