// automatically generated by Xtext
grammar org.etsi.mts.tdl.TDLtx with org.eclipse.xtext.common.Terminals 

import "http://www.etsi.org/spec/TDL/1.4.1" as tdl
import "http://www.etsi.org/spec/TDL/1.3.1/structured" as to
import "http://www.eclipse.org/emf/2002/Ecore" as ecore
import "http://www.etsi.org/spec/TDL/1.3.1/configurations" as tc


//# Foundation

//Needs to be the first rule
Package returns tdl::Package:
    AnnotationCommentFragment
    'Package' name=Identifier
    (BEGIN
        (^import+=ElementImport//)*
        | packagedElement+=PackageableElement //)*
        | nestedPackage+=Package)*
    END)?
;

PackageableElement returns tdl::PackageableElement:
    (AnnotationType | TestObjective
     | ConstraintType
     | DataResourceMapping | DataElementMapping
     | SimpleDataType | SimpleDataInstance 
     | StructuredDataType | StructuredDataInstance 
     | CollectionDataType | CollectionDataInstance
     | ProcedureSignature 
     | Action | Function 
     | PredefinedFunction 
     | EnumDataType
     | Time 
     | ComponentType | GateType 
     | TestConfiguration 
     | TestDescription
    //Part 4
    | Entity 
    | Event 
    | PICS
    | StructuredTestObjective
    | EventSpecificationTemplate
    | TestPurposeDescription
    //Part 7
    | ExtendedTestConfiguration
    )
;

//Element : Abstract

fragment AnnotationFragment returns tdl::Element:
	'@' 
	//Workaround for upstream issue
	( 
		annotation+=Annotation
		| 
		('[' annotation+=Annotation (',' annotation+=Annotation)+ ']')
	)
;

fragment CommentFragment returns tdl::Element:
	'Note' 
	//Workaround for upstream issue
	( 
		comment+=SingleComment
		| 
		('[' comment+=MultiComment (',' comment+=MultiComment)+ ']')
	)
;


fragment AnnotationCommentFragment returns tdl::Element:
    CommentFragment?
    AnnotationFragment?
    //(annotation+=Annotation)*
;

fragment NameFragment returns tdl::Element:
    'Name' ':' name=Identifier
;

fragment WithCommentFragment returns tdl::Element:
    'with'
    BEGIN
        CommentFragment
    END
;

fragment WithNameFragment returns tdl::Element:
    'with'
    BEGIN
        NameFragment
    END
;

//NamedElement : Abstract

ElementImport returns tdl::ElementImport:
    AnnotationCommentFragment
    'Import'
    ('all' | 
        (importedElement+=[tdl::PackageableElement|Identifier] 
            ( ',' importedElement+=[tdl::PackageableElement|Identifier])*
        )
    )
    'from' importedPackage=[tdl::Package|QIdentifier]
;

SingleComment returns tdl::Comment:
    (name=NIdentifier)? 
    ':' body=EString
;

MultiComment returns tdl::Comment:
    (name=NIdentifier ':')? 
    body=EString
;


Annotation returns tdl::Annotation:
    key=[tdl::AnnotationType|AIdentifier]
    (':' value=EString)?
;

CheckAnnotation returns tdl::Annotation:
    key=[tdl::AnnotationType|CheckIdentifier]
    (':' value=EString)
;


AnnotationType returns tdl::AnnotationType:
    AnnotationCommentFragment
    'Annotation' name = AIdentifier
    ('extends' extension=Extension)?
;

TestObjective returns tdl::TestObjective:
    AnnotationCommentFragment
    'Objective' name=Identifier
    (BEGIN
        ('Description' ':' description=EString)?
        ('References' ':' objectiveURI+=EString (',' objectiveURI+=EString)*)?
    END)?
;

Extension returns tdl::Extension:
    //NOTE: No annotations or comments
    extending=[tdl::PackageableElement|Identifier]
;

ConstraintType returns tdl::ConstraintType: 
    AnnotationCommentFragment
    'Constraint' name=Identifier
;

Constraint returns tdl::Constraint: 
    //NOTE: No annotations or comments
    type=[tdl::ConstraintType|Identifier]
    (':' quantifier+=DataUse (',' quantifier+=DataUse)* )?
;

//# Data

//## Data Definition

DataResourceMapping returns tdl::DataResourceMapping:
    AnnotationCommentFragment
    'Use' resourceURI=EString
    'as' name=Identifier
;

DataElementMapping returns tdl::DataElementMapping:
    AnnotationCommentFragment
    'Map' mappableDataElement=[tdl::MappableDataElement|GRIdentifier]
    ('to' elementURI=EString)?
    'in' dataResourceMapping=[tdl::DataResourceMapping|Identifier]
    'as' name=Identifier
    (BEGIN
        parameterMapping+=ParameterMapping (',' parameterMapping+=ParameterMapping)*
    END)?
;

ParameterMapping returns tdl::ParameterMapping:
    AnnotationCommentFragment
    parameter=[tdl::Parameter|Identifier]
    '->' parameterURI=EString
;

//DataType: Abstract

fragment ConstraintFragment returns tdl::DataType:
    (LBrace constraint+=Constraint RBrace)* 
;

SimpleDataType returns tdl::SimpleDataType:
    AnnotationCommentFragment
    'Type' name=Identifier
    ConstraintFragment
    ('extends' extension=Extension)?
;

//DONE: boolean data instance
SimpleDataInstance returns tdl::SimpleDataInstance:
    AnnotationCommentFragment
    dataType=[tdl::DataType|Identifier]
    //for backwards compatibility -> Predefined Booleans now True and False
    //(name=Identifier | name=BOOLEANNAME)
    name=Identifier 
;

EnumDataInstance returns tdl::SimpleDataInstance:
    AnnotationCommentFragment
    dataType=[tdl::DataType|Identifier]?
    //for backwards compatibility -> Predefined Booleans now True and False
    //(name=Identifier | name=BOOLEANNAME)
    name=Identifier 
;


StructuredDataType returns tdl::StructuredDataType:
    AnnotationCommentFragment
    'Structure' name=Identifier
    ConstraintFragment
    ('extends' extension+=Extension (',' extension+=Extension)*)?
    LParen (member+=Member (',' member+=Member)*)? RParen
;

Member returns tdl::Member:
    AnnotationCommentFragment
    (isOptional?='optional')?
    dataType=[tdl::DataType|Identifier]
    name=Identifier
    (LBrace constraint+=Constraint RBrace)*
;

StructuredDataInstance returns tdl::StructuredDataInstance:
    AnnotationCommentFragment
    dataType=[tdl::DataType|Identifier]
    name=Identifier
    ('<' unassignedMember=UnassignedMemberTreatment '>')?
    LParen (memberAssignment+=MemberAssignment (',' memberAssignment+=MemberAssignment)*)? RParen
;

MemberAssignment returns tdl::MemberAssignment:
    AnnotationCommentFragment
    member=[tdl::Member|Identifier]
    '=' memberSpec=DataUse
;

CollectionDataType returns tdl::CollectionDataType:
    AnnotationCommentFragment
    'Collection' name=Identifier
    ConstraintFragment
    'of' itemType=[tdl::DataType|Identifier]
