next up previous index
Next: Unification and Binding Up: Interface to Externals Previous: Exit

Type Testing

The basic structure of an external predicate is almost always the same: first a check is made on the types of the arguments, and the predicate either fails or gives an error if the arguments are not of the expected type. Then the operation of the predicate continues. ECLiPSe provides a set of macros which make this initial type checking easy. All take a single tag as argument. The macro

Error_If_Ref(tag);
  will return control from the external predicate with an instantiation fault if its argument is a free variable. The Check_ family of   macros, such as
Check_Atom(val);
have the same effect as Error_If_Ref, and additionally return with a type error if the argument does not have the desired type. The only exception is Check_Ref which raises a type error if its argument is not a free variable. The Check_Output macro family, e.g.
Check_Output_Integer(tag)
  provide a way to test the type of arguments which may be either unbound or bound to a term of a certain type. They issue a type error if their argument is not a variable and it has not the specified type.

All the type testing macros mentioned in this section can be applied to arguments of the external predicates as well as to other Prolog terms, e.g. to the arguments of compound terms. In this case, however, their value has first to be dereferenced using the Dereference macro. The

Dereference(pw)
    macro takes a pointer to Prolog word pw and dereferences it, so that it points to the real value of the term. The arguments of an external predicate are dereferenced before the external is called and so they need not be dereferenced explicitly (as is the case in some Prolog systems). Other Prolog terms must be always dereferenced before testing.

Other macros are available which simply test the type of a Prolog term, and do not return control from the external. These are the Is   family, which evaluate to true if the tag is of the correct type, and to false otherwise. Thus IsString(tag) will return true if tag is of type TSTRG, for instance; that is, if the Prolog term represented is a string.

Another useful type checking macro compares two Prolog terms.

SameType(tag1, tag2);
is true if tag1 and tag2 are equal,   false otherwise.

If the Prolog term represented by a tag is a functor, the value is its DID (dictionary identifier) and it   can be used instead of some more complex structure in any place where the atom or functor needs to be referred to. Two macros are provided which take these identifiers as arguments. The macro

DidName(did);
returns a pointer to a   C string corresponding to the atom or functor (i.e. if the atom is program the string will be "program").   A pointer to a proper ECLiPSe string (as described for the TSTRG tag) can be obtained from an atom using the similar macro DidString(). The macro
DidArity(did);
  returns the arity of the functor identified by did, and zero for an atom. A DID can be obtained from the name and arity of a functor using the macro
Did(Cstring, Arity)
  A DID has the C type word32. The Did() macro either only returns the appropriate DID if this functor already exists in the system, or it creates the new functor and its DID. For example, to obtain the DID of the functor salary/3 use
word32     d_salary;
..
d_salary = Did("salary", 3);

The macro

Get_Name(val, tag, name)
  can be used to obtain the C string associated with an atom or a Prolog string and to issue an error if the type of the Prolog word is not atom or string. After its invocation, name points to the string.

For the predicates that take the input of the form Name/Arity the following macro is useful:

Get_Proc_Did(val, tag, did)
  if val and tag specify a compound term of the form Name/Arity, did is assigned to the DID of the corresponding functor otherwise the corresponding error type is raised. The arity is checked for being in the range for predicates (0 to max_predicate_arity), so this macro should be used when predicate specifications are to be checked. The macro
Get_Functor_Did(val, tag, did)
  is similar, but apart from a term Name/Arity it accepts as well an atom and returns its DID. As opposed to the previous one it does not check for an arity limit since a limit exists only for predicates, not for data structures.

With the macros so far mentioned it is possible to write externals for Prolog procedures which simply test the types of their arguments. A simple example is the following, which tests if its two arguments are successive integers. An instantiation fault occurs if either argument is uninstantiated, and a type error if either is not an integer.

int
p_succ_ints(val1, tag1, val2, tag2)
value val1, val2;
type  tag1, tag2;
{

        Check_Integer(tag1);
        Check_Integer(tag2);

        Succeed_If(val1.nint + 1 == val2.nint);
}


next up previous index
Next: Unification and Binding Up: Interface to Externals Previous: Exit



Micha Meier
Mon Mar 4 12:11:45 MET 1996