Skip to main content

What goes where

A Flex file is its module header, then its imports, then a run of global declarations. A position is a place in that file where the grammar expects a declaration, a statement, or a clause, and most constructs stand in exactly one. Each table below answers one question — which positions accept a given construct.

module radar::sensors.tracking

component Radar;
component CommandPost;

message struct TrackReport {
    track_id: uint32;
    bearing_deg: float32;
}

struct SearchSector {
    start_deg: uint16;
    end_deg: uint16;
    assert end_deg > start_deg;
}

function span_deg(sector: SearchSector) -> uint16 {
    let span: uint16 = sector.end_deg - sector.start_deg;
    span;
}

const sweep_widths_deg: uint16[] = [w * 2 for w in [10: uint16, 20: uint16]];

local protocol Sweep in Radar {
    var sent: uint32 = 0;
    send any TrackReport to CommandPost;
    set sent = sent + 1;
}

global protocol Report {
    exch any TrackReport from Radar to CommandPost;
    in CommandPost {
        var seen: uint32 = 0;
        set seen = seen + 1;
    }
}

The positions​

PositionWhere it is
top levela file's body, after the header and the imports
blocka braced statement list: a function or transform body, and a branch of a statement if
contract bodyinside a contract
struct bodyinside a struct or a newtype
local bodyinside a local protocol
global bodyinside a global protocol
comprehensionafter the first element of a […] comprehension
  • A branch arm, a listen arm, a loop body in a local protocol, and an in block are all the local body position.
  • A choice arm, a parallel branch, and a loop body in a global protocol are all the global body position.
  • An in block is therefore the local body position sitting inside a global protocol.

Declarations​

The top level is a sequence of global declarations, and no other position accepts any of them:

Most may be preceded by a run of annotation uses. A struct or variant declaration may also carry leading modifier keywords. The header and the imports precede all of them — module has the shape of the file itself.

Statements​

Statementblockcontract bodystruct bodylocal bodyglobal body
let✓✓—✓—
assert✓✓✓——
if✓✓———
var———✓—
set———✓—
send———✓—
recv———✓—
branch———✓—
listen———✓—
exch————✓
choice————✓
parallel————✓
in————✓
loop———✓✓
break———✓✓
do———✓✓
a standalone annotation———✓✓
  • No statement stands at the top level, and no declaration stands in any of these positions.
  • A block's let and a local protocol's let are different statements, and they take different patterns.
  • A struct body takes its assertions after all of its fields.
  • var and set belong to a local protocol, so an in block is where a global protocol keeps state.
  • A break may name a loop that encloses the in block it stands in.
  • An in block holds local statements, so it does not accept another in.
  • Every annotation use other than the standalone form attaches to something. annotation holds the set of targets.

Clauses​

ClauseWhat takes it
extendsa struct declaration
givena transform declaration
givinga call to a transform that declares a given clause
into letexch
where, a predicatea send or exch payload that binds a name
assumingrecv, and exch … into
where, a variable lista choice naming more than one component
invarianta loop in a local protocol, or in an in block
for, if, let, scan, zip fora comprehension
  • A loop in a global protocol takes no invariant.
  • The comprehension clauses spelled if and let are clauses, not the statements above.

Expressions​

An expression stands in all of these slots:

  • a const initializer
  • a struct or newtype assertion
  • a block's statements and its tail value
  • a contract's assert
  • a let, var, or set value
  • a send or recv predicate
  • a branch or choice guard
  • a loop invariant
  • every clause of a comprehension

Some slots take less than a whole expression:

  • An annotation argument is a literal or a reference to a const. An argument built with an operator is a parse error.
  • An enum member's value is a literal.
  • A loop invariant begins with a reference to a bound variable or a let binding.
  • A guard of a choice naming more than one component reads only the variables its where clause defines.
  • ?name stands only in the body of the transform whose given clause declares it.

Types​

A type stands in all of these slots:

  • a struct or newtype field
  • a function or transform parameter and return type
  • an annotation parameter
  • a const declaration
  • a let or var annotation
  • an ascription, expr: Type
  • the right side of a type alias
  • an Optional<T> argument, an array's element, a tuple's element
  • the payload of send, recv, and exch
  • a value_cast target
  • the type a match pattern narrows to

Some slots take only certain types:

  • The payload of send, recv, and exch is a non-abstract message struct or a message variant.
  • A transform's parameter types and return type are non-abstract message structs.
  • An enum's backing type is a primitive.

Patterns​

SlotForms it takes
a block leta name, _, a tuple, or pat: Type
a protocol let or varone name
a recv bindinga name, _, a tuple, or pat: Type
a comprehension clause's bindinga name, _, a tuple, or pat: Type
a fold, map, filter, or flatmap bindinga name, _, a tuple, or pat: Type
a match arm_, a literal, some, none, a constructor, a tuple, an array, a name, pat as Type, pat : Type
  • A match arm is the only slot that takes the match patterns. pat as Type outside one is a parse error.

References​

SlotWhat the path names
from and to, on send, recv, and excha component
on, on send, recv, and excha connection
from and to, on a connection declarationa component
local protocol P in Ca component
in C { … }a component
choice in Ca component
do in a local protocola local protocol of the same component
do in a global protocola global protocol
a system membera local protocol
a group membera component or a group
extendsan extensible struct
an annotation usean annotation declaration
  • A send, recv, or exch needs a connection clause. A statement carrying none is a parse error.
  • An exch needs a from component, written or implied by an on connection.

Errors​

A declaration inside a protocol​

component Radar;

local protocol Sweep in Radar {
    const max_range_m: int32 = 40000;   // error: unexpected
}

A block statement in a global protocol​

component Radar;
component CommandPost;

message struct TrackReport {
    track_id: uint32;
}

global protocol Report {
    let latest: uint32 = 1;   // error: unexpected
    exch any TrackReport from Radar to CommandPost;
}

A field after an assertion​

struct SearchSector {
    start_deg: uint16;
    assert start_deg < 360;
    end_deg: uint16;   // error: unexpected
}

A break with no enclosing loop​

component Radar;

local protocol Sweep in Radar {
    break;   // error: break-outside-loop
}