Céu 0.10 - Reference Manual - (warning, incomplete!)

1

Introduction

Warning: This manual is under a rewriting process and still mostly reflects version 0.8.

Céu is an imperative, concurrent and reactive language in which then lines of execution, known as trails, react together continuously and in synchronous steps to external input events from the environment. Waiting for an event halts the running trail until that event occurs. The environment broadcasts an occurring event to all active trails, which share a single global time reference (the event itself).

The synchronous concurrency model of Céu greatly diverges from conventional multithreading (e.g. pthreads and Java threads) and the actor model (e.g. erlang and Go). On the one hand, trails can share variables in a deterministic and seamless way (e.g. no need for locks or semaphores). On the other hand, there is no real parallelism (e.g. multi-core execution) in the standard synchronous execution mode of the language.

Céu integrates well with C, being possible to define and call C functions from within Céu programs.

Céu is free software.

1.1

Synchronous execution model

Céu is grounded on a precise definition of logical time as a discrete sequence of external input events: a sequence because only a single input event is handled at a logical time; discrete because reactions to events are guaranteed to execute in bounded real time (see Bounded execution).

The execution model for Céu programs is as follows:

  1. The program initiates the boot reaction from the first line of code in a single trail.
  2. Active trails1, one after another, execute until they await or terminate. This step is named a reaction chain, and always runs in bounded time.
  3. The program goes idle and the environment takes control.
  4. On the occurrence of a new external input event, the environment awakes all trails awaiting that event. It then goes to step 2.

(1 Trails can be created with parallel compositions.)

The synchronous execution model of Céu is based on the hypothesis that internal reactions run infinitely faster in comparison to the rate of external events. An internal reaction is the set of computations that execute when an external event occurs. Conceptually, a program takes no time on step 2 and is always idle on step 3. In practice, if a new external input event occurs while a reaction chain is running (step 2), it is enqueued to run in the next reaction. When multiple trails are active at a logical time (i.e. awaking on the same event), Céu schedules them in the order they appear in the program text. This policy is somewhat arbitrary, but provides a priority scheme for trails, and also ensures deterministic and reproducible execution for programs. At any time, at most one trail is executing.

The program and diagram below illustrate the behavior of the scheduler of Céu:

 1:  input void A, B, C;
 2:  par/and do           // A, B, and C are external input events
 3:      // trail 1
 4:      <...>            // <...> represents non-awaiting statements
 5:      await A;
 6:      <...>
 7:  with
 8:      // trail 2
 9:      <...>
10:      await B;
11:      <...>
12:  with
13:      // trail 3
14:      <...>
15:      await A;
16:      <...>
17:      await B;
18:      par/and do
19:          // trail 3
20:          <...>
21:      with
22:          // trail 4
23:          <...>
24:      end
25:  end

The program starts in the boot reaction and splits in three trails (a par/and rejoins after all trails terminate). Following the order of declaration for the trails, they are scheduled as follows (t0 in the diagram):

As no other trails are pending, the reaction chain terminates and the scheduler remains idle until the event A occurs (t1 in the diagram):

During this reaction, new instances of events A, B, and C occur (t1 in the diagram) and are enqueued to be handled in the reactions that follow. As A happened first, it is used in the next reaction. However, no trails are awaiting it, so an empty reaction chain takes place (t2 in the diagram). The next reaction dequeues the event B (t3 in the diagram):

With all trails terminated, the program also terminates and does not react to the pending event C. Note that each step in the logical time line (t0, t1, etc.) is identified by the event it handles. Inside a reaction, trails only react to that identifying event (or remain suspended).

1.1.1

Parallel compositions and abortion

The use of trails in parallel allows programs to wait for multiple events at the same time. Céu supports three kinds of parallel compositions differing in how they rejoin and proceed to the statement in sequence:

  1. a par/and rejoins after all trails in parallel terminate;
  2. a par/or rejoins after any trail in parallel terminates;
  3. a par never rejoins (even if all trails terminate).

The termination of a trail inside a par/or aborts the other trails in parallel, which must be necessarily awaiting (from rule 2 of Execution model). Before aborting, a trail has a last opportunity to execute all active finalization statements.

As mentioned in the introduction and emphasized in the execution model, trails inside parallel compositions do not execute with real parallelism. Therefore, inside compositions trails are awaiting in parallel, rather than executing in parallel.

1.1.2

Bounded execution

Reaction chains should run in bounded time to guarantee that programs are responsive and can handle upcoming input events from the environment. For any loop statement in a program, Céu requires that every possible path inside its body contains at least one await or break statement, thus avoiding tight loops (i.e., unbounded loops that do not await).

In the example below, the if true branch may never execute, resulting in a tight loop (which the compiler complains about):

loop do
    if <cond> then
        break;
    end
end

For time-consuming algorithms that require unrestricted loops (e.g., cryptography, image processing), Céu provides Asynchronous execution.

1.1.3

Deterministic execution

TODO (shared memory + deterministic scheduler + optional static analysis)

1.1.4

Internal reactions

Céu provides inter-trail communication through internal events. Trails use the await and emit operations to manipulate internal events, i.e., a trail that emits an event can awake trails previously awaiting the same event.

An emit starts a new internal reaction in the program:

  1. On an emit, the scheduler remembers the statement following it to execute later (i.e., its continuation).
  2. All trails awaiting the emitted event awake and execute (like rule 2 for external reactions).
  3. The emitting trail resumes execution from its continuation.

If an awaking trail emits another internal event, a new internal reaction starts. The scheduler uses a stack policy (first in, last out) for saved continuation statements from rule 1.

Example:

1:  par/and do
2:      await e;
3:      emit f;
4:  with
5:      await f;
6:  with
7:      ...
8:      emit e;
9:  end

The emit e in trail-3 (line 8) starts an internal reaction that awakes the await e in trail-1 (line 2). Then, the emit f (line 3) starts another internal reaction that awakes the await f in trail-2 (line 5). Trail-2 terminates and the emit f resumes in trail-1. Trail-1 terminates and the emit e resumes in trail-3. Trail-3 terminates. Finally, the par/and rejoins (all trails have terminated) and the program terminates.

1.2

Organisms as abstractions

Céu uses an abstraction mechanism that reconciles data and control state into the single concept of an organism. Organisms provide an object-like interface (data state) as well as multiple lines of execution (control state).

A class of organisms is composed of an interface and a single execution body. The interface exposes public variables, methods, and internal events, just like objects. The body can contain any valid code in Céu, which starts on the organism instantiation and executes in parallel with the program. Organism instantiation can be either static or dynamic.

The example below (in the right) blinks two LEDs in parallel with different frequencies. Each blinking LED is a static instance organism of the Blink class:


 1:  class Blink with
 2:      var int led;
 3:      var int freq;
 4:  do
 5:      loop do
 6:          _on(this.led);
 7:          await (this.freq)s;
 8:          _off(this.led);
 9:          await (this.freq/2)s;
10:      end
11:  end
12:
13:  var Blink b1 with
14:       this.led  = 0;
15:       this.freq = 2;
16:  end
17:
18:  var Blink b2 with
19:       this.led  = 1;
20:       this.freq = 4;
21:  end
22:
23:  await 1min;

 1:  var _Blink b1 with
 2:      this.led  = 0;
 3:      this.freq = 2;
 4:  end
 5:
 6:  var _Blink b2 with
 7:      this.led  = 1;
 8:      this.freq = 4;
 9:  end