;

CollectionDataInstance returns tdl::CollectionDataInstance:
    AnnotationCommentFragment
    dataType=[tdl::DataType|Identifier] 
    name=Identifier
    (unassignedMember=UnassignedMemberTreatment)?
    '[' item+=DataUse (',' item+=DataUse)* ']'    
;

ProcedureSignature returns tdl::ProcedureSignature:
    AnnotationCommentFragment
    'Signature' name=Identifier
    LParen parameter+=ProcedureParameter ( ',' parameter+=ProcedureParameter)* RParen
;

ProcedureParameter returns tdl::ProcedureParameter:
    AnnotationFragment?
    kind=ParameterKind
    dataType=[tdl::DataType|Identifier]
    name=Identifier
    WithCommentFragment?
;

enum ParameterKind returns tdl::ParameterKind:
    In = 'in' | Out = 'out' | Exception = 'exception';

FormalParameter returns tdl::FormalParameter:
    AnnotationFragment?
    dataType=[tdl::DataType|Identifier]
    name=Identifier
    WithCommentFragment?
;

Variable returns tdl::Variable:
    AnnotationCommentFragment
    'variable' dataType=[tdl::DataType|Identifier]
    name=Identifier
    WithCommentFragment?
;

Action returns tdl::Action:
    AnnotationCommentFragment
    'Action' name=Identifier
    (LParen formalParameter+=FormalParameter ( ',' formalParameter+=FormalParameter)* RParen)?
    (':' body=EString)?
;
    
Function returns tdl::Function:
    AnnotationCommentFragment
    'Function' name=Identifier
    (LParen formalParameter+=FormalParameter ( ',' formalParameter+=FormalParameter)* RParen)?
    'returns' returnType=[tdl::DataType|Identifier]
    (':' body=EString)?
;

enum UnassignedMemberTreatment returns tdl::UnassignedMemberTreatment:
    AnyValue = '?' | AnyValueOrOmit = '*';

PredefinedFunction returns tdl::PredefinedFunction:
    AnnotationCommentFragment
    'Predefined' 
    (name=PredefinedIdentifierBinary
        | name=PredefinedIdentifierNot
        | name=PredefinedIdentifierSize
    )
    ('returns' returnType=[tdl::DataType|Identifier])?
;

PredefinedIdentifierBinary returns ecore::EString:
    '+' | '-' | '*' | '/' | 'mod' 
  | '>' | '<' | '>=' | '<=' //DONE: fix extra '>=' also in TDLan2
  | '==' | '!=' | 'and' | 'or' | 'xor'
;

PredefinedIdentifierNot returns ecore::EString:
    'not'
;

PredefinedIdentifierSize returns ecore::EString:
    'size'
;

EnumDataType returns tdl::EnumDataType: 
    AnnotationCommentFragment
    'Enumerated' name=Identifier
    BEGIN
        value+=EnumDataInstance (',' value+=EnumDataInstance)*
    END
;


//## Data Use

DataUse returns tdl::DataUse:
    //NOTE: No name, annotations or comments
    //Remove static and dynamic eventually in favour of the sub-rules 
    =>DataElementUse
//    | LiteralValueUse
//    | SpecialValueUse
//    | VariableUse
//    | PredefinedFunctionCall
    | =>(StaticDataUse)
    | (DynamicDataUse)
;

fragment ReductionFragment returns tdl::DataUse:
    (->reduction+=CollectionReference)?
    ('.' reduction+=MemberReference)*
;

fragment ParameterBindingFragment returns tdl::DataUse:
    LParen (argument+=ParameterBinding ( ',' argument+=ParameterBinding)*)? RParen
;

fragment CheckFragment returns tdl::DataUse:
    LBrace (annotation+=CheckAnnotation)  RBrace
;


ParameterBinding returns tdl::ParameterBinding:
    parameter=[tdl::Parameter|Identifier]
//    ('.' parameter+=[tdl::Parameter|Identifier])*
    ParameterReductionFragment
    '=' dataUse=DataUse
;

fragment ParameterReductionFragment returns tdl::ParameterBinding:
    (->reduction+=CollectionReference)?
    ('.' reduction+=MemberReference)*
;


MemberReference returns tdl::MemberReference:
    member=[tdl::Member|Identifier] 
    (->'[' collectionIndex=DataUse ']')? 
;

CollectionReference returns tdl::MemberReference:
    '[' collectionIndex=DataUse ']'
;

StaticDataUse returns tdl::StaticDataUse:    
    DataInstanceUse
    | SpecialValueUse
    | LiteralValueUse
    | CastDataUse
;

DataInstanceUse returns tdl::DataInstanceUse:
    (
    	'instance' dataInstance=[tdl::DataInstance|Identifier]
    	UnassignedFragment?
    	ParameterBindingFragment?
    	ReductionFragment
    )
    |
    (
    	'an' 'instance' 'of' dataType=[tdl::StructuredDataType|Identifier]
    	UnassignedFragment?
    	(ParameterBindingFragment | CollectionItemFragmentDataInstanceUse)
    )
    |
    (
	    'an' 'instance' 
	    UnassignedFragment?
	    (ParameterBindingFragment | CollectionItemFragmentDataInstanceUse)    	
    )
;

fragment UnassignedFragment returns tdl::DataInstanceUse:
    '<' unassignedMember=UnassignedMemberTreatment '>'
;

fragment CollectionItemFragmentDataInstanceUse returns tdl::DataInstanceUse:
    '[' (item+=DataUse (',' item+=DataUse)*)? ']'
;

SpecialValueUse returns tdl::SpecialValueUse:
    OmitValue | AnyValue | AnyValueOrOmit 
;

AnyValue returns tdl::AnyValue:
    name='?'
    (LBrace dataType=[tdl::DataType|Identifier] RBrace)?
    CheckFragment?
;

AnyValueOrOmit returns tdl::AnyValueOrOmit:
    name='*'
    CheckFragment?
;

OmitValue returns tdl::OmitValue:
    name='omit'
;

LiteralValueUse returns tdl::LiteralValueUse:
    (value=STRING | intValue=BIGINTEGER | boolValue=BOOLEAN)
    //Note overloaded syntax with constraints, in a sense this is a constraint too..
	(
		LBrace dataType=[tdl::DataType|Identifier] RBrace
		(ParameterBindingFragment | ReductionFragment)
	)?
	CheckFragment?
;

CastDataUse returns tdl::CastDataUse:
	LParen
	dataUse=DataUse
    'as' 
    dataType=[tdl::DataType|Identifier] 
    RParen
	(ParameterBindingFragment | ReductionFragment)
;


DynamicDataUse returns tdl::DynamicDataUse:
    FunctionCall 
    | FormalParameterUse
    | VariableUse 
    | PredefinedFunctionCall
    | TimeLabelUse 
;

//TODO: deprecated?
FunctionCall returns tdl::FunctionCall:
    'instance' 'returned' 'from' function=[tdl::Function|Identifier] 
    ParameterBindingFragment
    ReductionFragment
;

//TODO: deprecated?
FormalParameterUse returns tdl::FormalParameterUse:
    'parameter' parameter=[tdl::FormalParameter|Identifier]
    (ParameterBindingFragment | ReductionFragment)
