diff --git a/.claude/agents/textual-notation-reviewer.md b/.claude/agents/textual-notation-reviewer.md
new file mode 100644
index 00000000..20a302d6
--- /dev/null
+++ b/.claude/agents/textual-notation-reviewer.md
@@ -0,0 +1,77 @@
+---
+name: textual-notation-reviewer
+description: Expert reviewer for SysML2 TextualNotationBuilder generated code. Use this agent to verify that a generated Build{RuleName} method correctly implements its KEBNF grammar rule. Pass the file path and optionally a specific method name; the agent reads the grammar rule from the XML doc, inspects the implementation, and reports discrepancies.
+tools: Read, Grep, Glob, Bash
+---
+
+You are a master of the SysML2.NET textual notation code generation pipeline. Your job is to review generated `Build{RuleName}` methods and verify they correctly implement their KEBNF grammar rules.
+
+## Your Knowledge Base
+
+Before reviewing anything, read `SysML2.NET.CodeGenerator/GRAMMAR.md` to refresh your understanding of:
+- KEBNF grammar element types (NonTerminalElement, AssignmentElement, TerminalElement, GroupElement, ValueLiteralElement, NonParsingAssignmentElement)
+- Rule structure (`RuleName:TargetElementName = alternatives`)
+- Cursor model (shared via `ICursorCache`, `Move()` required after each item)
+- Guard mechanisms (`?=` booleans, `IsValidFor` extensions, type ordering)
+- Patterns currently handled by code-gen
+- Switch case variable scoping gotcha
+- Builder conventions (trailing space, terminal formatting, owned vs referenced elements)
+
+## Review Process
+
+Given a file path (and optionally a method name):
+
+1. **Locate the grammar rule**: find the XML `{rule}` comment immediately before the public `Build{RuleName}` method. This is the ground truth.
+
+2. **Parse the rule mentally**: break it into alternatives separated by `|`, and each alternative into its elements (terminals, NonTerminals, assignments, groups). Note quantifiers (`*`, `+`, `?`), operators (`=`, `+=`, `?=`), and nested groups.
+
+3. **Identify the target class**: `TargetElementName` defaults to the rule name if not declared (`RuleName:Target=...`). The builder parameter is `I{TargetElementName}`.
+
+4. **Inspect the implementation**: read the method body and check each grammar construct against generated code:
+
+| Grammar construct | Expected code |
+|---|---|
+| `'keyword'` | `stringBuilder.Append("keyword ")` (or `AppendLine` for `;`, `{`, `}`) |
+| `NonTerminal` | `BuildNonTerminal(poco, cursorCache, stringBuilder);` or `XxxTextualNotationBuilder.Build...` for cross-class |
+| `NonTerminal*` / `NonTerminal+` | `while (cursor.Current ...) { builderCall; cursor.Move(); }` |
+| `prop=NonTerminal` | Cursor-based cast + call + `Move()`, OR `poco.Prop` access |
+| `prop+=NonTerminal` | Cursor loop with type dispatch, `Move()` after each |
+| `prop?='keyword'` | `if (poco.Prop) { stringBuilder.Append(" keyword "); }` |
+| `prop=[QualifiedName]` | `stringBuilder.Append(poco.Prop.qualifiedName)` |
+| `(...)? ` | Optional: `if (condition) { ... }` guard |
+| `(A|B)` | Alternatives dispatched via switch or if/else |
+| `{prop='val'}` | NonParsingAssignment — implicit, usually no output |
+
+5. **Check for common issues**:
+ - **Missing `Move()`**: after processing a cursor element, the cursor must advance (either in the builder or in the calling loop)
+ - **Wrong variable**: NonTerminals targeting the declaring class use `poco`; others use the cast/cursor variable
+ - **Cursor exhaustion**: a `while` loop with no type guard consumes everything, starving subsequent siblings
+ - **Missing trailing space**: most content needs a trailing space so the next element doesn't abut
+ - **Duplicate trailing space**: chain builders emit their own trailing space — the caller shouldn't add another
+ - **Owned vs cross-reference**: for `prop=[QualifiedName]|prop=OwnedChain{...}` patterns, runtime must check `poco.OwnedRelatedElement.Contains(poco.Prop)`
+ - **Type scope leak**: `if (x is Type y)` pattern variables leak into enclosing scope; outer `if (x != null) { }` may serve as a scoping boundary
+ - **Case ordering**: switch cases for subclasses must come before superclass cases; cases matching the declaring class should generally be the `default:`
+ - **Guard correctness**: when duplicate UML classes dispatch, check `?=` boolean or `IsValidFor{RuleName}()` guards
+
+6. **Produce a report** with:
+ - **Rule**: the grammar rule and its interpretation
+ - **Verdict**: ✓ Correct / ⚠ Minor issue / ✗ Incorrect
+ - **Findings**: specific line references (`file.cs:42`) and descriptions
+ - **Suggested fix**: if applicable, the corrected code or the code-gen adjustment needed
+
+## Tone and Style
+
+- Be precise and terse. Use code blocks for generated vs. expected code comparisons.
+- Reference specific line numbers in the reviewed file using `file.cs:42` format.
+- If the rule is complex, break the analysis into sub-rules/alternatives.
+- Distinguish between **implementation bugs** (the generator has a fault), **hand-coding stubs** (expected — method throws `NotSupportedException`), and **missing code-gen coverage** (generator could theoretically produce this but doesn't yet).
+
+## When to Say "Looks Correct"
+
+Don't nitpick style. A method is correct if:
+- Every grammar element maps to generated code (or is intentionally skipped via NonParsingAssignment)
+- Cursor positions align with grammar order
+- Types and dispatch match the rule's structure
+- No obvious runtime bugs (infinite loops, unreachable cases, null dereferences)
+
+Output a clear ✓ verdict when appropriate — not every review needs to find issues.
diff --git a/CLAUDE.md b/CLAUDE.md
index af2fe8f9..4ed422db 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -35,6 +35,19 @@ Test framework: **NUnit**. Test classes use `[TestFixture]` and `[Test]` attribu
- favour duplicated code in codegeneration to have staticaly defined methods that provide performance over reflection based code.
- code generation is done by processing the UML model and creating handlebars templates
+- **When working on the grammar/textual notation code generator** (`SysML2.NET.CodeGenerator/HandleBarHelpers/RulesHelper.cs` and related grammar processing): read `SysML2.NET.CodeGenerator/GRAMMAR.md` for the KEBNF grammar model, cursor/builder conventions, and code-gen patterns already handled.
+
+### Textual notation reviewer is MANDATORY
+
+**Every code change under `SysML2.NET/TextualNotation/` (hand-coded partial classes, IsValidFor extensions, validation extensions) or to `SysML2.NET.CodeGenerator/HandleBarHelpers/RulesHelper.cs` (and any Handlebars template that emits textual notation code) MUST be verified by the `textual-notation-reviewer` agent before reporting the change as complete or committing.**
+
+The agent is defined at `.claude/agents/textual-notation-reviewer.md`. Invoke it with the rule's KEBNF grammar (from the `` XML doc) and the files to review. It enforces:
+- the `Move()` ↔ `+=` Golden Rule (cursor advances only on `+=` consumption)
+- EBNF quantifier semantics (`?` = 0..1, `*` = 0+, `+` = 1+)
+- correct runtime type discriminators (e.g., `ISpecialization` IS the cursor element, not wrapped in `IOwningMembership`)
+- absence of greedy-builder pitfalls that silently drop interleaved elements
+
+Reason this is mandatory: a single reviewer pass on `BuildTypeDeclarationHandCoded` caught 3 real grammar-correctness bugs (wrong discriminator, silent element drop, missing `*` loop) that would have shipped broken textual notation without failing any existing test.
### Code Generation Pipeline
@@ -118,3 +131,4 @@ Auto-generated DTOs use structured namespaces reflecting the KerML/SysML package
- Prefer switch expressions/statements over if-else chains when applicable
- Prefer indexer syntax (e.g., 'list[^1]') and range syntax (e.g., 'array[1..^1]') over LINQ methods (e.g., 'list.Last()', 'list.Skip(1).Take(n)') when applicable
- Use meaningful variable names instead of single-letter names in any context (e.g., 'charIndex' instead of 'i', 'currentChar' instead of 'c', 'element' instead of 'e')
+- Use 'NotSupportedException' (not 'NotImplementedException') for placeholder/stub methods that require manual implementation
diff --git a/Resources/KerML-textual-bnf.kebnf b/Resources/KerML-textual-bnf.kebnf
new file mode 100644
index 00000000..2837bcfd
--- /dev/null
+++ b/Resources/KerML-textual-bnf.kebnf
@@ -0,0 +1,1467 @@
+// Manual corrections by HP de Koning
+
+// Part 1 - Kernel Modeling Language (KerML)
+
+// Clause 8.2 Concrete Syntax
+
+// Clause 8.2.1 Concrete Syntax Overview
+
+// Clause 8.2.2 Lexical Structure
+
+// Clause 8.2.2.1 Line Terminators and White Space
+
+LINE_TERMINATOR =
+ '\n' | '\r' | '\r\n'
+// implementation defined character sequence
+
+LINE_TEXT =
+ '[^\r\n]*'
+// character sequence excluding LINE_TERMINATORs
+
+WHITE_SPACE =
+ ' ' | '\t' | '\f' | LINE_TERMINATOR
+// space | tab | form_feed | LINE_TERMINATOR
+
+// Notes:
+// 1. Notation text is divided up into lines separated by line terminators. A line terminator may be a single character (such as a line feed) or a sequence of characters (such as a carriage return/line feed combination). This specification does not require any specific encoding for a line terminator, but any encoding used must be consistent throughout any specific input text.
+// 2. Any characters in text line that are not a part of the line terminator are referred to as line text.
+// 3. A white space character is a space, tab, form feed or line terminator. Any contiguous sequence of white space characters can be used to separate tokens that would otherwise be considered to be part of a single token. It is otherwise ignored, with the single exception that a line terminator is used to mark the end of a single-line note (see 8.2.2.2).
+
+// Clause 8.2.2.2 Notes and Comments
+
+SINGLE_LINE_NOTE =
+ '//' LINE_TEXT
+
+MULTILINE_NOTE =
+ '//*' COMMENT_TEXT '*/'
+
+REGULAR_COMMENT =
+ '/*' COMMENT_TEXT '*/'
+
+COMMENT_TEXT =
+ ( COMMENT_LINE_TEXT | LINE_TERMINATOR )*
+
+COMMENT_LINE_TEXT =
+ '.*(?=(\r|\n|\*/))'
+// LINE_TEXT excluding the sequence '*/'
+
+// Clause 8.2.2.3 Names
+
+NAME =
+ BASIC_NAME | UNRESTRICTED_NAME
+
+BASIC_NAME =
+ BASIC_INITIAL_CHARACTER BASIC_NAME_CHARACTER*
+
+SINGLE_QUOTE =
+ '#x27'
+
+UNRESTRICTED_NAME =
+ SINGLE_QUOTE ( NAME_CHARACTER | ESCAPE_SEQUENCE )* SINGLE_QUOTE
+
+// (See Note 1)
+
+BASIC_INITIAL_CHARACTER =
+ ALPHABETIC_CHARACTER | '_'
+
+BASIC_NAME_CHARACTER =
+ BASIC_INITIAL_CHARACTER | DECIMAL_DIGIT
+
+ALPHABETIC_CHARACTER =
+ 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z' |
+ 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z'
+// any character 'a' through 'z' or 'A' through 'Z'
+
+DECIMAL_DIGIT =
+ '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
+
+NAME_CHARACTER =
+ 'any printable character other than backslash or single_quote'
+
+ESCAPE_SEQUENCE =
+ '\f' | '\n' | '\t' | '\r' | '\v'
+// (See Note 2)
+
+// Notes:
+// 1. The single_quote character is '. The name represented by an UNRESTRICTED_NAME shall consist of the characters within the single quotes, with escape characters resolved as described below. The surrounding single quote characters are not part of the represented name.
+// 2. An ESCAPE_SEQUENCE is a sequence of two text characters starting with a backslash that actually denotes only a single character, except for the newline escape sequence, which represents however many characters is necessary to represent an end of line in a specific implementation (see also 8.2.2.1). Table 4 shows the meaning of the allowed escape sequences. The ESCAPE_SEQUENCES in an UNRESTRICTED_NAME shall be replaced by the characters specified as their meanings in the actual represented name.
+
+// Clause 8.2.2.4 Numeric Values
+
+DECIMAL_VALUE =
+ DECIMAL_DIGIT+
+
+EXPONENTIAL_VALUE =
+ DECIMAL_VALUE ('e' | 'E') ('+' | '-')? DECIMAL_VALUE
+
+// Notes:
+// 1. A DECIMAL_VALUE may specify a natural literal, or it may be part of the specification of a real literal (see 8.2.5.8.4). Note that a DECIMAL_VALUE does not include a sign, because negating a literal is an operator in the KerML Expression syntax.
+// 2. An EXPONENTIAL_VALUE may be used in the specification of a real literal (see 8.2.5.8.4). Note that a decimal point and fractional part are not included in the lexical structure of an exponential value. They are handled as part of the syntax of real literals.
+
+// Clause 8.2.2.5 String Value
+
+STRING_VALUE =
+ '"' ( STRING_CHARACTER | ESCAPE_SEQUENCE )* '"'
+
+STRING_CHARACTER =
+ 'any printable character other than backslash or "'
+
+// Notes:
+// 1. ESCAPE_SEQUENCE is specified in 8.2.2.3.
+
+// Clause 8.2.2.6 Reserved Words
+
+RESERVED_KEYWORD =
+ 'about' | 'abstract' | 'alias' | 'all' | 'and' | 'as' | 'assoc' | 'behavior' | 'binding' | 'bool' | 'by' | 'chains'
+ | 'class' | 'classifier' | 'comment' | 'composite' | 'conjugate' | 'conjugates' | 'conjugation' | 'connector'
+ | 'const' | 'crosses' | 'datatype' | 'default' | 'dependency' | 'derived' | 'differences' | 'disjoining' | 'disjoint'
+ | 'doc' | 'else' | 'end' | 'expr' | 'false' | 'feature' | 'featured' | 'featuring' | 'filter' | 'first' | 'flow'
+ | 'for' | 'from' | 'function' | 'hastype' | 'if' | 'implies' | 'import' | 'in' | 'inout' | 'interaction'
+ | 'intersects' | 'inv' | 'inverse' | 'inverting' | 'istype' | 'language' | 'library' | 'locale' | 'member' | 'meta'
+ | 'metaclass' | 'metadata' | 'multiplicity' | 'namespace' | 'nonunique' | 'not' | 'null' | 'of' | 'or' | 'ordered'
+ | 'out' | 'package' | 'portion' | 'predicate' | 'private' | 'protected' | 'public' | 'redefines' | 'redefinition'
+ | 'references' | 'rep' | 'return' | 'specialization' | 'specializes' | 'standard' | 'step' | 'struct'
+ | 'subclassifier' | 'subset' | 'subsets' | 'subtype' | 'succession' | 'then' | 'to' | 'true' | 'type' | 'typed'
+ | 'typing' | 'unions' | 'var' | 'xor'
+
+// Clause 8.2.2.7 Symbols
+
+RESERVED_SYMBOL =
+ '~' | '}' | '|' | '{' | '^' | ']' | '[' | '@' | '??' | '?' | '>=' | '>' | '=>' | '===' | '==' | '=' | '<=' | '<'
+ | ';' | ':>>' | ':>' | ':=' | '::>' | '::' | ':' | '/' | '.?' | '..' | '.' | '->' | '-' | ',' | '+' | '**' | '*' | ')'
+ | '(' | '&' | '%' | '$' | '#' | '!==' | '!='
+
+TYPED_BY = ':' | 'typed' 'by'
+
+SPECIALIZES = ':>' | 'specializes'
+
+SUBSETS = ':>' | 'subsets'
+
+REFERENCES = '::>' | 'references'
+
+CROSSES = '=>' | 'crosses'
+
+REDEFINES = ':>>' | 'redefines'
+
+CONJUGATES = '~' | 'conjugates'
+
+// Clause 8.2.3 Root Concrete Syntax
+
+// Clause 8.2.3.1 Elements and Relationships Concrete Syntax
+
+Identification : Element =
+ ( '<' declaredShortName = NAME '>' )?
+ ( declaredName = NAME )?
+
+RelationshipBody : Relationship =
+ ';' | '{' RelationshipOwnedElement* '}'
+
+RelationshipOwnedElement : Relationship =
+ ownedRelatedElement += OwnedRelatedElement
+ | ownedRelationship += OwnedAnnotation
+
+OwnedRelatedElement : Element =
+ NonFeatureElement | FeatureElement
+
+// Clause 8.2.3.2 Dependencies Concrete Syntax
+
+Dependency =
+ ( ownedRelationship += PrefixMetadataAnnotation )*
+ 'dependency' ( Identification? 'from' )?
+ client += [QualifiedName] ( ',' client += [QualifiedName] )* 'to'
+ supplier += [QualifiedName] ( ',' supplier += [QualifiedName] )*
+ RelationshipBody
+
+// Notes:
+// 1. PrefixMetadataAnnotation is defined in the Kernel layer (see 8.2.5.12).
+
+// Clause 8.2.3.3 Annotations Concrete Syntax
+
+// Clause 8.2.3.3.1 Annotations
+
+Annotation =
+ annotatedElement = [QualifiedName]
+
+OwnedAnnotation : Annotation =
+ ownedRelatedElement += AnnotatingElement
+
+AnnotatingElement =
+ Comment
+ | Documentation
+ | TextualRepresentation
+ | MetadataFeature
+
+// Notes:
+// 1. MetadataFeature is defined in the Kernel layer (see 8.2.5.12).
+
+// Clause 8.2.3.3.2 Comments and Documentation
+
+Comment =
+ ( 'comment' Identification
+ ( 'about' ownedRelationship += Annotation
+ ( ',' ownedRelationship += Annotation )*
+ )?
+ )?
+ ( 'locale' locale = STRING_VALUE )?
+ body = REGULAR_COMMENT
+
+Documentation =
+ 'doc' Identification
+ ( 'locale' locale = STRING_VALUE )?
+ body = REGULAR_COMMENT
+
+// Notes:
+// 1. The text of a lexical REGULAR_COMMENT or PREFIX_COMMENT shall be processed as follows before it is included as the body of a Comment or Documentation:
+// • Remove the initial /* and final */ characters.
+// • Remove any white space immediately after the initial /*, up to and including the first line terminator (if any).
+// • On each subsequent line of the text:
+// • Strip initial white space other than line terminators.
+// • Then, if the first remaining character is "*", remove it.
+// • Then, if the first remaining character is now a space, remove it.
+// 2. The body text of a Comment can include markup information (such as HTML), and a conforming tool may display such text as rendered according to the markup. However, marked up "rich text" for a Comment written using the KerML textual concrete syntax shall be stored in the Comment body in plain text including all mark up text, with all line terminators and white space included as entered, other than what is removed according to the rules above.
+
+// Clause 8.2.3.3.3 Textual Representation
+
+TextualRepresentation =
+ ( 'rep' Identification )?
+ 'language' language = STRING_VALUE
+ body = REGULAR_COMMENT
+
+// Notes:
+// 1. The lexical text of a REGULAR_COMMENT shall be processed as specified in 8.2.3.3.2 for Comments before being included as the body of a TextualRepresentation.
+// 2. See also 8.3.2.3.6 on the standard language names recognized for a TextualRepresentation.
+
+// Clause 8.2.3.4 Namespaces Concrete Syntax
+
+// Clause 8.2.3.4.1 Namespaces
+
+RootNamespace : Namespace =
+ NamespaceBodyElement*
+
+// (See Note 1)
+
+Namespace =
+ ( ownedRelationship += PrefixMetadataMember )*
+ NamespaceDeclaration NamespaceBody
+
+// (See Note 2)
+
+NamespaceDeclaration : Namespace =
+ 'namespace' Identification
+
+NamespaceBody : Namespace =
+ ';' | '{' NamespaceBodyElement* '}'
+
+NamespaceBodyElement : Namespace =
+ ownedRelationship += NamespaceMember
+ | ownedRelationship += AliasMember
+ | ownedRelationship += Import
+
+MemberPrefix : Membership =
+ ( visibility = VisibilityIndicator )?
+
+VisibilityIndicator : VisibilityKind =
+ 'public' | 'private' | 'protected'
+
+NamespaceMember : OwningMembership =
+ NonFeatureMember
+ | NamespaceFeatureMember
+
+NonFeatureMember : OwningMembership =
+ MemberPrefix
+ ownedRelatedElement += MemberElement
+
+NamespaceFeatureMember : OwningMembership =
+ MemberPrefix
+ ownedRelatedElement += FeatureElement
+
+AliasMember : Membership =
+ MemberPrefix
+ 'alias' ( '<' memberShortName = NAME '>' )?
+ ( memberName = NAME )?
+ 'for' memberElement = [QualifiedName]
+ RelationshipBody
+
+QualifiedName =
+ ( '$' '::' )? ( NAME '::' )* NAME
+
+// (See Note 3)
+
+// Notes:
+// 1. A root Namespace is a Namespace that has no owningNamespace (see 8.3.2.4). Every Element other than a root Namespace must be contained, directly or indirectly, within some root Namespace. Therefore, every valid KerML concrete syntax text can be parsed starting from the RootNamespace production.
+// 2. PrefixMetadataMember is defined in the Kernel layer (see 8.2.5.12).
+// 3. A qualified name is notated as a sequence of segment names separated by "::" punctuation, optionally with the global scope qualifier "$" as an initial segment. An unqualified name can be considered the degenerate case of a qualified name with a single segment name. A qualified name is used in the KerML textual concrete syntax to identify an Element that is being referred to in the representation of another Element. A qualified name used in this way does not appear in the corresponding abstract syntax—instead, the abstract syntax representation contains an actual reference to the identified Element. Name resolution is the process of determining the Element that is identified by a qualified name. The segment names of the qualified name other than the last identify a sequence of nested Namespaces that provide the context for resolving the final segment name (see 8.2.3.5). The notation [QualifiedName] is used in concrete syntax grammar productions to indicate the result of resolving text parsed as a QualifiedName (see also 8.2.1).
+
+// Clause 8.2.3.4.2 Imports
+
+Import =
+ visibility = VisibilityIndicator
+ 'import' ( isImportAll ?= 'all' )?
+ ImportDeclaration RelationshipBody
+
+ImportDeclaration : Import =
+ MembershipImport | NamespaceImport
+
+MembershipImport =
+ importedMembership = [QualifiedName]
+ ( '::' isRecursive ?= '**' )?
+
+// (See Note 1)
+
+NamespaceImport =
+ importedNamespace = [QualifiedName] '::' '*'
+ ( '::' isRecursive ?= '**' )?
+ | importedNamespace = FilterPackage
+ { ownedRelatedElement += importedNamespace }
+
+FilterPackage : Package =
+ ownedRelationship += ImportDeclaration
+ ( ownedRelationship += FilterPackageMember )+
+
+FilterPackageMember : ElementFilterMembership =
+ '[' ownedRelatedElement += OwnedExpression ']'
+
+// Notes:
+// 1. The importedMembership of a MembershipImport is the single case in which the Element required from the resolution [QualifiedName] is the actual Membership identified by the QualifedName, not the memberElement of that Membership (see 8.2.3.5).
+
+// Clause 8.2.3.4.3 Namespace Elements
+
+MemberElement : Element =
+ AnnotatingElement | NonFeatureElement
+
+NonFeatureElement : Element =
+ Dependency
+ | Namespace
+ | Type
+ | Classifier
+ | DataType
+ | Class
+ | Structure
+ | Metaclass
+ | Association
+ | AssociationStructure
+ | Interaction
+ | Behavior
+ | Function
+ | Predicate
+ | Multiplicity
+ | Package
+ | LibraryPackage
+ | Specialization
+ | Conjugation
+ | Subclassification
+ | Disjoining
+ | FeatureInverting
+ | FeatureTyping
+ | Subsetting
+ | Redefinition
+ | TypeFeaturing
+
+FeatureElement : Feature =
+ Feature
+ | Step
+ | Expression
+ | BooleanExpression
+ | Invariant
+ | Connector
+ | BindingConnector
+ | Succession
+ | Flow
+ | SuccessionFlow
+
+// Clause 8.2.3.5 Name Resolution
+
+// Clause 8.2.3.5.1 Name Resolution Overview
+
+// Clause 8.2.3.5.2 Local and Global Namespaces
+
+// Clause 8.2.3.5.3 Local and Visible Resolution
+
+// Clause 8.2.3.5.4 Full Resolution
+
+// Clause 8.2.4 Core Concrete Syntax
+
+// Clause 8.2.4.1 Types Concrete Syntax
+
+// Clause 8.2.4.1.1 Types
+
+Type =
+ TypePrefix 'type'
+ TypeDeclaration TypeBody
+
+TypePrefix : Type =
+ ( isAbstract ?= 'abstract' )?
+ ( ownedRelationship += PrefixMetadataMember )*
+
+TypeDeclaration : Type =
+ ( isSufficient ?= 'all' )? Identification
+ ( ownedRelationship += OwnedMultiplicity )?
+ ( SpecializationPart | ConjugationPart )+
+ TypeRelationshipPart*
+
+SpecializationPart : Type =
+ SPECIALIZES ownedRelationship += OwnedSpecialization
+ ( ',' ownedRelationship += OwnedSpecialization )*
+
+ConjugationPart : Type =
+ CONJUGATES ownedRelationship += OwnedConjugation
+
+TypeRelationshipPart : Type =
+ DisjoiningPart
+ | UnioningPart
+ | IntersectingPart
+ | DifferencingPart
+
+DisjoiningPart : Type =
+ 'disjoint' 'from' ownedRelationship += OwnedDisjoining
+ ( ',' ownedRelationship += OwnedDisjoining )*
+
+UnioningPart : Type =
+ 'unions' ownedRelationship += Unioning
+ ( ',' ownedRelationship += Unioning )*
+
+IntersectingPart : Type =
+ 'intersects' ownedRelationship += Intersecting
+ ( ',' ownedRelationship += Intersecting )*
+
+DifferencingPart : Type =
+ 'differences' ownedRelationship += Differencing
+ ( ',' ownedRelationship += Differencing )*
+
+TypeBody : Type =
+ ';' | '{' TypeBodyElement* '}'
+
+TypeBodyElement : Type =
+ ownedRelationship += NonFeatureMember
+ | ownedRelationship += FeatureMember
+ | ownedRelationship += AliasMember
+ | ownedRelationship += Import
+
+// Clause 8.2.4.1.2 Specialization
+
+Specialization =
+ ( 'specialization' Identification )?
+ 'subtype' SpecificType
+ SPECIALIZES GeneralType
+ RelationshipBody
+
+OwnedSpecialization : Specialization =
+ GeneralType
+
+SpecificType : Specialization =
+ specific = [QualifiedName]
+ | specific += OwnedFeatureChain
+ { ownedRelatedElement += specific }
+
+GeneralType : Specialization =
+ general = [QualifiedName]
+ | general += OwnedFeatureChain
+ { ownedRelatedElement += general }
+
+// Clause 8.2.4.1.3 Conjugation
+
+Conjugation =
+ ( 'conjugation' Identification )?
+ 'conjugate'
+ ( conjugatedType = [QualifiedName]
+ | conjugatedType = FeatureChain
+ { ownedRelatedElement += conjugatedType }
+ )
+ CONJUGATES
+ ( originalType = [QualifiedName]
+ | originalType = FeatureChain
+ { ownedRelatedElement += originalType }
+ )
+ RelationshipBody
+
+OwnedConjugation : Conjugation =
+ originalType = [QualifiedName]
+ | originalType = FeatureChain
+ { ownedRelatedElement += originalType }
+
+// Clause 8.2.4.1.4 Disjoining
+
+Disjoining =
+ ( 'disjoining' Identification )?
+ 'disjoint'
+ ( typeDisjoined = [QualifiedName]
+ | typeDisjoined = FeatureChain
+ { ownedRelatedElement += typeDisjoined }
+ )
+ 'from'
+ ( disjoiningType = [QualifiedName]
+ | disjoiningType = FeatureChain
+ { ownedRelatedElement += disjoiningType }
+ )
+ RelationshipBody
+
+OwnedDisjoining : Disjoining =
+ disjoiningType = [QualifiedName]
+ | disjoiningType = FeatureChain
+ { ownedRelatedElement += disjoiningType }
+
+// Clause 8.2.4.1.5 Unioning, Intersecting and Differencing
+
+Unioning =
+ unioningType = [QualifiedName]
+ | ownedRelatedElement += OwnedFeatureChain
+
+Intersecting =
+ intersectingType = [QualifiedName]
+ | ownedRelatedElement += OwnedFeatureChain
+
+Differencing =
+ differencingType = [QualifiedName]
+ | ownedRelatedElement += OwnedFeatureChain
+
+// Clause 8.2.4.1.6 Feature Membership
+
+FeatureMember : OwningMembership =
+ TypeFeatureMember
+ | OwnedFeatureMember
+
+TypeFeatureMember : OwningMembership =
+ MemberPrefix 'member' ownedRelatedElement += FeatureElement
+
+OwnedFeatureMember : FeatureMembership =
+ MemberPrefix ownedRelatedElement += FeatureElement
+
+// Clause 8.2.4.2 Classifiers Concrete Syntax
+
+// Clause 8.2.4.2.1 Classifiers
+
+Classifier =
+ TypePrefix 'classifier'
+ ClassifierDeclaration TypeBody
+
+ClassifierDeclaration : Classifier =
+ ( isSufficient ?= 'all' )? Identification
+ ( ownedRelationship += OwnedMultiplicity )?
+ ( SuperclassingPart | ConjugationPart )?
+ TypeRelationshipPart*
+
+SuperclassingPart : Classifier =
+ SPECIALIZES ownedRelationship += OwnedSubclassification
+ ( ',' ownedRelationship += OwnedSubclassification )*
+
+// Clause 8.2.4.2.2 Subclassification
+
+Subclassification =
+ ( 'specialization' Identification )?
+ 'subclassifier' subclassifier = [QualifiedName]
+ SPECIALIZES superclassifier = [QualifiedName]
+ RelationshipBody
+
+OwnedSubclassification : Subclassification =
+ superclassifier = [QualifiedName]
+
+// Clause 8.2.4.3 Features Concrete Syntax
+
+// Clause 8.2.4.3.1 Features
+
+Feature =
+ ( FeaturePrefix
+ ( 'feature' | ownedRelationship += PrefixMetadataMember )
+ FeatureDeclaration?
+ | ( EndFeaturePrefix | BasicFeaturePrefix )
+ FeatureDeclaration
+ )
+ ValuePart? TypeBody
+
+// (See Note 1)
+
+EndFeaturePrefix : Feature =
+ ( isConstant ?= 'const' { isVariable = true } )?
+ isEnd ?= 'end'
+
+BasicFeaturePrefix : Feature =
+ ( direction = FeatureDirection )?
+ ( isDerived ?= 'derived' )?
+ ( isAbstract ?= 'abstract' )?
+ ( isComposite ?= 'composite' | isPortion ?= 'portion' )?
+ ( isVariable ?= 'var' | isConstant ?= 'const' { isVariable = true } )?
+
+FeaturePrefix =
+ ( EndFeaturePrefix ( ownedRelationship += OwnedCrossFeatureMember )?
+ | BasicFeaturePrefix
+ )
+ ( ownedRelationship += PrefixMetadataMember )*
+
+// (See Note 1)
+
+OwnedCrossFeatureMember : OwningMembership =
+ ownedRelatedElement += OwnedCrossFeature
+
+OwnedCrossFeature : Feature =
+ BasicFeaturePrefix FeatureDeclaration
+
+FeatureDirection : FeatureDirectionKind =
+ 'in' | 'out' | 'inout'
+
+FeatureDeclaration : Feature =
+ ( isSufficient ?= 'all' )?
+ ( FeatureIdentification
+ ( FeatureSpecializationPart | ConjugationPart )?
+ | FeatureSpecializationPart
+ | ConjugationPart
+ )
+ FeatureRelationshipPart*
+
+FeatureIdentification : Feature =
+ '<' declaredShortName = NAME '>' ( declaredName = NAME )?
+ | declaredName = NAME
+
+FeatureRelationshipPart : Feature =
+ TypeRelationshipPart
+ | ChainingPart
+ | InvertingPart
+ | TypeFeaturingPart
+
+ChainingPart : Feature =
+ 'chains'
+ ( ownedRelationship += OwnedFeatureChaining
+ | FeatureChain )
+
+InvertingPart : Feature =
+ 'inverse' 'of' ownedRelationship += OwnedFeatureInverting
+
+TypeFeaturingPart : Feature =
+ 'featured' 'by' ownedRelationship += OwnedTypeFeaturing
+ ( ',' ownedTypeFeaturing += OwnedTypeFeaturing )*
+
+FeatureSpecializationPart : Feature =
+ FeatureSpecialization+ MultiplicityPart? FeatureSpecialization*
+ | MultiplicityPart FeatureSpecialization*
+
+MultiplicityPart : Feature =
+ ownedRelationship += OwnedMultiplicity
+ | ( ownedRelationship += OwnedMultiplicity )?
+ ( isOrdered ?= 'ordered' ( {isUnique = false} 'nonunique' )?
+ | {isUnique = false} 'nonunique' ( isOrdered ?= 'ordered' )? )
+
+FeatureSpecialization : Feature =
+ Typings | Subsettings | References | Crosses | Redefinitions
+
+Typings : Feature =
+ TypedBy ( ',' ownedRelationship += OwnedFeatureTyping )*
+
+TypedBy : Feature =
+ TYPED_BY ownedRelationship += OwnedFeatureTyping
+
+Subsettings : Feature =
+ Subsets ( ',' ownedRelationship += OwnedSubsetting )*
+
+Subsets : Feature =
+ SUBSETS ownedRelationship += OwnedSubsetting
+
+References : Feature =
+ REFERENCES ownedRelationship += OwnedReferenceSubsetting
+
+Crosses : Feature =
+ CROSSES ownedRelationship += OwnedCrossSubsetting
+
+Redefinitions : Feature =
+ Redefines ( ',' ownedRelationship += OwnedRedefinition )*
+
+Redefines : Feature =
+ REDEFINES ownedRelationship += OwnedRedefinition
+
+// Notes:
+// 1. PrefixMetadataMember is defined in the Kernel layer (see 8.3.4.12).
+
+// Clause 8.2.4.3.2 Feature Typing
+
+FeatureTyping =
+ ( 'specialization' Identification )?
+ 'typing' typedFeature = [QualifiedName]
+ TYPED_BY GeneralType
+ RelationshipBody
+
+OwnedFeatureTyping : FeatureTyping =
+ GeneralType
+
+// Clause 8.2.4.3.3 Subsetting
+
+Subsetting =
+ ( 'specialization' Identification )?
+ 'subset' SpecificType
+ SUBSETS GeneralType
+ RelationshipBody
+
+OwnedSubsetting : Subsetting =
+ GeneralType
+
+OwnedReferenceSubsetting : ReferenceSubsetting =
+ GeneralType
+
+OwnedCrossSubsetting : CrossSubsetting =
+ GeneralType
+
+// Clause 8.2.4.3.4 Redefinition
+
+Redefinition =
+ ( 'specialization' Identification )?
+ 'redefinition' SpecificType
+ REDEFINES GeneralType
+ RelationshipBody
+
+OwnedRedefinition : Redefinition =
+ GeneralType
+
+// Clause 8.2.4.3.5 Feature Chaining
+
+OwnedFeatureChain : Feature =
+ FeatureChain
+
+FeatureChain : Feature =
+ ownedRelationship += OwnedFeatureChaining
+ ( '.' ownedRelationship += OwnedFeatureChaining )+
+
+OwnedFeatureChaining : FeatureChaining =
+ chainingFeature = [QualifiedName]
+
+// Clause 8.2.4.3.6 Feature Inverting
+
+FeatureInverting =
+ ( 'inverting' Identification? )?
+ 'inverse'
+ ( featureInverted = [QualifiedName]
+ | featureInverted = OwnedFeatureChain
+ { ownedRelatedElement += featureInverted }
+ )
+ 'of'
+ ( invertingFeature = [QualifiedName]
+ | ownedRelatedElement += OwnedFeatureChain
+ { ownedRelatedElement += invertingFeature }
+ )
+ RelationshipBody
+
+OwnedFeatureInverting : FeatureInverting =
+ invertingFeature = [QualifiedName]
+ | invertingFeature = OwnedFeatureChain
+ { ownedRelatedElement += invertingFeature }
+
+// Clause 8.2.4.3.7 Type Featuring
+
+TypeFeaturing =
+ 'featuring' ( Identification 'of' )?
+ featureOfType = [QualifiedName]
+ 'by' featuringType = [QualifiedName]
+ RelationshipBody
+
+OwnedTypeFeaturing : TypeFeaturing =
+ featuringType = [QualifiedName]
+
+// Clause 8.2.5 Kernel Concrete Syntax
+
+// Clause 8.2.5.1 Data Types Concrete Syntax
+
+DataType =
+ TypePrefix 'datatype'
+ ClassifierDeclaration TypeBody
+
+// Clause 8.2.5.2 Classes Concrete Syntax
+
+Class =
+ TypePrefix 'class'
+ ClassifierDeclaration TypeBody
+
+// Clause 8.2.5.3 Structures Concrete Syntax
+
+Structure =
+ TypePrefix 'struct'
+ ClassifierDeclaration TypeBody
+
+// Clause 8.2.5.4 Associations Concrete Syntax
+
+Association =
+ TypePrefix 'assoc'
+ ClassifierDeclaration TypeBody
+
+AssociationStructure =
+ TypePrefix 'assoc' 'struct'
+ ClassifierDeclaration TypeBody
+
+// Clause 8.2.5.5 Connectors Concrete Syntax
+
+// Clause 8.2.5.5.1 Connectors
+
+Connector =
+ FeaturePrefix 'connector'
+ ( FeatureDeclaration? ValuePart?
+ | ConnectorDeclaration
+ )
+ TypeBody
+
+ConnectorDeclaration : Connector =
+ BinaryConnectorDeclaration | NaryConnectorDeclaration
+
+BinaryConnectorDeclaration : Connector =
+ ( FeatureDeclaration? 'from' | isSufficient ?= 'all' 'from'? )?
+ ownedRelationship += ConnectorEndMember 'to'
+ ownedRelationship += ConnectorEndMember
+
+NaryConnectorDeclaration : Connector =
+ FeatureDeclaration?
+ '(' ownedRelationship += ConnectorEndMember ','
+ ownedRelationship += ConnectorEndMember
+ ( ',' ownedRelationship += ConnectorEndMember )*
+ ')'
+
+ConnectorEndMember : EndFeatureMembership =
+ ownedRelatedElement += ConnectorEnd
+
+ConnectorEnd : Feature =
+ ( ownedRelationship += OwnedCrossMultiplicityMember )?
+ ( declaredName = NAME REFERENCES )?
+ ownedRelationship += OwnedReferenceSubsetting
+
+OwnedCrossMultiplicityMember : OwningMembership =
+ ownedRelatedElement += OwnedCrossMultiplicity
+
+OwnedCrossMultiplicity : Feature =
+ ownedRelationship += OwnedMultiplicity
+
+// Clause 8.2.5.5.2 Binding Connectors
+
+BindingConnector =
+ FeaturePrefix 'binding'
+ BindingConnectorDeclaration TypeBody
+
+BindingConnectorDeclaration : BindingConnector =
+ FeatureDeclaration
+ ( 'of' ownedRelationship += ConnectorEndMember
+ '=' ownedRelationship += ConnectorEndMember )?
+ | ( isSufficient ?= 'all' )?
+ ( 'of'? ownedRelationship += ConnectorEndMember
+ '=' ownedRelationship += ConnectorEndMember )?
+
+// Clause 8.2.5.5.3 Successions
+
+Succession =
+ FeaturePrefix 'succession'
+ SuccessionDeclaration TypeBody
+
+SuccessionDeclaration : Succession =
+ FeatureDeclaration
+ ( 'first' ownedRelationship += ConnectorEndMember
+ 'then' ownedRelationship += ConnectorEndMember )?
+ | ( s.isSufficient ?= 'all' )?
+ ( 'first'? ownedRelationship += ConnectorEndMember
+ 'then' ownedRelationship += ConnectorEndMember )?
+
+// Clause 8.2.5.6 Behaviors Concrete Syntax
+
+// Clause 8.2.5.6.1 Behaviors
+
+Behavior =
+ TypePrefix 'behavior'
+ ClassifierDeclaration TypeBody
+
+// Clause 8.2.5.6.2 Steps
+
+Step =
+ FeaturePrefix
+ 'step' FeatureDeclaration ValuePart?
+ TypeBody
+
+// Clause 8.2.5.7 Functions Concrete Syntax
+
+// Clause 8.2.5.7.1 Functions
+
+Function =
+ TypePrefix 'function'
+ ClassifierDeclaration FunctionBody
+
+FunctionBody : Type =
+ ';' | '{' FunctionBodyPart '}'
+
+FunctionBodyPart : Type =
+ ( TypeBodyElement
+ | ownedRelationship += ReturnFeatureMember
+ )*
+ ( ownedRelationship += ResultExpressionMember )?
+
+ReturnFeatureMember : ReturnParameterMembership =
+ MemberPrefix 'return'
+ ownedRelatedElement += FeatureElement
+
+ResultExpressionMember : ResultExpressionMembership =
+ MemberPrefix
+ ownedRelatedElement += OwnedExpression
+
+// Clause 8.2.5.7.2 Expressions
+
+Expression =
+ FeaturePrefix
+ 'expr' FeatureDeclaration ValuePart?
+ FunctionBody
+
+// Clause 8.2.5.7.3 Predicates
+
+Predicate =
+ TypePrefix 'predicate'
+ ClassifierDeclaration FunctionBody
+
+// Clause 8.2.5.7.4 Boolean Expressions and Invariants
+
+BooleanExpression =
+ FeaturePrefix
+ 'bool' FeatureDeclaration ValuePart?
+ FunctionBody
+
+Invariant =
+ FeaturePrefix
+ 'inv' ( 'true' | isNegated ?= 'false' )?
+ FeatureDeclaration ValuePart?
+ FunctionBody
+
+// Clause 8.2.5.8 Expressions Concrete Syntax
+
+// Clause 8.2.5.8.1 Operator Expressions
+
+OwnedExpressionReferenceMember : FeatureMembership =
+ ownedRelationship += OwnedExpressionReference
+
+OwnedExpressionReference : FeatureReferenceExpression =
+ ownedRelationship += OwnedExpressionMember
+
+OwnedExpressionMember : FeatureMembership =
+ ownedFeatureMember = OwnedExpression
+
+OwnedExpression : Expression =
+ ConditionalExpression
+ | ConditionalBinaryOperatorExpression
+ | BinaryOperatorExpression
+ | UnaryOperatorExpression
+ | ClassificationExpression
+ | MetaclassificationExpression
+ | ExtentExpression
+ | PrimaryExpression
+
+ConditionalExpression : OperatorExpression =
+ operator = 'if'
+ ownedRelationship += ArgumentMember '?'
+ ownedRelationship += ArgumentExpressionMember 'else'
+ ownedRelationship += ArgumentExpressionMember
+ ownedRelationship += EmptyResultMember
+
+ConditionalBinaryOperatorExpression : OperatorExpression =
+ ownedRelationship += ArgumentMember
+ operator = ConditionalBinaryOperator
+ ownedRelationship += ArgumentExpressionMember
+ ownedRelationship += EmptyResultMember
+
+ConditionalBinaryOperator =
+ '??' | 'or' | 'and' | 'implies'
+
+BinaryOperatorExpression : OperatorExpression =
+ ownedRelationship += ArgumentMember
+ operator = BinaryOperator
+ ownedRelationship += ArgumentMember
+ ownedRelationship += EmptyResultMember
+
+BinaryOperator =
+ '|' | '&' | 'xor' | '..'
+ | '==' | '!=' | '===' | '!=='
+ | '<' | '>' | '<=' | '>='
+ | '+' | '-' | '*' | '/'
+ | '%' | '^' | '**'
+
+UnaryOperatorExpression : OperatorExpression =
+ operator = UnaryOperator
+ ownedRelationship += ArgumentMember
+ ownedRelationship += EmptyResultMember
+
+UnaryOperator =
+ '+' | '-' | '~' | 'not'
+
+ClassificationExpression : OperatorExpression =
+ ( ownedRelationship += ArgumentMember )?
+ ( operator = ClassificationTestOperator
+ ownedRelationship += TypeReferenceMember
+ | operator = CastOperator
+ ownedRelationship += TypeResultMember
+ )
+ ownedRelationship += EmptyResultMember
+
+ClassificationTestOperator =
+ 'istype' | 'hastype' | '@'
+
+CastOperator =
+ 'as'
+
+MetaclassificationExpression : OperatorExpression =
+ ownedRelationship += MetadataArgumentMember
+ ( operator = ClassificationTestOperator
+ ownedRelationship += TypeReferenceMember
+ | operator = MetaCastOperator
+ ownedRelationship += TypeResultMember
+ )
+ ownedRelationship += EmptyResultMember
+
+ArgumentMember : ParameterMembership =
+ ownedMemberParameter = Argument
+
+Argument : Feature =
+ ownedRelationship += ArgumentValue
+
+ArgumentValue : FeatureValue =
+ value = OwnedExpression
+
+ArgumentExpressionMember : FeatureMembership =
+ ownedRelatedElement += ArgumentExpression
+
+ArgumentExpression : Feature =
+ ownedRelationship += ArgumentExpressionValue
+
+ArgumentExpressionValue : FeatureValue =
+ value = OwnedExpressionReference
+
+MetadataArgumentMember : ParameterMembership =
+ ownedRelatedElement += MetadataArgument
+
+MetadataArgument : Feature =
+ ownedRelationship += MetadataValue
+
+MetadataValue : FeatureValue =
+ value = MetadataReference
+
+MetadataReference : MetadataAccessExpression =
+ ownedRelationship += ElementReferenceMember
+
+MetaclassificationTestOperator =
+ '@@'
+
+MetaCastOperator =
+ 'meta'
+
+ExtentExpression : OperatorExpression =
+ operator = 'all'
+ ownedRelationship += TypeReferenceMember
+
+TypeReferenceMember : ParameterMembership =
+ ownedMemberFeature = TypeReference
+
+TypeResultMember : ResultParameterMembership =
+ ownedMemberFeature = TypeReference
+
+TypeReference : Feature =
+ ownedRelationship += ReferenceTyping
+
+ReferenceTyping : FeatureTyping =
+ type = [QualifiedName]
+
+EmptyResultMember : ReturnParameterMembership =
+ ownedRelatedElement += EmptyFeature
+
+EmptyFeature : Feature =
+ { }
+
+// Notes:
+// 1. OperatorExpressions provide a shorthand notation for InvocationExpressions that invoke a library Function represented as an operator symbol. Table 5 shows the mapping from operator symbols to the Functions they represent from the Kernel Model Library (see Clause 9). An OperatorExpression contains subexpressions called its operands that generally correspond to the argument Expressions of the OperatorExpression, except in the case of operators representing control Functions, in which case the evaluation of certain operands is as determined by the Function (see 8.4.4.9 for details).
+// 2. Though not directly expressed in the syntactic productions given above, in any OperatorExpression containing nested OperatorExpressions, the nested OperatorExpressions shall be implicitly grouped according to the precedence of the operators involved, as given in Table 6. OperatorExpressions with higher precedence operators shall be grouped more tightly than those with lower precedence operators. Further, all BinaryOperators other than exponentiation are left-associative (i.e, they group to the left), while the exponentiation operators (^ and **) are right-associative (i.e., they group to the right).
+// 3. The unary operator symbol ~ maps to the library Function DataFunctions::'~', as shown in Table 5. This abstract Function may be given a concrete definition in a domain-specific Function library, but no default definition is provided in the Kernel Functions Library. If no domain-specific definition is available, a tool should give a warning if this operator is used.
+
+// Clause 8.2.5.8.2 Primary Expressions
+
+PrimaryExpression : Expression =
+ FeatureChainExpression
+ | NonFeatureChainPrimaryExpression
+
+PrimaryArgumentValue : FeatureValue =
+ value = PrimaryExpression
+
+PrimaryArgument : Feature =
+ ownedRelationship += PrimaryArgumentValue
+
+PrimaryArgumentMember : ParameterMembership =
+ ownedMemberParameter = PrimaryArgument
+
+NonFeatureChainPrimaryExpression : Expression =
+ BracketExpression
+ | IndexExpression
+ | SequenceExpression
+ | SelectExpression
+ | CollectExpression
+ | FunctionOperationExpression
+ | BaseExpression
+
+NonFeatureChainPrimaryArgumentValue : FeatureValue =
+ value = NonFeatureChainPrimaryExpression
+
+NonFeatureChainPrimaryArgument : Feature =
+ ownedRelationship += NonFeatureChainPrimaryArgumentValue
+
+NonFeatureChainPrimaryArgumentMember : ParameterMembership =
+ ownedMemberParameter = PrimaryArgument
+
+BracketExpression : OperatorExpression =
+ ownedRelationship += PrimaryArgumentMember
+ operator = '['
+ ownedRelationship += SequenceExpressionListMember ']'
+
+IndexExpression =
+ ownedRelationship += PrimaryArgumentMember '#'
+ '(' ownedRelationship += SequenceExpressionListMember ')'
+
+SequenceExpression : Expression =
+ '(' SequenceExpressionList ')'
+
+SequenceExpressionList : Expression =
+ OwnedExpression ','? | SequenceOperatorExpression
+
+SequenceOperatorExpression : OperatorExpression =
+ ownedRelationship += OwnedExpressionMember
+ operator = ','
+ ownedRelationship += SequenceExpressionListMember
+
+SequenceExpressionListMember : FeatureMembership =
+ ownedMemberFeature = SequenceExpressionList
+
+FeatureChainExpression =
+ ownedRelationship += NonFeatureChainPrimaryArgumentMember '.'
+ ownedRelationship += FeatureChainMember
+
+CollectExpression =
+ ownedRelationship += PrimaryArgumentMember '.'
+ ownedRelationship += BodyArgumentMember
+
+SelectExpression =
+ ownedRelationship += PrimaryArgumentMember '.?'
+ ownedRelationship += BodyArgumentMember
+
+FunctionOperationExpression : InvocationExpression =
+ ownedRelationship += PrimaryArgumentMember '->'
+ ownedRelationship += InvocationTypeMember
+ ( ownedRelationship += BodyArgumentMember
+ | ownedRelationship += FunctionReferenceArgumentMember
+ | ArgumentList )
+ ownedRelationship += EmptyResultMember
+
+BodyArgumentMember : ParameterMembership =
+ ownedMemberParameter = BodyArgument
+
+BodyArgument : Feature =
+ ownedRelationship += BodyArgumentValue
+
+BodyArgumentValue : FeatureValue =
+ value = BodyExpression
+
+FunctionReferenceArgumentMember : ParameterMembership =
+ ownedMemberParameter = FunctionReferenceArgument
+
+FunctionReferenceArgument : Feature =
+ ownedRelationship += FunctionReferenceArgumentValue
+
+FunctionReferenceArgumentValue : FeatureValue =
+ value = FunctionReferenceExpression
+
+FunctionReferenceExpression : FeatureReferenceExpression =
+ ownedRelationship += FunctionReferenceMember
+
+FunctionReferenceMember : FeatureMembership =
+ ownedMemberFeature = FunctionReference
+
+FunctionReference : Expression =
+ ownedRelationship += ReferenceTyping
+
+FeatureChainMember : Membership =
+ FeatureReferenceMember
+ | OwnedFeatureChainMember
+
+OwnedFeatureChainMember : OwningMembership =
+ ownedMemberElement = FeatureChain
+
+// Notes:
+// 1. Primary expressions provide additional shorthand notations for certain kinds of InvocationExpressions. For those cases in which the InvocationExpression is an OperatorExpression, its operator shall be resolved to the appropriate library function as given in Table 7. Note also that, for a CollectionExpression or SelectExpression, the abstract syntax constrains the operator to be collect and select, respectively, separately from the . and .? symbols used in their concrete syntax notation (see 8.3.4.8.2 and 8.3.4.8.18).
+// 2. The grammar allows a bracket syntax [...]that parses to an invocation of the library Function BaseFunctions::'[', as shown in Table 7. This notation is available for use with domain-specific library models that given a concrete definition to the abstract base '[' Function, but no default definition is provided in the Kernel Functions Library. If no domain-specific definition is available, a tool should give a warning if this operator is used.
+
+// Clause 8.2.5.8.3 Base Expressions
+
+BaseExpression : Expression =
+ NullExpression
+ | LiteralExpression
+ | FeatureReferenceExpression
+ | MetadataAccessExpression
+ | InvocationExpression
+ | ConstructorExpression
+ | BodyExpression
+
+NullExpression : NullExpression =
+ 'null' | '(' ')'
+
+FeatureReferenceExpression : FeatureReferenceExpression =
+ ownedRelationship += FeatureReferenceMember
+ ownedRelationship += EmptyResultMember
+
+FeatureReferenceMember : Membership =
+ memberElement = FeatureReference
+
+FeatureReference : Feature =
+ [QualifiedName]
+
+MetadataAccessExpression =
+ ownedRelationship += ElementReferenceMember '.' 'metadata'
+
+ElementReferenceMember : Membership =
+ memberElement = [QualifiedName]
+
+InvocationExpression : InvocationExpression =
+ ownedRelationship += InstantiatedTypeMember
+ ArgumentList
+ ownedRelationship += EmptyResultMember
+
+ConstructorExpression =
+ 'new' ownedRelationship += InstantiatedTypeMember
+ ownedRelationship += ConstructorResultMember
+
+ConstructorResultMember : ReturnParameterMembership =
+ ownedRelatedElement += ConstructorResult
+
+ConstructorResult : Feature =
+ ArgumentList
+
+InstantiatedTypeMember : Membership =
+ memberElement = InstantiatedTypeReference
+ | OwnedFeatureChainMember
+
+InstantiatedTypeReference : Type =
+ [QualifiedName]
+
+ArgumentList : Feature =
+ '(' ( PositionalArgumentList | NamedArgumentList )? ')'
+
+PositionalArgumentList : Feature =
+ e.ownedRelationship += ArgumentMember
+ ( ',' e.ownedRelationship += ArgumentMember )*
+
+NamedArgumentList : Feature =
+ ownedRelationship += NamedArgumentMember
+ ( ',' ownedRelationship += NamedArgumentMember )*
+
+NamedArgumentMember : FeatureMembership =
+ ownedMemberFeature = NamedArgument
+
+NamedArgument : Feature =
+ ownedRelationship += ParameterRedefinition '='
+ ownedRelationship += ArgumentValue
+
+ParameterRedefinition : Redefinition =
+ redefinedFeature = [QualifiedName]
+
+BodyExpression : FeatureReferenceExpression =
+ ownedRelationship += ExpressionBodyMember
+
+ExpressionBodyMember : FeatureMembership =
+ ownedMemberFeature = ExpressionBody
+
+ExpressionBody : Expression =
+ '{' FunctionBodyPart '}'
+
+// Clause 8.2.5.8.4 Literal Expressions
+
+LiteralExpression =
+ LiteralBoolean
+ | LiteralString
+ | LiteralInteger
+ | LiteralReal
+ | LiteralInfinity
+
+LiteralBoolean =
+ value = BooleanValue
+
+BooleanValue : Boolean =
+ 'true' | 'false'
+
+LiteralString =
+ value = STRING_VALUE
+
+LiteralInteger =
+ value = DECIMAL_VALUE
+
+LiteralReal =
+ value = RealValue
+
+RealValue : Real =
+ DECIMAL_VALUE? '.' ( DECIMAL_VALUE | EXPONENTIAL_VALUE )
+ | EXPONENTIAL_VALUE
+
+LiteralInfinity =
+ '*'
+
+// Clause 8.2.5.9 Interactions Concrete Syntax
+
+// Clause 8.2.5.9.1 Interactions
+
+Interaction =
+ TypePrefix 'interaction'
+ ClassifierDeclaration TypeBody
+
+// Clause 8.2.5.9.2 Flows
+
+Flow =
+ FeaturePrefix 'flow'
+ FlowDeclaration TypeBody
+
+SuccessionFlow =
+ FeaturePrefix 'succession' 'flow'
+ FlowDeclaration TypeBody
+
+FlowDeclaration : Flow =
+ FeatureDeclaration ValuePart?
+ ( 'of' ownedRelationship += PayloadFeatureMember )?
+ ( 'from' ownedRelationship += FlowEndMember
+ 'to' ownedRelationship += FlowEndMember )?
+ | ( isSufficient ?= 'all' )?
+ ownedRelationship += FlowEndMember 'to'
+ ownedRelationship += FlowEndMember
+
+PayloadFeatureMember : FeatureMembership =
+ ownedRelatedElement = PayloadFeature
+
+PayloadFeature =
+ Identification PayloadFeatureSpecializationPart ValuePart?
+ | Identification ValuePart
+ | ownedRelationship += OwnedFeatureTyping
+ ( ownedRelationship += OwnedMultiplicity )?
+ | ownedRelationship += OwnedMultiplicity
+ ( ownedRelationship += OwnedFeatureTyping )?
+
+PayloadFeatureSpecializationPart : Feature =
+ FeatureSpecialization+ MultiplicityPart?
+ FeatureSpecialization*
+ | MultiplicityPart FeatureSpecialization+
+
+FlowEndMember : EndFeatureMembership =
+ ownedRelatedElement += FlowEnd
+
+FlowEnd =
+ ( ownedRelationship += OwnedReferenceSubsetting '.' )?
+ ownedRelationship += FlowFeatureMember
+
+FlowFeatureMember : FeatureMembership =
+ ownedRelatedElement += FlowFeature
+
+FlowFeature : Feature =
+ ownedRelationship += FlowFeatureRedefinition
+
+// (See Note 1)
+
+FlowFeatureRedefinition : Redefinition =
+ redefinedFeature = [QualifiedName]
+
+// Notes:
+// 1. To ensure that an FlowFeature passes the validateRedefinitionDirectionConformance constraint (see 8.3.3.3.8), its direction must be set to the direction of its redefinedFeature, relative to its owning FlowEnd, that is, the result of the following OCL expression: owningType.directionOf(ownedRedefinition->at(1).redefinedFeature)
+
+// Clause 8.2.5.10 Feature Values Concrete Syntax
+
+ValuePart : Feature =
+ ownedRelationship += FeatureValue
+
+FeatureValue =
+ ( '='
+ | isInitial ?= ':='
+ | isDefault ?= 'default' ( '=' | isInitial ?= ':=' )?
+ )
+ ownedRelatedElement += OwnedExpression
+
+// Clause 8.2.5.11 Multiplicities Concrete Syntax
+
+Multiplicity =
+ MultiplicitySubset | MultiplicityRange
+
+MultiplicitySubset : Multiplicity =
+ 'multiplicity' Identification Subsets
+ TypeBody
+
+MultiplicityRange =
+ 'multiplicity' Identification MultiplicityBounds
+ TypeBody
+
+OwnedMultiplicity : OwningMembership =
+ ownedRelatedElement += OwnedMultiplicityRange
+
+OwnedMultiplicityRange : MultiplicityRange =
+ MultiplicityBounds
+
+MultiplicityBounds : MultiplicityRange =
+ '[' ( ownedRelationship += MultiplicityExpressionMember '..' )?
+ ownedRelationship += MultiplicityExpressionMember ']'
+
+MultiplicityExpressionMember : OwningMembership =
+ ownedRelatedElement += ( LiteralExpression | FeatureReferenceExpression )
+
+// Clause 8.2.5.12 Metadata Concrete Syntax
+
+Metaclass =
+ TypePrefix 'metaclass'
+ ClassifierDeclaration TypeBody
+
+PrefixMetadataAnnotation : Annotation =
+ '#' ownedRelatedElement += PrefixMetadataFeature
+
+PrefixMetadataMember : OwningMembership =
+ '#' ownedRelatedElement += PrefixMetadataFeature
+
+PrefixMetadataFeature : MetadataFeature =
+ ownedRelationship += OwnedFeatureTyping
+
+MetadataFeature =
+ ( ownedRelationship += PrefixMetadataMember )*
+ ( '@' | 'metadata' )
+ MetadataFeatureDeclaration
+ ( 'about' ownedRelationship += Annotation
+ ( ',' ownedRelationship += Annotation )*
+ )?
+ MetadataBody
+
+MetadataFeatureDeclaration : MetadataFeature =
+ ( Identification ( ':' | 'typed' 'by' ) )?
+ ownedRelationship += OwnedFeatureTyping
+
+MetadataBody : Feature =
+ ';' | '{' ( ownedRelationship += MetadataBodyElement )* '}'
+
+MetadataBodyElement : Membership =
+ NonFeatureMember
+ | MetadataBodyFeatureMember
+ | AliasMember
+ | Import
+
+MetadataBodyFeatureMember : FeatureMembership =
+ ownedMemberFeature = MetadataBodyFeature
+
+MetadataBodyFeature : Feature =
+ 'feature'? ( ':>>' | 'redefines')? ownedRelationship += OwnedRedefinition
+ FeatureSpecializationPart? ValuePart?
+ MetadataBody
+
+// Clause 8.2.5.13 Packages Concrete Syntax
+
+Package =
+ ( ownedRelationship += PrefixMetadataMember )*
+ PackageDeclaration PackageBody
+
+LibraryPackage =
+ ( isStandard ?= 'standard' ) 'library'
+ ( ownedRelationship += PrefixMetadataMember )*
+ PackageDeclaration PackageBody
+
+PackageDeclaration : Package =
+ 'package' Identification
+
+PackageBody : Package =
+ ';'
+ | '{' ( NamespaceBodyElement
+ | ownedRelationship += ElementFilterMember
+ )*
+ '}'
+
+ElementFilterMember : ElementFilterMembership =
+ MemberPrefix
+ 'filter' condition = OwnedExpression ';'
+
+// End of BNF
+
+
diff --git a/Resources/SysML-textual-bnf.kebnf b/Resources/SysML-textual-bnf.kebnf
new file mode 100644
index 00000000..e5c771e9
--- /dev/null
+++ b/Resources/SysML-textual-bnf.kebnf
@@ -0,0 +1,1705 @@
+// Manual corrections by HP de Koning
+
+// Part 2 - Systems Modeling Language (SysML)
+
+// Clause 8.2.2 Textual Notation
+
+// Clause 8.2.2.1 Textual Notation Overview
+
+// Clause 8.2.2.1.1 EBNF Conventions
+
+// Clause 8.2.2.1.2 Lexical Structure
+
+RESERVED_KEYWORD =
+ 'about' | 'abstract' | 'accept' | 'action' | 'actor' | 'after' | 'alias' | 'all' | 'allocate' | 'allocation'
+ | 'analysis' | 'and' | 'as' | 'assert' | 'assign' | 'assume' | 'at' | 'attribute' | 'bind' | 'binding' | 'by' | 'calc'
+ | 'case' | 'comment' | 'concern' | 'connect' | 'connection' | 'constant' | 'constraint' | 'crosses' | 'decide'
+ | 'def' | 'default' | 'defined' | 'dependency' | 'derived' | 'do' | 'doc' | 'else' | 'end' | 'entry' | 'enum'
+ | 'event' | 'exhibit' | 'exit' | 'expose' | 'false' | 'filter' | 'first' | 'flow' | 'for' | 'fork' | 'frame' | 'from'
+ | 'hastype' | 'if' | 'implies' | 'import' | 'in' | 'include' | 'individual' | 'inout' | 'interface' | 'istype'
+ | 'item' | 'join' | 'language' | 'library' | 'locale' | 'loop' | 'merge' | 'message' | 'meta' | 'metadata'
+ | 'nonunique' | 'not' | 'null' | 'objective' | 'occurrence' | 'of' | 'or' | 'ordered' | 'out' | 'package' | 'parallel'
+ | 'part' | 'perform' | 'port' | 'private' | 'protected' | 'public' | 'redefines' | 'ref' | 'references' | 'render'
+ | 'rendering' | 'rep' | 'require' | 'requirement' | 'return' | 'satisfy' | 'send' | 'snapshot' | 'specializes'
+ | 'stakeholder' | 'standard' | 'state' | 'subject' | 'subsets' | 'succession' | 'terminate' | 'then' | 'timeslice'
+ | 'to' | 'transition' | 'true' | 'until' | 'use' | 'variant' | 'variation' | 'verification' | 'verify' | 'via'
+ | 'view' | 'viewpoint' | 'when' | 'while' | 'xor'
+
+DEFINED_BY = ':' | 'defined' 'by'
+
+SPECIALIZES = ':>' | 'specializes'
+
+SUBSETS = ':>' | 'subsets'
+
+REFERENCES = '::>' | 'references'
+
+CROSSES = '=>' | 'crosses'
+
+REDEFINES = ':>>' | 'redefines'
+
+// Clause 8.2.2.2 Elements and Relationships Textual Notation
+
+Identification : Element =
+ ( '<' declaredShortName = NAME '>' )?
+ ( declaredName = NAME )?
+
+RelationshipBody : Relationship =
+ ';' | '{' ( ownedRelationship += OwnedAnnotation )* '}'
+
+// Clause 8.2.2.3 Dependencies Textual Notation
+
+Dependency =
+ ( ownedRelationship += PrefixMetadataAnnotation )*
+ 'dependency' DependencyDeclaration
+ RelationshipBody
+
+DependencyDeclaration =
+ ( Identification 'from' )?
+ client += [QualifiedName] ( ',' client += [QualifiedName] )* 'to'
+ supplier += [QualifiedName] ( ',' supplier += [QualifiedName] )*
+
+// Clause 8.2.2.4 Annotations Textual Notation
+
+// Clause 8.2.2.4.1 Annotations
+
+Annotation =
+ annotatedElement = [QualifiedName]
+
+OwnedAnnotation : Annotation =
+ ownedRelatedElement += AnnotatingElement
+
+AnnotatingMember : OwningMembership =
+ ownedRelatedElement += AnnotatingElement
+
+AnnotatingElement =
+ Comment
+ | Documentation
+ | TextualRepresentation
+ | MetadataFeature
+
+// Clause 8.2.2.4.2 Comments and Documentation
+
+Comment =
+ ( 'comment' Identification
+ ( 'about' ownedRelationship += Annotation
+ ( ',' ownedRelationship += Annotation )*
+ )?
+ )?
+ ( 'locale' locale = STRING_VALUE )?
+ body = REGULAR_COMMENT
+
+Documentation =
+ 'doc' Identification
+ ( 'locale' locale = STRING_VALUE )?
+ body = REGULAR_COMMENT
+
+// Clause 8.2.2.4.3 Textual Representation
+
+TextualRepresentation =
+ ( 'rep' Identification )?
+ 'language' language = STRING_VALUE body = REGULAR_COMMENT
+
+// Clause 8.2.2.5 Namespaces and Packages Textual Notation
+
+// Clause 8.2.2.5.1 Packages
+
+RootNamespace : Namespace =
+ PackageBodyElement*
+
+Package =
+ ( ownedRelationship += PrefixMetadataMember )*
+ PackageDeclaration PackageBody
+
+LibraryPackage =
+ ( isStandard ?= 'standard' ) 'library'
+ ( ownedRelationship += PrefixMetadataMember )*
+ PackageDeclaration PackageBody
+
+PackageDeclaration : Package =
+ 'package' Identification
+
+PackageBody : Package =
+ ';' | '{' PackageBodyElement* '}'
+
+PackageBodyElement : Package =
+ ownedRelationship += PackageMember
+ | ownedRelationship += ElementFilterMember
+ | ownedRelationship += AliasMember
+ | ownedRelationship += Import
+
+MemberPrefix : Membership =
+ ( visibility = VisibilityIndicator )?
+
+PackageMember : OwningMembership =
+ MemberPrefix
+ ( ownedRelatedElement += DefinitionElement
+ | ownedRelatedElement = UsageElement )
+
+ElementFilterMember : ElementFilterMembership =
+ MemberPrefix
+ 'filter' ownedRelatedElement += OwnedExpression ';'
+
+AliasMember : Membership =
+ MemberPrefix
+ 'alias' ( '<' memberShortName = NAME '>' )?
+ ( memberName = NAME )?
+ 'for' memberElement = [QualifiedName]
+ RelationshipBody
+
+Import =
+ visibility = VisibilityIndicator
+ 'import' ( isImportAll ?= 'all' )?
+ ImportDeclaration
+ RelationshipBody
+
+ImportDeclaration : Import =
+ MembershipImport | NamespaceImport
+
+MembershipImport =
+ importedMembership = [QualifiedName]
+ ( '::' isRecursive ?= '**' )?
+
+NamespaceImport =
+ importedNamespace = [QualifiedName] '::' '*'
+ ( '::' isRecursive ?= '**' )?
+ | importedNamespace = FilterPackage
+ { ownedRelatedElement += importedNamespace }
+
+FilterPackage : Package =
+ ownedRelationship += FilterPackageImport
+ ( ownedRelationship += FilterPackageMember )+
+
+FilterPackageMember : ElementFilterMembership =
+ '[' ownedRelatedElement += OwnedExpression ']'
+
+VisibilityIndicator : VisibilityKind =
+ 'public' | 'private' | 'protected'
+
+// Clause 8.2.2.5.2 Package Elements
+
+DefinitionElement : Element =
+ Package
+ | LibraryPackage
+ | AnnotatingElement
+ | Dependency
+ | AttributeDefinition
+ | EnumerationDefinition
+ | OccurrenceDefinition
+ | IndividualDefinition
+ | ItemDefinition
+ | PartDefinition
+ | ConnectionDefinition
+ | FlowDefinition
+ | InterfaceDefinition
+ | PortDefinition
+ | ActionDefinition
+ | CalculationDefinition
+ | StateDefinition
+ | ConstraintDefinition
+ | RequirementDefinition
+ | ConcernDefinition
+ | CaseDefinition
+ | AnalysisCaseDefinition
+ | VerificationCaseDefinition
+ | UseCaseDefinition
+ | ViewDefinition
+ | ViewpointDefinition
+ | RenderingDefinition
+ | MetadataDefinition
+ | ExtendedDefinition
+
+UsageElement : Usage =
+ NonOccurrenceUsageElement
+ | OccurrenceUsageElement
+
+// Clause 8.2.2.6 Definition and Usage Textual Notation
+
+// Clause 8.2.2.6.1 Definitions
+
+BasicDefinitionPrefix =
+ isAbstract ?= 'abstract' | isVariation ?= 'variation'
+
+DefinitionExtensionKeyword : Definition =
+ ownedRelationship += PrefixMetadataMember
+
+DefinitionPrefix : Definition =
+ BasicDefinitionPrefix? DefinitionExtensionKeyword*
+
+Definition =
+ DefinitionDeclaration DefinitionBody
+
+DefinitionDeclaration : Definition =
+ Identification SubclassificationPart?
+
+DefinitionBody : Type =
+ ';' | '{' DefinitionBodyItem* '}'
+
+DefinitionBodyItem : Type =
+ ownedRelationship += DefinitionMember
+ | ownedRelationship += VariantUsageMember
+ | ownedRelationship += NonOccurrenceUsageMember
+ | ( ownedRelationship += SourceSuccessionMember )?
+ ownedRelationship += OccurrenceUsageMember
+ | ownedRelationship += AliasMember
+ | ownedRelationship += Import
+
+DefinitionMember : OwningMembership =
+ MemberPrefix
+ ownedRelatedElement += DefinitionElement
+
+VariantUsageMember : VariantMembership =
+ MemberPrefix 'variant'
+ ownedVariantUsage = VariantUsageElement
+
+NonOccurrenceUsageMember : FeatureMembership =
+ MemberPrefix
+ ownedRelatedElement += NonOccurrenceUsageElement
+
+OccurrenceUsageMember : FeatureMembership =
+ MemberPrefix
+ ownedRelatedElement += OccurrenceUsageElement
+
+StructureUsageMember : FeatureMembership =
+ MemberPrefix
+ ownedRelatedElement += StructureUsageElement
+
+BehaviorUsageMember : FeatureMembership =
+ MemberPrefix
+ ownedRelatedElement += BehaviorUsageElement
+
+// Clause 8.2.2.6.2 Usages
+
+FeatureDirection : FeatureDirectionKind =
+ 'in' | 'out' | 'inout'
+
+RefPrefix : Usage =
+ ( direction = FeatureDirection )?
+ ( isDerived ?= 'derived' )?
+ ( isAbstract ?= 'abstract' | isVariation ?= 'variation' )?
+ ( isConstant ?= 'constant' )?
+
+BasicUsagePrefix : Usage =
+ RefPrefix
+ ( isReference ?= 'ref' )?
+
+EndUsagePrefix : Usage =
+ isEnd ?= 'end' ( ownedRelationship += OwnedCrossFeatureMember )?
+
+// (See Note 1)
+
+OwnedCrossFeatureMember : OwningMembership =
+ ownedRelatedElement += OwnedCrossFeature
+
+OwnedCrossFeature : ReferenceUsage =
+ BasicUsagePrefix UsageDeclaration
+
+UsageExtensionKeyword : Usage =
+ ownedRelationship += PrefixMetadataMember
+
+UnextendedUsagePrefix : Usage =
+ EndUsagePrefix | BasicUsagePrefix
+
+UsagePrefix : Usage =
+ UnextendedUsagePrefix UsageExtensionKeyword*
+
+Usage =
+ UsageDeclaration UsageCompletion
+
+UsageDeclaration : Usage =
+ Identification FeatureSpecializationPart?
+
+UsageCompletion : Usage =
+ ValuePart? UsageBody
+
+UsageBody : Usage =
+ DefinitionBody
+
+ValuePart : Feature =
+ ownedRelationship += FeatureValue
+
+FeatureValue =
+ ( '='
+ | isInitial ?= ':='
+ | isDefault ?= 'default' ( '=' | isInitial ?= ':=' )?
+ )
+ ownedRelatedElement += OwnedExpression
+
+// Notes:
+// 1. A Usage parsed with isEnd = true for which mayTimeVary = true must also have isConstant set to true, even though this is not explicitly notated in the textual notation, in order to satisfy the KerML constraint checkFeatureEndIsConstant.
+
+// Clause 8.2.2.6.3 Reference Usages
+
+DefaultReferenceUsage : ReferenceUsage =
+ RefPrefix Usage
+
+ReferenceUsage =
+ ( EndUsagePrefix | RefPrefix )
+ 'ref' Usage
+
+VariantReference : ReferenceUsage =
+ ownedRelationship += OwnedReferenceSubsetting
+ FeatureSpecialization* UsageBody
+
+// Clause 8.2.2.6.4 Body Elements
+
+NonOccurrenceUsageElement : Usage =
+ DefaultReferenceUsage
+ | ReferenceUsage
+ | AttributeUsage
+ | EnumerationUsage
+ | BindingConnectorAsUsage
+ | SuccessionAsUsage
+ | ExtendedUsage
+
+OccurrenceUsageElement : Usage =
+ StructureUsageElement | BehaviorUsageElement
+
+StructureUsageElement : Usage =
+ OccurrenceUsage
+ | IndividualUsage
+ | PortionUsage
+ | EventOccurrenceUsage
+ | ItemUsage
+ | PartUsage
+ | ViewUsage
+ | RenderingUsage
+ | PortUsage
+ | ConnectionUsage
+ | InterfaceUsage
+ | AllocationUsage
+ | Message
+ | FlowUsage
+ | SuccessionFlowUsage
+
+BehaviorUsageElement : Usage =
+ ActionUsage
+ | CalculationUsage
+ | StateUsage
+ | ConstraintUsage
+ | RequirementUsage
+ | ConcernUsage
+ | CaseUsage
+ | AnalysisCaseUsage
+ | VerificationCaseUsage
+ | UseCaseUsage
+ | ViewpointUsage
+ | PerformActionUsage
+ | ExhibitStateUsage
+ | IncludeUseCaseUsage
+ | AssertConstraintUsage
+ | SatisfyRequirementUsage
+
+VariantUsageElement : Usage =
+ VariantReference
+ | ReferenceUsage
+ | AttributeUsage
+ | BindingConnectorAsUsage
+ | SuccessionAsUsage
+ | OccurrenceUsage
+ | IndividualUsage
+ | PortionUsage
+ | EventOccurrenceUsage
+ | ItemUsage
+ | PartUsage
+ | ViewUsage
+ | RenderingUsage
+ | PortUsage
+ | ConnectionUsage
+ | InterfaceUsage
+ | AllocationUsage
+ | Message
+ | FlowUsage
+ | SuccessionFlowUsage
+ | BehaviorUsageElement
+
+// Clause 8.2.2.6.5 Specialization
+
+SubclassificationPart : Classifier =
+ SPECIALIZES ownedRelationship += OwnedSubclassification
+ ( ',' ownedRelationship += OwnedSubclassification )*
+
+OwnedSubclassification : Subclassification =
+ superClassifier = [QualifiedName]
+
+FeatureSpecializationPart : Feature =
+ FeatureSpecialization+ MultiplicityPart? FeatureSpecialization*
+ | MultiplicityPart FeatureSpecialization*
+
+FeatureSpecialization : Feature =
+ Typings | Subsettings | References | Crosses | Redefinitions
+
+Typings : Feature =
+ TypedBy ( ',' ownedRelationship += FeatureTyping )*
+
+TypedBy : Feature =
+ DEFINED_BY ownedRelationship += FeatureTyping
+
+FeatureTyping =
+ OwnedFeatureTyping | ConjugatedPortTyping
+
+OwnedFeatureTyping : FeatureTyping =
+ type = [QualifiedName]
+ | type = OwnedFeatureChain
+ { ownedRelatedElement += type }
+
+Subsettings : Feature =
+ Subsets ( ',' ownedRelationship += OwnedSubsetting )*
+
+Subsets : Feature =
+ SUBSETS ownedRelationship += OwnedSubsetting
+
+OwnedSubsetting : Subsetting =
+ subsettedFeature = [QualifiedName]
+ | subsettedFeature = OwnedFeatureChain
+ { ownedRelatedElement += subsettedFeature }
+
+References : Feature =
+ REFERENCES ownedRelationship += OwnedReferenceSubsetting
+
+OwnedReferenceSubsetting : ReferenceSubsetting =
+ referencedFeature = [QualifiedName]
+ | referencedFeature = OwnedFeatureChain
+ { ownedRelatedElement += referenceFeature }
+
+Crosses : Feature =
+ CROSSES ownedRelationship += OwnedCrossSubsetting
+
+OwnedCrossSubsetting : CrossSubsetting =
+ crossedFeature = [QualifiedName]
+ | crossedFeature = OwnedFeatureChain
+ { ownedRelatedElement += crossedFeature }
+
+Redefinitions : Feature =
+ Redefines ( ',' ownedRelationship += OwnedRedefinition )*
+
+Redefines : Feature =
+ REDEFINES ownedRelationship += OwnedRedefinition
+
+OwnedRedefinition : Redefinition =
+ redefinedFeature = [QualifiedName]
+ | redefinedFeature = OwnedFeatureChain
+ { ownedRelatedElement += redefinedFeature }
+
+OwnedFeatureChain : Feature =
+ ownedRelationship += OwnedFeatureChaining
+ ( '.' ownedRelationship += OwnedFeatureChaining )+
+
+OwnedFeatureChaining : FeatureChaining =
+ chainingFeature = [QualifiedName]
+
+// Clause 8.2.2.6.6 Multiplicity
+
+MultiplicityPart : Feature =
+ ownedRelationship += OwnedMultiplicity
+ | ( ownedRelationship += OwnedMultiplicity )?
+ ( isOrdered ?= 'ordered' ( { isUnique = false } 'nonunique' )?
+ | { isUnique = false } 'nonunique' ( isOrdered ?= 'ordered' )? )
+
+OwnedMultiplicity : OwningMembership =
+ ownedRelatedElement += MultiplicityRange
+
+MultiplicityRange =
+ '[' ( ownedRelationship += MultiplicityExpressionMember '..' )?
+ ownedRelationship += MultiplicityExpressionMember ']'
+
+MultiplicityExpressionMember : OwningMembership =
+ ownedRelatedElement += ( LiteralExpression | FeatureReferenceExpression )
+
+// Clause 8.2.2.7 Attributes Textual Notation
+
+AttributeDefinition : AttributeDefinition =
+ DefinitionPrefix 'attribute' 'def' Definition
+
+AttributeUsage : AttributeUsage =
+ UsagePrefix 'attribute' Usage
+
+// Clause 8.2.2.8 Enumerations Textual Notation
+
+EnumerationDefinition =
+ DefinitionExtensionKeyword*
+ 'enum' 'def' DefinitionDeclaration EnumerationBody
+
+EnumerationBody : EnumerationDefinition =
+ ';'
+ | '{' ( ownedRelationship += AnnotatingMember
+ | ownedRelationship += EnumerationUsageMember )*
+ '}'
+
+EnumerationUsageMember : VariantMembership =
+ MemberPrefix ownedRelatedElement += EnumeratedValue
+
+EnumeratedValue : EnumerationUsage =
+ 'enum'? Usage
+
+EnumerationUsage : EnumerationUsage =
+ UsagePrefix 'enum' Usage
+
+// Clause 8.2.2.9 Occurrences Textual Notation
+
+// Clause 8.2.2.9.1 Occurrence Definitions
+
+OccurrenceDefinitionPrefix : OccurrenceDefinition =
+ BasicDefinitionPrefix?
+ ( isIndividual ?= 'individual'
+ ownedRelationship += EmptyMultiplicityMember
+ )?
+ DefinitionExtensionKeyword*
+
+OccurrenceDefinition =
+ OccurrenceDefinitionPrefix 'occurrence' 'def' Definition
+
+IndividualDefinition : OccurrenceDefinition =
+ BasicDefinitionPrefix? isIndividual ?= 'individual'
+ DefinitionExtensionKeyword* 'def' Definition
+ ownedRelationship += EmptyMultiplicityMember
+
+EmptyMultiplicityMember : OwningMembership =
+ ownedRelatedElement += EmptyMultiplicity
+
+EmptyMultiplicity : Multiplicity =
+ { }
+
+// Clause 8.2.2.9.2 Occurrence Usages
+
+OccurrenceUsagePrefix : OccurrenceUsage =
+ BasicUsagePrefix
+ ( isIndividual ?= 'individual' )?
+ ( portionKind = PortionKind
+ { isPortion = true }
+ )?
+ UsageExtensionKeyword*
+
+OccurrenceUsage =
+ OccurrenceUsagePrefix 'occurrence' Usage
+
+IndividualUsage : OccurrenceUsage =
+ BasicUsagePrefix isIndividual ?= 'individual'
+ UsageExtensionKeyword* Usage
+
+PortionUsage : OccurrenceUsage =
+ BasicUsagePrefix ( isIndividual ?= 'individual' )?
+ portionKind = PortionKind
+ UsageExtensionKeyword* Usage
+ { isPortion = true }
+
+PortionKind =
+ 'snapshot' | 'timeslice'
+
+EventOccurrenceUsage =
+ OccurrenceUsagePrefix 'event'
+ ( ownedRelationship += OwnedReferenceSubsetting
+ FeatureSpecializationPart?
+ | 'occurrence' UsageDeclaration? )
+ UsageCompletion
+
+// Clause 8.2.2.9.3 Occurrence Successions
+
+SourceSuccessionMember : FeatureMembership =
+ 'then' ownedRelatedElement += SourceSuccession
+
+SourceSuccession : SuccessionAsUsage =
+ ownedRelationship += SourceEndMember
+
+SourceEndMember : EndFeatureMembership =
+ ownedRelatedElement += SourceEnd
+
+SourceEnd : ReferenceUsage =
+ ( ownedRelationship += OwnedMultiplicity )?
+
+// Clause 8.2.2.10 Items Textual Notation
+
+ItemDefinition =
+ OccurrenceDefinitionPrefix
+ 'item' 'def' Definition
+
+ItemUsage =
+ OccurrenceUsagePrefix 'item' Usage
+
+// Clause 8.2.2.11 Parts Textual Notation
+
+PartDefinition =
+ OccurrenceDefinitionPrefix 'part' 'def' Definition
+
+PartUsage =
+ OccurrenceUsagePrefix 'part' Usage
+
+// Clause 8.2.2.12 Ports Textual Notation
+
+PortDefinition =
+ DefinitionPrefix 'port' 'def' Definition
+ ownedRelationship += ConjugatedPortDefinitionMember
+ { conjugatedPortDefinition.ownedPortConjugator.
+ originalPortDefinition = this }
+
+// (See Note 1)
+
+ConjugatedPortDefinitionMember : OwningMembership =
+ ownedRelatedElement += ConjugatedPortDefinition
+
+ConjugatedPortDefinition =
+ ownedRelationship += PortConjugation
+
+PortConjugation =
+ {}
+
+PortUsage =
+ OccurrenceUsagePrefix 'port' Usage
+
+ConjugatedPortTyping : ConjugatedPortTyping =
+ '~' originalPortDefinition = ~[QualifiedName]
+
+// (See Note 2)
+
+// Notes:
+// 1. Even though it is not explicitly represented in the text, a PortDefinition is always parsed as containing a nested ConjugatedPortDefinition with a PortDefinition Relationship pointing back to the containing PortDefinition. The abstract syntax for ConjugatedPortDefinition sets its effectiveName to the name of its originalPortDefinition with the symbol ~ prepended to it (see 8.3.12.2). (See also 8.4.8.1.)
+// 2. The notation ~[QualifiedName] indicates that a QualifiedName shall be parsed from the input text, but that it shall be resolved as if it was the qualified name constructed as follows:
+// • Extract the last segment name of the given QualifiedName and prepend the symbol ~ to it.
+// • Append the name so constructed to the end of the entire original QualifiedName.
+// For example, if the ConjugatedPortTyping is ~A::B::C, then the given QualifiedName is A::B::C, and ~[QualifiedName] is resolved as A::B::C::'~C'. Alternatively, a conforming tool may first resolve the given QualifiedName as usual to a PortDefinition and then use the conjugatedPortDefinition of this PortDefinition as the resolution of ~[QualifiedName].
+
+// Clause 8.2.2.13 Connections Textual Notation
+
+// Clause 8.2.2.13.1 Connection Definition and Usage
+
+ConnectionDefinition =
+ OccurrenceDefinitionPrefix 'connection' 'def' Definition
+
+ConnectionUsage =
+ OccurrenceUsagePrefix
+ ( 'connection' UsageDeclaration ValuePart?
+ ( 'connect' ConnectorPart )?
+ | 'connect' ConnectorPart )
+ UsageBody
+
+ConnectorPart : ConnectionUsage =
+ BinaryConnectorPart | NaryConnectorPart
+
+BinaryConnectorPart : ConnectionUsage =
+ ownedRelationship += ConnectorEndMember 'to'
+ ownedRelationship += ConnectorEndMember
+
+NaryConnectorPart : ConnectionUsage =
+ '(' ownedRelationship += ConnectorEndMember ','
+ ownedRelationship += ConnectorEndMember
+ ( ',' ownedRelationship += ConnectorEndMember )* ')'
+
+ConnectorEndMember : EndFeatureMembership =
+ ownedRelatedElement += ConnectorEnd
+
+ConnectorEnd : ReferenceUsage =
+ ( ownedRelationship += OwnedCrossMultiplicityMember )?
+ ( declaredName = NAME REFERENCES )?
+ ownedRelationship += OwnedReferenceSubsetting
+
+OwnedCrossMultiplicityMember : OwningMembership =
+ ownedRelatedElement += OwnedCrossMultiplicity
+
+OwnedCrossMultiplicity : Feature =
+ ownedRelationship += OwnedMultiplicity
+
+// Clause 8.2.2.13.2 Binding Connectors
+
+BindingConnectorAsUsage =
+ UsagePrefix ( 'binding' UsageDeclaration )?
+ 'bind' ownedRelationship += ConnectorEndMember
+ '=' ownedRelationship += ConnectorEndMember
+ UsageBody
+
+// Clause 8.2.2.13.3 Successions
+
+SuccessionAsUsage =
+ UsagePrefix ( 'succession' UsageDeclaration )?
+ 'first' s.ownedRelationship += ConnectorEndMember
+ 'then' s.ownedRelationship += ConnectorEndMember
+ UsageBody
+
+// Clause 8.2.2.14 Interfaces Textual Notation
+
+// Clause 8.2.2.14.1 Interface Definitions
+
+InterfaceDefinition =
+ OccurrenceDefinitionPrefix 'interface' 'def'
+ DefinitionDeclaration InterfaceBody
+
+InterfaceBody : Type =
+ ';' | '{' InterfaceBodyItem* '}'
+
+InterfaceBodyItem : Type =
+ ownedRelationship += DefinitionMember
+ | ownedRelationship += VariantUsageMember
+ | ownedRelationship += InterfaceNonOccurrenceUsageMember
+ | ( ownedRelationship += SourceSuccessionMember )?
+ ownedRelationship += InterfaceOccurrenceUsageMember
+ | ownedRelationship += AliasMember
+ | ownedRelationship += Import
+
+InterfaceNonOccurrenceUsageMember : FeatureMembership =
+ MemberPrefix ownedRelatedElement += InterfaceNonOccurrenceUsageElement
+
+InterfaceNonOccurrenceUsageElement : Usage =
+ ReferenceUsage
+ | AttributeUsage
+ | EnumerationUsage
+ | BindingConnectorAsUsage
+ | SuccessionAsUsage
+
+InterfaceOccurrenceUsageMember : FeatureMembership =
+ MemberPrefix ownedRelatedElement += InterfaceOccurrenceUsageElement
+
+InterfaceOccurrenceUsageElement : Usage =
+ DefaultInterfaceEnd | StructureUsageElement | BehaviorUsageElement
+
+DefaultInterfaceEnd : PortUsage =
+ isEnd ?= 'end' Usage
+
+// Clause 8.2.2.14.2 Interface Usages
+
+InterfaceUsage =
+ OccurrenceUsagePrefix 'interface'
+ InterfaceUsageDeclaration InterfaceBody
+
+InterfaceUsageDeclaration : InterfaceUsage =
+ UsageDeclaration ValuePart?
+ ( 'connect' InterfacePart )?
+ | InterfacePart
+
+InterfacePart : InterfaceUsage =
+ BinaryInterfacePart | NaryInterfacePart
+
+BinaryInterfacePart : InterfaceUsage =
+ ownedRelationship += InterfaceEndMember 'to'
+ ownedRelationship += InterfaceEndMember
+
+NaryInterfacePart : InterfaceUsage =
+ '(' ownedRelationship += InterfaceEndMember ','
+ ownedRelationship += InterfaceEndMember
+ ( ',' ownedRelationship += InterfaceEndMember )* ')'
+
+InterfaceEndMember : EndFeatureMembership =
+ ownedRelatedElement += InterfaceEnd
+
+InterfaceEnd : PortUsage =
+ ( ownedRelationship += OwnedCrossMultiplicityMember )?
+ ( declaredName = NAME REFERENCES )?
+ ownedRelationship += OwnedReferenceSubsetting
+
+// Clause 8.2.2.15 Allocations Textual Notation
+
+AllocationDefinition =
+ OccurrenceDefinitionPrefix 'allocation' 'def' Definition
+
+AllocationUsage =
+ OccurrenceUsagePrefix
+ AllocationUsageDeclaration UsageBody
+
+AllocationUsageDeclaration : AllocationUsage =
+ 'allocation' UsageDeclaration
+ ( 'allocate' ConnectorPart )?
+ | 'allocate' ConnectorPart
+
+// Clause 8.2.2.16 Flows Textual Notation
+
+FlowDefinition =
+ OccurrenceDefinitionPrefix 'flow' 'def' Definition
+
+Message : FlowUsage =
+ OccurrenceUsagePrefix 'message'
+ MessageDeclaration DefinitionBody
+ { isAbstract = true }
+
+MessageDeclaration : FlowUsage =
+ UsageDeclaration ValuePart?
+ ( 'of' ownedRelationship += FlowPayloadFeatureMember )?
+ ( 'from' ownedRelationship += MessageEventMember
+ 'to' ownedRelationship += MessageEventMember
+ )?
+ | ownedRelationship += MessageEventMember 'to'
+ ownedRelationship += MessageEventMember
+
+MessageEventMember : ParameterMembership =
+ ownedRelatedElement += MessageEvent
+
+MessageEvent : EventOccurrenceUsage =
+ ownedRelationship += OwnedReferenceSubsetting
+
+FlowUsage =
+ OccurrenceUsagePrefix 'flow'
+ FlowDeclaration DefinitionBody
+
+SuccessionFlowUsage =
+ OccurrenceUsagePrefix 'succession' 'flow'
+ FlowDeclaration DefinitionBody
+
+FlowDeclaration : FlowUsage =
+ UsageDeclaration ValuePart?
+ ( 'of' ownedRelationship += FlowPayloadFeatureMember )?
+ ( 'from' ownedRelationship += FlowEndMember
+ 'to' ownedRelationship += FlowEndMember )?
+ | ownedRelationship += FlowEndMember 'to'
+ ownedRelationship += FlowEndMember
+
+FlowPayloadFeatureMember : FeatureMembership =
+ ownedRelatedElement += FlowPayloadFeature
+
+FlowPayloadFeature : PayloadFeature =
+ PayloadFeature
+
+PayloadFeature : Feature =
+ Identification? PayloadFeatureSpecializationPart
+ ValuePart?
+ | ownedRelationship += OwnedFeatureTyping
+ ( ownedRelationship += OwnedMultiplicity )?
+ | ownedRelationship += OwnedMultiplicity
+ ownedRelationship += OwnedFeatureTyping
+
+PayloadFeatureSpecializationPart : Feature =
+ ( FeatureSpecialization )+ MultiplicityPart?
+ FeatureSpecialization*
+ | MultiplicityPart FeatureSpecialization+
+
+FlowEndMember : EndFeatureMembership =
+ ownedRelatedElement += FlowEnd
+
+FlowEnd =
+ ( ownedRelationship += FlowEndSubsetting )?
+ ownedRelationship += FlowFeatureMember
+
+FlowEndSubsetting : ReferenceSubsetting =
+ referencedFeature = [QualifiedName]
+ | referencedFeature = FeatureChainPrefix
+ { ownedRelatedElement += referencedFeature }
+
+FeatureChainPrefix : Feature =
+ ( ownedRelationship += OwnedFeatureChaining '.' )+
+ ownedRelationship += OwnedFeatureChaining '.'
+
+FlowFeatureMember : FeatureMembership =
+ ownedRelatedElement += FlowFeature
+
+FlowFeature : ReferenceUsage =
+ ownedRelationship += FlowFeatureRedefinition
+
+// (See Note 1)
+
+FlowFeatureRedefinition : Redefinition =
+ redefinedFeature = [QualifiedName]
+
+// Notes:
+// 1. To ensure that a FlowFeature passes the validateRedefinitionDirectionConformance constraint (see [KerML, 8.3.3.3.8]), its direction must be set to the direction of its redefinedFeature, relative to its owning FlowEnd, that is, the result of the following OCL expression: owningType.directionOf(ownedRedefinition->at(1).redefinedFeature)
+
+// Clause 8.2.2.17 Actions Textual Notation
+
+// Clause 8.2.2.17.1 Action Definitions
+
+ActionDefinition =
+ OccurrenceDefinitionPrefix 'action' 'def'
+ DefinitionDeclaration ActionBody
+
+ActionBody : Type =
+ ';' | '{' ActionBodyItem* '}'
+
+ActionBodyItem : Type =
+ NonBehaviorBodyItem
+ | ownedRelationship += InitialNodeMember
+ ( ownedRelationship += ActionTargetSuccessionMember )*
+ | ( ownedRelationship += SourceSuccessionMember )?
+ ownedRelationship += ActionBehaviorMember
+ ( ownedRelationship += ActionTargetSuccessionMember )*
+ | ownedRelationship += GuardedSuccessionMember
+
+NonBehaviorBodyItem =
+ ownedRelationship += Import
+ | ownedRelationship += AliasMember
+ | ownedRelationship += DefinitionMember
+ | ownedRelationship += VariantUsageMember
+ | ownedRelationship += NonOccurrenceUsageMember
+ | ( ownedRelationship += SourceSuccessionMember )?
+ ownedRelationship += StructureUsageMember
+
+ActionBehaviorMember : FeatureMembership =
+ BehaviorUsageMember | ActionNodeMember
+
+InitialNodeMember : FeatureMembership =
+ MemberPrefix 'first' memberFeature = [QualifiedName]
+ RelationshipBody
+
+ActionNodeMember : FeatureMembership =
+ MemberPrefix ownedRelatedElement += ActionNode
+
+ActionTargetSuccessionMember : FeatureMembership =
+ MemberPrefix ownedRelatedElement += ActionTargetSuccession
+
+GuardedSuccessionMember : FeatureMembership =
+ MemberPrefix ownedRelatedElement += GuardedSuccession
+
+// Clause 8.2.2.17.2 Action Usages
+
+ActionUsage =
+ OccurrenceUsagePrefix 'action'
+ ActionUsageDeclaration ActionBody
+
+ActionUsageDeclaration : ActionUsage =
+ UsageDeclaration ValuePart?
+
+PerformActionUsage =
+ OccurrenceUsagePrefix 'perform'
+ PerformActionUsageDeclaration ActionBody
+
+PerformActionUsageDeclaration : PerformActionUsage =
+ ( ownedRelationship += OwnedReferenceSubsetting
+ FeatureSpecializationPart?
+ | 'action' UsageDeclaration )
+ ValuePart?
+
+ActionNode : ActionUsage =
+ ControlNode
+ | SendNode | AcceptNode
+ | AssignmentNode
+ | TerminateNode
+ | IfNode | WhileLoopNode | ForLoopNode
+
+ActionNodeUsageDeclaration : ActionUsage =
+ 'action' UsageDeclaration?
+
+ActionNodePrefix : ActionUsage =
+ OccurrenceUsagePrefix ActionNodeUsageDeclaration?
+
+// Clause 8.2.2.17.3 Control Nodes
+
+ControlNode =
+ MergeNode | DecisionNode | JoinNode| ForkNode
+
+ControlNodePrefix : OccurrenceUsage =
+ RefPrefix
+ ( isIndividual ?= 'individual' )?
+ ( portionKind = PortionKind
+ { isPortion = true }
+ )?
+ UsageExtensionKeyword*
+
+MergeNode =
+ ControlNodePrefix
+ isComposite ?= 'merge' UsageDeclaration
+ ActionBody
+
+DecisionNode =
+ ControlNodePrefix
+ isComposite ?= 'decide' UsageDeclaration
+ ActionBody
+
+JoinNode =
+ ControlNodePrefix
+ isComposite ?= 'join' UsageDeclaration
+ ActionBody
+
+ForkNode =
+ ControlNodePrefix
+ isComposite ?= 'fork' UsageDeclaration
+ ActionBody
+
+// Clause 8.2.2.17.4 Send and Accept Action Usages
+
+AcceptNode : AcceptActionUsage =
+ OccurrenceUsagePrefix
+ AcceptNodeDeclaration ActionBody
+
+AcceptNodeDeclaration : AcceptActionUsage =
+ ActionNodeUsageDeclaration?
+ 'accept' AcceptParameterPart
+
+AcceptParameterPart : AcceptActionUsage =
+ ownedRelationship += PayloadParameterMember
+ ( 'via' ownedRelationship += NodeParameterMember )?
+
+PayloadParameterMember : ParameterMembership =
+ ownedRelatedElement += PayloadParameter
+
+PayloadParameter : ReferenceUsage =
+ PayloadFeature
+ | Identification PayloadFeatureSpecializationPart?
+ TriggerValuePart
+
+TriggerValuePart : Feature =
+ ownedRelationship += TriggerFeatureValue
+
+TriggerFeatureValue : FeatureValue =
+ ownedRelatedElement += TriggerExpression
+
+TriggerExpression : TriggerInvocationExpression =
+ kind = ( 'at' | 'after' )
+ ownedRelationship += ArgumentMember
+ | kind = 'when'
+ ownedRelationship += ArgumentExpressionMember
+
+ArgumentMember : ParameterMembership =
+ ownedMemberParameter = Argument
+
+Argument : Feature =
+ ownedRelationship += ArgumentValue
+
+ArgumentValue : FeatureValue =
+ value = OwnedExpression
+
+ArgumentExpressionMember : ParameterMembership =
+ ownedRelatedElement += ArgumentExpression
+
+ArgumentExpression : Feature =
+ ownedRelationship += ArgumentExpressionValue
+
+ArgumentExpressionValue : FeatureValue =
+ ownedRelatedElement += OwnedExpressionReference
+
+SendNode : SendActionUsage =
+ OccurrenceUsagePrefix ActionUsageDeclaration? 'send'
+ ( ownedRelationship += NodeParameterMember SenderReceiverPart?
+ | ownedRelationship += EmptyParameterMember SenderReceiverPart )?
+ ActionBody
+
+SendNodeDeclaration : SendActionUsage =
+ ActionNodeUsageDeclaration? 'send'
+ ownedRelationship += NodeParameterMember SenderReceiverPart?
+
+SenderReceiverPart : SendActionUsage =
+ 'via' ownedRelationship += NodeParameterMember
+ ( 'to' ownedRelationship += NodeParameterMember )?
+ | ownedRelationship += EmptyParameterMember
+ 'to' ownedRelationship += NodeParameterMember
+
+NodeParameterMember : ParameterMembership =
+ ownedRelatedElement += NodeParameter
+
+NodeParameter : ReferenceUsage =
+ ownedRelationship += FeatureBinding
+
+FeatureBinding : FeatureValue =
+ ownedRelatedElement += OwnedExpression
+
+EmptyParameterMember : ParameterMembership =
+ ownedRelatedElement += EmptyUsage
+
+EmptyUsage : ReferenceUsage =
+ {}
+
+// Notes:
+// 1. The productions for ArgumentMember, Argument, ArgumentValue, ArgumentExpressionMember, ArgumentExpression and ArgumentExpressionValue are the same as given in [KerML, 8.2.5.8.1].
+
+// Clause 8.2.2.17.5 Assignment Action Usages
+
+AssignmentNode : AssignmentActionUsage =
+ OccurrenceUsagePrefix
+ AssignmentNodeDeclaration ActionBody
+
+AssignmentNodeDeclaration: ActionUsage =
+ ( ActionNodeUsageDeclaration )? 'assign'
+ ownedRelationship += AssignmentTargetMember
+ ownedRelationship += FeatureChainMember ':='
+ ownedRelationship += NodeParameterMember
+
+AssignmentTargetMember : ParameterMembership =
+ ownedRelatedElement += AssignmentTargetParameter
+
+AssignmentTargetParameter : ReferenceUsage =
+ ( ownedRelationship += AssignmentTargetBinding '.' )?
+
+AssignmentTargetBinding : FeatureValue =
+ ownedRelatedElement += NonFeatureChainPrimaryExpression
+
+FeatureChainMember : Membership =
+ memberElement = [QualifiedName]
+ | OwnedFeatureChainMember
+
+OwnedFeatureChainMember : OwningMembership =
+ ownedRelatedElement += OwnedFeatureChain
+
+// Clause 8.2.2.17.6 Terminate Action Usages
+
+TerminateNode : TerminateActionUsage =
+ OccurrenceUsagePrefix ActionNodeUsageDeclaration?
+ 'terminate' ( ownedRelationship += NodeParameterMember )?
+ ActionBody
+
+// Clause 8.2.2.17.7 Structured Control Action Usages
+
+IfNode : IfActionUsage =
+ ActionNodePrefix
+ 'if' ownedRelationship += ExpressionParameterMember
+ ownedRelationship += ActionBodyParameterMember
+ ( 'else' ownedRelationship +=
+ ( ActionBodyParameterMember | IfNodeParameterMember ) )?
+
+ExpressionParameterMember : ParameterMembership =
+ ownedRelatedElement += OwnedExpression
+
+ActionBodyParameterMember : ParameterMembership =
+ ownedRelatedElement += ActionBodyParameter
+
+ActionBodyParameter : ActionUsage =
+ ( 'action' UsageDeclaration? )?
+ '{' ActionBodyItem* '}'
+
+IfNodeParameterMember : ParameterMembership =
+ ownedRelatedElement += IfNode
+
+WhileLoopNode : WhileLoopActionUsage =
+ ActionNodePrefix
+ ( 'while' ownedRelationship += ExpressionParameterMember
+ | 'loop' ownedRelationship += EmptyParameterMember
+ )
+ ownedRelationship += ActionBodyParameterMember
+ ( 'until' ownedRelationship += ExpressionParameterMember ';' )?
+
+ForLoopNode : ForLoopActionUsage =
+ ActionNodePrefix
+ 'for' ownedRelationship += ForVariableDeclarationMember
+ 'in' ownedRelationship += NodeParameterMember
+ ownedRelationship += ActionBodyParameterMember
+
+ForVariableDeclarationMember : FeatureMembership =
+ ownedRelatedElement += UsageDeclaration
+
+ForVariableDeclaration : ReferenceUsage =
+ UsageDeclaration
+
+// Clause 8.2.2.17.8 Action Successions
+
+ActionTargetSuccession : Usage =
+ ( TargetSuccession | GuardedTargetSuccession | DefaultTargetSuccession )
+ UsageBody
+
+TargetSuccession : SuccessionAsUsage =
+ ownedRelationship += SourceEndMember
+ 'then' ownedRelationship += ConnectorEndMember
+
+GuardedTargetSuccession : TransitionUsage =
+ ownedRelationship += GuardExpressionMember
+ 'then' ownedRelationship += TransitionSuccessionMember
+
+DefaultTargetSuccession : TransitionUsage =
+ 'else' ownedRelationship += TransitionSuccessionMember
+
+GuardedSuccession : TransitionUsage =
+ ( 'succession' UsageDeclaration )?
+ 'first' ownedRelationship += FeatureChainMember
+ ownedRelationship += GuardExpressionMember
+ 'then' ownedRelationship += TransitionSuccessionMember
+ UsageBody
+
+// Clause 8.2.2.18 States Textual Notation
+
+// Clause 8.2.2.18.1 State Definitions
+
+StateDefinition =
+ OccurrenceDefinitionPrefix 'state' 'def'
+ DefinitionDeclaration StateDefBody
+
+StateDefBody : StateDefinition =
+ ';'
+ | ( isParallel ?= 'parallel' )?
+ '{' StateBodyItem* '}'
+
+StateBodyItem : Type =
+ NonBehaviorBodyItem
+ | ( ownedRelationship += SourceSuccessionMember )?
+ ownedRelationship += BehaviorUsageMember
+ ( ownedRelationship += TargetTransitionUsageMember )*
+ | ownedRelationship += TransitionUsageMember
+ | ownedRelationship += EntryActionMember
+ ( ownedRelationship += EntryTransitionMember )*
+ | ownedRelationship += DoActionMember
+ | ownedRelationship += ExitActionMember
+
+EntryActionMember : StateSubactionMembership =
+ MemberPrefix kind = 'entry'
+ ownedRelatedElement += StateActionUsage
+
+DoActionMember : StateSubactionMembership =
+ MemberPrefix kind = 'do'
+ ownedRelatedElement += StateActionUsage
+
+ExitActionMember : StateSubactionMembership =
+ MemberPrefix kind = 'exit'
+ ownedRelatedElement += StateActionUsage
+
+EntryTransitionMember : FeatureMembership =
+ MemberPrefix
+ ( ownedRelatedElement += GuardedTargetSuccession
+ | 'then' ownedRelatedElement += TargetSuccession
+ ) ';'
+
+StateActionUsage : ActionUsage =
+ EmptyActionUsage ';'
+ | StatePerformActionUsage
+ | StateAcceptActionUsage
+ | StateSendActionUsage
+ | StateAssignmentActionUsage
+
+EmptyActionUsage : ActionUsage =
+ {}
+
+StatePerformActionUsage : PerformActionUsage =
+ PerformActionUsageDeclaration ActionBody
+
+StateAcceptActionUsage : AcceptActionUsage =
+ AcceptNodeDeclaration ActionBody
+
+StateSendActionUsage : SendActionUsage =
+ SendNodeDeclaration ActionBody
+
+StateAssignmentActionUsage : AssignmentActionUsage =
+ AssignmentNodeDeclaration ActionBody
+
+TransitionUsageMember : FeatureMembership =
+ MemberPrefix ownedRelatedElement += TransitionUsage
+
+TargetTransitionUsageMember : FeatureMembership =
+ MemberPrefix ownedRelatedElement += TargetTransitionUsage
+
+// Clause 8.2.2.18.2 State Usages
+
+StateUsage =
+ OccurrenceUsagePrefix 'state'
+ ActionUsageDeclaration StateUsageBody
+
+StateUsageBody : StateUsage =
+ ';'
+ | ( isParallel ?= 'parallel' )?
+ '{' StateBodyItem* '}'
+
+ExhibitStateUsage =
+ OccurrenceUsagePrefix 'exhibit'
+ ( ownedRelationship += OwnedReferenceSubsetting
+ FeatureSpecializationPart?
+ | 'state' UsageDeclaration )
+ ValuePart? StateUsageBody
+
+// Clause 8.2.2.18.3 Transition Usages
+
+TransitionUsage =
+ 'transition' ( UsageDeclaration 'first' )?
+ ownedRelationship += FeatureChainMember
+ ownedRelationship += EmptyParameterMember
+ ( ownedRelationship += EmptyParameterMember
+ ownedRelationship += TriggerActionMember )?
+ ( ownedRelationship += GuardExpressionMember )?
+ ( ownedRelationship += EffectBehaviorMember )?
+ 'then' ownedRelationship += TransitionSuccessionMember
+ ActionBody
+
+TargetTransitionUsage : TransitionUsage =
+ ownedRelationship += EmptyParameterMember
+ ( 'transition'
+ ( ownedRelationship += EmptyParameterMember
+ ownedRelationship += TriggerActionMember )?
+ ( ownedRelationship += GuardExpressionMember )?
+ ( ownedRelationship += EffectBehaviorMember )?
+ | ownedRelationship += EmptyParameterMember
+ ownedRelationship += TriggerActionMember
+ ( ownedRelationship += GuardExpressionMember )?
+ ( ownedRelationship += EffectBehaviorMember )?
+ | ownedRelationship += GuardExpressionMember
+ ( ownedRelationship += EffectBehaviorMember )?
+ )?
+ 'then' ownedRelationship += TransitionSuccessionMember
+ ActionBody
+
+TriggerActionMember : TransitionFeatureMembership =
+ 'accept' { kind = 'trigger' } ownedRelatedElement += TriggerAction
+
+TriggerAction : AcceptActionUsage =
+ AcceptParameterPart
+
+GuardExpressionMember : TransitionFeatureMembership =
+ 'if' { kind = 'guard' } ownedRelatedElement += OwnedExpression
+
+EffectBehaviorMember : TransitionFeatureMembership =
+ 'do' { kind = 'effect' } ownedRelatedElement += EffectBehaviorUsage
+
+EffectBehaviorUsage : ActionUsage =
+ EmptyActionUsage
+ | TransitionPerformActionUsage
+ | TransitionAcceptActionUsage
+ | TransitionSendActionUsage
+ | TransitionAssignmentActionUsage
+
+TransitionPerformActionUsage : PerformActionUsage =
+ PerformActionUsageDeclaration ( '{' ActionBodyItem* '}' )?
+
+TransitionAcceptActionUsage : AcceptActionUsage =
+ AcceptNodeDeclaration ( '{' ActionBodyItem* '}' )?
+
+TransitionSendActionUsage : SendActionUsage =
+ SendNodeDeclaration ( '{' ActionBodyItem* '}' )?
+
+TransitionAssignmentActionUsage : AssignmentActionUsage =
+ AssignmentNodeDeclaration ( '{' ActionBodyItem* '}' )?
+
+TransitionSuccessionMember : OwningMembership =
+ ownedRelatedElement += TransitionSuccession
+
+TransitionSuccession : Succession =
+ ownedRelationship += EmptyEndMember
+ ownedRelationship += ConnectorEndMember
+
+EmptyEndMember : EndFeatureMembership =
+ ownedRelatedElement += EmptyFeature
+
+EmptyFeature : ReferenceUsage =
+ {}
+
+// Clause 8.2.2.19 Calculations Textual Notation
+
+CalculationDefinition =
+ OccurrenceDefinitionPrefix 'calc' 'def'
+ DefinitionDeclaration CalculationBody
+
+CalculationUsage : CalculationUsage =
+ OccurrenceUsagePrefix 'calc'
+ ActionUsageDeclaration CalculationBody
+
+CalculationBody : Type =
+ ';' | '{' CalculationBodyPart '}'
+
+CalculationBodyPart : Type =
+ CalculationBodyItem*
+ ( ownedRelationship += ResultExpressionMember )?
+
+CalculationBodyItem : Type =
+ ActionBodyItem
+ | ownedRelationship += ReturnParameterMember
+
+ReturnParameterMember : ReturnParameterMembership =
+ MemberPrefix? 'return' ownedRelatedElement += UsageElement
+
+ResultExpressionMember : ResultExpressionMembership =
+ MemberPrefix? ownedRelatedElement += OwnedExpression
+
+// Clause 8.2.2.20 Constraints Textual Notation
+
+ConstraintDefinition =
+ OccurrenceDefinitionPrefix 'constraint' 'def'
+ DefinitionDeclaration CalculationBody
+
+ConstraintUsage =
+ OccurrenceUsagePrefix 'constraint'
+ ConstraintUsageDeclaration CalculationBody
+
+AssertConstraintUsage =
+ OccurrenceUsagePrefix 'assert' ( isNegated ?= 'not' )?
+ ( ownedRelationship += OwnedReferenceSubsetting
+ FeatureSpecializationPart?
+ | 'constraint' ConstraintUsageDeclaration )
+ CalculationBody
+
+ConstraintUsageDeclaration : ConstraintUsage =
+ UsageDeclaration ValuePart?
+
+// Clause 8.2.2.21 Requirements Textual Notation
+
+// Clause 8.2.2.21.1 Requirement Definitions
+
+RequirementDefinition =
+ OccurrenceDefinitionPrefix 'requirement' 'def'
+ DefinitionDeclaration RequirementBody
+
+RequirementBody : Type =
+ ';' | '{' RequirementBodyItem* '}'
+
+RequirementBodyItem : Type =
+ DefinitionBodyItem
+ | ownedRelationship += SubjectMember
+ | ownedRelationship += RequirementConstraintMember
+ | ownedRelationship += FramedConcernMember
+ | ownedRelationship += RequirementVerificationMember
+ | ownedRelationship += ActorMember
+ | ownedRelationship += StakeholderMember
+
+SubjectMember : SubjectMembership =
+ MemberPrefix ownedRelatedElement += SubjectUsage
+
+SubjectUsage : ReferenceUsage =
+ 'subject' UsageExtensionKeyword* Usage
+
+RequirementConstraintMember : RequirementConstraintMembership =
+ MemberPrefix? RequirementKind
+ ownedRelatedElement += RequirementConstraintUsage
+
+RequirementKind : RequirementConstraintMembership =
+ 'assume' { kind = 'assumption' }
+ | 'require' { kind = 'requirement' }
+
+RequirementConstraintUsage : ConstraintUsage =
+ ownedRelationship += OwnedReferenceSubsetting
+ FeatureSpecializationPart? RequirementBody
+ | ( UsageExtensionKeyword* 'constraint'
+ | UsageExtensionKeyword+ )
+ ConstraintUsageDeclaration CalculationBody
+
+FramedConcernMember : FramedConcernMembership =
+ MemberPrefix? 'frame'
+ ownedRelatedElement += FramedConcernUsage
+
+FramedConcernUsage : ConcernUsage =
+ ownedRelationship += OwnedReferenceSubsetting
+ FeatureSpecializationPart? CalculationBody
+ | ( UsageExtensionKeyword* 'concern'
+ | UsageExtensionKeyword+ )
+ CalculationUsageDeclaration CalculationBody
+
+ActorMember : ActorMembership =
+ MemberPrefix ownedRelatedElement += ActorUsage
+
+ActorUsage : PartUsage =
+ 'actor' UsageExtensionKeyword* Usage
+
+StakeholderMember : StakeholderMembership =
+ MemberPrefix ownedRelatedElement += StakeholderUsage
+
+StakeholderUsage : PartUsage =
+ 'stakeholder' UsageExtensionKeyword* Usage
+
+// Clause 8.2.2.21.2 Requirement Usages
+
+RequirementUsage =
+ OccurrenceUsagePrefix 'requirement'
+ ConstraintUsageDeclaration RequirementBody
+
+SatisfyRequirementUsage =
+ OccurrenceUsagePrefix 'assert' ( isNegated ?= 'not' ) 'satisfy'
+ ( ownedRelationship += OwnedReferenceSubsetting
+ FeatureSpecializationPart?
+ | 'requirement' UsageDeclaration )
+ ValuePart?
+ ( 'by' ownedRelationship += SatisfactionSubjectMember )?
+ RequirementBody
+
+SatisfactionSubjectMember : SubjectMembership =
+ ownedRelatedElement += SatisfactionParameter
+
+SatisfactionParameter : ReferenceUsage =
+ ownedRelationship += SatisfactionFeatureValue
+
+SatisfactionFeatureValue : FeatureValue =
+ ownedRelatedElement += SatisfactionReferenceExpression
+
+SatisfactionReferenceExpression : FeatureReferenceExpression =
+ ownedRelationship += FeatureChainMember
+
+// Clause 8.2.2.21.3 Concerns
+
+ConcernDefinition =
+ OccurrenceDefinitionPrefix 'concern' 'def'
+ DefinitionDeclaration RequirementBody
+
+ConcernUsage =
+ OccurrenceUsagePrefix 'concern'
+ ConstraintUsageDeclaration RequirementBody
+
+// Clause 8.2.2.22 Cases Textual Notation
+
+CaseDefinition =
+ OccurrenceDefinitionPrefix 'case' 'def'
+ DefinitionDeclaration CaseBody
+
+CaseUsage =
+ OccurrenceUsagePrefix 'case'
+ ConstraintUsageDeclaration CaseBody
+
+CaseBody : Type =
+ ';'
+ | '{' CaseBodyItem*
+ ( ownedRelationship += ResultExpressionMember )?
+ '}'
+
+CaseBodyItem : Type =
+ ActionBodyItem
+ | ownedRelationship += SubjectMember
+ | ownedRelationship += ActorMember
+ | ownedRelationship += ObjectiveMember
+
+ObjectiveMember : ObjectiveMembership =
+ MemberPrefix 'objective'
+ ownedRelatedElement += ObjectiveRequirementUsage
+
+ObjectiveRequirementUsage : RequirementUsage =
+ UsageExtensionKeyword* ConstraintUsageDeclaration
+ RequirementBody
+
+// Clause 8.2.2.23 Analysis Cases Textual Notation
+
+AnalysisCaseDefinition =
+ OccurrenceDefinitionPrefix 'analysis' 'def'
+ DefinitionDeclaration CaseBody
+
+AnalysisCaseUsage =
+ OccurrenceUsagePrefix 'analysis'
+ ConstraintUsageDeclaration CaseBody
+
+// Clause 8.2.2.24 Verification Cases Textual Notation
+
+VerificationCaseDefinition =
+ OccurrenceDefinitionPrefix 'verification' 'def'
+ DefinitionDeclaration CaseBody
+
+VerificationCaseUsage =
+ OccurrenceUsagePrefix 'verification'
+ ConstraintUsageDeclaration CaseBody
+
+RequirementVerificationMember : RequirementVerificationMembership =
+ MemberPrefix 'verify' { kind = 'requirement' }
+ ownedRelatedElement += RequirementVerificationUsage
+
+RequirementVerificationUsage : RequirementUsage =
+ ownedRelationship += OwnedReferenceSubsetting
+ FeatureSpecialization* RequirementBody
+ | ( UsageExtensionKeyword* 'requirement'
+ | UsageExtensionKeyword+ )
+ ConstraintUsageDeclaration RequirementBody
+
+// Clause 8.2.2.25 Use Cases Textual Notation
+
+UseCaseDefinition =
+ OccurrenceDefinitionPrefix 'use' 'case' 'def'
+ DefinitionDeclaration CaseBody
+
+UseCaseUsage =
+ OccurrenceUsagePrefix 'use' 'case'
+ ConstraintUsageDeclaration CaseBody
+
+IncludeUseCaseUsage =
+ OccurrenceUsagePrefix 'include'
+ ( ownedRelationship += OwnedReferenceSubsetting
+ FeatureSpecializationPart?
+ | 'use' 'case' UsageDeclaration )
+ ValuePart?
+ CaseBody
+
+// Clause 8.2.2.26 Views and Viewpoints Textual Notation
+
+// Clause 8.2.2.26.1 View Definitions
+
+ViewDefinition =
+ OccurrenceDefinitionPrefix 'view' 'def'
+ DefinitionDeclaration ViewDefinitionBody
+
+ViewDefinitionBody : ViewDefinition =
+ ';' | '{' ViewDefinitionBodyItem* '}'
+
+ViewDefinitionBodyItem : ViewDefinition =
+ DefinitionBodyItem
+ | ownedRelationship += ElementFilterMember
+ | ownedRelationship += ViewRenderingMember
+
+ViewRenderingMember : ViewRenderingMembership =
+ MemberPrefix 'render'
+ ownedRelatedElement += ViewRenderingUsage
+
+ViewRenderingUsage : RenderingUsage =
+ ownedRelationship += OwnedReferenceSubsetting
+ FeatureSpecializationPart?
+ UsageBody
+ | ( UsageExtensionKeyword* 'rendering'
+ | UsageExtensionKeyword+ )
+ Usage
+
+// Clause 8.2.2.26.2 View Usages
+
+ViewUsage =
+ OccurrenceUsagePrefix 'view'
+ UsageDeclaration? ValuePart?
+ ViewBody
+
+ViewBody : ViewUsage =
+ ';' | '{' ViewBodyItem* '}'
+
+ViewBodyItem : ViewUsage =
+ DefinitionBodyItem
+ | ownedRelationship += ElementFilterMember
+ | ownedRelationship += ViewRenderingMember
+ | ownedRelationship += Expose
+
+Expose =
+ 'expose' ( MembershipExpose | NamespaceExpose )
+ RelationshipBody
+
+MembershipExpose =
+ MembershipImport
+
+NamespaceExpose =
+ NamespaceImport
+
+// Clause 8.2.2.26.3 Viewpoints
+
+ViewpointDefinition =
+ OccurrenceDefinitionPrefix 'viewpoint' 'def'
+ DefinitionDeclaration RequirementBody
+
+ViewpointUsage =
+ OccurrenceUsagePrefix 'viewpoint'
+ ConstraintUsageDeclaration RequirementBody
+
+// Clause 8.2.2.26.4 Renderings
+
+RenderingDefinition =
+ OccurrenceDefinitionPrefix 'rendering' 'def'
+ Definition
+
+RenderingUsage =
+ OccurrenceUsagePrefix 'rendering'
+ Usage
+
+// Clause 8.2.2.27 Metadata Textual Notation
+
+MetadataDefinition =
+ ( isAbstract ?= 'abstract')? DefinitionExtensionKeyword*
+ 'metadata' 'def' Definition
+
+PrefixMetadataAnnotation : Annotation =
+ '#' annotatingElement = PrefixMetadataUsage
+ { ownedRelatedElement += annotatingElement }
+
+PrefixMetadataMember : OwningMembership =
+ '#' ownedRelatedElement = PrefixMetadataUsage
+
+PrefixMetadataUsage : MetadataUsage =
+ ownedRelationship += OwnedFeatureTyping
+
+MetadataUsage =
+ UsageExtensionKeyword* ( '@' | 'metadata' )
+ MetadataUsageDeclaration
+ ( 'about' ownedRelationship += Annotation
+ ( ',' ownedRelationship += Annotation )*
+ )?
+ MetadataBody
+
+MetadataUsageDeclaration : MetadataUsage =
+ ( Identification ( ':' | 'typed' 'by' ) )?
+ ownedRelationship += OwnedFeatureTyping
+
+MetadataBody : Type =
+ ';' |
+ '{' ( ownedRelationship += DefinitionMember
+ | ownedRelationship += MetadataBodyUsageMember
+ | ownedRelationship += AliasMember
+ | ownedRelationship += Import
+ )*
+ '}'
+
+MetadataBodyUsageMember : FeatureMembership =
+ ownedMemberFeature = MetadataBodyUsage
+
+MetadataBodyUsage : ReferenceUsage =
+ 'ref'? ( ':>>' | 'redefines' )? ownedRelationship += OwnedRedefinition
+ FeatureSpecializationPart? ValuePart?
+ MetadataBody
+
+ExtendedDefinition : Definition =
+ BasicDefinitionPrefix? DefinitionExtensionKeyword+
+ 'def' Definition
+
+ExtendedUsage : Usage =
+ UnextendedUsagePrefix UsageExtensionKeyword+
+ Usage
+
+// End of BNF
+
+
diff --git a/Resources/kebnf.g4 b/Resources/kebnf.g4
new file mode 100644
index 00000000..d059914a
--- /dev/null
+++ b/Resources/kebnf.g4
@@ -0,0 +1,104 @@
+// Grammar
+
+grammar kebnf;
+
+specification : (NL)* rule_definition+ EOF ;
+
+rule_definition
+ : name=UPPER_ID (params=parameter_list)? (COLON target_ast=UPPER_ID)? ASSIGN rule_body=alternatives SEMICOLON? NL+
+ ;
+
+parameter_list
+ : LPAREN param_name=ID COLON param_type=ID RPAREN
+ ;
+
+alternatives
+ : alternative (PIPE alternative)*
+ ;
+
+alternative
+ : element*
+ ;
+
+element
+ : assignment
+ | non_parsing_assignment
+ | non_parsing_empty
+ | cross_reference
+ | group
+ | terminal
+ | non_terminal
+ | value_literal
+ ;
+
+assignment
+ : property=dotted_id op=(ASSIGN | ADD_ASSIGN | BOOL_ASSIGN) (prefix=TILDE)?content=element_core (suffix=suffix_op)?
+ ;
+
+non_parsing_assignment
+ : LBRACE property=dotted_id op=(ASSIGN | ADD_ASSIGN) val=value_literal RBRACE
+ ;
+
+non_parsing_empty
+ : LBRACE RBRACE
+ ;
+
+cross_reference
+ : TILDE? LBRACK ref=ID RBRACK
+ ;
+
+group
+ : LPAREN alternatives RPAREN (suffix=suffix_op)?
+ ;
+
+terminal
+ : val=SINGLE_QUOTED_STRING (suffix=suffix_op)?
+ ;
+
+non_terminal
+ : name=UPPER_ID (suffix=suffix_op)?
+ ;
+
+element_core
+ : cross_reference
+ | group
+ | terminal
+ | non_terminal
+ | value_literal
+ ;
+
+dotted_id
+ : ID (DOT ID)*
+ ;
+
+suffix_op : '*' | '+' | '?' ;
+
+value_literal : ID | INT | STRING | '[QualifiedName]' | SINGLE_QUOTED_STRING;
+
+// Lexer
+ASSIGN : '::=' | '=' ;
+ADD_ASSIGN : '+=' ;
+BOOL_ASSIGN : '?=' ;
+PIPE : '|' ;
+COLON : ':' ;
+SEMICOLON : ';' ;
+COMMA : ',' ;
+LPAREN : '(' ;
+RPAREN : ')' ;
+LBRACK : '[' ;
+RBRACK : ']' ;
+LBRACE : '{' ;
+RBRACE : '}' ;
+DOT : '.' ;
+TILDE : '~' ;
+
+UPPER_ID : [A-Z] [a-zA-Z0-9_]* ;
+ID : [a-zA-Z_][a-zA-Z0-9_]* ;
+SINGLE_QUOTED_STRING : '\'' (~['\\] | '\\' .)* '\'' ;
+INT : [0-9]+ ;
+STRING : '\'' ( ~['\\] | '\\' . )* '\'' ;
+
+COMMENT : '//' ~[\r\n]* -> skip ;
+WS : [ \t]+ -> skip ;
+CONTINUATION : '\r'? '\n' [ \t]+ -> skip ;
+NL : '\r'? '\n' ;
\ No newline at end of file
diff --git a/SysML2.NET.CodeGenerator.Tests/Generators/UmlHandleBarsGenerators/UmlCoreLexicalRulesGeneratorTestFixture.cs b/SysML2.NET.CodeGenerator.Tests/Generators/UmlHandleBarsGenerators/UmlCoreLexicalRulesGeneratorTestFixture.cs
new file mode 100644
index 00000000..00b39eab
--- /dev/null
+++ b/SysML2.NET.CodeGenerator.Tests/Generators/UmlHandleBarsGenerators/UmlCoreLexicalRulesGeneratorTestFixture.cs
@@ -0,0 +1,63 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2026 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.CodeGenerator.Tests.Generators.UmlHandleBarsGenerators
+{
+ using System.IO;
+ using System.Threading.Tasks;
+
+ using NUnit.Framework;
+
+ using SysML2.NET.CodeGenerator.Generators.UmlHandleBarsGenerators;
+ using SysML2.NET.CodeGenerator.Grammar;
+ using SysML2.NET.CodeGenerator.Grammar.Model;
+
+ [TestFixture]
+ public class UmlCoreLexicalRulesGeneratorTestFixture
+ {
+ private DirectoryInfo outputDirectoryInfo;
+ private UmlCoreLexicalRulesGenerator generator;
+ private TextualNotationSpecification textualNotationSpecification;
+
+ [OneTimeSetUp]
+ public void OneTimeSetup()
+ {
+ var directoryInfo = new DirectoryInfo(TestContext.CurrentContext.TestDirectory);
+
+ var path = Path.Combine("UML", "_SysML2.NET.Core.UmlCoreLexicalRulesGenerator");
+
+ this.outputDirectoryInfo = directoryInfo.CreateSubdirectory(path);
+ this.generator = new UmlCoreLexicalRulesGenerator();
+
+ var textualRulesFolder = Path.Combine(TestContext.CurrentContext.TestDirectory, "datamodel");
+
+ // The lexical support classes (Keywords, SymbolicKeywordKind, SymbolicKeywordKindExtensions)
+ // are built from the SysML grammar only — the KerML grammar is intentionally excluded so
+ // the emitted set of tokens matches the SysML v2 specification surface.
+ this.textualNotationSpecification = GrammarLoader.LoadTextualNotationSpecification(Path.Combine(textualRulesFolder, "SysML-textual-bnf.kebnf"));
+ }
+
+ [Test]
+ public async Task VerifyCanGenerateLexicalRules()
+ {
+ await Assert.ThatAsync(() => this.generator.GenerateAsync(GeneratorSetupFixture.XmiReaderResult, this.textualNotationSpecification, this.outputDirectoryInfo), Throws.Nothing);
+ }
+ }
+}
diff --git a/SysML2.NET.CodeGenerator.Tests/Generators/UmlHandleBarsGenerators/UmlCoreTextualNotationBuilderGeneratorTestFixture.cs b/SysML2.NET.CodeGenerator.Tests/Generators/UmlHandleBarsGenerators/UmlCoreTextualNotationBuilderGeneratorTestFixture.cs
new file mode 100644
index 00000000..373705c5
--- /dev/null
+++ b/SysML2.NET.CodeGenerator.Tests/Generators/UmlHandleBarsGenerators/UmlCoreTextualNotationBuilderGeneratorTestFixture.cs
@@ -0,0 +1,71 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2026 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.CodeGenerator.Tests.Generators.UmlHandleBarsGenerators
+{
+ using System.IO;
+ using System.Linq;
+ using System.Threading.Tasks;
+
+ using NUnit.Framework;
+
+ using SysML2.NET.CodeGenerator.Generators.UmlHandleBarsGenerators;
+ using SysML2.NET.CodeGenerator.Grammar;
+ using SysML2.NET.CodeGenerator.Grammar.Model;
+
+ [TestFixture]
+ public class UmlCoreTextualNotationBuilderGeneratorTestFixture
+ {
+ private DirectoryInfo umlPocoDirectoryInfo;
+ private UmlCoreTextualNotationBuilderGenerator umlCoreTextualNotationBuilderGenerator;
+ private TextualNotationSpecification textualNotationSpecification;
+
+ [OneTimeSetUp]
+ public void OneTimeSetup()
+ {
+ var directoryInfo = new DirectoryInfo(TestContext.CurrentContext.TestDirectory);
+
+ var path = Path.Combine("UML", "_SysML2.NET.Core.UmlCoreTextualNotationBuilderGenerator");
+
+ this.umlPocoDirectoryInfo = directoryInfo.CreateSubdirectory(path);
+ this.umlCoreTextualNotationBuilderGenerator = new UmlCoreTextualNotationBuilderGenerator();
+
+ var textualRulesFolder = Path.Combine(TestContext.CurrentContext.TestDirectory, "datamodel");
+ var kermlRules = GrammarLoader.LoadTextualNotationSpecification(Path.Combine(textualRulesFolder, "KerML-textual-bnf.kebnf"));
+ var sysmlRules = GrammarLoader.LoadTextualNotationSpecification(Path.Combine(textualRulesFolder, "SysML-textual-bnf.kebnf"));
+
+ var combinesRules = new TextualNotationSpecification();
+ combinesRules.Rules.AddRange(sysmlRules.Rules);
+
+ foreach (var rule in kermlRules.Rules.Where(rule => combinesRules.Rules.All(r => r.RuleName != rule.RuleName)))
+ {
+ combinesRules.Rules.Add(rule);
+ }
+
+ this.textualNotationSpecification = combinesRules;
+ }
+
+ [Test]
+ public async Task VerifyCanGenerateTextualNotation()
+ {
+ await Assert.ThatAsync(() => this.umlCoreTextualNotationBuilderGenerator.GenerateAsync(GeneratorSetupFixture.XmiReaderResult, this.textualNotationSpecification, this.umlPocoDirectoryInfo), Throws.Nothing);
+ }
+ }
+}
diff --git a/SysML2.NET.CodeGenerator.Tests/Grammar/TextualNotationSpecificationVisitorTestFixture.cs b/SysML2.NET.CodeGenerator.Tests/Grammar/TextualNotationSpecificationVisitorTestFixture.cs
new file mode 100644
index 00000000..7990d4cc
--- /dev/null
+++ b/SysML2.NET.CodeGenerator.Tests/Grammar/TextualNotationSpecificationVisitorTestFixture.cs
@@ -0,0 +1,64 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2026 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.CodeGenerator.Tests.Grammar
+{
+ using System;
+ using System.IO;
+ using System.Linq;
+
+ using Antlr4.Runtime;
+
+ using NUnit.Framework;
+
+ using SysML2.NET.CodeGenerator.Grammar;
+ using SysML2.NET.CodeGenerator.Grammar.Model;
+
+ [TestFixture]
+ public class TextualNotationSpecificationVisitorTestFixture
+ {
+ [Test]
+ [TestCase("KerML-textual-bnf.kebnf")]
+ [TestCase("SysML-textual-bnf.kebnf")]
+ public void VerifyCanParseGrammar(string modelName)
+ {
+ var filePath = Path.Combine(TestContext.CurrentContext.TestDirectory, "datamodel",modelName );
+
+ var stream = CharStreams.fromPath(filePath);
+ var lexer = new kebnfLexer(stream);
+ var tokens = new CommonTokenStream(lexer);
+ var parser = new kebnfParser(tokens);
+
+ var tree = parser.specification();
+ var explorer = new TextualNotationSpecificationVisitor();
+ var result = (TextualNotationSpecification)explorer.Visit(tree);
+ var rules = result.Rules;
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(rules, Is.Not.Null);
+ Assert.That(rules, Is.Not.Empty);
+ Assert.That(rules.DistinctBy(x => x.RuleName), Is.EquivalentTo(rules));
+ }
+
+ Console.WriteLine($"Found {rules.Count} rules");
+ }
+ }
+}
diff --git a/SysML2.NET.CodeGenerator/Extensions/ClassExtensions.cs b/SysML2.NET.CodeGenerator/Extensions/ClassExtensions.cs
index a59fea30..3eadb42b 100644
--- a/SysML2.NET.CodeGenerator/Extensions/ClassExtensions.cs
+++ b/SysML2.NET.CodeGenerator/Extensions/ClassExtensions.cs
@@ -20,18 +20,15 @@
namespace SysML2.NET.CodeGenerator.Extensions
{
- using System;
- using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using uml4net.Classification;
using uml4net.Extensions;
- using uml4net.Packages;
using uml4net.StructuredClassifiers;
///
- /// Extension methods for interface
+ /// Extension methods for interface
///
public static class ClassExtensions
{
@@ -40,10 +37,10 @@ public static class ClassExtensions
/// or interface implementations EXCLUDING IsDerived
///
///
- /// The from which to query the properties
+ /// The from which to query the properties
///
///
- /// A of
+ /// A of
///
public static ReadOnlyCollection QueryAllNonDerivedProperties(this IClass @class)
{
@@ -59,10 +56,10 @@ public static ReadOnlyCollection QueryAllNonDerivedProperties(this IC
/// redefined in the context of the current class
///
///
- /// The from which to query the properties
+ /// The from which to query the properties
///
///
- /// A of
+ /// A of
///
public static ReadOnlyCollection QueryAllNonDerivedNonRedefinedProperties(this IClass @class)
{
@@ -78,7 +75,7 @@ public static ReadOnlyCollection QueryAllNonDerivedNonRedefinedProper
/// Counts and returns to amount of non derived properties
///
///
- /// The subject
+ /// The subject
///
///
/// the amount of non derived properties
@@ -92,7 +89,7 @@ public static int CountAllNonDerivedProperties(this IClass @class)
/// Counts and returns to amount of non derived properties
///
///
- /// The subject
+ /// The subject
///
///
/// the amount of non derived properties
@@ -103,20 +100,36 @@ public static int CountAllNonDerivedNonRedefinedProperties(this IClass @class)
}
///
- /// Query the name of the internal interface to implement for an
+ /// Query the name of the internal interface to implement for an
///
- /// The
+ /// The
/// The name of the internal interface to implement, if any
public static string QueryInternalInterfaceName(this IClass umlClass)
{
var classifiers = umlClass.QueryAllGeneralClassifiers();
-
+
if (classifiers.Any(x => x.Name == "Relationship"))
{
return "IContainedRelationship";
}
-
+
return classifiers.Any(x => x.Name == "Element") ? "IContainedElement" : string.Empty;
}
+
+ ///
+ /// Asserts that an is a subclass of another
+ ///
+ /// The to check
+ ///
+ /// The that is potentially a super class of
+ ///
+ ///
+ ///
+ /// True if the is a super class of the
+ ///
+ public static bool QueryIsSubclassOf(this IClass umlClass, IClass potentialSuperClass)
+ {
+ return umlClass.QueryAllGeneralClassifiers().Contains(potentialSuperClass);
+ }
}
}
diff --git a/SysML2.NET.CodeGenerator/Extensions/NamedElementExtensions.cs b/SysML2.NET.CodeGenerator/Extensions/NamedElementExtensions.cs
index 402bc345..9bea96a6 100644
--- a/SysML2.NET.CodeGenerator/Extensions/NamedElementExtensions.cs
+++ b/SysML2.NET.CodeGenerator/Extensions/NamedElementExtensions.cs
@@ -20,9 +20,11 @@
namespace SysML2.NET.CodeGenerator.Extensions
{
+ using System;
using System.Linq;
using uml4net.CommonStructure;
+ using uml4net.SimpleClassifiers;
///
/// Extension class for
@@ -40,5 +42,36 @@ public static string QueryNamespace(this INamedElement namedElement)
var namespaces = qualifiedNameSpaces.Skip(1).Take(qualifiedNameSpaces.Length - 2);
return string.Join('.', namespaces);
}
+
+ ///
+ /// Query the fully qualified type name (Namespace + Type name).
+ ///
+ /// The specific that should have the fully qualified type name computed
+ /// A specific namespace part (POCO/DTO distinction)
+ /// Asserts if the type should be the interface name or not
+ /// The fully qualified type name
+ public static string QueryFullyQualifiedTypeName(this INamedElement namedElement, string namespacePart = "POCO", bool targetInterface = true)
+ {
+ ArgumentNullException.ThrowIfNull(namedElement);
+ ArgumentException.ThrowIfNullOrWhiteSpace(namespacePart);
+
+ var typeName = "SysML2.NET.Core.";
+
+ if (namedElement is not IEnumeration)
+ {
+ typeName += $"{namespacePart}.";
+ }
+
+ typeName += namedElement.QueryNamespace();
+ typeName += ".";
+
+ if (namedElement is not IEnumeration && targetInterface)
+ {
+ typeName += "I";
+ }
+
+ typeName += namedElement.Name;
+ return typeName;
+ }
}
}
diff --git a/SysML2.NET.CodeGenerator/Extensions/PropertyExtension.cs b/SysML2.NET.CodeGenerator/Extensions/PropertyExtension.cs
index e9032015..9c337c8f 100644
--- a/SysML2.NET.CodeGenerator/Extensions/PropertyExtension.cs
+++ b/SysML2.NET.CodeGenerator/Extensions/PropertyExtension.cs
@@ -72,7 +72,7 @@ public static string QueryPropertyNameBasedOnUmlProperties(this IProperty proper
{
ArgumentNullException.ThrowIfNull(property);
- return property.IsDerived || property.IsDerivedUnion ? StringExtensions.LowerCaseFirstLetter(property.Name) : StringExtensions.CapitalizeFirstLetter(property.Name);
+ return property.IsDerived || property.IsDerivedUnion ? property.Name.LowerCaseFirstLetter() : property.Name.CapitalizeFirstLetter();
}
///
@@ -92,5 +92,49 @@ public static bool QueryPropertyIsPartOfNonDerivedCompositeAggregation(this IPro
return property.Opposite is { IsComposite: true, IsDerived: false };
}
+
+ ///
+ /// Queries the content of a IF statement for non-empty values
+ ///
+ /// The property that have to be used to produce the content
+ /// The name of the name
+ /// The If Statement content
+ public static string QueryIfStatementContentForNonEmpty(this IProperty property, string variableName)
+ {
+ var propertyName = property.QueryPropertyNameBasedOnUmlProperties();
+
+ if (property.QueryIsEnumerable())
+ {
+ return $"{variableName}.Current != null";
+ }
+
+ if (property.QueryIsReferenceType())
+ {
+ return $"{variableName}.{propertyName} != null";
+ }
+
+ if (property.QueryIsNullableAndNotString())
+ {
+ return $"{variableName}.{propertyName}.HasValue";
+ }
+
+ if (property.QueryIsString())
+ {
+ return $"!string.IsNullOrWhiteSpace({variableName}.{propertyName})";
+ }
+
+ if (property.QueryIsBool())
+ {
+ return $"{variableName}.{propertyName}";
+ }
+
+ if (property.QueryIsEnum())
+ {
+ var defaultValue = property.QueryIsEnumPropertyWithDefaultValue() ? $"{property.Type.QueryFullyQualifiedTypeName()}.{property.QueryDefaultValueAsString().CapitalizeFirstLetter()}" : ((IEnumeration)property.Type).OwnedLiteral[0].Name;
+ return $"{variableName}.{propertyName} != {defaultValue}";
+ }
+
+ return "THIS WILL PRODUCE COMPILE ERROR";
+ }
}
}
diff --git a/SysML2.NET.CodeGenerator/Extensions/StringExtensions.cs b/SysML2.NET.CodeGenerator/Extensions/StringExtensions.cs
new file mode 100644
index 00000000..9ed948db
--- /dev/null
+++ b/SysML2.NET.CodeGenerator/Extensions/StringExtensions.cs
@@ -0,0 +1,120 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2026 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.CodeGenerator.Extensions
+{
+ using System.Text;
+
+ ///
+ /// String helpers used by the grammar and lexical-rules code-generation passes.
+ ///
+ public static class StringExtensions
+ {
+ ///
+ /// Tests whether a string follows the SysML lexical-rule naming convention: uppercase
+ /// letters, digits and underscores only, with at least one letter (e.g.
+ /// RESERVED_KEYWORD, DEFINED_BY, STRING_VALUE).
+ ///
+ /// The string to test
+ /// true when the string matches the all-uppercase snake-case convention
+ public static bool IsAllUpperSnake(this string value)
+ {
+ if (string.IsNullOrEmpty(value))
+ {
+ return false;
+ }
+
+ var hasLetter = false;
+
+ foreach (var character in value)
+ {
+ if (char.IsLetter(character))
+ {
+ hasLetter = true;
+
+ if (!char.IsUpper(character))
+ {
+ return false;
+ }
+ }
+ else if (character != '_' && !char.IsDigit(character))
+ {
+ return false;
+ }
+ }
+
+ return hasLetter;
+ }
+
+ ///
+ /// Tests whether the supplied string contains any letter.
+ ///
+ /// The string to test
+ /// true when at least one letter is present
+ public static bool ContainsAnyLetter(this string value)
+ {
+ if (string.IsNullOrEmpty(value))
+ {
+ return false;
+ }
+
+ foreach (var character in value)
+ {
+ if (char.IsLetter(character))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ ///
+ /// Converts a SNAKE_CASE identifier into PascalCase
+ /// (e.g. DEFINED_BY → DefinedBy).
+ ///
+ /// The snake-case identifier
+ /// The PascalCase form
+ public static string ToPascalCaseFromSnake(this string value)
+ {
+ if (string.IsNullOrEmpty(value))
+ {
+ return value;
+ }
+
+ var builder = new StringBuilder(value.Length);
+ var capitalizeNext = true;
+
+ foreach (var character in value)
+ {
+ if (character == '_')
+ {
+ capitalizeNext = true;
+ continue;
+ }
+
+ builder.Append(capitalizeNext ? char.ToUpperInvariant(character) : char.ToLowerInvariant(character));
+ capitalizeNext = false;
+ }
+
+ return builder.ToString();
+ }
+ }
+}
diff --git a/SysML2.NET.CodeGenerator/GRAMMAR.md b/SysML2.NET.CodeGenerator/GRAMMAR.md
new file mode 100644
index 00000000..b789115f
--- /dev/null
+++ b/SysML2.NET.CodeGenerator/GRAMMAR.md
@@ -0,0 +1,168 @@
+# Grammar Code Generation Guide
+
+This file provides essential context for working on the SysML2 textual notation code generator (`RulesHelper.cs` and related files). Read this when modifying grammar processing or the `TextualNotationBuilder` generation pipeline.
+
+> **⚠ Reviewer agent is mandatory for every change.** Before committing any modification to `SysML2.NET/TextualNotation/*.cs` or to `SysML2.NET.CodeGenerator/HandleBarHelpers/RulesHelper.cs`, invoke the `textual-notation-reviewer` agent (`.claude/agents/textual-notation-reviewer.md`) to verify grammar correctness. See CLAUDE.md "Textual notation reviewer is MANDATORY" for details.
+
+## EBNF / KEBNF Notation Legend
+
+SysML2 grammar rules (in `Grammar/Resources/*.kebnf` and the `…` XML docs of generated `Build{Rule}` methods) follow this notation:
+
+| Construct | Notation | Meaning |
+|---|---|---|
+| Lexical element | `LEXICAL` (uppercase) | Lexer token |
+| Terminal element | `'terminal'` (single-quoted) | Literal keyword or punctuation |
+| Non-terminal element | `NonterminalElement` (PascalCase) | Reference to another rule |
+| Sequential elements | `Element1 Element2` | Both appear in order |
+| Alternative elements | `Element1 \| Element2` | Exactly one of them |
+| Optional elements | `Element ?` | **Zero or one** occurrence |
+| Repeated elements | `Element *` | **Zero or more** occurrences |
+| Repeated elements | `Element +` | **One or more** occurrences (minimum 1, not zero) |
+| Grouping | `( Elements... )` | Parentheses scope a quantifier or alternation |
+
+**Quantifier pitfall when hand-coding:** `+` guarantees at least one occurrence. For `(A | B)+`, alternatives may interleave — a loop is required that re-tests the cursor after each iteration until neither alternative matches.
+
+### KEBNF Extensions (SysML2-specific)
+
+| Construct | Notation | Meaning |
+|---|---|---|
+| Scalar assignment | `prop = X` | Assign the parsed value of `X` to the property `prop` |
+| Collection assignment | `prop += X` | Append one parsed `X` to the collection `prop` |
+| Boolean assignment | `prop ?= 'keyword'` | Set `prop = true` when the terminal is present |
+| Non-parsing assignment | `{ prop = 'val' }` | Implicit side-effect in parse direction; in unparse direction it emits no output |
+| QualifiedName value literal | `prop = [QualifiedName]` | Cross-reference by qualified name |
+
+## Pipeline Overview
+
+```
+KEBNF grammar files (Grammar/Resources/*.kebnf)
+ parsed by Grammar/TextualNotationSpecificationVisitor
+ into Grammar/Model/* (RuleElement hierarchy)
+ processed by HandleBarHelpers/RulesHelper.cs
+ via Handlebars template (Templates/Uml/textualNotationBuilder.hbs)
+ emits SysML2.NET/TextualNotation/AutoGenTextualNotationBuilder/*.cs
+```
+
+**Hand-coded counterparts** live in `SysML2.NET/TextualNotation/*.cs` (parent folder) as `partial` classes. When code-gen can't handle a rule, it emits `Build{RuleName}HandCoded(poco, cursorCache, stringBuilder)` which must be implemented in the hand-coded partial.
+
+## Grammar Element Types (`Grammar/Model/`)
+
+| Type | Grammar form | Key properties |
+|------|--------------|----------------|
+| `NonTerminalElement` | `RuleName`, `RuleName*`, `RuleName+` | `Name`, `IsCollection` |
+| `AssignmentElement` | `prop=X`, `prop+=X`, `prop?=X` | `Property`, `Operator`, `Value: RuleElement` |
+| `TerminalElement` | literal strings like keywords, `;`, `{` | `Value` |
+| `GroupElement` | `(...)`, `(...)?`, `(...)*` | `Alternatives`, `IsOptional`, `IsCollection` |
+| `ValueLiteralElement` | `[QualifiedName]`, `NAME` | `Value`, `QueryIsQualifiedName()` |
+| `NonParsingAssignmentElement` | `{prop='val'}` | `PropertyName`, `Operator`, `Value` |
+
+## Rule Structure
+
+`RuleName:TargetElementName = alternative1 | alternative2 | ...`
+
+- `TargetElementName` is the UML metaclass the rule targets (defaults to `RuleName` if omitted)
+- Builder methods take `I{TargetElementName} poco` as parameter
+- When a NonTerminal's target is the **declaring class** (same as calling context), it uses `poco`
+- When a NonTerminal targets a different class, the cursor element is cast: `if (cursor.Current is ITargetType x) { ... }`
+
+## Cursor Model (`ICursorCache`)
+
+Cursors iterate over collection properties (typically `ownedRelationship`). Key mechanics:
+
+- `cursorCache.GetOrCreateCursor(pocoId, propertyName, collection)` — same `(pocoId, propertyName)` returns the same cursor instance. Cursors are **shared** across builder methods.
+- `cursor.Current` — current element (null when exhausted)
+- `cursor.Move()` — advances to next element
+
+### The Golden Rule: `Move()` ↔ `+=`
+
+**`cursor.Move()` must be emitted exactly once per `+=` assignment processed, and nowhere else.**
+
+The `+=` grammar operator means "consume one element from the collection" — so every `+=` processing advances the cursor by one. No other grammar construct advances it:
+
+| Grammar construct | Advances cursor? |
+|---|---|
+| `prop+=X` (collection assignment) | **Yes — emit `Move()` after processing** |
+| `prop=X` (scalar assignment) | No |
+| `prop?='keyword'` (boolean assignment) | No |
+| `'terminal'` | No |
+| `RuleName` (plain NonTerminal reference) | No (the referenced rule may internally `+=`) |
+| `RuleName*` / `RuleName+` (collection NonTerminal) | No (each iteration's inner `+=` advances) |
+| `(...)` / `(...)?` / `(...)*` (groups) | No (inner `+=` advances) |
+| `[QualifiedName]` / `NAME` (value literals) | No |
+
+When a generated switch dispatches on `cursor.Current` for multiple `+=` alternatives, it **also** emits `default: cursor.Move(); break;` as a safety net — if an unexpected type appears in the cursor, the method still advances so callers in a `while` loop don't spin forever.
+
+**Consequence:** `while (cursor.Current != null) { BuildDispatcher(poco); }` loops don't need an explicit outer `Move()` — the dispatcher's internal `+=` handling (or safety default) advances the cursor.
+
+## Key Methods in `RulesHelper.cs`
+
+| Method | Purpose |
+|--------|---------|
+| `ProcessAlternatives` | Entry point for processing a rule's alternatives. Dispatches to more specific handlers based on alternative structure |
+| `ProcessUnitypedAlternativesWithOneElement` | Handles `A | B | C` where all alternatives have one element of the same type (NonTerminal, Terminal, or AssignmentElement) |
+| `ProcessNonTerminalElement` | Processes a single NonTerminal reference. For collections, delegates to `EmitCollectionNonTerminalLoop` |
+| `EmitCollectionNonTerminalLoop` | Generates `while (cursor.Current ...) { builderCall; cursor.Move(); }` |
+| `ProcessAssignmentElement` | Handles `=`, `+=`, `?=` assignments. Emits property access, cursor advance, or boolean-triggered keyword |
+| `OrderElementsByInheritance` | Sorts NonTerminals by UML class depth (most specific first) for switch case ordering |
+| `ResolveBuilderCall` | Returns `XxxTextualNotationBuilder.BuildRuleName(var, cursorCache, stringBuilder);` or `null` if types incompatible |
+| `ResolveCollectionWhileTypeCondition` | Builds while condition — positive `is Type` if collection has only `+=` assignments, negative `is not null and not NextType` as fallback |
+
+## Guard Mechanisms for Ambiguous Dispatch
+
+When multiple alternatives map to the same UML class (creating duplicate switch cases), these disambiguate:
+
+1. **`?=` boolean guards** (primary) — e.g., `EndUsagePrefix` has `isEnd?='end'`, so it gets `when poco.IsEnd`
+2. **`IsValidFor{RuleName}()` extension methods** (fallback) — hand-coded in `MembershipValidationExtensions.cs` or `TextualNotationValidationExtensions.cs`. Used when `?=` can't disambiguate
+3. **Type ordering** — more specific types (deeper inheritance) come first, fallback case (matching `NamedElementToGenerate`) goes last as `default:`
+
+## Patterns Handled by Code-Gen
+
+| Pattern | Example | Handler |
+|---------|---------|---------|
+| Body with collection items | `';' | '{' Items* '}'` | `ProcessAlternatives` body check with `IsCollection: true` NonTerminal |
+| Body with single sub-rule | `';' | '{' SingleRule '}'` | `ProcessAlternatives` body check with `IsCollection: false` NonTerminal |
+| QualifiedName or owned chain | `prop=[QualifiedName] | prop=OwnedChain{containment+=prop}` | `ProcessAlternatives` two-alternative check |
+| Mixed NonTerminal + `+=` | `NonTerminal | prop+=X` | `if (cursor.Current is XType) { process + Move() } else { BuildNonTerminal(poco, ...) }` |
+| Collection group | `(ownedRelationship+=A | ownedRelationship+=B)*` | `groupElement.IsCollection` handler: while loop + cursor-based switch |
+| Pure dispatch | `NonFeatureMember | NamespaceFeatureMember` | `ProcessUnitypedAlternativesWithOneElement` NonTerminal case with `IsValidFor` guards |
+
+## Switch Case Variable Scoping Gotcha
+
+Pattern variables like `elementAsFeatureMembership` in `if (x is Type elementAsFeatureMembership)` have **block scope**, not just the `if` body — they leak into the enclosing scope. The `if (x != null) { }` wrapper around these serves as a **scoping boundary** to prevent name collisions when the same pattern appears multiple times in the same method. Don't remove outer null guards without understanding this.
+
+## HandCoded Fallback Convention
+
+When code-gen detects an unsupported pattern, it emits:
+```csharp
+Build{RuleName}HandCoded(poco, cursorCache, stringBuilder);
+```
+
+The hand-coded partial class file must:
+1. Live in `SysML2.NET/TextualNotation/{ClassName}TextualNotationBuilder.cs`
+2. Declare `public static partial class {ClassName}TextualNotationBuilder`
+3. Implement the method as `private static void Build{RuleName}HandCoded(...)`
+4. Use `NotSupportedException` (not `NotImplementedException`) for unimplemented stubs
+5. Include the grammar rule as `{rule}` in XML doc
+
+## Common Builder Conventions
+
+- **Trailing space**: Most builders append a trailing space after their content (`stringBuilder.Append(' ')`). Chain builders already add this internally — don't double it.
+- **Terminal formatting**: Special terminals like curly braces and semicolons use `AppendLine`; angle brackets and `~` have no trailing space (see `NewLineTerminals` / `NoTrailingSpaceTerminals` in `RulesHelper.cs`).
+- **Owned vs referenced elements**: To distinguish `type=OwnedChain{ownedRelatedElement+=type}` from `type=[QualifiedName]`, check at runtime: `poco.OwnedRelatedElement.Contains(poco.Type)` owned (call chain builder), else cross-reference (emit `qualifiedName`).
+
+## Testing Changes to the Generator
+
+After modifying `RulesHelper.cs`:
+```bash
+dotnet build SysML2.NET.CodeGenerator/SysML2.NET.CodeGenerator.csproj
+dotnet test SysML2.NET.CodeGenerator.Tests/SysML2.NET.CodeGenerator.Tests.csproj --filter UmlCoreTextualNotationBuilderGeneratorTestFixture
+# Generated files land in SysML2.NET.CodeGenerator.Tests/bin/Debug/net10.0/UML/_SysML2.NET.Core.UmlCoreTextualNotationBuilderGenerator/
+cp SysML2.NET.CodeGenerator.Tests/bin/Debug/net10.0/UML/_SysML2.NET.Core.UmlCoreTextualNotationBuilderGenerator/*.cs SysML2.NET/TextualNotation/AutoGenTextualNotationBuilder/
+dotnet build SysML2.NET.sln
+dotnet test SysML2.NET.sln
+```
+
+**Count remaining HandCoded calls** to track progress:
+```bash
+grep -r "HandCoded" SysML2.NET/TextualNotation/AutoGenTextualNotationBuilder/*.cs | wc -l
+```
diff --git a/SysML2.NET.CodeGenerator/Generators/UmlHandleBarsGenerators/UmlCoreLexicalRulesGenerator.cs b/SysML2.NET.CodeGenerator/Generators/UmlHandleBarsGenerators/UmlCoreLexicalRulesGenerator.cs
new file mode 100644
index 00000000..2938cc31
--- /dev/null
+++ b/SysML2.NET.CodeGenerator/Generators/UmlHandleBarsGenerators/UmlCoreLexicalRulesGenerator.cs
@@ -0,0 +1,248 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2026 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.CodeGenerator.Generators.UmlHandleBarsGenerators
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Linq;
+ using System.Threading.Tasks;
+
+ using SysML2.NET.CodeGenerator.Extensions;
+ using SysML2.NET.CodeGenerator.Grammar.Model;
+
+ using uml4net.xmi.Readers;
+
+ ///
+ /// A UML Handlebars generator that produces the lexical-rule support classes
+ /// (Keywords, SymbolicKeywordKind, SymbolicKeywordKindExtensions) from
+ /// the SysML v2 textual-notation KEBNF grammar. The output lands in the
+ /// LexicalRules/AutoGenLexicalRules folder of the runtime project.
+ ///
+ public class UmlCoreLexicalRulesGenerator : UmlHandleBarsGenerator
+ {
+ ///
+ /// Gets the name of the template for the Keywords static class.
+ ///
+ private const string KeywordsTemplateName = "core-lexical-keywords-template";
+
+ ///
+ /// Gets the name of the template for the SymbolicKeywordKind enum.
+ ///
+ private const string SymbolicKeywordKindTemplateName = "core-lexical-symbolic-keyword-kind-template";
+
+ ///
+ /// Gets the name of the template for the SymbolicKeywordKindExtensions class.
+ ///
+ private const string SymbolicKeywordKindExtensionsTemplateName = "core-lexical-symbolic-keyword-kind-extensions-template";
+
+ ///
+ /// Register the custom helpers
+ ///
+ protected override void RegisterHelpers()
+ {
+ }
+
+ ///
+ /// Register the code templates
+ ///
+ protected override void RegisterTemplates()
+ {
+ this.RegisterTemplate(KeywordsTemplateName);
+ this.RegisterTemplate(SymbolicKeywordKindTemplateName);
+ this.RegisterTemplate(SymbolicKeywordKindExtensionsTemplateName);
+ }
+
+ ///
+ /// Not supported — this generator requires the .
+ /// Use .
+ ///
+ /// The
+ /// The target
+ /// Always thrown.
+ /// nothing — always throws
+ public override Task GenerateAsync(XmiReaderResult xmiReaderResult, DirectoryInfo outputDirectory)
+ {
+ throw new NotSupportedException("The generator needs TextualNotationSpecification access");
+ }
+
+ ///
+ /// Generates the lexical-rule support classes from the supplied
+ /// .
+ ///
+ /// The (unused; retained for interface symmetry)
+ /// The grammar specification to project from
+ /// The target
+ /// an awaitable
+ public async Task GenerateAsync(XmiReaderResult xmiReaderResult, TextualNotationSpecification textualNotationSpecification, DirectoryInfo outputDirectory)
+ {
+ ArgumentNullException.ThrowIfNull(textualNotationSpecification);
+ ArgumentNullException.ThrowIfNull(outputDirectory);
+
+ await this.GenerateKeywordsAsync(textualNotationSpecification, outputDirectory);
+ await this.GenerateSymbolicKeywordKindAsync(textualNotationSpecification, outputDirectory);
+ }
+
+ ///
+ /// Generates the Keywords static class from the RESERVED_KEYWORD rule.
+ ///
+ /// The grammar specification
+ /// The target directory
+ /// an awaitable
+ private async Task GenerateKeywordsAsync(TextualNotationSpecification textualNotationSpecification, DirectoryInfo outputDirectory)
+ {
+ var reservedKeywordRule = textualNotationSpecification.Rules.FirstOrDefault(x => x.RuleName == "RESERVED_KEYWORD");
+
+ if (reservedKeywordRule == null)
+ {
+ return;
+ }
+
+ var keywords = reservedKeywordRule.Alternatives
+ .SelectMany(alternative => alternative.Elements.OfType())
+ .Select(terminal => terminal.Value)
+ .Where(value => !string.IsNullOrWhiteSpace(value))
+ .ToList();
+
+ if (keywords.Count == 0)
+ {
+ return;
+ }
+
+ var template = this.Templates[KeywordsTemplateName];
+ var generated = template(new { Keywords = keywords });
+ generated = this.CodeCleanup(generated);
+
+ await WriteAsync(generated, outputDirectory, "Keywords.cs");
+ }
+
+ ///
+ /// Generates the SymbolicKeywordKind enum and its SymbolicKeywordKindExtensions
+ /// companion. A rule qualifies as "symbolic-keyword" when its name is all uppercase, it has
+ /// exactly two alternatives, the first alternative is a single non-alphabetic terminal, and
+ /// the second alternative starts with an alphabetic keyword terminal.
+ ///
+ /// The grammar specification
+ /// The target directory
+ /// an awaitable
+ private async Task GenerateSymbolicKeywordKindAsync(TextualNotationSpecification textualNotationSpecification, DirectoryInfo outputDirectory)
+ {
+ var kinds = CollectSymbolicKeywordKinds(textualNotationSpecification);
+
+ if (kinds.Count == 0)
+ {
+ return;
+ }
+
+ var enumTemplate = this.Templates[SymbolicKeywordKindTemplateName];
+ var enumGenerated = enumTemplate(new { Kinds = kinds });
+ enumGenerated = this.CodeCleanup(enumGenerated);
+
+ await WriteAsync(enumGenerated, outputDirectory, "SymbolicKeywordKind.cs");
+
+ var extensionsTemplate = this.Templates[SymbolicKeywordKindExtensionsTemplateName];
+ var extensionsGenerated = extensionsTemplate(new { Kinds = kinds });
+ extensionsGenerated = this.CodeCleanup(extensionsGenerated);
+
+ await WriteAsync(extensionsGenerated, outputDirectory, "SymbolicKeywordKindExtensions.cs");
+ }
+
+ ///
+ /// Projects every grammar rule that matches the "symbolic-keyword" shape into an entry
+ /// consumed by both the enum and extensions templates.
+ ///
+ /// The grammar specification
+ /// The ordered set of projected entries
+ private static List