Refactor if statement, introduce nodes for elif and else (#22)

The old if layout couldn't differentiate between an else block with a
single if statement and an elif statement. Additionally we getting rid
of the recursion in favor of a single if struct with a vec of elif/else
children. This is accompanied by a big refactoring in ruff which removes
a bunch of TODOs and false negatives.
This commit is contained in:
konsti 2023-07-18 13:14:40 +02:00 committed by GitHub
parent ff3e8ead36
commit db04fd4157
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 20655 additions and 20466 deletions

View File

@ -650,12 +650,12 @@ pub struct StmtIf {
pub range: TextRange, pub range: TextRange,
pub test: Box<Expr>, pub test: Box<Expr>,
pub body: Vec<Stmt>, pub body: Vec<Stmt>,
pub orelse: Vec<Stmt>, pub elif_else_clauses: Vec<ElifElseClause>,
} }
impl Node for StmtIf { impl Node for StmtIf {
const NAME: &'static str = "If"; const NAME: &'static str = "If";
const FIELD_NAMES: &'static [&'static str] = &["test", "body", "orelse"]; const FIELD_NAMES: &'static [&'static str] = &["test", "body", "elif_else_clauses"];
} }
impl From<StmtIf> for Stmt { impl From<StmtIf> for Stmt {
fn from(payload: StmtIf) -> Self { fn from(payload: StmtIf) -> Self {
@ -668,6 +668,18 @@ impl From<StmtIf> for Ast {
} }
} }
#[derive(Clone, Debug, PartialEq)]
pub struct ElifElseClause {
pub range: TextRange,
pub test: Option<Expr>,
pub body: Vec<Stmt>,
}
impl Node for ElifElseClause {
const NAME: &'static str = "ElifElse";
const FIELD_NAMES: &'static [&'static str] = &["test", "body"];
}
/// See also [With](https://docs.python.org/3/library/ast.html#ast.With) /// See also [With](https://docs.python.org/3/library/ast.html#ast.With)
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct StmtWith { pub struct StmtWith {

View File

@ -127,6 +127,11 @@ impl Ranged for crate::generic::StmtIf {
self.range self.range
} }
} }
impl Ranged for crate::generic::ElifElseClause {
fn range(&self) -> TextRange {
self.range
}
}
impl Ranged for crate::generic::StmtWith { impl Ranged for crate::generic::StmtWith {
fn range(&self) -> TextRange { fn range(&self) -> TextRange {
self.range self.range

View File

@ -760,25 +760,24 @@ ClassPattern: ast::Pattern = {
} }
IfStatement: ast::Stmt = { IfStatement: ast::Stmt = {
<location:@L> "if" <test:NamedExpressionTest> ":" <body:Suite> <s2:(<@L> "elif" <NamedExpressionTest> ":" <Suite>)*> <s3:("else" ":" <Suite>)?> => { <location:@L> "if" <test:NamedExpressionTest> ":" <body:Suite> <s2:(<@L> "elif" <NamedExpressionTest> ":" <Suite>)*> <s3:(<@L> "else" ":" <Suite>)?> => {
// Determine last else: let elif_else_clauses: Vec<_> = s2.into_iter().map(|(start, test, body)| ast::ElifElseClause {
let mut last = s3.unwrap_or_default(); range: (start..body.last().unwrap().end()).into(),
let end_location = last test: Some(test),
body,
}).chain(s3.into_iter().map(|(start, body)| ast::ElifElseClause {
range: (start..body.last().unwrap().end()).into(),
test: None,
body,
})).collect();
let end_location = elif_else_clauses
.last() .last()
.or_else(|| s2.last().and_then(|last| last.2.last())) .map(|last| last.end())
.or_else(|| body.last()) .unwrap_or_else(|| body.last().unwrap().end());
.unwrap()
.end();
// handle elif:
for i in s2.into_iter().rev() {
let x = ast::Stmt::If(
ast::StmtIf { test: Box::new(i.1), body: i.2, orelse: last, range: (i.0..end_location).into() }
);
last = vec![x];
}
ast::Stmt::If( ast::Stmt::If(
ast::StmtIf { test: Box::new(test), body, orelse: last, range: (location..end_location).into() } ast::StmtIf { test: Box::new(test), body, elif_else_clauses, range: (location..end_location).into() }
) )
}, },
}; };

40981
parser/src/python.rs generated

File diff suppressed because it is too large Load Diff

View File

@ -34,7 +34,7 @@ expression: parse_ast
}, },
), ),
], ],
orelse: [], elif_else_clauses: [],
}, },
), ),
] ]

View File

@ -627,7 +627,7 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
}, },
), ),
], ],
orelse: [], elif_else_clauses: [],
}, },
), ),
Match( Match(

View File

@ -31,11 +31,11 @@ expression: parse_ast
}, },
), ),
], ],
orelse: [ elif_else_clauses: [
If( ElifElseClause {
StmtIf { range: 9..19,
range: 9..28, test: Some(
test: Constant( Constant(
ExprConstant { ExprConstant {
range: 14..15, range: 14..15,
value: Int( value: Int(
@ -44,40 +44,44 @@ expression: parse_ast
kind: None, kind: None,
}, },
), ),
body: [ ),
Expr( body: [
StmtExpr { Expr(
range: 17..19, StmtExpr {
value: Constant( range: 17..19,
ExprConstant { value: Constant(
range: 17..19, ExprConstant {
value: Int( range: 17..19,
20, value: Int(
), 20,
kind: None, ),
}, kind: None,
), },
}, ),
), },
], ),
orelse: [ ],
Expr( },
StmtExpr { ElifElseClause {
range: 26..28, range: 20..28,
value: Constant( test: None,
ExprConstant { body: [
range: 26..28, Expr(
value: Int( StmtExpr {
30, range: 26..28,
), value: Constant(
kind: None, ExprConstant {
}, range: 26..28,
), value: Int(
}, 30,
), ),
], kind: None,
}, },
), ),
},
),
],
},
], ],
}, },
), ),

View File

@ -627,7 +627,7 @@ expression: "ast::Suite::parse(source, \"<test>\").unwrap()"
}, },
), ),
], ],
orelse: [], elif_else_clauses: [],
}, },
), ),
Assign( Assign(