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

//import "http://www.eclipse.org/uml2/4.0.0/Types" 
import "http://www.etsi.org/spec/TDL/1.4.1"
//import "http://www.eclipse.org/uml2/5.0.0/Types" as types 
import "http://www.eclipse.org/emf/2002/Ecore" as ecore

//#####################################################################################
DataUse returns DataUse:
    //TODO: make sure that DataElementUse works -> may be clashing with others (requires deeper alignment and cleanup)
	DynamicDataUse | StaticDataUse | DataElementUse;

StaticDataUse returns StaticDataUse:
	SpecialValueUse | DataInstanceUse | LiteralValueUse;

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

//Copied and adjusted from TDLtx 
DataElementUse returns 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=[NamedElement|Identifier]
        UnassignedFragmentNamedElement?
        ParameterBindingFragment?
        ReductionFragment
    ) | (
        //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')
            'new' dataElement=[DataType|Identifier]
        )?
        UnassignedFragmentNamedElement?
        (ParameterBindingFragment | CollectionItemFragment)
    )
;

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

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

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

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


SpecialValueUse returns StaticDataUse:
	NoneValue | AnyValue | AnyNoneValue;

EString returns ecore::EString:
	ID;

Identifier:
    ID
;

DataInstanceUse returns DataInstanceUse:
	{DataInstanceUse}
	((dataInstance=[DataInstance|NumberAsIdentifier] |
	dataInstance=[DataInstance|EString])
	((unassignedMember=UnassignedMemberTreatment)?
	('(' argument+=ParameterBinding ("," argument+=ParameterBinding)* ')')?
	('.' reduction+=MemberReference)*)?)
	|
	(dataType=[StructuredDataType|EString]
	(unassignedMember=UnassignedMemberTreatment)?
	('(' argument+=ParameterBinding ("," argument+=ParameterBinding)* ')'))
	|
	((unassignedMember=UnassignedMemberTreatment)?
	('(' argument+=ParameterBinding ("," argument+=ParameterBinding)* ')'))
	|
	{DataInstanceUse}
	((dataType=[CollectionDataType|EString])?
	(unassignedMember=UnassignedMemberTreatment)?
	'{'
	(item+=DataUse ("," item+=DataUse)*)?
	'}') // TODO: if for some reason the data instance use does have a name
// it will cause problems... same applies for other scenarios 
// TODO: create a more elegant way to handle that gracefully)
// (name=EString)?
;

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

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

LiteralValueUse returns LiteralValueUse:
	{LiteralValueUse}
	(value=String0 | intValue=BigInt | boolValue=Boolean)
	(':' dataType=[DataType|EString]
       (ParameterBindingFragment | ReductionFragment)
	)?
;

BigInt returns ecore::EBigInteger:
	INT;

Boolean returns ecore::EBoolean:
	'true' | 'false';

MemberReference returns MemberReference:
	member=[Member|EString];

FormalParameterUse returns FormalParameterUse:
	parameter=[FormalParameter|EString]
	('(' argument+=ParameterBinding ("," argument+=ParameterBinding)* ')')?
	("." reduction+=MemberReference)*;

FunctionCall returns FunctionCall:
	function=[Function|EString]
	'('
	(argument+=ParameterBinding ("," argument+=ParameterBinding)*)?
	')'
	('.' reduction+=MemberReference)*;

VariableUse returns VariableUse:
	componentInstance=[ComponentInstance|EString]
	'->'
	variable=[Variable|EString]
	('(' argument+=ParameterBinding ("," argument+=ParameterBinding)* ')')?
	("." reduction+=MemberReference)*;

TimeLabelUse returns TimeLabelUse:
	// XXX need to add predefined function -> for what
	timeLabel=[TimeLabel|EString]
    ('.' kind=TimeLabelUseKind)?
;	

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


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

ParameterBinding returns ParameterBinding:
	parameter=[Parameter|EString]
	':='
	dataUse=DataUse;

NoneValue returns OmitValue:
	{OmitValue}
	'omit';

AnyValue returns AnyValue:
	'?'
	(':' dataType=[DataType|EString]);

AnyNoneValue returns AnyValueOrOmit:
	{AnyValueOrOmit}
	'*';

String0 returns ecore::EString:
	STRING;

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


PredefinedFunctionCall returns PredefinedFunctionCall:
	// XXX add all predefined functions -> done?
	PredefinedFunctionCallSize | PredefinedFunctionCallNot | PredefinedFunctionCallBinary;

PredefinedFunctionCallSize returns PredefinedFunctionCall:
	function=[PredefinedFunction|PredefinedIdentifierSize]
	'('
	actualParameters+=DataUse
	')'
	// XXX check reduction -> no reduction?
;

PredefinedFunctionCallNot returns PredefinedFunctionCall:
	function=[PredefinedFunction|PredefinedIdentifierNot]
	'('
	actualParameters+=DataUse
	')';

PredefinedFunctionCallBinary returns PredefinedFunctionCall:
	'('
	actualParameters+=DataUse
	function=[PredefinedFunction|PredefinedIdentifierBinary]
	actualParameters+=DataUse
	')';

PredefinedIdentifierBinary returns ecore::EString:
	'+' | '-' | '*' | '/' | 'mod'
	| '>' | '<' | '>=' | '<=' | '>='
	| '==' | '!=' | 'and' | 'or' | 'xor';

PredefinedIdentifierNot returns ecore::EString:
	'not';

PredefinedIdentifierSize returns ecore::EString:
	'size';
	
LParen:
    '('
;

RParen:
    ')'
;
	