Download ADA USER JOURNAL - Ada

Transcript
62
function First_To_Previous (Container : List;
Current : Cursor) return List;
The function Current_To_Last takes a container Cont and
a cursor Cu in argument and returns a container that is
Cont where every cursor preceding Cu in Cont have been
removed:
function Current_To_Last (Container : List;
Current : Cursor) return List;
Finally, the function Strict_Equal takes two containers
and returns true if and only if they contain the same
elements in the same order and iteration can be done on
both of them using the same cursors.
function Strict_Equal (Left, Right : List)
return Boolean;
Thanks to these function, we can complete the
specification of Increment_Element:
procedure Increment_Element (L : in out List;
Cu : Cursor) with
Pre => Has_Element (L, Cu) and then
Element (L, Cu) < Element_Type'Last,
Post => Has_Element (L, Cu) and then
Element (L, Cu) = Element (L'Old, Cu) + 1
and then
Strict_Equal (First_To_Previous (L, Cu),
First_To_Previous (L'Old, Cu))
and then
Strict_Equal (Current_To_Last (L, Next(L, Cu)),
Current_To_Last (L'Old, Next(L'Old, Cu)));
The implementation of Increment_Element is as simple as
calling procedure Replace_Element from the formal
containers' API:
procedure Increment_Element (L : in out List;
Cu : Cursor) is
begin
Replace_Element (L, Cu, Element (L, Cu) + 1);
end Increment_Element;
And guess what? GNATprove manages to prove
automatically that the implementation above indeed
implements the contract that we specified for
Increment_Element. And that no run-time errors can be
raised in this code. Not bad for a non-trivial specification!
2 Expressing Properties over Formal
Containers
We saw in the previous post how formal containers can be
used in SPARK code. In this post, I describe how to
express properties over the content of these containers,
using quantified expressions. In their simplest form,
quantified expressions in Ada 2012 can be used to express
a property over a scalar range. For example, that all
integers between 1 and 6 have a square less than 40:
(for all J in 1 .. 6 => J * J < 40)
Vo lu me 3 5 , Nu mb er 1 , March 2014
SPARK 2014 Rationale: Formal Containers
or that every even integer greater than 2 can be expressed
as the sum of two primes (also known as Goldbach's
conjecture):
(for all J in Integer =>
(if J > 2 then
(for some P in 1 .. J / 2 => Is_Prime (P) and then
Is_Prime (J - P))))
The second form of quantified expressions allows to
express a property over a standard container. For
example, that all elements of a list of integers are prime,
which can be expressed by iterating over cursors as
follows:
(for all Cu in My_List => Is_Prime (Element (Cu)))
The general mechanism in Ada 2012 that provides this
functionality relies on the use of tagged types (for the
container type) and various aspects involving access types
so cannot be applied to the SPARK formal containers.
Instead, we have defined in GNAT an aspect Iterable that
provides the same functionality in a simpler way, leading
also to much simpler object code. For example, here is
how it can be used on a type Container_Type:
type Container_Type is ... -- the structure on which we
-- want to quantify
with Iterable => (First => My_First,
Has_Element => My_Has_Element,
Next => My_Next);
where My_First is a function taking a single argument of
type Container_Type and returning a cursor:
function My_First (Cont : Container_Type)
return My_Cursor_Type;
and My_Has_Element is a function taking a container and
a cursor and returning whether this cursor has an
associated element in the container:
function My_Has_Element (Cont : Container_Type;
Pos : My_Cursor_Type) return Boolean;
and My_Next is a function taking a container and a cursor
and returning the next cursor in this container:
function My_Next (Cont : Container_Type; Pos :
My_Cursor_Type) return My_Cursor_Type;
Now, if the type of object Cont is iterable in the sense
given above, it is possible to express a property over all
elements in Cont as follows:
(for all Cu in Cont => Property (Cu))
The compiler will generate code that iterates over Cont
using the functions My_First, My_Has_Element and
My_Next given in the Iterable aspect, so that the above is
equivalent to:
declare
Cu : My_Cursor_Type := My_First (Cont);
Result : Boolean := True;
Ad a User Jo urn al