10:
11:  par/or do
12:      // body of b1
13:      loop do
14:          _on(b1.led);
15:          await (b1.freq)s;
16:          _off(b1.led);
17:          await (b1.freq)s;
18:      end
19:      await FOREVER;
20:  with
21:      // body of b2
22:      loop do
23:          _on(b2.led);
24:          await (b2.freq)s;
25:          _off(b2.led);
26:          await (b2.freq)s;
27:      end
28:      await FOREVER;
29:  with
30:      await 1min;
31:  end

The Blink class (lines 1-11) exposes the led and freq fields, which correspond to the LED port and blinking frequency to be configured for each instance. The application creates two instances, specifying the fields in the constructors (lines 13-16 and 18-21). A constructor starts the instance body to execute in parallel with the application. When reaching the await 1min (line 23), each instance already has its body switching between _on() and _off() every freq milliseconds (lines 5-10).

The code in the left is semantically equivalent to the one in the right, which expands the organisms bodies (lines 13-18 and 22-27) in a par/or with the rest of the application (await 1min, in line 30). Note the await FOREVER statements (lines 19 and 28) that avoid the organisms bodies to terminate the par/or. The _Blink type corresponds to a simple datatype without execution body (i.e., conventional structs or records or objects).

See also Organism declarations, Class and Interface declarations, and Organisms instantiation.


2

Lexical rules

2.1

Keywords

Keywords in Céu are reserved names that cannot be used as identifiers (e.g., variable and class names):



        and             async           async/thread    atomic          await

        bool            break           byte            call            call/rec

        char            class           continue        data            do

        else            else/if         emit            end             escape

        event           every           f32             f64             false

        finalize        float           FOREVER         function        global

        if              in              input           input/output    int

        interface       interrupt       kill            loop            native

        native/pre      new             not             nothing         null

        or              outer           output          output/input    par

        par/and         par/or          pause/if        pool            pre

        return          s16             s32             s64             s8

        request         sizeof          spawn           sync            tag

        then            this            traverse        true            u16

        u32             u64             u8              uint            until

        var             void            watching        with            word

        @const          @hold           @nohold         @plain          @pure

        @rec            @safe

2.2

Identifiers

Céu uses identifiers to refer to variables, internal events, external events, classes/interfaces, data types, data tags, fields, and native symbols.

ID       ::= <a-z, A-Z, 0-9, _>+
ID_var   ::= `_´ | ID           // [variables and internal events] beginning with a lowercase letter
ID_ext   ::= ID                 // [external events] all in uppercase, not beginning with a digit
ID_cls   ::= ID                 // [classes and interfaces] beginning with an uppercase letter
ID_data  ::= ID                 // [data types] beginning with an uppercase letter
ID_tag   ::= ID                 // [data tags] all in uppercase, not beginning with a digit
ID_field ::= ID                 // [fields] not beginning with a digit
ID_nat   ::= ID                 // [native symbols] beginning with an underscore
ID_type  ::= ( ID_nat | ID_cls  // [types]
             | <b>bool</b>  | <b>byte</b>  | <b>char</b>  | <b>f32</b>   | <b>f64</b>   |
             | <b>float</b> | <b>int</b>   | <b>s16</b>   | <b>s32</b>   | <b>s64</b>   |
             | <b>s8</b>    | <b>u16</b>   | <b>u32</b>   | <b>u64</b>   | <b>u8</b>    |
             | <b>uint</b>  | <b>void</b>  | <b>word</b> )

Class, interface, and data declarations create new types which can be used as type identifiers.

Examples:

var int a;                    // "a" is a variable, "int" is a type
emit e;                       // "e" is an internal event
await E;                      // "E" is an external input event
var Sprite s;                 // "Sprite" is a class and a type
var List l;                   // "List" is a data type and a type
return list.CONS.head;        // "CONS" is a tag, "head" is a field
_printf("hello world!\n");    // "_printf" is a native symbol

2.3

Literals

2.3.1

Booleans

Boolean types have the values true and false.

2.3.2

Integers

Integer values can be written in different bases and also as ASCII characters:

Examples:

// all following are equal to the decimal 127
v = 127;
v = 0777;
v = 0x7F;

// newline ASCII character = decimal 10
c = '\n';

2.3.3

Floats

TODO (like C)

2.3.4

Null pointer

The null literal represents null pointers.

2.3.5

Strings

A sequence of characters surrounded by " is converted into a null-terminated string, just like in C:

Example:

_printf("Hello World!\n");

2.4

Comments

Céu provides C-style comments.

Single-line comments begin with // and run to end of the line.

Multi-line comments use /* and */ as delimiters. Multi-line comments can be nested by using a different number of * as delimiters.

Examples:

var int a;    // this is a single-line comment

/** comments a block that contains comments

var int a;
/* this is a nested multi-line comment
a = 1;
*/

**/

3

Types

Céu is statically typed, requiring all variables and events to be declared before they are used.

A type is composed of an identifier with a sequence of optional modifiers:

Type ::= ID_type ( `&&´ | `&´ | `?´ | `[´ [NUM] `]´ )

A type identifier can be a native identifier, a class identifier, a data type identifier or one of the primitive types:

ID_type ::= ( ID_nat | ID_cls | ID_data
              bool  | byte  | char  | f32   | f64   |
              float | int   | s16   | s32   | s64   |
              s8    | u16   | u32   | u64   | u8    |
              uint  | void  | word )

Examples:

var u8 v;       // "v" is of 8-bit unsigned integer type
var _rect r;    // "r" is of external native type "rect"
var char&& buf; // "buf" is a pointer to a "char"
var Send s;     // "s" is an organism of class "Send"
var Tree t;     // "t" is a data of type "Tree"

3.1

Primitive types

Céu has the following primitive types:

    void               // void type
    word               // type with the size of platform dependent word
    bool               // boolean type
    char               // char type
    byte               // 1-byte type
    int      uint      // platform dependent signed and unsigned integer
    s8       u8        // signed and unsigned  8-bit integer
    s16      u16       // signed and unsigned 16-bit integer
    s32      u32       // signed and unsigned 32-bit integer
    s64      u64       // signed and unsigned 64-bit integer
    float              // platform dependent float
    f32      f64       // 32-bit and 64-bit floats

See also the literals for these types.

3.2

Native types

Types defined externally in C can be prefixed by _ to be used in Céu programs.

Example:

var _message_t msg;      // "message_t" is a C type defined in an external library

Native types support annotations which provide additional information to the compiler.

3.3

Class and Interface types

TODO (brief description)

See Classes and Interfaces.

3.4

Type modifiers

Types can be suffixed with the following modifiers: &, &&, ?, and [N].

3.4.1

References

TODO

Céu supports two forms of references: aliases and pointers.

3.4.1.1

Alias

TODO (like C++ references)

3.4.1.2

Pointer

TODO (like C)

restrictions - across yielding statements

3.4.2

Option

TODO (like Maybe)

3.4.3

Dimension

TODO (vectors, pools)

One-dimensional vectors are declared by suffixing the variable type with the vector length surrounded by [ and ]. The first index of a vector is zero.

Example:

var int[2] v;       // declares a vector "v" of 2 integers

4

Statements

4.1

Blocks

A block is a sequence of statements separated by semicolons (;):

Block ::= { Stmt `;´ }

Note: statements terminated with the end keyword do not require a terminating semicolon.

A block creates a new scope for variables, which are only visible for statements inside the block.

Compound statements (e.g. if-then-else) create new blocks and can be nested for an arbitrary level.

4.1.1

do-end

A block can be explicitly created with the do-end statement:

Do ::= do Block end

4.1.2

Pre

TODO ("static code" appended in sequence to the beginning)

Pre ::= pre do Block end

4.2

Nothing

nothing is a innocuous statement:

Nothing ::= nothing

4.3

Declarations

4.3.1

Variables

The syntax for the definition of variables is as follows:

DclVar ::= var Type ID_var [`=´ Assignment] { `,´ ID_var [`=´ Assignment] }

