.. index::
   pair: checking; design

.. _design-check:


Checking
========

.. mps:prefix:: design.mps.check


Introduction
------------

:mps:tag:`intro` This documents the design of structure checking within the
MPS.

:mps:tag:`readership` MPS developers.


Implementation
--------------

:mps:tag:`level` There are three levels of checking:

#. :mps:tag:`level.sig` The lowest level checks only that the
   structure has a valid ``Signature`` (see
   design.mps.sig).

#. :mps:tag:`level.shallow` Shallow checking checks all local fields
   (including signature) and also checks the signatures of any parent
   or child structures.

#. :mps:tag:`level.deep` Deep checking checks all local fields
   (including signatures), the signatures of any parent structures,
   and does full recursive checking on any child structures.

:mps:tag:`level.control` Control over the levels of checking is via the
definition of at most one of the macros :c:macro:`TARGET_CHECK_SHALLOW`
(which if defined gives :mps:ref:`.level.shallow`), :c:macro:`TARGET_CHECK_DEEP`
(which if defined gives :mps:ref:`.level.deep`). If neither macro is defined
then :mps:ref:`.level.sig` is used. These macros are not intended to be
manipulated directly by developers, they should use the interface in
impl.h.target.

:mps:tag:`order` Because deep checking (:mps:ref:`.level.deep`) uses unchecked
recursion, it is important that child relationships are acyclic
(:mps:ref:`.macro.down`).

:mps:tag:`fun` Every abstract data type which is a structure pointer should
have a function ``<type>Check`` which takes a pointer of type
``<type>`` and returns a :c:type:`Bool`. It should check all fields in
order, using one of the macros in :mps:ref:`.macro`, or document why not.

:mps:tag:`fun.omit` The only fields which should be omitted from a check
function are those for which there is no meaningful check (for
example, an unlimited unsigned integer with no relation to other
fields).

:mps:tag:`fun.return` Although the function returns a :c:type:`Bool`, if the assert
handler returns (or there is no assert handler), then this is taken to
mean "ignore and continue", and the check function hence returns
:c:macro:`TRUE`.

:mps:tag:`macro` Checking is implemented by invoking four macros in
impl.h.assert:

.. c:function:: CHECKS(type, val)

:mps:tag:`macro.sig` ``CHECKS(type, val)`` checks the signature only, and
should be called precisely on ``type`` and the received object
pointer.

.. c:function:: CHECKL(cond)

:mps:tag:`macro.local` ``CHECKL(cond)`` checks a local field (depending on
level; see :mps:ref:`.level`), and should be called on each local field that
is not an abstract data type structure pointer itself (apart from
the signature), with an appropriate normally-true test condition.

.. c:function:: CHECKU(type, val)

:mps:tag:`macro.up` ``CHECKU(type, val)`` checks a parent abstract data
type structure pointer, performing at most signature checks
(depending on level; see :mps:ref:`.level`). It should be called with the
parent type and pointer.

.. c:function:: CHECKD(type, val)

:mps:tag:`macro.down` ``CHECKD(type, val)`` checks a child abstract data
type structure pointer, possibly invoking ``<type>Check`` (depending
on level; see :mps:ref:`.level`). It should be called with the child type
and pointer.

:mps:tag:`full-type` Use :c:func:`CHECKS()`, :c:func:`CHECKD()` or :c:func:`CHECKU()` on all
types that satisfy these three requirements:

:mps:tag:`full-type.pointer` The type is a pointer type.

:mps:tag:`full-type.check` The type provides a function ``Bool TypeCheck(Type
type)`` where ``Type`` is substituted for the name of the type (for
example, :c:func:`PoolCheck()`).

:mps:tag:`full-type.sig` The expression ``obj->sig`` is a valid value of
type :c:type:`Sig` whenever ``obj`` is a valid value of type ``Type``.

:mps:tag:`partial-type` Where the type satisfies :mps:ref:`.full-type.pointer` and
:mps:ref:`.full-type.check` but not :mps:ref:`.full-type.sig` because the type lacks a
signature in order to save space (this applies to small structures
that are embedded many times in other structures, for example
:c:type:`Ring`), use :c:func:`CHECKD_NOSIG()`.

:mps:tag:`hidden-type` Where the type satisfies :mps:ref:`.full-type.pointer` and
:mps:ref:`.full-type.check` but not :mps:ref:`.full-type.sig` because the structure
has a signature but the structure definition is not visible at point
of checking (for example :c:type:`Root`), use :c:func:`CHECKD_NOSIG()` and
reference this tag. The structure could be considered for addition to
``mpmst.h``.