Message Interface (MINT) Representation

The Message Interface (mint) intermediate language is designed to represent a collection of rpc/rmi interfaces in terms of the messages -- requests and replies -- that will be exchanged between clients and servers. Like aoi, mint descriptions are abstract: not concerned with particular message formats, data encoding schemes, or stub styles. These concrete notions are determined by Flick's presentation generators and back ends, after the mint representation of the interfaces has been built.

mint does not generally stand on its own, because by itself, mint does not carry enough information to completely represent an interface. Rather, mint is a part of the more expressive and complete pres_c language. mint simply describes collections of abstract messages; other parts of pres_c attach meanings to those messages, thus creating a complete representation language for interface description.

5.1 MINT Overview


PIC
Figure 5.1The Message Interface (mint) Tree.

mint represents a collection of interfaces as a tree, as illustrated in Figure 5.1. (In truth, mint represents graphs, not trees, but the "top level" of the graph is always a tree.) At the root of the tree is a discriminated union, representing the collection of different idls. The separate branches of the union correspond to different idls: corba, onc rpc, mig, or other idls to be supported. Although mint was designed to support interfaces from multiple idls at the same time, but in current practice, only one idl is represented by any one mint tree.

At the next level of the tree, a node represents a collection of defined interfaces or object type. Here, each branch corresponds to a different interface type. At the third level, a mint node represents the collection of messages, both requests and replies, that are part of the interface. For each request, there is a fourth-level node (a MINT_STRUCT) that describes the request parameter types. For each reply, there is a fourth-level node (a MINT_UNION) that describes the types of the reply data. A reply is a union because it represents both normal and exceptional reply messages.

Beyond the fourth level of the tree, mint describes the types of individual message elements, much as aoi describes the types of idl operation parameters. Mapping from the aoi representation of an interface and its operations to the corresponding mint representation is straightforward. Since both aoi and mint are abstract description languages, the translation can in fact be implemented by a library function shared by all of Flick's presentation generators.1 The translation from aoi to mint is "lossy," however: some of the information in the aoi description of an interface or idl-defined type is lost. This is because mint only represents the structure or syntax of messages that will be exchanged between clients and servers. Semantic notions -- names (type names, structure slot names, . . . ), inheritance, exceptions, and so on -- that give meanings to messages are discarded when aoi is translated into mint. These semantics are "recovered" when the presentation generator makes a second pass over the aoi while building the pres_c representation of the types, stubs, and skeletons that will ultimately implement the interface.

5.2 MINT Data Structures

Like aoi, mint must be written to and read from files, and it therefore defined using the onc rpc idl. The data structures are defined in mom/mint.x.

The top-level mint data structure is called mint_1 and contains two slots. The first slot, defs, contains a mint type graph, represented as a single array of type definitions, with each definition represented by a mint_def structure. mint definitions will be described shortly, in Section 5.2.1. Unlike aoi, there is no semantic significance to the order of the definitions in the array.

The second slot in a mint_1 is called standard_refs and contains a references to certain "well known" and common mint type definitions. It is convenient to keep these references around because certain basic types are used again and again. A reference to a mint type definition is a mint_ref, which is implemented as an index into the mint_1 array of mint_defs. A null reference is represented by the special mint_ref_null value.
 typedef int mint_ref;
 const mint_ref_null = -1;
 
 struct mint_1
 {
         mint_def                defs<>;
 
         /* `standard_refs' are initialized by `mint_add_standard_defs'. */
         mint_standard_refs      standard_refs;
 };
 
 /*
  * A `mint_standard_refs' contains `mint_ref's for commonly-used MINT types.
  * It is useful to have immediate access to these basic building blocks.
  */
 struct mint_standard_refs
 {
         mint_ref void_ref;
 
         mint_ref bool_ref;
         mint_ref signed8_ref;
         mint_ref signed16_ref;
         mint_ref signed32_ref;
         mint_ref signed64_ref;
         mint_ref unsigned8_ref;
         mint_ref unsigned16_ref;
         mint_ref unsigned32_ref;
         mint_ref unsigned64_ref;
 
         mint_ref char8_ref;
         mint_ref float32_ref;
         mint_ref float64_ref;
 
         mint_ref interface_name_ref;
         mint_ref interface_invoke_ref;
         mint_ref interface_invoke_once_ref;
         mint_ref interface_service_ref;
         mint_ref system_exception_ref;
 };