;

VariableUse returns tdl::VariableUse:
    componentInstance=[tdl::ComponentInstance|Identifier]
    '::' variable=[tdl::Variable|Identifier]
    (ParameterBindingFragment | ReductionFragment)
;

PredefinedFunctionCall returns tdl::PredefinedFunctionCall:
    PredefinedFunctionCallSize
    | PredefinedFunctionCallNot 
    | PredefinedFunctionCallBinary
;

PredefinedFunctionCallSize returns tdl::PredefinedFunctionCall:
    function=[tdl::PredefinedFunction|PredefinedIdentifierSize] 
    LParen actualParameters+=DataUse RParen
;

PredefinedFunctionCallNot returns tdl::PredefinedFunctionCall:
    function=[tdl::PredefinedFunction|PredefinedIdentifierNot] 
    LParen actualParameters+=DataUse RParen
;

PredefinedFunctionCallBinary returns tdl::PredefinedFunctionCall:
    //Note: necessary to avoid left recursion
    LParen
    actualParameters+=DataUse 
    function=[tdl::PredefinedFunction|PredefinedIdentifierBinary] 
    actualParameters+=DataUse
    RParen
;

DataElementUse returns tdl::DataElementUse:
    //'unified' //this gets embedded in the first alternative somehow!? -> shouldn't be needed anyway
    //express also through table
    //              -   (binding) [index] [items]
    //anonymous            x                 x
    //type                 x                 x
    //instance      x      x         x        

    (   
//        //anonymous - split in case of problems
////        (ParameterBindingFragment | CollectionItemFragment)
////    ) | (
        //instance
        dataElement=[tdl::NamedElement|Identifier]
        UnassignedFragmentNamedElement?
        ParameterBindingFragment?
        ReductionFragment
        CheckFragment?
    ) | (
        //type / anonymous (simplified, avoid duplication, otherwise remove "?")
        //DONE: empty parameters / collections? -> added
        //DONE: support simple data types as well? -> use any value instead
        //DONE: decide on prefix -> extract to comment? -> capture as name
        //(('new' | 'a') dataElement=[tdl::DataType|Identifier])?
        (
        	//DONE: do we really need different ways? -> not for now!
        	//name=('new' | 'a' | 'an' | 'the')
        	//TODO: is this still used?
        	'new' dataElement=[tdl::DataType|Identifier]
        )?
        UnassignedFragmentNamedElement?
        (ParameterBindingFragment | CollectionItemFragment)
        CheckFragment?
    )
;

fragment UnassignedFragmentNamedElement returns tdl::DataElementUse:
    '<' unassignedMember=UnassignedMemberTreatment '>'
;

fragment CollectionItemFragment returns tdl::DataElementUse:
    '[' (item+=DataUse (',' item+=DataUse)*)? ']'
;

//# Time

Time returns tdl::Time:
    AnnotationCommentFragment
    'Time' name=Identifier
;

TimeLabel returns tdl::TimeLabel:
    //NOTE: No annotations or comments
    name=Identifier '=' 'now'    
;

TimeLabelUse returns tdl::TimeLabelUse:
    //NOTE: No reduction and parameter binding (constraint)
    '@' timeLabel=[tdl::TimeLabel|Identifier]
    ('.' kind=TimeLabelUseKind)?
;


enum TimeLabelUseKind returns tdl::TimeLabelUseKind:
    Last = 'last' | Previous = 'previous' | First = 'first'
;

TimeConstraint returns tdl::TimeConstraint:
    //NOTE: No annotations or comments
    timeConstraintExpression=DataUse
;

Timer returns tdl::Timer:
    AnnotationCommentFragment
    'timer' name=Identifier
;

TimeOperation returns tdl::TimeOperation: 
    Wait | Quiescence
;

Wait returns tdl::Wait: 
    AtomicPrefixFragment
    'wait' 'for' period=DataUse
    ( 'on' componentInstance=[tdl::ComponentInstance|Identifier])
;

Quiescence returns tdl::Quiescence: 
    AtomicPrefixFragment
    'quiet' 'for' period=DataUse 
    (  'on' (
            componentInstance=[tdl::ComponentInstance|Identifier] 
            | ('gate' gateReference=[tdl::GateReference|GRIdentifier])
        )
    )?
;


TimerOperation returns tdl::TimerOperation: 
    TimerStart | TimerStop | TimeOut
;

TimerStart returns tdl::TimerStart:
    AtomicPrefixFragment
    'start' componentInstance=[tdl::ComponentInstance|Identifier]
    '::' timer=[tdl::Timer|Identifier]
    'for' period=DataUse
;

TimerStop returns tdl::TimerStop:
    AtomicPrefixFragment
    'stop' componentInstance=[tdl::ComponentInstance|Identifier]
    '::' timer=[tdl::Timer|Identifier]
;

TimeOut returns tdl::TimeOut:
    AtomicPrefixFragment
    'timeout' 'on' componentInstance=[tdl::ComponentInstance|Identifier]
    '::' timer=[tdl::Timer|Identifier]
;

//# Test Configuration

GateType returns tdl::GateType:
    AnnotationCommentFragment
    kind=GateTypeKind
    'Gate' name=Identifier
    ('extends' extension=Extension)?
    'accepts' dataType+=[tdl::DataType|Identifier] ( ',' dataType+=[tdl::DataType|Identifier])*
;

enum GateTypeKind returns tdl::GateTypeKind:
    Message = 'Message' | Procedure = 'Procedure'
;

GateInstance returns tdl::GateInstance:
    AnnotationCommentFragment
    'gate' type=[tdl::GateType|Identifier]
    name=Identifier
    WithCommentFragment?  
;

ComponentType returns tdl::ComponentType:
    AnnotationCommentFragment
    'Component' name=Identifier
    ('extends' extension=Extension)?
    BEGIN
        (timer+=Timer | variable+=Variable | gateInstance+=GateInstance)*
    END
;

ComponentInstance returns tdl::ComponentInstance:
    AnnotationCommentFragment
    type=[tdl::ComponentType|Identifier]
    name=Identifier
    'as' role=ComponentInstanceRole
;

enum ComponentInstanceRole returns tdl::ComponentInstanceRole:
    SUT = 'SUT' | Tester = 'Tester'
;

GateReference returns tdl::GateReference:
    //NOTE: No annotations or comments
    //		-> note that if the name is present, it shall be used exclusively
    (name=GRIdentifier '=')? 
    component=[tdl::ComponentInstance|Identifier]
    '::' 
    gate=[tdl::GateInstance|Identifier]
;

Connection returns tdl::Connection:
    AnnotationCommentFragment
    'connect' endPoint+=GateReference 
    'to' endPoint+=GateReference
    WithNameFragment?
;


TestConfiguration returns tdl::TestConfiguration:
    AnnotationCommentFragment
    'Configuration' name=Identifier
    BEGIN
        componentInstance+=ComponentInstance (',' componentInstance+=ComponentInstance)* 
        (',' connection+=Connection)* 
    END
;

//# Test Behaviour

//## Test Description

