File: continuation_ext.cpp

package info (click to toggle)
falconpl 0.9.6.9-git20120606-2
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 46,176 kB
  • sloc: cpp: 181,389; ansic: 109,025; yacc: 2,310; xml: 1,218; sh: 403; objc: 245; makefile: 82; sql: 20
file content (214 lines) | stat: -rw-r--r-- 6,627 bytes parent folder | download | duplicates (2)
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) );
}

}
}