• Aucun résultat trouvé

3.2 Spécification du langage OCaLustre formalisée avec Ott et Coq

3.2.3 Règles de typage des programmes

À l’instar de son langage cible OCaml, l’extension de langage OCaLustre correspond à un langage de programmation statiquement typé, implantant un mécanisme d’inférence de types à la compilation. Chaque variable d’un programme OCaLustre possède un type dont la nature peut être déterminée pendant la compilation. Il est à noter cependant que le système de types d’OCaLustre est monomorphe, contrairement au système polymorphe d’OCaml.

Dire qu’un flot x ≡ (x1, x2, ..., xi, ...) est de type « flot de t » (noté simplement « t ») revient à dire que tous les éléments de la séquence de valeurs à laquelle il correspond sont de type t. À l’image des listes homogènes du langage OCaml, un flot ne peut « porter » des valeurs dont le type change au fil du temps. Par conséquent, la création d’un flot dont la valeur peut changer de type d’un instant à l’autre , comme le flot (0, 2, 4, true, 10, 4.5, 14, . . . ), est donc impossible dans OCaLustre.

Les types manipulés dans OCaLustre peuvent être des types de base (int, bool, float), des types « flèches » (les types des nœuds), des types énumérés (représentés par l’ensemble de leurs constructeurs

Xi), ou bien des n-uplets de types (correspondant au type d’une liste d’expressions) :

t ::= unit | int | bool | f loat | t → t0 | {X1, . . . , Xn} | t1× ... × tn

À partir de la représentation en forme normale des programmes OCaLustre, nous définissons alors formellement les conditions qui régissent le bon typage d’un programme.

SoitΓ un environnement de typage local, c’est-à-dire une fonction qui à chaque variable d’un nœud OCaLustre associe son type : par exemple, si le flot x est de type int, alorsΓ(x) = int. On note Γ ` e : t le

3.2. Spécification du langage OCaLustre formalisée avec Ott et Coq 97

prédicat (appelé jugement de typage) indiquant que dans l’environnement de typageΓ l’expression e est de type t.

Nous définissons à partir de tels jugements des règles d’inférence représentant la cohérence du typage des expressions d’OCaLustre. De telles règles, de la forme

P1 . . . Pn

Q

permettent d’établir qu’à partir des conditions en prémisse P1à Pn, on peut déduire le jugement Q .

Typage des expressions : La figure 3.7 représente les règles de typage des expressions OCaLustre. Par exemple, la règle de typage de l’application d’un opérateur arithmétique entier ^int (par exemple l’opérateur+) décrit le fait que cette dernière ne peut être réalisée qu’entre deux entiers, et le résultat est lui-même un entier :

Γ ` e1 : int Γ ` e2: int Γ ` e1^inte2: int

Il est à noter qu’il est ici supposé, pour la règle de typage des opérateurs de comparaison, qu’aucune comparaison de valeurs de type fonctionnels n’est réalisée dans un programme OCaLustre. Ceci est laissé à la responsabilité du programmeur, qui doit s’assurer de ne pas réaliser une telle opération9. Comme nous reposons sur une exécution du code OCaml généré par compilation d’OCaLustre, la fonction de comparaison est polymorphe et son usage sur des valeurs de types fonctionnels lève une exception. Toute exception dans un programme OCaLustre entraîne l’arrêt de son exécution.

Par ailleurs, le jugement de la forme t= {X1, . . . Xn} signifie que le type t a été préalablement défini (dans l’en-tête OCaml) comme un type énuméré composé des constructeurs X1à Xn.

