// automatically generated by Xtext
//grammar org.etsi.mts.tdl.TPLan2 with org.eclipse.xtext.common.Terminals
grammar org.etsi.mts.tdl.TPLan2 hidden(WS, ML_COMMENT, SL_COMMENT)

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

import "platform:/resource/org.etsi.mts.tdl.model/model/structured.ecore" as to
import "platform:/resource/org.etsi.mts.tdl.model/model/tdl.ecore" as tdl

//import "http://www.etsi.org/spec/TDL/1.3.1"
//import "http://www.eclipse.org/emf/2002/Ecore" as ecore

Package returns tdl::Package:
    {tdl::Package}
    'Package'
    name=Identifier 
    '{'
		(^import+=ElementImport)*
    
    	//TODO: move to a type of package, similar to group perhaps?
    	('Domain' '{'
	        ('pics' ':' ( packagedElement+=PICS)+';' )?
	        ('entity' 'types' ':' ( packagedElement+=EntityType)+ ';' )?
	        ('entities' ':' ( packagedElement+=Entity)+ ';' )?
	        ('event' 'types' ':' ( packagedElement+=EventType)+ ';' )?
	        ('events' ':' ( packagedElement+=Event)+ ';' )?
	        ('event' 'templates' ':' ( packagedElement+=EventOccurrenceTemplate)+ ';' )?
    	'}')?
    	('Data' '{'
	        (packagedElement+=StructuredDataType)*
	        (packagedElement+=StructuredDataInstance)*
    	'}'
    	)?
    	('Configuration' '{'
	        (packagedElement+=GateType)*
	        (packagedElement+=ComponentType)*
	        (packagedElement+=TestConfiguration)*
    	'}'
    	)?
        (packagedElement+=StructuredTestObjective)*
        (nestedPackage+=Group)*
    '}';


ElementImport returns tdl::ElementImport:
	{tdl::ElementImport}
	'import'
	(	'all'
		|
		(importedElement+=[tdl::PackageableElement|Identifier] ( "," importedElement+=[tdl::PackageableElement|Identifier])*)
	)
	'from' importedPackage=[tdl::Package|Identifier]
	';';

Group returns tdl::Package:
    {tdl::Package}
    'Group'
    name=Identifier
    '{'
        (^import+=ElementImport)*
        (packagedElement+=StructuredTestObjective)*
        (nestedPackage+=Group)*
    '}';

PICS returns to::PICS:
    {to::PICS}
    '-'
    name=Identifier
    ("(" comment+=Qualifier ")")?
    ;

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

EntityType returns tdl::AnnotationType:
    {tdl::AnnotationType}
    '-'
    name=Identifier
    ;

Entity returns to::Entity:
    {to::Entity}
    '-'
    name=Identifier
    ('(' annotation+=Annotation (',' annotation+=Annotation)* ')')?
    ;

EventType returns tdl::AnnotationType:
    {tdl::AnnotationType}
    '-'
    name=Identifier
    ;

Annotation returns tdl::Annotation:
    {tdl::Annotation}
    key=[tdl::AnnotationType|Identifier]
    ;

Event returns to::Event:
    {to::Event}
    '-'
    name=Identifier
    ('(' annotation+=Annotation (',' annotation+=Annotation)* ')')?
    ;

EventOccurrenceTemplate returns to::EventSpecificationTemplate:
    {to::EventSpecificationTemplate}
    '-'
    name=Identifier
    '{'
    eventSpecification=EventSpecification
    '}'
    ;


EventSpecification returns to::EventOccurrenceSpecification:
    {to::EventOccurrenceSpecification}
    (entityReference=EntityReference)?
    eventReference=EventReference
	(eventArgument=Argument)?
    (oppositeEntityReference+=OppositeEntityReference (',' oppositeEntityReference+=OppositeEntityReference)* )?
    ;