5.2.1 Type Definitions




aoi Type Kind
Description


MINT_INTEGER
an integer with a specified minimum value and range
MINT_SCALAR
an integer with range determined by # of bits
MINT_FLOAT
a floating-point type with a specified # of bits
MINT_CHAR
a character with flags and a specified # of bits
MINT_BOOLEAN
true or false
MINT_VOID
void
MINT_ARRAY
an array, fixed- or variable-length
MINT_STRUCT
a collection of unnamed, unordered fields
MINT_UNION
a discriminated union
MINT_ANY
"any" value, without a type tag
MINT_TYPE_TAG
an opaque type identifier
MINT_TYPED
a pair: a type identifier and a value of that type
MINT_INTERFACE
a reference to an object instance
MINT_SYSTEM_EXCEPTION
an opaque, system-generated exception



Table 5.1Summary of the Available mint Type Kinds.

A mint type definition is implemented by a discriminated union of the possible type kinds, which are summarized in Table 5.1. The details of individual mint types are specified by further mint structures as shown in the code below.

It is important to note the differences between an aoi_def (described in Section 4.2.1) and a mint_def. Unlike an aoi_def, a mint_def does not include a name, a scope, or any other "semantic" information beyond the essential structure of the type.
 union mint_def
 switch (mint_def_kind kind)
 {
         case MINT_VOID:                 void;
         case MINT_BOOLEAN:              void;
         case MINT_INTEGER:              mint_integer_def        integer_def;
         case MINT_SCALAR:               mint_scalar_def         scalar_def;
         case MINT_FLOAT:                mint_float_def          float_def;
         case MINT_CHAR:                 mint_char_def           char_def;
         case MINT_ARRAY:                mint_array_def          array_def;
         case MINT_STRUCT:               mint_struct_def         struct_def;
         case MINT_UNION:                mint_union_def          union_def;
 
         case MINT_INTERFACE:            mint_interface_def      interface_def;
         case MINT_SYSTEM_EXCEPTION:     void;
 
         case MINT_ANY:                  void;
 
         case MINT_TYPE_TAG:             void;
         case MINT_TYPED:                mint_typed_def          typed_def;
 };

The current mint type kinds are described below, in the order in which they appear in Table 5.1.

Integers

A MINT_INTEGER represents an integer type with a specified (constant) minimum value and range. This type is used to represent all integer types whose values can be represented with not more that 32 bits. This includes unsigned and signed 32-, 16-, and 8-bit types, as well as booleans and certain integer "constants." (If the specified range is zero, then the MINT_INTEGER describes a type with only one possible value. This is useful for describing other types such as fixed-length arrays.)

Obviously, MINT_INTEGER has a direct correspondence with AOI_INTEGER.
 struct mint_integer_def
 {
         /* Lowest possible value this integer can take.
            If >= 0, it's an unsigned integer.  */
         int min;
 
         /* Number of possible values this integer can take in addition to
            `min'.  The maximum legal value is `min + range'.
            If range is 0, the integer can take only one value -
            i.e. it carries no information; useful for representing fixed-length
            arrays.
            If range is 1, it's a boolean.  */
         unsigned range;
 };

Scalars

A MINT_SCALAR describes an integer type by specifying the number of bits in its range. The minimum value is determined by flags that indicate whether the type is signed or unsigned. Scalars are only used to describe integer types that a MINT_INTEGER cannot represent (e.g., 64-bit and 128-bit integers).