Enfin, nous distinguons les règles de typage d’une expression « simple » de celles d’une expression conditionnelle en annotant pour les règles portant sur les expressions conditionnelles le symbole « thèse » (`) de la façon suivante : `ce.

Les règles relatives au typage des équations et des nœuds OCaLustre sont données dans la figure 3.8. Dans la suite, nous les passons en revue afin de les décrire avec précision.

Typage des équations : SoitG un environnement de typage global qui associe à chaque fonction OCaml

et à chaque nœud OCaLustre son type (un type « flèche » de la forme type des entrées→ type des sorties). Une équation dans le corps d’un nœud OCaLustre correspondant à l’application d’un autre nœud⃗y = f (⃗e) est bien typée si et seulement si f a pour signature un type t1→ t2, le paramètre⃗e de l’application est de type t1et le résultat⃗y est de type t2:

Γ ` ⃗y : t2 G(f ) = t1→ t2 Γ ` ⃗e : t1 G, Γ ` ⃗y = f (⃗e)

Γ ` e : t

Γ ` () : unit Γ ` int_literal : int Γ ` bool_literal : bool Γ ` f loat_literal : f loat

Γ(x) = t Γ ` x : t t= {X1, ..., Xn} Γ ` Xi : t Γ ` e1: int Γ ` e2: int Γ ` e1^inte2: int Γ ` e1: bool Γ ` e2 : bool Γ ` e1^boole2: bool Γ ` e1: f loat Γ ` e2: f loat Γ ` e1^f loate2: f loat Γ ` e1 : t Γ ` e2: t Γ ` e1^compe2: bool Γ ` e : int Γ ` − e : int Γ ` e : f loat Γ ` −. e : f loat Γ ` e : bool Γ ` not e : bool Γ ` e : t Γ(x) = bool Γ ` e when x : t Γ ` e : t Γ(x) = bool Γ ` e whennot x : t Γ ` ⃗e : t Γ ` e : t Γ ` [e] : t Γ ` e : t Γ ` ⃗e : t0 Γ ` e,⃗e : t × t0 Γ `cece : t Γ ` e : t Γ `cee : t

Γ ` e1: bool Γ `cece2 : t Γ `cece3: t Γ `ceife1thence2elsece3: t Γ(x) = bool Γ `cece1: t Γ `cece2 : t

Γ `cemergex ce1ce2: t

3.2. Spécification du langage OCaLustre formalisée avec Ott et Coq 99 Γ ` ⃗y : t Γ ` () : unit Γ(y) = t Γ ` y : t Γ ` y : t Γ ` ⃗y : t0 Γ ` y, ⃗y : t × t0 G, Γ ` eqn Γ ` y : t Γ `cece : t G, Γ ` y = ce Γ ` y : t Γ ` k : t Γ ` e : t G, Γ ` y = k fby e Γ ` ⃗y : t2 G(f ) = t1→ t2 Γ ` ⃗e : t1 G, Γ ` ⃗y = f (⃗e) Γ ` y : tn G(f) = t0→ t1→ ... → tn−1→ tn Γ ` e0: t0 Γ ` e1: t1 ... Γ ` en−1: tn−1 G, Γ ` y = call f e0e1... en−1 G, Γ ` ⃗eqn G, Γ ` eqn G, Γ ` [eqn] G, Γ ` eqn G, Γ ` ⃗eqn G, Γ ` eqn; ⃗eqn G ` node : t G, Γ ` ⃗eqn Γ ` ⃗x : t1 Γ ` ⃗y : t2 G ` node f (⃗x) return (⃗y) = ⃗eqn : t1→ t2

G ` program

G ` ∅

G ` node f (⃗x) return (⃗y) = ⃗eqn : t1→ t2 (f : t1→ t2)] G ` ⃗nodes G ` node f (⃗x) return (⃗y) = ⃗eqn; ; ⃗nodes

Figure 3.8 – Règles de typage des équations et des nœuds

Une équation qui correspond à l’application de l’opérateur « followed-by » est bien typée à condition que la constante à gauche de l’opérateur≫ et l’expression à droite de ce dernier soient de même type, et que la variable à gauche de l’opérateur d’égalité soit aussi du même type :

Γ ` y : t Γ ` k : t Γ ` e : t

G, Γ ` y = k fby e

L’application d’une fonction OCaml est de type tnsi et seulement si la fonction OCaml est de type

t0→ · · · → tn−1→ tnet ses paramètres consécutifs sont de type t0à tn−1:

