forked from LPCIC/coq-elpi
-
Notifications
You must be signed in to change notification settings - Fork 0
/
example_fuzzer.v
99 lines (81 loc) · 2.78 KB
/
example_fuzzer.v
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
From elpi Require Import elpi.
(** Intrinsically typed data type and semantics, from software foundations.
We devise a command to fuzz the semantics by flipping some operators.
We do it by locally checking that the fuzzing produces welltyped terms,
reducing a bit the nondeterminism of the fuzzer.
*)
Inductive ty := B | N.
Inductive Exp : ty -> Type :=
| NUM : nat -> Exp N
| BOOL : bool -> Exp B
| PLUS : Exp N -> Exp N -> Exp N
| AND : Exp B -> Exp B -> Exp B
| OR : Exp B -> Exp B-> Exp B
| EQ : Exp N -> Exp N -> Exp B.
Inductive Val : ty -> Set :=
| iNv : nat -> Val N
| iBv : bool -> Val B.
Inductive eval : forall {T: ty}, Exp T -> Val T -> Prop :=
| E_Num n :
eval (NUM n) (iNv n)
| E_Bool b :
eval (BOOL b) (iBv b)
| E_Plus e1 e2 n1 n2 :
eval e1 (iNv n1) ->
eval e2 (iNv n2) ->
eval (PLUS e1 e2) (iNv (n1 + n2))
| E_AND e1 e2 b1 b2 :
eval e1 (iBv b1) ->
eval e2 (iBv b2) ->
eval (AND e1 e2) (iBv (b1 && b2))
| E_OR e1 e2 b1 b2 :
eval e1 (iBv b1) ->
eval e2 (iBv b2) ->
eval (OR e1 e2) (iBv (b1 || b2))
| E_EQ e1 e2 n1 n2 :
eval e1 (iNv n1) ->
eval e2 (iNv n2) ->
eval (EQ e1 e2) (iBv (Nat.eqb n1 n2)).
Elpi Command fuzz.
Elpi Accumulate lp:{{
pred fuzz i:term, o:term.
% fuzzin rule: we look for a Coq term (?Op ?A ?B) and we turn it in (AND ?A ?B)
% only if the new term is well typed.
fuzz {{ lp:Op lp:A lp:B }} Fuzzed :-
coq.say "DEBUG: attempt at fuzzing binary op:" Op,
fuzz A A1, fuzz B B1,
Fuzzed = {{ AND lp:A1 lp:B1 }},
coq.typecheck Fuzzed _ ok, % we don't care about the type, only that it is ok
coq.say "DEBUG: fuzzed!".
% rule for the dependent function space
fuzz (prod N S T) (prod N S1 T1) :-
fuzz S S1,
% we load the context with types for x and y, as well as the fact that
% we fuzz x to y
pi x y\ decl x N S => decl y N S1 => fuzz x y => fuzz (T x) (T1 y).
% rule for application
fuzz (app L) (app L1) :- std.map L fuzz L1.
% rule for global constants
fuzz (global X) (global X).
% TODO: we should have clauses for all other type formers...
pred rename-constructors i:constructor, o:pair constructor string.
rename-constructors C (pr C C1) :-
coq.gref->id (indc C) S,
C1 is S ^ "1".
main [str IN, str OUT ] :-
% locate the inductive
coq.locate IN (indt I),
% fetch all its data, in particulat the types of the constructors
coq.env.indt I B NP NPU A KN KT,
% fuzz all constructor types
std.map KT fuzz KT1,
% we rename them, otherwise Coq complains the names are already used
std.map KN rename-constructors KN1,
% declare the new inductive
coq.build-indt-decl (pr I OUT) B NP NPU A KN1 KT1 Decl,
coq.env.add-indt Decl _.
}}.
Elpi Typecheck.
Elpi fuzz eval eval1.
(* let's print our new, broken, semantics ;-) *)
Print eval1.