StructuredTestObjective returns to::StructuredTestObjective:
	{to::StructuredTestObjective}
    'Test Purpose'
    '{'
	    'TP Id' name=Identifier
        'Test objective' description=Identifier 
        ('Reference' objectiveURI+=Identifier (',' objectiveURI+=Identifier )*)?
        ('Config Id' configuration=[tdl::TestConfiguration|Identifier])? 
        ('PICS Selection' picsReference+=PICSReference (picsReference+=PICSReference)*)? 
        (initialConditions=InitialConditions)?
        (expectedBehaviour=ExpectedBehaviour)?
        (finalConditions=FinalConditions)?
    '}';

InitialConditions returns to::InitialConditions:
    name='Initial conditions'
    'with' '{' conditions=EventSequence '}' 
    ;

ExpectedBehaviour returns to::ExpectedBehaviour:
	FullExpectedBehaviour | PartialExpectedBehaviour
;

FullExpectedBehaviour returns to::ExpectedBehaviour:
    name='Expected behaviour'
    'ensure that'
    '{'
       ('when'
           '{'
               whenClause=EventSequence
           '}'
        'then'
           '{'
               thenClause=EventSequence
           '}'
       )
    '}'
    ;

PartialExpectedBehaviour returns to::ExpectedBehaviour:
    name='Expected behaviour'
    'ensure that'
    '{'
       thenClause=EventSequence
    '}'
    ;


FinalConditions returns to::FinalConditions:
    {to::FinalConditions}
    name='Final conditions'
    'with' '{' conditions=EventSequence '}' 
    ;


EventSequence returns to::EventSequence: 
	RepeatedEventSequence | SimpleEventSequence	
;

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

RepeatedEventSequence returns to::RepeatedEventSequence:
	{to::RepeatedEventSequence}
	'repeat'
	('every' interval=IterationValue | repetitions=IterationValue 'times')? 
	'{'
    events+=FirstEventOccurrence (events+=EventOccurrence)*
    '}'  
    ;


FirstEventOccurrence returns to::EventOccurrence:
	//TODO: fix
	FirstEventOccurrenceSpecification | FirstEventTemplateOccurrence 
;


EventOccurrence returns to::EventOccurrence:
	EventOccurrenceSpecification | EventTemplateOccurrence
;

FirstEventOccurrenceSpecification returns to::EventOccurrenceSpecification:
    {to::EventOccurrenceSpecification}

    (	(	(timeLabel=TimeLabel 
    			(	(',' timeConstraint=TimeConstraint)
    				| ':'
    			)
    		) 
    		| 
    		(timeConstraint=TimeConstraint)
		)
    )?
    (entityReference=EntityReference)?
    eventReference=EventReference
	(eventArgument=Argument)?
    (oppositeEntityReference+=OppositeEntityReference (',' oppositeEntityReference+=OppositeEntityReference)* )?
    (comment+=Note)*
;

FirstEventTemplateOccurrence returns to::EventTemplateOccurrence:
    {to::EventTemplateOccurrence}

    (	(	(timeLabel=TimeLabel 
    			(	(',' timeConstraint=TimeConstraint)
    				| ':'
    			)
    		) 
    		| 
    		(timeConstraint=TimeConstraint)
		)
    )?
    'event' 
    eventTemplate=[to::EventSpecificationTemplate|Identifier]
    'occurs'
    ('with' 
    '{'
    	(entityBinding+=EntityBinding (',' entityBinding+=EntityBinding)*)?
		('argument' 'replaced' 'by' occurrenceArgument=Argument)?
    	
    '}'
    )?
    (comment+=Note)*
;

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


Note returns tdl::Comment:
	'('
	'Note'
	name=NumberAsIdentifier
	':'
	body=Identifier
	')'
;

EventOccurrenceSpecification returns to::EventOccurrenceSpecification:
    {to::EventOccurrenceSpecification}
    comment+=AndOrQualifier
    (		(timeLabel=TimeLabel 
    			(	(',' timeConstraint=TimeConstraint)
    				| ':'
    			)
    		) 
    		| 
    		(timeConstraint=TimeConstraint)
		
    )?
    (entityReference=EntityReference)?
    eventReference=EventReference
	(eventArgument=Argument)?
    (oppositeEntityReference+=OppositeEntityReference (',' oppositeEntityReference+=OppositeEntityReference)* )?
    (comment+=Note)*
    ;

