package archetype

  1. Overview
  2. Docs

Source file printer_pt_markdown.ml

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
(* -------------------------------------------------------------------------- *)
open Ident
open Tools
open Location
open ParseTree
open Printer_tools

let cmp_lident i1 i2 : bool = String.equal (unloc i1) (unloc i2)

let pp_literal fmt (l : literal) =
  match l with
  | Lint      n -> Format.fprintf fmt "%s" (Big_int.string_of_big_int n)
  | Lnat      n -> Format.fprintf fmt "%sn" (Big_int.string_of_big_int n)
  | Ldecimal  n -> Format.fprintf fmt "%s" n
  | Ltz       n -> Format.fprintf fmt "%stz"   (Big_int.string_of_big_int n)
  | Lmtz      n -> Format.fprintf fmt "%smtz"  (Big_int.string_of_big_int n)
  | Lutz      n -> Format.fprintf fmt "%sutz"  (Big_int.string_of_big_int n)
  | Laddress  a -> Format.fprintf fmt "%s" a
  | Lstring   s -> Format.fprintf fmt "\"%s\"" s
  | Lbool     b -> Format.fprintf fmt "%s" (if b then "true" else "false")
  | Lduration d -> Format.fprintf fmt "%s" d
  | Ldate     d -> Format.fprintf fmt "%s" d
  | Lbytes    s -> Format.fprintf fmt "0x%s" s
  | Lpercent  n -> Format.fprintf fmt "%s%%"  (Big_int.string_of_big_int n)

let pp_expr fmt e =
  match unloc e with
  | Eliteral l -> pp_literal fmt l
  | _ -> Printer_pt.pp_simple_expr fmt e