TestDescription returns tdl::TestDescription:
    TDPrefixFragment
    ('Test' 'Description' | isLocallyOrdered?='Test') 
    name=Identifier
    (LParen formalParameter+=FormalParameter ( ',' formalParameter+=FormalParameter)* RParen )?
    'uses' testConfiguration=[tdl::TestConfiguration|Identifier]
    (behaviourDescription=BehaviourDescription)?
;

fragment TDPrefixFragment returns tdl::TestDescription:
    TDObjectiveFragment?
    AnnotationCommentFragment
;

fragment TDObjectiveFragment returns tdl::TestDescription:
    'Objective' ':' testObjective+=[tdl::TestObjective|Identifier] 
    ( ',' testObjective+=[tdl::TestObjective|Identifier])*
;


BehaviourDescription returns tdl::BehaviourDescription:
    //NOTE: No annotations or comments
    behaviour=Behaviour
;

//## Combined Behaviour

Behaviour returns tdl::Behaviour:
    CombinedBehaviour | AtomicBehaviour
    //NOTE: Excluded via constraint:
    //PeriodicBehaviour
    //DefaultBehaviour | InterruptBehaviour | 
;

fragment WithBehaviourFragment returns tdl::Behaviour:
    'with'
    BEGIN
        NameFragment?
        ObjectiveFragment?
        CommentFragment?
    END
;

fragment ObjectiveFragment returns tdl::Behaviour:
    'Objective' ':' testObjective+=[tdl::TestObjective|Identifier] ( ',' testObjective+=[tdl::TestObjective|Identifier])*
;


Block returns tdl::Block:
    //NOTE: No annotations or comments
    ('[' 
//    	('@' annotation+=PICSAnnotation)? //TODO: Exception for PICS? seems not enough
		AnnotationFragment?
    	guard+=LocalExpression ( ',' guard+=LocalExpression)* 
	']')?
    BEGIN
        behaviour+=Behaviour+ 
    END
;

LocalExpression returns tdl::LocalExpression:
    //NOTE: No annotations or comments
    expression=DataUse
    ('on' componentInstance=[tdl::ComponentInstance|Identifier])?
;

LocalLoopExpression returns tdl::LocalExpression:
    //NOTE: No annotations or comments
    expression=DataUse 'times'
    ('on' componentInstance=[tdl::ComponentInstance|Identifier])?
;


CombinedBehaviour returns tdl::CombinedBehaviour:
    (SingleCombinedBehaviour | MultipleCombinedBehaviour)
    =>WithCombinedFragment?
;

fragment WithCombinedFragment returns tdl::CombinedBehaviour:
    'with'
    BEGIN
        NameFragment?
        ObjectiveFragment?
        CommentFragment?
        (periodic+=PeriodicBehaviour //)*
        | exceptional+=ExceptionalBehaviour)*
    END
;


SingleCombinedBehaviour returns tdl::SingleCombinedBehaviour:
    CompoundBehaviour
    | BoundedLoopBehaviour
    | UnboundedLoopBehaviour 
    | OptionalBehaviour
;

CompoundBehaviour returns tdl::CompoundBehaviour:
    AnnotationFragment?
    block=Block
;

BoundedLoopBehaviour returns tdl::BoundedLoopBehaviour:
    AnnotationFragment?
    'repeat' numIteration+=LocalLoopExpression (',' numIteration+=LocalLoopExpression)*
    block=Block
;

UnboundedLoopBehaviour returns tdl::UnboundedLoopBehaviour:
    AnnotationFragment?
    'while' block=Block
;

OptionalBehaviour returns tdl::OptionalBehaviour:
    AnnotationFragment?
    'optionally' block=Block
;

MultipleCombinedBehaviour returns tdl::MultipleCombinedBehaviour:
    ConditionalBehaviour 
    | AlternativeBehaviour
    | ParallelBehaviour
;

ConditionalBehaviour returns tdl::ConditionalBehaviour:
    AnnotationFragment?
    'if' block+=Block
    (=>('else' block+=Block)
    | (('else' 'if' block+=Block)* 
       ('else' block+=Block)))? 
;

AlternativeBehaviour returns tdl::AlternativeBehaviour:
    AnnotationFragment?
    'alternatively' block+=Block
    ('or' block+=Block)+ 
;

ParallelBehaviour returns tdl::ParallelBehaviour:
    AnnotationFragment?
    'run' block+=Block 
    ('in' 'parallel' 'to' block+=Block)
    ('and' block+=Block)*
;

ExceptionalBehaviour returns tdl::ExceptionalBehaviour:
    DefaultBehaviour | InterruptBehaviour
;

DefaultBehaviour returns tdl::DefaultBehaviour:
    AnnotationFragment?
    'default' 
    ('on' guardedComponent=[tdl::ComponentInstance|Identifier])?
    block=Block
    WithBehaviourFragment?
;

InterruptBehaviour returns tdl::InterruptBehaviour:
    AnnotationFragment?
    'interrupt'
    ('on' guardedComponent=[tdl::ComponentInstance|Identifier])?
    block=Block
    WithBehaviourFragment?
;

PeriodicBehaviour returns tdl::PeriodicBehaviour:
    AnnotationFragment?
    'every'
    (period+=LocalExpression (',' period+=LocalExpression)*)
    block=Block
    WithBehaviourFragment?
;

//## Atomic Behaviour

AtomicBehaviour returns tdl::AtomicBehaviour:
    (TimerOperation
    | TimeOperation
    | Break | Stop
    | VerdictAssignment | Assertion
    | Interaction
    | TestDescriptionReference 
    | ActionBehaviour 
    | Assignment)
    WithAtomicFragment?
;

fragment AtomicPrefixFragment returns tdl::AtomicBehaviour:
    ObjectiveFragment?
    AnnotationCommentFragment
;

fragment WithAtomicFragment returns tdl::AtomicBehaviour:
	//NOTE: No names
    'with'
    BEGIN
        //NameFragment?
        TimeLabelFragment?
        TimeConstraintFragment?
    END
;

fragment TimeLabelFragment returns tdl::AtomicBehaviour:
    timeLabel=TimeLabel 
;

fragment TimeConstraintFragment returns tdl::AtomicBehaviour:
    LBrace timeConstraint+=TimeConstraint ( ',' timeConstraint+=TimeConstraint)* RBrace
;



Break returns tdl::Break:
    {tdl::Break}
    AtomicPrefixFragment
    'break'
;

Stop returns tdl::Stop:
    {tdl::Stop}
    AtomicPrefixFragment
    'terminate'
;

VerdictAssignment returns tdl::VerdictAssignment:
    AtomicPrefixFragment
    'set' 'verdict' 'to' verdict=DataUse
;

Assertion returns tdl::Assertion:
    {tdl::Assertion}
    AtomicPrefixFragment
    'assert' condition=DataUse
    ('on' componentInstance=[tdl::ComponentInstance|Identifier])?
    ('otherwise' otherwise=DataUse)?
;

Interaction returns tdl::Interaction: 
    Message | ReceiveMessage | ProcedureCall | ProcedureCallResponse
;

Message returns tdl::Message:
    AtomicPrefixFragment
    sourceGate=[tdl::GateReference|GRIdentifier]
    ('sends' | (isTrigger?='triggers')) 
    argument=DataUse
    'to' target+=TargetMessage ( ',' target+=TargetMessage)* 
