Exporting Types in ATS for Use in C

There is also support in ATS for exporting types to make them available for use in C directly. In the following example, a typedef of the name int_and_string is expected to be declared in the generated C code for values that are assigned the type (int, string) in ATS:

extern typedef "int_and_string" = (int, string)

Essentially, int_and_string is defined in C as follows:

typedef
struct {
  int atslab__0; void *atslab__1; 
} int_and_string ;

Sometimes, we want to construct in C values of a datatype declared in ATS. For instance, let us try to construct a value of the form cons2(i, d) in C for an integer i and a double d, where cons2 is a data constructor associated with the following declared datatype abc:

datatype abc = | cons1 of int | cons2 of (int, double)

Whenever a data constructor is declared, a corresponding (linear) type constructor is created whose name equals the concatenation of the name of the data constructor and the string "_pstruct". So in the case of the above declared datatype abc, the type constructors cons1_pstruct and cons2_pstruct are created, and these type constructors can be used to form types for boxed values constructed with the data constructors cons1 and cons2.

In the following declaration, the type cons2_pstruct(int, double) in ATS is exported to C under the name cons2_node:

extern vtypedef "cons2_node" = cons2_pstruct(int, double)

Implicitly, a typedef in C of the name cons2_node_ is also introduced for the unboxed portion of a value constructed with the data constructor cons2. Essentially, we have the following generated code in C:

typedef
struct {
int contag ; // constructor tag
int atslab__0; double atslab__1; 
} cons2_node_ ;
typedef cons2_node_ *cons2_node ;

It is now straightforward to create a value of the form cons2(i,d) in C directly:

cons2_node
cons2_make
(
  int i, double d
) {
  cons2_node p ;
  p = ATS_MALLOC(sizeof(cons2_node_)) ;
  p->contag = 1 ;
  p->atslab__0 = i ;
  p->atslab__1 = d ;
  return p ;
} /* end of [cons2_make] */

Note that the tags for cons1 and cons2 are 0 and 1, respectively, as cons1 and cons2 are the first and second constructors associated with the datatype abc.

By assigning an interface to cons2_make in ATS, we can readily check whether cons2_make behaves as expected:

// extern fun cons2_make(int, double): abc = "mac#" // val-cons2(1, 2.34) = cons2_make(1, 2.34) //

In general, it is essential for a programmer to acquire a solid understanding of low-level data representation of a programming language in order to use that language in low-level systems programming. The low-level data representation of ATS can be readily explained in terms of types in C, making it straightforward, when needed, to construct and manipulate ATS-values in C directly.