.. _generators: ========= Generator ========= Generators allow you to declare a lambda that behaves like an iterator. For all intents and purposes, a generator is a lambda passed to an ``each`` or ``each_ref`` function. Generator syntax is similar to lambda syntax:: generator ::= `generator` < type > $ ( ) block Generator lambdas must have no arguments. It always returns boolean:: let gen <- generator() <| $() // gen is iterator for t in range(0,10) yield t return false // returning false stops iteration The result type of a ``generator`` expression is an iterator (see :ref:`Iterators `). Generators output iterator values via ``yield`` expressions. Similar to the return statement, move semantic ``yield <-`` is allowed:: return <- generator () <| $ () for w in src yield <- invoke(blk,w) // move invoke result return false Generators can output ref types. They can have a capture section:: unsafe // unsafe due to capture of src by reference var src = [[int 1;2;3;4]] var gen <- generator [[&src]] () <| $ () // capturing src by ref for w in src yield w // yield of int& return false for t in gen t ++ print("src = {src}\n") // will output [[2;3;4;5]] Generators can have loops and other control structures:: let gen <- generator() <| $() var t = 0 while t < 100 if t == 10 break yield t ++ return false let gen <- generator() <| $() for t in range(0,100) if t >= 10 continue yield t return false Generators can have a ``finally`` expression on its blocks, with the exception of the if-then-else blocks:: let gen <- generator() <| $() for t in range(0,9) yield t finally yield 9 return false ---------------------- implementation details ---------------------- In the following example:: var gen <- generator () <| $ () for x in range(0,10) if (x & 1)==0 yield x return false A lambda is generated with all captured variables:: struct _lambda_thismodule_8_8_1 __lambda : function<(__this:_lambda_thismodule_8_8_1;_yield_8:int&):bool const> = @@_::_lambda_thismodule_8_8_1`function __finalize : function<(__this:_lambda_thismodule_8_8_1? -const):void> = @@_::_lambda_thismodule_8_8_1`finalizer __yield : int _loop_at_8 : bool x : int // captured constant _pvar_0_at_8 : void? _source_0_at_8 : iterator A lambda function is generated:: [GENERATOR] def _lambda_thismodule_8_8_1`function ( var __this:_lambda_thismodule_8_8_1; var _yield_8:int& ) : bool const goto __this.__yield label 0: __this._loop_at_8 = true __this._source_0_at_8 <- __::builtin`each(range(0,10)) memzero(__this.x) __this._pvar_0_at_8 = reinterpret addr(__this.x) __this._loop_at_8 &&= _builtin_iterator_first(__this._source_0_at_8,__this._pvar_0_at_8,__context__) label 3: /*begin for at line 8*/ if !__this._loop_at_8 goto label 5 if !((__this.x & 1) == 0) goto label 2 _yield_8 = __this.x __this.__yield = 1 return /*yield*/ true label 1: /*yield at line 10*/ label 2: /*end if at line 9*/ label 4: /*continue for at line 8*/ __this._loop_at_8 &&= _builtin_iterator_next(__this._source_0_at_8,__this._pvar_0_at_8,__context__) goto label 3 label 5: /*end for at line 8*/ _builtin_iterator_close(__this._source_0_at_8,__this._pvar_0_at_8,__context__) return false Control flow statements are replaced with the ``label`` + ``goto`` equivalents. Generators always start with ``goto __this.yield``. This effectively produces a finite state machine, with the ``yield`` variable holding current state index. The ``yield`` expression is converted into a copy result and return value pair. A label is created to specify where to go to next time, after the ``yield``:: _yield_8 = __this.x // produce next iterator value __this.__yield = 1 // label to go to next (1) return /*yield*/ true // return true to indicate, that iterator produced a value label 1: /*yield at line 10*/ // next label marker (1) Iterator initialization is replaced with the creation of the lambda:: var gen:iterator <- each(new> [[_lambda_thismodule_8_8_1]])