Storage Entities

Storage entities represent all objects that are stored in memory during execution. Céu supports variables, vectors, events (external and internal), and pools as entity classes.

An entity declaration consists of an entity class, a type, and an identifier.

Examples:

var    int    v;     // "v" is a variable of type "int"
var[9] byte   buf;   // "buf" is a vector with at most 9 values of type "byte"
input  none&& A;     // "A" is an input event that carries values of type "none&&"
event  bool   e;     // "e" is an internal event that carries values of type "bool"
pool[] Anim   anims; // "anims" is a dynamic "pool" of instances of type "Anim"

A declaration binds the identifier with a memory location that holds values of the associated type.

Lexical Scope

Storage entities have lexical scope, i.e., they are visible only in the block in which they are declared.

The lifetime of entities, which is the period between allocation and deallocation in memory, is also limited to the scope of the enclosing block. However, individual elements inside vector and pool entities have dynamic lifetime, but which never outlive the scope of the declaration.

Entity Classes

Variables

A variable in Céu holds a value of a declared type that may vary during program execution. The value of a variable can be read in expressions or written in assignments. The current value of a variable is preserved until the next assignment, during its whole lifetime.

Example:

var int v = _;  // empty initializaton
par/and do
    v = 1;      // write access
with
    v = 2;      // write access
end
escape v;       // read access (yields 2)

Vectors

A vector in Céu is a dynamic and contiguous collection of variables of the same type.

A vector declaration specifies its type and maximum number of elements (possibly unlimited). The current length of a vector is dynamic and can be accessed through the operator $.

Individual elements of a vector can be accessed through an index starting from 0. Céu generates an error for out-of-bounds vector accesses.

Example:

var[9] byte buf = [1,2,3];  // write access
buf = buf .. [4];           // write access
escape buf[1];              // read access (yields 2)

TODO: ring buffers

Events

Events account for the reactive nature of Céu. Programs manipulate events through the await and emit statements. An await halts the running trail until the specified event occurs. An event occurrence is broadcast to the whole program and awakes trails awaiting that event to resume execution.

Unlike all other entity classes, the value of an event is ephemeral and does not persist after a reaction terminates. For this reason, an event identifier is not a variable: values can only be communicated through emit and await statements. A declaration includes the type of value the occurring event carries.

Note: none is a valid type for signal-only events with no associated values.

Example:

input  none I;           // "I" is an input event that carries no values
output int  O;           // "O" is an output event that carries values of type "int"
event  int  e;           // "e" is an internal event that carries values of type "int"
par/and do
    await I;             // awakes when "I" occurs
    emit e(10);          // broadcasts "e" passing 10, awakes the "await" below
with
    var int v = await e; // awaits "e" assigning the received value to "v"
    emit O(v);           // emits "O" back to the environment passing "v"
end

As described in Internal Reactions, Céu supports external and internal events with different behavior.

External Events

External events are used as interfaces between programs and devices from the real world:

  • input events represent input devices such as a sensor, button, mouse, etc.
  • output events represent output devices such as a LED, motor, screen, etc.

The availability of external events depends on the environment in use.

Programs can emit output events and await input events.

Internal Events

Internal events, unlike external events, do not represent real devices and are defined by the programmer. Internal events serve as signalling and communication mechanisms among trails in a program.

Programs can emit and await internal events.

Pools

A pool is a dynamic container to hold running code abstractions.

A pool declaration specifies the type of the abstraction and maximum number of concurrent instances (possibly unlimited). Individual elements of pools can only be accessed through iterators. New elements are created with spawn and are removed automatically when the code execution terminates.

Example:

code/await Anim (none) => none do       // defines the "Anim" code abstraction
    <...>                               // body of "Anim"
end
pool[] Anim as;                         // declares an unlimited container for "Anim" instances
loop i in [1->10] do
    spawn Anim() in as;                 // creates 10 instances of "Anim" into "as"
end

When a pool declaration goes out of scope, all running code abstractions are automatically aborted.

TODO: kill

Locations

A location (aka l-value) is a path to a memory position holding a value.

The list that follows summarizes all valid locations:

  • storage entity: variable, vector, internal event (but not external), or pool
  • native expression or symbol
  • data field
  • vector index
  • vector length $
  • pointer dereferencing *
  • option unwrapping !

Locations appear in assignments, event manipulation, iterators, and expressions. Locations are detailed in Locations and Expressions.

Examples:

emit e(1);          // "e" is an internal event
_UDR = 10;          // "_UDR" is a native symbol
person.age = 70;    // "age" is a field of "person"
vec[0] = $vec;      // "vec[0]" is a vector index
$vec = 1;           // "$vec" is a vector length
*ptr = 1;           // "ptr" is a pointer to a variable
a! = 1;             // "a" is of an option type

References

Céu supports aliases and pointers as references to entities, aka strong and weak references, respectively.

An alias is an alternate view for an entity: after the entity and alias are bounded, they are indistinguishable.

A pointer is a value that is the address of an entity, providing indirect access to it.

As an analogy with a person's identity, a family nickname referring to a person is an alias; a job position referring to a person is a pointer.

Aliases

Céu support aliases to all storage entity classes, except external events and pointer types. Céu also supports option variable aliases which are aliases that may be bounded or not.

An alias is declared by suffixing the entity class with the modifier & and is acquired by prefixing an entity identifier with the operator &.

An alias must have a narrower scope than the entity it refers to. The assignment to the alias is immutable and must occur between its declaration and first access or next yielding statement.

Example:

var  int v = 0;
var& int a = &v;        // "a" is an alias to "v"
...
a = 1;                  // "a" and "v" are indistinguishable
_printf("%d\n", v);     // prints 1

An option variable alias, declared as var&?, serves two purposes:

  • Map a native resource to Céu. The alias is acquired by prefixing the associated native call with the operator &. Since the allocation may fail, the alias may remain unbounded.
  • Hold the result of a spawn invocation. Since the allocation may fail, the alias may remain unbounded.

Accesses to option variable aliases must always use option checking or unwrapping.

TODO: or implicit assert with & declarations

Examples:

var&? _FILE f = &_fopen(<...>) finalize with
                    _fclose(f);
                end;
if f? then
    <...>   // "f" is assigned
else
    <...>   // "f" is not assigned
end
var&? My_Code my_code = spawn My_Code();
if my_code? then
    <...>   // "spawn" succeeded
else
    <...>   // "spawn" failed
end

Pointers

A pointer is declared by suffixing the type with the modifier && and is acquired by prefixing an entity with the operator &&. Applying the operator * to a pointer provides indirect access to its referenced entity.

Example:

var int   v = 0;
var int&& p = &&v;      // "p" holds a pointer to "v"
...
*p = 1;                 // "p" provides indirect access to "v"
_printf("%d\n", v);     // prints 1

The following restrictions apply to pointers in Céu:

  • No support for pointers to events, vectors, or pools (only variables).
  • A pointer is only accessible between its declaration and the next yielding statement.