Skip to content

Commit bc5b8b9

Browse files
Fix: Support generator expressions as function arguments.
1 parent 7f587d5 commit bc5b8b9

3 files changed

Lines changed: 34 additions & 2 deletions

File tree

compiler/src/modules/parser/literals.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,13 +297,29 @@ impl<'src, I: Iterator<Item = Token>> Parser<'src, I> {
297297
let i = self.chunk.push_const(Value::Str(self.lexeme(&t).to_string()));
298298
self.chunk.emit(OpCode::LoadConst, i);
299299
self.expr();
300-
kwargs += 1; // +1 in argc below -> 2 slots per kwarg matches key+value on stack
300+
kwargs += 1;
301301
} else {
302+
// Support genexpr after name arg (expr for ...)
303+
let elem_start = self.chunk.instructions.len();
302304
self.name(t);
303305
self.infix_bp(0);
306+
if matches!(self.peek(), Some(TokenType::For)) {
307+
let versions_before = self.ssa_versions.clone();
308+
let elem_ins: Vec<Instruction> = self.chunk.instructions.drain(elem_start..).collect();
309+
self.chunk.emit(OpCode::BuildList, 0);
310+
self.comprehension_loop(&[elem_ins], OpCode::ListAppend, &versions_before);
311+
}
304312
}
305313
} else {
314+
// Support genexpr in arg position (expr for ...)
315+
let elem_start = self.chunk.instructions.len();
306316
self.expr();
317+
if matches!(self.peek(), Some(TokenType::For)) {
318+
let versions_before = self.ssa_versions.clone();
319+
let elem_ins: Vec<Instruction> = self.chunk.instructions.drain(elem_start..).collect();
320+
self.chunk.emit(OpCode::BuildList, 0);
321+
self.comprehension_loop(&[elem_ins], OpCode::ListAppend, &versions_before);
322+
}
307323
}
308324
argc += 1;
309325
if matches!(self.peek(), Some(TokenType::Comma)) {

compiler/tests/cases/parser_cases.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1646,5 +1646,12 @@
16461646
"names": ["x_1"],
16471647
"instructions": [["LoadConst", 0], ["BuildList", 1], ["StoreName", 0], ["ReturnValue", 0]],
16481648
"annotations": {"x": "tuple"}
1649+
},
1650+
{
1651+
"src": "sum(i for i in range(3))",
1652+
"constants": ["3"],
1653+
"names": ["i_0", "i_1"],
1654+
"instructions": [["BuildList",0], ["LoadConst",0], ["CallRange",1], ["GetIter",0], ["ForIter",9], ["StoreName",1], ["LoadName",1], ["ListAppend",0], ["Jump",4], ["CallSum",1], ["PopTop",0], ["ReturnValue",0]],
1655+
"annotations": {}
16491656
}
16501657
]

compiler/tests/cases/vm_cases.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,5 +232,14 @@
232232
{"src": "pairs = [(1, 'a'), (2, 'b'), (3, 'c')]\nprint({k: v for k, v in pairs})", "output": ["{1: 'a', 2: 'b', 3: 'c'}"], "result": "None"},
233233
{"src": "print(sum((x for x in range(5))))", "output": ["10"], "result": "None"},
234234
{"src": "print([x for x in [1, 2, 3, 4, 5] if x > 2])", "output": ["[3, 4, 5]"], "result": "None"},
235-
{"src": "matrix = [[1, 2], [3, 4], [5, 6]]\nprint([row[0] for row in matrix])", "output": ["[1, 3, 5]"], "result": "None"}
235+
{"src": "matrix = [[1, 2], [3, 4], [5, 6]]\nprint([row[0] for row in matrix])", "output": ["[1, 3, 5]"], "result": "None"},
236+
{"src": "x = [1,2,3]\ny = [4,5,6]\nprint(sum(xi*yi for xi,yi in zip(x,y)))", "output": ["32"], "result": "None"},
237+
{"src": "print(sum(i for i in range(5)))", "output": ["10"], "result": "None"},
238+
{"src": "print(sum(i*i for i in range(4)))", "output": ["14"], "result": "None"},
239+
{"src": "print(list(x*2 for x in range(3)))", "output": ["[0, 2, 4]"], "result": "None"},
240+
{"src": "print(max(i for i in [3,1,4,1,5]))", "output": ["5"], "result": "None"},
241+
{"src": "print(min(i for i in [3,1,4,1,5]))", "output": ["1"], "result": "None"},
242+
{"src": "print(sum(x for x in range(10) if x % 2 == 0))", "output": ["20"], "result": "None"},
243+
{"src": "print(sum(i*j for i in range(3) for j in range(3)))", "output": ["9"], "result": "None"},
244+
{"src": "print(sum(x+y for x,y in zip([1,2],[3,4])))", "output": ["10"], "result": "None"}
236245
]

0 commit comments

Comments
 (0)