Obviously, MINT_SCALAR is the mint equivalent of aoi's AOI_SCALAR type.
 typedef u_int mint_scalar_flags;
 const MINT_SCALAR_FLAG_NONE     = 0;
 const MINT_SCALAR_FLAG_SIGNED   = 1;
 const MINT_SCALAR_FLAG_UNSIGNED = 2;
 
 struct mint_scalar_def
 {
         int                     bits;
         mint_scalar_flags       flags;
 };

Floats

A MINT_FLOAT describes a floating point type in terms of the number of bits in the encoding of the type. Again, there is an obvious and direct correspondence with the equivalent aoi type.
 struct mint_float_def
 {
         /* Currently may be 32 or 64.  */
         int     bits;
 };

Characters

A MINT_CHAR describes a character type. Again, the range of the type is described by the number of bits required to encode values of the type (generally 8). In addition, a set of flags describe additional properties, such as whether the characters are "signed" or "unsigned." As with most primitive types, the representations of mint and aoi characters are identical.
 /* These are flags to modify mint_char's: signed, unsigned, or default. */
 typedef u_int mint_char_flags;
 const MINT_CHAR_FLAG_NONE     = 0;
 const MINT_CHAR_FLAG_SIGNED   = 1;
 const MINT_CHAR_FLAG_UNSIGNED = 2;
 
 struct mint_char_def
 {
         /* Currently, `bits' may be 8 (char) or 16 (wchar).  */
         int     bits;
         mint_char_flags flags;
 };

Booleans

A MINT_BOOLEAN represents the standard boolean type: true or false. Currently, this type is unused: the boolean type is instead represented as a kind of MINT_INTEGER.

Voids

A MINT_VOID represents a void type: a type with no values.

Arrays

A MINT_ARRAY describes an array type: a numbered and ordered collection of values of a single (element) type. The set of possible array lengths is described by a MINT_INTEGER, referenced by the length_type slot of the mint_array_def. The array may be variable-length (if the MINT_INTEGER has a non-zero range) or fixed-length (if the MINT_INTEGER has a zero range). Obviously, the MINT_ARRAY description also contains a reference to the type of the array elements, as shown below.

Note that unlike an AOI_ARRAY, a MINT_ARRAY definition does not have a set of flags describing semantic properties of the array (e.g., NUL-termination).
 struct mint_array_def
 {
         /* Type of each of the elements in this array.  */
         mint_ref element_type;
 
         /* Type representing the possible lengths of this array.
            Must be an integer type of some kind.
            If the integer's `range' is zero, it's a fixed-length array.  */
         mint_ref length_type;
 };

Structures

A MINT_STRUCT describes a collection of unordered, unnamed values of heterogeneous types. This is different that the usual notion of a "structure" type in most programming languages. Here, a structure is simply a set of (zero or more) independent data elements. Each element has a specific type, but there is no significance to the order of the elements, nor are there any semantic connections between elements. For example, no element describes the "length" or the "type" of another.

In truth, the elements of a MINT_STRUCT are ordered in the sense that order is preserved when translating from an AOI_STRUCT, and the order of elements in an AOI_STRUCT is the order in which the slots were named in the original idl input. Order is also important when Flick must create constant values that are of specific structure types. But this ordering of slots is only "coincidental" to the meaning of a MINT_STRUCT. The ordering of the slots in a MINT_STRUCT does not, for example, specify or constrain the order in which the structure elements might eventually be written into memory or into a request or reply message. Flick presentation generators and back ends can choose to process the MINT_STRUCT elements in any order they see fit.
 struct mint_struct_def
 {
         mint_ref slots<>;
 };

Unions

A MINT_UNION represents a discriminated union: a compound data type containing a discriminator that selects from a set of possible "arms" or cases. The value of the discriminator determines which one of the possible union cases is valid (i.e., part of the complete value of the union).

