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
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
(* SPDX-License-Identifier: AGPL-3.0-or-later *)
(* Copyright © 2021-2024 OCamlPro *)
(* Written by the Owi programmers *)
open Types
open Fmt
open Syntax
(*
unop ::= '-' ==> Neg
binop ::= '+' ==> Plus
| '-' ==> Minus
| '*' ==> Mult
| '/' ==> Div
term ::= '(' pterm ')' ==> pterm
| i32 ==> match Int32.of_string i32 with Some i32 -> Int32 i32
| ind ==> match parse_text_id ind with Some ind -> Var (Text ind)
| 'result' ==> Result None
pterm ::= 'i32' i32 ==> match Int32.of_string i32 with Some i32 -> Int32 i32 | None -> `Spec_invalid_int32 i32
| 'i64' i64 ==> match Int64.of_string i64 with Some i64 -> Int64 i64 | None -> `Spec_invalid_int64 i64
| 'f32' f32 ==> match Float32.of_string f32 with Some f32 -> Float32 f32 | None -> `Spec_invalid_float32 f32
| 'f64' f64 ==> match Float64.of_string f64 with Some f64 -> Float64 f64 | None -> `Spec_invalid_float64 f64
| 'param' ind ==> let* ind = parse_indice ind in ParamVar ind
| 'global' ind ==> let* ind = parse_indice ind in GlobalVar ind
| 'binder' ind ==> let* ind = parse_indice ind in BinderVar ind
| unop term_1 ==> Unop (unop, term_1)
| binop term_1 term_2 ==> BinOp (binop, term_1, term_2)
| 'result' i ==> Result (Some i)
| 'memory' term_1 ==> Memory term_1
binpred ::= '>=' ==> Ge
| '>' ==> Gt
| '<=' ==> Le
| '<' ==> Lt
| '=' ==> Eq
| '!=' ==> Neq
unconnect ::= '!' ==> Not
binconnect ::= '&&' ==> And
| '||' ==> Or
| '==>' ==> Imply
| '<==>' ==> Equiv
prop ::= '(' pprop ')' ==> pprop
| 'true' ==> Const true
| 'false' ==> Const false
binder ::= 'forall' ==> Forall
| 'exists' ==> Exists
binder_type ::= 'i32' ==> I32
| 'i64' ==> I64
| 'f32' ==> F32
| 'f64' ==> F64
pprop ::= binpred term_1 term_2 ==> BinPred (binpred, term_1, term_2)
| unconnect prop_1 ==> UnConnect (unconnect, prop_1)
| binconnect prop_1 prop_2 ==> BinConnect (binconnect, prop_1, prop_2)
| binder binder_type prop_1 ==> Binder (binder, binder_type, None, prop_1)
| binder binder_type ind prop_1 ==> let* ind = (parse_text_id_result ind) in
Binder (binder, binder_type, Some ind, prop_1)
*)
type nonrec binpred =
| Ge
| Gt
| Le
| Lt
| Eq
| Neq
type nonrec unconnect = Not
type nonrec binconnect =
| And
| Or
| Imply
| Equiv
type nonrec binder =
| Forall
| Exists
type nonrec binder_type = num_type
type nonrec unop = Neg
type nonrec binop =
| Plus
| Minus
| Mult
| Div
type 'a term =
| Int32 : Int32.t -> 'a term
| Int64 : Int64.t -> 'a term
| Float32 : Float32.t -> 'a term
| Float64 : Float64.t -> 'a term
| Var : text indice -> text term
| ParamVar : 'a indice -> 'a term
| GlobalVar : 'a indice -> 'a term
| BinderVar : 'a indice -> 'a term
| UnOp : unop * 'a term -> 'a term
| BinOp : binop * 'a term * 'a term -> 'a term
| Result : int option -> 'a term
| Memory : 'a term -> 'a term
type 'a prop =
| Const : bool -> 'a prop
| BinPred : binpred * 'a term * 'a term -> 'a prop
| UnConnect : unconnect * 'a prop -> 'a prop
| BinConnect : binconnect * 'a prop * 'a prop -> 'a prop
| Binder : binder * binder_type * string option * 'a prop -> 'a prop
let pp_binpred fmt = function
| Ge -> pf fmt "≥"
| Gt -> pf fmt ">"
| Le -> pf fmt "≤"
| Lt -> pf fmt "<"
| Eq -> pf fmt "="
| Neq -> pf fmt "≠"
let pp_unconnect fmt = function Not -> pf fmt "¬"
let pp_binconnect fmt = function
| And -> pf fmt "∧"
| Or -> pf fmt "∨"
| Imply -> pf fmt "⇒"
| Equiv -> pf fmt "⇔"
let pp_binder fmt = function Forall -> pf fmt "∀" | Exists -> pf fmt "∃"
let pp_binder_type = pp_num_type
let pp_unop fmt = function Neg -> pf fmt "-"
let pp_binop fmt = function
| Plus -> pf fmt "+"
| Minus -> pf fmt "-"
| Mult -> pf fmt "*"
| Div -> pf fmt "/"
let rec pp_term : type a. formatter -> a term -> unit =
fun fmt -> function
| Int32 i32 -> pf fmt "(i32 %i)" (Int32.to_int i32)
| Int64 i64 -> pf fmt "(i64 %i)" (Int64.to_int i64)
| Float32 f32 -> pf fmt "(f32 %a)" Float32.pp f32
| Float64 f64 -> pf fmt "(f64 %a)" Float64.pp f64
| Var ind -> pf fmt "%a" pp_indice ind
| ParamVar ind -> pf fmt "(param %a)" pp_indice ind
| GlobalVar ind -> pf fmt "(global %a)" pp_indice ind
| BinderVar ind -> pf fmt "(binder %a)" pp_indice ind
| UnOp (u, tm1) -> pf fmt "@[<hv 2>(%a@ %a)@]" pp_unop u pp_term tm1
| BinOp (b, tm1, tm2) ->
pf fmt "@[<hv 2>(%a@ %a@ %a)@]" pp_binop b pp_term tm1 pp_term tm2
| Result (Some i) -> pf fmt "(result %i)" i
| Result None -> pf fmt "result"
| Memory tm1 -> pf fmt "(memory %a)" pp_term tm1
let rec pp_prop : type a. formatter -> a prop -> unit =
fun fmt -> function
| Const bool -> pf fmt "%a" Fmt.bool bool
| BinPred (b, tm1, tm2) ->
pf fmt "@[<hv 2>(%a@ %a@ %a)@]" pp_binpred b pp_term tm1 pp_term tm2
| UnConnect (u, pr1) -> pf fmt "@[<hv 2>(%a@ %a)@]" pp_unconnect u pp_prop pr1
| BinConnect (b, pr1, pr2) ->
pf fmt "@[<hv 2>(%a@ %a@ %a)@]" pp_binconnect b pp_prop pr1 pp_prop pr2
| Binder (b, bt, id_opt, pr1) -> (
match id_opt with
| Some id ->
pf fmt "@[<hv 2>(%a %a:%a@ %a)@]" pp_binder b pp_id id pp_binder_type bt
pp_prop pr1
| None ->
pf fmt "@[<hv 2>(%a %a@ %a)@]" pp_binder b pp_binder_type bt pp_prop pr1 )
let valid_text_indice_char = function
| '0' .. '9'
| 'a' .. 'z'
| 'A' .. 'Z'
| '!' | '#' | '$' | '%' | '&' | '\'' | '*' | '+' | '-' | '.' | '/' | ':' | '<'
| '=' | '>' | '?' | '@' | '\\' | '^' | '_' | '`' | '|' | '~' ->
true
| _ -> false
let parse_text_id id =
let len = String.length id in
if len >= 2 then
let hd = String.get id 0 in
let tl = String.sub id 1 (len - 1) in
if Char.equal hd '$' && String.for_all valid_text_indice_char id then
Some tl
else None
else None
let parse_text_id_result id =
let len = String.length id in
if len >= 2 then
let hd = String.get id 0 in
let tl = String.sub id 1 (len - 1) in
if Char.equal hd '$' && String.for_all valid_text_indice_char id then Ok tl
else Error (`Spec_invalid_text_indice id)
else Error (`Spec_invalid_text_indice id)
let parse_raw_id id = int_of_string id
let parse_indice id =
match (parse_text_id id, parse_raw_id id) with
| Some id, _ -> Ok (Text id)
| _, Some id -> Ok (Raw id)
| _, _ -> Error (`Spec_invalid_indice id)
let parse_binder_type =
let open Sexp in
function
| Atom "i32" -> Ok I32
| Atom "i64" -> Ok I64
| Atom "f32" -> Ok F32
| Atom "f64" -> Ok F64
| bt -> Error (`Spec_unknown_binder_type bt)
let rec parse_term =
let open Sexp in
function
| Atom a as tm -> begin
(* Int32 *)
match Int32.of_string a with
| Some i32 -> Ok (Int32 i32)
| None -> (
(* Var *)
match parse_text_id a with
| Some ind -> Ok (Var (Text ind))
| None ->
(* Result *)
if String.equal "result" a then Ok (Result None) (* Invalid *)
else Error (`Spec_unknown_term tm) )
end
(* Result *)
| List [ Atom "result"; Atom i ] -> (
match int_of_string i with
| Some i -> Ok (Result (Some i))
| None -> Error (`Spec_invalid_int32 i) )
(* Int32 *)
| List [ Atom "i32"; Atom i32 ] -> (
match Int32.of_string i32 with
| Some i32 -> ok @@ Int32 i32
| None -> Error (`Spec_invalid_int32 i32) )
(* Int64 *)
| List [ Atom "i64"; Atom i64 ] -> (
match Int64.of_string i64 with
| Some i64 -> ok @@ Int64 i64
| None -> Error (`Spec_invalid_int64 i64) )
(* Float32 *)
| List [ Atom "f32"; Atom f32 ] -> (
match Float32.of_string f32 with
| Some f32 -> ok @@ Float32 f32
| None -> Error (`Spec_invalid_float32 f32) )
(* Float64 *)
| List [ Atom "f64"; Atom f64 ] -> (
match Float64.of_string f64 with
| Some f64 -> ok @@ Float64 f64
| None -> Error (`Spec_invalid_float64 f64) )
(* ParamVar *)
| List [ Atom "param"; Atom ind ] ->
let+ ind = parse_indice ind in
ParamVar ind
(* GlobalVar *)
| List [ Atom "global"; Atom ind ] ->
let+ ind = parse_indice ind in
GlobalVar ind
(* BinderVar *)
| List [ Atom "binder"; Atom ind ] ->
let+ ind = parse_indice ind in
BinderVar ind
(* UnOp *)
| List [ Atom "-"; tm1 ] ->
let+ tm1 = parse_term tm1 in
UnOp (Neg, tm1)
(* BinOp *)
| List [ Atom "+"; tm1; tm2 ] ->
let* tm1 = parse_term tm1 in
let+ tm2 = parse_term tm2 in
BinOp (Plus, tm1, tm2)
| List [ Atom "-"; tm1; tm2 ] ->
let* tm1 = parse_term tm1 in
let+ tm2 = parse_term tm2 in
BinOp (Minus, tm1, tm2)
| List [ Atom "*"; tm1; tm2 ] ->
let* tm1 = parse_term tm1 in
let+ tm2 = parse_term tm2 in
BinOp (Mult, tm1, tm2)
| List [ Atom "/"; tm1; tm2 ] ->
let* tm1 = parse_term tm1 in
let+ tm2 = parse_term tm2 in
BinOp (Div, tm1, tm2)
(* Memory *)
| List [ Atom "memory"; tm1 ] ->
let+ tm1 = parse_term tm1 in
Memory tm1
(* Invalid *)
| tm -> Error (`Spec_unknown_term tm)
let rec parse_prop =
let open Sexp in
function
(* Const *)
| Atom "true" -> ok @@ Const true
| Atom "false" -> ok @@ Const false
(* BinPred *)
| List [ Atom (">=" | "≥"); tm1; tm2 ] ->
let* tm1 = parse_term tm1 in
let+ tm2 = parse_term tm2 in
BinPred (Ge, tm1, tm2)
| List [ Atom ">"; tm1; tm2 ] ->
let* tm1 = parse_term tm1 in
let+ tm2 = parse_term tm2 in
BinPred (Gt, tm1, tm2)
| List [ Atom ("<=" | "≤"); tm1; tm2 ] ->
let* tm1 = parse_term tm1 in
let+ tm2 = parse_term tm2 in
BinPred (Le, tm1, tm2)
| List [ Atom "<"; tm1; tm2 ] ->
let* tm1 = parse_term tm1 in
let+ tm2 = parse_term tm2 in
BinPred (Lt, tm1, tm2)
| List [ Atom "="; tm1; tm2 ] ->
let* tm1 = parse_term tm1 in
let+ tm2 = parse_term tm2 in
BinPred (Eq, tm1, tm2)
| List [ Atom ("!=" | "≠"); tm1; tm2 ] ->
let* tm1 = parse_term tm1 in
let+ tm2 = parse_term tm2 in
BinPred (Neq, tm1, tm2)
(* UnConnect *)
| List [ Atom ("!" | "¬"); pr1 ] ->
let+ pr1 = parse_prop pr1 in
UnConnect (Not, pr1)
(* BinConnect *)
| List [ Atom ("&&" | "∧"); pr1; pr2 ] ->
let* pr1 = parse_prop pr1 in
let+ pr2 = parse_prop pr2 in
BinConnect (And, pr1, pr2)
| List [ Atom ("||" | "∨"); pr1; pr2 ] ->
let* pr1 = parse_prop pr1 in
let+ pr2 = parse_prop pr2 in
BinConnect (Or, pr1, pr2)
| List [ Atom ("==>" | "⇒"); pr1; pr2 ] ->
let* pr1 = parse_prop pr1 in
let+ pr2 = parse_prop pr2 in
BinConnect (Imply, pr1, pr2)
| List [ Atom ("<==>" | "⇔"); pr1; pr2 ] ->
let* pr1 = parse_prop pr1 in
let+ pr2 = parse_prop pr2 in
BinConnect (Equiv, pr1, pr2)
(* Binder *)
| List [ Atom ("forall" | "∀"); bt; pr1 ] ->
let* bt = parse_binder_type bt in
let+ pr1 = parse_prop pr1 in
Binder (Forall, bt, None, pr1)
| List [ Atom ("forall" | "∀"); bt; Atom ind; pr1 ] ->
let* bt = parse_binder_type bt in
let* ind = parse_text_id_result ind in
let+ pr1 = parse_prop pr1 in
Binder (Forall, bt, Some ind, pr1)
| List [ Atom ("exists" | "∃"); bt; pr1 ] ->
let* bt = parse_binder_type bt in
let+ pr1 = parse_prop pr1 in
Binder (Exists, bt, None, pr1)
| List [ Atom ("exists" | "∃"); bt; Atom ind; pr1 ] ->
let* bt = parse_binder_type bt in
let* ind = parse_text_id_result ind in
let+ pr1 = parse_prop pr1 in
Binder (Exists, bt, Some ind, pr1)
(* invalid *)
| _ as pr -> Error (`Spec_unknown_prop pr)