OK, so now a side issue. We already have an iterator: slice_range first last
so you can already write: for i in slice_range first last do .. done The problem here is that the implementation of a loop for an argument value D is var it = iterator D; label:>> var maybe_index = it (); match maybe_index with | Some ?index => i = index; body; goto label; | None => ; endmatch; So this does: apply function named "iterator" to D to get the iterator closure into variable it. Now apply the iterator to () to get a value. If it's Some thing then assign the thing to the loop index, execute the body, and branch back, otherwise just drop thru. The processes a stream of Some's until it gets a None. An option type in general requires a heap allocation. The iterator itself is a C++ object with an apply() method. The match has to do some munging too. The point? This isn't very efficient. It's fine for "scripting" but not so good for high performance numerical work. There are a couple of solutions. The first one is what we already have: use a low level loop. The second one is to get the parser to recognize the special case of an integer subrange (given literally of course) and do a low level loop. The third one is to INLINE the generator. Which leads to the question: HOW do you inline an generator? So what must happen is: when the generator gets to yield, the next instruction address has to be saved. Then we jump into the loop. For a simple loop we go to the beginning. At the end of the loop, we jump back to the saved address in the generator. When the generator does a return None, we just jump past the end of the loop. Now, since a generator MUST yield and return from the top level (you cannot do it inside a nested block because there are no nested blocks, only nested functions/procedures, so if you try this you're yielding from the wrong function). So the generator can easily be converted to a procedure, with the yield assigning to the loop control variable (directly, no "Some") and jumping into the loop. Since a loop can also call the same generator in its body, we either have to not optimise (if we can even detect this!) or change the semantics so a call to the generator saves the address in the loop body, and then the generator has to jump there (not the beginning). So in summary .. we need two "program counters" one for the generator and one for the loop body, and we jump back and forth between the two. Hardly surprising .. you did know they're coroutines right!! So here's the FUN thing. The instruction we need is Branch and Link. >From the PDP-11. given two registers PC1 and PC2 then: label: BL PC1, PC2 does this: PC2 = PC + 1 // next address PC = *PC1 // GOTO For example: BL iterator, body will jump to the iterator (last location) and save the next instruction position in the body in body. The iterator then does BL body, iterator to swap back. I believe this will work for any number of coroutines. Note these are NOT fibres: the control exchange is always to a KNOWN target. There's no data exchange, hence no "read/write" direction, and no non-determinism. -- john skaller skal...@users.sourceforge.net http://felix-lang.org ------------------------------------------------------------------------------ WatchGuard Dimension instantly turns raw network data into actionable security intelligence. It gives you real-time visual feedback on key security issues and trends. Skip the complicated setup - simply import a virtual appliance and go from zero to informed in seconds. http://pubads.g.doubleclick.net/gampad/clk?id=123612991&iu=/4140/ostg.clktrk _______________________________________________ Felix-language mailing list Felix-language@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/felix-language