Note that the discriminator does not have to be a simple integer type: it can be a complex type such as an array of characters or a structure. This allows mint to describe unions in which the discriminator values are strings (e.g., interface or operation names) or other complex values (e.g., onc/tcp program/version pairs, or dce uuids).

Each arm is represented by a mint_union_case containing a discriminator value -- the value that selects the arm -- and type for the arm. The mint representation of constant values is described in Section 5.2.2. The union cases come in no particular order (although order is preserved when translating from an AOI_UNION).

The union as a whole is essentially represented as a kind of structure with a distinguished discriminator member, an array of mint_union_cases representing the arms of the union, and an optional "default" arm that is selected when none of the ordinary union cases are selected. If there is no default branch, then the dfault slot of the mint_union_def will be set to mint_ref_null. In this case, a discriminator value that does not match any of the cases is considered illegal (i.e., decoding will fail on an incoming message containing a union with a bad discriminator). If there is a default case and that default case is void, then dfault must refer to a valid MINT_VOID type node.
 struct mint_union_case
 {
         mint_const      val;
         mint_ref        var;
 };
 
 struct mint_union_def
 {
         /* Union discriminator variable.
            Type must be based on an int or enum prim_type.  */
         mint_ref discrim;
 
         /* Variable for each non-default case.
            Any case can be void, meaning no additional data. */
         mint_union_case cases<>;
 
         /* Variable for the default case, `mint_ref_null' if no default.
            (If there's a default case but it's void, then `dfault' should
            point to a MINT_VOID.) */
         mint_ref dfault;
 };

Anys

A MINT_ANY represents "any type," the type of all possible values. Because MINT_ANY is all-encompassing, there is no additional data associated with a MINT_ANY.

Type Tags

A MINT_TYPE_TAG represents an opaque indicator of a type. In other words, the value of a type tag is a description of type. Like AOI_TYPE_TAGs, MINT_TYPE_TAGs are opaque in the sense that the compiler portions of Flick do not provide, understand, or enforce any semantics for type tags. Other than marshaling and unmarshaling tag instances, Flick does nothing with tags. Semantics must be provided by runtime libraries.

Since type tags are opaque, a MINT_TYPE_TAG has no attributes.

Typed Values

A MINT_TYPED describes pairs containing a type description and a value of the described type. In other words, a MINT_TYPED represents type-tagged values. The tag and ref fields of a mint_typed_def structure may conceptually refer to any mint type, but in practice, the former is always a MINT_TYPE_TAG and the latter is always a MINT_ANY.

There is an obvious and direct correspondence between the mint and aoi representations of type-tagged "any" values.
 /* used for type-tagged data, e.g. MIG's polymorphic type */
 struct mint_typed_def
 {
         mint_ref        tag;
         mint_ref        ref;
 };

Interfaces

A MINT_INTERFACE represents a reference to an instance of an idl-defined object type. Note that this is quite different than the notion described by an AOI_INTERFACE. An AOI_INTERFACE describes the type of object instances; a MINT_INTERFACE describes the type of object references. In common idls, one passes object references in messages, not the objects themselves.2

A MINT_INTERFACE has a single datum describing the high-level rpc characteristics of the reference: e.g., whether the reference is for sending or receiving requests. (The current set of characteristics are derived from those implemented in the Mach operating system.) More specific properties, such as the on-the-wire encoding of object references, are not represented by mint: by being abstract, mint allows different back ends to choose different encodings.
 enum mint_interface_right
 {
         MINT_INTERFACE_NAME             = 0,    /* just names a interface   */
         MINT_INTERFACE_INVOKE           = 1,    /* can invoke an interface  */
         MINT_INTERFACE_INVOKE_ONCE      = 2,    /* can invoke only once     */
         MINT_INTERFACE_SERVICE          = 3     /* can service an interface */
 };
 
 struct mint_interface_def
 {
         mint_interface_right    right;
 };

System Exceptions

