Project

General

Profile

Scol reflexive functions » History » Version 1

ModularMix, 10/18/2011 03:48 PM

1 1 ModularMix
h1. Scol reflexive functions
2 1 ModularMix
3 1 ModularMix
The purpose of this document is to explain how a reflexive Scol function works, that is to say a callback function which can be called from Scol language.
4 1 ModularMix
In this tutorial, we will use the term *callback function* for the C++ function which be called when the event will occur, and the term *reflexive function* for the Scol function called by the callback function (so when the event occurs). In other terms, a reflexive function is comparable to a callback function which can be called in Scol language.
5 1 ModularMix
Our example will show how to call a reflexive function as soon as one the values of *Bloc* instance is updated.
6 1 ModularMix
7 1 ModularMix
h2. Creation of a callback for Bloc type
8 1 ModularMix
9 1 ModularMix
The constant *SCOL_BLOC_NEW_DATA_CB* correspond to the ID of the reflexive function in the data type *Bloc*. We can explain this principle as an ID of a slot in the data type *Bloc*, each slot corresponding to a specific reflexive function which can be defined (if a reflexive function is not defined in the slot of an instance of this object, the Scol Virtual machine will ignore this call).
10 1 ModularMix
11 1 ModularMix
The variable named *BLOC_NEW_DATA_CB* enables to store the ID of the Windows event which will trigger the call to the C++ callback.
12 1 ModularMix
<pre>
13 1 ModularMix
 //! New data event callback number
14 1 ModularMix
 int SCOL_BLOC_NEW_DATA_CB=0;
15 1 ModularMix
 
16 1 ModularMix
 //! New data event number
17 1 ModularMix
 int BLOC_NEW_DATA_CB;