A variable has an associated type and can be optionally initialized (see Assignments).

Variables are only visible inside the block they are defined.

Examples:

var int a=0, b=3;   // declares and initializes integer variables "a" and "b"
var int[2] v;       // declares a vector "v" of size 2
4.3.1.1

Organisms

An organism is a variable whose type is the identifier of a class declaration. An optional constructor can initialize the organism fields:

DclOrg ::= var Type ID_var [ with
              Block
           end ]

Example:

class T with
    var int v;
do
    <body-of-T>
end
var T t with       // "t" is an organism of class "T"
    this.v = 0;    // whose field "v" is initialized to "0"
end

After the declaration, the body of an organism starts to execute in [parallel](#parallel-compositions] with the rest of the application. The table below shows the equivalent expansion of an organism declaration to a par/or containing the class body:

<code-pre-declaration>
var T t with
    <code-constructor-of-t>
end;
<code-pos-declaration>
<code-pre-declaration>
par/or do
    <code-constructor-of-t>
    <code-body-of-class-T>
    await FOREVER;
with
    <code-pos-declaration>
end

Given that an organism is a variable, the block it is declared restricts its lifetime. In the expansion, the par/or makes the organism to go out of scope when <code-pos-declaration> terminates.

TODO (assumes code-pos-declaration closes the block exactly on the end)

TODO (vectors of organisms: copy the declaration N times)

4.3.1.1.1
Constructors

Inside constructors the expression this refers to the new organism, while the expression outer refers to the enclosing organism creating the new organism:

class U with
    var int v;
do
    ...
end

class T with
    var int v;
do
    var U u with
        this.v = outer.v;   // "this" is of class "U", "outer" is of class "T"
    end;
end

4.3.2

Pools

A pool is a container for dynamic instances of organisms and recursive data of the same type:

DclPool ::= pool Type ID_var [`=´ Assignment] { `,´ ID_var [`=´ Assignment] }

The type has to be a class, interface, or data type identifier followed by a dimension modifier. For pools of classes and recursive data types, the number inside the dimension brackets represents the maximum number of instances supported by the pool. For pools of interfaces, the number represents the maximum number of bytes for all instances (as each instance may have a different size).

The number inside the vector modifier brackets is optional. If not specified, the number of instances in the pool is unbounded and all allocations go to the heap. When specified, allocation goes to a static memory pool preallocated at compile time.

Examples:

pool T[10]  ts;      // a pool of at most 10 instances of class "T"
pool T[]    ts;      // an unbounded pool of instances of class "T"
pool I[100] is;      // a pool of at most 100 bytes of instances of interface "I"
pool I[]    is;      // an unbounded pool of instances of interface "I"
pool D[100] ds;      // a pool of at most 100 instances of recursive data type "D"
pool D[]    ds;      // an unbounded pool of instances of recursive data type "D"

The lifetime of all instances inside a pool is restricted to the block it is declared. When a pool of organisms goes out of scope, all organism bodies are automatically aborted.

See Dynamic execution for organisms allocation. See TODO for recursive data allocation.

4.3.3

Functions

TODO (intro/prototype/implementation)

/* internal functions */
DclFun ::= function [@rec] `(´ParList`)´ `=>´ Type ID_var
              [ `do´ Block `end´ ]

/* external functions */
DclFunExt ::= output [@rec] `(´ParList`)´ `=>´ Type ID_var ID_ext { `,´ ID_ext }
            | input  [@rec] `(´ParList`)´ `=>´ Type ID_var ID_ext { `,´ ID_ext }
                 [ `do´ Block `end´ ]

Return ::= return [Exp]