Γ ` y : tn G(f) = t0→ t1→ ... → tn−1→ tn Γ ` e0: t0 Γ ` e1: t1 ... Γ ` en−1: tn−1 G, Γ ` y = call f e0e1... en−1

des fonctions OCaml qui sont censées être uniquement capables de manipuler des valeurs « standards ». Par exemple, une valeur de type « flot de int » dans OCaLustre est considérée par la fonction OCaml appelée comme une valeur de type int. Cette distinction ne pose cependant pas de problème compte tenu du fait qu’à chaque instant du programme un flot ne possède qu’une seule valeur (un « flot de int » est donc réduit à un simple int)10. Formellement, l’opérateurcallpeut être vu comme une fonction map qui « lifte » une fonction OCaml pour qu’elle puisse s’appliquer à des flots :

call f e0e1 . . . en−1 ≡ (map f ) e0e1 . . . en−1

Toute autre équation y= ce est bien typée si l’expression ce qui lui est associée est bien typée et que la variable y est du même type dansΓ :

Γ ` y : t Γ `cece : t G, Γ ` y = ce

Une liste d’équations (le corps d’un nœud) est bien typée dès lors que toutes les équations qu’elle contient sont bien typées :

G, Γ ` eqn G, Γ ` [eqn]

G, Γ ` eqn G, Γ ` ⃗eqn G, Γ ` eqn; ⃗eqn

Typage d’un nœud et d’un programme synchrone : Le type d’un nœud OCaLustre est similaire au type d’une fonction dans OCaml. C’est un type flèche t1→ t2avec t1le type des flots qui peuvent lui être passés en entrée, et t2le type des valeurs qu’il calcule en sortie :

G, Γ ` ⃗eqn Γ ` ⃗x : t1 Γ ` ⃗y : t2 G ` node f (⃗x) return (⃗y) = ⃗eqn : t1→ t2

Enfin, un programme synchrone (i.e. une liste de nœuds) est bien typé à condition que chaque nœud qu’il contient soit bien typé :

G ` ∅

G ` node f (⃗x) return (⃗y) = ⃗eqn : t1→ t2 (f : t1→ t2)] G ` ⃗nodes G ` node f (⃗x) return (⃗y) = ⃗eqn; ; ⃗nodes

Le jugement de typage d’un programme synchrone est initialement invoqué avec l’environnement de typage qui correspond aux fonctions OCaml précédemment définies dans l’en-tête du programme. Les environnements de typage entre les fonctions OCaml et les nœuds sont donc partagés, et nous supposerons donc que les espaces de noms entre les fonctions et les nœuds sont différents et qu’il n’y a donc pas de conflits de noms (qui entraîneraient des phénomènes de masquage).

Les règles de typage de l’extension OCaLustre sont suffisamment proches des règles de typage d’OCaml pour qu’un programme OCaLustre bien typé soit bien typé après sa traduction vers OCaml et 10. Ce phénomène se retrouve aussi lorsqu’il est question de « brancher » un programme OCaLustre à des fonctions qui calculent les entrées et les sorties d’un instant synchrone.

3.2. Spécification du langage OCaLustre formalisée avec Ott et Coq 101

pour que la génération d’un programme OCaml mal typé dénote le fait que le programme OCaLustre d’origine est mal typé. De ce fait, grâce à la correction du typage vis-à-vis de la traduction vers OCaml (dont nous présenterons la preuve dans la section 5.1), les règles énoncées dans cette section ne nécessitent pas, pour maintenir la sûreté des programmes, d’être explicitement vérifiées par le compilateur d’OCaLustre. En effet, nous tirons profit du langage cible dont le compilateur réalise statiquement la vérification et l’inférence de types. Cette analyse se fait donc, dans notre situation, après traduction du code du langage OCaLustre vers un code OCaml classique. Le compilateur OCaml est alors capable de faire remarquer au développeur les erreurs de typage des programmes, y compris lorsqu’ils proviennent du code OCaLustre. Par ailleurs, puisque OCaLustre est réalisé avec des outils faisant partie de l’écosystème de compi-lation d’un programme OCaml, il est tout à fait compatible avec des d’autres outils puissants d’analyse statique tel que l’outil Merlin [BRS18] qui offre de nombreuses fonctionnalités pour simplifier le dévelop-pement de programmes OCaml (tel qu’un mécanisme d’auto-completion sensible au contexte, ou l’accès « en direct » à des informations relatives au typage) en s’intégrant dans des éditeurs de texte variés (Vim, Emacs, Atom . . . ). Une telle compatibilité permet d’offrir à l’utilisateur d’OCaLustre un retour immédiat et précis quant à la position des erreurs relatives (entre autres) à la cohérence de typage et du cadencement de ses programmes, et ce au sein même de son éditeur de texte favori.