-
Notifications
You must be signed in to change notification settings - Fork 0
/
SugarCubesJS_doc.html
470 lines (459 loc) · 17.6 KB
/
SugarCubesJS_doc.html
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
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Tentative de doc SugarCubes JS</title>
<script type="text/javascript" src="SugarCubes.js">
</script>
<style>
pre, code{
font-size:1.3em;
}
span.keyword{
font-weight:bold;
color:purple;
}
</style>
</head>
<body>
<script type="text/javascript">
var JFS = {
m: SC.machine(30,{
init:SC.pause(SC.forever)
})
, sensors:{}
, events:{}
} ;
</script>
<h1>SugarCubes JS</h1>
<section id="scjs_doc_intro">
**SugarCubesJS** is a Javascript implementation of the Reactive Programming Framework SugarCubes v5 originally designed on top of Java.
It uses Frederic Boussinot's synchronous/reactive paradigm proposed in the early 90's by Frédéric BOUSSINOT[Bo1] and allows one to write reactive parallel/concurrent programs on top of Javascript.
</section>
<h4>Tentative de description des instructions réactives...</h4>
<p>Un programme SugarCubesJS est un une structure arborescente dont les nœuds sont des instructions réactives. Une instruction réactive est implantée par un objet par un objet JavaScript. Pour chaque type d'instruction, un constructeur permet de créer un objet implantant cette instruction :</p>
Par exemple pour la séquence, un constructeur <code>SC_Seq()</code> permet de construire des objets séquences.<br>
Le constructeur permet de créer une séquence à partir d'un tableau d'instructions passé en paramètre au constructeur. Ainsi :
<pre><span class="keyword">new</span> SC_Seq([<em>i1</em>, <em>i2</em>, <em>i3</em>])</pre>
permettrait de créer une séquence des instructions i1 puis i2 puis i3.
<pre>
|
-------
| Seq |
-------
/ | \
------ ------ ------
| i1 | | i2 | | i3 |
------ ------ ------
--------------------->
sens de parcours de l'arbre.
</pre>
<p>
Mais en SugarCubes on ne manipule pas directement les constructeurs. On utilise l'objet global <code>SC</code> dont les méthodes associées font appel aux différents constructeurs. Cela permet d'isoler la construction d'un programme, de la façon dont sont implantées les instructions.
</p>
Ainsi pour la séquence, on utilisera <code>SC.seq(<em>i1</em>, <em>i2</em>, <em>i3</em>)</code> au lieu du constructeur.<br>
Remarquons au passage que dans cette notation, on n'explicite plus le tableau d'instructions, ce qui rend un peu moins lourd l'écriture d'un programme.
<p>
A chaque constructeur d'instruction on associe un prototype contenant quelques méthodes importantes pour exécuter le programme. Ceci constitue en quelques sorte une interface de manipulation des instructions par la machine d'exécution :
<!--
s/\(\%V.*\%V.\)/<code>\1<\/code>
-->
<ul>
<li> <code>activate()</code> : activation d'une instruction durant l'instant
<li> <code>eoi()</code> : activation d'une instruction à la toute fin de l'instant
<li> <code>reset()</code> : réinitialisation de l'état d'une instruction.
<li> <code>wackup()</code> : réveil d'une instruction en attente sur un ou plusieurs événements quand l'un de ces événements est émis.
<li> <code>awake()</code> : propagation de l'information de réveil dans l'AST depuis la feuille jusqu'à la racine (précurseur)
<li> <code>bindTo()</code> : copie d'un programme et optimisation en vu de son exécution (une machine d'exécution n'exécute que des copies d'un programme qu'on lui soumet par <code>addProgram()</code> jamais le programme lui même).
<li> <code>toString()</code> : retourne une chaine de caractère représentant le programme dans un langage à la ReactiveScript.
</ul>
D'autres méthodes accessoires sont aussi présentes pour gérer l'enregistrement ou le desenregistrement des instruction sur les événements, la production des valeurs associées aux événements, etc.
<h3>La méthode <code>activate()</code></h3>
La méthode la plus importante est la méthode <code>activate()</code> qui implante une micro étape d'exécution d'une instruction.
<p>
À chaque instant, la machine d'exécution réactive appelle la méthode <code>activate()</code> sur la racine du programme. Cette méthode va récursivement s'appeler et parcourir l'aborescnece des instructions exécutables et faire évoluer l'état de ces instructions.<p>
Lorsque la transition d'état d'un instruction est faite, la méthode <code>activate()</code> retourne un statut d'exécution parmi les valeurs suivantes :
<ul>
<li><code><strong><em>SUSP</em></strong></code> : «à activer dans l'instant courant»
<li><code><strong><em>WEOI</em></strong></code> : «à activer si l'événement attendu est là ou à la fin de l'instant»
<li><code><strong><em>OEOI</em></strong></code> : «à activer uniquement à la fin de l'instant»
<li><code><strong><em>STOP</em></strong></code> : «à activer à l'instant suivant»
<li><code><strong><em>WAIT</em></strong></code> : «à activer si seulement un événement attendu est présent»
<li><code><strong><em>HALT</em></strong></code> : «ne plus activer mais ne termine pas»
<li><code><strong><em>TERM</em></strong></code> : «ne plus activer est complètement terminé»
</ul>
<h5><strong><em>SUSP</em></strong> :</h5> Ce statut signifie : «il est impératif de réactiver cette instruction avant que l'instant courant ne termine car elle n'a pas terminé son évolution pour l'instant courant mais a juste suspendu momentanément son exécution afin de permettre à d'autres instructions de progresser».<br>
<strong><em>SUSP</em></strong> indique que l'instruction peut progresser dans son exécution au cours de l'instant.
<p>
Par exemple, imaginons le programme suivant :
<pre>
SC.par( SC.await(&e), SC.generate(&e))
</pre>
<p>
il va nous donner l'AST suivant :
</p>
<div style="height:200px;line-height:200px">
<pre id="animation1" style="float:left;vertical-align:middle; line-height:normal">
|
-------
| Par |
-------
/ \
--------- ------------
| Await | | Generate |
--------- ------------
</pre>
<section style="display:inline-block;vertical-align:middle; line-height:normal">
<em><- Click the graph to animate</em><br>
<code>o</code> symbolise l'appel de la méthode <code>activate()</code> sur une instruction.<br>
<code>△</code> symbolise l'appel de la méthode <code>wakeup()</code> sur une instruction, lorsqu"un événement attendu par l'instruction est généré.<br>
<code>x</code> symbolise l'appel de la méthode <code>awake()</code> sur une instruction. (précurseur remontant l'arbre depuis une feuille nouvellement débloquée jusqu'à la racine).<br>
</section>
</div>
<br style="clear:both">
<script>
var vues = [
" |\n\
\n\
-------\n\
| Par | \n\
-------\n\
/ \\\n\
\n\
--------- ------------\n\
| Await | | Generate |\n\
--------- ------------\n\
"
,
" \n\
\n\
\n\
\n\
\n\
DÉBUT !!! \n\
\n\
\n\
\n\
\n\
"
,
" |\n\
\n\
-------\n\
<strong><em>SUSP</em></strong> | Par | <strong><em>SUSP</em></strong>\n\
-------\n\
/ \\\n\
\n\
--------- ------------\n\
| Await | | Generate |\n\
--------- ------------\n\
"
,
" |\n\
o\n\
-------\n\
<strong><em>SUSP</em></strong> | Par | <strong><em>SUSP</em></strong>\n\
-------\n\
/ \\\n\
\n\
--------- ------------\n\
| Await | | Generate |\n\
--------- ------------\n\
"
,
" |\n\
o\n\
-------\n\
<strong><em>SUSP</em></strong> | Par | <strong><em>SUSP</em></strong>\n\
-------\n\
/ \\\n\
o\n\
--------- ------------\n\
| Await | | Generate |\n\
--------- ------------\n\
"
,
" |\n\
o\n\
-------\n\
<strong><em>SUSP</em></strong> | Par | <strong><em>SUSP</em></strong>\n\
-------\n\
/ \\\n\
o (<strong><em>WAIT</em></strong>)\n\
--------- ------------\n\
| Await | | Generate |\n\
--------- ------------\n\
"
,
" |\n\
o\n\
-------\n\
<strong><em>WAIT</em></strong> | Par | <strong><em>SUSP</em></strong>\n\
-------\n\
/ \\\n\
\n\
--------- ------------\n\
| Await | | Generate |\n\
--------- ------------\n\
"
,
" |\n\
o\n\
-------\n\
<strong><em>WAIT</em></strong> | Par | <strong><em>SUSP</em></strong>\n\
-------\n\
/ \\\n\
o\n\
--------- ------------\n\
| Await | | Generate |\n\
--------- ------------\n\
"
,
" |\n\
o\n\
-------\n\
<strong><em>WAIT</em></strong> | Par | <strong><em>SUSP</em></strong>\n\
-------\n\
/ \\\n\
o\n\
--------- ------------\n\
| Await | | Generate |\n\
--------- ------------\n\
△_____________|"
,
" |\n\
o\n\
-------\n\
<strong><em>WAIT</em></strong> | Par | <strong><em>SUSP</em></strong>\n\
-------\n\
/ \\\n\
x o\n\
--------- ------------\n\
| Await | | Generate |\n\
--------- ------------\n\
△_____________|"
,
" |\n\
o\n\
-------\n\
<strong><em>SUSP</em></strong> | Par | <strong><em>SUSP</em></strong>\n\
-------\n\
/ \\\n\
x o\n\
--------- ------------\n\
| Await | | Generate |\n\
--------- ------------\n\
△_____________|"
,
" |\n\
o\n\
-------\n\
<strong><em>SUSP</em></strong> | Par | <strong><em>SUSP</em></strong>\n\
-------\n\
/ \\\n\
o\n\
--------- ------------\n\
| Await | | Generate |\n\
--------- ------------\n\
△_____________|"
,
" |\n\
o\n\
-------\n\
<strong><em>SUSP</em></strong> | Par | <strong><em>SUSP</em></strong>\n\
-------\n\
/ \\\n\
o\n\
--------- ------------\n\
| Await | | Generate |\n\
--------- ------------\n\
"
,
" |\n\
o\n\
-------\n\
<strong><em>SUSP</em></strong> | Par | <strong><em>SUSP</em></strong>\n\
-------\n\
/ \\\n\
o (<strong><em>TERM</em></strong>)\n\
--------- ------------\n\
| Await | | Generate |\n\
--------- ------------\n\
"
,
" |\n\
o\n\
-------\n\
<strong><em>SUSP</em></strong> | Par | <strong><em>TERM</em></strong>\n\
-------\n\
/ \\\n\
\n\
--------- ------------\n\
| Await | | Generate |\n\
--------- ------------\n\
"
,
" |\n\
o (<strong><em>SUSP</em></strong>)\n\
-------\n\
<strong><em>SUSP</em></strong> | Par | <strong><em>TERM</em></strong>\n\
-------\n\
/ \\\n\
\n\
--------- ------------\n\
| Await | | Generate |\n\
--------- ------------\n\
"
,
" |\n\
\n\
-------\n\
<strong><em>SUSP</em></strong> | Par | <strong><em>TERM</em></strong>\n\
-------\n\
/ \\\n\
\n\
--------- ------------\n\
| Await | | Generate |\n\
--------- ------------\n\
"
,
" |\n\
o \n\
-------\n\
<strong><em>SUSP</em></strong> | Par | <strong><em>TERM</em></strong>\n\
-------\n\
/ \\\n\
\n\
--------- ------------\n\
| Await | | Generate |\n\
--------- ------------\n\
"
,
" |\n\
o \n\
-------\n\
<strong><em>SUSP</em></strong> | Par | <strong><em>TERM</em></strong>\n\
-------\n\
/ \\\n\
o \n\
--------- ------------\n\
| Await | | Generate |\n\
--------- ------------\n\
"
,
" |\n\
o \n\
-------\n\
<strong><em>SUSP</em></strong> | Par | <strong><em>TERM</em></strong>\n\
-------\n\
/ \\\n\
o (<strong><em>TERM</em></strong>) \n\
--------- ------------\n\
| Await | | Generate |\n\
--------- ------------\n\
"
,
" |\n\
o \n\
-------\n\
<strong><em>TERM</em></strong> | Par | <strong><em>TERM</em></strong>\n\
-------\n\
/ \\\n\
\n\
--------- ------------\n\
| Await | | Generate |\n\
--------- ------------\n\
"
,
" |\n\
o (<strong><em>TERM</em></strong>)\n\
-------\n\
<strong><em>TERM</em></strong> | Par | <strong><em>TERM</em></strong>\n\
-------\n\
/ \\\n\
\n\
--------- ------------\n\
| Await | | Generate |\n\
--------- ------------\n\
"
,
" \n\
\n\
\n\
\n\
\n\
FIN !!! \n\
\n\
\n\
\n\
\n\
"
];
var animable1 = document.getElementById("animation1");
animable1.style.display="table";
//animable1.style.border="1px solid";
JFS.anim1_clickSensor = SC.sensorize({name:"SC_evt_touch_cancel"
, dom_targets:[
{
target:animable1
, evt:"click"
}
]
});
animable1.prevBuild = SC.evt("prevBuild");
animable1.nextBuild = SC.evt("nextBuild");
animable1.build = 0;
animable1.my_width = parseInt(window.getComputedStyle(animable1).width);
JFS.m.addToOwnProgram(
SC.cube(animable1
, SC.par(
SC.actionOn(JFS.anim1_clickSensor
, function(vals){
var evt = vals[JFS.anim1_clickSensor];
for(var i in evt){
var tmp = evt[i].cx-this.offsetLeft;
/*if(tmp < this.my_width/4){
console.log("prevBuild "+tmp+"/"+this.my_width);
JFS.m.addToOwnEntry(this.prevBuild);
}
if(tmp > this.my_width*3/4){*/
console.log("nextBuild");
this.build++;
this.build %= vues.length;
this.innerHTML = vues[this.build];
JFS.m.addToOwnEntry(this.prevBuild);
// }
}
}.bind(animable1)
, undefined
, SC.forever
)
)
)
);
</script>
On commence par appeler la méthode <code>activate()</code> de l'objet <code>Par</code> (la méthode <code>activate()</code> du prototype associé au constructeur <code>Par()</code> ).
<p>
Le comportement standard de l'instruction Par est d'activer ces 2 branches. On doit donc faire un choix dans l'ordre d'activation (on ne considère pas ici un moteur d'exécution parallèle mais séquentiel, les SugarCubes permettent d'exprimer du parallélisme mais leur interprétation peut-être parfaitement séquentiel). Pour les besoins de l'illustration, on choisit (parmi d'autres choix possibles) une interprétation séquentiel de Par qui active toujours dans une micro étape la branche gauche puis la branche droite de ce parallèle binaire. On suppose que l'on a que ce programme dans la machine d'exécution et que l'événement &e n'est pas une entée du programme c'est à dire qu'il n'est pas généré par un composant externe au programme réactif. Au début de l'instant on ne sait donc pas si e est présent ou absent on lui donne donc un statut inconnu. Le Await est activé (appel de sa méthode activate() ) en premier et arrive à la conclusion qu'il ne peut pas progresser car e est dans un état encore inconnu et que la seul chose qui l'intéresse est la présence (et uniquement la présence - l'absence ne l'intéresse pas) de l'événement e. Comme il ne peut se décider il retourne un autre statut <strong><em>WAIT</em></strong> (que l'on verra plus loin), le await informe donc son parent (l'instruction par) qu'il ne peut plus progresser et qu'il se met en attente d'un événement. Le par mémorise ce status pour sa première branche et passe à l'activation de la seconde...
</p>
Le generate lui a un comportement simple : lorsque sa méthode activate est appelée, il positionne le status de &e à présent et renvoi le status d'exécution <strong><em>TERM</em></strong>, indiquant que la seconde branche du par à complètement terminé son exécution, inutile de la réactivé à l'avenir.
avant d'activer la seconde branche le par avait mémoriser les status suivant : branche 1 <strong><em>WAIT</em></strong> et branche 2 <strong><em>SUSP</em></strong>.
après l'activvation du générate il a la mémoire suivante ; branche 1 <strong><em>SUSP</em></strong> et branche 2 <strong><em>TERM</em></strong>.
car la génération de l'événment e va modifier par le mécanisme des précurseurs le status associé au Await qui était en attente de l'événement e.
Comme au moins une de ses branche est dans l'état <strong><em>SUSP</em></strong>, le par remonte un état <strong><em>SUSP</em></strong>. indiquant à la machine d'exécution que l'instant ne peut pas être terminé puisque des choses restent à faire (le await peut maintenant progresser). La machine va donc attendre encore avant de déclarer l'instant terminé et va relancer la méthode activate() à la racine...
<h5><strong><em>WEOI</em></strong> :</h5>
indique qu'une instruction est bloquée en attente d'information sur un ou plusieurs événements et qu'il est intéressé à la fois par la présence et par l'absence d'un événement. En SugarCubes la présence est signalé immédiatement au moment l'événement est généré comme dans l'exemple précédent.
<script type="text/javascript">
// create a Blob object with a worker code
var blob = new Blob(["onmessage = function(e) { postMessage('msg from worker'); }"]);
// Obtain a blob URL reference to our worker 'file'.
var blobURL = window.URL.createObjectURL(blob);
// create a Worker
var worker = new Worker(blobURL);
worker.onmessage = function(e) {
console.log(e.data);
};
worker.postMessage("Send some Data");
</script>
</body>
</html>