From 8caa28f0f8c08b60584e3d7652de71160b1a734d Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Tue, 21 Feb 2023 12:00:33 +0900 Subject: [PATCH 1/2] Update Python.asdl from CPython 3.11.1 --- ast/Python.asdl | 1 + ast/src/ast_gen.rs | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/ast/Python.asdl b/ast/Python.asdl index 32fdc01..e9423a7 100644 --- a/ast/Python.asdl +++ b/ast/Python.asdl @@ -40,6 +40,7 @@ module Python | Raise(expr? exc, expr? cause) | Try(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody) + | TryStar(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody) | Assert(expr test, expr? msg) | Import(alias* names) diff --git a/ast/src/ast_gen.rs b/ast/src/ast_gen.rs index 32dd89c..c11fd87 100644 --- a/ast/src/ast_gen.rs +++ b/ast/src/ast_gen.rs @@ -139,6 +139,12 @@ pub enum StmtKind { orelse: Vec>, finalbody: Vec>, }, + TryStar { + body: Vec>, + handlers: Vec>, + orelse: Vec>, + finalbody: Vec>, + }, Assert { test: Box>, msg: Option>>, @@ -726,6 +732,17 @@ pub mod fold { orelse: Foldable::fold(orelse, folder)?, finalbody: Foldable::fold(finalbody, folder)?, }), + StmtKind::TryStar { + body, + handlers, + orelse, + finalbody, + } => Ok(StmtKind::TryStar { + body: Foldable::fold(body, folder)?, + handlers: Foldable::fold(handlers, folder)?, + orelse: Foldable::fold(orelse, folder)?, + finalbody: Foldable::fold(finalbody, folder)?, + }), StmtKind::Assert { test, msg } => Ok(StmtKind::Assert { test: Foldable::fold(test, folder)?, msg: Foldable::fold(msg, folder)?, From c7ed645cc6485b954fde70204e7b38479e4cae31 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Mon, 20 Feb 2023 13:40:19 -0500 Subject: [PATCH 2/2] Implement except* syntax --- parser/python.lalrpop | 49 + parser/src/parser.rs | 31 + ...rustpython_parser__parser__tests__try.snap | 487 ++++++++++ ...ython_parser__parser__tests__try_star.snap | 861 ++++++++++++++++++ 4 files changed, 1428 insertions(+) create mode 100644 parser/src/snapshots/rustpython_parser__parser__tests__try.snap create mode 100644 parser/src/snapshots/rustpython_parser__parser__tests__try_star.snap diff --git a/parser/python.lalrpop b/parser/python.lalrpop index 78b7136..d37f93e 100644 --- a/parser/python.lalrpop +++ b/parser/python.lalrpop @@ -451,6 +451,27 @@ TryStatement: ast::Stmt = { }, } }, + "try" ":" => { + let orelse = else_suite.map(|s| s.2).unwrap_or_default(); + let finalbody = finally.map(|s| s.2).unwrap_or_default(); + let end_location = finalbody + .last() + .or_else(|| orelse.last()) + .map(|last| last.end_location) + .or_else(|| handlers.last().map(|last| last.end_location)) + .unwrap(); + ast::Stmt { + custom: (), + location, + end_location, + node: ast::StmtKind::TryStar { + body, + handlers, + orelse, + finalbody, + }, + } + }, "try" ":" => { let handlers = vec![]; let orelse = vec![]; @@ -470,6 +491,34 @@ TryStatement: ast::Stmt = { }, }; +ExceptStarClause: ast::Excepthandler = { + "except" "*" > ":" => { + let end_location = body.last().unwrap().end_location.unwrap(); + ast::Excepthandler::new( + location, + end_location, + ast::ExcepthandlerKind::ExceptHandler { + type_: Some(Box::new(typ)), + name: None, + body, + }, + ) + }, + "except" "*" "as" Identifier)> ":" => { + let end_location = body.last().unwrap().end_location.unwrap(); + ast::Excepthandler::new( + location, + end_location, + ast::ExcepthandlerKind::ExceptHandler { + type_: Some(Box::new(x.0)), + name: Some(x.2), + body, + }, + ) + }, +}; + + ExceptClause: ast::Excepthandler = { "except" ?> ":" => { let end_location = body.last().unwrap().end_location.unwrap(); diff --git a/parser/src/parser.rs b/parser/src/parser.rs index 7f82802..cc3cb18 100644 --- a/parser/src/parser.rs +++ b/parser/src/parser.rs @@ -405,6 +405,37 @@ with (0 as a, 1 as b,): pass insta::assert_debug_snapshot!(parse_ast); } + #[test] + fn test_try() { + let parse_ast = parse_program( + r#"try: + raise ValueError(1) +except TypeError as e: + print(f'caught {type(e)}') +except OSError as e: + print(f'caught {type(e)}')"#, + "", + ) + .unwrap(); + insta::assert_debug_snapshot!(parse_ast); + } + + #[test] + fn test_try_star() { + let parse_ast = parse_program( + r#"try: + raise ExceptionGroup("eg", + [ValueError(1), TypeError(2), OSError(3), OSError(4)]) +except* TypeError as e: + print(f'caught {type(e)} with nested {e.exceptions}') +except* OSError as e: + print(f'caught {type(e)} with nested {e.exceptions}')"#, + "", + ) + .unwrap(); + insta::assert_debug_snapshot!(parse_ast); + } + #[test] fn test_dict_unpacking() { let parse_ast = parse_expression(r#"{"a": "b", **c, "d": "e"}"#, "").unwrap(); diff --git a/parser/src/snapshots/rustpython_parser__parser__tests__try.snap b/parser/src/snapshots/rustpython_parser__parser__tests__try.snap new file mode 100644 index 0000000..5b6037a --- /dev/null +++ b/parser/src/snapshots/rustpython_parser__parser__tests__try.snap @@ -0,0 +1,487 @@ +--- +source: compiler/parser/src/parser.rs +expression: parse_ast +--- +[ + Located { + location: Location { + row: 1, + column: 0, + }, + end_location: Some( + Location { + row: 6, + column: 30, + }, + ), + custom: (), + node: Try { + body: [ + Located { + location: Location { + row: 2, + column: 4, + }, + end_location: Some( + Location { + row: 2, + column: 23, + }, + ), + custom: (), + node: Raise { + exc: Some( + Located { + location: Location { + row: 2, + column: 10, + }, + end_location: Some( + Location { + row: 2, + column: 23, + }, + ), + custom: (), + node: Call { + func: Located { + location: Location { + row: 2, + column: 10, + }, + end_location: Some( + Location { + row: 2, + column: 20, + }, + ), + custom: (), + node: Name { + id: "ValueError", + ctx: Load, + }, + }, + args: [ + Located { + location: Location { + row: 2, + column: 21, + }, + end_location: Some( + Location { + row: 2, + column: 22, + }, + ), + custom: (), + node: Constant { + value: Int( + 1, + ), + kind: None, + }, + }, + ], + keywords: [], + }, + }, + ), + cause: None, + }, + }, + ], + handlers: [ + Located { + location: Location { + row: 3, + column: 0, + }, + end_location: Some( + Location { + row: 4, + column: 30, + }, + ), + custom: (), + node: ExceptHandler { + type_: Some( + Located { + location: Location { + row: 3, + column: 7, + }, + end_location: Some( + Location { + row: 3, + column: 16, + }, + ), + custom: (), + node: Name { + id: "TypeError", + ctx: Load, + }, + }, + ), + name: Some( + "e", + ), + body: [ + Located { + location: Location { + row: 4, + column: 4, + }, + end_location: Some( + Location { + row: 4, + column: 30, + }, + ), + custom: (), + node: Expr { + value: Located { + location: Location { + row: 4, + column: 4, + }, + end_location: Some( + Location { + row: 4, + column: 30, + }, + ), + custom: (), + node: Call { + func: Located { + location: Location { + row: 4, + column: 4, + }, + end_location: Some( + Location { + row: 4, + column: 9, + }, + ), + custom: (), + node: Name { + id: "print", + ctx: Load, + }, + }, + args: [ + Located { + location: Location { + row: 4, + column: 10, + }, + end_location: Some( + Location { + row: 4, + column: 29, + }, + ), + custom: (), + node: JoinedStr { + values: [ + Located { + location: Location { + row: 4, + column: 10, + }, + end_location: Some( + Location { + row: 4, + column: 29, + }, + ), + custom: (), + node: Constant { + value: Str( + "caught ", + ), + kind: None, + }, + }, + Located { + location: Location { + row: 4, + column: 10, + }, + end_location: Some( + Location { + row: 4, + column: 29, + }, + ), + custom: (), + node: FormattedValue { + value: Located { + location: Location { + row: 4, + column: 20, + }, + end_location: Some( + Location { + row: 4, + column: 27, + }, + ), + custom: (), + node: Call { + func: Located { + location: Location { + row: 4, + column: 20, + }, + end_location: Some( + Location { + row: 4, + column: 24, + }, + ), + custom: (), + node: Name { + id: "type", + ctx: Load, + }, + }, + args: [ + Located { + location: Location { + row: 4, + column: 25, + }, + end_location: Some( + Location { + row: 4, + column: 26, + }, + ), + custom: (), + node: Name { + id: "e", + ctx: Load, + }, + }, + ], + keywords: [], + }, + }, + conversion: 0, + format_spec: None, + }, + }, + ], + }, + }, + ], + keywords: [], + }, + }, + }, + }, + ], + }, + }, + Located { + location: Location { + row: 5, + column: 0, + }, + end_location: Some( + Location { + row: 6, + column: 30, + }, + ), + custom: (), + node: ExceptHandler { + type_: Some( + Located { + location: Location { + row: 5, + column: 7, + }, + end_location: Some( + Location { + row: 5, + column: 14, + }, + ), + custom: (), + node: Name { + id: "OSError", + ctx: Load, + }, + }, + ), + name: Some( + "e", + ), + body: [ + Located { + location: Location { + row: 6, + column: 4, + }, + end_location: Some( + Location { + row: 6, + column: 30, + }, + ), + custom: (), + node: Expr { + value: Located { + location: Location { + row: 6, + column: 4, + }, + end_location: Some( + Location { + row: 6, + column: 30, + }, + ), + custom: (), + node: Call { + func: Located { + location: Location { + row: 6, + column: 4, + }, + end_location: Some( + Location { + row: 6, + column: 9, + }, + ), + custom: (), + node: Name { + id: "print", + ctx: Load, + }, + }, + args: [ + Located { + location: Location { + row: 6, + column: 10, + }, + end_location: Some( + Location { + row: 6, + column: 29, + }, + ), + custom: (), + node: JoinedStr { + values: [ + Located { + location: Location { + row: 6, + column: 10, + }, + end_location: Some( + Location { + row: 6, + column: 29, + }, + ), + custom: (), + node: Constant { + value: Str( + "caught ", + ), + kind: None, + }, + }, + Located { + location: Location { + row: 6, + column: 10, + }, + end_location: Some( + Location { + row: 6, + column: 29, + }, + ), + custom: (), + node: FormattedValue { + value: Located { + location: Location { + row: 6, + column: 20, + }, + end_location: Some( + Location { + row: 6, + column: 27, + }, + ), + custom: (), + node: Call { + func: Located { + location: Location { + row: 6, + column: 20, + }, + end_location: Some( + Location { + row: 6, + column: 24, + }, + ), + custom: (), + node: Name { + id: "type", + ctx: Load, + }, + }, + args: [ + Located { + location: Location { + row: 6, + column: 25, + }, + end_location: Some( + Location { + row: 6, + column: 26, + }, + ), + custom: (), + node: Name { + id: "e", + ctx: Load, + }, + }, + ], + keywords: [], + }, + }, + conversion: 0, + format_spec: None, + }, + }, + ], + }, + }, + ], + keywords: [], + }, + }, + }, + }, + ], + }, + }, + ], + orelse: [], + finalbody: [], + }, + }, +] diff --git a/parser/src/snapshots/rustpython_parser__parser__tests__try_star.snap b/parser/src/snapshots/rustpython_parser__parser__tests__try_star.snap new file mode 100644 index 0000000..472f316 --- /dev/null +++ b/parser/src/snapshots/rustpython_parser__parser__tests__try_star.snap @@ -0,0 +1,861 @@ +--- +source: compiler/parser/src/parser.rs +expression: parse_ast +--- +[ + Located { + location: Location { + row: 1, + column: 0, + }, + end_location: Some( + Location { + row: 7, + column: 57, + }, + ), + custom: (), + node: TryStar { + body: [ + Located { + location: Location { + row: 2, + column: 4, + }, + end_location: Some( + Location { + row: 3, + column: 62, + }, + ), + custom: (), + node: Raise { + exc: Some( + Located { + location: Location { + row: 2, + column: 10, + }, + end_location: Some( + Location { + row: 3, + column: 62, + }, + ), + custom: (), + node: Call { + func: Located { + location: Location { + row: 2, + column: 10, + }, + end_location: Some( + Location { + row: 2, + column: 24, + }, + ), + custom: (), + node: Name { + id: "ExceptionGroup", + ctx: Load, + }, + }, + args: [ + Located { + location: Location { + row: 2, + column: 25, + }, + end_location: Some( + Location { + row: 2, + column: 29, + }, + ), + custom: (), + node: Constant { + value: Str( + "eg", + ), + kind: None, + }, + }, + Located { + location: Location { + row: 3, + column: 8, + }, + end_location: Some( + Location { + row: 3, + column: 61, + }, + ), + custom: (), + node: List { + elts: [ + Located { + location: Location { + row: 3, + column: 9, + }, + end_location: Some( + Location { + row: 3, + column: 22, + }, + ), + custom: (), + node: Call { + func: Located { + location: Location { + row: 3, + column: 9, + }, + end_location: Some( + Location { + row: 3, + column: 19, + }, + ), + custom: (), + node: Name { + id: "ValueError", + ctx: Load, + }, + }, + args: [ + Located { + location: Location { + row: 3, + column: 20, + }, + end_location: Some( + Location { + row: 3, + column: 21, + }, + ), + custom: (), + node: Constant { + value: Int( + 1, + ), + kind: None, + }, + }, + ], + keywords: [], + }, + }, + Located { + location: Location { + row: 3, + column: 24, + }, + end_location: Some( + Location { + row: 3, + column: 36, + }, + ), + custom: (), + node: Call { + func: Located { + location: Location { + row: 3, + column: 24, + }, + end_location: Some( + Location { + row: 3, + column: 33, + }, + ), + custom: (), + node: Name { + id: "TypeError", + ctx: Load, + }, + }, + args: [ + Located { + location: Location { + row: 3, + column: 34, + }, + end_location: Some( + Location { + row: 3, + column: 35, + }, + ), + custom: (), + node: Constant { + value: Int( + 2, + ), + kind: None, + }, + }, + ], + keywords: [], + }, + }, + Located { + location: Location { + row: 3, + column: 38, + }, + end_location: Some( + Location { + row: 3, + column: 48, + }, + ), + custom: (), + node: Call { + func: Located { + location: Location { + row: 3, + column: 38, + }, + end_location: Some( + Location { + row: 3, + column: 45, + }, + ), + custom: (), + node: Name { + id: "OSError", + ctx: Load, + }, + }, + args: [ + Located { + location: Location { + row: 3, + column: 46, + }, + end_location: Some( + Location { + row: 3, + column: 47, + }, + ), + custom: (), + node: Constant { + value: Int( + 3, + ), + kind: None, + }, + }, + ], + keywords: [], + }, + }, + Located { + location: Location { + row: 3, + column: 50, + }, + end_location: Some( + Location { + row: 3, + column: 60, + }, + ), + custom: (), + node: Call { + func: Located { + location: Location { + row: 3, + column: 50, + }, + end_location: Some( + Location { + row: 3, + column: 57, + }, + ), + custom: (), + node: Name { + id: "OSError", + ctx: Load, + }, + }, + args: [ + Located { + location: Location { + row: 3, + column: 58, + }, + end_location: Some( + Location { + row: 3, + column: 59, + }, + ), + custom: (), + node: Constant { + value: Int( + 4, + ), + kind: None, + }, + }, + ], + keywords: [], + }, + }, + ], + ctx: Load, + }, + }, + ], + keywords: [], + }, + }, + ), + cause: None, + }, + }, + ], + handlers: [ + Located { + location: Location { + row: 4, + column: 0, + }, + end_location: Some( + Location { + row: 5, + column: 57, + }, + ), + custom: (), + node: ExceptHandler { + type_: Some( + Located { + location: Location { + row: 4, + column: 8, + }, + end_location: Some( + Location { + row: 4, + column: 17, + }, + ), + custom: (), + node: Name { + id: "TypeError", + ctx: Load, + }, + }, + ), + name: Some( + "e", + ), + body: [ + Located { + location: Location { + row: 5, + column: 4, + }, + end_location: Some( + Location { + row: 5, + column: 57, + }, + ), + custom: (), + node: Expr { + value: Located { + location: Location { + row: 5, + column: 4, + }, + end_location: Some( + Location { + row: 5, + column: 57, + }, + ), + custom: (), + node: Call { + func: Located { + location: Location { + row: 5, + column: 4, + }, + end_location: Some( + Location { + row: 5, + column: 9, + }, + ), + custom: (), + node: Name { + id: "print", + ctx: Load, + }, + }, + args: [ + Located { + location: Location { + row: 5, + column: 10, + }, + end_location: Some( + Location { + row: 5, + column: 56, + }, + ), + custom: (), + node: JoinedStr { + values: [ + Located { + location: Location { + row: 5, + column: 10, + }, + end_location: Some( + Location { + row: 5, + column: 56, + }, + ), + custom: (), + node: Constant { + value: Str( + "caught ", + ), + kind: None, + }, + }, + Located { + location: Location { + row: 5, + column: 10, + }, + end_location: Some( + Location { + row: 5, + column: 56, + }, + ), + custom: (), + node: FormattedValue { + value: Located { + location: Location { + row: 5, + column: 20, + }, + end_location: Some( + Location { + row: 5, + column: 27, + }, + ), + custom: (), + node: Call { + func: Located { + location: Location { + row: 5, + column: 20, + }, + end_location: Some( + Location { + row: 5, + column: 24, + }, + ), + custom: (), + node: Name { + id: "type", + ctx: Load, + }, + }, + args: [ + Located { + location: Location { + row: 5, + column: 25, + }, + end_location: Some( + Location { + row: 5, + column: 26, + }, + ), + custom: (), + node: Name { + id: "e", + ctx: Load, + }, + }, + ], + keywords: [], + }, + }, + conversion: 0, + format_spec: None, + }, + }, + Located { + location: Location { + row: 5, + column: 10, + }, + end_location: Some( + Location { + row: 5, + column: 56, + }, + ), + custom: (), + node: Constant { + value: Str( + " with nested ", + ), + kind: None, + }, + }, + Located { + location: Location { + row: 5, + column: 10, + }, + end_location: Some( + Location { + row: 5, + column: 56, + }, + ), + custom: (), + node: FormattedValue { + value: Located { + location: Location { + row: 5, + column: 42, + }, + end_location: Some( + Location { + row: 5, + column: 54, + }, + ), + custom: (), + node: Attribute { + value: Located { + location: Location { + row: 5, + column: 42, + }, + end_location: Some( + Location { + row: 5, + column: 43, + }, + ), + custom: (), + node: Name { + id: "e", + ctx: Load, + }, + }, + attr: "exceptions", + ctx: Load, + }, + }, + conversion: 0, + format_spec: None, + }, + }, + ], + }, + }, + ], + keywords: [], + }, + }, + }, + }, + ], + }, + }, + Located { + location: Location { + row: 6, + column: 0, + }, + end_location: Some( + Location { + row: 7, + column: 57, + }, + ), + custom: (), + node: ExceptHandler { + type_: Some( + Located { + location: Location { + row: 6, + column: 8, + }, + end_location: Some( + Location { + row: 6, + column: 15, + }, + ), + custom: (), + node: Name { + id: "OSError", + ctx: Load, + }, + }, + ), + name: Some( + "e", + ), + body: [ + Located { + location: Location { + row: 7, + column: 4, + }, + end_location: Some( + Location { + row: 7, + column: 57, + }, + ), + custom: (), + node: Expr { + value: Located { + location: Location { + row: 7, + column: 4, + }, + end_location: Some( + Location { + row: 7, + column: 57, + }, + ), + custom: (), + node: Call { + func: Located { + location: Location { + row: 7, + column: 4, + }, + end_location: Some( + Location { + row: 7, + column: 9, + }, + ), + custom: (), + node: Name { + id: "print", + ctx: Load, + }, + }, + args: [ + Located { + location: Location { + row: 7, + column: 10, + }, + end_location: Some( + Location { + row: 7, + column: 56, + }, + ), + custom: (), + node: JoinedStr { + values: [ + Located { + location: Location { + row: 7, + column: 10, + }, + end_location: Some( + Location { + row: 7, + column: 56, + }, + ), + custom: (), + node: Constant { + value: Str( + "caught ", + ), + kind: None, + }, + }, + Located { + location: Location { + row: 7, + column: 10, + }, + end_location: Some( + Location { + row: 7, + column: 56, + }, + ), + custom: (), + node: FormattedValue { + value: Located { + location: Location { + row: 7, + column: 20, + }, + end_location: Some( + Location { + row: 7, + column: 27, + }, + ), + custom: (), + node: Call { + func: Located { + location: Location { + row: 7, + column: 20, + }, + end_location: Some( + Location { + row: 7, + column: 24, + }, + ), + custom: (), + node: Name { + id: "type", + ctx: Load, + }, + }, + args: [ + Located { + location: Location { + row: 7, + column: 25, + }, + end_location: Some( + Location { + row: 7, + column: 26, + }, + ), + custom: (), + node: Name { + id: "e", + ctx: Load, + }, + }, + ], + keywords: [], + }, + }, + conversion: 0, + format_spec: None, + }, + }, + Located { + location: Location { + row: 7, + column: 10, + }, + end_location: Some( + Location { + row: 7, + column: 56, + }, + ), + custom: (), + node: Constant { + value: Str( + " with nested ", + ), + kind: None, + }, + }, + Located { + location: Location { + row: 7, + column: 10, + }, + end_location: Some( + Location { + row: 7, + column: 56, + }, + ), + custom: (), + node: FormattedValue { + value: Located { + location: Location { + row: 7, + column: 42, + }, + end_location: Some( + Location { + row: 7, + column: 54, + }, + ), + custom: (), + node: Attribute { + value: Located { + location: Location { + row: 7, + column: 42, + }, + end_location: Some( + Location { + row: 7, + column: 43, + }, + ), + custom: (), + node: Name { + id: "e", + ctx: Load, + }, + }, + attr: "exceptions", + ctx: Load, + }, + }, + conversion: 0, + format_spec: None, + }, + }, + ], + }, + }, + ], + keywords: [], + }, + }, + }, + }, + ], + }, + }, + ], + orelse: [], + finalbody: [], + }, + }, +]