;

TargetMessage returns tdl::Target:
    //NOTE: No name, annotations or comments
    targetGate=[tdl::GateReference|GRIdentifier]
    (valueAssignment+=ValueAssignmentMessage)?
;

ValueAssignmentMessage returns tdl::ValueAssignment:
    //NOTE: No name, annotations or comments
    'where' 'it' 'is' 
    'assigned' 'to' variable=[tdl::Variable|Identifier]
;

ReceiveMessage returns tdl::Message:
    AtomicPrefixFragment
    //NOTE: Only single target possible
    target+=ReceiveTargetMessage //( ',' target+=ReceiveTargetMessage)*
    'receives' (isTrigger?='trigger')? 
    argument=DataUse
    'from' sourceGate=[tdl::GateReference|GRIdentifier]
;

ReceiveTargetMessage returns tdl::Target:
    //NOTE: No name, annotations or comments
    (valueAssignment+=ReceiveValueAssignmentMessage)?
    targetGate=[tdl::GateReference|GRIdentifier]
;

ReceiveValueAssignmentMessage returns tdl::ValueAssignment:
    //NOTE: No name, annotations or comments
    variable=[tdl::Variable|Identifier] '='
;

ProcedureCall returns tdl::ProcedureCall:
    AtomicPrefixFragment
    (name=Identifier ':')?
    sourceGate=[tdl::GateReference|GRIdentifier]
    'calls' signature=[tdl::ProcedureSignature|Identifier]
    LParen argument+=ParameterBinding (',' argument+=ParameterBinding)* RParen
    'on' target+=TargetProcedure
;

ProcedureCallResponse returns tdl::ProcedureCall:
    AtomicPrefixFragment
    (replyTo=[tdl::ProcedureCall|Identifier] ':')?
    sourceGate=[tdl::GateReference|GRIdentifier]
    'responds' 'with' signature=[tdl::ProcedureSignature|Identifier]
    LParen argument+=ParameterBinding (',' argument+=ParameterBinding)* RParen
    'to' target+=TargetProcedure
;

TargetProcedure returns tdl::Target:
    //NOTE: No name, annotations or comments
    targetGate=[tdl::GateReference|GRIdentifier]
    (valueAssignment+=ValueAssignmentProcedure (',' valueAssignment+=ValueAssignmentProcedure)*)?
;

ValueAssignmentProcedure returns tdl::ValueAssignment:
    //NOTE: No name, annotations or comments
    'where' parameter=[tdl::Parameter|Identifier] 'is' 
    'assigned' 'to' variable=[tdl::Variable|Identifier]
;
    
TestDescriptionReference returns tdl::TestDescriptionReference:
    AtomicPrefixFragment
    'execute' testDescription=[tdl::TestDescription|Identifier]
    (LParen argument+=ParameterBinding ( ',' argument+=ParameterBinding)* RParen )?
    (BEGIN
        componentInstanceBinding+=ComponentInstanceBinding 
        (',' componentInstanceBinding+=ComponentInstanceBinding)*
    END)?
;

ComponentInstanceBinding returns tdl::ComponentInstanceBinding:
    AnnotationCommentFragment
    formalComponent=[tdl::ComponentInstance|Identifier]
    '->' actualComponent=[tdl::ComponentInstance|Identifier]
;

ActionBehaviour returns tdl::ActionBehaviour: 
    ActionReference | InlineAction
;

ActionReference returns tdl::ActionReference:
    AtomicPrefixFragment
    'perform' action=[tdl::Action|Identifier]
    (LParen argument+=ParameterBinding ( ',' argument+=ParameterBinding)* RParen )?
    ('on' componentInstance=[tdl::ComponentInstance|Identifier])?
;

InlineAction returns tdl::InlineAction:
    AtomicPrefixFragment
    'perform' 'action' ':' body=EString
    ('on' componentInstance=[tdl::ComponentInstance|Identifier])?
;

Assignment returns tdl::Assignment:
    AtomicPrefixFragment
    variable=VariableUse
    '=' expression=DataUse
;


//# Auxiliary

//## Fragments

//DataUse: Abstract

//DataInstanceUse: Abstract

//DataElementUse: Abstract

//Behaviour : Abstract

//TestDescription

//AtomicBehaviour : Abstract

//CombinedBehaviour : Abstract



//## ValueConverter Rules (Pseudo-terminals)

//DONE: why does this strip quotes when it is a single word? -> added custom value converter
EString:
    STRING
    // | ID
;

//LiteralValue returns ecore::EString:
//    STRING
//    | ('-'? INT ('.' INT)?)
//;


Identifier:
    ID 
    //implementation specific
    | 'name' | 'type' | 'value'//TODO: exclude other keywords to the extent possible?
;

AIdentifier:    
    Identifier 
    | InitialBlockName 
    | ExpectedBlockName 
    | FinalBlockName 
    | TestPurposeDescriptionName
    | When
    | Then
    | PICSName
    | CheckIdentifier
;

CheckIdentifier:    
    Check
    | Where    
;

GRIdentifier:
    ID ('::' ID)?
;

QIdentifier:
    ID ('.' ID)*
;

NIdentifier returns ecore::EString:
	('-'? INT ('.' INT)?)
;

//Retain Braces even in indentation-based
LBrace:
    BEGIN
;

RBrace:
    END
;

LParen:
    '('
;

RParen:
	')'
;


BIGINTEGER returns ecore::EBigInteger:
	INT
;

//## Terminals
//TODO: consider rolling back depending on outcome..
BOOLEAN returns ecore::EBoolean:
	TRUE | FALSE
;

BOOLEANNAME:
	TRUE | FALSE
;

terminal TRUE : 'true';
terminal FALSE : 'false';
    
// The following synthetic tokens are used for the indentation-aware blocks -> moved to extended grammar
//terminal BEGIN: 'synthetic:BEGIN';  // increase indentation
//terminal END: 'synthetic:END';      // decrease indentation

//alternative bindings for brace-based delimiters
terminal BEGIN: '{';
terminal END: '}';


//#############################################
//## Part 4 (TO) syntax 

//# Foundation

Entity returns to::Entity:
    AnnotationCommentFragment
    'Entity' name=Identifier
;

Event returns to::Event:
    AnnotationCommentFragment
    //DONE: extend identifiers with STRING or multi-word value converters?
    //      only for select uses (distinct rule) or for the entire grammar?
    //      -> not in this version
    //DONE: check how well multi-word value converters work as a separate rule..
    //      would it then be a single string or should it be decomposed in a sequence?
    //      -> not in this version
    'Event' name=KIdentifier
;

PICS returns to::PICS:
    AnnotationCommentFragment
    PICSName name=Identifier
;

//PICS as data instance
//PICS returns tdl::SimpleDataInstance:
//    AnnotationCommentFragment
//    dataType=[tdl::DataType|PICSName] 
//    name=Identifier
//;


//# Comments as Qualifiers

//DONE: Group by context? -> no
//DONE: Move elsewhere -> follow document structure
//DONE: See above regarding multiwords.. -> partially resolved
//DONE: Add predefined annotations for Blocks and Behaviours?