18 1 ModularMix
</pre>
19 1 ModularMix
20 1 ModularMix
21 1 ModularMix
We will define our first callback function. Its purpose is to push the parameters used by the reflexive function (we'll define them later) into the Scol stack, an then call the reflexive function using a function from the Scol API named *OBJcallreflex*.
22 1 ModularMix
This function takes as parameters :
23 1 ModularMix
* 2 mandatory parameters for the reflexive function
24 1 ModularMix
** the object which has triggered the call (first parameter)
25 1 ModularMix
** a user parameter which can be of any type (second parameter, unused in our case)
26 1 ModularMix
* as many optional parameters as we need to use
27 1 ModularMix
28 1 ModularMix
Our custom parameters will respectively be the new integer value stored in Bloc object, et the new name of this object.
29 1 ModularMix
Consequently, we can already notice that the prototype of our Scol reflexive function will be : *fun [ObjBloc u0 I S] u1*.
30 1 ModularMix
31 1 ModularMix
The other important point concerns the function *OBJbeginreflex* from the Scol API. It can notice the Scol VM that we're preparing a call to a reflexive function.
32 1 ModularMix
Given that several of these functions can be defined in the VM for each data type, even for each object instance of this data type, it's used to specify the target of the call.
33 1 ModularMix
34 1 ModularMix
In our case, the reflexive function called which be the one from the slot *SCOL_BLOC_NEW_DATA_CB* of the object instance *bloc*, which Scol type is *OBJBLOCSCOL*.
35 1 ModularMix
<pre>
36 1 ModularMix
 /*!
37 1 ModularMix
 * \brief Callback function for calling scol reflex defined for BLOC_NEW_DATA_CB
38 1 ModularMix
 *
39 1 ModularMix
 * \param mmachine : scol machine structure
40 1 ModularMix
 * \param HWND : target window handle
41 1 ModularMix
 * \param unsigned msg : window message
42 1 ModularMix
 * \param UINT : callback param
43 1 ModularMix
 * \param LONG : callback param
44 1 ModularMix
 * \param int : return value
45 1 ModularMix
 */
46 1 ModularMix
 int getBlocNewData(mmachine m, HWND h, unsigned msg, UINT id, LONG param, int *ret)
47 1 ModularMix
 {
48 1 ModularMix
     int k = 0;
49 1 ModularMix
 
50 1 ModularMix
     // Cast id parameter to BlocObj type
51 1 ModularMix
     Bloc * bloc = (Bloc*) id;
52 1 ModularMix
 
53 1 ModularMix
     // Use : OBJbeginreflex(mmachine, type of object, ptr object, callback type)
54 1 ModularMix
     if (OBJbeginreflex(m, OBJBLOCSCOL, (int)bloc, SCOL_BLOC_NEW_DATA_CB))
55 1 ModularMix
     {
56 1 ModularMix
         MMechostr(MSKDEBUG,"Bloc not found\n");
57 1 ModularMix
         return 0;
58 1 ModularMix
     }
59 1 ModularMix
 
60 1 ModularMix
     // Retrieve current bloc value, and set it as 3rd parameter of the callback
61 1 ModularMix
     MMpush(m, ITOM(bloc->getValue()));
62 1 ModularMix
     // Retrieve current bloc name, and set it as 4th parameter of the callback
63 1 ModularMix
     Mpushstrbloc(m, bloc->getName());
64 1 ModularMix
 
65 1 ModularMix
     // Call reflex previously defined
66 1 ModularMix
     k = OBJcallreflex(m, 2 /*nb param after obj and u0*/);
67 1 ModularMix
     return k;
68 1 ModularMix
 }
69 1 ModularMix
</pre>
70 1 ModularMix
71 1 ModularMix
72 1 ModularMix
When the plugin is loading, we have to notify to the Scol VM that we want our reflexive function to be available on our object *Bloc*.
73 1 ModularMix
74 1 ModularMix
The call of the function enabling to register the new data type must be updated, because the first parameter of *OBJregister* corresponds to the number of callbacks which will be defined on the object. Then, we have to update this parameter to '1'.
75 1 ModularMix
76 1 ModularMix
In addition, we have to define a new event and associate to it the callback function. These 2 operations are done by calling the following functions from the Scol API :
77 1 ModularMix
* *OBJgetUserEvent* : returns an event ID which is available into the Scol VM,
78 1 ModularMix
* *OBJdefEvent* : associates this ID to a pointer on the callback function.
79 1 ModularMix
80 1 ModularMix
<pre>
81 1 ModularMix
 /*!
82 1 ModularMix
  * \brief Load the template functions
83 1 ModularMix
  *
84 1 ModularMix
  * \param mmachine : scol machine structure
85 1 ModularMix
  *
86 1 ModularMix
  * \return int : 0 if succes, error code otherwise
87 1 ModularMix
  **/
88 1 ModularMix
 int LoadTemplate(mmachine m)
89 1 ModularMix
 {
90 1 ModularMix
     int k;
91 1 ModularMix
 
92 1 ModularMix
     // Declare a new type of object ("OBJBLOCSCOL")
93 1 ModularMix
     OBJBLOCSCOL = OBJregister('''1 /*nb of callback*/''', 1/* deleted from parent */, destroyBlocObj, "OBJBLOCSCOL");
94 1 ModularMix
 
95 1 ModularMix
     // ----- Define callbacks
96 1 ModularMix
     // Get a new user event
97 1 ModularMix
     BLOC_NEW_DATA_CB = OBJgetUserEvent();
98 1 ModularMix
 
99 1 ModularMix
     // ----- Define callbacks for the call of the reflexive function.
100 1 ModularMix
     OBJdefEvent(BLOC_NEW_DATA_CB, (int (__cdecl *)(struct Mmachine *, int, unsigned int, int, int, int *))getBlocNewData);
101 1 ModularMix
 
102 1 ModularMix
     // Load package
103 1 ModularMix
     k = PKhardpak(m, "TemplateEngine", NbTplPKG, TplName, TplFunc, TplNArg, TplType);
104 1 ModularMix
     return k;
105 1 ModularMix
 }
106 1 ModularMix
</pre>
107 1 ModularMix
108 1 ModularMix
109 1 ModularMix
Then, we have to add the following code in the functions *_SETBlocValue* and *_SETBlocName* to trigger the new event.
110 1 ModularMix
<pre>
111 1 ModularMix
 // send the change data callback message to scol, use PostMessage instead if you need to poll the message
112 1 ModularMix
 SendMessage( HScol, BLOC_NEW_DATA_CB,(int)bloc,(LPARAM)NULL);
113 1 ModularMix
</pre>
114 1 ModularMix
115 1 ModularMix
116 1 ModularMix
h2. Registration of a new reflexive function
117 1 ModularMix
118 1 ModularMix
In order to be able to call a reflexive function of a *Bloc* object, we first have to associate it to this instance.
119 1 ModularMix
The next function enables to register in the slot *SCOL_BLOC_NEW_DATA_CB* an object *OBJBLOCSCOL* in the Scol function which prototype is *fun [ObjBloc u0 I S] u1*, which will be called when *OBJcallreflex* will be run.
120 1 ModularMix
<pre>
121 1 ModularMix
 /*! @ingroup group1
122 1 ModularMix
 * \brief _CBblocChangeValue : This function sets the reflexive function to be executed when Bloc value change event happens
123 1 ModularMix
 *
124 1 ModularMix
 * <b>Prototype:</b> fun [BlocObj fun [ObjBloc u0 I S] u1 u0] BlocObj
125 1 ModularMix
 *
126 1 ModularMix
 * \param BlocObj : Bloc Object whose value has changed
127 1 ModularMix
 * \param fun [ObjBloc u0 I S] u1 : The reflexive function to call when the event occurs.
128 1 ModularMix
 * - I : int value of the object
129 1 ModularMix
 * - S   : name value of the object
130 1 ModularMix
 * \param u0 : User parameter
131 1 ModularMix
 *
132 1 ModularMix
 * \return BlocObj : The Bloc object whose value has changed
133 1 ModularMix
 */
134 1 ModularMix
 int _CBblocChangeValue(mmachine m)
135 1 ModularMix
 {
136 1 ModularMix
     // Add a reflex
137 1 ModularMix
     MMechostr(MSKDEBUG, "_CBblocChangeValue ...adding reflex\n");
138 1 ModularMix
     return OBJaddreflex(m, OBJBLOCSCOL, SCOL_BLOC_NEW_DATA_CB);
139 1 ModularMix
 }
140 1 ModularMix
</pre>
141 1 ModularMix
142 1 ModularMix
143 1 ModularMix
To allow the Scol developer to associate a reflexive function, we have to bind the function *_CBblocChangeValue* using the same method described above in the document.
144 1 ModularMix
Consequently, we will modify the variables used by *PKhardpak*. The prototype for the Scol function named *_CBblocChangeValue* is : *_fun [ObjBloc fun [ObjBloc u0 I S] u1 u0] ObjBloc*.
145 1 ModularMix
Note that the prototype of the reflexive function is the second parameter.
146 1 ModularMix
<pre>
147 1 ModularMix
 //! Nb of Scol functions or types
148 1 ModularMix
 #define NbTplPKG	9
149 1 ModularMix
 
150 1 ModularMix
 /*!
151 1 ModularMix
  * Scol function names
152 1 ModularMix
  **/
153 1 ModularMix
 char* TplName[NbTplPKG] =
154 1 ModularMix
 {
155 1 ModularMix
     "_HelloWorld",
156 1 ModularMix
     "ObjBloc",
157 1 ModularMix
     "_CRbloc",
158 1 ModularMix
     "_DSbloc",
159 1 ModularMix
     "_GETblocValue",
160 1 ModularMix
     "_GETblocName",
161 1 ModularMix
     "_SETblocName",
162 1 ModularMix
     "_SETblocValue",
163 1 ModularMix
     "_CBblocChangeValue"
164 1 ModularMix
 };
165 1 ModularMix
 
166 1 ModularMix
 /*!
167 1 ModularMix
  * Pointers to C functions that manipulate the VM for each scol function previously defined
168 1 ModularMix
  **/
169 1 ModularMix
 int (*TplFunc[NbTplPKG])(mmachine m)=
170 1 ModularMix
 {
171 1 ModularMix
     _HelloWorld,
172 1 ModularMix
     NULL,
173 1 ModularMix
     _CRbloc,
174 1 ModularMix
     _DSbloc,
175 1 ModularMix
     _GETblocValue,
176 1 ModularMix
     _GETblocName,
177 1 ModularMix
     _SETblocName,
178 1 ModularMix
     _SETblocValue,
179 1 ModularMix
     _CBblocChangeValue
180 1 ModularMix
 };
181 1 ModularMix
 
182 1 ModularMix
 /*!
183 1 ModularMix
  * Nb of arguments of each scol function
184 1 ModularMix
  **/
185 1 ModularMix
 int TplNArg[NbTplPKG]=
186 1 ModularMix
 {
187 1 ModularMix
     0,
188 1 ModularMix
     TYPTYPE,
189 1 ModularMix
     1,
190 1 ModularMix
     1,
191 1 ModularMix
     1,
192 1 ModularMix
     1,
193 1 ModularMix
     2,
194 1 ModularMix
     2,
195 1 ModularMix
     3
196 1 ModularMix
 };
197 1 ModularMix
 
198 1 ModularMix
 /*!
199 1 ModularMix
  * Prototypes of the scol functions
200 1 ModularMix
  **/
201 1 ModularMix
 char* TplType[NbTplPKG]=
202 1 ModularMix
 {
203 1 ModularMix
     "fun [] I",                                        // _HelloWorld
204 1 ModularMix
     NULL,
205 1 ModularMix
     "fun [Chn] ObjBloc",				// _CRbloc
206 1 ModularMix
     "fun [ObjBloc] I",					// _DSbloc
207 1 ModularMix
     "fun [ObjBloc] I",                                 // _GETblocValue
208 1 ModularMix
     "fun [ObjBloc] S",                                 // _GETblocName
209 1 ModularMix
     "fun [ObjBloc S] I",                               // _SETblocName
210 1 ModularMix
     "fun [ObjBloc I] I",                               // _SETblocValue
211 1 ModularMix
     "fun [ObjBloc fun [ObjBloc u0 I S] u1 u0] ObjBloc" //_CBblocChangeValue
212 1 ModularMix
 };
213 1 ModularMix
</pre>
214 1 ModularMix
215 1 ModularMix
216 1 ModularMix
h2. Use of a reflexive function in Scol
217 1 ModularMix
218 1 ModularMix
The purpose of the reflexive function is to log into the Scol console the updated values for the object *ObjBloc*. Let's add the following function into *template.pkg* file :
219 1 ModularMix
<pre>
220 1 ModularMix
 /*! \brief Callback that show values of an ObjBloc whenever a property he owned is changed.
221 1 ModularMix
  *
222 1 ModularMix
  *  Values are save to console log.
223 1 ModularMix
  *
224 1 ModularMix
  *  <b>Prototype:</b> fun [u0 u1 u1 u2] I
225 1 ModularMix
  *
226 1 ModularMix
  *  \param u0: not used, but the bloc instance where a value has changed is passed.
227 1 ModularMix
  *  \param u1: not used
228 1 ModularMix
  *  \param I : bloc value
229 1 ModularMix
  *  \param S : bloc name
230 1 ModularMix
  *   
231 1 ModularMix
  *  \return I : 0
232 1 ModularMix
  **/
233 1 ModularMix
 fun blocHasChanged(blocInstance, userParam, newValue, newName)=
234 1 ModularMix
   // Log new values
235 1 ModularMix
   _fooS strcatn "Bloc name:  "::newName::"\nBloc value: "::(itoa newValue)::nil;
236 1 ModularMix
   0;;
237 1 ModularMix
</pre>
238 1 ModularMix
239 1 ModularMix
We'll add a second function into the file *template.pkg*.
240 1 ModularMix
It's important to understand how this function works. Once the instance *bloc* which type is *ObjBloc* is created, we allocate the reflexive function using *_CBblocChangeValue* value.
241 1 ModularMix
Notice the '@' character just before the parameter, it represents the reflexive function that we want to call when the event is triggered. The character indicates that it's actually a pointer to the function. The parameter named *u0* is not used, so in our case we will set its value to *nil*.
242 1 ModularMix
<pre>
243 1 ModularMix
 /*! \brief Sample main function that show how to use a callback.
244 1 ModularMix
  *
245 1 ModularMix
  *  <b>Prototype:</b> fun [S I] I
246 1 ModularMix
  *
247 1 ModularMix
  *  \param S : bloc name
248 1 ModularMix
  *  \param I : bloc value
249 1 ModularMix
  *   
250 1 ModularMix
  *  \return I : 0
251 1 ModularMix
  **/
252 1 ModularMix
 fun objBlocTestEvent(nameValue, integerValue)=
253 1 ModularMix
   let _CRbloc _channel -> blocInstance in 
254 1 ModularMix
   {
255 1 ModularMix
     // Setting callback
256 1 ModularMix
     _CBblocChangeValue blocInstance @blocHasChanged nil; 
257 1 ModularMix
 
258 1 ModularMix
     // Set ObjBloc properties values
259 1 ModularMix
     _SETblocName blocInstance nameValue;
260 1 ModularMix
     _SETblocValue blocInstance integerValue;
261 1 ModularMix
 
262 1 ModularMix
     // Manually destroying blocInstance
263 1 ModularMix
     _DSbloc blocInstance;
264 1 ModularMix
   };
265 1 ModularMix
   0;;
266 1 ModularMix
</pre>
267 1 ModularMix
268 1 ModularMix
269 1 ModularMix
Now, we'll create another file into our user partition : *testObjBlocEvent.scol*. This Scol program will load the package *template.pkg* that we have just updated, and run the function *objBlocTestEvent* using 2 parameters :
270 1 ModularMix
* the name of the bloc (string value),
271 1 ModularMix
* its value (integer).
272 1 ModularMix
273 1 ModularMix
<pre>
274 1 ModularMix
 _load "template.pkg"
275 1 ModularMix
 objBlocTestEvent "newBloc" ff
276 1 ModularMix
</pre>
277 1 ModularMix
278 1 ModularMix
Finally, we can run the program *testObjBlocEvent.scol*. The log file should contain the following lines :
279 1 ModularMix
<pre>
280 1 ModularMix
 Loading C:\Users\Jeff\Documents\Scol Voyager\Partition_LocalUsr\template.pkg ...
281 1 ModularMix
 typechecking
282 1 ModularMix
 fun main : fun [] I
283 1 ModularMix
 fun objBlocTest : fun [S I] I
284 1 ModularMix
 fun blocHasChanged : fun [u0 u1 I S] I
285 1 ModularMix
 fun objBlocTestEvent : fun [S I] I
286 1 ModularMix
 Generating bytecodes for 'main'...
287 1 ModularMix
 3 bytes generated (for a total of 375 bytes)
288 1 ModularMix
 Generating bytecodes for 'objBlocTest'...
289 1 ModularMix
 79 bytes generated (for a total of 454 bytes)
290 1 ModularMix
 Generating bytecodes for 'blocHasChanged'...
291 1 ModularMix
 51 bytes generated (for a total of 505 bytes)
292 1 ModularMix
 Generating bytecodes for 'objBlocTestEvent'...
293 1 ModularMix
 28 bytes generated (for a total of 533 bytes)
294 1 ModularMix
 Loading complete
295 1 ModularMix
 
296 1 ModularMix
 
297 1 ModularMix
 > exec: objBlocTestEvent "newBloc" ff
298 1 ModularMix
 
299 1 ModularMix
 _CRbloc
300 1 ModularMix
 _CRbloc ...initialization successful
301 1 ModularMix
 _CRbloc ...MMmalloc successful
302 1 ModularMix
 _CRbloc ...object creation successful
303 1 ModularMix
 ok
304 1 ModularMix
 _CBblocChangeValue ...adding reflex
305 1 ModularMix
 _SETblocName
306 1 ModularMix
 Bloc name:  newBloc
307 1 ModularMix
 Bloc value: 0
308 1 ModularMix
 ok
309 1 ModularMix
 _SETblocValue
310 1 ModularMix
 Bloc name:  newBloc
311 1 ModularMix
 Bloc value: 255
312 1 ModularMix
 ok
313 1 ModularMix
 _DSbloc
314 1 ModularMix
 Bloc object destroyed.
315 1 ModularMix
 ok
316 1 ModularMix
</pre>