EventTemplateOccurrence returns to::EventTemplateOccurrence:
    {to::EventTemplateOccurrence}
    comment+=AndOrQualifier
    (		(timeLabel=TimeLabel 
    			(	(',' timeConstraint=TimeConstraint)
    				| ':'
    			)
    		) 
    		| 
    		(timeConstraint=TimeConstraint)
		
    )?
    'event' 
    eventTemplate=[to::EventSpecificationTemplate|Identifier]
    'occurs'
    ('with' 
    '{'
    	(entityBinding+=EntityBinding (',' entityBinding+=EntityBinding)*)?
		('argument' 'replaced' 'by' occurrenceArgument=Argument)?
    	
    '}'
    )?
    (comment+=Note)*
    ;


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

TimeConstraint returns tdl::TimeConstraint:
	{tdl::TimeConstraint}
	'(!)' 
	(comment+=Qualifier)*
	comment+=TimeConstraintQualifier
	(comment+=Qualifier | comment+=CommonWordQualifier | comment+=ArticleQualifier)*
	timeConstraintExpression=TimeConstraintExpression
	':'
;

TimeConstraintExpression returns tdl::DataUse:
    //TODO: formalize further? make use of predefined data instances? need complex syntax for that
	//TODO: check the scope of the integration and what is really needed
//	dataInstance=[TimeLabel|Identifier]
//	dataInstance=[DataInstance|Identifier]
	ConstraintTimeLabelUse | ConstraintDataInstanceUse
	//('with' argument+=ArgumentSpecification ( "," argument+=ArgumentSpecification)* )?
;


ConstraintDataInstanceUse returns tdl::DataInstanceUse:
	( dataInstance=[tdl::DataInstance|Identifier] | dataInstance=[tdl::DataInstance|NumberAsIdentifier] )
	;
ConstraintTimeLabelUse returns tdl::TimeLabelUse:
	( timeLabel=[tdl::TimeLabel|Identifier])
	;



TimeConstraintQualifier returns tdl::Comment:
    {tdl::Comment}
    (body='before' | body='after' | body='during' | body='within' )
    ;
    
EntityReference returns to::EntityReference:
    {to::EntityReference}
    (comment+=ArticleQualifier)
    (comment+=Qualifier)*
    (
    	(entity=[to::Entity|Identifier] 'entity')
      | (component=[tdl::ComponentInstance|Identifier] 'component')
    )
    ;
    
OppositeEntityReference returns to::EntityReference:
    {to::EntityReference}
    (comment+=DirectionQualifier)
    (comment+=ArticleQualifier)
    (comment+=Qualifier)*
    (
    	(entity=[to::Entity|Identifier] 'entity')
      | (component=[tdl::ComponentInstance|Identifier] 'component')
    )
    ;

EventReference returns to::EventReference:
    {to::EventReference}
    (comment+=Qualifier | comment+=CommonWordQualifier)*
    event=[to::Event|Identifier] 
    ;

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

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

TypedValue returns to::Value:
    TypedLiteralValue | 
  	DataReference | 
    ContentReference | 
    LiteralValueReference
    //TODO: need for parameter reference?
    ;

IterationValue returns to::Value:
    IterationLiteralValue | 
  	IterationDataReference
  	;


    
TypedLiteralValueAsArgument returns to::LiteralValue:
    {to::LiteralValue}
    (comment+=ArticleQualifier
        | comment+=QuantifiedQualifier
    )
	'(typed)'
    (comment+=Qualifier)* 
    (name=Identifier | name=NumberAsIdentifier)
	dataType=[tdl::DataType|Identifier]
    ('containing' content+=TypedDataContent (',' content+=TypedDataContent)* ';')?
    ;


TypedLiteralValue returns to::LiteralValue:
    {to::LiteralValue}
    comment+=AssignmentQualifier 
    (comment+=Qualifier)* 
	(name=Identifier | name=NumberAsIdentifier)
	//data type?
	('containing' content+=TypedDataContent (',' content+=TypedDataContent)* ';')?
    ;

