1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
|
/*
FALCON - The Falcon Programming Language.
FILE: continuation.h
Continuation object.
-------------------------------------------------------------------
Author: Giancarlo Niccolai
Begin: Sat, 05 Dec 2009 17:04:27 +0100
-------------------------------------------------------------------
(C) Copyright 2009: the FALCON developers (see list in AUTHORS file)
See LICENSE file for licensing details.
*/
#include "core_module.h"
#include <falcon/continuation.h>
#include <falcon/mempool.h>
#include <falcon/globals.h>
/*#
@beginmodule core
*/
namespace Falcon {
namespace core {
//===========================================================
//
/*#
@class Continuation
@brief Intra-context suspension and resume control device.
@param callable A function or any callable item.
This instances of this class can be used to execute some
code that can be interrupted at any time and resumed later
from the point they were interrupted.
The function or other callable item set as the parameter
in the constructor of this class will receive a special
copy of the instance when this instance is called
as a @i functor. For example:
@code
function callable( cont )
> cont.toString()
end
c = Continuation( callable )
c() // will call callable( c )
@endcode
The special instance which is passed to the @b callable item is itself
a functor. Calling it causes immediate suspension and return to the
original frame where the continuation instance was first called. An optional
value can be returned to the caller by passing it as a parameter of the
continuation instance.
For example; the following code returns to the continuation first caller
if the random number matches a dividend of a "secret" number.
@code
c = Continuation( { c, secret =>
while true
r = random( 2, secret )
if secret % r == 0
c(r) // return "r" to our caller
end
end })
> "A random factor of 136: ", c(136)
@endcode
Other than returning immediately to the first caller of the continuation,
the current state of the called sequence is recorded and restored when
subsequent calls are performed. The following code returns the
position where a given element is found in an array:
@code
finder = Continuation( { c, elem, array =>
for n in [0: array.len()]
if array[n] == elem: c(n)
end })
pos = finder(10, [1,"a",10,5,10] )
while pos >= 0
> "Found a '10' at pos ", pos
pos = finder()
end
@endcode
Parameters passed in subsequent calls are returned inside the continuation function. For example,
the following code adds a parameter that is passed from the caller to the callee and then displayed:
@code
finder = Continuation( { c, elem, array =>
for n in [0: array.len()]
if array[n] == elem
> "Found ", c(n), " elements."
end
end })
pos = finder(10, [1,"a",10,5,10] )
count = 0
while pos >= 0
> "Found a '10' at pos ", pos
pos = finder(++count)
end
@endcode
@note It is not possible to use continuations in atomic calls; for/in
generators are called as atomically, so it's not possible to use
continuations as generators in for/in loops. Use standard \b while
loops instead.
Separate continuations calling the same functions have a completely different
state.
Also, the @a Continuation.reset method clears any previously existing state of a
continuation, so that it can be called anew again without the need to recreate it.
*/
FALCON_FUNC Continuation_init ( ::Falcon::VMachine *vm )
{
Item* i_cc = vm->param(0);
if ( i_cc == 0 || ! i_cc->isCallable() )
{
throw new ParamError( ErrorParam( e_inv_params ).
extra("C") );
}
ContinuationCarrier* cc = dyncast<ContinuationCarrier*>( vm->self().asObject() );
cc->cont( new Continuation(vm) );
cc->ccItem( *i_cc );
cc->getMethod("_suspend", cc->suspendItem() );
}
/*#
@method __call Continuation
@brief Enters into or exit from a continuation.
@param ... parameters passed to the callable stored in the instance, or to the return value.
@return The parameter passed to this method from inside the continuation.
For the complete usage pattern, see the @a Continuation class.
*/
FALCON_FUNC Continuation_call ( ::Falcon::VMachine *vm )
{
ContinuationCarrier* cc = dyncast<ContinuationCarrier*>( vm->self().asObject() );
// eventually, prepare the parameter to be returned in case of jump
Item iContPass;
if ( vm->paramCount() > 0 )
iContPass = *vm->param(0);
// call in passive phase calls the desired item.
if( cc->cont()->jump(iContPass) )
{
// the jump happened, we just must return.
return;
}
vm->pushParam( cc->suspendItem() );
for( int32 i = 0; i < vm->paramCount(); i++)
{
vm->pushParam( *vm->param(i) );
}
// otherwise, we have to call the item from here.
vm->callFrame( cc->ccItem(), 1 + vm->paramCount() );
}
/*#
@method reset Continuation
@brief Clears the continuation state.
Allows to recycle a continuation after it is terminated, or at any moment.
This must be called when the continuation has returned the control to its
caller: it has no effect otherwise.
*/
FALCON_FUNC Continuation_reset ( ::Falcon::VMachine *vm )
{
ContinuationCarrier* cc = dyncast<ContinuationCarrier*>( vm->self().asObject() );
cc->cont()->reset();
}
/*#
@method complete Continuation
@brief Indicates if the continuation has been completely executed or not.
@return True if the continuation code has exited through any mean except calling the continuation.
When the code inside the continuation calls the continuation, it means it has more
operations to perform; the calling code may then decide to call the continuation to let
it continue, or to reset it, or just to discard it.
*/
FALCON_FUNC Continuation_complete ( ::Falcon::VMachine *vm )
{
ContinuationCarrier* cc = dyncast<ContinuationCarrier*>( vm->self().asObject() );
cc->cont()->complete();
}
FALCON_FUNC Continuation__suspend ( ::Falcon::VMachine *vm )
{
ContinuationCarrier* susp = dyncast<ContinuationCarrier*>( vm->self().asObject() );
susp->cont()->suspend( vm->param(0) == 0 ? Item(): *vm->param(0) );
}
}
}
|