estolus: A Racket #lang for Esterel which outputs equivalent Lustre code.
=========================================================================

0- Sommaire
-----------

1- Introduction ...................................................... ligne 15
2- Installation ...................................................... ligne 40
3- Utilisation ....................................................... ligne 67
4- Principe de traduction ............................................ ligne 97
5- Organisation du code ............................................. ligne 127
6- More fun ......................................................... ligne 164


1- Introduction
---------------

Mon but principal dans ce projet, en plus de mieux comprendre les langages
synchrones Lustre et Esterel, a été d'appendre à utiliser des outils que je ne
connaissais pas encore de la plateforme Racket : en particulier le lexer, le
parser, et la création de #lang (les langages embedded dans Racket).

La traduction se fait donc pour la première couche en remplaçant les fonction
read et read-syntax de Racket par un parseur mini Esterel qui produit des
objects syntax (voir
http://docs.racket-lang.org/reference/syntax-model.html#%28part._stxobj-model%29
pour plus d'information).

La syntax ainsi générée est bindée à des macros qui la transforme en une suite
de macro define-node qui implémente l'impression sur la sortie standard du code
Lustre correspondant.

Ce n'est clairement pas une stratégie très adaptée au travail demandée si on
souhaite faire des optimisations avant de générer le code Lustre par exemple,
mais le but été avant tout d'apprendre des choses et de s'amuser (de ce côté là
c'est réussi). On remarque toutefois que le code est assez cours (un peu plus
de 400 lignes si on ne compte pas le code administratif (voir section 5.4)).


2- Installation
---------------

Il faut d'abord installer Racket, c'est très vite fait (avec l'intsallateur
disponible ici: http://racket-lang.org/download/) et ça ne met pas le óai dans
son système si on choisi l'installation local (on peut tout supprimer d'un coup
en supprimant simplement le dossier, mais vous n'en aurez plus envie de toutes
façons :-p).

Ensuite il faut demander à Racket de connaitre estolus, pour cela, après avoir
rajouter les exécutables fourni par Racket dans son PATH, il suffit de faire

    raco link estolus

(Je suppose que vous êtes dans le répertoire où ce trouve ce README et le
répertoire estolus lui même.)

Ensuite pour que ça aille un peu plus vite (par exemple pour lui éviter de
reconstruire et recompiler le parseur à chaque fois qu'on exécute un script) il
faut compiler en bytecode avec.

    raco setup estolus

(Cette fois ci ça peut être fait de n'importe où, Racket connait maintenant la
collection estolus.)


3- Utilisation
--------------

Maintenant que estolus est installé, il suffit d'écrire son code mini-Esterel
dans un fichier qui commence par la ligne :

    #lang estolus

Et de lancer la commande "racket le-fichier.rkt".
Voir les exemples 1 à 12 dans le dossiers tests se trouvant à côté de ce
README.

Il est aussi possible de partir de moins loin dans la chaine, par exemple de la
syntax intermédiraire en s-expression pour mini-esterel en commençant par la
ligne :

    #lang s-exp estolus/esterel

Voir l'exemple 13.

On peut même utiliser directement la dernière étape de la transformation, cette
fois ci en Racket en requirant le module :

    #lang racket/base
    
    (require estolus/lustre)

Voir l'exemple 14.


4- Principe de traduction
-------------------------

Les exemples 1 à 10 présente des cas très simple pour montrer la tranduction de
chaque construction mini-Esterel en node Lustre.

L'idée générale est de faire un nœud Lustre pour chaque construction
mini-Esterel. Chaque nœud prends en entrée un ensemble de booléen qui
représente :
- le contrôle (idée reprise de l'énoncé de l'exam de 2008) ;
- un "câble" pour suspend ;
- un "câble" pour abort ;
- un booléen supplémentaire par signal visible dans le scope.
En sortie, il y a :
- le contrôle (qui est a vrai quand le nœud a terminé) ;
- un booléen supplémentaire par signal visible dans le scope.

Une node "main" est ajoutée par dessus. Elle a en entrée un argument qu'elle
ignore et une sortie finished qui est a vrai quand le programme a terminé. À
l'intéreieur, cette node "main" appelle la construction la "plus haute" du
programme mini-Esterel avec un contrôle qui est vrai au premier instant puis
toujours faux (afin de lancer le programme) et avec suspend et abort à faux
aussi.

Je n'ai pas exactement respecté la syntaxe demandé pour mini-Esterel, j'ai
préféré suivre celle du vrai Esterel (avec les "end" à la fin des constrcutions
"signal", "present" et "loop"). J'ai aussi rajouté le support de la
construction "emit", sinon c'était pas très intéressant.


5- Organisation du code
-----------------------

Les fichiers auxquels je fais référence dans cette section sont tous dans le
dossier estolus qui se situe à côté de ce README. Le code n'est pas commenté
parce qu'il n'y a pas de section algorithmiquement complexe qui nécéssiterai
une explication en plus du code lui même, et que donc rajouter des commentaires
dans ce contexte impliquerai de devoir maintenir deux versions du code dont une
dans un langage mal défini aussi appelée "langue naturelle".

5.1- Le lexer est le parser sont dans lexer-parser.rkt. Il n'y a rien à
dire de spécial dessus si ce n'est que la longueur du fichier (100 lignes) est
principalement dû au fait que je créer des objets syntax avec toutes les
informations de positions que les macros utiliseront automatiquement pour
reporter des erreurs.

5.2- Le langage est implémenté dans esterel.rkt. Attention, ce fichier ne doit
pas être évident à lire quand on n'est pas familier avec les macros de Scheme
et en particulier avec tout ce que Racket permet.
En gros, l'idée est qu'il y a une macro "define-esterel-construct" qui quand on
l'utilise écrit elle même écrit une macro qui implémente la construction
mini-Esterel. Il y a aussi quelques helpers qui sont définis pour la phase 1
(la phase d'expansion des macros, enfin la première… ^^) pour facilité de
travail et factorisé un peu les tâches répétitives.

5.3- Les macros générées par l'utilisation de "define-esterel-construct"
génèrent elles en coopérant un ensemble d'appelle de la macros "define-node",
qui s'expanse en une suite d'instructions d'affichage du code Lustre
correspondant. La macro "define-node" est implémentée dans le fichier
lustre.rkt.

5.4- Le fichier lang/reader.rkt est celui que Racket va chercher pour remplacer
son reader quand on utilise #lang estolus. Le fichier info.rkt est juste un peu
d'information pour Racket et son système de distribution (rien de très utile
pour ce projet donc, mais par principe il est là).


6- More fun
-----------

J'aurais aimé avoir plus de temps à consacrer à ce projet ces derniers temps
mais mon rôle d'élu au CA de l'École ma pris un temps monstrueux sur les deux
dernières semaines (entre 10h et 15h). Ce que j'aurais surtout aimé faire c'est
d'apprendre à utiliser l'outils "syntax-parse" de Racket pour implémenté la
macro "define-node", ça aurait permis un mécanisme de gestion des erreurs et de
sûreté assez cool grâce au système de syntax-class (en gros, un genre de typage
de la syntaxe, mais je crois que c'est un gros mot de le dire comme ça ;-)).
J'ai lu le papier correspondant il y a quelques temps mais j'ai encore jamais
vraiment jouer avec l'outil (voir
http://www.ccs.neu.edu/racket/pubs/icfp10-cf.pdf si vous êtes curieux).

Ça m'aurais aussi plu d'implémenter les constructions trap et exit, ça ne doit
pas être bien compliqué avec "l'infrastructure" mise en place pour le abort (le
"câble" abort) de le faire, et ça permettrais d'avoir tout ce que la page
wikipédia d'Esterel appelle "kernel-Esterel".

Il aurait aussi été amusant d'avoir un autre backend que la sortie de code
Lustre, par exemple coder effetivement un runtime Lustre (ou directement
mini-Esterel d'ailleurs) en Racket pour pouvoir aussi exécuter le code
mini-Esterel. Ça ne semble pas un défi trop élevé, à part que ça prends du
temps…