ParList ::= ParItem { `,´ ParItem }
ParItem ::= [@hold] Type [ID_var]
4.3.3.1

Internal functions

TODO (like functions in any language)

4.3.3.2

External functions

TODO (more or less like dynamically loaded functions)

4.3.3.2.1
return

TODO (like return in any language)

4.3.4

Interrupt service routines

TODO

DclIsr ::= interrupt `[´ NUM `]´ [@rec]
              [ `do´ Block `end´ ]

4.3.5

Events

See also Event handling.

4.3.5.1

Internal events

Internal events have the same purpose of external events, but for communication within trails in a program.

The declaration of internal events is as follows:

DclInt ::= event (Type | `(´ TypeList `)´) ID_var { `,´ ID_var }

In contrast with external events, an internal event is for input and output at the same time.

Internal events cannot be of a vector type.

Note: void is a valid type for signal-only internal events.

4.3.5.2

External events

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

Being reactive, programs in Céu have input events as their sole entry points through await statements.

The declaration of input and output events is as follows:

DclExt ::= output (Type | `(´ TypeList `)´) ID_ext { `,´ ID_ext }
         | input  (Type | `(´ TypeList `)´) ID_ext { `,´ ID_ext }

TypeList ::= Type { `,´ Type }

Events communicate values between the environment and the application (and vice-versa). The declaration includes the type of the value, which can be also a list of types when the event communicates multiple values.

Note: void is a valid type for signal-only events.

The visibility of external events is always global, regardless of the block they are declared.

Examples:

input void A,B;      // "A" and "B" are input events carrying no values
output int MY_EVT;   // "MY_EVT" is an output event carrying integer values

The availability of external events depends on the platform in use. Therefore, external declarations just make pre-existing events visible to a program.

Refer to Environment for information about interfacing with external events in the platform level.

4.3.5.2.1
External Requests

TODO (emit + await)

DclReq ::= output/input `[´ [Exp] `]´ `(´ParList`)´ `=>´ Type ID_ext { `,´ ID_ext }
         | input/output `[´ [Exp] `]´ `(´ParList`)´ `=>´ Type ID_ext { `,´ ID_ext }
            [ `do´ Block `end´ ]

4.3.6

Classes and Interfaces

A class is a template for creating organisms. It contains an interface and a body common to all instances of the class. The interface exposes internal variables, events, and methods that other organisms can manipulate directly. The body specifies the behavior of the organism and executes when it is instantiated.

An interface is a template for classes that shares the same interface1. The body and method implementations may vary among classes sharing the same interface.

(1 The term "interface" is overload with two possible meanings: the set of members exposed by a class; and a template that defines a set of members that classes can reuse.)

The declaration of classes and interfaces is as follows:

DclCls ::= class ID_cls with
                Dcls    // interface
            do
                Block   // body
            end

DclIfc ::= interface ID_cls with
                Dcls    // interface
            end

Dcls ::= { (DclVar | DclInt | DclPool | DclFun | DclImp) `;´ }

DclImp ::= interface ID_cls { `,´ ID_cls }

Dcls is a sequence of variables, events, pools, and functions (methods) declarations. It can also refer to other interfaces through a DclImp clause, which copies all declarations from the referred interfaces.

4.3.7

Data Types

TODO

DclData ::= data ID_data with
                (Struct | Union)
            end

Struct ::= DclVar `;´ { DclVar `;´ }
Union  ::= DclTag { or DclTag }

DclVar ::= var Type ID_var { `,´ ID_var }
DclTag ::= tag ID_tag with
               DclVar `;´ { DclVar `;´ }
           end

Example (structured data type)

data Foo with
    var u8 a;
    var int b;
    var s16 c;
end

Example (tagged data type)

data Foo with
    // declare 'BAR' as one possible structure of 'Foo'
    tag BAR with
        var u8 a;
        var int b;
        var s16 c;
    end
    
    or
    
    // declare 'BAZ' as another possible structure of 'Foo'
    tag BAZ with 
        var int d;
        var s8 e;
    end
end

Note: Céu vectors are not yet supported within data types!

4.3.8

Native declarations

4.3.8.1

Native blocks

TODO (native/pre)

Native blocks define new types, variables, and functions in C:

Native ::= (native | native/pre) do
               <code_in_C>
           end

Example:

native do
    #include 
    int inc (int i) {
        return i+1;
    }
end
_assert(_inc(0) == 1);

If the code in C contains the terminating end keyword of Céu, the native block should be delimited with any matching comments to avoid confusing the parser:

native do
    /*** c code ***/
    char str = "This `end` confuses the parser";
    /*** c code ***/
end
4.3.8.2

Native annotations

Native declarations provide additional information about external C symbols. A declaration is an annotation followed by a list of symbols:

DclNat   ::= native [@pure|@const|@nohold|@plain] Nat_list
Nat_list  ::= (Nat_type|Nat_func|Nat_var) { `,` (Nat_type|Nat_func|Nat_var) }
Nat_type  ::= ID_nat `=´ NUM
Nat_func  ::= ID_nat `(´ `)´
Nat_var   ::= ID_nat

A type declaration may define its size in bytes to help the compiler organizing memory. A type of size 0 is an opaque type and cannot be instantiated as a variable that is not a pointer.

Functions and variables are distinguished by the () that follows function declarations.

Native symbols can have the following annotations:

@plain states that the type is not a pointer to another type. @const states that the symbol is a constant (e.g. a #define). @pure states that the function has no side effects. @nohold states that the function does not hold pointers passed as parameters.

The static analysis of Céu relies on annotations.

Examples:

native _char=1, _FILE=0;              // "char" is a 1-byte type, while `FILE` is "opaque"
native @plain  _rect;                  // "rect" is not a pointer type
native @const  _NULL;                  // "NULL" is a constant
native @pure   _abs(), _pow();         // "abs" and "pow" are pure functions
native @nohold _fprintf(), _sprintf(); // functions receive pointers but do not hold references to them

4.3.9

Deterministic annotations

A variable or function can be declared as @safe with a set of other functions or variables:

DclDet ::= @safe ID with ID { `,´ ID }

Example:

native _p, _f1(), _f2();
@safe _f1 with _f2;
var int* p;
@safe p with _p;
par do
    _f1(...);    // `f1` is safe with `f2`
    *p = 1;      // `p`  is safe with `_p`
    ...
with
    _f2(...);    // `f2` is safe with `f1`
    *_p = 2;     // `_p` is safe with `p`
    ...
end

See also Static analysis.

4.4

Assignments

Céu supports many kinds of assignments:

Set ::= (Exp | `(´VarList`)´) `=´ Assignment

VarList ::= ID_var  { `,´ ID_var } `)´

Assignment ::= Exp
             | AssignableBlock
             | <await>
             | ( [ `(´ ] <emit-ext>
                       | <call-ext>
                       | <request-ext>
                 [ `)´ ] )
             | [ `new´ ] Data
             | <traverse-loop>
             | <traverse-rec>
             | Vector
             | <lua>
             | <do-org>
             | <spawn>
             | <thread>

The expression on the left side must be assignable.

TODO (Exp, VarList)

4.4.1

Simple assignment

The simpler form of assignment uses expressions as values.

Example:

var int a,b;
a = b + 1;

4.4.2

Block assignment

A whole block can be used as an assignment value by escaping from it. The following block statements can be used in assignments: do-end if-then-else, loop, every, and par:

AssignableBlock ::= <do-end> | <if-then-else> | <loop> | <every> | <par>
4.4.2.1

escape

An escape statement escapes the deepest block being assigned to a variable. The expression following it is then assigned to the respective variable:

Escape ::= escape Exp

Every possible path inside the block must reach a escape statement whose expression becomes the final value of the assignment.

Example:

a = loop do              // a=1, when "cond" is satisfied
        ...
        if cond then
            escape 1;    // "loop" is the deepest assignment block
        end
        ...
    end

Every program in Céu contains an implicit do-end surrounding it, assigning to a special integer variable $ret holding the return value for the program execution.

Therefore, a program such as

escape 1;

should read as

var int $ret =
    do
        escape 1;
    end;

4.4.3

Await assignment

See Await statements.

4.4.4

Emit assignment

See Emit statements.

4.4.5

Data assignment

TODO

Data ::= ID_data [`.´ ID_tag] `(´ List `)´
List ::= [ (Data|Exp) { `,´ (Data|Exp) } ]

Example (structured data type)

// calls the constructor for 'Foo' and uses the provided values for struct initialization
var Foo f = Foo(4, 7, 1);

Example (tagged data type)

// calls the constructor for 'Foo' (using tag BAZ) and uses the provided values for struct initialization
var Foo f = Foo.BAZ(2, -9);

4.4.6

Traverse assignment

TODO

4.4.7

Vector assignment

TODO

Vector ::= Item { `..´ Item }
Item   ::= Exp | `[´ [ExpList] `]´

Example

var int[3] v;        // declare an empty vector of length 3
v = v .. [8];        // append value '8' to the empty vector
v = v .. [1] .. [5]; // append the values '1' and '5' to the vector
                     // here: v = {8, 1, 5}

4.4.8

Lua assignment

TODO

4.4.9

Do organism assignment

TODO

4.4.10

Spawn assignment

See Spawn.

4.4.11

Thread assignment

See Threads.

4.5

Calls

The syntax for function calls is as follows:

/* internal calls */
CallInt ::= [call|call/rec] Exp * `(´ [ExpList] `)´

/* external calls */
CallExt ::= (call+call/rec) ID_ext [ `=>´ (Exp | `(´ [ExpList] `)´)

ExpList = Exp { `,´ Exp }

4.5.1

Internal calls

TODO

4.5.2

External calls

TODO

4.6

Event handling

Events are the most fundamental concept of Céu, accounting for its reactive nature. Programs manipulate events through the await and emit statements. An await halts the running trail until that event occurs. An event occurrence is broadcast to all trails trails awaiting that event, awaking them to resume execution.

Céu supports external and internal events. External events are triggered by the environment, while internal events, by the emit statement. See also Synchronous execution model for the differences between external and internal reactions.

4.6.1

Await statements

The await statement halts the running trail until the referred wall-clock time, input event, or internal event occurs.

Await ::= ( await ID_ext |
            await Exp    |
            await (WCLOCKK|WCLOCKE)
          ) [ until Exp ]
       | await FOREVER

WCLOCKK ::= [NUM h] [NUM min] [NUM s] [NUM ms] [NUM us]
WCLOCKE ::= `(´ Exp `)´ (h|min|s|ms|us)

Examples:

await A;                  // awaits the input event `A`
await a;                  // awaits the internal event `a`

await 10min3s5ms100us;    // awaits the specified time
await (t)ms;              // awaits the current value of the variable `t` in milliseconds
    
await FOREVER;            // awaits forever

An await may evaluate to zero or more values which can be captured with the optional assignment syntax.

The optional until clause tests an additional condition required to awake. It can be understood as the expansion below:

loop do
    await <...>;
    if <Exp> then
        break;
    end
end
4.6.1.1

Await event

For await statements with internal or external events, the running trail awakes when the referred event is emitted. The await evaluates to the type of the event.

input int E;
var int v = await E;

event (int,int*) e;
var int  v;
var int* ptr;
(v,ptr) = await e;

TODO (awake rule for internal events, unless "every")

4.6.1.2

Await time

For await statements with wall-clock time (i.e., time measured in minutes, milliseconds, etc.), the running trail awakes when the referred time elapses.

A constant time is expressed with a sequence of value/unit-of-time pairs (see WCLOCKK above). An expression time is specified with an expression in parenthesis followed by a single unit of time (see WCLOCKE above).

The await evaluates to the residual delta time (dt) (i.e. elapsed time minus requested time), measured in microseconds:

var int dt = await 30ms;    // if 31ms elapses, then dt=1000

Note: dt is always greater than or equal to 0.

4.6.1.3

Await organism

TODO

4.6.1.4

Await FOREVER

The await FOREVER halts the running trail forever. It cannot be used in assignments, because it never evaluates to anything.

4.6.2

Emit statements

The emit statement triggers the referred wall-clock time, input event, or internal event, awaking all trails waiting for it.

Emit ::= emit Exp    [ `=>´ (Exp | `(´ [ExpList] `)´)
      |  emit ID_ext [ `=>´ (Exp | `(´ [ExpList] `)´)
      |  emit (WCLOCKK|WCLOCKE)
4.6.2.1

Emit event

Emit statements with internal or external events expect parameters that match the event type (unless the event is of type void).

Examples:

output int E;
emit E => 1;

event (int,int) e;
emit e => (1,2);

External input events can only be emitted inside asynchronous blocks.

The emission of internal events start new internal reactions.

TODO (emit output evaluates to "int")

4.6.2.2

Emit time

Emit statements with wall-clock time expect expressions with units of time, as described in Await time.

Like input events, time can only be emitted inside asynchronous blocks.

4.6.3

Requests

TODO (emit+await)

Request ::= request ID_ext [ `=>´ (Exp | `(´ [ExpList] `)´)

4.7

Organism instantiation

4.7.1

Do organism

TODO

DoOrg ::= do ID_cls [with
              Constructor
          end]

4.7.2

Spawn

The spawn statement creates instances of organisms dynamically:

Spawn ::= spawn ID_cls [in Exp] [with
              Constructor
          end]

TODO(option return)

The optional in clause allows the statement to specify in which pool the organisms will live. If absent, the organism is allocated on an implicit pool in the outermost block of the class the allocation happens.

On allocation, the body of the organism starts to execute in parallel with the rest of the application, just like static organisms. The constructor clause is also the same as for static organisms.

In contrast to static organisms, the lifetime of a dynamic instance is attached to the scope of the pool and not to the scope of the spawn instantiation. Furthermore, a dynamic organism is automatically deallocated when its execution body terminates.

See Static analysis for the restrictions on manipulating pointers and references to organisms.

4.7.3

Kill

TODO

kill * Exp * [ `=>´ Exp ]

4.8

Conditional

Conditional flow uses the if-then-else statement:

If ::= if Exp then
           Block
       { else/if Exp then
           Block }
       [ else
           Block ]
       end

The block following then executes if the condition expression after the if evaluates to a non-zero value. Otherwise, the same process holds each else/if alternative. Finally, it they all fail, the block following the else executes.

4.9

Loop

A loop continuously executes its body block:

Loop ::= loop[`/´ Exp] [ ID_var [in Exp] ] do
             Block
         end

A loop terminates when it reaches a break or its (optional) iterator terminates.

TODO (hard limit)

4.9.1

break

A break escapes the innermost enclosing loop:

Break ::= break

Example:

loop do                   // loop 1
    ...
    loop do               // loop 2
        if <cond-1> then
            break;        // escapes loop 2
        end
        ...
    end
    ...
    if <cond-2> then
        break;            // escapes loop 1
    end
    ...
end

4.9.2

continue

A continue restarts the innermost enclosing loop:

Continue ::= continue

Example:

loop do                   // loop 1
    ...
    loop do               // loop 2
        if <cond-1> then
            continue;        // restarts loop 2
        end
        ...
    end
    ...
    if <cond-2> then
        break;            // restarts loop 1
    end
    ...
end

A continue can only be used inside an if-then-else with an empty else branch and exactly one level deeper than the enclosing loop:

loop do
    par do    // makes the "continue" illegal
        if <cond> then
            continue;
        else  // makes the "continue" illegal
            ...
        end
    with
        ...
    end
end

4.9.3

Iterators

A loop may specify an iterator that yields a new value on each loop iteration.

4.9.3.1

Incremental index

For iterators in which Exp is empty or is of type int, ID_var is incremented after each loop iteration. ID_var is automatically declared read-only, with visibility restricted to the loop body, and is initialized to zero. The optional Exp limits the number of iterations, and is evaluated once before the loop starts.

Example:

loop i in 10 do
    _printf("i = %d\n", i);     // prints "i = 0" up to "i = 9"
end
4.9.3.2

Pool instances

For iterators in which Exp evaluates to a pool of organisms, ID_var evaluates to pointers to instances in the pool, one at a time, from the oldest to the newest created. ID_var is automatically declared read-only, with visibility restricted to the loop body.

TODO (example)

4.9.4

every

The every statement continuously awaits an event and executes its body:

Every ::= every (Var | `(´VarList`)´) in (WCLOCKK|WCLOCKE|ID_ext|Exp) do
              Block
          end

An every expands to a loop as illustrated below:

every <attr> in <event> do
    <block>
end
loop do
    <attr> = await <event>
    <block>
end

The body of an every cannot contain an await, ensuring that no occurrences of <event> are ever missed.

TODO (restrictions, escape/break)

TODO (exception to the rule for internal events)

4.9.5

Traverse

TODO

TraverseLoop ::= traverse ID_var in (`[´ Exp `]´ | Exp)
                    [ with Dcls end ]
                 do
                     Block
                 end
TraverseRec  ::= traverse['/' NUM] Exp
                     [ with Block end ]

4.10

Finalization

The finalize statement postpones the execution of its body to happen when its associated block goes out of scope:

Finalize ::= finalize
                 [Exp `=´ Assignment]
             with
                 Block
             end

The presence of the optional attribution clause determines which block to associate with the finalize:

  1. The enclosing block, if the attribution is absent.
  2. The block of the variable being assigned, if the attribution is present.

Example:


input int A;
par/or do
    var _FILE* f;
    finalize
        f = _fopen("/tmp/test.txt");
    with
        _fclose(f);
    end
    every v in A do
        fwrite(&v, ..., f);
    end
with
    await 1s;
end

The program opens f and writes to it on every occurrence of A. The writing trail is aborted after one second, but the finalize safely closes the file, because it is associated to the block that declares f.

The static analysis of Céu enforces the use of finalize for unsafe attributions.

4.11

Parallel compositions

The parallel statements par/and, par/or, and par split the running trail in multiple others:

Pars ::= (par/and|par/or|par) do
               Block
          with
               Block
          { with
               Block }
           end

They differ only on how trails terminate (rejoin).

See Synchronous execution model for a detailed description of parallel execution.

4.11.1

par/and

The par/and statement stands for parallel-and and rejoins when all trails terminate:

4.11.2

par/or

The par/or statement stands for parallel-or and rejoins when any of the trails terminate:

4.11.3

par

The par statement never rejoins and should be used when the trails in parallel are supposed to run forever:

4.11.4

watching

The watching statement aborts its body when its associated event occurs:

 Watching ::= watching [ (Var | `(´VarList`)´) in ] (WCLOCKK|WCLOCKE|ID_ext|Exp)
                 Block
             end

A watching expands to a par/or as illustrated below:

watching <...> in <event> do
    <block>
end
par/or do
    <...> await <event>
with
    <block>
end

TODO (Var/VarList is implicitly declared)

TODO: strong abortion

TODO: see Await for supported events

4.12

pause/if

TODO

Pause ::= pause/if Exp do
              Block
          end

4.13

Asynchronous execution

Asynchronous execution permit that programs execute time consuming computations without interfering with the synchronous side of applications (i.e., everything, except asynchronous statements).

Async ::= (async | async/thread) [ `(´VarList`)´ ] do
              Block
          end

4.13.1

Asynchronous blocks

Asynchronous blocks (async) are the simplest alternative for asynchronous execution.

An async body can contain non-awaiting loops (tight loops), which are disallowed on the synchronous side to ensure that programs remain reactive.

The optional list of variables copies values between the synchronous and asynchronous scopes. With the prefix &, the variable is passed by reference and can be altered from inside the async.

The next example uses an async to execute a time-consuming computation, keeping the synchronous side reactive. In a parallel trail, the program awaits one second to kill the computation if it takes too long:

var int fat;
par/or do
    var int v = ...

    // calculates the factorial of v
    fat = async (v) do
        var int fat = 1;
        loop i in v do   // a tight loop
            // v varies from 0 to (v-1)
            fat = fat * (i+1);
        end
        return fat;
    end;
with
    await 1s;          // watchdog to kill the async if it takes too long
    fat = 0;
end
return fat;

An async has the following restrictions:

  1. Only executes if there are no pending input events.
  2. Yields control on every loop iteration on its body.
  3. Cannot use parallel compositions.
  4. Cannot nest other asyncs.
  5. Cannot await events.
  6. Cannot emit internal events.
4.13.1.1

Simulation

An async is allowed to trigger input events and the passage of time, providing a way to test programs in the language itself:

input int A;

// tests a program with a simulation in parallel
par do

    // original program
    var int v = await A;
    loop i do
        await 10ms;
        _printf("v = %d\n", v+i);
    end

with

    // input simulation
    async do
        emit A=>0;      // initial value for "v"
        emit 1s35ms;    // the loop executes 103 times
    end
    return 0;
end

Every time the async emits an event, it suspends (due to rule 1 of previous section). The example prints the v = <v+i> message exactly 103 times.

4.13.2

Threads

TODO(async/thread)

4.13.2.1

Synchronous blocks

TODO

Sync ::= sync do
             Block
         end
4.13.2.2

Atomic blocks

TODO(mutual exclusion isr and sync)

Atomic ::= atomic do
             Block
         end

4.14

C statements

TODO

C ::= `{´ <C code> `}´

4.15

Lua statements

TODO

Lua ::= `[´ {`=´} `[´
                       { <lua code> | `@´ Exp }
                   `]´ {`=´} `]´

5

Expressions

The syntax for expressions in Céu is as follows:

Exp ::= Prim
        |  Exp or Exp
        |  Exp and Exp
        |  Exp (`!=´|`==´|`<=´|`<´|`>´|`>=´) Exp
        |  Exp `|´ Exp
        |  Exp `^´ Exp
        |  Exp `&´ Exp
        |  Exp (`<<´|`>>´) Exp
        |  Exp (`+´|`-´) Exp
        |  Exp (`*´|`/´|`%´) Exp
        |  (not|`+´|`-´|`~´|`*´|`&&´|`&´|`$$´|`$´) Exp
        |  `(´ Type `)´ Exp     /* same precedence as previous */
        |  Exp `[´ Exp `]´      /* same precedence for all following */
        |  Exp (`.´|`:´) (ID_field | ID_tag)
        |  Exp (`?´|`!´)
        |  Exp `(´ [ExpList] `)´ [finalize with Block end]

Prim ::= `(´ Exp `)´
        |  sizeof `(´ (Type|Exp) `)´
        |  ID_var | ID_nat
        |  null | NUM | String
        |  true | false
        |  global | this | outer
        |  (call | call/rec) Exp
        |  <c-stat>

Note: assignments are not expressions in Céu.

5.1

Primary

TODO: global, this, outer, ID_var, ID_nat, null, NUM, String, true, false, call/call/rec/finalize, C, parens

5.2

Arithmetic

The arithmetic operators of Céu are

    +      -      %      *      /      +      -

which correspond to addition, subtraction, modulo (remainder), multiplication, division, unary-plus, and unary-minus.

5.3

Relational

The relational operators of Céu are

    ==      !=      >      <      >=      <=

which correspond to equal-to, not-equal-to, greater-than, less-than, greater-than-or-equal-to, and less-than-or-equal-to.

Relational expressions evaluate to 1 (true) or 0 (false).

5.4

Logical

The logical operators of Céu are

    not      and      or

5.5

Bitwise

The bitwise operators of Céu are

    ~      &      |      ^      <<      >>

which correspond to not, and, or, xor, left-shift, and right-shift.

5.6

Vector indexing

Céu uses square brackets to index vectors:

Index ::= Exp `[´ Exp `]´

The expression on the left side is expected to evaluate to a vector.

Vector indexes start at zero.

5.7

References

TODO

5.7.1

Aliasing

TODO

Alias ::= `&´ Exp

The operand to &amp; must be an [[#sec.exps.assignable|assignable expression]].

5.8

### Pointer referencing and dereferencing

TODO

The operator &amp;&amp; returns the address of its operand, while the operator * dereferences its pointer operand.

Address ::= `&&´ Exp
Deref   ::= `*´ Exp

The operand to &amp;&amp; must be an [[#sec.exps.assignable|assignable expression]].

5.9

Fields

TODO (tags,fields)

5.9.1

Structs

The operators .´ and:´ access the fields of structs.

Dot   ::= Exp `.´ Exp
Colon ::= Exp `:´ Exp

The operator . expects a struct as its left operand, while the operator : expects a reference to a struct.

Example:

native do
    typedef struct {
        int v;
    } mystruct;
end
var _mystruct s;
var _mystruct* p = &s;
s.v = 1;
p:v = 0;

Note: struct must be declared in C, as Céu currently has no support for it.

5.9.2

Organisms

TODO

TODO (index clash)

5.10

Option

TODO (?!)

5.11

Type casting

Céu uses parenthesis for type casting:

Cast ::= `(´ ID_type `)´

5.12

Sizeof

A sizeof expression returns the size of a type or expression, in bytes:

Sizeof ::= sizeof `(´ (Type|Exp) `)´

5.13

Precedence

Céu follows the same precedence of C operators:

    /* lowest priority */

    or

    and

    !=    ==    <=    >=    <     >

    |

    ^

    &

    >>    <<

    +     -

    *     /     %

    not    +    -    ~    *    &&    &    $$    $    (Type)

    ()    []    :    .    ?    !

    /* highest priority */

5.14

Assignable expressions

An assignable expression (also known as an l-value) can be a variable, vector index, pointer dereference, or struct access. L-values are required in [[#sec.stmts.assignments|assignments]] and [[#sec.exps.pointers|references]].

Examples:

var int a;
a = 1;

var int[2] v;
v[0] = 1;

var int&& p;
*p = 1;

var _mystruct s;
s.v = 1;

var _mystruct&& ps;
ps:v = 1;

6

Static analysis

TODO (introduction)

6.1

Types

TODO (weakly typed, like C)

TODO (index clash)

6.2

Loops

TODO

6.3

Finalization

TODO

TODO (index clash)

6.4

Organisms references

TODO


7

Environment

As a reactive language, Céu depends on an external environment (the host platform) to provide input and output events to programs. The environment is responsible for sensing the world and notifying Céu about changes. The actual events vary from environment to environment, as well as the implementation for the notification mechanism (e.g. polling or interrupt-driven).

7.1

The C API

The final output of the compiler of Céu is a program in C that follows a standard application programming interface. The interface specifies some types, macros, and functions, which the environment has to manipulate in order to guide the execution of the original program in Céu.

The example below illustrates a possible main for a host platform:

#include "_ceu_app.c"

int main (void)
{
    char mem[sizeof(CEU_Main)];
    tceu_app app;
        app.data = &mem;
    ceu_app_init(&app);

    while(app->isAlive) {
        ceu_sys_go(app, CEU_IN__ASYNC,  CEU_EVTP((void*)NULL));
        ceu_sys_go(app, CEU_IN__WCLOCK, CEU_EVTP(<how-much-time-since-previous-iteration>));
        if (occuring(CEU_IN_EVT1)) {
            ceu_sys_go(app, CEU_IN__EVT1, param1);
        }
        ...
        if (occuring(CEU_IN_EVTn)) {
            ceu_sys_go(app, CEU_IN__EVTn, paramN);
        }
    }
    return app->ret;
}

int occurring (int evt_id) {
    <platform dependent>
}

tceu_app is a type that represents an application in Céu. The field app.data expects a pointer to the memory of the application, which has to be previously declared.

TODO

7.1.1

Types

TODO

TODO (index clash)

7.1.2

Functions

TODO

TODO (index clash)

7.1.3

Macros

TODO

7.1.4

Constants and Defines

TODO

7.2

Compiler

Céu provides a command line compiler that generates C code for a given input program. The compiler is independent of the target platform.

The generated C output should be included in the main application, and is supposed to be integrated with the specific platform through the presented [[#sec.env.api|API]].

The command line options for the compiler are as follows:

./ceu <filename>              # Ceu input file, or `-` for stdin

    --output <filename>       # C output file (stdout)

    --defs-file <filename>    # define constants in a separate output file (no)

    --join (--no-join)        # join lines enclosed by /*{-{*/ and /*}-}*/ (join)

    --dfa (--no-dfa)          # perform DFA analysis (no-dfa)
    --dfa-viz (--no-dfa-viz)  # generate DFA graph (no-dfa-viz)

    --m4 (--no-m4)            # preprocess the input with `m4` (no-m4)
    --m4-args                 # preprocess the input with `m4` passing arguments in between `"` (no)

The values in parenthesis show the defaults for the options that are omitted.


8

Errors

8.1

Pointer attributions (11xx)

8.1.1

1101 : wrong operator

Use of the unsafe operator ":=" for non-pointer attributions.

Instead, use =.

Example:

var int v := 1;

>>> ERR [1101] : file.ceu : line 1 : wrong operator

8.1.2

1102 : attribution does not require "finalize"

Use of finalize for non-pointer attributions.

Instead, do not use finalize.

Example:

var int v;
finalize
    v = 1;
with
    <...>
end

>>> ERR [1102] : file.lua : line 3 : attribution does not require "finalize"

8.1.3

1103 : wrong operator

Use of the unsafe operator := for constant pointer attributions.

Instead, use =.

Example:

var int ptr := null;

>>> ERR [1103] : file.ceu : line 1 : wrong operator

8.1.4

1104 : attribution does not require "finalize"

Use of finalize for constant pointer attributions.

Instead, do not use finalize.

Example:

var int ptr;
finalize
    ptr = null;
with
    <...>
end

>>> ERR [1104] : file.lua : line 3 : attribution does not require `finalize´

8.1.5

1105 : destination pointer must be declared with the "[]" buffer modifier

Use of normal pointer * to hold pointer to acquired resource.

Instead, use [].

Example:

var int* ptr = _malloc();

>>> ERR [1105] : file.ceu : line 1 : destination pointer must be declared with the `[]´ buffer modifier

8.1.6

1106 : parameter must be "hold"

Omit @hold annotation for function parameter held in the class or global.

Instead, annotate the parameter declaration with @hold.

Examples:

class T with
    var void* ptr;
    function (void* v)=>void f;
do
    function (void* v)=>void f do
        ptr := v;
    end
end

>>> ERR [1106] : file.ceu : line 6 : parameter must be `hold´

/*****************************************************************************/

native do
    void* V;
end
function (void* v)=>void f do
    _V := v;
end

>>> ERR [1106] : file.ceu : line 5 : parameter must be `hold´

8.1.7

1107 : pointer access across "await"

Access to pointer across an await statement. The pointed data may go out of scope between reactions to events.

Instead, don't do it. :)

(Or check if the pointer is better represented as a buffer pointer ([]).)

Examples:

event int* e;
var int* ptr = await e;
await e;     // while here, what "ptr" points may go out of scope
escape *ptr;

>>> ERR [1107] : file.ceu : line 4 : pointer access across `await´

/*****************************************************************************/

var int* ptr = <...>;
par/and do
    await 1s;   // while here, what "ptr" points may go out of scope
with
    event int* e;
    ptr = await e;
end
escape *ptr;

>>> ERR [1107] : file.ceu : line 8 : pointer access across `await´

8.1.8

1108 : "finalize" inside constructor

Use of finalize inside constructor.

Instead, move it to before the constructor or to inside the class.

Examples:

class T with
    var void* ptr;
do
    <...>
end

var T t with
    finalize
        this.ptr = _malloc(10);
    with
        _free(this.ptr);
    end
end;

>>> ERR [1008] : file.ceu : line 7 : `finalize´ inside constructor

/*****************************************************************************/

class T with
    var void* ptr;
do
    <...>
end

spawn T with
    finalize
        this.ptr = _malloc(10);
    with
        _free(this.ptr);
    end
end;

>>> ERR [1008] : file.ceu : line 7 : `finalize´ inside constructor

8.1.9

1109 : call requires "finalize"

Call missing finalize clause.

Call passes a pointer. Function may hold the pointer indefinitely. Pointed data goes out of scope and yields a dangling pointer.

Instead, finalize the call.

Example:

var char[255] buf;
_enqueue(buf);

>>> ERR [1009] : file.ceu : line 2 : call requires `finalize´'

8.1.10

1110 : invalid "finalize"

Call a function that does not require a finalize.

Instead, don't use it.

Example:

_f() finalize with
        <...>
     end;

>>> ERR [1010] : file.ceu : line 1 : invalid `finalize´

9

Syntax


Stmt ::= <empty-string>
      |  nothing
      |  escape Exp
      |  return [Exp]
      |  break
      |  continue

  /* Declarations */

      /* variables, organisms, pools, and internal events */
      | var Type ID_var [`=´ <Assignment>] { `,´ ID_var [`=´ <Assignment>] }
      | var Type ID_var with
            Block
        end
      | pool Type ID_var [`=´ <Assignment>] { `,´ ID_var [`=´ <Assignment>] }
      | event (Type | `(´ TypeList `)´) ID_var { `,´ ID_var }

      /* internal functions */
      | function [@rec] `(´ParList`)´ `=>´ Type ID_var
            [ `do´ Block `end´ ]

      /* external functions */
      | output [@rec] `(´ParList`)´ `=>´ Type ID_var ID_ext { `,´ ID_ext }
      | input  [@rec] `(´ParList`)´ `=>´ Type ID_var ID_ext { `,´ ID_ext }
            [ `do´ Block `end´ ]

      /* interrupts */
      | interrupt `[´ NUM `]´ [@rec]
            [ `do´ Block `end´ ]

      /* external events */
      | output (Type | `(´ TypeList `)´) ID_ext { `,´ ID_ext }
      | input  (Type | `(´ TypeList `)´) ID_ext { `,´ ID_ext }

      /* external requests */
      | output/input `[´ [Exp] `]´ `(´ParList`)´ `=>´ Type ID_ext { `,´ ID_ext }
      | input/output `[´ [Exp] `]´ `(´ParList`)´ `=>´ Type ID_ext { `,´ ID_ext }
            [ `do´ Block `end´ ]

      /* classes & interfaces */
      | class ID_cls with
            Dcls
        do
            Block
        end
      | interface ID_cls with
            Dcls
        end
          where
              Dcls   ::= { (<var> | <event-int> | <pool> | <function> | DclImp) `;´ }
              DclImp ::= interface ID_cls { `,´ ID_cls }

      /* data types */
      | data ID_data with
            (Struct | Union)
        end
          where
              Struct ::= DclVar `;´ { DclVar `;´ }
              Union  ::= DclTag { or DclTag }
                  where
                      DclVar ::= var Type ID_var { `,´ ID_var }
                      DclTag ::= tag ID_tag with
                                     DclVar `;´ { DclVar `;´ }
                                 end

      /* C integration */
      | native [@pure|@const|@nohold|@plain] Nat_list
          where
              Nat_list  ::= (Nat_type|Nat_func|Nat_var) { `,` (Nat_type|Nat_func|Nat_var) }
              Nat_type  ::= ID_nat `=´ NUM
              Nat_func  ::= ID_nat `(´ `)´
              Nat_var   ::= ID_nat
      | (native/pre | native) do
            <C code definitions>
        end

      /* deterministic annotations */
      | @safe ID with ID { `,´ ID }

  /* Assignments */

      | (Exp | `(´VarList`)´) `=´
          /* Assignment */
          ( Exp
          | AssignableBlock
          | <await>
          | ( [ `(´ ] <emit-ext>
                    | <call-ext>
                    | <request-ext>
              [ `)´ ] )
          | [ `new´ ] Data
          | <traverse-loop>
          | <traverse-rec>
          | Vector
          | <lua>
          | <do-org>
          | <spawn>
          | <thread>
          )
              where
                  Data ::= ID_data [`.´ ID_tag] `(´ List `)´
                  List ::= [ (Data|Exp) { `,´ (Data|Exp) } ]

                  Vector ::= Item { `..´ Item }
                  Item   ::= Exp | `[´ [ExpList] `]´

                  AssignableBlock ::= <do-end> | <if-then-else> | <loop> | <every> | <par>

  /* Function calls */

      /* internal calls */
      | [call|call/rec] Exp * `(´ [ExpList] `)´

      /* external calls */
      | (call+call/rec) ID_ext [ `=>´ (Exp | `(´ [ExpList] `)´)

  /* Event handling */

      /* internal/external await */
      | ( await ID_ext
        | await Exp
        | await (WCLOCKK|WCLOCKE)
        ) [ until Exp ]
      | await FOREVER

      /* internal/external emit */
      | emit Exp    [ `=>´ (Exp | `(´ [ExpList] `)´)
      | emit ID_ext [ `=>´ (Exp | `(´ [ExpList] `)´)
      | emit (WCLOCKK|WCLOCKE)

      /* external request */
      | request ID_ext [ `=>´ (Exp | `(´ [ExpList] `)´)

  /* Organism instantiation */

      /* do organism */
      | do ID_cls with
            Block
        end

      /* spawn */
      | spawn * ID_cls * [in Exp]
            [ with Block end ]

      /* kill */
      | kill * Exp * [ `=>´ Exp ]

  /* Flow control */

      /* explicit block */
      |  do Block end

      /* pre (top level) execution */
      | pre do
            Block
        end

      /* conditional */
      | if Exp then
            Block
        { else/if Exp then
            Block }
        [ else
            Block ]
        end

      /* loops */
      | loop[`/´ Exp] [ ID_var [in Exp] ] do
            Block
        end
      | every (Var | `(´VarList`)´) in (WCLOCKK|WCLOCKE|ID_ext|Exp) do
            Block
        end

      /* traverse */
      | traverse ID_var in (`[´ Exp `]´ | Exp)
            [ with Dcls end ]
            do
                Block
            end
      | traverse['/' NUM] Exp
            [ with Block end ]

      /* finalization */
      | finalize [<assignment>] with
            Block
        end

      /* parallel compositions */
      | (par/and|par/or|par) do
            Block
        with
            Block
        { with
            Block }
         end
      | watching [ (Var | `(´VarList`)´) in ] (WCLOCKK|WCLOCKE|ID_ext|Exp)
        do
            Block
        end

      /* pause */
      | pause/if Exp do
            Block
        end

      /* asynchronous execution */
      | (async | [async/thread]) [ `(´VarList`)´ ] do
            Block
        end

      /* synchronization */
      | sync do
            Block
        end
      | atomic do
            Block
        end

  /* C integration */

     | `{´ <C code> `}´

  /* Lua integration */

      | `[´ {`=´} `[´
            { <lua code> | `@´ Exp }
        `]´ {`=´} `]´

/* Block */

Block ::= { Stmt `;´ }

