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 dans automaton

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 et present

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

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

buffer_circ

Exercice/Problème : e devrait être d’horloge w et o devrait être d’horloge r. On pourrait aussi ajouter une sortie d’erreur qui détecte si le producteur ou le consommateur est trop rapide.