Finally, a MINT_SYSTEM_EXCEPTION describes the type of exceptions generated by the rpc/rmi runtime layers. These are implicit exceptions, not generally defined by in idl. Explicit exceptions, on the other hand, are defined in idl to be a part of an interface. Explicit exceptions are represented as ordinary mint types (e.g., as MINT_STRUCT); only implicit, "system-generated" exceptions are represented by MINT_SYSTEM_EXCEPTION.

System exceptions are handled specially because different rpc standards define different properties for system exceptions. For example, corba defines a standard set of exceptions that may be raised by the underlying orb, and also defines the data to be communicated within these system exceptions. onc rpc, on the other hand, defines a completely different method for communicating rpc errors to client programs.

Thus, in order to be general, mint must support system exceptions in an abstract way: mint defines when they may occur, but does not define the actual content or structure of system-generated exceptions. (These things are determined by Flick's individual back ends, long after the translation from aoi to mint takes place.) In a sense, a MINT_SYSTEM_EXCEPTION is a kind of placeholder that a back end must fill in as part of implementing a complete message protocol.

Because system exceptions are opaque to mint, a MINT_SYSTEM_EXCEPTION has no attributes.

5.2.2 Constants

In general, mint is only concerned with the structure of data, not with particular data values. Some data types, however, incorporate constants as part of their descriptions. Discriminated unions are a prime example. (In fact, discriminated unions are the only mint type that currently makes use of constants.) To support union discriminators and possibly other future mint type kinds, mint provides a way to express constant values.

A constant is represented as a mint_const, which is a pointer to a mint_const_u. A mint_const_u is a discriminated union of the possible constant kinds, as shown in the code below. There are three primitive constant types (integers, characters, and floats) and two constructed types (structures and arrays).

A primitive constant can be described as a literal value (a MINT_CONST_LITERAL) or as a symbolic value (a MINT_CONST_SYMBOLIC). Symbolic values are used when the specific value of a constant is unimportant in terms of abstract message format; in general, idl-specified constants are represented as literals and idl-unspecified constants (e.g., the discriminator values that select between normal and exceptional reply messages) are symbolic. In mint, it is not necessary to define the value of a symbolic constant: mint really only concerns itself with types, not specific values. Of course, a symbolic constant must eventually be assigned a value if the constant is to be used in generated stub code. This value is generally assigned by a Flick back end or by one of Flick's runtime library header files. In any case, it happens outside the scope of mint.

A compound (array or structure) constant is simply represented as an array of other mint constants. In a MINT_CONST_ARRAY, the number of sub-nodes is the array length, and the nodes themselves are the array elements, in order. In a MINT_CONST_STRUCT, the number of sub-nodes is the number of slots in the structure type. When matching a constant structure against a particular MINT_STRUCT type description (e.g., when interpreting a union discriminator value in terms of the defined union discriminator type), the slots of the constant and type descriptions are paired in order. The number of elements in each must be the same.

Other kinds of complex constants (e.g., unions) are not currently supported, but may be supported in the future if need arises.
 typedef struct mint_const_u *mint_const;
 
 enum mint_const_kind
 {
         MINT_CONST_INT          = 1,
         MINT_CONST_CHAR         = 2,
         MINT_CONST_FLOAT        = 3,
         MINT_CONST_STRUCT       = 4,
         MINT_CONST_ARRAY        = 5
 };
 
 enum mint_const_category
 {
         MINT_CONST_LITERAL      = 1,
         MINT_CONST_SYMBOLIC     = 2
 };
 
 union mint_const_int_u
 switch (mint_const_category kind)
 {
         case MINT_CONST_LITERAL:        long            value;
         case MINT_CONST_SYMBOLIC:       string          name<>;
 };
 
 union mint_const_char_u
 switch (mint_const_category kind)
 {
         case MINT_CONST_LITERAL:        char            value;
         case MINT_CONST_SYMBOLIC:       string          name<>;
 };
 
 union mint_const_float_u
 switch (mint_const_category kind)
 {
         case MINT_CONST_LITERAL:        double          value;
         case MINT_CONST_SYMBOLIC:       string          name<>;
 };
 
 typedef mint_const mint_const_struct<>;
 typedef mint_const mint_const_array<>;
 
 union mint_const_u
 switch (mint_const_kind kind)
 {
         case MINT_CONST_INT:    mint_const_int_u        const_int;
         case MINT_CONST_CHAR:   mint_const_char_u       const_char;
         case MINT_CONST_FLOAT:  mint_const_float_u      const_float;
         case MINT_CONST_STRUCT: mint_const_struct       const_struct;
         case MINT_CONST_ARRAY:  mint_const_array        const_array;
 };

5.2.3 Differences Between AOI and MINT Types

Comparing aoi and mint, one notices that certain aoi types are missing from mint:

AOI_ENUM
aoi enumeration types describe associations between names and values. In mint, names are unimportant. Therefore, aoi enumeration types can simply be "reduced" to MINT_INTEGER types, and references to specific enumeration values can be reduced to (literal) MINT_CONST_INTEGERs.
AOI_CONST
aoi constants definitions are similarly "compiled away." When needed, an aoi constant can be translated into a literal mint constant.
AOI_EXCEPTION
An AOI_EXCEPTION represents an idl-described exception, i.e., what corba calls a "user exception." Except for the semantic that these types are associated with runtime errors, an AOI_EXCEPTION simply describes a structure, and so they are translated into MINT_STRUCT types.
AOI_OPTIONAL
An optional type is represented as a MINT_ARRAY containing zero or one elements.
AOI_NAMESPACE
Namespaces are lexical notions, which have no importance to mint. Namespace definitions are simply discarded in the translation from aoi to mint.
AOI_FWD_INTRFC
Similarly, forward interface declarations are lexical notions and are unimportant to mint.
AOI_INDIRECT
An AOI_INDIRECT is a reference to a named type. Because names are unimportant to mint, indirect references can simply be compiled away by "dereferencing" the AOI_INDIRECT type.
AOI_ERROR
An AOI_ERROR represents an idl parse error -- obviously, not something mint needs to describe!

In addition, AOI_INTERFACE and MINT_INTERFACE represent different notions as described previously in Section 5.2.1. The different parts of an aoi interface type declaration become different mint constructs:

To summarize, the primary distinction between aoi and mint is that aoi describes interfaces in idl-like terms, and mint describes interfaces in terms of the messages that will implement an interface.

5.3 The MINT Library

The libmint library is provided to help deal with constructing and manipulating the various mint data structures. Its header file is mom/libmint.h and has the following functions:

void mint_add_standard_defs(mint_1 *mint)
Create the standard set of mint type definitions as described by the mint_standard_refs structure type, described in Section 5.2. The mint type definitions are added to the array of mint_defs in mint, and the mint_refs within mint->standard_refs are set to point to the proper definitions.
mint_ref mint_add_def(mint_1 *mint)
Return a mint_ref that refers to a newly allocated mint type definition (mint_def). The mint_def is completely uninitialized and must be filled in by the caller. For this reason, it is often more convenient to call one of the following, more specific constant constructors:
mint_ref mint_add_union_def(mint_1 *mint, mint_ref discrim_type, int len)
Return a mint_ref to a newly allocated MINT_UNION with the given discriminator type and number of cases. The cases are uninitialized; the default case is set to mint_ref_null.
mint_ref mint_add_integer_def(mint_1 *mint, int min, unsigned range)
Return a mint_ref to a newly allocated MINT_INTEGER with the given minimum value and range.
mint_ref mint_add_array_def(mint_1 *mint, mint_ref element_type, unsigned min_len,  unsigned max_len)
Return a mint_ref to a MINT_ARRAY with the given element type, minimum length, and maximum length. If a mint array definition with the given attributes already exists in mint, return a reference to it. Otherwise, allocate and initialize a new MINT_ARRAY definition.
mint_ref mint_add_def_tags(mint_def_kind kind, mint_1 *mint, int tag, ...)
Return a mint_ref to a mint definition of the given kind, with the definition slots initialized according to the list of tags. The tags and associated tag values are listed below. Note that most tags are appropriate for only certain mint type kinds. mint_def_add_tags will call panic if given a tag that is inappropriate for the specified mint type kind.
MINT_TAG_DONE
(No required tag values.) Marks the end of the tag list.
MDA_Min
(Required tag values: int.) The minimum value of a MINT_INTEGER type.
MDA_Range
(Required tag values: int.) The range of a MINT_INTEGER type.
MDA_Bits
(Required tag values: int.) The number of bits for a MINT_SCALAR, MINT_FLOAT, or MINT_CHAR.
MDA_Flags
(Required tag values: mint_scalar_flags or mint_char_flags.) The flags for a scalar or character type.
MDA_ElementType
(Required tag values: mint_ref.) The element type for a MINT_ARRAY.
MDA_LengthType
(Required tag values: mint_ref.) The length type for a MINT_ARRAY.
MDA_Slot
(Required tag values: mint_ref.) A slot within a MINT_STRUCT. This tag may be repeated in order to specify multiple structure slots. The slots are added to the structure in the order in which they are specified in the tag list.
MDA_Discrim
(Required tag values: mint_ref.) The discriminator type for a MINT_UNION.
MDA_Case
(Required tag values: mint_const and mint_ref.) A case within a MINT_UNION type. This tag may be repeated in order to specify multiple union cases.
MDA_Default
(Required tag values: mint_ref.) The default case in a MINT_UNION.
MDA_Tag
(Required tag values: mint_ref.) The type tag for a MINT_TYPED.
MDA_Ref
(Required tag values: mint_ref.) The typed reference (i.e., ref slot) within a MINT_ TYPED.
MDA_Right
(Required tag values: mint_interface_right.) The right within a MINT_INTERFACE type.

In addition, libmint.h provides a set of simple MINT_*_REF macros to be used in combination with the above tags to aid in the construction of mint type definitions. See the header file for details. Flick implementors must use these macros with caution, however, so as not to introduce portability problems. With these macros, it is easy to create an argument list that contains multiple calls to mint_ add_ def_ tags . Each call is a separate parameter, and each call has side effects, so the order in which the calls take place is significant. However, C doesn't guarantee an order of evaluation for function parameters. This means that the calls might be evaluated in different orders, depending on the compiler, thus producing different (although logically equivalent) mint_ def arrays. This in turn would cause Flick to produce different pres_c files on different platforms, thus making testing much more difficult!

void mint_get_int_size(mint_1 *mint, mint_ref itype, int *out_bits, int *out_signed)
Determine the number of bits (8, 16, or 32) required to represent the mint type referenced by itype. In essence, this function converts a description of an integer range into a bits/signedness representation. The required number of bits is stored in *out_bits and the signedness indicator (zero or one) is stored in *out_signed.
void mint_get_array_len(mint_1 *mint, mint_ref itype, unsigned *min, unsigned *max)
Determine the minimum and maximum lengths of the mint array referenced by itype. The minimum length is stored in *min and the maximum is stored in *max. (If the lengths are equal, then the array is fixed-length.)
int mint_add_struct_slot(mint_1 *mint, mint_ref struct_itype)
Add a new slot to the MINT_STRUCT referenced by struct_itype, and return the index of the new slot. The slot contents are uninitialized.
int mint_add_union_case(mint_1 *mint, mint_ref union_itype)
Add a new case to the MINT_UNION referenced by union_itype, and return the index of the new case. The case contents are uninitialized.
mint_ref mint_find_union_case(mint_1 *mint, mint_ref union_r, mint_const const_r)
Return a reference to the mint type node that is selected by const_r in the MINT_UNION referenced by union_r. (union_r must point to a union type.) If the constant does not correspond to any explicit case of the union, then this function returns the dfault branch of the union, which may be mint_ref_null.
mint_const mint_new_const(mint_const_kind kind)
Return a mint_const that refers to a newly allocated mint_const_u initialized with the given mint constant kind. Other fields of the returned constant description are uninitialized and must be filled in by the caller. Therefore, it is often more convenient to call one of the following, more specific constant constructors:
mint_const mint_new_const_int(int val)
Return a mint_const that points to a newly allocated mint_const_u describing the constant integer val.
mint_const mint_new_const_string(const char *val)
Return a mint_const that points to a newly allocated mint_const_u describing the constant string val. The string is represented as an array of characters, including a terminating NUL. (Note that this is different than the behavior of the aoi_new_const_string function described in Section 4.3.)
mint_const mint_new_const_from_aoi_const(aoi_const aoiconst)
Return a mint_const that points to a newly allocated mint_const_u that is the mint equivalent of the given aoi constant.
mint_const mint_new_symbolic_const(mint_const_kind kind, const char *name)
Return a mint_const that points to a newly allocated mint_const_u describing a symbolic constant with the given type and name.

int mint_const_cmp(mint_const c1, mint_const c2)
Compare two mint constants. Return 1 if the constants are unequal and 0 otherwise. Two constants of different types are never equal. Two primitive literal constants are equal only if they contain the same literal values; two primitive symbolic constants are equal only if they have the same name (and are of the same type, as just mentioned). Two compound constants are equal if they are structurally identical and have equal corresponding elements.

Note that a literal constant and a symbolic constant are never equal.

void mint_const_check(mint_const mc)
Check the validity of the given mint_const.
void mint_1_check(mint_1 *mint)
Check the validity of the given mint_1 structure. If an error is found, this function calls panic, which causes the process to print an error message and exit.
void mint_1_readfh(mint_1 *dest, FILE *fh)
Read a mint_1 structure from fh into dest. The disk data is stored in xdr format, and the actual I/O is performed by functions that are generated by rpcgen from the mom/mint.x file. If input fails for some reason, this function invokes panic.
void mint_1_writefh(mint_1 *src, FILE *fh)
Write the given mint_1 structure to fh. (As before, the data in the file is stored in xdr format, and the actual I/O is performed by rpcgen-generated functions.) This function invokes mint_1_check to verify the validity of the mint data before writing the data to disk. If output fails for some reason, this function calls panic.

5.4 Summary and Comments

mint allows Flick to represent messages in an abstract manner, without describing the exact message formats or data encodings that will eventually be used. There are ways, however, in which the current implementation of mint is problematic: either too abstract, or not abstract enough.

Primitive mint Types.
Some of the basic mint types, such as floats and characters, are perhaps too abstract. For instance, it is necessary to know more about the range of a floating-point type that just the total number of bits. Different idls may have different implicit semantics for floats, e.g., different expectations about the sizes of the exponent and mantissa. These expectations should be represented in mint (and properly in aoi as well). In a similar way, character types should describe additional properties such as the character set from which the character is chosen. Representing all of the encoding details of floats and characters is likely not to be worthwhile. A compromise would be to refer to some encoding details by the names of standards, e.g., "ASCII", "Unicode UTF-16", or "IEEE ...".
Interface and Operation Names.
The identifiers for interface, operations, and other "unpresented" parts of a mint tree are not sufficiently abstract.

The union discriminators used in the upper levels of the mint tree are chosen by the presentation generator from the names and codes described in aoi. In practice, these mint union discriminators then become the identifiers used by back ends when implementing their message formats. This is a problem: the presentation generators should not be choosing the identifiers that should be used in "unpresented" parts of a message. To fix this problem, mint must be extended to represent abstract interface and operation identifiers. These abstract identifiers should allow for multiple names, carried forward from aoi. (See the discussion in Section 4.5.) It would be the job of a back end to translate a mint abstract identifier into a concrete value, much in the way that back ends already handle mint symbolic constants.