/* Identifiers */

ID       ::= <a-z, A-Z, 0-9, _> +
ID_var   ::= `_´ | ID    // beginning with a lowercase letter
ID_ext   ::= ID          // all in uppercase, not beginning with a digit
ID_cls   ::= ID          // beginning with an uppercase letter
ID_data  ::= ID          // beginning with an uppercase letter
ID_tag   ::= ID          // all in uppercase, not beginning with a digit
ID_field ::= ID          // not beginning with a digit
ID_nat   ::= ID          // beginning with an underscore
ID_type  ::= ( ID_nat | ID_cls | ID_data
             | bool  | byte  | char  | f32   | f64   |
             | float | int   | s16   | s32   | s64   |
             | s8    | u16   | u32   | u64   | u8    |
             | uint  | void  | word )

/* Types */

Type ::= ID_type ( `&&´ | `&´ | `?´ | `[´ [NUM] `]´ )

/* Lists */

TypeList ::= Type    { `,´ Type    }
ExpList  ::= Exp     { `,´ Exp     }
VarList  ::= ID_var  { `,´ ID_var  }
ParList  ::= ParItem { `,´ ParItem }
                where
                    ParItem ::= [@hold] Type [ID_var] 

/* Wall-clock values */

WCLOCKK ::= [NUM h] [NUM min] [NUM s] [NUM ms] [NUM us]
WCLOCKE ::= `(´ Exp `)´ (h|min|s|ms|us)

/* Expressions */

Exp ::= Prim
        |  (`$$´|`$´) Exp
        |  Exp (`?´|`!´)
        |  Exp `(´ [ExpList] `)´ [finalize with Block end]

Prim ::= `(´ Exp `)´
        |  ID_var | ID_nat
        |  null | NUM | String
        |  true | false
        |  (call | call/rec) Exp
        |  <c-code>

/* Operator precedence */

    /* lowest priority */
    or
    and
    !=    ==    <=    >=    <     >
    |
    ^
    &
    >>    <<
    +     -
    *     /     %
    not    +    -    ~    *    &&    &    $$    $    (Type)
    ()    []    :    .    ?    !
    /* highest priority */

/* Other */

    // single-line comment

    /** nested
        /* multi-line */
        comments **/

    # preprocessor directive


10

License

Céu is distributed under the MIT license reproduced below:

 Copyright (C) 2012 Francisco Sant'Anna
 
 Permission is hereby granted, free of charge, to any person obtaining a copy of
 this software and associated documentation files (the "Software"), to deal in
 the Software without restriction, including without limitation the rights to
 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 of the Software, and to permit persons to whom the Software is furnished to do
 so, subject to the following conditions:
 
 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.