Skip to content

Commit 8d879a5

Browse files
authored
Merge pull request RustPython#4327 from harupy/fix-end-location-body
Fix end location of compound statements
2 parents cbf2ec9 + 7a40d9c commit 8d879a5

File tree

6 files changed

+94
-67
lines changed

6 files changed

+94
-67
lines changed

Lib/test/test_ast.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1987,8 +1987,6 @@ def test_continued_str(self):
19871987
self._check_end_pos(assign, 2, 13)
19881988
self._check_end_pos(assign.value, 2, 13)
19891989

1990-
# TODO: RUSTPYTHON
1991-
@unittest.expectedFailure
19921990
def test_suites(self):
19931991
# We intentionally put these into the same string to check
19941992
# that empty lines are not part of the suite.

compiler/parser/python.lalrpop

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -360,16 +360,21 @@ CompoundStatement: ast::Stmt = {
360360
};
361361

362362
IfStatement: ast::Stmt = {
363-
<location:@L> "if" <test:NamedExpressionTest> ":" <body:Suite> <s2:(@L "elif" NamedExpressionTest ":" Suite @R)*> <s3:("else" ":" Suite)?> <end_location:@R> => {
363+
<location:@L> "if" <test:NamedExpressionTest> ":" <body:Suite> <s2:(@L "elif" NamedExpressionTest ":" Suite)*> <s3:("else" ":" Suite)?> => {
364364
// Determine last else:
365365
let mut last = s3.map(|s| s.2).unwrap_or_default();
366-
366+
let end_location = last
367+
.last()
368+
.or_else(|| s2.last().and_then(|last| last.4.last()))
369+
.or_else(|| body.last())
370+
.unwrap()
371+
.end_location;
367372
// handle elif:
368373
for i in s2.into_iter().rev() {
369374
let x = ast::Stmt {
370375
custom: (),
371376
location: i.0,
372-
end_location: Some(i.5),
377+
end_location: i.4.last().unwrap().end_location,
373378
node: ast::StmtKind::If { test: Box::new(i.2), body: i.4, orelse: last },
374379
};
375380
last = vec![x];
@@ -378,19 +383,24 @@ IfStatement: ast::Stmt = {
378383
ast::Stmt {
379384
custom: (),
380385
location,
381-
end_location: Some(end_location),
386+
end_location,
382387
node: ast::StmtKind::If { test: Box::new(test), body, orelse: last }
383388
}
384389
},
385390
};
386391

387392
WhileStatement: ast::Stmt = {
388-
<location:@L> "while" <test:NamedExpressionTest> ":" <body:Suite> <s2:("else" ":" Suite)?> <end_location:@R> => {
393+
<location:@L> "while" <test:NamedExpressionTest> ":" <body:Suite> <s2:("else" ":" Suite)?> => {
389394
let orelse = s2.map(|s| s.2).unwrap_or_default();
395+
let end_location = orelse
396+
.last()
397+
.or_else(|| body.last())
398+
.unwrap()
399+
.end_location;
390400
ast::Stmt {
391401
custom: (),
392402
location,
393-
end_location: Some(end_location),
403+
end_location,
394404
node: ast::StmtKind::While {
395405
test: Box::new(test),
396406
body,
@@ -401,8 +411,14 @@ WhileStatement: ast::Stmt = {
401411
};
402412

403413
ForStatement: ast::Stmt = {
404-
<location:@L> <is_async:"async"?> "for" <target:ExpressionList> "in" <iter:TestList> ":" <body:Suite> <s2:("else" ":" Suite)?> <end_location:@R> => {
414+
<location:@L> <is_async:"async"?> "for" <target:ExpressionList> "in" <iter:TestList> ":" <body:Suite> <s2:("else" ":" Suite)?> => {
405415
let orelse = s2.map(|s| s.2).unwrap_or_default();
416+
let end_location = orelse
417+
.last()
418+
.or_else(|| body.last())
419+
.unwrap()
420+
.end_location
421+
.unwrap();
406422
let target = Box::new(set_context(target, ast::ExprContext::Store));
407423
let iter = Box::new(iter);
408424
let type_comment = None;
@@ -419,10 +435,16 @@ TryStatement: ast::Stmt = {
419435
<location:@L> "try" ":" <body:Suite> <handlers:ExceptClause+> <else_suite:("else" ":" Suite)?> <finally:("finally" ":" Suite)?> <end_location:@R> => {
420436
let orelse = else_suite.map(|s| s.2).unwrap_or_default();
421437
let finalbody = finally.map(|s| s.2).unwrap_or_default();
438+
let end_location = finalbody
439+
.last()
440+
.map(|last| last.end_location)
441+
.or_else(|| orelse.last().map(|last| last.end_location))
442+
.or_else(|| handlers.last().map(|last| last.end_location))
443+
.unwrap();
422444
ast::Stmt {
423445
custom: (),
424446
location,
425-
end_location: Some(end_location),
447+
end_location,
426448
node: ast::StmtKind::Try {
427449
body,
428450
handlers,
@@ -431,14 +453,15 @@ TryStatement: ast::Stmt = {
431453
},
432454
}
433455
},
434-
<location:@L> "try" ":" <body:Suite> <finally:("finally" ":" Suite)> <end_location:@R> => {
456+
<location:@L> "try" ":" <body:Suite> <finally:("finally" ":" Suite)> => {
435457
let handlers = vec![];
436458
let orelse = vec![];
437459
let finalbody = finally.2;
460+
let end_location = finalbody.last().unwrap().end_location;
438461
ast::Stmt {
439462
custom: (),
440463
location,
441-
end_location: Some(end_location),
464+
end_location,
442465
node: ast::StmtKind::Try {
443466
body,
444467
handlers,
@@ -450,7 +473,8 @@ TryStatement: ast::Stmt = {
450473
};
451474

452475
ExceptClause: ast::Excepthandler = {
453-
<location:@L> "except" <typ:Test?> ":" <body:Suite> <end_location:@R> => {
476+
<location:@L> "except" <typ:Test?> ":" <body:Suite> => {
477+
let end_location = body.last().unwrap().end_location.unwrap();
454478
ast::Excepthandler::new(
455479
location,
456480
end_location,
@@ -461,7 +485,8 @@ ExceptClause: ast::Excepthandler = {
461485
},
462486
)
463487
},
464-
<location:@L> "except" <x:(Test "as" Identifier)> ":" <body:Suite> <end_location:@R> => {
488+
<location:@L> "except" <x:(Test "as" Identifier)> ":" <body:Suite> => {
489+
let end_location = body.last().unwrap().end_location.unwrap();
465490
ast::Excepthandler::new(
466491
location,
467492
end_location,
@@ -475,7 +500,8 @@ ExceptClause: ast::Excepthandler = {
475500
};
476501

477502
WithStatement: ast::Stmt = {
478-
<location:@L> <is_async:"async"?> "with" <items:WithItems> ":" <body:Suite> <end_location:@R> => {
503+
<location:@L> <is_async:"async"?> "with" <items:WithItems> ":" <body:Suite> => {
504+
let end_location = body.last().unwrap().end_location.unwrap();
479505
let type_comment = None;
480506
let node = if is_async.is_some() {
481507
ast::StmtKind::AsyncWith { items, body, type_comment }
@@ -514,9 +540,10 @@ WithItem: ast::Withitem = {
514540
};
515541

516542
FuncDef: ast::Stmt = {
517-
<decorator_list:Decorator*> <location:@L> <is_async:"async"?> "def" <name:Identifier> <args:Parameters> <r:("->" Test)?> ":" <body:Suite> <end_location:@R> => {
543+
<decorator_list:Decorator*> <location:@L> <is_async:"async"?> "def" <name:Identifier> <args:Parameters> <r:("->" Test)?> ":" <body:Suite> => {
518544
let args = Box::new(args);
519545
let returns = r.map(|x| Box::new(x.1));
546+
let end_location = body.last().unwrap().end_location.unwrap();
520547
let type_comment = None;
521548
let node = if is_async.is_some() {
522549
ast::StmtKind::AsyncFunctionDef { name, args, body, decorator_list, returns, type_comment }
@@ -668,15 +695,16 @@ KwargParameter<ArgType>: Option<Box<ast::Arg>> = {
668695
};
669696

670697
ClassDef: ast::Stmt = {
671-
<decorator_list:Decorator*> <location:@L> "class" <name:Identifier> <a:("(" ArgumentList ")")?> ":" <body:Suite> <end_location:@R> => {
698+
<decorator_list:Decorator*> <location:@L> "class" <name:Identifier> <a:("(" ArgumentList ")")?> ":" <body:Suite> => {
672699
let (bases, keywords) = match a {
673700
Some((_, arg, _)) => (arg.args, arg.keywords),
674701
None => (vec![], vec![]),
675702
};
703+
let end_location = body.last().unwrap().end_location;
676704
ast::Stmt {
677705
custom: (),
678706
location,
679-
end_location: Some(end_location),
707+
end_location,
680708
node: ast::StmtKind::ClassDef {
681709
name,
682710
bases,

compiler/parser/src/parser.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,8 @@ class Foo(A, B):
173173
def __init__(self):
174174
pass
175175
def method_with_default(self, arg='default'):
176-
pass";
176+
pass
177+
";
177178
insta::assert_debug_snapshot!(parse_program(source, "<test>").unwrap());
178179
}
179180

compiler/parser/src/snapshots/rustpython_parser__parser__tests__parse_class.snap

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compiler/parser/src/snapshots/rustpython_parser__parser__tests__parse_if_elif_else.snap

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)