File: GenExec.v

package info (click to toggle)
coq-quickchick 2.1.1-2
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 2,432 kB
  • sloc: ml: 4,367; ansic: 789; makefile: 388; sh: 27; python: 4; lisp: 2; perl: 2
file content (167 lines) | stat: -rw-r--r-- 4,558 bytes parent folder | download | duplicates (4)
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
From QuickChick Require Import QuickChick.

Require Import ZArith.
Require Import List.
Import ListNotations.
From QuickChick.ifcbasic Require Import Machine.

(* Overriding default instance to generate "in-bounds" things *)
Definition mem_length : Z := 10.

Definition gen_Z := choose (0,mem_length).

Definition gen_label := elements L [L; H].

Definition gen_atom := liftGen2 Atm gen_Z gen_label.

Definition gen_memory := vectorOf 10 gen_atom.

Definition is_atom_low (a : Atom) :=
  match a with
    | _ @ L => true
    | _     => false
  end.

Local Open Scope nat.

Definition ainstr (st : State) : G Instruction :=
  let '(St im m stk pc ) := st in
  let fix stack_length s :=
      match s with
        | _ :: s' => 1 + stack_length s'
        | _ => 0
      end in
  let sl := stack_length stk in
  let fix containsRet s :=
      match s with
        | _ ::: _ => true
        | _ :: s' => containsRet s'
        | _ => false
      end in
  let onLength len x := if leb x len then x else 0 in
  freq_ (returnGen Nop) [
              (1, returnGen Nop);
              (10, liftGen Push gen_Z);
              (if sl < 1 ? then 0 else 10, liftGen BCall (if Nat.eqb sl 0 then returnGen 0
                                  else choose (0, Z.of_nat sl-1))%Z);
              (if containsRet stk then 10 else 0, returnGen BRet);
              (if sl < 2 ? then 0 else 10, returnGen Add);
              (if sl < 1 ? then 0 else 10, returnGen Load);
              (if sl < 2 ? then 0 else 100, returnGen Store)].

Fixpoint gen_stack (n : nat) (onlyLow : bool) : G Stack :=
  (*
  let gen_atom :=
      if onlyLow then liftGen2 Atm gen_Z (returnGen L)
      else gen_atom
  in
   *)
  match n with
    | O => returnGen Mty
    | S n' =>
      freq_ (returnGen Mty) [
                  (10, liftGen2 Cons gen_atom (gen_stack n' onlyLow));
                  (4, bindGen gen_atom (fun pc =>
                       liftGen (RetCons pc) (gen_stack n' (is_atom_low pc))))]
  end.

Fixpoint gen_by_exec (t : table) (fuel : nat) (st : State) :=
  let '(St im m stk (Atm addr pcl)) := st in
  match fuel with
  | O => returnGen st
  | S fuel' =>
    match nth im addr with
    | Some Nop =>
      (* If it is a noop, generate *)
      bindGen (ainstr st) (fun i =>
      match upd im addr i with
      | Some im' =>
        let st' := St im' m stk (Atm addr pcl) in
        gen_by_exec t fuel' st'
      | None => returnGen st
      end)
    | Some _ =>
      (* Existing instruction, execute *)
      match exec t st with
      | Some st' =>
        gen_by_exec t fuel' st'
      | None => returnGen st
      end
    | None =>
      (* Out of bounds, terminate *)
      returnGen st
    end
  end.

Require Import ExtLib.Structures.Monads.
Import MonadNotation.
Open Scope monad_scope.

Definition gen_state : G State :=
  let imem0 := replicate 10 Nop in
  pc <- gen_atom ;;
  mem <- gen_memory ;;
  stk <- gen_stack 10 (is_atom_low pc) ;;
  st' <- gen_by_exec default_table 20 (St imem0 mem stk pc) ;;
  ret st'.

From QuickChick.ifcbasic Require Import Generation.

#[global]
Instance vary_atom' : Vary Atom :=
{|
  vary a :=
    let '(x @ l) := a in
    match l with
      | L => returnGen a
      | H => liftGen2 Atm gen_Z (returnGen H)
    end
|}.

#[global]
Instance vary_mem' : Vary Mem :=
{|
  vary m := sequenceGen (map vary m)
|}.

Fixpoint vary_stack (s : Stack) (isLow : bool) : G Stack :=
  match s with
    | a :: s'  => if isLow then liftGen2 Cons (vary a) (vary_stack s' isLow)
                  else liftGen2 Cons gen_atom (vary_stack s' isLow)
    | (x@l) ::: s' =>
      match l with
        | L => liftGen (RetCons (x@l)) (vary_stack s' true)
        | H => liftGen2 RetCons (vary (x@l)) (vary_stack s' false)
      end
    | Mty => returnGen Mty
  end.

Import QcDefaultNotation.
#[global]
Instance vary_state' : Vary State :=
{|
  vary st :=
    let '(St imem mem stk pc) := st in
    mem' <- vary mem ;;
    pc'  <- vary pc ;;
    let isLow := match pc with
                   | _ @ L => true
                   | _ @ H => false
                 end in
    if isLow then
      stk' <- vary_stack stk isLow ;;
      ret (St imem mem' stk' pc')
    else
      stk' <- vary_stack stk isLow ;;
      bindGen (@arbitrary bool _) (fun b : bool =>
      if b then
        extra_elem <- gen_atom ;;
        ret (St imem mem' (extra_elem :: stk') pc')
      else
        ret (St imem mem' stk' pc'))
|}.

Definition gen_variation_state' : G (@Variation State) :=
  bindGen gen_state (fun st =>
  bindGen (vary st) (fun st' =>
  returnGen (V st st'))).