.. 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 ``Check`` which takes a pointer of 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 ``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``.