Data Types

Basic Data Types

There are seven basic data types in the Vesta System Description Language: Each of these are described below.


A boolean value, either true or false.  There are only two literals of type bool: TRUE and FALSE.


An integer value.  Integer literals can be written in decimal, or following the C conventions for octal and hexadecimal.  All of these are valid integer literals:
07531 // Octal 7531, equal to 3929 decimal
0xa0  // Hex a0, equal to 160 decimal


An arbitrary byte sequence.  Can be anything from a short string, to an entire source file, to the binary data contained in a compiled library.

Text literals follow the C/C++ convention for double-quoted strings.  Examples of valid text literals:

"Simple text."
"Text with \"quotes\"."
"Examples of\n\tescaped whitespace.\n"


A sequence of zero or more arbitrary values.

List literals are enclosed in angle brackets with individual elements separated by commas:

<1, "abcdefg", FALSE>
List elements can be specified by any arbitrary expression, including lists:
<1, <"abc", "def", "ghi"> >
A trailing comma is allowed after the last list element:
<1, 2, 3, 4, >
The empty list can be represented by angle brackets with nothing between them:


A mapping from names to values.  More precisely, a sequence of zero or more pairs, in which the first member  of each pair is a non-empty value of type text, the second is any arbitrary value, and the first members of all the pairs are distinct.

Binding literals are enclosed in square brackets with commas separating individual assignments.  As with lists, the empty binding can be represented with empty square brackets:

The simplest way to write a binding is as though it were a sequence of variable assignments:
[ foo = 1, bar = TRUE, msg = "a string", ]
The values can be arbitrary expressions (including other lists, nested bindings, etc.).  Note that, as with lists, a trailing comma is allowed.  Beyond this form, there are a variety of shortcuts and more complicated forms for creating bindings.  The simplest of these is the self-assigning binding:
[ foo, bar, msg ]
This is equivalent to writing:
[ foo = foo, bar = bar, msg = msg ]
If foo, bar, and msg are variables with values assigned to them, then this would capture the values of those variables in the binding.  As with lists, it is possible to have bindings containing bindings:
[ foo = [ a = 1 ], bar = [ b = 2] ]
However, it can quickly become tedious to write nested bindings in this fashion.  For this reason, there's a shortcut.  The following binding is equivalent to the previous one:
[ foo/a = 1, bar/b = 2 ]
These nested binding "paths" can be arbitrarily deep.  For example, these two bindings are equivalent:
[ Cxx/switches/program/shared_libs = "-non_shared" ]

[ Cxx = [ switches = [ program = [ shared_libs = "-non_shared" ] ] ] ]

It's possible to replace either the name in a binding assignment or one of the names in a binding path assignment with a variable or an arbitrary expression.  If there is a variable containing a text value, it can be prepended with the dollar sign to use its value as a name:
name = "foo";
[ $name = 1 ]                // Same as [ foo = 1]
[ bar/$name/a = "a string" ] // Same as [ bar/foo/a = "a string"]
There are two different but equivalent forms with which arbitrary expressions can be used in place of names in bindings: $(expression) and %expression%.  For example:
[ $("foo" + "bar") = TRUE ]                      // Same as [ foobar = TRUE ]
[ %"foo" + "bar"% = FALSE ]                      // Same as [ foobar = FALSE ]
[ foo/$(_sub("barbaz", 0, 3))/a = <1, 2, 3> ] // Same as [ foo/bar/a = <1,2,3> ]
[ foo/%_sub("barbaz", 3, 3)%/b = <4, 5, 6> ]  // Same as [ foo/baz/b = <4,5,6> ]


A function, much like a lambda expression (as seen in the Lisp and Scheme languages).  (Functions are first-class values in Vesta and can be created at run-time.)  More precisely, a function (or closure) is a triple <e, f, b> where: There is no way to specify a literal function value.  The only way to define a function is to bind it to a name with a function definition statement.


A value indicating that a run-time error has occurred.

There is only one literal of type err: ERR.

The use of ERR is considered deprecated at this point, and is supported only to provide backward-compatibility with older Vesta models. A much better way to indicate a run-time error is with the _assert primitive function.

Aggregate Type Expressions

The Vesta SDL includes a small sub-language of type expressions, which includes the ability to describe aggregate types (lists, bindings, and functions) with varying degrees of detail.  It is possible to define type names which refer to simple or complex types (such as a list of integers) with a type definition statement.  Type expressions, including previously defined named types, may be attached to function arguments and results and to local variables, indicating the type of the expected value for these identifiers and expressions during evaluation.

The Vesta evaluator currently treats type expressions as syntactically checked comments; it performs no other checking. Future implementations may type-check expressions at run-time and report an error if the value does not match the specified type.

The simplest form of type expression is just the name of one of the basic types: bool, int, text, list, binding, function.  Also, you can express that something may be of any type with the keyword any.  Each of the three aggregate types (list, binding, function) has more complex forms which allow you to specify the types of its componenets.

List type expressions

Lists are the simplest, because the only restriction you can make is to state that all elements of a list must have a particular type.  For example:
Would be a list of booleans.  Incidentally, list by itself is equivalent to list(any).

Binding type expressions

Bindings have two more specific forms.  First, you can specify that all elements of a binding must have values of a particular type.  This:
Specifies a binding where the value portion of each element is of type text.  You can also specify that a binding must have particular names bound to particular types:
binding(x:int, y:int, z:int)
The above specifies a binding which must have three names (x, y, and z) all bound to integer values.

Function type expressions

A function type expression can have types specified for its arguments and its return value, and either or both of these can be omitted.  For example:
function : bool
Indicates a function which returns a boolean with unspecified arguments.  Conversely:
Specifies a function which takes a single text string argument, but whose return type is unspecified.  When argument types are specified, argument names may be as well:
function(t: text, i: int): text
The above describes a function taking a text argument named t and an integer argument named i and which returns a text string.

A complex example

Type expressions can be arbitrarily complex.  For example, the following:
function(function(text, bool): int, binding(:bool)): list(int)
Describes a function which:
Kenneth C. Schalk <>   / Vesta SDL Programmer's Reference