Qualifier returns tdl::Comment:
    body=(Identifier | NIdentifier) //DONE: Numbers as well? -> yes! Strings as well?? -> not for now!
;

NotQualifier returns tdl::Comment:
    body='not'
;

AndOrQualifier returns tdl::Comment:
    body='and' | body='or'
;

ArticleQualifier returns tdl::Comment:
    body='a' | body='an' | body='the'
;

AssignmentQualifier returns tdl::Comment:
    body=Assignments
;

CommonWordQualifier returns tdl::Comment:
    body='before' 
    | body='after' 
    | body='from' 
    | body='to' 
    | body='of'
    | body='start'
;

DirectionQualifier returns tdl::Comment:
    body='by'
    | body='in'
    | body='into'
    | body='for' 
    | body='from' 
    | body='to'
;

QuantifiedQualifier returns tdl::Comment:
    body='all' 
    | body='any'
    | body='few'
    | body='multiple' 
    | body='no' 
    | body='only'
    | body='several' 
    | body='some'
;

ReferenceQualifier returns tdl::Comment:
    body=References
;

TimeConstraintQualifier returns tdl::Comment:
    body='before' 
    | body='after' 
    | body='during' 
    | body='within' 
;


//TODO: explore whether this can be simplified as follows
//      - a side benefit being that IdentifierRefined : ID | TimeConstraintKeyword | ...
//      which would make the use of keywords more flexible
//      but also likely removing the formatting?
//      - also it will likely cause some conflicts, 
//      so it shall be used carefully where it makes sense only
TimeConstraintQualifierRefined returns tdl::Comment:
    body=TimeConstraintKeyword
;

TimeConstraintKeyword returns ecore::EString:
    'before' | 'after' | 'during' | 'within'
;


//TODO: this may need to be pulled to TX..
//TODO: quite a bit contrived.. -> may be restricted to TO... (separate editor?)
//@Override
//AnnotationType returns tdl::AnnotationType:
//    'Annotation' name = (
//        Identifier 
//        | InitialBlockName 
//        | ExpectedBlockName 
//        | FinalBlockName 
//        | TestPurposeDescriptionName
//        | When
//        | Then
//    )
//;

InitialConditionsAnnotation returns tdl::Annotation:
    key=[tdl::AnnotationType|InitialBlockName]
;

ExpectedBehaviourAnnotation returns tdl::Annotation:
    key=[tdl::AnnotationType|ExpectedBlockName]
;

FinalConditionsAnnotation returns tdl::Annotation:
    key=[tdl::AnnotationType|FinalBlockName]
;

TestPurposeDescriptionAnnotation returns tdl::Annotation:
    key=[tdl::AnnotationType|TestPurposeDescriptionName]
;

WhenAnnotation returns tdl::Annotation:
    key=[tdl::AnnotationType|When]
;

ThenAnnotation returns tdl::Annotation:
    key=[tdl::AnnotationType|Then]
;

PICSAnnotation returns tdl::Annotation:
    key=[tdl::AnnotationType|PICSName]
;


//## Element: Abstract 
fragment InitialConditionsFragment returns tdl::Element:
    annotation+=InitialConditionsAnnotation 
;

fragment ExpectedBehaviourFragment returns tdl::Element:
    annotation+=ExpectedBehaviourAnnotation 
;

fragment FinalConditionsFragment returns tdl::Element:
    annotation+=FinalConditionsAnnotation 
;

fragment ElementAndOrPrefix returns tdl::Element:
    comment+=AndOrQualifier
;

//@Override
//PackageableElement returns tdl::PackageableElement:
//    super
//    | Entity 
//    | Event 
//    | PICS
//    | StructuredTestObjective
//    | EventSpecificationTemplate
//    | TestPurposeDescription
//    | ExtendedTestConfiguration
//;

//# Test Objective

StructuredTestObjective returns to::StructuredTestObjective:
    'Test' 'Purpose' name=Identifier
    BEGIN
        ('Objective' ':' description=EString)? 
        ('Reference' ':' objectiveURI+=EString (',' objectiveURI+=EString )*)?
        ('Configuration' ':' configuration=[tdl::TestConfiguration|Identifier])? 
        ('PICS' ':' picsReference+=FirstPICSReference (picsReference+=PICSReference)*)?
        //('Guard:' guard+=DataUse)? //Substitute for PICS eventually?
        (initialConditions=InitialConditions)?
        (expectedBehaviour=ExpectedBehaviour)?
        (finalConditions=FinalConditions)?
        (WithCommentFragment)?
        (variants=Variants)?
    END
;

FirstPICSReference returns to::PICSReference :
    (comment+=NotQualifier)?
    pics=[to::PICS|Identifier]
;

PICSReference returns to::PICSReference :
    ElementAndOrPrefix
    (comment+=NotQualifier)?
    pics=[to::PICS|Identifier]
; 

InitialConditions returns to::InitialConditions:
    InitialConditionsFragment
    'with' conditions=EventSequence 
;

ExpectedBehaviour returns to::ExpectedBehaviour:
    //DONE: are the event sequences mapped to distinct behaviours? -> initially no? perhaps yes?
    //DONE: it will mean that the event sequence will be annotated.. -> not at present  
    ExpectedBehaviourFragment
    'ensure' 'that'
    (
        (BEGIN
            When whenClause=EventSequence
            Then thenClause=EventSequence
        END)
        | 
        (thenClause=EventSequence)
    )
;

FinalConditions returns to::FinalConditions:
    FinalConditionsFragment
    'with' conditions=EventSequence 
;



//# Events

EventSequence returns to::EventSequence:
    BEGIN 
        (RepeatedEventSequence | SimpleEventSequence)
    END 
;

SimpleEventSequence returns to::EventSequence:
    events+=FirstEventOccurrence (events+=EventOccurrence)*
;

RepeatedEventSequence returns to::RepeatedEventSequence:
    'repeat'
    (
        ('every' interval=LiteralOrDataReferenceAsBinding)  
        | 
        (repetitions=LiteralOrDataReferenceAsBinding 'times')
    )? ':' //TODO: add ':' to specification
    BEGIN
        events+=FirstEventOccurrence 
        events+=EventOccurrence*
    END
;

FirstEventOccurrence returns to::EventOccurrence:
    FirstEventOccurrenceSpecification | FirstEventTemplateOccurrence 
;

EventOccurrence returns to::EventOccurrence:
    EventOccurrenceSpecification | EventTemplateOccurrence 
;

fragment EventTimingPrefix returns to::EventOccurrence:
    (   
        (
            (timeLabel=PrefixTimeLabel (',' timeConstraint+=PrefixTimeConstraint)?)
            |
            timeConstraint+=TimeConstraint
        )
        ':'
    )    
;

fragment EventTimingSuffix returns to::EventOccurrence:
    'with'
    BEGIN
        EventTimeLabelFragment?
        EventTimeConstraintFragment?
    END
;

fragment EventTimeLabelFragment returns to::EventOccurrence:
    timeLabel=TimeLabel 
;

fragment EventTimeConstraintFragment returns to::EventOccurrence:
    LBrace timeConstraint+=TimeConstraint ( ',' timeConstraint+=TimeConstraint)* RBrace
