2026-03-29 15:32:35 +00:00
|
|
|
module Functional =
|
|
|
|
|
struct
|
|
|
|
|
|
|
|
|
|
type data = int
|
2026-04-28 14:37:54 +00:00
|
|
|
type memid = int
|
|
|
|
|
|
|
|
|
|
(* --- syntax --- *)
|
2026-03-29 15:32:35 +00:00
|
|
|
|
|
|
|
|
type read_cap = Rd | NRd
|
2026-04-28 14:37:54 +00:00
|
|
|
|
2026-03-29 15:32:35 +00:00
|
|
|
type write_cap = AlwaysWr | MayWr | NeverWr
|
2026-04-28 14:37:54 +00:00
|
|
|
type copy_cap = Cp | Rf
|
2026-03-29 15:32:35 +00:00
|
|
|
|
|
|
|
|
type in_cap = In | NIn
|
|
|
|
|
type out_cap = Out | NOut
|
|
|
|
|
|
2026-04-28 14:37:54 +00:00
|
|
|
type mode = in_cap * out_cap
|
2026-03-29 15:32:35 +00:00
|
|
|
|
2026-04-05 21:45:18 +00:00
|
|
|
type path = VarP of data | DerefP of path | AccessP of path * data
|
2026-03-29 15:32:35 +00:00
|
|
|
|
2026-04-28 14:37:54 +00:00
|
|
|
type atype = UnitT of read_cap * write_cap
|
|
|
|
|
| RefT of copy_cap * atype
|
|
|
|
|
| TupleT of atype list
|
2026-04-29 11:03:52 +00:00
|
|
|
| FunT of (mode * atype) list (* TODO: declaration id for ease of impl / performance instead (?) *)
|
2026-04-28 14:37:54 +00:00
|
|
|
|
|
|
|
|
type mtype = mode * atype
|
|
|
|
|
|
|
|
|
|
type expr = UnitE
|
|
|
|
|
| PathE of path
|
2026-05-01 13:40:56 +00:00
|
|
|
(* TODO: extend to include arbitrary path *)
|
|
|
|
|
| RefE of data
|
2026-04-28 14:37:54 +00:00
|
|
|
| TupleE of expr list
|
2026-03-29 15:32:35 +00:00
|
|
|
|
2026-04-29 15:12:45 +00:00
|
|
|
type stmt = SkipS
|
|
|
|
|
| CallS of path * expr list
|
2026-04-28 14:37:54 +00:00
|
|
|
| WriteS of path
|
|
|
|
|
| ReadS of path
|
|
|
|
|
| SeqS of stmt * stmt
|
|
|
|
|
| ChoiceS of stmt * stmt
|
|
|
|
|
|
|
|
|
|
type decl = VarD of (* data * *) atype * expr
|
|
|
|
|
| FunD of (* data * *) (* (data * *) mtype (* ) *) list * stmt
|
|
|
|
|
|
|
|
|
|
type prog = decl list * stmt
|
2026-03-29 15:32:35 +00:00
|
|
|
|
|
|
|
|
(* --- exceptions --- *)
|
|
|
|
|
|
2026-04-28 14:37:54 +00:00
|
|
|
(* exception Incorrect_memory_access of int *)
|
|
|
|
|
(* exception Ref_rvalue_argument of int *)
|
|
|
|
|
(* exception Incorrect_const_cast of int *)
|
|
|
|
|
(* exception Invalid_argument_tag of int *)
|
|
|
|
|
(* exception Incompatible_states *)
|
|
|
|
|
(* exception Incompatible_path_and_type *)
|
|
|
|
|
(* exception Incompatible_path_and_mem *)
|
|
|
|
|
(* exception Incompatible_path_and_type_for_tag *)
|
|
|
|
|
exception Typing_error of string
|
2026-04-29 09:16:24 +00:00
|
|
|
exception Eval_error of string
|
|
|
|
|
exception Cant_fold3_error
|
2026-04-28 14:37:54 +00:00
|
|
|
|
|
|
|
|
(* value model & memory model *)
|
|
|
|
|
|
|
|
|
|
type deepvalue = ZeroDV
|
|
|
|
|
| SmthDV
|
|
|
|
|
| BotDV
|
2026-04-29 12:07:33 +00:00
|
|
|
| FunDV of ((* data list * *) stmt) list
|
2026-04-28 14:37:54 +00:00
|
|
|
| RefDV of deepvalue
|
|
|
|
|
| TupleDV of deepvalue list
|
|
|
|
|
|
|
|
|
|
type value = ZeroV
|
|
|
|
|
| SmthV
|
|
|
|
|
| BotV
|
2026-04-29 12:07:33 +00:00
|
|
|
| FunV of ((* data list * *) stmt) list
|
2026-04-28 14:37:54 +00:00
|
|
|
| RefV of memid
|
|
|
|
|
| TupleV of value list
|
|
|
|
|
|
2026-05-10 17:19:00 +00:00
|
|
|
type revpath = VarRP | DerefRP of revpath | AccessRP of revpath * data
|
|
|
|
|
|
2026-04-28 14:37:54 +00:00
|
|
|
(* TODO: any additional difference between rvalue and lvalue now ?? *)
|
2026-03-29 15:32:35 +00:00
|
|
|
|
2026-04-28 14:37:54 +00:00
|
|
|
(* --- *)
|
2026-03-29 15:32:35 +00:00
|
|
|
|
2026-04-29 09:16:24 +00:00
|
|
|
type mem = value list * memid (* NOTE: memory and first free elem *)
|
2026-05-06 15:20:44 +00:00
|
|
|
type types = (data * atype) list (* glob *) * (data * atype) list (* glob + loc *)
|
|
|
|
|
type vals = (data * memid) list (* glob *) * (data * memid) list (* glob + loc *)
|
2026-05-09 16:34:47 +00:00
|
|
|
type visited = stmt list (* TODO: FIXME: optimize, use ids *)
|
|
|
|
|
type state = mem * types * vals * visited
|
2026-03-29 15:32:35 +00:00
|
|
|
|
2026-04-28 14:37:54 +00:00
|
|
|
(* --- *)
|
2026-03-29 15:32:35 +00:00
|
|
|
|
2026-05-06 15:20:44 +00:00
|
|
|
(* - state utils *)
|
|
|
|
|
|
|
|
|
|
let types_assoc (x : data) (types : types) : atype =
|
|
|
|
|
(* try ( List.assoc x (fst types) ) *)
|
|
|
|
|
(* with Not_found -> *)
|
|
|
|
|
List.assoc x (snd types)
|
|
|
|
|
let vals_assoc (x : data) (vals : vals) : memid =
|
|
|
|
|
(* try ( List.assoc x (fst vals) ) *)
|
|
|
|
|
(* with Not_found -> *)
|
|
|
|
|
List.assoc x (snd vals)
|
|
|
|
|
|
|
|
|
|
let types_glob_add (types : types) (x : data) (t : atype) =
|
|
|
|
|
((x, t) :: fst types, (x, t) :: snd types)
|
|
|
|
|
|
|
|
|
|
let types_add (types : types) (x : data) (t : atype) =
|
|
|
|
|
(fst types, (x, t) :: snd types)
|
|
|
|
|
|
|
|
|
|
let vals_glob_add (vals : vals) (x : data) (id : memid) =
|
|
|
|
|
((x, id) :: fst vals, (x, id) :: snd vals)
|
|
|
|
|
|
|
|
|
|
let vals_add (vals : vals) (x : data) (id : memid) =
|
|
|
|
|
(fst vals, (x, id) :: snd vals)
|
|
|
|
|
|
2026-04-29 09:16:24 +00:00
|
|
|
(* - utils *)
|
|
|
|
|
|
|
|
|
|
let rec list_replace (xs : 'a list) (id : int) (y : 'a) : 'a list = match xs, id with
|
|
|
|
|
| _ :: xs, 0 -> y :: xs
|
|
|
|
|
| x :: xs, _ -> x :: list_replace xs (id - 1) y
|
|
|
|
|
| [], _ -> raise Not_found
|
|
|
|
|
|
2026-05-05 14:35:35 +00:00
|
|
|
(* TODO: FIXME: check if this foldl or foldr *)
|
|
|
|
|
let rec list_foldl3 f (acc : 'a) (xs : 'b list) (ys : 'c list) (zs : 'd list) : 'a = match xs, ys, zs with
|
|
|
|
|
| x :: xs, y :: ys, z :: zs -> list_foldl3 f (f acc x y z) xs ys zs
|
|
|
|
|
| [], [], [] -> acc
|
|
|
|
|
| _, _, _ -> raise Cant_fold3_error
|
|
|
|
|
|
|
|
|
|
(* --- *)
|
|
|
|
|
|
2026-04-29 09:16:24 +00:00
|
|
|
(* NOTE: old variant with assoc array *)
|
|
|
|
|
(* let mem_get (mem : mem) (id : memid) : value = List.assoc id (fst mem) *)
|
|
|
|
|
(* let mem_add (mem : mem) (v : value) : mem * memid = *)
|
|
|
|
|
(* (((snd mem, v) :: fst mem, snd mem + 1), snd mem) *)
|
|
|
|
|
(* let mem_set (mem : mem) (id : memid) (v : value) : mem = *)
|
|
|
|
|
(* ((id, v) :: fst mem, snd mem) *)
|
2026-05-10 17:19:00 +00:00
|
|
|
let mem_get (mem : mem) (id : memid) : value = (* FIXME TMP Printf.printf "l%i i%i %i: access\n" (snd mem) id (snd mem - id - 1); *)
|
2026-05-04 13:42:53 +00:00
|
|
|
List.nth (fst mem) (snd mem - id - 1)
|
2026-04-28 14:37:54 +00:00
|
|
|
let mem_add (mem : mem) (v : value) : mem * memid =
|
2026-04-29 09:16:24 +00:00
|
|
|
((v :: fst mem, snd mem + 1), snd mem)
|
2026-04-28 14:37:54 +00:00
|
|
|
let mem_set (mem : mem) (id : memid) (v : value) : mem =
|
2026-05-01 13:40:56 +00:00
|
|
|
(list_replace (fst mem) (snd mem - id - 1) v, snd mem)
|
2026-04-28 14:37:54 +00:00
|
|
|
|
|
|
|
|
let rec v_to_deepv (mem : mem) (v : value) : deepvalue = match v with
|
|
|
|
|
| ZeroV -> ZeroDV
|
|
|
|
|
| SmthV -> SmthDV
|
|
|
|
|
| BotV -> BotDV
|
|
|
|
|
| FunV s -> FunDV s
|
|
|
|
|
| RefV id -> RefDV (v_to_deepv mem @@ mem_get mem id)
|
|
|
|
|
| TupleV vs -> TupleDV (List.map (v_to_deepv mem) vs)
|
|
|
|
|
|
|
|
|
|
let is_trivial_v (v : value) : bool =
|
|
|
|
|
v == ZeroV || v == SmthV || v == BotV
|
|
|
|
|
|
|
|
|
|
(* --- path accessors --- *)
|
|
|
|
|
|
|
|
|
|
let rec pathvar (p : path) : data = match p with
|
|
|
|
|
| VarP x -> x
|
|
|
|
|
| DerefP p -> pathvar p
|
|
|
|
|
| AccessP (p, _) -> pathvar p
|
|
|
|
|
|
2026-05-10 17:19:00 +00:00
|
|
|
let rec pathrev (p : path) (acc : revpath) : revpath = match p with
|
|
|
|
|
| VarP x -> acc
|
|
|
|
|
| DerefP p -> pathrev p @@ DerefRP acc
|
|
|
|
|
| AccessP (p, i) -> pathrev p @@ AccessRP (acc, i)
|
|
|
|
|
|
2026-04-28 14:37:54 +00:00
|
|
|
let rec pathtype (types : types) (p : path) : atype = match p with
|
2026-05-06 15:20:44 +00:00
|
|
|
| VarP x -> types_assoc x types
|
2026-04-28 14:37:54 +00:00
|
|
|
| DerefP p -> (match pathtype types p with
|
|
|
|
|
| RefT (_, t) -> t
|
|
|
|
|
| _ -> raise @@ Typing_error "pathtype: deref")
|
|
|
|
|
| AccessP (p, id) -> match pathtype types p with
|
2026-05-10 17:19:00 +00:00
|
|
|
| TupleT ts -> (* FIXME TMP Printf.printf "pathtype access sz=%i id=%i\n" (List.length ts) id; *)
|
|
|
|
|
(List.nth ts id)
|
2026-04-28 14:37:54 +00:00
|
|
|
| _ -> raise @@ Typing_error "pathtype: access"
|
|
|
|
|
|
|
|
|
|
let rec pathval (mem : mem) (vals : vals) (p : path) : value = match p with
|
2026-05-01 13:40:56 +00:00
|
|
|
| VarP x -> mem_get mem @@ ((* Printf.printf "%i: " x; (* FIXME TMP *)
|
|
|
|
|
ignore @@ List.map (fun (x, _) -> Printf.printf "%i " x) vals;
|
|
|
|
|
Printf.printf "mem size: %i, " (List.length (fst mem));
|
|
|
|
|
Printf.printf "mem size stored: %i " (snd mem);
|
|
|
|
|
Printf.printf "\n"; *)
|
2026-05-06 15:20:44 +00:00
|
|
|
vals_assoc x vals)
|
2026-04-28 14:37:54 +00:00
|
|
|
| DerefP p -> (match pathval mem vals p with
|
|
|
|
|
| RefV id -> mem_get mem id
|
|
|
|
|
| _ -> raise @@ Typing_error "pathval: deref")
|
|
|
|
|
| AccessP (p, id) -> match pathval mem vals p with
|
2026-05-10 17:19:00 +00:00
|
|
|
| TupleV vs -> (* FIXME TMP Printf.printf "pathval access sz=%i id=%i\n" (List.length vs) id; *)
|
|
|
|
|
(List.nth vs id)
|
2026-04-28 14:37:54 +00:00
|
|
|
| _ -> raise @@ Typing_error "pathval: access"
|
|
|
|
|
|
|
|
|
|
(* --- eval rules --- *)
|
|
|
|
|
|
|
|
|
|
(* - value construction *)
|
|
|
|
|
|
2026-05-05 14:35:35 +00:00
|
|
|
let rec valcopy (mem : mem) (v : value) (t : atype) : mem * value =
|
|
|
|
|
if is_trivial_v v
|
|
|
|
|
then match t with
|
|
|
|
|
| UnitT (Rd, _) -> (mem, v)
|
|
|
|
|
| UnitT (NRd, _) -> (mem, BotV)
|
|
|
|
|
| _ -> raise @@ Typing_error "valcopy: trivial value, wrong type"
|
|
|
|
|
else match t, v with
|
|
|
|
|
(* NOTE: replaced with if | best choice ?? *)
|
|
|
|
|
(* | UnitT (Rd, w), ZeroV -> (mem, v) *)
|
|
|
|
|
(* | UnitT (Rd, w), SmthV -> (mem, v) *)
|
|
|
|
|
(* | UnitT (Rd, w), BotV -> (mem, v) *)
|
|
|
|
|
(* | UnitT (NRd, w), ZeroV -> (mem, BotV) *)
|
|
|
|
|
(* | UnitT (NRd, w), SmthV -> (mem, BotV) *)
|
|
|
|
|
(* | UnitT (NRd, w), BotV -> (mem, BotV) *)
|
2026-04-28 14:37:54 +00:00
|
|
|
| FunT _, FunV _ -> (mem, v)
|
|
|
|
|
| RefT (Rf, _), RefV _ -> (mem, v)
|
|
|
|
|
| RefT (Cp, t), RefV id -> let (mem', v') = valcopy mem (mem_get mem id) t in
|
|
|
|
|
let (mem'', id'') = mem_add mem' v' in
|
|
|
|
|
(mem'', RefV id'')
|
|
|
|
|
| TupleT ts, TupleV vs -> let folder = fun (mem, vs') v t -> let (mem', v') = valcopy mem v t in
|
2026-05-10 13:44:35 +00:00
|
|
|
(mem', v' :: vs') in
|
2026-04-28 14:37:54 +00:00
|
|
|
let mem', vs' = List.fold_left2 folder (mem, []) vs ts in
|
2026-05-10 13:44:35 +00:00
|
|
|
(mem', TupleV (List.rev vs')) (* TODO: FIXME: should reverse or not ?? *)
|
2026-05-05 14:35:35 +00:00
|
|
|
| _, _ -> raise @@ Typing_error "valcopy: not trivial value, wrong type"
|
2026-04-28 14:37:54 +00:00
|
|
|
|
|
|
|
|
(* - value update *)
|
|
|
|
|
|
2026-05-10 17:19:00 +00:00
|
|
|
let rec valupd (mem : mem) (v : value) (p : revpath) (b : value) : mem * value = match p, v with
|
|
|
|
|
| VarRP, _ -> (mem, b)
|
|
|
|
|
| DerefRP p, RefV id -> let (mem', v') = valupd mem (mem_get mem id) p b in
|
|
|
|
|
(mem_set mem' id v', RefV id)
|
|
|
|
|
| AccessRP (p, id), TupleV vs -> let (mem', v') = (* FIXME TMP Printf.printf "vs size=%i id=%i\n" (List.length vs) id; *)
|
|
|
|
|
valupd mem (List.nth vs id) p b in
|
|
|
|
|
(* FIXME TMP Printf.printf "before return\n"; *)
|
|
|
|
|
(mem', TupleV (list_replace vs id v'))
|
2026-04-28 14:37:54 +00:00
|
|
|
| _, _ -> raise @@ Typing_error "valupd"
|
|
|
|
|
|
|
|
|
|
(* - value combination *)
|
|
|
|
|
|
|
|
|
|
let rec valcomb (u : value) (v : value) : value =
|
|
|
|
|
if is_trivial_v u && is_trivial_v v
|
|
|
|
|
then (if u == v then u else BotV)
|
|
|
|
|
else match u, v with
|
2026-05-05 14:35:35 +00:00
|
|
|
| FunV ustmts, FunV vstmts -> FunV (ustmts @ vstmts)
|
2026-04-28 14:37:54 +00:00
|
|
|
| RefV a, RefV b -> if a == b then u else raise @@ Typing_error "valcomb: ref"
|
|
|
|
|
| TupleV us, TupleV vs -> TupleV (List.map2 valcomb us vs)
|
2026-04-29 09:16:24 +00:00
|
|
|
| _, _ -> raise @@ Typing_error "valcomb"
|
2026-04-28 14:37:54 +00:00
|
|
|
|
2026-04-29 09:16:24 +00:00
|
|
|
let rec memcomb (m : mem) (n : mem) : mem =
|
|
|
|
|
if snd m != snd n
|
|
|
|
|
then raise @@ Typing_error "memcomb"
|
|
|
|
|
else (List.map2 valcomb (fst m) (fst n), snd m)
|
2026-04-28 14:37:54 +00:00
|
|
|
|
2026-04-29 11:03:52 +00:00
|
|
|
(* - expression evaluation *)
|
|
|
|
|
|
|
|
|
|
let rec exprval (mem : mem) (vals : vals) (e : expr) : value = match e with
|
|
|
|
|
| UnitE -> ZeroV
|
|
|
|
|
| PathE p -> pathval mem vals p
|
2026-05-06 15:20:44 +00:00
|
|
|
| RefE x -> RefV (vals_assoc x vals)
|
2026-04-29 11:03:52 +00:00
|
|
|
| TupleE es -> TupleV (List.map (exprval mem vals) es)
|
|
|
|
|
|
|
|
|
|
(* - expression typing *)
|
|
|
|
|
|
|
|
|
|
let rec exprtype (types : types) (e : expr) : atype = match e with
|
|
|
|
|
| UnitE -> UnitT (Rd, NeverWr)
|
|
|
|
|
| PathE p -> pathtype types p
|
2026-05-06 15:20:44 +00:00
|
|
|
| RefE x -> RefT (Rf, types_assoc x types)
|
2026-04-29 11:03:52 +00:00
|
|
|
| TupleE es -> TupleT (List.map (exprtype types) es)
|
|
|
|
|
|
2026-04-29 12:44:15 +00:00
|
|
|
(* - context initialization *)
|
|
|
|
|
|
2026-04-29 15:12:45 +00:00
|
|
|
(* let rec valcopy (mem : mem) (v : value) (t : atype) : mem * value = match t, v with *)
|
|
|
|
|
|
|
|
|
|
(* TODO: check new in vars *)
|
2026-04-29 12:44:15 +00:00
|
|
|
let add_decl (state : state) (x : data) (d : decl) : state =
|
2026-05-09 16:34:47 +00:00
|
|
|
match state with (mem, types, vals, visited) -> match d with
|
2026-04-29 12:44:15 +00:00
|
|
|
| VarD (t, e) -> let v = exprval mem vals e in
|
2026-04-29 15:12:45 +00:00
|
|
|
let (mem', v') = valcopy mem v t in
|
|
|
|
|
let (mem'', id) = mem_add mem' v' in
|
2026-05-09 16:34:47 +00:00
|
|
|
(mem'', types_glob_add types x t, vals_glob_add vals x id, visited)
|
2026-04-29 12:44:15 +00:00
|
|
|
| FunD (ts, s) -> let (mem', id) = mem_add mem (FunV [s]) in
|
2026-05-09 16:34:47 +00:00
|
|
|
(mem', types_glob_add types x (FunT ts), vals_glob_add vals x id, visited)
|
2026-04-29 12:44:15 +00:00
|
|
|
|
2026-05-01 13:40:56 +00:00
|
|
|
let empty_mem : mem = ([], 0)
|
2026-05-09 16:34:47 +00:00
|
|
|
let empty_state : state = (empty_mem, ([], []), ([], []), [])
|
2026-04-29 12:44:15 +00:00
|
|
|
|
2026-04-29 15:12:45 +00:00
|
|
|
(* TODO: better way ??? *)
|
|
|
|
|
let globals_min_id : data = 1000
|
|
|
|
|
|
2026-04-29 12:44:15 +00:00
|
|
|
let prog_init (prog : prog) : state =
|
|
|
|
|
match prog with (decls, _) -> fst @@ List.fold_left (* TODO: FIXME: check x's order *)
|
|
|
|
|
(fun (st, x) d -> (add_decl st x d, x + 1))
|
2026-04-29 15:12:45 +00:00
|
|
|
(empty_state, globals_min_id)
|
2026-04-29 12:44:15 +00:00
|
|
|
decls
|
|
|
|
|
|
2026-04-28 14:37:54 +00:00
|
|
|
(* - call values spoil *)
|
|
|
|
|
|
|
|
|
|
(* TODO: check all cases *)
|
|
|
|
|
let is_correct_tags (v : value) (r : read_cap) (w : write_cap)
|
|
|
|
|
(r' : read_cap) (w' : write_cap) (m : mode)
|
|
|
|
|
(c : copy_cap) : bool =
|
2026-05-06 15:01:34 +00:00
|
|
|
(* FIXME TMP *)
|
|
|
|
|
(* Printf.printf "%b %b %b %b %b\n" *)
|
|
|
|
|
(* (r != Rd || v == ZeroV) *)
|
|
|
|
|
(* (r != Rd || fst m == In) *)
|
|
|
|
|
(* (snd m != Out || w == AlwaysWr) *)
|
|
|
|
|
(* (* TODO: FIXME: why always write ?? *) *)
|
|
|
|
|
(* (((not ((w == AlwaysWr || w == MayWr) && (snd m == Out || c == Rf))) || w' == AlwaysWr)) *)
|
|
|
|
|
(* (is_trivial_v v); *)
|
2026-04-28 14:37:54 +00:00
|
|
|
(r != Rd || v == ZeroV) &&
|
|
|
|
|
(r != Rd || fst m == In) &&
|
2026-04-29 09:16:24 +00:00
|
|
|
(snd m != Out || w == AlwaysWr) &&
|
2026-05-08 14:50:36 +00:00
|
|
|
(* TODO: FIXME: check *)
|
2026-05-01 13:40:56 +00:00
|
|
|
((not ((w == AlwaysWr || w == MayWr) && (snd m == Out || c == Rf))) || w' == AlwaysWr) &&
|
2026-04-28 14:37:54 +00:00
|
|
|
is_trivial_v v
|
|
|
|
|
|
|
|
|
|
let rec valspoil (mem : mem) (v : value) (t : atype)
|
|
|
|
|
(u : atype) (m : mode) (c : copy_cap)
|
|
|
|
|
: mem * value = match t, u, v with
|
2026-04-29 09:16:24 +00:00
|
|
|
| UnitT (r, w), UnitT (r', w'), _ ->
|
|
|
|
|
if not @@ is_trivial_v v
|
|
|
|
|
then raise @@ Typing_error "valspoil: unit, not trivial"
|
|
|
|
|
else if not @@ is_correct_tags v r w r' w' m c
|
|
|
|
|
then raise @@ Typing_error "valspoil: unit, not correct"
|
|
|
|
|
else if snd m == NOut && c == Rf && (w == AlwaysWr || w == MayWr)
|
|
|
|
|
then (mem, BotV)
|
|
|
|
|
else if snd m == Out && w == AlwaysWr
|
|
|
|
|
then (mem, ZeroV)
|
|
|
|
|
else (mem, v)
|
2026-04-28 14:37:54 +00:00
|
|
|
| FunT ts, FunT us, FunV _ -> if ts == us then (mem, v) else raise @@ Typing_error "valspoil: fun"
|
|
|
|
|
| RefT (ct, t), RefT (cu, u), RefV id ->
|
|
|
|
|
let (mem', v') = valspoil mem (mem_get mem id) t u m ct in
|
|
|
|
|
(mem_set mem id v', RefV id)
|
2026-04-29 09:16:24 +00:00
|
|
|
| TupleT ts, TupleT us, TupleV vs ->
|
|
|
|
|
let folder = fun (mem, vs') t u v ->
|
|
|
|
|
let (mem', v') = valspoil mem v t u m c in (mem', v' :: vs') in
|
|
|
|
|
let (mem', vs') = list_foldl3 folder (mem, []) ts us vs in
|
2026-05-10 16:56:15 +00:00
|
|
|
(mem', TupleV (List.rev vs'))
|
2026-04-28 14:37:54 +00:00
|
|
|
| _, _, _ -> raise @@ Typing_error "valspoil"
|
|
|
|
|
|
2026-04-29 09:16:24 +00:00
|
|
|
(* full spoil *)
|
2026-04-29 12:44:15 +00:00
|
|
|
|
2026-05-05 18:14:58 +00:00
|
|
|
let argsspoilp (state : state) (m : mode) (t : atype) (p : path) : mem =
|
2026-05-09 16:34:47 +00:00
|
|
|
match state with (mem, types, vals, visited) ->
|
2026-04-29 09:16:24 +00:00
|
|
|
let x = pathvar p in
|
2026-05-06 16:14:35 +00:00
|
|
|
let id = vals_assoc x vals in (* base var address *)
|
|
|
|
|
let b = pathval mem vals p in (* subvalue in var *)
|
|
|
|
|
let t' = pathtype types p in (* type of subvalue *)
|
|
|
|
|
let (mem', b') = valspoil mem b t t' m Cp in (* spoil subvalue *)
|
2026-05-10 16:56:15 +00:00
|
|
|
(* TODO: FIXME: why copy (Cp)? maybe sometimes use top-level capability ? *)
|
2026-05-10 17:19:00 +00:00
|
|
|
let pi = pathrev p VarRP in
|
|
|
|
|
let (mem'', v'') = valupd mem' (mem_get mem' id) pi b' in (* set subvalue into var *)
|
2026-04-29 09:16:24 +00:00
|
|
|
mem_set mem'' id v''
|
|
|
|
|
|
2026-04-29 11:03:52 +00:00
|
|
|
let rec argsspoile (state : state) (m : mode) (t : atype) (e : expr) : mem =
|
2026-05-09 16:34:47 +00:00
|
|
|
match state with (mem, types, vals, visited) -> match e, t with
|
2026-04-29 11:03:52 +00:00
|
|
|
| UnitE, UnitT _ -> mem
|
|
|
|
|
| PathE p, t -> argsspoilp state m t p
|
2026-05-05 18:14:58 +00:00
|
|
|
| RefE x, t -> argsspoilp state m t (VarP x)
|
|
|
|
|
(* TODO: FIXME: check RefE case ? *)
|
2026-04-29 11:03:52 +00:00
|
|
|
| TupleE es, TupleT ts -> List.fold_left2
|
2026-05-09 16:34:47 +00:00
|
|
|
(fun mem' t' e' -> argsspoile (mem', types, vals, visited) m t' e')
|
2026-04-29 11:03:52 +00:00
|
|
|
mem ts es
|
|
|
|
|
| _, _ -> raise @@ Typing_error "valspoile"
|
2026-04-29 09:16:24 +00:00
|
|
|
|
|
|
|
|
(* - funciton argument addition *)
|
|
|
|
|
|
2026-05-01 13:40:56 +00:00
|
|
|
let addarg (state : state) (oldvals : vals) (x : data) (t : atype) (e : expr) : state =
|
2026-05-09 16:34:47 +00:00
|
|
|
match state with (mem, types, vals, visited) ->
|
2026-05-01 13:40:56 +00:00
|
|
|
let v = exprval mem oldvals e in
|
2026-04-29 09:16:24 +00:00
|
|
|
(* let t' = pathtype types p in *)
|
|
|
|
|
let (mem', v') = valcopy mem v t in
|
2026-05-05 18:14:58 +00:00
|
|
|
let (mem'', id) = mem_add mem' v' in
|
2026-05-09 16:34:47 +00:00
|
|
|
(mem'', types_add types x t, vals_add vals x id, visited)
|
2026-04-29 09:16:24 +00:00
|
|
|
|
2026-04-29 12:07:33 +00:00
|
|
|
(* - function evaluation *)
|
|
|
|
|
(* NOTE: not needed due to performed optimization in stmt_eval *)
|
|
|
|
|
(* let func_eval (mem : mem) (vals : vals) (s : stmt) (ts : mtype list) (es : expr list) = *)
|
|
|
|
|
|
2026-04-29 11:03:52 +00:00
|
|
|
(* - statement evaluation *)
|
|
|
|
|
|
2026-04-29 09:16:24 +00:00
|
|
|
let rec stmt_eval (state : state) (s : stmt) : state =
|
2026-05-09 16:34:47 +00:00
|
|
|
match state with (mem, types, vals, visited) -> match s with
|
2026-04-29 15:12:45 +00:00
|
|
|
| SkipS -> state
|
2026-05-05 18:14:58 +00:00
|
|
|
| CallS (f, es) -> let v = (* FIXME TMP Printf.printf "call, before v\n"; *)
|
|
|
|
|
pathval mem vals f in
|
|
|
|
|
let t = (* FIXME TMP Printf.printf "call, before t\n"; *)
|
|
|
|
|
pathtype types f in
|
2026-05-06 15:20:44 +00:00
|
|
|
let types' : types = (fst types, fst types) in
|
|
|
|
|
let vals' : vals = (fst vals, fst vals) in
|
2026-04-29 11:03:52 +00:00
|
|
|
(match v, t with
|
2026-04-29 12:07:33 +00:00
|
|
|
| FunV (* xs, *) fstmts (* ) *), FunT ts ->
|
2026-05-05 18:14:58 +00:00
|
|
|
let (state_with_args, _) = (* FIXME TMP Printf.printf "call, before args\n"; *)
|
|
|
|
|
List.fold_left2 (* TODO: FIXME: check x's order *)
|
|
|
|
|
(fun (st, x) (m, t) e -> (addarg st vals x t e, x + 1))
|
2026-05-09 16:34:47 +00:00
|
|
|
((mem, types', vals', visited), 0) ts es in
|
2026-04-29 12:07:33 +00:00
|
|
|
(* NOTE: same x's, so can use same args for all the statements *)
|
2026-05-09 16:34:47 +00:00
|
|
|
(match state_with_args with (mem_swa, types_swa, vals_swa, visited_swa) ->
|
|
|
|
|
let visited_new = (* FIXME TMP Printf.printf "call, before eval\n"; *)
|
|
|
|
|
List.fold_left
|
|
|
|
|
(fun visited_old stmt ->
|
|
|
|
|
if List.mem stmt visited_old
|
|
|
|
|
then stmt :: visited_old
|
|
|
|
|
else match stmt_eval (mem_swa, types_swa, vals_swa, stmt :: visited_old) stmt with
|
|
|
|
|
(_, _, _, visited_after_stmt) -> visited_after_stmt)
|
|
|
|
|
visited_swa
|
|
|
|
|
fstmts in
|
|
|
|
|
let mem_spoiled = (* FIXME TMP Printf.printf "call, before spoil\n"; *)
|
|
|
|
|
List.fold_left2
|
|
|
|
|
(fun mem (m, t) e -> argsspoile (mem, types, vals, (* NOTE: not important *) visited_new) m t e)
|
|
|
|
|
mem ts es in
|
|
|
|
|
(mem_spoiled, types, vals, visited_new))
|
2026-05-01 13:40:56 +00:00
|
|
|
| FunV _, _ -> raise @@ Eval_error "call: function type"
|
|
|
|
|
| _, FunT _ -> raise @@ Eval_error "call: function val"
|
|
|
|
|
| _, _ -> raise @@ Eval_error "call: function type & val")
|
2026-04-29 09:16:24 +00:00
|
|
|
| WriteS p -> (match pathtype types p with
|
|
|
|
|
| UnitT (_, w) ->
|
|
|
|
|
if w == NeverWr
|
|
|
|
|
then raise @@ Eval_error "write: write tag"
|
|
|
|
|
else let x = pathvar p in
|
2026-05-06 15:20:44 +00:00
|
|
|
let id = vals_assoc x vals in
|
2026-05-10 17:19:00 +00:00
|
|
|
let pi = pathrev p VarRP in
|
|
|
|
|
let (mem', v') = valupd mem (mem_get mem id) pi ZeroV in
|
2026-05-09 16:34:47 +00:00
|
|
|
(mem_set mem' id v', types, vals, visited)
|
2026-05-10 16:56:15 +00:00
|
|
|
| RefT _ -> raise @@ Eval_error "write: ref type"
|
|
|
|
|
| TupleT _ -> raise @@ Eval_error "write: tuple type"
|
2026-04-29 09:16:24 +00:00
|
|
|
| _ -> raise @@ Eval_error "write: type")
|
2026-05-06 16:14:35 +00:00
|
|
|
| ReadS p -> if pathval mem vals p == SmthV || pathval mem vals p == BotV
|
|
|
|
|
then raise @@ Eval_error "read: spoiled value"
|
|
|
|
|
else if pathval mem vals p != ZeroV
|
|
|
|
|
then raise @@ Eval_error "read: nontrivial value"
|
2026-04-29 09:16:24 +00:00
|
|
|
else state
|
|
|
|
|
| SeqS (sl, sr) -> let statel = stmt_eval state sl in
|
|
|
|
|
stmt_eval statel sr
|
|
|
|
|
| ChoiceS (sl, sr) -> let statel = stmt_eval state sl in
|
|
|
|
|
let stater = stmt_eval state sr in
|
2026-05-09 16:34:47 +00:00
|
|
|
match statel with (meml, typesl, valsl, visitedl) ->
|
|
|
|
|
match stater with (memr, typesr, valsr, visitedr) ->
|
2026-04-29 09:16:24 +00:00
|
|
|
if typesl != typesr || valsl != valsr
|
|
|
|
|
then raise @@ Eval_error "choice"
|
2026-05-09 16:34:47 +00:00
|
|
|
(* TODO: FIXME: better list union ?? *)
|
|
|
|
|
else (memcomb meml memr, typesl, valsl, visitedl @ visitedr)
|
2026-04-29 09:16:24 +00:00
|
|
|
|
2026-05-05 14:35:35 +00:00
|
|
|
(* --- program execution --- *)
|
2026-04-29 15:12:45 +00:00
|
|
|
|
2026-05-05 14:35:35 +00:00
|
|
|
let prog_eval (prog : prog) : state =
|
|
|
|
|
match prog with (decls, s) ->
|
|
|
|
|
let init_state = prog_init prog in
|
|
|
|
|
stmt_eval init_state s
|
2026-04-29 15:12:45 +00:00
|
|
|
|
2026-05-05 14:35:35 +00:00
|
|
|
let prog_eval_noret (prog : prog) : unit =
|
|
|
|
|
ignore @@ prog_eval prog
|
2026-04-29 15:12:45 +00:00
|
|
|
|
|
|
|
|
(* --- tests --- *)
|
|
|
|
|
|
2026-05-01 13:40:56 +00:00
|
|
|
(* - shortcuts *)
|
|
|
|
|
|
|
|
|
|
let ( #. ) x y = SeqS (x, y)
|
2026-05-10 13:44:35 +00:00
|
|
|
let ( |. ) x y = ChoiceS (x, y)
|
2026-05-01 13:40:56 +00:00
|
|
|
|
2026-05-06 15:01:34 +00:00
|
|
|
let v0 = VarP 0
|
|
|
|
|
let v1 = VarP 1
|
|
|
|
|
let v2 = VarP 2
|
|
|
|
|
let v3 = VarP 3
|
|
|
|
|
let v4 = VarP 4
|
|
|
|
|
let v5 = VarP 5
|
2026-05-06 16:14:35 +00:00
|
|
|
let v6 = VarP 6
|
|
|
|
|
let v7 = VarP 7
|
|
|
|
|
let v8 = VarP 8
|
|
|
|
|
let vg0 = VarP globals_min_id
|
2026-05-06 15:01:34 +00:00
|
|
|
let vg1 = VarP (globals_min_id + 1)
|
|
|
|
|
let vg2 = VarP (globals_min_id + 2)
|
|
|
|
|
let vg3 = VarP (globals_min_id + 3)
|
|
|
|
|
let vg4 = VarP (globals_min_id + 4)
|
|
|
|
|
let vg5 = VarP (globals_min_id + 5)
|
2026-05-06 16:14:35 +00:00
|
|
|
let vg6 = VarP (globals_min_id + 6)
|
|
|
|
|
let vg7 = VarP (globals_min_id + 7)
|
|
|
|
|
let vg8 = VarP (globals_min_id + 8)
|
2026-05-10 13:44:35 +00:00
|
|
|
let vg9 = VarP (globals_min_id + 9)
|
|
|
|
|
let vg10 = VarP (globals_min_id + 10)
|
2026-05-06 15:01:34 +00:00
|
|
|
|
|
|
|
|
let rf0E = RefE 0
|
|
|
|
|
let rf1E = RefE 1
|
|
|
|
|
let rf2E = RefE 2
|
|
|
|
|
let rf3E = RefE 3
|
|
|
|
|
let rf4E = RefE 4
|
|
|
|
|
let rf5E = RefE 5
|
2026-05-06 16:14:35 +00:00
|
|
|
let rf3E = RefE 3
|
|
|
|
|
let rf4E = RefE 4
|
|
|
|
|
let rf5E = RefE 5
|
2026-05-06 15:01:34 +00:00
|
|
|
let rfg0E = RefE globals_min_id
|
|
|
|
|
let rfg1E = RefE (globals_min_id + 1)
|
|
|
|
|
let rfg2E = RefE (globals_min_id + 2)
|
|
|
|
|
let rfg3E = RefE (globals_min_id + 3)
|
|
|
|
|
let rfg4E = RefE (globals_min_id + 4)
|
|
|
|
|
let rfg5E = RefE (globals_min_id + 5)
|
2026-05-06 16:14:35 +00:00
|
|
|
let rfg6E = RefE (globals_min_id + 6)
|
|
|
|
|
let rfg7E = RefE (globals_min_id + 7)
|
|
|
|
|
let rfg8E = RefE (globals_min_id + 8)
|
|
|
|
|
|
2026-05-06 15:01:34 +00:00
|
|
|
let pE p = PathE p
|
2026-05-01 13:40:56 +00:00
|
|
|
|
|
|
|
|
let drf p = DerefP p
|
2026-05-10 13:44:35 +00:00
|
|
|
let access i p = AccessP (p, i)
|
2026-05-01 13:40:56 +00:00
|
|
|
|
|
|
|
|
let wr x = ReadS x
|
|
|
|
|
let rd x = WriteS x
|
|
|
|
|
let skp = SkipS
|
|
|
|
|
|
|
|
|
|
let uT_r_aw = UnitT (Rd, AlwaysWr)
|
|
|
|
|
let uT_r_mw = UnitT (Rd, MayWr)
|
|
|
|
|
let uT_aw = UnitT (NRd, AlwaysWr)
|
|
|
|
|
let uT_mw = UnitT (NRd, MayWr)
|
|
|
|
|
let uT_r = UnitT (Rd, NeverWr)
|
|
|
|
|
let uT = UnitT (NRd, NeverWr)
|
|
|
|
|
|
|
|
|
|
let rfT t = RefT (Rf, t)
|
|
|
|
|
let cpT t = RefT (Cp, t)
|
|
|
|
|
|
|
|
|
|
let moded t = ((In, NOut), t)
|
|
|
|
|
|
2026-05-06 15:01:34 +00:00
|
|
|
let defgu t = VarD (t, UnitE)
|
|
|
|
|
let defg t e = VarD (t, e)
|
|
|
|
|
|
|
|
|
|
let wrS p = WriteS p
|
|
|
|
|
let rdS p = ReadS p
|
|
|
|
|
let callS f args = CallS (f, args)
|
2026-05-01 13:40:56 +00:00
|
|
|
|
|
|
|
|
(* - utils tests *)
|
|
|
|
|
|
|
|
|
|
let%expect_test "mem add / get / set" =
|
|
|
|
|
let mem = empty_mem in
|
|
|
|
|
let (mem, id1) = mem_add mem ZeroV in
|
|
|
|
|
let (mem, id2) = mem_add mem SmthV in
|
|
|
|
|
let (mem, id3) = mem_add mem BotV in
|
|
|
|
|
Printf.printf "%i %i %i " id1 id2 id3;
|
|
|
|
|
Printf.printf "%b %b %b " (mem_get mem id1 == ZeroV)
|
|
|
|
|
(mem_get mem id2 == SmthV)
|
|
|
|
|
(mem_get mem id3 == BotV);
|
|
|
|
|
let mem = mem_set mem id1 BotV in
|
|
|
|
|
let mem = mem_set mem id2 ZeroV in
|
|
|
|
|
let mem = mem_set mem id3 SmthV in
|
|
|
|
|
Printf.printf "%b %b %b" (mem_get mem id1 == BotV)
|
|
|
|
|
(mem_get mem id2 == ZeroV)
|
|
|
|
|
(mem_get mem id3 == SmthV);
|
|
|
|
|
[%expect {| 0 1 2 true true true true true true |}]
|
|
|
|
|
|
|
|
|
|
(* - basic var tests *)
|
2026-04-29 15:12:45 +00:00
|
|
|
|
|
|
|
|
let%expect_test "empty" =
|
|
|
|
|
prog_eval_noret ([], SkipS);
|
|
|
|
|
Printf.printf "done!";
|
|
|
|
|
[%expect {| done! |}]
|
|
|
|
|
|
|
|
|
|
let%expect_test "simple var" =
|
2026-05-08 12:06:53 +00:00
|
|
|
prog_eval_noret ([VarD (UnitT (Rd, MayWr), UnitE)],
|
|
|
|
|
ReadS (VarP globals_min_id));
|
2026-04-29 15:12:45 +00:00
|
|
|
Printf.printf "done!";
|
|
|
|
|
[%expect {| done! |}]
|
|
|
|
|
|
2026-05-08 12:06:53 +00:00
|
|
|
let%expect_test "simple var, forbidden read" =
|
|
|
|
|
try(prog_eval_noret ([VarD (UnitT (NRd, MayWr), UnitE)],
|
|
|
|
|
ReadS (VarP globals_min_id));
|
2026-04-29 15:12:45 +00:00
|
|
|
[%expect.unreachable]);
|
|
|
|
|
with Eval_error msg -> Printf.printf "%s" msg;
|
2026-05-06 16:14:35 +00:00
|
|
|
[%expect {| read: spoiled value |}]
|
2026-04-29 15:12:45 +00:00
|
|
|
|
2026-05-01 13:40:56 +00:00
|
|
|
let%expect_test "simple vars, no read & read" =
|
|
|
|
|
prog_eval_noret ([VarD (UnitT (NRd, MayWr), UnitE);
|
|
|
|
|
VarD (UnitT (Rd, MayWr), UnitE)],
|
|
|
|
|
ReadS (VarP (globals_min_id + 1)));
|
|
|
|
|
Printf.printf "done!";
|
|
|
|
|
[%expect {| done! |}]
|
|
|
|
|
|
|
|
|
|
let%expect_test "simple var, write" =
|
2026-05-08 12:06:53 +00:00
|
|
|
prog_eval_noret ([VarD (UnitT (NRd, MayWr), UnitE)],
|
|
|
|
|
WriteS (VarP globals_min_id));
|
2026-05-01 13:40:56 +00:00
|
|
|
Printf.printf "done!";
|
|
|
|
|
[%expect {| done! |}]
|
|
|
|
|
|
2026-05-08 12:06:53 +00:00
|
|
|
let%expect_test "simple var, forbidden write" =
|
|
|
|
|
try(prog_eval_noret ([VarD (UnitT (NRd, NeverWr), UnitE)],
|
|
|
|
|
WriteS (VarP globals_min_id));
|
2026-05-01 13:40:56 +00:00
|
|
|
[%expect.unreachable]);
|
|
|
|
|
with Eval_error msg -> Printf.printf "%s" msg;
|
|
|
|
|
[%expect {| write: write tag |}]
|
|
|
|
|
|
|
|
|
|
let%expect_test "simple var, write & read" =
|
2026-05-08 12:06:53 +00:00
|
|
|
prog_eval_noret ([VarD (UnitT (NRd, MayWr), UnitE)],
|
|
|
|
|
SeqS (WriteS (VarP globals_min_id),
|
|
|
|
|
ReadS (VarP globals_min_id)));
|
2026-05-01 13:40:56 +00:00
|
|
|
Printf.printf "done!";
|
|
|
|
|
[%expect {| done! |}]
|
|
|
|
|
|
|
|
|
|
(* - basic call tests *)
|
|
|
|
|
|
2026-05-06 15:01:34 +00:00
|
|
|
(* let%expect_test "simple call with read" = *)
|
|
|
|
|
(* prog_eval_noret ([VarD (UnitT (Rd, NeverWr), UnitE); *)
|
2026-05-08 12:06:53 +00:00
|
|
|
(* FunD ([((In, NOut), UnitT (Rd, NeverWr)], ReadS (VarP 0)))], *)
|
2026-05-06 15:01:34 +00:00
|
|
|
(* CallS (VarP (globals_min_id + 1), *)
|
|
|
|
|
(* [PathE (VarP globals_min_id)])); *)
|
|
|
|
|
(* Printf.printf "done!"; *)
|
|
|
|
|
(* [%expect {| done! |}] *)
|
|
|
|
|
|
|
|
|
|
(* let%expect_test "simple call with write" = *)
|
|
|
|
|
(* prog_eval_noret ([VarD ((UnitT (Rd, MayWr)), UnitE); *)
|
2026-05-08 14:50:36 +00:00
|
|
|
(* VarD (RefT (Rf, UnitT (Rd, MayWr)), RefE globals_min_id); *)
|
2026-05-08 12:06:53 +00:00
|
|
|
(* FunD ([((In, NOut), RefT (Cp, UnitT (Rd, MayWr)))], WriteS (DerefP (VarP 0)))], *)
|
2026-05-06 15:01:34 +00:00
|
|
|
(* CallS (VarP (globals_min_id + 2), *)
|
|
|
|
|
(* [PathE (VarP (globals_min_id + 1))])); *)
|
|
|
|
|
(* Printf.printf "done!"; *)
|
|
|
|
|
(* [%expect {| done! |}] *)
|
|
|
|
|
|
|
|
|
|
let%expect_test "simple call with read, dsl" =
|
|
|
|
|
prog_eval_noret (
|
|
|
|
|
[
|
|
|
|
|
defgu uT_r_mw;
|
|
|
|
|
defg (rfT uT_r_mw) rfg0E;
|
|
|
|
|
FunD (
|
|
|
|
|
[moded @@ cpT @@ uT_r],
|
|
|
|
|
rdS @@ drf @@ v0
|
|
|
|
|
)
|
|
|
|
|
],
|
|
|
|
|
callS vg2 [pE vg1]
|
|
|
|
|
);
|
|
|
|
|
Printf.printf "done!";
|
|
|
|
|
[%expect {| done! |}]
|
|
|
|
|
|
|
|
|
|
let%expect_test "simple call with write, dsl" =
|
|
|
|
|
prog_eval_noret (
|
|
|
|
|
[
|
|
|
|
|
defgu uT_r_mw;
|
|
|
|
|
defg (rfT uT_r_mw) rfg0E;
|
|
|
|
|
FunD (
|
|
|
|
|
[moded @@ cpT @@ uT_r_mw],
|
|
|
|
|
wrS @@ drf @@ v0
|
|
|
|
|
)
|
|
|
|
|
],
|
|
|
|
|
callS vg2 [pE vg1]
|
|
|
|
|
);
|
|
|
|
|
Printf.printf "done!";
|
|
|
|
|
[%expect {| done! |}]
|
|
|
|
|
|
|
|
|
|
let%expect_test "simple call with read after write, dsl" =
|
|
|
|
|
prog_eval_noret (
|
|
|
|
|
[
|
|
|
|
|
defgu uT_r_mw;
|
|
|
|
|
defg (rfT uT_r_mw) rfg0E;
|
|
|
|
|
FunD (
|
|
|
|
|
[moded @@ cpT @@ uT_mw],
|
|
|
|
|
(wrS @@ drf @@ v0) #.
|
|
|
|
|
(rdS @@ drf @@ v0)
|
|
|
|
|
)
|
|
|
|
|
],
|
|
|
|
|
callS vg2 [pE vg1]
|
|
|
|
|
);
|
|
|
|
|
Printf.printf "done!";
|
|
|
|
|
[%expect {| done! |}]
|
|
|
|
|
|
|
|
|
|
let%expect_test "simple call with forbidden write, dsl" =
|
|
|
|
|
try (prog_eval_noret (
|
|
|
|
|
[
|
|
|
|
|
defgu uT_r_mw;
|
|
|
|
|
defg (rfT uT_r_mw) rfg0E;
|
|
|
|
|
FunD (
|
|
|
|
|
[moded @@ cpT @@ uT_r],
|
|
|
|
|
wrS @@ drf @@ v0
|
|
|
|
|
)
|
|
|
|
|
],
|
|
|
|
|
callS vg2 [pE vg1]
|
|
|
|
|
);
|
|
|
|
|
[%expect.unreachable]);
|
|
|
|
|
with Eval_error msg -> Printf.printf "%s" msg;
|
|
|
|
|
[%expect {| write: write tag |}]
|
|
|
|
|
|
|
|
|
|
(* TODO: FIXME: why is condition on always write in parent ?? *)
|
|
|
|
|
let%expect_test "simple call with write to ref, dsl" =
|
|
|
|
|
prog_eval_noret (
|
|
|
|
|
[
|
|
|
|
|
defgu uT_r_aw;
|
|
|
|
|
defg (rfT uT_r_aw) rfg0E;
|
|
|
|
|
FunD (
|
|
|
|
|
[moded @@ rfT @@ uT_aw],
|
|
|
|
|
wrS @@ drf @@ v0
|
|
|
|
|
)
|
|
|
|
|
],
|
|
|
|
|
callS vg2 [pE vg1]
|
|
|
|
|
);
|
|
|
|
|
Printf.printf "done!";
|
|
|
|
|
[%expect {| done! |}]
|
|
|
|
|
|
|
|
|
|
let%expect_test "simple call with forbidden write to ref, dsl" =
|
|
|
|
|
try (prog_eval_noret (
|
|
|
|
|
[
|
|
|
|
|
defgu uT_r_aw;
|
|
|
|
|
defg (rfT uT_r_aw) rfg0E;
|
|
|
|
|
FunD (
|
|
|
|
|
[moded @@ rfT @@ uT_aw],
|
|
|
|
|
wrS @@ drf @@ v0
|
|
|
|
|
)
|
|
|
|
|
],
|
|
|
|
|
(callS vg2 [pE vg1]) #.
|
|
|
|
|
(rdS @@ drf @@ vg1)
|
|
|
|
|
);
|
|
|
|
|
[%expect.unreachable]);
|
|
|
|
|
with Eval_error msg -> Printf.printf "%s" msg;
|
2026-05-06 16:14:35 +00:00
|
|
|
[%expect {| read: spoiled value |}]
|
2026-05-06 15:01:34 +00:00
|
|
|
|
2026-05-06 16:18:42 +00:00
|
|
|
let%expect_test "simple call with write to ref with fix, dsl" =
|
|
|
|
|
prog_eval_noret (
|
|
|
|
|
[
|
|
|
|
|
defgu uT_r_aw;
|
|
|
|
|
defg (rfT uT_r_aw) rfg0E;
|
|
|
|
|
FunD (
|
|
|
|
|
[moded @@ rfT @@ uT_aw],
|
|
|
|
|
wrS @@ drf @@ v0
|
|
|
|
|
)
|
|
|
|
|
],
|
|
|
|
|
(callS vg2 [pE vg1]) #.
|
|
|
|
|
(wrS @@ drf @@ vg1) #.
|
|
|
|
|
(rdS @@ drf @@ vg1)
|
|
|
|
|
);
|
|
|
|
|
Printf.printf "done!";
|
|
|
|
|
[%expect {| done! |}]
|
|
|
|
|
|
2026-05-06 15:20:44 +00:00
|
|
|
let%expect_test "call inside call, dsl" =
|
|
|
|
|
prog_eval_noret (
|
|
|
|
|
[
|
|
|
|
|
defgu uT_r_aw;
|
|
|
|
|
defg (rfT uT_r_aw) rfg0E;
|
|
|
|
|
FunD (
|
|
|
|
|
[moded @@ rfT @@ uT_aw],
|
|
|
|
|
wrS @@ drf @@ v0
|
|
|
|
|
);
|
|
|
|
|
FunD (
|
|
|
|
|
[moded @@ cpT @@ uT_aw],
|
|
|
|
|
(callS vg2 [pE v0]) #.
|
|
|
|
|
(wrS @@ drf @@ v0)
|
|
|
|
|
)
|
|
|
|
|
],
|
|
|
|
|
(callS vg3 [pE vg1]) #.
|
|
|
|
|
(rdS @@ drf @@ vg1)
|
|
|
|
|
);
|
|
|
|
|
Printf.printf "done!";
|
|
|
|
|
[%expect {| done! |}]
|
2026-05-06 15:01:34 +00:00
|
|
|
|
2026-05-09 16:34:47 +00:00
|
|
|
(* NOTE: memoization used *)
|
|
|
|
|
let%expect_test "call inside call, recursive, dsl" =
|
|
|
|
|
prog_eval_noret (
|
|
|
|
|
[
|
|
|
|
|
defgu uT_r_aw;
|
|
|
|
|
defg (rfT uT_r_aw) rfg0E;
|
|
|
|
|
FunD (
|
|
|
|
|
[moded @@ cpT @@ uT_aw],
|
|
|
|
|
(callS vg2 [pE v0]) #.
|
|
|
|
|
(wrS @@ drf @@ v0)
|
|
|
|
|
)
|
|
|
|
|
],
|
|
|
|
|
(callS vg2 [pE vg1]) #.
|
|
|
|
|
(rdS @@ drf @@ vg1)
|
|
|
|
|
);
|
|
|
|
|
Printf.printf "done!";
|
|
|
|
|
[%expect {| done! |}]
|
|
|
|
|
|
2026-05-06 16:18:42 +00:00
|
|
|
let%expect_test "call to fix after call, dsl" =
|
|
|
|
|
prog_eval_noret (
|
|
|
|
|
[
|
|
|
|
|
defgu uT_r_aw;
|
|
|
|
|
defg (rfT uT_r_aw) rfg0E;
|
|
|
|
|
FunD (
|
|
|
|
|
[moded @@ rfT @@ uT_aw],
|
|
|
|
|
wrS @@ drf @@ v0
|
|
|
|
|
);
|
|
|
|
|
FunD (
|
|
|
|
|
[((In, Out), rfT @@ uT_aw)],
|
|
|
|
|
wrS @@ drf @@ v0
|
|
|
|
|
)
|
|
|
|
|
],
|
|
|
|
|
(callS vg2 [pE vg1]) #.
|
|
|
|
|
(callS vg3 [pE vg1]) #.
|
|
|
|
|
(rdS @@ drf @@ vg1)
|
|
|
|
|
);
|
|
|
|
|
Printf.printf "done!";
|
|
|
|
|
[%expect {| done! |}]
|
|
|
|
|
|
2026-05-06 15:01:34 +00:00
|
|
|
let%expect_test "simple call with global variable usage, dsl" =
|
|
|
|
|
prog_eval_noret (
|
|
|
|
|
[
|
|
|
|
|
defgu uT_r_aw;
|
|
|
|
|
defg (rfT uT_r_aw) rfg0E;
|
|
|
|
|
FunD (
|
|
|
|
|
[moded @@ cpT @@ uT_aw],
|
|
|
|
|
(wrS @@ vg0) #.
|
|
|
|
|
(rdS @@ drf @@ vg1)
|
|
|
|
|
)
|
|
|
|
|
],
|
|
|
|
|
(callS vg2 [pE vg1]) #.
|
|
|
|
|
(rdS @@ drf @@ vg1)
|
|
|
|
|
);
|
2026-05-01 13:40:56 +00:00
|
|
|
Printf.printf "done!";
|
|
|
|
|
[%expect {| done! |}]
|
|
|
|
|
|
2026-05-06 15:01:34 +00:00
|
|
|
let%expect_test "simple call with read & write (2 args), dsl" =
|
|
|
|
|
prog_eval_noret (
|
|
|
|
|
[
|
|
|
|
|
defgu uT_r_aw;
|
|
|
|
|
defg (rfT uT_r_aw) rfg0E;
|
|
|
|
|
defgu uT_r_aw;
|
2026-05-06 16:14:35 +00:00
|
|
|
defg (rfT uT_r_aw) rfg2E;
|
2026-05-06 15:01:34 +00:00
|
|
|
FunD (
|
|
|
|
|
[
|
|
|
|
|
moded @@ rfT @@ uT_r;
|
|
|
|
|
moded @@ rfT @@ uT_aw;
|
|
|
|
|
],
|
|
|
|
|
(rdS @@ drf @@ v0) #.
|
|
|
|
|
(wrS @@ drf @@ v1)
|
|
|
|
|
)
|
|
|
|
|
],
|
|
|
|
|
callS vg4 [pE vg1; pE vg3]
|
|
|
|
|
);
|
2026-05-01 13:40:56 +00:00
|
|
|
Printf.printf "done!";
|
|
|
|
|
[%expect {| done! |}]
|
|
|
|
|
|
2026-05-06 16:14:35 +00:00
|
|
|
let%expect_test "simple call with different arguments modifiers, copy, dsl" =
|
|
|
|
|
prog_eval_noret (
|
|
|
|
|
[
|
|
|
|
|
defgu uT_r_aw;
|
|
|
|
|
defg (rfT uT_r_aw) rfg0E;
|
|
|
|
|
defgu uT_r_aw;
|
|
|
|
|
defg (rfT uT_r_aw) rfg2E;
|
|
|
|
|
defgu uT_r_aw;
|
|
|
|
|
defg (rfT uT_r_aw) rfg4E;
|
|
|
|
|
defgu uT_r_aw;
|
|
|
|
|
defg (rfT uT_r_aw) rfg6E;
|
|
|
|
|
FunD (
|
|
|
|
|
[
|
|
|
|
|
((NIn, NOut), cpT @@ uT_aw);
|
|
|
|
|
((In, NOut), cpT @@ uT_r_aw);
|
|
|
|
|
((NIn, Out), cpT @@ uT_aw);
|
|
|
|
|
((In, Out), cpT @@ uT_r_aw);
|
|
|
|
|
],
|
|
|
|
|
(rdS @@ drf @@ v1) #.
|
|
|
|
|
(rdS @@ drf @@ v3) #.
|
|
|
|
|
(wrS @@ drf @@ v1) #.
|
|
|
|
|
(wrS @@ drf @@ v2) #.
|
|
|
|
|
(wrS @@ drf @@ v3)
|
|
|
|
|
)
|
|
|
|
|
],
|
|
|
|
|
(callS vg8 [pE vg1; pE vg3; pE vg5; pE vg7]) #.
|
|
|
|
|
(rdS @@ drf @@ vg1) #.
|
|
|
|
|
(rdS @@ drf @@ vg3) #.
|
|
|
|
|
(rdS @@ drf @@ vg5) #.
|
|
|
|
|
(rdS @@ drf @@ vg7)
|
|
|
|
|
);
|
|
|
|
|
Printf.printf "done!";
|
|
|
|
|
[%expect {| done! |}]
|
|
|
|
|
|
|
|
|
|
let%expect_test "simple call with different arguments modifiers, ref, dsl" =
|
|
|
|
|
prog_eval_noret (
|
|
|
|
|
[
|
|
|
|
|
defgu uT_r_aw;
|
|
|
|
|
defg (rfT uT_r_aw) rfg0E;
|
|
|
|
|
defgu uT_r_aw;
|
|
|
|
|
defg (rfT uT_r_aw) rfg2E;
|
|
|
|
|
defgu uT_r_aw;
|
|
|
|
|
defg (rfT uT_r_aw) rfg4E;
|
|
|
|
|
defgu uT_r_aw;
|
|
|
|
|
defg (rfT uT_r_aw) rfg6E;
|
|
|
|
|
FunD (
|
|
|
|
|
[
|
|
|
|
|
((NIn, NOut), rfT @@ uT);
|
|
|
|
|
((In, NOut), rfT @@ uT_r);
|
|
|
|
|
((NIn, Out), rfT @@ uT_aw);
|
|
|
|
|
((In, Out), rfT @@ uT_r_aw);
|
|
|
|
|
],
|
|
|
|
|
(rdS @@ drf @@ v1) #.
|
|
|
|
|
(rdS @@ drf @@ v3) #.
|
|
|
|
|
(wrS @@ drf @@ v2) #.
|
|
|
|
|
(wrS @@ drf @@ v3)
|
|
|
|
|
)
|
|
|
|
|
],
|
|
|
|
|
(callS vg8 [pE vg1; pE vg3; pE vg5; pE vg7]) #.
|
|
|
|
|
(rdS @@ drf @@ vg1) #.
|
|
|
|
|
(rdS @@ drf @@ vg3) #.
|
|
|
|
|
(rdS @@ drf @@ vg5) #.
|
|
|
|
|
(rdS @@ drf @@ vg7)
|
|
|
|
|
);
|
|
|
|
|
Printf.printf "done!";
|
|
|
|
|
[%expect {| done! |}]
|
|
|
|
|
|
2026-05-10 13:44:35 +00:00
|
|
|
(* - complex tests *)
|
|
|
|
|
|
2026-05-10 16:56:15 +00:00
|
|
|
(* NOTE: path access isreversed to intuitive function application
|
|
|
|
|
by definition *)
|
2026-05-10 13:44:35 +00:00
|
|
|
let%expect_test "complex test: send, dsl" =
|
|
|
|
|
prog_eval_noret (
|
|
|
|
|
(* TODO: set optimal ref mods later *)
|
|
|
|
|
let user_utilsT = TupleT [uT_r_aw (* 0 id *); uT_r_aw] in
|
|
|
|
|
let user_infoT = TupleT [uT_r_aw (* 0 name *); uT_r_aw; uT_r_aw] in
|
|
|
|
|
let userT = TupleT [cpT user_utilsT (* 0 utils *); cpT user_infoT (* 1 info *)] in
|
|
|
|
|
let versionT = TupleT [uT_r_aw (* 0 id *); uT_r_aw; uT_r_aw] in
|
|
|
|
|
let utilsT = TupleT [uT_r_aw (* 0 has_version *); uT_r_aw (* 1 id *)] in
|
|
|
|
|
let requestT = TupleT [cpT userT (* 0 user *);
|
|
|
|
|
cpT versionT (* 1 version *);
|
|
|
|
|
cpT utilsT (* 2 utils *);
|
|
|
|
|
cpT uT_r_aw (* 3 data *);
|
|
|
|
|
uT_r_aw (* 4 operation_date *)] in
|
|
|
|
|
let user_utilsE = TupleE [UnitE (* 0 id *); UnitE] in
|
|
|
|
|
let user_infoE = TupleE [UnitE (* 0 name *); UnitE; UnitE] in
|
|
|
|
|
let userE = TupleE [rfg0E (* 0 utils *); rfg1E (* 1 info *)] in
|
|
|
|
|
let versionE = TupleE [UnitE (* 0 id *); UnitE; UnitE] in
|
|
|
|
|
let utilsE = TupleE [UnitE (* 0 has_version *); UnitE (* 1 id *)] in
|
|
|
|
|
let requestE = TupleE [rfg2E (* 0 user *);
|
|
|
|
|
rfg3E (* 1 version *);
|
|
|
|
|
rfg4E (* 2 utils *);
|
|
|
|
|
rfg5E (* 3 data *);
|
|
|
|
|
UnitE (* 4 operation_date *)] in
|
|
|
|
|
let get_version_idID = vg7 in
|
|
|
|
|
let updated_versionID = vg8 in
|
|
|
|
|
let sendID = vg9 in
|
|
|
|
|
let send_allID = vg10 in
|
|
|
|
|
let get_version_idF = FunD ([moded requestT],
|
2026-05-10 16:56:15 +00:00
|
|
|
(rdS @@ access 0 @@ drf @@ access 1 v0) |. skp) in
|
2026-05-10 13:44:35 +00:00
|
|
|
let updated_versionF = FunD ([moded requestT],
|
2026-05-10 16:56:15 +00:00
|
|
|
(rdS @@ access 0 @@ drf @@ access 2 v0) #.
|
2026-05-10 13:44:35 +00:00
|
|
|
(* TODO: read all the substructure ?? *)
|
2026-05-10 16:56:15 +00:00
|
|
|
(rdS @@ access 0 @@ drf @@ access 1 v0) #.
|
|
|
|
|
(rdS @@ access 1 @@ drf @@ access 1 v0)) in
|
2026-05-10 13:44:35 +00:00
|
|
|
let sendF = FunD ([moded requestT],
|
2026-05-10 16:56:15 +00:00
|
|
|
((
|
|
|
|
|
(wrS @@ access 0 @@ drf @@ access 2 v0) #.
|
|
|
|
|
(rdS @@ drf @@ access 3 v0) #.
|
2026-05-10 17:19:00 +00:00
|
|
|
(wrS @@ drf @@ access 3 v0) #.
|
2026-05-10 16:56:15 +00:00
|
|
|
(rdS @@ access 0 @@ drf @@ access 1 @@ drf @@ access 0 v0)
|
|
|
|
|
) |. skp) #.
|
|
|
|
|
(wrS @@ access 4 v0) #.
|
2026-05-10 13:44:35 +00:00
|
|
|
(* TODO: read all the substructure ?? *)
|
2026-05-10 16:56:15 +00:00
|
|
|
(rdS @@ access 4 v0) (*rdS v0*)) in (* FIXME: TMP, parial read, should be full *)
|
2026-05-10 13:44:35 +00:00
|
|
|
let send_allF = FunD ([moded requestT],
|
|
|
|
|
(wrS @@ access 4 v0) (*wrS v0*) #. (* FIXME: TMP, parial write, should be full *)
|
2026-05-10 16:56:15 +00:00
|
|
|
(callS sendID [pE v0]) #.
|
|
|
|
|
(callS get_version_idID [pE v0]) #.
|
|
|
|
|
(callS updated_versionID [pE v0]) #.
|
2026-05-10 13:44:35 +00:00
|
|
|
(* TODO: read all the substructure ?? *)
|
2026-05-10 16:56:15 +00:00
|
|
|
(wrS @@ access 0 @@ drf @@ access 1 v0) #.
|
|
|
|
|
(wrS @@ access 1 @@ drf @@ access 1 v0) #.
|
2026-05-10 13:44:35 +00:00
|
|
|
(* --- *)
|
2026-05-10 16:56:15 +00:00
|
|
|
((rdS @@ access 0 @@ drf @@ access 0 @@ drf @@ access 0 v0) |.
|
|
|
|
|
(rdS @@ access 0 @@ drf @@ access 1 v0))) in
|
2026-05-10 13:44:35 +00:00
|
|
|
let varID = vg6 in
|
|
|
|
|
[
|
|
|
|
|
defg user_utilsT user_utilsE;
|
|
|
|
|
defg user_infoT user_infoE;
|
|
|
|
|
defg userT userE;
|
|
|
|
|
defg versionT versionE;
|
|
|
|
|
defg utilsT utilsE;
|
|
|
|
|
defgu uT_r_aw;
|
|
|
|
|
defg requestT requestE;
|
|
|
|
|
get_version_idF;
|
|
|
|
|
updated_versionF;
|
|
|
|
|
sendF;
|
|
|
|
|
send_allF
|
|
|
|
|
],
|
|
|
|
|
callS send_allID [pE varID]
|
|
|
|
|
);
|
|
|
|
|
Printf.printf "done!";
|
|
|
|
|
[%expect {| done! |}]
|
2026-05-06 16:14:35 +00:00
|
|
|
|
2026-05-10 17:34:45 +00:00
|
|
|
(* TODO: version with more optimal modifiers *)
|
2026-03-29 15:32:35 +00:00
|
|
|
end
|