Documentation menu

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 "}" ;

Source: spec/GRAMMAR.ebnf in the ArcLang repository.