diff --git a/.cspell.json b/.cspell.json index 268e458139..090b581c1a 100644 --- a/.cspell.json +++ b/.cspell.json @@ -30,6 +30,7 @@ "bindgen", "cstring", "chrono", + "insta", "peekable", "lalrpop", "memmap", diff --git a/compiler/parser/python.lalrpop b/compiler/parser/python.lalrpop index 719cef464b..78b7136186 100644 --- a/compiler/parser/python.lalrpop +++ b/compiler/parser/python.lalrpop @@ -1274,11 +1274,11 @@ ArgumentList: ArgumentList = { }; FunctionArgument: (Option<(ast::Location, ast::Location, Option)>, ast::Expr) = { - => { + => { let expr = match c { Some(c) => ast::Expr { - location: e.location, - end_location: e.end_location, + location, + end_location: Some(end_location), custom: (), node: ast::ExprKind::GeneratorExp { elt: Box::new(e), diff --git a/compiler/parser/src/parser.rs b/compiler/parser/src/parser.rs index 8abbcacf71..38b065a581 100644 --- a/compiler/parser/src/parser.rs +++ b/compiler/parser/src/parser.rs @@ -310,6 +310,19 @@ with (0 as a, 1 as b,): pass } } + #[test] + fn test_generator_expression_argument() { + let source = r#"' '.join( + sql + for sql in ( + "LIMIT %d" % limit if limit else None, + ("OFFSET %d" % offset) if offset else None, + ) +)"#; + let parse_ast = parse_expression(source, "").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/compiler/parser/src/snapshots/rustpython_parser__parser__tests__generator_expression_argument.snap b/compiler/parser/src/snapshots/rustpython_parser__parser__tests__generator_expression_argument.snap new file mode 100644 index 0000000000..863ece4606 --- /dev/null +++ b/compiler/parser/src/snapshots/rustpython_parser__parser__tests__generator_expression_argument.snap @@ -0,0 +1,333 @@ +--- +source: compiler/parser/src/parser.rs +expression: parse_ast +--- +Located { + location: Location { + row: 1, + column: 0, + }, + end_location: Some( + Location { + row: 7, + column: 1, + }, + ), + custom: (), + node: Call { + func: Located { + location: Location { + row: 1, + column: 0, + }, + end_location: Some( + Location { + row: 1, + column: 8, + }, + ), + custom: (), + node: Attribute { + value: Located { + location: Location { + row: 1, + column: 0, + }, + end_location: Some( + Location { + row: 1, + column: 3, + }, + ), + custom: (), + node: Constant { + value: Str( + " ", + ), + kind: None, + }, + }, + attr: "join", + ctx: Load, + }, + }, + args: [ + Located { + location: Location { + row: 2, + column: 4, + }, + end_location: Some( + Location { + row: 6, + column: 5, + }, + ), + custom: (), + node: GeneratorExp { + elt: Located { + location: Location { + row: 2, + column: 4, + }, + end_location: Some( + Location { + row: 2, + column: 7, + }, + ), + custom: (), + node: Name { + id: "sql", + ctx: Load, + }, + }, + generators: [ + Comprehension { + target: Located { + location: Location { + row: 3, + column: 8, + }, + end_location: Some( + Location { + row: 3, + column: 11, + }, + ), + custom: (), + node: Name { + id: "sql", + ctx: Store, + }, + }, + iter: Located { + location: Location { + row: 3, + column: 15, + }, + end_location: Some( + Location { + row: 6, + column: 5, + }, + ), + custom: (), + node: Tuple { + elts: [ + Located { + location: Location { + row: 4, + column: 8, + }, + end_location: Some( + Location { + row: 4, + column: 45, + }, + ), + custom: (), + node: IfExp { + test: Located { + location: Location { + row: 4, + column: 30, + }, + end_location: Some( + Location { + row: 4, + column: 35, + }, + ), + custom: (), + node: Name { + id: "limit", + ctx: Load, + }, + }, + body: Located { + location: Location { + row: 4, + column: 8, + }, + end_location: Some( + Location { + row: 4, + column: 26, + }, + ), + custom: (), + node: BinOp { + left: Located { + location: Location { + row: 4, + column: 8, + }, + end_location: Some( + Location { + row: 4, + column: 18, + }, + ), + custom: (), + node: Constant { + value: Str( + "LIMIT %d", + ), + kind: None, + }, + }, + op: Mod, + right: Located { + location: Location { + row: 4, + column: 21, + }, + end_location: Some( + Location { + row: 4, + column: 26, + }, + ), + custom: (), + node: Name { + id: "limit", + ctx: Load, + }, + }, + }, + }, + orelse: Located { + location: Location { + row: 4, + column: 41, + }, + end_location: Some( + Location { + row: 4, + column: 45, + }, + ), + custom: (), + node: Constant { + value: None, + kind: None, + }, + }, + }, + }, + Located { + location: Location { + row: 5, + column: 8, + }, + end_location: Some( + Location { + row: 5, + column: 50, + }, + ), + custom: (), + node: IfExp { + test: Located { + location: Location { + row: 5, + column: 34, + }, + end_location: Some( + Location { + row: 5, + column: 40, + }, + ), + custom: (), + node: Name { + id: "offset", + ctx: Load, + }, + }, + body: Located { + location: Location { + row: 5, + column: 9, + }, + end_location: Some( + Location { + row: 5, + column: 29, + }, + ), + custom: (), + node: BinOp { + left: Located { + location: Location { + row: 5, + column: 9, + }, + end_location: Some( + Location { + row: 5, + column: 20, + }, + ), + custom: (), + node: Constant { + value: Str( + "OFFSET %d", + ), + kind: None, + }, + }, + op: Mod, + right: Located { + location: Location { + row: 5, + column: 23, + }, + end_location: Some( + Location { + row: 5, + column: 29, + }, + ), + custom: (), + node: Name { + id: "offset", + ctx: Load, + }, + }, + }, + }, + orelse: Located { + location: Location { + row: 5, + column: 46, + }, + end_location: Some( + Location { + row: 5, + column: 50, + }, + ), + custom: (), + node: Constant { + value: None, + kind: None, + }, + }, + }, + }, + ], + ctx: Load, + }, + }, + ifs: [], + is_async: 0, + }, + ], + }, + }, + ], + keywords: [], + }, +}