4.2 Langage de communications
Le langage SCOL est un langage de communication pour la
Son noyau est proche de celui de Caml : il est fonctionnel, statiquement typé, polymorphe paramétrique avec inférence de types.
Il est "multimedia" grâce à ses API importantes pour le son, la 2D et la 3D.
Enfin il est interfacé avec java, javascript et activeX.
L'implantation de SCOL est classique, c'est un compilateur de byte-code.
La bibliothèque d'exécution possède un GC. Le code peut être téléchargé sous forme de sources, qui sont ensuite compilés puis exécutés.
Une version de "démonstration" est téléchargeable sur le site de la société CRYO :
http://www.cryo-networks.com
4.2.1 Utilisation de SCOL
Une fois téléchargé, la version de démonstration de SCOL contient le minimum pour pouvoir développer des programmes. Les fichiers d'extension ".pkg" contiennent des programmes SCOL, les fichiers d'extension ".scm" sont des scripts de lancement des programmes. L'extension ".scm" est liée au démarrage d'une machine SCOL.
Voici un exemple d'un script "
mic: more pavage/pavage.scm
_load "locked/lib/const.pkg"
_load "pavage/debug.pkg"
_load "pavage/util.pkg"
_load "pavage/geom.pkg"
_load "pavage/gen.pkg"
_load "pavage/visu.pkg"
_load "pavage/main.pkg"
main
où les différents fichiers ".pkg" sont chargéspuis la fonction main est exécutée.
4.2.2 Noyau fonctionnel et impératif du langage
Un programme SCOL est une suite de déclaration gloables. Elles concernent
les variables, les fonctions, les types, les constructeurs de communication et les déclarations avancées. Il n'y a pas de calcul d'expressions au niveau global, ni de déclaration d'exceptions.
variable
typeof x = I;;
var y = 4;;
fonctions
/* fonction succ */
fun succ(x) = x + 1;;
/* fonction add */
fun add(x,y) = x + y;;
/* longueur d'une liste */
fun len (l) = if l == nil then 0
else 1 + len (tl l);;
types
Les types de base sont les entiers (type I
), les flottants (type F
), les chaînes (type S
), les tuples [ ... ]
et les tableaux.
Le type d'une valeur fonctionnelle est : fun [ t1 t2 ... tn] tr
où les ti sont les types des paramètres et tr le type du résultat.
Il y a 2 types de déclarations de types : les "struct" et les types somme.
struct Point [x:I, y:I] mkPoint;;
typedef Num = mF F
| mI I;;
Le polymorphisme de Scol diffère de celui de Caml, bien qu'il soit lui aussi polymorphe paramétrique.
Les variables de types sont nommées ui indiquant une i-eme inconnue de
type. Elles doivent être liées. Par exemple la fonction id suivante :
fun id (x) = x;;
a le type fonctionnel : fun [u0] u0
qui se lit tuple des types des paramètres (entre crochets) type du résultat. Les types récursifs, comme les listes, sont décrits par le niveau de récursivité. Par exemple une liste
d'entiers : 1:;2::3::nil
ou [ 1 [2 [ 3 nil]]]
a le type
[I [ I [ I]]]
que l'on peut noter [ I r1]
où r1,
type du 2eme élément,
correspond au type de niveau 1 (c'est à dire une lite d'entiers). Cela permet d'avoir le même type pour des listes d'entiers de longueur quelconque.
Les 'a list
de Caml auront le type : [u0 r1]
où
En résumé, les types sont représentés par un graphe. Les types de base
sont des feuilles ainsi que les variables de types. Les tableaux ont un fils
(le type des éléments du tableau), les n-tuples ont n fils (chacun correspondant à un élément). Les fonctions ont 2 fils, le premier est le tuple des paramètres, le second le type du résultat.
expressions
La déclaration locale est dans l'ordre inverse de Caml :
SCOL CAML
let e1 -> p in e2 let p = e1 in e2
où e1 est le calcul d'une expression, p est le motif qui filtre cette
expression et e2 est l'expression à calculer où les variables du motif p sont connues.
La conditionnelle est classique :
if c then e1 else e2
où c est une expression entière (il n'y a pas le type booléen), et la branche else est obligatoire.
L'application est légèrement différente, ce qui force à parenthéser :
succ 3
add 5 6
len 1::2::3::nil
add len 1::2::3::nil len 2::6::nil
add (len 1::2::3::nil) (len 2::6::nil)
L'affectation d'une variable utilise le mot clé set
set v = 100
Le mot clé mutate permet d'effectuer un effet de bord sur une valeur complexe, le tout avec filtrage :
let [1 2 nil [3 4 ] ] -> t in
mutate t <- [ _ 5 6 _ ]
Les valeurs fonctionnelles ne sont pas des objets de 1ère classe.
Un paramètre fonctionnel se marque avec @f pour parler de la valeur fonctionnelle de f.
L'application d'une variable (contenant une valeur fonctionnelle) doit la spécialiser par :
set g = @add
exec g with [4 5]
La séquence de calcul d'expressions est parenthésée, le séparateur des
expressions est le ;.
La boucle while est là encore classique :
while e_1 do e_2
Les tableaux et les structs ont la notation "point" pour accéder à un élément :
t.5
t.(3+5)
set t.1 = 5.45
let mkPoint [2 3] -> p in p.x
Enfin le filtrage utilise la construction match :
match e with
(p1 -> e1)
| (p2 -> e2)
...
| (pn -> en)
C'est tout. Le reste du langage pour la partie communication est décrit
à la prochaine section.
4.2.3 Communication et environnement
L'originalité de Scol provient de la communication entre machines virtuelles.
La communication entre machines s'effectue à travers des canaux. Un canal est
un couple (environnement, liaison réseau). La liaison est une socket (TCP ou UDP).
Si la liaison n'existe pas on dit alors que le canal est "unplugged". C'est le cas au démarrage d'une machine SCOL.
Un environnement est associé au canal, s'il vaut nil il ne comprendra que l'environnement minimal.
la liai
canaux
_channel : fun [] Chn /* retourne le canal courant */
_setchannel : fun {Chn] Chn /* change le canal courant */
_load : fun [S] I /* chargement d'un fichier SCOL */
_openchannel : fun [S S Env] Chn
La fonction _openchannel
prend 3 paramètres :
-
une adresse IP (suivie ou non d'un port)
- un script de commande
- un environnement
Par exemple pour ouvrir un canal sur le port 2000 de la machine 132.227.89.8, en lui donnant l'environnement minimal, et en compilant le fichier "toto.pkg" et exécuter la fonction main de ce fichier, on écrira :
_openchannel "132.227.89.8:2000" "_load \"toto.pkg\"\nmain" nil
environnement
_envchannel : fun [Chn] Env
_removepkg : fun [Env] Env
_envfirstname : fun [Env] S
_setenv : fun [Chn Env] I
Les différentes fonctions sur les environnements permettent de charger un nouveau fichier (load),
de connaître l'environnement d'un canal, de connaître la tête de liste, d'enlever la tête de liste et de modifier l;environnement d'un canal.
Pour créer un canal "unplugged" qui hérite de l'environnement du canal courant et dans lequel on veut
charger "toto.pkg", puis exécuter main, on écrira :
_openchannel nil "\load \"toto.pkg\"\nmain" _envchannel _channel
communication
On définit des constructeurs de communication pour passer des valeurs (entières ou chaînes) sur un canal via la fonction _on : fun [Chn Comm] I
.
Le type Comm
correspond à un constructeur de communication appliqué à ses arguments. On les définit de la manière suivante :
defcom X = foo I I S;;
...
_on TheChannel foo [123 345 "toto"];
...
/* ou */
defcomvar Y = I I S;;
...
_on TheChannel Y "foo" [123 345 "toto"];
...
serveurs
Pour accepter une connexion, il est nécessaire de faire tourner auparavant un serveur sur la machine où l'on se connecte sur le bon port. La création d'un serveur utilise la fonction :
_setserver : fun [Env I S] Srv
qui hérite de l'environnement passé, exécute le script et ouvre le serveur sur le port,
Quand une connexion est demandée sur le serveur, un nouveau canal est ouvert. Ce canal hérite
de l'environnement défini avec le serveur et le script défini avec le serveur est alors exécuté.
_setserver _envchannel _channel 2000 "_load \"toto.pkg\"\nmain"
crée un serveur sur le port 2000 dans l'environnement courant, charge "toto.pkg" et exécute main.
connexion
Quand on ouvre une connexion par _openchannel
, le canal est immédiatement créé et la connexion réseau est lancée. Le programme continue son déroulement avant que cette connexion soit effective. Quand elle l'est, la machine SCOL exécute la fonction _connected
si elle existe. La fonction _connected : fun [] ?
ne prend pas d'arguments et retourne une valeur quelconque.
Le même procédé existe aussi sur le serveur, après l'exécution du script une fonction _connected
est aussi exécutée (si elle existe).
Une fois une connexion effectuée, le serveur et le client possèdent chacun un canal de communication de l'un vers l'autre.
4.2.4 API
L'environnement de développement de SCOL est riche. Une des API les plus importantes est l'API 3D qui permet de construire des mondes 3D avec détection des collisions. Le moteur 3D de cette bibliothèque est efficace.
L'API 2D pour les interfaces graphique est assez conséquente.
C'est l'ensemble des possibilités réseau et 3D qui rendent SCOL attrayant.
4.2.5 Les modules distribués