let pp_archetype fmt pt =

  let pp_marchetype fmt es =
    let decls =  List.map unloc es in

    let pp_title fmt _ =
      let name = List.fold_left (fun accu -> function | Darchetype (x, _) -> unloc x | _ -> accu) "" decls in
      Format.fprintf fmt "# %a@\n\
                          > Genrated with [Archetype](%a) v%a@\n@\n" (* date ? *)
        pp_str name
        pp_str Options.url
        pp_str Options.version
    in

    let pp_extension fmt (e : extension_unloc) =
      match e with
      | Eextension (id, _) -> pp_id fmt id
    in

    let pp_roles fmt _ =
      let pp_variable_decl fmt (id, _type_, dv, variable_kind, _invs, exts : variable_decl) =
        Format.fprintf fmt
          "### %a@\n@\n\
           | Attribute              | Value  |@\n\
           |----------------|---|---|@\n\
           | Kind           | %a  |@\n\
           | Address        | %a  |@\n\
           %a@\n"
          pp_id id
          (fun fmt ->
             function
             | VKvariable -> pp_str fmt "variable"
             | VKconstant -> pp_str fmt "constant") variable_kind
          (pp_option pp_expr) dv
          (fun fmt xs ->
             if Option.is_none xs
             then ()
             else
               let xs = xs |> Option.get |> List.map unloc in
               Format.fprintf fmt "| Extension      |  %a |@\n"
                 (pp_list ", " pp_extension) xs
          ) exts
      in
      let roles : variable_decl list =
        List.fold_right (fun x accu -> x |> unloc |> function | Dvariable ((_, {pldesc = Tref {pldesc = "role"}; _}, _, _, _, _) as a) -> a::accu | _ -> accu) es []
      in
      match roles with
      | [] -> ()
      | _ ->
        Format.fprintf fmt "## Roles@\n@\n%a@\n"
          (pp_list "@\n" pp_variable_decl) roles
    in

    let pp_assets fmt _ =
      let pp_asset_decl fmt ((name, fields, shadow_fields, aopts, _ , _, _) : asset_decl) =
        let keys : lident list = List.fold_right (fun x accu -> match x with AOidentifiedby ks -> ks @ accu | _ -> accu) aopts [] in
        let orders : lident list = List.fold_left (fun accu x -> match x with AOsortedby s -> s::accu | _ -> accu) [] aopts in
        let fields = fields @ shadow_fields |> List.map unloc in
        let pp_asset_field fmt (f : field_unloc) =
          match f with
          | Ffield (id, type_, _dv, _exts) ->
            let attributes : ident list =
              []
              |>
              (fun l ->
                 if List.exists (cmp_lident id) orders
                 then "order"::l
                 else l)
              |> (fun l ->
                  if List.exists (cmp_lident id) keys
                  then "__key__"::l
                  else l)
            in
            Format.fprintf fmt "| %a |  | %a | %a"
              pp_id id
              Printer_pt.pp_type type_
              (pp_list ", " pp_str) attributes
        in
        Format.fprintf fmt "### %a@\n@\n\
                            | Field | Desc | Type | Attribute |@\n\
                            |--|--|--|--|@\n\
                            %a@\n@\n"
          pp_id name
          (pp_list "@\n" pp_asset_field) fields
      in
      let assets : asset_decl list =
        List.fold_right (fun x accu -> x |> unloc |> function | Dasset a -> a::accu | _ -> accu) es []
      in
      match assets with
      | [] -> ()
      | _ ->
        Format.fprintf fmt "## Assets@\n@\n%a"
          (pp_list "@\n" pp_asset_decl) assets
    in

    let pp_called_by = (pp_option (fun fmt (x, _) -> Format.fprintf fmt "`called by ` %a@\n" pp_expr x)) in
    let pp_entries fmt _ =
      let pp_entry_decl fmt ((name, args, entry_properties, _ , _exts) : entry_decl) =
        let pp_formula fmt (label, f : ident * expr) =
          Format.fprintf fmt "##### %a@\n`%a`"
            pp_str label
            pp_expr f
        in
        let pp_args fmt l =
          let pp_arg fmt (id, type_, _exts : lident_typ) =
            Format.fprintf fmt "|%a||%a|"
              pp_id id
              Printer_pt.pp_type type_
          in
          if List.is_empty l
          then ()
          else
            Format.fprintf fmt "| Name | Desc | Type |@\n\
                                |--|--|--|@\n\
                                %a@\n"
              (pp_list "@\n" pp_arg) l
        in
        let pp_formulas fmt (l : (ident * expr) list) =
          if List.is_empty l
          then ()
          else
            Format.fprintf fmt "#### Postconditions @\n%a@\n"
              (pp_list "@\n" pp_formula) l
        in
        let formulas : (ident * expr) list =
          entry_properties.spec_fun
          |> Option.get_as_list
          |> List.map unloc
          |> List.map fst
          |> List.flatten
          |> List.map unloc
          |>  (fun l -> List.fold_right (fun x accu ->
              match x with
              | Vpostcondition (l, e, _, _, _) -> (unloc l, e)::accu
              | _ -> accu
            ) l [])
        in
        let pp_rf name fmt (l : ((lident * expr * expr option) list * exts) option) =
          let l =
            l
            |> Option.get_as_list
            |> List.map fst
            |> List.flatten
            |> List.map (fun (x, y, _) -> unloc x, y)
          in
          if List.is_empty l
          then ()
          else
            Format.fprintf fmt "#### %a @\n%a@\n"
              pp_str name
              (pp_list "@\n" pp_formula) l
        in
        Format.fprintf fmt "### %a@\n" pp_id name;
        pp_called_by fmt entry_properties.calledby;
        pp_args fmt args;
        (pp_rf "require") fmt entry_properties.require;
        (pp_rf "failif") fmt entry_properties.failif;
        pp_formulas fmt formulas;
      in
      let entries : entry_decl list =
        List.fold_right (fun x accu -> x |> unloc |> function | Dentry a -> a::accu | _ -> accu) es []
      in
      match entries with
      | [] -> ()
      | _ ->
        Format.fprintf fmt "## entries@\n@\n%a"
          (pp_list "@\n" pp_entry_decl) entries
    in

    let pp_transitions fmt _ =
      let pp_transition_decl fmt (name, _args, _, _, entry_properties, _transitions, _exts : transition_decl) =
        Format.fprintf fmt "### %a@\n" pp_id name;
        pp_called_by fmt entry_properties.calledby;
      in
      let transitions : transition_decl list =
        List.fold_right (fun x accu -> x |> unloc |> function | Dtransition a -> a::accu | _ -> accu) es []
      in
      match transitions with
      | [] -> ()
      | _ ->
        Format.fprintf fmt "## Transitions@\n@\n%a"
          (pp_list "@\n" pp_transition_decl) transitions
    in

    let pp_sec_preds fmt _ =
      let rec pp_security_arg fmt arg =
        let arg = unloc arg in
        match arg with
        | Sident id -> pp_id fmt id
        | Sdot (a, b) ->
          Format.fprintf fmt "%a.%a"
            pp_id a
            pp_id b
        | Slist l ->
          Format.fprintf fmt "[%a]"
            (pp_list " or " pp_security_arg) l
        | Sapp (id, args) ->
          Format.fprintf fmt "(%a %a)"
            pp_id id
            (pp_list "@ " pp_security_arg) args
        | Sbut (id, arg) ->
          Format.fprintf fmt "(%a but %a)"
            pp_id id
            pp_security_arg arg
        | Sto (id, arg) ->
          Format.fprintf fmt "(%a to %a)"
            pp_id id
            pp_security_arg arg
      in
      let pp_security_item fmt (s : security_item) =
        let (label, id, args) = unloc s in
        Format.fprintf fmt "##### %a@\n\
                            `%a %a`"
          pp_id label
          pp_id id
          (pp_list " " pp_security_arg) args
      in
      let pp_security_items =
        pp_list "@\n" pp_security_item
      in
      let security_items : security_item list =
        List.fold_right (
          fun x accu ->
            x
            |> unloc
            |> function
            | Dsecurity s -> (
                s
                |> unloc
                |> fst
                |> fun x -> x @ accu)
            | _ -> accu) es []
      in
      match security_items with
      | [] -> ()
      | _ ->
        Format.fprintf fmt "## Security predicates@\n@\n%a@\n@\n"
          pp_security_items security_items
    in

    pp_title fmt ();
    pp_roles fmt ();
    pp_assets fmt ();
    pp_transitions fmt ();
    pp_entries fmt ();
    pp_sec_preds fmt ()
  in

  match unloc pt with
  | Marchetype es ->
    pp_marchetype fmt es
  | Mextension (_id, _ds, _es) -> ()

(* -------------------------------------------------------------------------- *)
let string_of__of_pp pp x =
  Format.asprintf "%a@." pp x

let show_model (x : archetype) = string_of__of_pp pp_archetype x