Strange (undocumented it seems) list comprehension context `{;` and other hidden gems in the parser, like infinite list generators

I think I figured it out. It’s for when you want to explicitly yield from the generator/comprehension

r = r { loop { {; yield(x*2), x <- (2..6)} } };
r.nextN(7);
// -> [ 4, 6, 8, 10, 12, 4, 6 ]

It gets more interesting perhaps that–like in a routine–you can yield more than once “in a row” in that first expression in the generator.

r = r { loop { {; yield(x*2); yield(x**3), x <- (2..6)} } };
r.nextN(12);
// -> [ 4, 8.0, 6, 27.0, 8, 64.0, 10, 125.0, 12, 216.0, 4, 8.0 ]

This became obvious after looking at “action” part of parser code for generators/comprehensions; the yield is removed too (in addition to the r preamble) for “action 2”, which is what {; puts on the generator stack.

nextqual	:
				{
					// innermost part
					int action = popls(&generatorStack);
					PyrParseNode* expr = (PyrParseNode*)popls(&generatorStack);

					switch (action)
					{
						case 1 :
						{
							PyrSlot slot;
							SetSymbol(&slot, getsym("yield"));
							PyrSlotNode* selectornode = newPyrSlotNode(&slot);

							$$ = (intptr_t)newPyrCallNode(selectornode, expr, 0, 0);
						} break;
						case 2 :
						{
							$$ = (intptr_t)expr;
						} break;
					}
				}
			| ',' qual
				{ $$ = $2; }
			;
2 Likes