TypedDataContent returns to::Content:
	{to::Content}
    (comment+=Qualifier)*
    member=[tdl::Member|Identifier]
    (
	    ('containing' content+=TypedDataContent (',' content+=TypedDataContent)* ';')
    	|
		(value=TypedValue)
	)?
    ;

LiteralValueAsArgument returns to::LiteralValue:
    {to::LiteralValue}
    (comment+=ArticleQualifier
        | comment+=QuantifiedQualifier
    )
//	'(literal)'
    (comment+=Qualifier)* 
    (name=Identifier | name=NumberAsIdentifier)
    ('containing' content+=DataContent (',' content+=DataContent)* ';')?
    ;

LiteralValue returns to::LiteralValue:
    {to::LiteralValue}
    comment+=AssignmentQualifier 
    (comment+=Qualifier)* 
	(name=Identifier | name=NumberAsIdentifier)
	('containing' content+=DataContent (',' content+=DataContent)* ';')?
    ;

IterationLiteralValue returns to::LiteralValue:
    {to::LiteralValue}
	(name=Identifier | name=NumberAsIdentifier)
    ;

IterationDataReference returns to::DataReference:
   	content=RepetitionDataInstanceUse
    ;



DataContent returns to::Content:
	{to::Content}
    (comment+=Qualifier)*
    //(parameter=[Parameter|Identifier] | name=Identifier | name=NumberAsIdentifier)
    (name=Identifier | name=NumberAsIdentifier)
    (
	    ('containing' content+=DataContent (',' content+=DataContent)* ';')
    	|
		(value=Value)
	)?
    ;

Identifier returns ecore::EString:
    STRING | ID;

Qualifier returns tdl::Comment:
    body=Identifier | body=NumberAsIdentifier
    ;

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

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

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

AssignmentQualifier returns tdl::Comment:
	(body='indicating value' | body='set to')
;

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

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

ReferenceQualifier returns tdl::Comment:
    (body='corresponding to' | body='derived from' | body='carrying'  | body='contained in' | body='associated with')
    ;

DataInstanceUse returns tdl::DataInstanceUse:
	( dataInstance=[tdl::DataInstance|Identifier]
		| dataInstance=[tdl::DataInstance|NumberAsIdentifier]
	)
	('containing' argument+=ParameterBinding ( ',' argument+=ParameterBinding)* ';')?
	;

RepetitionDataInstanceUse returns tdl::DataInstanceUse:
	( dataInstance=[tdl::DataInstance|Identifier] | dataInstance=[tdl::DataInstance|NumberAsIdentifier])
	;


StaticDataUse returns tdl::StaticDataUse:
	DataInstanceUse | AnyValue | AnyValueOrOmit | OmitValue;

AnyValue returns tdl::AnyValue:
	'any'
	dataType=[tdl::DataType|Identifier]
	;

AnyValueOrOmit returns tdl::AnyValueOrOmit:
	{tdl::AnyValueOrOmit}
	'any' 'or' 'omitted'
	;

OmitValue returns tdl::OmitValue:
	{tdl::OmitValue}
	'omitted'
;

ParameterBinding returns tdl::ParameterBinding:
	parameter=[tdl::Parameter|Identifier]
	comment+=AssignmentQualifier 
    (comment+=Qualifier)*
	dataUse=StaticDataUse
	;

ContentReference returns to::ContentReference:
   	comment+=ReferenceQualifier
   	'the' 'value' 'contained in' 
   	//make more complex: simplify
   	//e.g. 
    //(comment+=ArticleQualifier)?
    //(comment+=Qualifier)*
	//(name=Identifier | name='value')
   	//comment+=ReferenceQualifier
   	(comment+=Qualifier)*
   	content=[to::Content|Identifier]
    ;

LiteralValueReference returns to::LiteralValueReference:
   	comment+=ReferenceQualifier
   	'the' 'value' 'of'
    (comment+=Qualifier)*
   	content=[to::LiteralValue|Identifier]
    ;