;


PrefixTimeLabel returns tdl::TimeLabel:
    {tdl::TimeLabel}
    '(.)' 'at' 'time' 'point' 
    name=Identifier
;

PrefixTimeConstraint returns tdl::TimeConstraint:
    {tdl::TimeConstraint}
    '(!)' 
    (comment+=Qualifier)*
    comment+=TimeConstraintQualifier
    //TODO: ambiguity
//    (comment+=(Qualifier | CommonWordQualifier | ArticleQualifier))*
    timeConstraintExpression=DataUse
;


FirstEventOccurrenceSpecification returns to::EventOccurrenceSpecification:
    EventOccurrenceSpecificationFragment
;

EventOccurrenceSpecification returns to::EventOccurrenceSpecification:
    ElementAndOrPrefix
    EventOccurrenceSpecificationFragment
;

fragment EventOccurrenceSpecificationFragment returns to::EventOccurrenceSpecification:
//    EventTimingPrefix?
    entityReference=EntityReference?
    eventReference=EventReference
    eventArgument=Argument?
    (oppositeEntityReference+=OppositeEntityReference 
        (',' oppositeEntityReference+=OppositeEntityReference)*
    )?
    EventTimingSuffix?
    CommentFragment?
;

EntityReference returns to::EntityReference:
    EntityReferenceFragment
;

OppositeEntityReference returns to::EntityReference:
    comment+=DirectionQualifier
    EntityReferenceFragment
;

fragment EntityReferenceFragment returns to::EntityReference:
    comment+=ArticleQualifier
    comment+=Qualifier*
    (
        (entity=[to::Entity|Identifier] 'entity')
      | (component=[tdl::ComponentInstance|Identifier] 'component')
    )
;


EventReference returns to::EventReference:
    (comment+=Qualifier | comment+=CommonWordQualifier | comment+=NotQualifier)*
    event=[to::Event|KIdentifier] 
;

//# Data

Value returns to::Value:
    LiteralValue 
    | DataReference 
    | ContentReference 
    | LiteralValueReference
;

Argument returns to::Value:
    LiteralValueAsArgument
//    | TypedLiteralValueAsArgument
    | DataReferenceAsArgument
    | ContentReferenceAsArgument
    | LiteralValueReferenceArgument
;

fragment ValueReferenceFragment returns to::Value:
    comment+=NotQualifier?
    comment+=ReferenceQualifier
;

LiteralOrDataReferenceAsBinding returns to::Value:
    LiteralValueAsBinding | DataReferenceAsBinding
;

LiteralValue returns to::LiteralValue:
    comment+=NotQualifier?
    comment+=AssignmentQualifier
    LiteralValueFragment 
;

LiteralValueAsArgument returns to::LiteralValue:
    (comment+=ArticleQualifier | comment+=QuantifiedQualifier)
    LiteralValueFragment
;

LiteralValueAsBinding returns to::LiteralValue:
    LiteralValueFragment    
;

fragment LiteralValueFragment returns to::LiteralValue:
    comment+=Qualifier* 
    (name=Identifier | name=NIdentifier | name = EString)
    ('containing' 
        BEGIN
            content+=DataContent (',' content+=DataContent)* 
        END
    )?
;

DataContent returns to::Content:
    comment+=NotQualifier?
//    (parameter=[Parameter|Identifier] | name=Identifier | name=NumberAsIdentifier)
//    member=[tdl::Member|Identifier]
    comment+=Qualifier*
    (name=Identifier | name=NIdentifier)
    (
        ('containing' 
            BEGIN
                content+=DataContent (',' content+=DataContent)* 
            END
        )
        | value=Value
    )?
; 


LiteralValueReference returns to::LiteralValueReference:
    ValueReferenceFragment
    LiteralValueReferenceFragment
;

LiteralValueReferenceArgument returns to::LiteralValueReference:
    LiteralValueReferenceFragment
;

BindingLiteralValueReference returns to::LiteralValueReference:
    content=[to::LiteralValue|Identifier] | content=[to::LiteralValue|NIdentifier] 
;

fragment LiteralValueReferenceFragment returns to::LiteralValueReference:
    'the' 'value' 'of'
    comment+=ArticleQualifier?
    comment+=Qualifier*
    content=[to::LiteralValue|Identifier]
;

ContentReference returns to::ContentReference:
    ValueReferenceFragment
    ContentReferenceFragment
;

ContentReferenceAsArgument returns to::ContentReference:
    ContentReferenceFragment
;

BindingContentReference returns to::ContentReference:
    content=[to::Content|Identifier]
;

fragment ContentReferenceFragment returns to::ContentReference:
    'the' 'value' 'contained' 'in'
    comment+=ArticleQualifier?
    // (comment+=Qualifier)*
    // (name=Identifier | name='value')
    // comment+=ReferenceQualifier
    comment+=Qualifier*
    content=[to::Content|Identifier]
;

DataReference returns to::DataReference:
    //TODO: is this still needed? causes ambiguity..
    //        -> does not seem to be the case, perhaps for typed?! -> likely not
    //        or simply a leftover..
    //name=Identifier?
    ValueReferenceFragment
    DataReferenceFragment
;

DataReferenceAsArgument returns to::DataReference:
    (
        comment+=ArticleQualifier 
        | comment+=QuantifiedQualifier
    )
    '(predefined)'
    DataReferenceFragment    
;

BindingDataReference returns to::DataReference:
    //TODO: review
    content=StaticDataUse
;

DataReferenceAsBinding returns to::DataReference:
    '(predefined)'    
    DataReferenceFragment
;

fragment DataReferenceFragment returns to::DataReference:
    comment+=Qualifier*
    //name=Identifier
    //TODO: change to data use?
    //TODO: keep syntax or adapt? 
    //        especially with data element use and literal value use..
    //        may need further consideration
    //        on the other hand no one really used this for the most part..  
    content=StaticDataUse
;


    

//# Event Templates

EventSpecificationTemplate returns to::EventSpecificationTemplate:
    AnnotationCommentFragment
    'Template' name=Identifier
    BEGIN
        eventSpecification=FirstEventOccurrenceSpecification
    END
;

FirstEventTemplateOccurrence returns to::EventTemplateOccurrence:
    EventTemplateOccurrenceFragment
;

EventTemplateOccurrence returns to::EventTemplateOccurrence:
    ElementAndOrPrefix
    EventTemplateOccurrenceFragment
;

fragment EventTemplateOccurrenceFragment returns to::EventTemplateOccurrence:
//    EventTimingPrefix?
    'event' 
    eventTemplate=[to::EventSpecificationTemplate|Identifier]
    'occurs'
    ('with' 
    BEGIN
        EventTimeLabelFragment?
        EventTimeConstraintFragment?
        (entityBinding+=EntityBinding (',' entityBinding+=EntityBinding)*)?
        ('argument' 'replaced' 'by' occurrenceArgument=Argument)?
    END
    )?
    CommentFragment?
;

EntityBinding returns to::EntityBinding:
    templateEntity=EntityReference
    'replaced' 'by'
    occurrenceEntity=EntityReference
;


//# Structured Test Objective Variants

