1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
(* SPDX-License-Identifier: AGPL-3.0-or-later *)
(* Copyright © 2021-2024 OCamlPro *)
(* Written by the Owi programmers *)

open Types
open Fmt
open Spec
open Syntax

type 'a t =
  { funcid : 'a indice
  ; preconditions : 'a prop list
  ; postconditions : 'a prop list
  }

let compare_funcid c1 c2 = compare_indice c1.funcid c2.funcid

let join_contract { preconditions = pre1; postconditions = post1; funcid }
  { preconditions = pre2; postconditions = post2; _ } =
  let preconditions = pre1 @ pre2 in
  let postconditions = post1 @ post2 in
  { funcid; preconditions; postconditions }

let pp_contract fmt { funcid; preconditions; postconditions } =
  pf fmt
    "@[<v>Contract of function %a@,\
     Preconditions:@;\
     <1 2>@[<v>%a@]@,\
     Postconditions:@;\
     <1 2>@[<v>%a@]@]"
    pp_indice funcid
    (list ~sep:pp_newline pp_prop)
    preconditions
    (list ~sep:pp_newline pp_prop)
    postconditions

let parse_contract =
  let open Sexp in
  function
  | List (Atom funcid :: conds) ->
    let aux (l1, l2) = function
      | List [ Atom "requires"; precond ] ->
        let+ precond = parse_prop precond in
        (precond :: l1, l2)
      | List [ Atom "ensures"; postcond ] ->
        let+ postcond = parse_prop postcond in
        (l1, postcond :: l2)
      | cl -> Error (`Unknown_annotation_clause cl)
    in
    let* funcid = parse_indice funcid in
    let+ preconditions, postconditions = list_fold_left aux ([], []) conds in
    let preconditions = List.rev preconditions in
    let postconditions = List.rev postconditions in
    { funcid; preconditions; postconditions }
  | annot -> Error (`Unknown_annotation_object annot)