ContentReferenceAsArgument returns to::ContentReference:
   	'the' 'value' 'contained in' 
    (comment+=Qualifier)*
   	content=[to::Content|Identifier]
    ;

LiteralValueReferenceArgument returns to::LiteralValueReference:
   	'the' 'value' 'of'
    (comment+=Qualifier)*
   	content=[to::LiteralValue|Identifier]
    ;

DataReference returns to::DataReference:
    (name=Identifier)?
    comment+=ReferenceQualifier
    (comment+=Qualifier)*
   	content=StaticDataUse
    ;

DataReferenceAsArgument returns to::DataReference:
    (comment+=ArticleQualifier 
    	| comment+=QuantifiedQualifier
    )
	'(predefined)'    
    (comment+=Qualifier)*
    //name=Identifier
    content=StaticDataUse
;

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

StructuredDataType returns tdl::StructuredDataType:
	{tdl::StructuredDataType}
	'type'
	name=Identifier
	('with' member+=Member ( "," member+=Member)* )?
    ';';

Member returns tdl::Member:
	(isOptional?='optional')?
	name=Identifier
	'of' 'type'
	dataType=[tdl::DataType|Identifier]
	;

Optional returns ecore::EBoolean :
	'optional'
;

StructuredDataInstance returns tdl::StructuredDataInstance:
	{tdl::StructuredDataInstance}
	dataType=[tdl::DataType|Identifier]
	(name=Identifier | name=NumberAsIdentifier)
	('containing' memberAssignment+=MemberAssignment (',' memberAssignment+=MemberAssignment)* )?		
	';'
	;

MemberAssignment returns tdl::MemberAssignment:
	member=[tdl::Member|Identifier]
	comment+=AssignmentQualifier
	memberSpec=StaticDataUse
;


TestConfiguration returns tdl::TestConfiguration:
	'Test Configuration'
		name=Identifier
	'containing'
		componentInstance+=ComponentInstance (componentInstance+=ComponentInstance)* 
		connection+=Connection (connection+=Connection)* 
	';'
	;

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

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

Connection returns tdl::Connection:
	'connection'
	'between'
	endPoint+=GateReference "and" endPoint+=GateReference  
;

GateReference returns tdl::GateReference:
	component=[tdl::ComponentInstance|Identifier]
	'.'
	gate=[tdl::GateInstance|Identifier]
;

GateType returns tdl::GateType:
	'Interface' 'Type'
	name=Identifier
	'accepts'
		dataType+=[tdl::DataType|Identifier] ( "," dataType+=[tdl::DataType|Identifier])*  
	';';

ComponentType returns tdl::ComponentType:
	{tdl::ComponentType}
	'Component' 'Type'
	name=Identifier
	'with' 
		(timer+=Timer)*
		(variable+=Variable)* 
		(gateInstance+=GateInstance)* 
	';'
;

Timer returns tdl::Timer:
	{tdl::Timer}
	'timer'
	name=Identifier
	;

Variable returns tdl::Variable:
	'variable'
	name=Identifier
	'of' 'type'
	dataType=[tdl::DataType|Identifier]
	;

GateInstance returns tdl::GateInstance:
	{tdl::GateInstance}
	'gate'
	name=Identifier
	'of' 'type' type=[tdl::GateType|Identifier]
	;


    
terminal ID         : '^'?('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9'|'/')*;
terminal INT returns ecore::EInt: ('0'..'9')+;
terminal SQ : '"';
terminal DQ : "'";
terminal STRING : 
            DQ ( '\\' ('b'|'t'|'n'|'f'|'r'|'u'|'"'|"'"|'\\') | !('\\'|DQ) )* DQ |
            SQ ( '\\' ('b'|'t'|'n'|'f'|'r'|'u'|'"'|"'"|'\\') | !('\\'|SQ) )* SQ
        ; 
terminal ML_COMMENT : '/*' -> '*/';
terminal SL_COMMENT     : '//' !('\n'|'\r')* ('\r'? '\n')?;

//terminal NL         : ('\n');

terminal WS         : (' '|'\t'|'\r'|'\n')+;

terminal ANY_OTHER: .;