Variant returns to::TestObjectiveVariant:
    'Variant' name=Identifier
    BEGIN
        ('Objective' ':' description=EString)? 
        ('Reference' ':' objectiveURI+=EString (',' objectiveURI+=EString)*)?  
        ('PICS' ':' picsReference+=FirstPICSReference (picsReference+=PICSReference)*)?
        //('Guard:' guard+=DataUse)? //Substitute for PICS eventually? 
        ('Bindings' 
            BEGIN
                bindings+=VariantBinding (',' bindings+=VariantBinding)*
            END
        )?
        WithCommentFragment?
    END
;

Variants returns to::Variants:
    variants+=Variant+
    WithCommentFragment?
;

VariantBinding returns to::VariantBinding:
    VariantBindingValue
    | VariantBindingAttribute 
    | VariantBindingPredefined   
;

VariantBindingValue returns to::VariantBinding:
    'value' value=BindingLiteralValueReference
    comment+=AssignmentQualifier
    boundTo=LiteralOrDataReferenceAsBinding
    WithCommentFragment?
;

VariantBindingAttribute returns to::VariantBinding:
    'attribute' value=BindingContentReference
    comment+=AssignmentQualifier
    boundTo=LiteralOrDataReferenceAsBinding
    WithCommentFragment?
;

VariantBindingPredefined returns to::VariantBinding:
    'predefined' 'value' value=BindingDataReference
    comment+=AssignmentQualifier
    boundTo=DataReferenceAsBinding
    WithCommentFragment?
;

//# Test Description
TestPurposeDescription returns tdl::TestDescription:
    annotation+=TestPurposeDescriptionAnnotation
    //TODO: locally ordered?
    //('TestDescription' | isLocallyOrdered?='Test') 
    name=Identifier
    (LParen formalParameter+=FormalParameter ( ',' formalParameter+=FormalParameter)* RParen )?
    //TODO: Reference, PICS?, Objective reference vs Objective inline (all annotations?) or simply defer to objective
    BEGIN
        TDObjectiveFragment?
        'Configuration' ':' testConfiguration=[tdl::TestConfiguration|Identifier]
        (behaviourDescription=TPDBehaviourDescription)
    END
;

TPDBehaviourDescription returns tdl::BehaviourDescription:
    behaviour=TPDCompoundBehaviour
;

TPDCompoundBehaviour returns tdl::CompoundBehaviour:
    //(annotation+=PICSAnnotation ':')?
    block=TPDBlock
;

InitialConditionsBehaviour returns tdl::CompoundBehaviour:
    annotation+=InitialConditionsAnnotation
    'with' block=Block
;

ExpectedBehaviourBehaviour returns tdl::CompoundBehaviour:
    annotation+=ExpectedBehaviourAnnotation
	'ensure' 'that'
    (
        BEGIN
            block=WhenThenBlock
        END
    )
    //TODO: this does not seem to work
    |
	block=Block
;

FinalConditionsBehaviour returns tdl::CompoundBehaviour:
    annotation+=FinalConditionsAnnotation
    'with' block=Block
;


WhenBehaviour returns tdl::CompoundBehaviour:
    annotation+=WhenAnnotation
    block=Block
;

ThenBehaviour returns tdl::CompoundBehaviour:
    annotation+=ThenAnnotation
    block=Block
;

TPDBlock returns tdl::Block:
    //NOTE: No guard -> guard is PICS
    //TODO: annotation has to be pulled up? or pushed down?
    (annotation+=PICSAnnotation ':' guard+=LocalExpression)?
    (behaviour+=InitialConditionsBehaviour)? 
    (behaviour+=ExpectedBehaviourBehaviour)? 
    (behaviour+=FinalConditionsBehaviour)? 
;

WhenThenBlock returns tdl::Block:
    behaviour+=WhenBehaviour
    behaviour+=ThenBehaviour 
;





//#############################################
//## Part 7 (TC) syntax 

//Extended Test Configurations
ExtendedTestConfiguration returns tc::ExtendedTestConfiguration:
    AnnotationCommentFragment
    'Configuration' name=Identifier 
    'with'
    BEGIN
       configurations+=TestConfigurationInstance 
       (',' configurations+=TestConfigurationInstance)*
       (',' operations+=TestConfigurationOperation)*
       (',' componentInstance+=ComponentInstance)* 
       (',' connection+=ExtendedConnection)*       
    END
;

TestConfigurationInstance returns tc::TestConfigurationInstance:
    AnnotationCommentFragment
    configuration=[tdl::TestConfiguration|Identifier] 
    'as' name=Identifier
;

TestConfigurationOperation returns tc::TestConfigurationOperation:
    ComponentMerge
    | ComponentHide
    | ReassignRole
    | ComponentAlias
;

ComponentReference returns tc::ComponentReference:
    configuration=[tc::TestConfigurationInstance]
    '::' component=[tdl::ComponentInstance|Identifier]
;

ExtendedGateReference returns tc::ExtendedGateReference:
    (name=GRIdentifier '=')? 
    configuration=[tc::TestConfigurationInstance|Identifier]
    '::'
    component=[tdl::ComponentInstance|Identifier]
    '::' 
    gate=[tdl::GateInstance|Identifier]
;

ComponentMerge returns tc::ComponentMerge:
    AnnotationCommentFragment
    component=ComponentReference 
    'merged' 'into' target=ComponentReference
;

ComponentAlias returns tc::ComponentAlias:
    AnnotationCommentFragment
    component=ComponentReference 
    'as' name=Identifier
;

ComponentHide returns tc::ComponentHide:
    AnnotationCommentFragment
    component=ComponentReference 'hidden'
;

ReassignRole returns tc::ReassignRole:
    AnnotationCommentFragment
    component=ComponentReference 
    'as' role=ComponentInstanceRole
;

ExtendedConnection returns tdl::Connection:
    AnnotationCommentFragment
    'connect'
    endPoint+=(GateReference | ExtendedGateReference) 
    'to' endPoint+=(GateReference | ExtendedGateReference)
    WithNameFragment?
;




//## ValueConverter Rules (Pseudo-terminals)

Assignments:
    'indicating' 'value' 
    | 'set' 'to'
;

References:
    'corresponding' 'to' 
    | 'derived' 'from' 
    | 'carrying'  
    | 'contained' 'in' 
    | 'associated' 'with'
;

InitialBlockName:
    'Initial' 'conditions'
;

ExpectedBlockName:
    'Expected' 'behaviour'
;

FinalBlockName:
    'Final' 'conditions'
;

TestPurposeDescriptionName:
    'Test' 'Purpose' 'Description'
;

PICSName:
    'PICS'
;

When:
    'when'
;

Then:
    'then'
;

Check:
    'check'
;

Where:
    'where'
;


KIdentifier:
    ID | 'sends' | 'receives' | 'triggers' | 'in'
;

//TODO: document?
@Override 
//terminal ID: '^'?('a'..'z'|'A'..'Z'|'_') (ALPHANUM | (('-'|':') ALPHANUM))*;
terminal ID: '^'?('a'..'z'|'A'..'Z'|'_') (ALPHANUM | (('-') ALPHANUM))*;
terminal fragment ALPHANUM: ('a'..'z'|'A'..'Z'|'_'|'0'..'9');