annotation
A named piece of metadata with optional parameters and optional scope restrictions. It is a global declaration, importable like a struct or a const, and it leaves the element it decorates unchanged.
annotation Classification(level: string)
annotation Deprecated
@Deprecated
@Classification("unclassified")
struct TrackReport {
track_id: uint32;
bearing_deg: float32;
}Parameters
Parameters follow the name in parentheses, each a name, a colon, and a type.
- Parameters are optional. A parameterless annotation takes no parentheses, and an empty
()is a parse error. - Parameter names are unique within the declaration.
- A parameter's type may be any type.
annotation Note(id: int32, msg: string)
annotation Critical
annotation Offset(x: int32, y: int32)Scopes
A scope list between | bars restricts where the annotation may be applied. With no list, it applies
to any target below.
| Keyword | Target |
|---|---|
Struct / Field | a struct declaration / one of its fields |
Variant / VariantConstructor | a variant declaration / one of its constructors |
Enum / EnumValue | an enum declaration / one of its members |
Newtype | a newtype declaration (NewType is accepted as well) |
TypeAlias | a type alias |
Const | a const declaration |
Function / Transform / Contract | the corresponding declaration |
Component / Connection / System | the corresponding declaration |
LocalProtocol / GlobalProtocol | a local protocol / global protocol declaration |
DeclAnnotation | an annotation declaration itself |
ProtocolStmt / ProtocolState | an annotatable protocol statement: send, recv, exch, a listen arm, or a standalone use |
Unique / Requirement | not a target — see below |
- Each name in the list is one of the keywords above.
- Several keywords may be listed, separated by whitespace, and a use matching any one of them is accepted.
UniqueandRequirementname no target. Listed alone, they leave the annotation applicable anywhere; listed beside a target scope, that scope still restricts.
annotation Deprecated | Struct Variant VariantConstructor |
annotation FieldTag(tag: uint8) | Field |
annotation Topic(name: string) | ProtocolStmt |Unique
Unique limits an annotation to one use per set of argument values per package.
- Two uses carrying the same argument values within one package are an error, and every use after the first is flagged.
- Uses whose arguments differ are unrelated.
- The rule is package-scoped, so the same values may repeat in a different package, and two colliding uses may sit in different modules of one package.
- An argument-less annotation carries an empty argument tuple, which equals itself, so a bare
| Unique |marker appears at most once per package. - Arguments compare as values, not as spellings.
@TrackId(42),@TrackId(0x2A), and@TrackId(4_2)are one value, as are1.0,1.00, and1e0. - A constant reference is not evaluated.
@TrackId(max_tracks)is compared by the declarationmax_tracksresolves to, so it never collides with@TrackId(42)even whenmax_tracksis42. Two references to the same constant do collide.
annotation TrackId(id: int32) | Unique |
const max_tracks: int32 = 42;
@TrackId(42)
struct TrackReport { track_id: uint32; }
@TrackId(max_tracks)
struct TrackUpdate { track_id: uint32; }Requirement
Requirement marks the annotation as carrying requirement identity. The language records the mark
and reads nothing from it; requirement tracing outside the language is what reads it. A use is
checked exactly as any other use is.
Like Unique, it names no target, so a target scope listed beside it is what decides where the
annotation may be applied.
enum GpsRequirement int32 {
SysReq1234 = 1234;
SysReq1235 = 1235;
}
annotation GpsClaim(req: GpsRequirement) | Requirement LocalProtocol |Uses
A use is @, the annotation's path, and arguments in parentheses when the declaration takes
parameters. It stands immediately before the element it decorates, on its own line or on that
element's line, and several uses stack in order.
- The Target column above is the whole set of positions a use may occupy. An
import, amoduleheader, alet, and a newtype's single field take none. - The path must resolve to an annotation declaration. An annotation imported under a module alias is
used as
@alias.Deprecated.
annotation Deprecated | Struct Variant VariantConstructor Field EnumValue |
annotation FieldTag(tag: uint8) | Field |
@Deprecated
struct Contact {
@FieldTag(1) contact_id: uint32;
@Deprecated @FieldTag(2) bearing_deg: float32;
}
variant TrackKind {
Air(uint32);
@Deprecated Surface(uint32);
}
enum SensorMode string {
Search = "search";
@Deprecated Sweep = "sweep";
}Arguments
An argument is a literal or a path naming a const or an enum member, either one optionally preceded
by a unary -. No other expression is an argument.
- Arguments match parameters positionally, and the count must match exactly.
- Each argument's type must be assignable to its parameter's type. A numeric literal pins to the parameter's width.
- A path argument carries the type of the declaration it resolves to.
- Unary
-applies to a numeric literal or a numeric constant, and never to an unsigned-integer parameter.
annotation Offset(x: int32, y: int32)
annotation Label(name: string, active: bit)
annotation Mode(mode: SensorMode)
enum SensorMode string {
Search = "search";
Track = "track";
}
const default_offset: int32 = 25;
@Offset(-10, default_offset)
@Label("header", true)
@Mode(SensorMode.Search)
struct DisplayHint { hint_id: uint32; }Protocol statements
Annotations on a protocol carry transport metadata — a topic, a URL, a timeout — and do not affect what the protocol does. They appear in two positions.
- Attached: a trailing run on a
send,recv, orexchstatement, or on alistenarm, ahead of the terminator. These belong to that statement. - Standalone: a bare use as a statement of its own, anywhere a protocol statement is allowed. Each use is one statement, so two uses written ahead of another statement are two statements rather than a run attached to it.
A standalone use is scope-checked as a protocol statement, so ProtocolStmt and ProtocolState both
admit it.
message struct TrackReport { track_id: uint32; }
component Radar;
component CommandPost;
annotation Topic(name: string) | ProtocolStmt |
annotation RecvWithinMs(ms: int32) | ProtocolStmt |
global protocol ReportTrack {
@Topic("tracks")
exch any TrackReport from Radar to CommandPost
@RecvWithinMs(1000);
}Errors
Two parameters with one name
annotation Note(id: int32, id: string) // error: duplicate-annotation-paramA scope the language does not define
The scope list is a fixed vocabulary.
annotation Deprecated | Gadget | // error: invalid-annotation-scopeThe same Unique values twice in one package
annotation TrackId(id: int32) | Unique |
@TrackId(42)
struct TrackReport { track_id: uint32; }
@TrackId(42) // error: duplicate-unique-annotation
struct TrackUpdate { track_id: uint32; }Using something that is not an annotation
struct Contact { contact_id: uint32; }
@Contact // error: not-an-annotation
struct Radar { scan_period_ms: uint32; }The wrong number of arguments
annotation Note(id: int32, msg: string)
@Note(42) // error: annotation-arg-count
struct TrackReport { track_id: uint32; }An argument the parameter's type does not accept
annotation Note(id: int32, msg: string)
annotation FieldTag(tag: uint8) | Field |
@Note("42", "late") // error: annotation-arg-type
struct TrackReport {
@FieldTag(-1) track_id: uint32; // error: annotation-arg-type
}Applying an annotation outside its scopes
annotation Deprecated | Struct |
@Deprecated // error: annotation-scope-mismatch
variant TrackKind { Air(uint32); Surface(uint32); }