ArcLang grammar (EBNF)
The normative syntax of ArcLang. The parser accepts exactly this; anything else is a compile error with a line and a column.
(* ===========================================================================
ArcLang grammar — CANONICAL specification
===========================================================================
This file is the single source of truth for ArcLang SYNTAX; the typed
element kinds, attributes, enumerations and units are specified in
spec/METAMODEL.md (generated from src/compiler/metamodel.rs). It describes
exactly what src/compiler/parser.rs accepts in v3. If the parser and this
file disagree, one of them has a bug — file an issue.
Conventions:
- The parser is STRICT: any construct not derivable from this grammar is
a compile error with a source location. Nothing is silently skipped.
- `dataflow`, `data_flows`, `validation` and `traceability` blocks are
accepted syntactically but NOT yet represented in the compiled model;
the compiler emits a warning for each occurrence (see "Unmodeled
blocks" below). Everything else in this grammar is fully modeled.
=========================================================================== *)
(* ---- Lexical elements ---------------------------------------------------- *)
Identifier ::= ( Letter | "_" ) ( Letter | Digit | "_" )* ;
DottedName ::= Identifier ( "." Identifier )* ;
String ::= '"' Character* '"' ; (* \n \t \r \" \\ escapes *)
Number ::= "-"? Digit+ ( "." Digit+ )? ; (* "_" digit separators allowed *)
Name ::= DottedName | String ;
LineComment ::= "//" AnyCharacterExceptNewline* ;
BlockComment ::= "/*" AnyCharacter* "*/" ;
(* ---- Top level ------------------------------------------------------------ *)
CompilationUnit ::= ImportDecl* ModelDecl ( ImportDecl | TopLevelBlock )*
| ( ImportDecl | TopLevelBlock )+ ;
(* Multi-file models: the path is resolved relative to the importing file.
The compiler merges imported fragments into one model; circular imports
and missing files are errors. *)
ImportDecl ::= "import" STRING ;
ModelDecl ::= ( "model" | "system" ) Name "{" ModelElement* "}" ;
ModelElement ::= MetadataBlock
| ModelAttribute
| TopLevelBlock ;
MetadataBlock ::= "metadata" AttributeBlock ;
ModelAttribute ::= AttributeKey ":" AttributeValue ;
TopLevelBlock ::= RequirementsBlock
| ArchitectureBlock
| OperationalAnalysis
| SystemAnalysis
| LogicalArchitecture
| PhysicalArchitecture
| Epbs
| SafetyAnalysis
| SecurityAnalysis
| SecurityScales
| TraceDecl
| DiagramDecl
| TableDecl
| UnmodeledBlock ; (* warning emitted *)
(* ---- Requirements ---------------------------------------------------------- *)
RequirementsBlock ::= "requirements" RequirementsSubtype? "{" RequirementDecl* "}" ;
RequirementsSubtype ::= "stakeholder" | "system" | "safety" | Identifier ;
RequirementDecl ::= "req" Name String? AttributeBlock (* req REQ-001 "Title" { ... } *)
| "requirement" Name AttributeBlock (* requirement "REQ-001" { ... } *)
| "concern" Name AttributeBlock ; (* concern "Driver safety" { stakeholders: [...] } *)
(* A requirement frames concerns (frames: [...]), is about a subject (subject: "LC-1")
and requires or assumes constraints written as comparisons (require: ["mass <= 1200 kg"]).
`concern` is also declared in a system_analysis block. *)
(* ---- Operational Analysis (OA) --------------------------------------------- *)
OperationalAnalysis ::= "operational_analysis" Name "{" OaElement* "}" ;
OaElement ::= "actor" Name AttributeBlock
| ( "operational_entity" | "entity" ) Name "{" EntityElement* "}"
| OperationalCapabilityDecl
| OperationalActivityDecl
| OperationalExchange
| TraceDecl
| Attribute ; (* name: overrides block name *)
EntityElement ::= OperationalActivityDecl
| Attribute ;
OperationalActivityDecl ::= ( "operational_activity" | "activity" ) Name
"{" ( Attribute | FunctionPortDecl | OperationalActivityDecl )* "}" ;
(* an activity carries ports and sub-activities, as a function does *)
OperationalExchange ::= ( "operational_exchange" | "exchange" | "interaction" )
( Name "->" Name AttributeBlock (* arrow form *)
| Name AttributeBlock ) ; (* block form: from:/to: required *)
(* ---- System Analysis (SA) --------------------------------------------------- *)
SystemAnalysis ::= "system_analysis" Name "{" SaElement* "}" ;
SaElement ::= RequirementDecl
| ( "function" | "system_function" ) Name "{" FunctionElement* "}"
| "actor" Name "{" ( Attribute | ComponentPortDecl )* "}"
| "system_component" Name "{" ( Attribute | ComponentPortDecl )* "}"
| "component_exchange" Name AttributeBlock (* from_port:/to_port:, or ends: [...]
for more than two ends *)
| FunctionalExchange
| MissionDecl
| CapabilityDecl
| FunctionalChainDecl
| TraceDecl
| Attribute ;
(* Capabilities nest: one declared inside another is part of it. Relations
between capabilities of ONE level are attributes of the source:
extends: [ <ref>* ], includes: [ <ref>* ], specializes: [ <ref>* ].
A target that is unknown, of another level or the capability itself is
an ERROR. involves: [ <ref>* ] names actors, entities, activities and
processes (operational) or functions, actors and chains (system). *)
OperationalCapabilityDecl ::= "operational_capability" Name
"{" ( Attribute | OperationalCapabilityDecl )* "}" ;
(* Arcadia: Mission requires Capability; Capability realized across layers;
Functional Chains exemplify capabilities. *)
MissionDecl ::= "mission" Name AttributeBlock ;
CapabilityDecl ::= "capability" Name "{" ( Attribute | CapabilityDecl )* "}" ;
(* attributes: id:, mission: <ref>, realizes: <ref>,
involves: [ <ref>* ] — references resolve by id or
unambiguous name; dangling references are ERRORS *)
FunctionalChainDecl ::= "functional_chain" Name "{" ( Attribute | ControlNodeDecl | SequenceLinkDecl )* "}" ;
(* involves: [ <ref>* ] ordered: functions, exchanges and
CHAINS (a chain involving a chain references it, as
Capella does); empty is a WARNING (path not described
yet). Control nodes and sequence links branch the
chain; without any, the chain is the order of involves. *)
ControlNodeDecl ::= "control" ( "and" | "or" | "iterate" ) Name AttributeBlock? ;
(* id: defaults to <chain id>.<name> *)
SequenceLinkDecl ::= "sequence" Name "->" Name AttributeBlock? ;
(* each end a step of the chain (as written in involves)
or one of its control nodes, else an ERROR;
attributes: condition: <text>, id: *)
FunctionElement ::= "function" Name AttributeBlock? (* nested sub-function *)
| FunctionPortDecl
| Attribute ;
(* Function ports are strictly input XOR output (Arcadia). *)
FunctionPortDecl ::= "port" ( "in" | "out" ) Name AttributeBlock? ;
ComponentPortDecl ::= "port" ( "in" | "out" | "inout" ) Name
( "{" ( Attribute | ComponentPortDecl )* "}" )? ;
(* physics: signal|electrical|mechanical_translational|
mechanical_rotational|thermal|fluid (on a port, a physical
port, or the type a port `is:`) — the Modelica connector of
`arclang export -f modelica`; pole: positive|negative;
flange: a|b. Ends of one link must have the same physics
(ERROR otherwise). *)
(* a port may hold ports; an exchange names one
as Owner.port.sub, drawn at the outer port *)
(* A function of the logical or physical level: declared inside the
component that performs it (allocation by containment), or at the level
when nothing performs it yet (a breakdown's parents). It carries its own
ports and sub-functions; `realizes: <ref>` names the function of the
level above it realizes. Exchanges between the functions of a level are
declared at that level with FunctionalExchange, their ends being
functions or `Function.port`. *)
LevelFunctionDecl ::= "function" Name
( "{" ( Attribute | FunctionPortDecl | LevelFunctionDecl )* "}" )? ;
(* attributes: data_type:, type: data|control|event *)
FunctionalExchange ::= ( "functional_exchange" | "exchange" | "flow" )
( Name "->" Name AttributeBlock
| Name AttributeBlock ) ; (* from:/to: required *)
(* ---- Logical Architecture (LA) ----------------------------------------------- *)
LogicalArchitecture ::= "logical_architecture" Name "{" LaElement* "}"
| "architecture" "logical" Name? "{" LaElement* "}" ;
CapabilityRealizationDecl ::= ( "capability_realization" | "capability" ) Name
"{" ( Attribute | CapabilityRealizationDecl )* "}" ;
LaElement ::= Component
| LevelFunctionDecl (* a function no component performs *)
| FunctionalExchange (* between logical functions *)
| "interface" Name "{" InterfaceBody "}"
| ConnectionDecl
| "component_exchange" Name AttributeBlock (* from_port:/to_port:, or ends: [...]
for more than two ends *)
| CapabilityRealizationDecl
| FunctionalChainDecl
| TraceDecl
| Attribute ;
Component ::= "component" Name "{" ComponentElement* "}" ;
ComponentElement ::= Component (* nested components *)
| ComponentPortDecl
| LevelFunctionDecl (* the logical functions it performs *)
| "interface_in" ":"? Name "{" InterfaceAttrs "}"
| "interface_out" ":"? Name "{" InterfaceAttrs "}"
| "provides" "interface"? Name "{" InterfaceAttrs "}"
| "requires" "interface"? Name "{" InterfaceAttrs "}"
| OccurrenceDecl
| Attribute ;
(* A stretch or a moment of the element's life (SysML v2 timeslice, snapshot):
start:/end: (a timeslice) and at: (a snapshot) are times; the other
attributes are the values the element has then. *)
OccurrenceDecl ::= "timeslice" Name "{" ( Attribute | SnapshotDecl )* "}"
| SnapshotDecl ;
SnapshotDecl ::= "snapshot" Name AttributeBlock ;
InterfaceAttrs ::= ( "protocol" ":" String | Attribute )* ;
InterfaceBody ::= ( "from" ":" Name | "to" ":" Name | Attribute )* ;
ConnectionDecl ::= "connection" Name ( "->" Name )? AttributeBlock ;
(* block form requires from:/to: attributes *)
(* ---- Physical Architecture (PA) ----------------------------------------------- *)
PhysicalArchitecture ::= "physical_architecture" Name "{" PaElement* "}"
| "architecture" "physical" Name? "{" PaElement* "}" ;
PaElement ::= "node" Name "{" NodeElement* "}"
| LevelFunctionDecl (* a function no behavior component performs *)
| FunctionalExchange (* between physical functions *)
| FunctionalChainDecl (* ordered physical functions *)
| CapabilityRealizationDecl (* realizes a logical capability realization *)
| "component" Name PhysicalComponentBody?
| ConnectionDecl
| ( "physical_link" | "link" ) Name ( "->" Name )? AttributeBlock
(* from:/to: (or connects:) name a node or a
node's port, `Node.port`; the link is drawn
between the ports when they are named *)
| "physical_exchange" Name AttributeBlock (* from:/to: required; via:, message_type:, frequency: *)
| "deployment" Name "->" Name AttributeBlock?
| Attribute ;
NodeElement ::= "deploys" Name AttributeBlock?
| OccurrenceDecl
| "port" Name AttributeBlock? (* physical ports are UNORIENTED *)
| ComponentPortDecl (* port in|out|inout: a component port of the node,
end of a physical_exchange as `Node.port` *)
| LevelFunctionDecl (* the physical functions the node itself performs *)
| "behavior_component" Name "{" ( Attribute | ComponentPortDecl | LevelFunctionDecl )* "}"
(* its ports and the physical functions it performs;
allocated_component: <logical component ref> is the
one it realizes, allocated_functions: [...] the
functions it performs by name (legacy form) *)
| "hardware_component" Name AttributeBlock?
| Attribute ;
PhysicalComponentBody ::= "{" ( "interface_in" ":"? Name "{" InterfaceAttrs "}"
| "interface_out" ":"? Name "{" InterfaceAttrs "}"
| "function" Name AttributeBlock?
| Attribute )* "}" ;
(* ---- EPBS ---------------------------------------------------------------------- *)
Epbs ::= "epbs" Name "{" ( EpbsSystem | EpbsSubsystem )* "}" ;
EpbsSystem ::= "system" Name "{" ( EpbsSubsystem | Attribute )* "}" ;
EpbsSubsystem ::= "subsystem" Name "{" ( EpbsItem | Attribute )* "}" ;
EpbsItem ::= "item" Name AttributeBlock
| "assembly" Name AttributeBlock ;
(* ---- Safety ---------------------------------------------------------------------- *)
SafetyAnalysis ::= "safety_analysis" "{" SafetyElement* "}" ;
SafetyElement ::= "hazard" Name AttributeBlock
| "fmea" Name AttributeBlock
| Attribute ;
(* ---- Cybersecurity (Capella Cybersecurity viewpoint) ------------------------------ *)
SecurityAnalysis ::= "security_analysis" "{" SecurityElement* "}" ; (* level: "oa"|"sa"|"la"|"pa", id: *)
SecurityElement ::= "threat" Name AttributeBlock (* kind:, level: Integer, applies_to: [asset…], involves: [element…], security_<need>: *)
| "asset" Name AttributeBlock (* kind: "functional"|"information"|"enterprise", members: [element…] *)
| Attribute ;
SecurityScales ::= "security_scales" AttributeBlock ; (* confidentiality|integrity|availability|traceability: [literal…], threat_kinds: [name…] *)
(* ---- Traceability ------------------------------------------------------------------ *)
TraceDecl ::= "trace" AttributeBlock (* from:/to:/type: *)
| "trace" Name "->" Name AttributeBlock?
| "trace" Name TraceKind Name AttributeBlock? ;
TraceKind ::= "satisfies" | "implements" | "validates"
| "realizes" | "refines" (* inter-layer realization *)
| "allocates" ; (* `is:` an allocation definition: a type
with from_kind/to_kind, checked *)
Configuration ::= "configuration" Name AttributeBlock ; (* selects: [variant…]; one per variation *)
(* ---- Attributes ---------------------------------------------------------------------- *)
AttributeBlock ::= "{" Attribute* "}" ;
Attribute ::= AttributeKey ":" AttributeValue ;
AttributeKey ::= Identifier | Keyword ; (* any keyword may be used as a key *)
AttributeValue ::= String
| Quantity (* typed: 25 ms, 100 Mbps, 512 MB *)
| Number
| DottedName (* bare identifier / reference *)
| "[" ( AttributeValue ( "," AttributeValue )* )? "]"
| AttributeBlock ; (* nested map *)
(* A quantity is a number immediately followed by a unit symbol. The unit
table (symbols, dimensions, conversion factors) is part of the metamodel:
see spec/METAMODEL.md "Units". An unknown unit is a compile ERROR. The
next token after a Number is read as a unit only when it is NOT the key
of the following attribute (i.e. not followed by ":").
Typed attributes (which keys expect which dimension or enumeration) are
declared in spec/METAMODEL.md; violations are `metamodel:` warnings at
compile time and blockers in the production gate. *)
Quantity ::= Number UnitSymbol ;
UnitSymbol ::= Identifier ( "/" Identifier )? (* must be in the unit table: ms, km/h *)
| "%" ; (* percent, same unit as `percent` *)
(* ---- Data Model (Arcadia: Class, DataType, Enumeration, Exchange Item) -------------------- *)
ClassDecl ::= "class" Name AttributeBlock ;
(* every attribute but id:, description:, summary:, status:,
constraints: and extends: is a field, name -> type. Fields
keep their declared order; one declared twice is an ERROR.
extends: <class ref> names the class this one specializes. *)
AssociationDecl ::= "association" Name AttributeBlock ;
(* an association between two classes, as an element:
from: <class ref> (owns the navigable end), to: <class ref>,
role: <field of from typed by to>, kind: association |
aggregation | composition, multiplicity: <text>, id:.
Unknown classes or role are ERRORS. Declared wherever a
class is. *)
EnumerationDecl ::= "enumeration" Name AttributeBlock ; (* values: [ Name* ] *)
DataTypeDecl ::= "data_type" Name AttributeBlock ;
(* base:, unit: <UnitSymbol> — a symbol outside the unit
table is reported like any typed attribute. *)
ExchangeItemDecl ::= "exchange_item" Name AttributeBlock ;
(* mechanism: EVENT|FLOW|OPERATION|DATA|SHARED_DATA (ERROR otherwise);
elements: [ <class/datatype ref>* ] — dangling refs are ERRORS.
When exchange items are declared, exchanges referencing
unknown items produce warnings. *)
(* ---- Physical paths ------------------------------------------------------------------------ *)
PhysicalPathDecl ::= "physical_path" Name AttributeBlock ;
(* involves: [ <named link>+ ] REQUIRED, ordered; links are
referenced by name; dangling refs are ERRORS. Methodology
lint: component exchanges crossing nodes must be
transported by a physical link or exchange. *)
(* ---- Operational processes & communication means ------------------------------------------- *)
OperationalProcessDecl ::= "operational_process" Name "{" ( Attribute | ControlNodeDecl | SequenceLinkDecl )* "}" ;
(* involves: [ <activity/interaction ref>* ] ordered; empty is a
WARNING; control nodes and sequence links as in a chain *)
CommunicationMeansDecl ::= "communication_means" Name AttributeBlock ;
(* from:, to: REQUIRED (operational entities) *)
(* ---- Verification (V&V) --------------------------------------------------------------------- *)
TestCaseDecl ::= "test_case" Name AttributeBlock ;
(* verifies: [ <requirement id>+ ] REQUIRED;
method: test|analysis|inspection|demonstration (ERROR otherwise).
The production gate (arclang gate) requires every
requirement to be verified by at least one test_case.
The verdict comes from ONE of:
asserts: [ <constraint ref>+ ] (an analysis);
verdict: pass|fail|inconclusive|error (a run elsewhere);
simulate: SimulateBlock with expects: [ Expect+ ]
(a simulation, run by `arclang verify`, cached;
inconclusive while stale or never run). *)
SimulateBlock ::= "{" SimulateKey ":" AttributeValue ( SimulateKey ":" AttributeValue )* "}" ;
SimulateKey ::= "backend" (* openmodelica (default) | fmu | command: the last two
are declared, answer inconclusive until built *)
| "model" (* REQUIRED: Modelica class name, Package.Model *)
| "stop_time" (* REQUIRED: a time quantity *)
| "start_time" (* a time quantity, 0 s when absent *)
| "configuration" (* configuration ref: the model extends its system model *)
| "sources" (* [ <Modelica file path, from the model file>* ] *)
| "tolerance" (* positive number *)
| "intervals" ; (* whole number of output intervals *)
(* Each Expect is a string holding: *)
Expect ::= Sum ( ">=" | "<=" | ">" | "<" | "==" | "!=" ) Sum ;
Sum ::= Product ( ( "+" | "-" ) Product )* ;
Product ::= Unary ( ( "*" | "/" ) Unary )* ;
Unary ::= "-" Unary | Number Unit? | "(" Sum ")"
| ( "min" | "max" | "final" | "initial" | "mean" ) "(" Variable ")"
| "at" "(" Sum "," Variable ")" ;
Variable ::= ModelicaName | '"' <ArcLang id or name> '"' ( "." ModelicaName )? ;
(* a variable of the simulation result; a quoted ArcLang
element is replaced by the instance it became. Values
are compared in SI units, dimension-checked when the
unit of the variable is known. *)
(* ---- User-defined types ------------------------------------------------------------------------ *)
TypeDecl ::= "type" Name ( "extends" Name )? "{" ( TypePort | Attribute )* "}" ;
TypePort ::= "port" ( "in" | "out" | "inout" ) Name AttributeBlock? ;
(* A type is a reusable definition. `required: [ key* ]` lists
the attributes every instance must provide.
Any element is typed with the attribute `is: <type name>`
or `is: [ <type name>+ ]` (multiple typing): it inherits
the types' attributes (own values win) and, for
components, their ports. Two types defining the same
attribute or port DIFFERENTLY is an ERROR unless the
element redefines it. ERRORS: duplicate or unknown
type, cyclic `extends`, a missing required attribute, a
redefinition that changes a quantity's dimension, a type
with ports applied to a non-component. `id`, `name`,
`description` and `required` are never inherited.
Types have their own namespace. *)
(* ---- Constraints ------------------------------------------------------------------------------ *)
ConstraintDecl ::= "constraint" Name "{" ( "assert" ":" Expression | Attribute )* "}" ;
(* exactly one `assert:` REQUIRED. The expression must be a
comparison of two values of the SAME dimension. Unknown
elements/attributes and dimension mismatches are ERRORS.
A constraint that evaluates to false is a `constraint:`
warning and a blocker in the production gate. *)
Expression ::= Additive ( ( "<" | "<=" | ">" | ">=" | "==" | "!=" ) Additive )? ;
Additive ::= Term ( ( "+" | "-" ) Term )* ;
Term ::= Unary ( ( "*" | "/" ) Unary )* ;
(* products and quotients carry DERIVED dimensions:
voltage * current is a power, size / data rate is a time.
"+", "-" and comparisons need both sides in the same
dimension. *)
Unary ::= "-" Unary | Primary ;
Primary ::= Quantity | Number
| Name "." AttributeKey (* attribute of an element, by id or name *)
| Identifier "(" ( Additive ( "," Additive )* )? ")"
| Name (* bare name: function argument only *)
| "(" Additive ")" ;
(* functions: sum(collection, attribute), min(...), max(...),
count(collection). A collection is an element with an
`involves:` list (functional chain, physical path,
capability). Members without attributes of their own
(exchanges) are not operands; a member lacking the
aggregated attribute is an ERROR naming it. *)
(* ---- Diagrams ------------------------------------------------------------- *)
(* A named diagram cut from one view: the elements it names (by id or name),
what holds them, and the exchanges between drawn elements. `context: true`
adds the elements an exchange ties to a named one. A view the model does
not draw, or a name no element answers to, is reported by the viewer. *)
DiagramDecl ::= "diagram" Name "{" DiagramAttribute* "}" ;
DiagramAttribute ::= "view" ":" ( "oab" | "sab" | "lab" | "pab" | "cap" | "cdb" | "pbs" | String )
| "shows" ":" "[" ( Name ( "," Name )* )? "]"
| "context" ":" ( "true" | "false" )
| "description" ":" String ;
(* ---- Tables ---------------------------------------------------------------- *)
(* A live table or matrix, computed by the compiler on every change (see
spec/METAMODEL.md, kind Table). For a matrix, `columns` names the kinds
(or layers) of its columns; for a table, the columns shown. *)
TableDecl ::= "table" Name "{" TableAttribute* "}" ;
TableAttribute ::= "kind" ":" ( "requirements_coverage" | "traceability_matrix" | "allocation_matrix"
| "interface_n2" | "icd" | "elements" )
| "id" ":" String
| "scope" ":" String (* OA, SA, LA, PA, EPBS or an element *)
| "row_type" ":" String
| ( "columns" | "rows" | "kinds" ) ":" "[" ( String ( "," String )* )? "]"
| "filter" ":" String (* words, col:text, col=text, col!=text, is:gap, -term *)
| "gaps_only" ":" ( "true" | "false" )
| "description" ":" String ;
(* ---- Modes & States (Arcadia transverse) -------------------------------------------------- *)
StateMachineDecl ::= "state_machine" Name "{" StateMachineElement* "}" ;
StateMachineElement ::= ( "state" | "mode" ) Name StateBody?
| "region" Name "{" ( Attribute | ( "state" | "mode" ) Name StateBody?
| "transition" Name "->" Name AttributeBlock? )* "}"
(* a top-level region of its own, with its initial: ; a
machine with several regions writes one block each.
Its states and transitions are the machine's too. *)
(* mode = chosen behavior, state = undergone (Arcadia) *)
(* A state holds a region: states, modes and transitions of its own. A
transition declared inside a state joins the machine's, and names any
state of the machine, at any depth. *)
StateBody ::= "{" ( Attribute | ( "state" | "mode" ) Name StateBody?
| "transition" Name "->" Name AttributeBlock? )* "}" ;
| "transition" Name "->" Name AttributeBlock?
(* attributes: trigger:, guard:, action:, timing:, priority:,
events: [...] (every attribute is kept) ;
endpoints must be declared states/modes (ERROR otherwise);
unresolved triggers are warnings. A state keeps its
attributes too: kind: final|choice|fork|join|terminate...
for a pseudo-state, initial: for the region it opens *)
| Attribute ; (* initial: "StateName" *)
(* ---- Scenarios (sequence flows) ------------------------------------------------------------ *)
ScenarioDecl ::= "scenario" Name "{" ScenarioElement* "}" ;
ScenariosBlock ::= "scenarios" Name? "{" ScenarioDecl* "}" ;
(* A combined fragment frames the messages it holds, in their order among
the scenario's messages: `alt` and `par` with their operands, `loop`,
`opt`, `seq` and `critical` with one body. A fragment with operand
blocks holds nothing outside them. Fragments nest. *)
FragmentDecl ::= "fragment" FragmentKind String?
"{" ( OperandDecl* | ( MessageDecl | FragmentDecl | InvariantDecl )* ) "}" ;
FragmentKind ::= "alt" | "opt" | "loop" | "par" | "seq" | "critical" ;
OperandDecl ::= "operand" String? "{" ( MessageDecl | FragmentDecl | InvariantDecl )* "}" ;
ScenarioElement ::= "participants" ":" "[" Name ( "," Name )* "]"
| FragmentDecl
(* participants must resolve to declared elements (ERROR) *)
| MessageDecl
| InvariantDecl
| Attribute ;
(* A state, mode or function asserted on a lifeline (Capella: state fragment):
`state "Lifeline" "Armed" { ... }`, `mode ...`, `function "Lifeline" "Sense" { ... }`.
It spans the messages written in its body (an instant without any); the
lifeline must be a participant and the name a declared state/mode or
function, by id or unambiguous name (ERROR). Allowed inside fragments. *)
InvariantDecl ::= ( "state" | "mode" | "function" ) Name Name
( "{" ( Attribute | MessageDecl | FragmentDecl | InvariantDecl )* "}" )? ;
MessageDecl ::= "message" Name "->" Name Name? AttributeBlock? ;
(* endpoints must be scenario participants (ERROR);
attributes: type: sync|async, timing:, kind: (Capella's
message kind), exchange: <functional or component
exchange carried; unknown = WARNING>; every attribute is kept.
A scenario's owner: <element> is kept too (unknown = WARNING). *)
(* ---- Unmodeled blocks (accepted, warned, ignored) -------------------------------------- *)
UnmodeledBlock ::= ( "dataflow" | "data_flows"
| "validation" | "traces" | "traceability" )
Name? "{" BalancedTokens "}" ;