block ::= (x1, ..., xn) = expr
| block; block
| automaton ... end (* automaton dans automaton possible ! *)
| reset block every expr
| if expr then block else block
| present ... end
| switch ... end
Exemple
automaton
dansautomaton
node f(cmd : bool) returns (o : float)
let
automaton
state Init (* état d'initialisation *)
do o = 0.0
unless cmd then Cruise
state Cruise (* état de croisière *)
var y : float;
do automaton
state A
do y = 0.0 fby (y +. 1.0)
until y >=. 10.0 then B
state B
do y = 1.0 fby (2.0 *. y)
until y >=. 128.0 then A
end;
o = y +. 10.0;
end
tel
switch
etpresent
type color = Green | Amber | Cyan
fun color2rgb(c : color) returns (r, g, b : float)
let
switch c
| Green
do r = 0.0; g = 1.0; b = 0.0
| Amber
do r = 1.0; g = 0.75; b = 0.0
| Cyan
do r = 0.0; g = 1.0; b = 1.0
end
tel
fun sign(x : float) returns (o : float)
let
present (* le booléen doit être combinatoire (sans état) *)
| x >. 0.0 do o = 1.0
| x <. 0.0 do o = -. 1.0
default do o = 0.0
end
tel
- Les tableaux en Heptagon sont persistants (non mutable)
- Taille fixée à la compilation ?
Les tableaux
- Type des tableaux d’entiers de taille 10 :
int^10
. - Type des tableaux de booléens de taille 30 :
bool^30
. - Type de matrice (tableau à deux dimensions) de flottants de taille 5x5 :
float^5^5
. - Type des tableaux de taille n dont les éléments de type t :
t^n
avec t un type et n une expression statique (valeur déterminée à la compilation, exemple : une constante littérale).
node arr0() returns (o1, o2, o3 : int^3)
let
o1 = [0, 1, 2];
o2 = 42^3;
o3 = o1 fby o2;
tel
node arr1() returns (o : int^2)
var n : int;
let
n = 0 fby (n + 2);
o = [n, n + 1];
tel
expr[expr]
----
|> expression statique (* permet au compilo de rester dans les bornes du tableau *)
expr[> expr <]
----
|> expression (* quelconque, pas besoin que ça soit statique *)
expr.[expr] default expr
----
|> expression
[ expr with [ expr ] = expr ]
---- ---- ---- ----
| | | |> : t
| | |> : int
| |> mot clé
|> : t^n
Exemple registre à décalage
(* les constructions dynamique sont à chier parce que si on a un bug il faudra débogguer *)
(* 3 bits + 1 entier de registre utilisé *)
node shiftr3dyn(ini : bool^3) returns (o : bool)
var mem : bool^3; idx : int;
let
mem = ini fby mem;
idx = 0 fby ((idx + 1) % 3);
o = mem[> idx <];
tel
node shiftr3dyn_bis(ini : bool^3) returns (o : bool)
var mem : bool^3; idx : int;
let
mem = ini fby mem;
idx = 0 fby ((idx + 1) % 3);
o = mem.[idx] default false;
tel
(* 3 bits de registre *)
node shiftr3(ini : bool^3) returns (o : bool)
var mem : bool^3;
let
mem = ini fby [ mem[1], mem[2], mem[0] ];
o = mem[0];
tel
\RA On ne peut toujours pas itérer dans un tableau.
(* pas idéal parce que s'il y a un bug dans le code, il faudra le débogger *)
node arr2() returns(o1, o2 : float^3)
let
o1 = [1.0, 3.0, 10.0]
o2 = [ o1 with [ 1 ] = 42.5 ]; (* modifie à l'index 1 *)
tel
node arr3() returns(o1, o2 : float^3)
let
o1 = [1.0, 3.0, 10.0]
o2 = [ o1 with [ 37 ] = 42.5 ]; (* modification ignorée car en dehors des bornes *)
tel
(* concaténatio de tableau *)
expr @ expr
node concat(a : int^1; b : int^2) returns (o : int^3)
let
o = a @ b;
tel
Buffer circulaire
node ring_buffer(e : int; w, r : bool) returns (o : int)
var pa, a : int^7; (* pa : précedent, a : courant*)
w_idx, r_idx : int; (* indices écriture et lecture *)
let
pa = (0^7) fby a;
a = if w then [ pa with [ w_idx ] = e ] else pa;
o = a[> r_idx <];
w_idx = 0 fby (w_idx + (if w then 1 else 0) % 7);
r_idx = 0 fby (r_idx + (if r then 1 else 0) % 7);
tel
(* on peut également déclarer une constante *)
const n : int = 7
node ring_buffer(e : int; w, r : bool) returns (o : int)
var pa, a : int^n; (* pa : précedent, a : courant*)
w_idx, r_idx : int; (* indices écriture et lecture *)
let
pa = (0^n) fby a;
a = if w then [ pa with [ w_idx ] = e ] else pa;
o = a[> r_idx <];
w_idx = 0 fby (w_idx + (if w then 1 else 0) % n);
r_idx = 0 fby (r_idx + (if r then 1 else 0) % n);
tel
(* on peut également donner en paramètre une constante *)
node ring_buffer<<n : int>>(e : int; w, r : bool) returns (o : int)
var pa, a : int^n; (* pa : précedent, a : courant*)
w_idx, r_idx : int; (* indices écriture et lecture *)
let
pa = (0^n) fby a;
a = if w then [ pa with [ w_idx ] = e ] else pa;
o = a[> r_idx <];
w_idx = 0 fby (w_idx + (if w then 1 else 0) % n);
r_idx = 0 fby (r_idx + (if r then 1 else 0) % n);
tel
node test_buffer() returns (o : int)
var e : int; w, r : bool;
let
e = 0 fby (e + 1);
w = true fby false fby w;
r = false fby true fby r;
o = ring_buffer<<10>>(e, w, r);
tel
Exercice/Problème :
e
devrait être d’horlogew
eto
devrait être d’horloger
. On pourrait aussi ajouter une sortie d’erreur qui détecte si le producteur ou le consommateur est trop rapide.