package p4spectec

  1. Overview
  2. Docs
P4-SpecTec: A mechanization toolchain for the P4 Programming Language

Install

dune-project
 Dependency

Authors

Maintainers

Sources

v0.1.2.tar.gz
md5=1a3bc0a385fe1ecf403c019f49aa6de6
sha512=5d20b5821f33e2a3a5419b208606f27c01511994c2b3b1e1cdf4c077056dfd0aa81682af0720e1060ee2bfb0341918fcc4c53159820205a2bc32b725e5c1a714

doc/src/p4spectec.domain/mixfix.ml.html

Source file mixfix.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
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
open Util.Source

type atom = Atom.t phrase [@@deriving yojson]

type 'a t =
  | Arg of 'a
  | Atom of atom
  | Brack of atom * 'a t * atom
  | Infix of 'a t * atom * 'a t
  | Seq of 'a t list
[@@deriving yojson]

type mixop = unit t

exception Arity_mismatch of string

(* Json serialization and deserialization *)

let rec mixop_to_yojson = function
  | Arg () -> `List [ `String "Arg"; `Null ]
  | Atom atom -> `List [ `String "Atom"; atom_to_yojson atom ]
  | Brack (atom_l, mixop, atom_r) ->
      `List
        [
          `String "Brack";
          atom_to_yojson atom_l;
          mixop_to_yojson mixop;
          atom_to_yojson atom_r;
        ]
  | Infix (mixop_l, atom, mixop_r) ->
      `List
        [
          `String "Infix";
          mixop_to_yojson mixop_l;
          atom_to_yojson atom;
          mixop_to_yojson mixop_r;
        ]
  | Seq mixops ->
      `List [ `String "Seq"; `List (List.map mixop_to_yojson mixops) ]

let rec mixop_of_yojson = function
  | `List [ `String "Arg"; `Null ] -> Ok (Arg ())
  | `List [ `String "Atom"; json_atom ] -> (
      match atom_of_yojson json_atom with
      | Ok atom -> Ok (Atom atom)
      | Error _ as err -> err)
  | `List [ `String "Brack"; json_atom_l; json_mixop; json_atom_r ] -> (
      match atom_of_yojson json_atom_l with
      | Error _ as err -> err
      | Ok atom_l -> (
          match mixop_of_yojson json_mixop with
          | Error _ as err -> err
          | Ok mixop -> (
              match atom_of_yojson json_atom_r with
              | Ok atom_r -> Ok (Brack (atom_l, mixop, atom_r))
              | Error _ as err -> err)))
  | `List [ `String "Infix"; json_mixop_l; json_atom; json_mixop_r ] -> (
      match mixop_of_yojson json_mixop_l with
      | Error _ as err -> err
      | Ok mixop_l -> (
          match atom_of_yojson json_atom with
          | Error _ as err -> err
          | Ok atom -> (
              match mixop_of_yojson json_mixop_r with
              | Ok mixop_r -> Ok (Infix (mixop_l, atom, mixop_r))
              | Error _ as err -> err)))
  | `List [ `String "Seq"; `List json_mixops ] -> (
      let rec loop acc = function
        | [] -> Ok (List.rev acc)
        | json_mixop :: json_mixops -> (
            match mixop_of_yojson json_mixop with
            | Ok mixop -> loop (mixop :: acc) json_mixops
            | Error _ as err -> err)
      in
      match loop [] json_mixops with
      | Ok mixops -> Ok (Seq mixops)
      | Error _ as err -> err)
  | _ -> Error "Mixfix.mixop_of_yojson"

(* Equality and comparison *)

let compare_atom (atom_a : atom) (atom_b : atom) =
  Atom.compare atom_a.it atom_b.it

let rec compare : type a b. compare_arg:(a -> b -> int) -> a t -> b t -> int =
 fun ~compare_arg mixfix_a mixfix_b ->
  if Obj.repr mixfix_a == Obj.repr mixfix_b then 0
  else
    let tag = function
      | Arg _ -> 0
      | Atom _ -> 1
      | Brack _ -> 2
      | Infix _ -> 3
      | Seq _ -> 4
    in
    match (mixfix_a, mixfix_b) with
    | Arg arg_a, Arg arg_b -> compare_arg arg_a arg_b
    | Atom atom_a, Atom atom_b -> compare_atom atom_a atom_b
    | Brack (atom_a_l, mixfix_a, atom_a_r), Brack (atom_b_l, mixfix_b, atom_b_r)
      ->
        let c = compare_atom atom_a_l atom_b_l in
        if c <> 0 then c
        else
          let c = compare ~compare_arg mixfix_a mixfix_b in
          if c <> 0 then c else compare_atom atom_a_r atom_b_r
    | ( Infix (mixfix_a_l, atom_a, mixfix_a_r),
        Infix (mixfix_b_l, atom_b, mixfix_b_r) ) ->
        let c = compare ~compare_arg mixfix_a_l mixfix_b_l in
        if c <> 0 then c
        else
          let c = compare_atom atom_a atom_b in
          if c <> 0 then c else compare ~compare_arg mixfix_a_r mixfix_b_r
    | Seq mixfixes_a, Seq mixfixes_b ->
        let rec compare_mixfixes mixfixes_a mixfixes_b =
          match (mixfixes_a, mixfixes_b) with
          | [], [] -> 0
          | [], _ :: _ -> -1
          | _ :: _, [] -> 1
          | mixfix_a :: mixfixes_a, mixfix_b :: mixfixes_b ->
              let c = compare ~compare_arg mixfix_a mixfix_b in
              if c <> 0 then c else compare_mixfixes mixfixes_a mixfixes_b
        in
        compare_mixfixes mixfixes_a mixfixes_b
    | _ -> Int.compare (tag mixfix_a) (tag mixfix_b)

let rec eq : type a b. eq_arg:(a -> b -> bool) -> a t -> b t -> bool =
 fun ~eq_arg mixfix_a mixfix_b ->
  Obj.repr mixfix_a == Obj.repr mixfix_b
  ||
  match (mixfix_a, mixfix_b) with
  | Arg arg_a, Arg arg_b -> eq_arg arg_a arg_b
  | Atom atom_a, Atom atom_b -> Atom.eq atom_a.it atom_b.it
  | Brack (atom_a_l, mixfix_a, atom_a_r), Brack (atom_b_l, mixfix_b, atom_b_r)
    ->
      Atom.eq atom_a_l.it atom_b_l.it
      && eq ~eq_arg mixfix_a mixfix_b
      && Atom.eq atom_a_r.it atom_b_r.it
  | ( Infix (mixfix_a_l, atom_a, mixfix_a_r),
      Infix (mixfix_b_l, atom_b, mixfix_b_r) ) ->
      Atom.eq atom_a.it atom_b.it
      && eq ~eq_arg mixfix_a_l mixfix_b_l
      && eq ~eq_arg mixfix_a_r mixfix_b_r
  | Seq mixfixes_a, Seq mixfixes_b -> eqs ~eq_arg mixfixes_a mixfixes_b
  | _ -> false

and eqs : type a b. eq_arg:(a -> b -> bool) -> a t list -> b t list -> bool =
 fun ~eq_arg mixfixes_a mixfixes_b ->
  match (mixfixes_a, mixfixes_b) with
  | [], [] -> true
  | mixfix_a :: mixfixes_a, mixfix_b :: mixfixes_b ->
      eq ~eq_arg mixfix_a mixfix_b && eqs ~eq_arg mixfixes_a mixfixes_b
  | _ -> false

let compare_mixop (mixfix_a : 'a t) (mixfix_b : 'b t) =
  compare ~compare_arg:(fun _ _ -> 0) mixfix_a mixfix_b

let eq_mixop (mixfix_a : 'a t) (mixfix_b : 'b t) =
  eq ~eq_arg:(fun _ _ -> true) mixfix_a mixfix_b

(* Fold, map, and iter *)

let rec fold (f : 'acc -> 'a -> 'acc) (acc : 'acc) (mixfix : 'a t) =
  match mixfix with
  | Arg arg -> f acc arg
  | Atom _ -> acc
  | Brack (_, mixfix, _) -> fold f acc mixfix
  | Infix (mixfix_l, _, mixfix_r) -> fold f (fold f acc mixfix_l) mixfix_r
  | Seq mixfixes -> List.fold_left (fold f) acc mixfixes

let rec map (f : 'a -> 'b) = function
  | Arg arg -> Arg (f arg)
  | Atom atom -> Atom atom
  | Brack (atom_l, mixfix, atom_r) -> Brack (atom_l, map f mixfix, atom_r)
  | Infix (mixfix_l, atom, mixfix_r) ->
      Infix (map f mixfix_l, atom, map f mixfix_r)
  | Seq mixfixes -> Seq (List.map (map f) mixfixes)

let rec map_atoms (f : atom -> atom) = function
  | Arg arg -> Arg arg
  | Atom atom -> Atom (f atom)
  | Brack (atom_l, mixfix, atom_r) ->
      Brack (f atom_l, map_atoms f mixfix, f atom_r)
  | Infix (mixfix_l, atom, mixfix_r) ->
      Infix (map_atoms f mixfix_l, f atom, map_atoms f mixfix_r)
  | Seq mixfixes -> Seq (List.map (map_atoms f) mixfixes)

let iter (f : 'a -> unit) (mixfix : 'a t) =
  fold
    (fun () arg ->
      f arg;
      ())
    () mixfix

let iter_atoms (f : atom -> unit) (mixfix : 'a t) =
  ignore
    (map_atoms
       (fun atom ->
         f atom;
         atom)
       mixfix)

(* Conversion *)

let to_string (mixfix : 'a t) =
  let rec to_string' = function
    | Arg _ -> "%"
    | Atom atom -> Atom.render_atom atom.it
    | Brack (atom_l, mixfix, atom_r) ->
        Atom.render_atom atom_l.it ^ to_string' mixfix
        ^ Atom.render_atom atom_r.it
    | Infix (mixfix_l, atom, mixfix_r) ->
        to_string' mixfix_l ^ Atom.render_atom atom.it ^ to_string' mixfix_r
    | Seq mixfixes -> String.concat " " (List.map to_string' mixfixes)
  in
  "`" ^ to_string' mixfix ^ "`"

let to_mixop (mixfix : 'a t) : mixop = map (fun _ -> ()) mixfix

(* Arity *)

let arity (mixfix : 'a t) = fold (fun arity _ -> arity + 1) 0 mixfix

(* Atoms and args *)

let rec atoms (mixfix : 'a t) =
  match mixfix with
  | Arg _ -> []
  | Atom atom -> [ atom ]
  | Brack (atom_l, mixfix, atom_r) -> (atom_l :: atoms mixfix) @ [ atom_r ]
  | Infix (mixfix_l, atom, mixfix_r) ->
      atoms mixfix_l @ [ atom ] @ atoms mixfix_r
  | Seq mixfixes ->
      List.fold_left
        (fun atoms_acc mixfix -> atoms_acc @ atoms mixfix)
        [] mixfixes

type atom_internal = Atom_internal of atom | Arg_internal

let atoms_matrix (mixfix : 'a t) =
  let rec atoms (atoms_acc : atom_internal list) (mixfix : 'a t) =
    match mixfix with
    | Arg _ -> Arg_internal :: atoms_acc
    | Atom atom -> Atom_internal atom :: atoms_acc
    | Brack (atom_l, mixfix, atom_r) ->
        Atom_internal atom_r :: atoms (Atom_internal atom_l :: atoms_acc) mixfix
    | Infix (mixfix_l, atom, mixfix_r) ->
        atoms (Atom_internal atom :: atoms atoms_acc mixfix_l) mixfix_r
    | Seq mixfixes -> List.fold_left atoms atoms_acc mixfixes
  in
  let atoms_internal = List.rev (atoms [] mixfix) in
  let rec split atoms_acc atoms_curr = function
    | [] -> List.rev (List.rev atoms_curr :: atoms_acc)
    | Arg_internal :: rest -> split (List.rev atoms_curr :: atoms_acc) [] rest
    | Atom_internal atom :: rest -> split atoms_acc (atom :: atoms_curr) rest
  in
  split [] [] atoms_internal

let args (mixfix : 'a t) =
  let rec args' args_rev = function
    | Arg arg -> arg :: args_rev
    | Atom _ -> args_rev
    | Brack (_, mixfix, _) -> args' args_rev mixfix
    | Infix (mixfix_l, _, mixfix_r) ->
        let args_rev = args' args_rev mixfix_r in
        args' args_rev mixfix_l
    | Seq mixfixes ->
        List.fold_right
          (fun mixfix args_rev -> args' args_rev mixfix)
          mixfixes args_rev
  in
  args' [] mixfix

(* Filling and splitting *)

let fill (mixop : mixop) (args : 'a list) : 'a t =
  let rec fill' mixop args =
    match mixop with
    | Arg () -> (
        match args with
        | arg :: args -> (Arg arg, args)
        | [] -> raise (Arity_mismatch "Mixfix.fill: too few arguments"))
    | Atom atom -> (Atom atom, args)
    | Brack (atom_l, mixop, atom_r) ->
        let mixfix, args = fill' mixop args in
        (Brack (atom_l, mixfix, atom_r), args)
    | Infix (mixop_l, atom, mixop_r) ->
        let mixfix_l, args = fill' mixop_l args in
        let mixfix_r, args = fill' mixop_r args in
        (Infix (mixfix_l, atom, mixfix_r), args)
    | Seq mixops ->
        let mixfixes, args =
          List.fold_left
            (fun (mixfixes_rev, args) mixop ->
              let mixfix, args = fill' mixop args in
              (mixfix :: mixfixes_rev, args))
            ([], args) mixops
        in
        (Seq (List.rev mixfixes), args)
  in
  match fill' mixop args with
  | mixfix, [] -> mixfix
  | _, _ :: _ -> raise (Arity_mismatch "Mixfix.fill: too many arguments")

let split (mixfix : 'a t) = (to_mixop mixfix, args mixfix)

(* Rendering *)

let assemble ~(empty : 'b) ~(space : 'b) ~(atom : atom -> 'b option)
    ~(concat : 'b -> 'b -> 'b) (mixfix : 'b t) : 'b =
  let join (pieces : 'b option list) : 'b option =
    match List.filter_map Fun.id pieces with
    | [] -> None
    | piece :: pieces ->
        Some
          (List.fold_left
             (fun acc piece -> concat (concat acc space) piece)
             piece pieces)
  in
  let rec go = function
    | Arg arg -> Some arg
    | Atom atom' -> atom atom'
    | Brack (atom_l, mixfix, atom_r) ->
        join [ atom atom_l; go mixfix; atom atom_r ]
    | Infix (mixfix_l, atom', mixfix_r) ->
        join [ go mixfix_l; atom atom'; go mixfix_r ]
    | Seq mixfixes -> join (List.map go mixfixes)
  in
  go mixfix |> Option.value ~default:empty

let render ~(string_of_atom : atom -> string) ~(string_of_arg : 'a -> string)
    (mixfix : 'a t) =
  assemble ~empty:""
    ~atom:(fun a -> match string_of_atom a with "" -> None | s -> Some s)
    ~space:" " ~concat:( ^ ) (map string_of_arg mixfix)