unused dependencies on Euclidean div/mod
[why3.git] / doc / exec.rst
blob589f6a39c814db5ac062000b0a509bff6c516505
1 .. _chap.exec:
3 Executing WhyML Programs
4 ========================
6 This chapter shows how WhyML code can be executed, either by being
7 interpreted or compiled to some existing programming language.
9 .. _sec.execute:
11 Interpreting WhyML Code
12 -----------------------
14 Consider the program of :numref:`sec.maxandsum` that computes the
15 maximum and the sum of an array of integers.
16 Let us assume it is contained in a file :file:`maxsum.mlw`.
18 To test function ``max_sum``, we can introduce a WhyML test function
19 in module ``MaxAndSum``
21 .. code-block:: whyml
23       let test () =
24         let n = 10 in
25         let a = make n 0 in
26         a[0] <- 9; a[1] <- 5; a[2] <- 0; a[3] <- 2;  a[4] <- 7;
27         a[5] <- 3; a[6] <- 2; a[7] <- 1; a[8] <- 10; a[9] <- 6;
28         max_sum a n
30 and then we use the :why3:tool:`execute` command to interpret this
31 function, as follows:
33 .. code-block:: console
35     $ why3 execute maxsum.mlw --use=MaxAndSum 'test ()'
36     result: (int, int) = (45, 10)
37     globals:
39 We get the expected output, namely the pair ``(45, 10)``.
41 Notice that the WhyML interpreter optionally supports Runtime
42 Assertion Checking (RAC). This is detailed in
43 :numref:`sec.why3execute`.
45 .. _sec.extract:
47 Compiling WhyML to OCaml
48 ------------------------
50 .. program:: why3 extract
52 An alternative to interpretation is to compile WhyML to OCaml. We do so
53 using the :why3:tool:`extract` command, as follows:
57     why3 extract -D ocaml64 maxsum.mlw -o max_sum.ml
59 The :why3:tool:`extract` command requires the name of a driver, which indicates
60 how theories/modules from the Why3 standard library are translated to
61 OCaml. Here we assume a 64-bit architecture and thus we pass
62 ``ocaml64``. We also specify an output file using option :option:`-o`, namely
63 :file:`max_sum.ml`. After this command, the file :file:`max_sum.ml` contains an
64 OCaml code for function ``max_sum``. To compile it, we create a file
65 :file:`main.ml` containing a call to ``max_sum``, *e.g.*,
67 .. code-block:: ocaml
69     let a = Array.map Z.of_int [| 9; 5; 0; 2; 7; 3; 2; 1; 10; 6 |]
70     let s, m = Max_sum.max_sum a (Z.of_int 10)
71     let () = Format.printf "sum=%s, max=%s@." (Z.to_string s) (Z.to_string m)
73 It is convenient to use :program:`ocamlbuild` to compile and link both files
74 :file:`max_sum.ml` and :file:`main.ml`:
78     ocamlbuild -pkg zarith main.native
80 Since Why3’s type ``int`` is translated to OCaml arbitrary precision
81 integers using the ``ZArith`` library, we have to pass option
82 ``-pkg zarith`` to :program:`ocamlbuild`. In order to get extracted code that
83 uses OCaml’s native integers instead, one has to use Why3’s types for
84 63-bit integers from libraries ``mach.int.Int63`` and
85 ``mach.array.Array63``.
87 Examples
88 ''''''''
90 We illustrate different ways of using the :why3:tool:`extract` command through
91 some examples.
93 Consider the program of :numref:`sec.aqueue`.
94 If we are only interested in extracting function ``enqueue``, we can
95 proceed as follows:
99     why3 extract -D ocaml64 -L . aqueue.AmortizedQueue.enqueue -o aqueue.ml
101 Here we assume that file :file:`aqueue.mlw` contains this program, and that
102 we invoke the :why3:tool:`extract` command from the directory where this file is stored. File
103 :file:`aqueue.ml` now contains the following OCaml code:
105 .. code-block:: ocaml
107     let enqueue (x: 'a) (q: 'a queue) : 'a queue =
108       create (q.front) (q.lenf) (x :: (q.rear))
109         (Z.add (q.lenr) (Z.of_string "1"))
111 Choosing a function symbol as the entry point of extraction allows us to
112 focus only on specific parts of the program. However, the generated code
113 cannot be type-checked by the OCaml compiler, as it depends on function
114 ``create`` and on type ``'a queue``, whose definitions are not given. In
115 order to obtain a *complete* OCaml implementation, we can perform a
116 recursive extraction:
120     why3 extract --recursive -D ocaml64 -L . aqueue.AmortizedQueue.enqueue -o aqueue.ml
122 This updates the contents of file :file:`aqueue.ml` as follows:
124 .. code-block:: ocaml
126     type 'a queue = {
127       front: 'a list;
128       lenf: Z.t;
129       rear: 'a list;
130       lenr: Z.t;
131       }
133     let create (f: 'a list) (lf: Z.t) (r: 'a list) (lr: Z.t) : 'a queue =
134       if Z.geq lf lr
135       then
136         { front = f; lenf = lf; rear = r; lenr = lr }
137       else
138         let f1 = List.append f (List.rev r) in
139         { front = f1; lenf = Z.add lf lr; rear = []; lenr = (Z.of_string "0") }
141     let enqueue (x: 'a) (q: 'a queue) : 'a queue =
142       create (q.front) (q.lenf) (x :: (q.rear))
143         (Z.add (q.lenr) (Z.of_string "1"))
145 This new version of the code is now accepted by the OCaml compiler
146 (provided the ``ZArith`` library is available, as above).
148 Extraction of functors
149 ''''''''''''''''''''''
151 WhyML and OCaml are both dialects of the ML-family, sharing many syntactic and
152 semantics traits. Yet their module systems differ significantly.
153 A WhyML program is a list of modules, a module is a list of top-level
154 declarations, and declarations can be organized within *scopes*, the WhyML unit
155 for namespaces management. In particular, there is no support for sub-modules in
156 Why3, nor a dedicated syntactic construction for functors. The latter are
157 represented, instead, as modules containing only abstract symbols
158 :cite:`paskevich20isola`. One must follow exactly this programming pattern when
159 it comes to extract an OCaml functor from a Why3 proof. Let us consider the
160 following (excerpt) of a WhyML module implementing binary search
161 trees:
163 .. code-block:: whyml
165     module BST
166       scope Make
167         scope Ord
168           type t
169           val compare : t -> t -> int
170         end
172         type elt = Ord.t
174         type t = E | N t elt t
176         use int.Int
178         let rec insert (x: elt) (t: t)
179         = match t with
180           | E -> N E x E
181           | N l y r ->
182               if Ord.compare x y > 0 then N l y (insert x r)
183               else N (insert x l) y r
184           end
185       end
186     end
188 For the sake of simplicity, we omit here behavioral specification. Assuming the
189 above example is contained in a file named :file:`bst.mlw`, one can
190 readily extract it into OCaml, as follows:
194     why3 extract -D ocaml64 bst.mlw --modular -o .
196 This produces the following functorial implementation:
198 .. code-block:: ocaml
200     module Make (Ord: sig type t
201       val compare : t -> t -> Z.t end) =
202     struct
203       type elt = Ord.t
205       type t =
206       | E
207       | N of t * Ord.t * t
209       let rec insert (x: Ord.t) (t: t) : t =
210         match t with
211         | E -> N (E, x, E)
212         | N (l, y, r) ->
213             if Z.gt (Ord.compare x y) Z.zero
214             then N (l, y, insert x r)
215             else N (insert x l, y, r)
216     end
218 The extracted code features the functor ``Make`` parameterized with a
219 module containing the abstract type ``t`` and function
220 ``compare``. This is similar to the OCaml standard library when it
221 comes to data structures parameterized by an order relation, *e.g.*,
222 the ``Set`` and ``Map`` modules.
224 From the result of the extraction, one understands that scope ``Make``
225 is turned into a functor, while the nested scope ``Ord`` is extracted
226 as the functor argument. In summary, for a WhyML implementation of the
227 form
229 .. code-block:: whyml
231     module M
232       scope A
233         scope X ... end
234         scope Y ... end
235         scope Z ... end
236       end
237       ...
238     end
240 contained in file :file:`f.mlw`, the Why3 extraction engine produces the
241 following OCaml code:
243 .. code-block:: ocaml
245     module A (X: ...) (Y: ...) (Z: ...) = struct
246       ...
247     end
249 and prints it into file :file:`f__M.ml`. In order for functor extraction
250 to succeed, scopes ``X``, ``Y``, and ``Z`` can only contain
251 non-defined programming symbols, *i.e.*, abstract type declarations,
252 function signatures, and exception declarations. If ever a scope mixes
253 non-defined and defined symbols, or if there is no surrounding scope
254 such as ``Make``, the extraction will complain about
255 the presence of non-defined symbols that cannot be extracted.
257 It is worth noting that extraction of functors only works for
258 *modular* extraction (*i.e.* with command-line option :option:`--modular`).
261 Custom extraction drivers
262 '''''''''''''''''''''''''
264 Several OCaml drivers can be specified on the command line, using option
265 :option:`-D` several times. In particular, one can provide a custom driver to
266 map some symbols of a Why3 development to existing OCaml code. Suppose
267 for instance we have a file :file:`file.mlw` containing a proof
268 parameterized with some type ``elt`` and some binary function ``f``:
270 .. code-block:: whyml
272     module M
273       type elt
274       val f (x y: elt) : elt
275       let double (x: elt) : elt = f x x
276       ...
278 When it comes to extract this module to OCaml, we may want to
279 instantiate type ``elt`` with OCaml’s type ``int`` and function ``f``
280 with OCaml’s addition. For this purpose, we provide the following in a
281 file :file:`mydriver.drv`:
285     module file.M
286       syntax type elt "int"
287       syntax val  f   "%1 + %2"
288     end
290 OCaml fragments to be substituted for Why3 symbols are given as
291 arbitrary strings, where ``%1``, ``%2``, etc., will be replaced with
292 actual arguments. Here is the extraction command line and its output:
294 .. code-block:: console
296     $ why3 extract -D ocaml64 -D mydriver.drv -L . file.M
297     let double (x: int) : int = x + x
298     ...
300 When using such custom drivers, it is not possible to pass Why3 file
301 names on the command line; one has to specify module names to be
302 extracted, as done above.
304 Compiling to Other Languages
305 ----------------------------
307 The :why3:tool:`extract` command can produce code for languages other
308 than just OCaml. This is a matter of choosing a suitable driver.
310 Compiling to C
311 ''''''''''''''
313 Consider the following example. It defines a function that returns the
314 position of the maximum element in an array ``a`` of size ``n``.
316 .. code-block:: whyml
318    use int.Int
319    use map.Map as Map
320    use mach.c.C
321    use mach.int.Int32
322    use mach.int.Int64
324    function ([]) (a: ptr 'a) (i: int): 'a = Map.get a.data.Array.elts (a.offset + i)
326    let locate_max (a: ptr int64) (n: int32): int32
327      requires { 0 < n }
328      requires { valid a n }
329      ensures  { 0 <= result < n }
330      ensures  { forall i. 0 <= i < n -> a[i] <= a[result] }
331    = let ref idx = 0 in
332      for j = 1 to n - 1 do
333        invariant { 0 <= idx < n }
334        invariant { forall i. 0 <= i < j -> a[i] <= a[idx] }
335        if get_ofs a idx < get_ofs a j then idx <- j
336      done;
337      idx
339 There are a few differences with a standard WhyML program. The main
340 one is that the array is described by a value of type ``ptr int64``,
341 which models a C pointer of type ``int64_t *``.
343 Among other things, the type ``ptr 'a`` has two fields: ``data`` and
344 ``offset``. The ``data`` field is of type ``array 'a``; its value
345 represents the content of the memory block (as allocated by
346 ``malloc``) the pointer points into. The ``offset`` field indicates
347 the actual position of the pointer into that block, as it might not
348 point at the start of the block.
350 The WhyML expression ``get_ofs a j`` in the example corresponds to the
351 C expression ``a[j]``. The assignment ``a[j] = v`` could be expressed
352 as ``set_ofs a j v``. To access just ``*a`` (i.e., ``a[0]``), one
353 could use ``get a`` and ``set a v``.
355 For the access ``a[j]`` to have a well-defined behavior, the memory
356 block needs to have been allocated and not yet freed, and it needs to
357 be large enough to accommodate the offset ``j``. This is expressed
358 using the precondition ``valid a n``, which means that the block
359 extends at least until ``a.offset + n``.
361 The code can be extracted to C using the following command:
365    why3 extract -D c locate_max.mlw
367 This gives the following C code.
369 .. code-block:: C
371    #include <stdint.h>
373    int32_t locate_max(int64_t * a, int32_t n) {
374      int32_t idx;
375      int32_t j, o;
376      idx = 0;
377      o = n - 1;
378      if (1 <= o) {
379        for (j = 1; ; ++j) {
380          if (a[idx] < a[j]) {
381            idx = j;
382          }
383          if (j == o) break;
384        }
385      }
386      return idx;
387    }
389 Not any WhyML code can be extracted to C. Here is a list of supported features and a few rules that your code must follow for extraction to succeed.
391 * Basic datatypes
393    * Integer types declared in ``mach.int`` library are supported for
394      sizes 16, 32 and 64 bits. They are translated into C types of
395      appropriate size and sign, say ``int32_t``, ``uint64_t``, etc.
397    * The mathematical integer type ``int`` is not supported.
399    * The Boolean type is translated to C type ``int``. The bitwise operators from ``bool.Bool`` are
400      supported.
402    * Character and strings are partially supported via the functions
403      declared in ``mach.c.String`` library
405    * Floating-point types are not yet supported
407 * Compound datatypes
409    * Record types are supported. When they have no mutable fields,
410      they are translated into C structs, and as such are passed by value and returned by
411      value. For example the WhyML code
413      .. code-block:: whyml
415         use mach.int.Int32
416         type r = { x : int32; y : int32 }
417         let swap (a : r) : r = { x = a.y ; y = a.x }
419      is extracted as
421      .. code-block:: c
423         #include <stdint.h>
425         struct r {
426           int32_t x;
427           int32_t y;
428         };
430         struct r swap(struct r a) {
431           struct r r;
432           r.x = a.y;
433           r.y = a.x;
434           return r;
435         }
437      On the other hand, records with mutable fields are interpreted as
438      pointers to structs, and are thus passed by reference. For example the WhyML code
440      .. code-block:: whyml
442         use mach.int.Int32
443         type r = { mutable x : int32; mutable y : int32 }
444         let swap (a : r) : unit =
445            let tmp = a.y in a.y <- a.x; a.x <- tmp
447      is extracted as
449      .. code-block:: c
451         struct r {
452           int32_t x;
453           int32_t y;
454         };
456         void swap(struct r * a) {
457           int32_t tmp;
458           tmp = a->y;
459           a->y = a->x;
460           a->x = tmp;
461         }
463    * WhyML arrays are not supported
465    * Pointer types are supported via the type ``ptr`` declared in
466      library ``mach.c.C``. See above for an example of use.
468    * Algebraic datatypes are not supported (even enumerations)
470 * Pointer aliasing constraints
472    The type ``ptr`` from ``mach.c.C`` must be seen as a WhyML mutable
473    type, and as such is subject to the WhyML restrictions regarding
474    aliasing. In particular, two pointers passed as argument to a
475    function are implicitly not aliased.
477 * Control flow structures
479    * Sequences, conditionals, ``while`` loops and ``for`` loops are supported
480    * Pattern matching is not supported
481    * Exception raising and catching is not supported
482    * ``break``, ``continue`` and ``return`` are supported