The stub handles the conversions for most values automatically. However, for those parameters that do not map directly into a single host language data type or that do not map to any host language data type, the encoding and decoding of the UTS value is placed under programmer control. Specifically, a representative for the UTS value is supplied as the argument value. Then, routines in the UTS library can be invoked with the representative as an argument to allow the programmer to inquire as to the UTS type of the corresponding value and to perform explicit conversion of values to and from the UTS language format and the format of the host language. Thus, the representative of a value can be viewed as a ticket that is presented to an agent to gain access to the value. The value itself is maintained by the agent, which also assigns the representative.
The UTS syntax provides for the expression of the most common base types as well as record and array composite types. Support for procedure arguments and arbitrary nesting of composite types is provided. Provision is also made for underspecified types. Import and export specifications have the following format:
import prog_name prog (args) [returns (type)] export prog_name prog (args) [returns (type)]
args ::= epsilon | arg args arg ::= direction represent type direction ::= val | res | var | epsilon represent ::= rep | epsilon types ::= epsilon | type types type ::= name single | name composite name ::= "text-string" | epsilon single ::= basetype | signature | error | null composite ::= record | array | prog basetype ::= simple | varying simple ::= integer | float | double | bool varying ::= string[number] | byte [number] record ::= record{types} array ::= array(name sizes) of type sizes ::= number | number, sizes prog ::= prog(args) | prog(args) returns(name type)
types ::= type or type | (type) | ? | * args ::= * sizes ::= * | size, sizes size ::= number - number | number - | - numberor is the type union operator; for example, the type constructed by ``
integer or float
''
contains all values of type integer and all
values of type float. The type ``?'' is the universal set; it contains
all single UTS values, including values of the composite types. The
``*'' operation, which is valid only as the last field of a record or
prog constructor, signifies a series of any number of UTS values of
any type.
For example, the type denoted by the expression
``record{integer, string[5], *}
''
includes any record that has an integer value in its first field
and a string of length 5 in its second field, no matter the contents
of the rest of the record.
The type
``record{integer, string[5], ?}
''
contains only the subset of those records that are exactly 3 elements long.
The use of ranges is simple; for example, ``string[3-6]
''
contains strings
with length between 3 and 6 (inclusive). A missing bound in a range
operation means that the bound is unspecified, so that the type
``string[3-]
''
contains any string with length greater than or equal to 3. Note that a
missing lower bound is equivalent to a lower bound of 0. The type
``string[-]
''
contains a string of any length. Where possible, the stub compilers handle underspecified types. For example, the C stub compiler (schc) will automatically handle underspecified strings, dynamically allocating memory as needed, and performing length checks at the upper and lower ends of the specified range of lengths. If the target language does not support dynamic memory, underspecified types have to be handled using a representative.
import sum prog("arg1" var array[10] of float) returns ("ans" float) export artest prog(res array ["sub1" 500, "sub2" 10] of float) export cvd prog(var record{float, float}) returns (integer) export sort prog(var array[100] of record{string[30], array [5] of integer, float}) import recur prog(val integer, val prog(val integer, val integer) returns (integer)) returns (integer)