/*******************************************************************************
 * Copyright (c) 2015, 2016 CNRS, IRIT, IRT AESE (IRT Saint Exupéry).
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the LGPL 3.0
 * which accompanies this distribution, and is available at
 * https://www.gnu.org/licenses/lgpl-3.0-standalone.html
 *
 * Contributors:
 *     Marc Pantel - initial API and implementation and/or initial documentation
 *     Faiez Zalila
 *******************************************************************************/
grammar fr.irit.fiacre.xtext.Fiacre with org.eclipse.xtext.common.Terminals

import "http://www.eclipse.org/emf/2002/Ecore" as ecore

generate fiacre "http://www.irit.fr/fiacre/xtext/Fiacre"

Model:
	{Model} imports+=ImportDeclaration* 
	(declarations+=Declaration | requirements+=Requirement  /* added alternative root */ | root+=Root )* 
//	((root=[RootDeclaration])? (declarations+=Declaration | requirements+=Requirement)*)
;

RootDeclaration:
	ComponentDeclaration
	| ProcessDeclaration
;

Root:
	{Root} declaration=[RootDeclaration]  ('>'(observed+=[RootDeclaration] ('|' observed+=[RootDeclaration])* ))?
;	
NamedElement:
	Declaration
	//| GenericDeclaration
	| PortDeclaration
	| ParameterDeclaration
	| VariableDeclaration
	| StateDeclaration
	| RecordFieldDeclaration
	| UnionTagDeclaration
	//ajout Faiez
//	| TagDeclaration
;

TypeDeclarationUse:
	TypeDeclaration
	//| GenericTypeDeclaration
	| ChannelDeclaration
	//| GenericConstantDeclaration
;

ConstantDeclarationUse:
	ConstantDeclaration
	//| GenericConstantDeclaration
;

ExpressionDeclarationUse:
	VariableDeclaration
	| ConstantDeclaration
	//| GenericConstantDeclaration
	| ParameterDeclaration
	| PortDeclaration
	| UnionTagDeclaration
	//| GenericDeclaration
	| FunctionDeclaration
;

ReferenceDeclarationUse:
	VariableDeclaration
	| ParameterDeclaration
;

UnionTagDeclarationUse:
	UnionTagDeclaration
	//| GenericUnionTagDeclaration
;

RecordFieldDeclarationUse:
	RecordFieldDeclaration
	//| GenericRecordFieldDeclaration
;

PatternDeclarationUse:
	VariableDeclaration
	| ParameterDeclaration
	| PortDeclaration
	| UnionTagDeclaration
	//| GenericUnionTagDeclaration
;

BoundDeclarationUse:
	VariableDeclaration
	//| GenericConstantDeclaration
	| ConstantDeclaration
;

PathDeclarationUse:
	ComponentDeclaration
	| InstanceDeclaration
	| ProcessDeclaration
;
	
PropertyDeclarationUse:
	PropertyDeclaration
	|VariableDeclaration
;

ImportDeclaration:
	'#include' importURI=STRING
;

Declaration:
	TypeDeclaration
	| ChannelDeclaration
	| ConstantDeclaration
	| ParameterizedDeclaration
	| PropertyDeclaration
;	
	
ParameterizedDeclaration:
	ProcessDeclaration
	| ComponentDeclaration
	//added
	| FunctionDeclaration
;

FunctionDeclaration:
	'function' name=ID
	('(' (parameters+=ParametersDeclaration (',' parameters+=ParametersDeclaration)*)? ')')
	':' type=Type
	'is'
	('var' variables+=VariablesDeclaration (',' variables+=VariablesDeclaration)*)?
	(statement=Statement)
;


TypeDeclaration:
	'type' name=ID 'is' value=Type
;

ChannelDeclaration:
	'channel' name=ID 'is' value=ChannelType
;

ChannelType:
	// added ? after the second 'out'
	{ChannelType} ('array' size=Expression 'of')? ((((in?='in' (out?='out')?) | out?='out')? (type=TupleType | 'none')) | 'none' | 'sync')
;
	
Type:
	BasicType
	| RangeType
	| UnionType
	| RecordType
	| QueueType
	| ArrayType
	| ReferencedType
//	| TupleType
;

TupleType returns Type:
	Type ({TupleType.types+=current} '#' types+=Type)*
;

BasicType:
	{NaturalType} 'nat'
	| {IntegerType} 'int'
	| {BooleanType} 'bool'
;
// changed
RangeType:
	 minimum=Expression '..' maximum=Expression 
;

UnionType:
	'union' tags+=UnionTags ('|' tags+=UnionTags)* 'end' ('union')?
;

UnionTags:
	tags+=UnionTagDeclaration (',' tags+=UnionTagDeclaration)* ('of' type=Type)?
;

UnionTagDeclaration:
	name=ID
;

RecordType:
	'record' fields+=RecordFields (',' fields+=RecordFields)* 'end' ('record')?
;

RecordFields:
	fields+=RecordFieldDeclaration (',' fields+=RecordFieldDeclaration)* ':' type=Type
;

RecordFieldDeclaration:
	name=ID
;

QueueType:
	'queue' size=Expression 'of' type=Type
;

ArrayType:
	'array' size=Expression 'of' type=Type
;


ReferencedType:
	type=[TypeDeclarationUse]
;

/* ChannelDeclaration:
	'channel' name=ID 'is' channel=ChannelType
; */

ConstantDeclaration:
	'const' name=ID ':' type=Type 'is' value=Expression 
;

ProcessDeclaration:
	'process' name=ID
	//('<|' generics+=GenericDeclaration (',' generics+=GenericDeclaration)* '|>')? 
	('[' ports+=PortsDeclaration (',' ports+=PortsDeclaration)* ']')? 
	('(' parameters+=ParametersDeclaration (',' parameters+=ParametersDeclaration)* ')')?
	'is'
	('port' localPorts+=PortsDeclaration (',' localPorts+=PortsDeclaration)*)? 
	('priority' priorities+=PriorityDeclaration (',' priorities+=PriorityDeclaration)*)? 
	'states' states+=StateDeclaration (',' states+=StateDeclaration)* 
	('var' variables+=VariablesDeclaration (',' variables+=VariablesDeclaration)*)? 
	('init' prelude=StatementSequence)? 
	(transitions+=Transition)+
;

//GenericDeclaration:
// 	('type' GenericTypeDeclaration)
//	| ('const' GenericConstantDeclaration)
//	| (('constr0' | 'constr1') GenericUnionTagDeclaration)
//	| ('field' GenericRecordFieldDeclaration)
//;
//
//GenericTypeDeclaration:
//	name=ID
//;
//
//GenericConstantDeclaration:
//	name=ID
//;
//
//GenericUnionTagDeclaration:
//	name=ID
//;
//
//GenericRecordFieldDeclaration:
//	name=ID
//;

StateDeclaration:
	name=ID
;
TransitionSource:
	'from' origin=[StateDeclaration]
;
Transition:
	 source=TransitionSource action=StatementSequence	
;

ComponentDeclaration:
	'component' name=ID 
	('[' ports+=PortsDeclaration (',' ports+=PortsDeclaration)* ']')? 
	('(' parameters+=ParametersDeclaration (',' parameters+=ParametersDeclaration)*')')? 
	'is'
	('var' variables+=VariablesDeclaration (',' variables+=VariablesDeclaration)*)?
	('port' localPorts+=LocalPortsDeclaration (',' localPorts+=LocalPortsDeclaration)*)?
	('priority' priorities+=PriorityDeclaration (',' priorities+=PriorityDeclaration)*)? 
	('init' prelude=StatementSequence)?
	body=Composition
;

PortsDeclaration:
	ports+=PortDeclaration (',' ports+=PortDeclaration)* ':' type=ChannelType
;

PortDeclaration:
	name=ID
;

LocalPortsDeclaration:
	 ports+=PortDeclaration (',' ports+=PortDeclaration)* ':' type=ChannelType ('in' left=LowerBound ',' right=UpperBound)?
;

ParametersDeclaration:
	parameters+=ParameterDeclaration (',' parameters+=ParameterDeclaration)* ':' (read?='read')? (write?='write')? type=Type
;

ParameterDeclaration:
	((reference?='&') (array?='[' size=Expression ']')?)? name=ID
;

VariablesDeclaration:
	variables+=VariableDeclaration (',' variables+=VariableDeclaration)* ':' type=Type (':=' value=Expression)?
;

VariableDeclaration:
	name=ID
;

PriorityDeclaration:
	groups+=PriorityGroup ('>' groups+=PriorityGroup)+ 
;

PriorityGroup:
	ports+=[PortDeclaration] ('|' ports+=[PortDeclaration])*
;

UnlessStatement returns Statement:
	StatementChoice ({UnlessStatement.followers+=current} 'unless' followers+=StatementChoice)*
;

StatementChoice returns Statement:
	StatementSequence ({StatementChoice.choices+=current} '[]' choices+=StatementSequence)*
;

StatementSequence returns Statement:
	Statement ({StatementSequence.statements+=current} ';' statements+=Statement)*
;

Statement:
	NullStatement
	| TaggedStatement
	| PatternStatement
	| ConditionalStatement
	| SelectStatement
	| WhileStatement
	| ForeachStatement
	| ToStatement
	| CaseStatement
	| LoopStatement
	| OnStatement
	| WaitStatement
	| ReturnStatement
	| BlockStatement
;

BlockStatement:
	'begin' body=StatementSequence 'end'
;

ReturnStatement:
	'return' expression=Expression
;

NullStatement:
	{NullStatement} 'null'
;

TaggedStatement:
	'#' name=ID //tag=TagDeclaration
;

//TagDeclaration:
//	name=ID
//;

PatternStatement:
	(
		Pattern 
		((',' {AssignStatement.patterns+=current} patterns+=Pattern (',' patterns+=Pattern)* ':=' values+=Expression (',' values+=Expression)*)
			|
			(':=' {AssignStatement.patterns+=current} ((values+=Expression (',' values+=Expression)*)))
			|
			(',' {AssignAnyStatement.patterns+=current} patterns+=Pattern (',' patterns+=Pattern)* ':=' ('any') ('where' exp=Expression)? )
			|
			(':=' {AssignAnyStatement.patterns+=current}  ('any') ('where' exp=Expression)?)
			|
			('!' {SendStatement.port=current} values+=Expression (',' values+=Expression)*)
			|
			('?' {ReceiveStatement.port=current} patterns+=Pattern (',' patterns+=Pattern)* ('where' exp=Expression)?)	
		)?		
	)
;

Pattern:
	AnyPattern
	| IntegerPattern
	| ConstantPattern
	| '(' Pattern ')'
	| IdentifierPattern
;

AnyPattern:
	{AnyPattern} 'any'
;

ConstantPattern:
	value=LiteralExpression
;

IntegerPattern:
	('+' | negative?='-') value=INT
;

IdentifierPattern:
// TODO : Provide a common type for declaration in ConstructorPattern and IdentifierPattern
//( parameters+=Expression (',' parameters+=Expression)* )?
	(
		({ConstructorPattern} declaration=[PatternDeclarationUse]  '(' ( parameters+=Pattern (',' parameters+=Pattern)* )? ')'  )
	|
		(
			declaration=[PatternDeclarationUse]
			(
				('[' {ArrayAccessPattern.source=current} index=Expression ']')
			|
				('.' {RecordAccessPattern.source=current} field=[RecordFieldDeclaration])
			)*
		)
	)
;

ConditionalStatement:
	'if' condition=Expression 
	'then' then=StatementSequence (elseif+=ExtendedConditionalStatement)*
	('else' else=StatementSequence)? 'end' ('if')?
;

ExtendedConditionalStatement:
	'elsif' condition=Expression 'then' then=StatementSequence
;

SelectStatement:
	'select' 
	body=UnlessStatement
	('|' index=VariableDeclaration 'in' type=RangeType)?
	'end' ('select')?
;

WhileStatement:
	'while' condition=Expression 'do' body=StatementSequence 'end' ('while')?
;

ForeachStatement:
	'foreach' variable=VariableDeclaration 'do' body=StatementSequence 'end' ('foreach')?
;

ToStatement:
	'to' state=[StateDeclaration]
;

CaseStatement:
	'case' value=Expression 'of' 
	pattern+=Pattern '->' body+=StatementSequence ('|' pattern+=Pattern '->' body+=StatementSequence)*
	'end' ('case')?
;

LoopStatement:
	{LoopStatement} 'loop'
;

OnStatement:
	'on' condition=Expression
;

WaitStatement:
	'wait' left=LowerBound ',' right=UpperBound
;
 
Composition:
	// added ?
 	'par' (  global=PortSet 'in')?
 	blocks+=Block ('||' blocks+=Block)*
 	//('|' index=VariableDeclaration 'in' type=RangeType)?
 	'end' ('par')?
 ;
 
Block:
	CompositeBlock | InstanceDeclaration
;

CompositeBlock:
	(local = PortSet ( '->' ) | ( '->' ) )? composition=Composition
;

InstanceDeclaration:
	(local = PortSet ( '->' ) | ( '->' ) )?  instance=ComponentInstance
;

PortSet:
	(
		allPorts?='*' 
	| 
		ports+=Expression (',' ports+=Expression)*
	)
;

ComponentInstance:
	component=[ParameterizedDeclaration]
	//('<|' generics+=GenericInstance (',' generics+=GenericInstance)* '|>')?
	('[' ports+=Expression (',' ports+=Expression)* ']')?
	('(' parameters+=Expression (',' parameters+=Expression)* ')')?
;

//GenericInstance:
//	TypeInstance
//	| ConstantInstance
//	| UnionTagInstance
//	| RecordFieldInstance
//;
//
//TypeInstance:
//	'type' type=Type
//;
//
//ConstantInstance:
//	'const' (const=[ConstantDeclarationUse] | value=LiteralExpression)
//;
//
//UnionTagInstance:
//	(constr0?='constr0' | constr1?='constr1') head=[UnionTagDeclarationUse]
//;
//
//RecordFieldInstance:
//	'field' field=[RecordFieldDeclarationUse]
//;

Expression:
	QuantifiedExpression
;

QuantifiedExpression returns Expression :
	(({AllExpression} 'all'|{ExistsExpression} 'exists') 
		index=VariableDeclaration ('in' type=RangeType)? '.' child=QuantifiedExpression
	) | 
	Conditional
;

Conditional returns Expression :
	Disjunction ('?' {Conditional.condition=current} then=Disjunction ':' else=Disjunction)?
;

Disjunction returns Expression :
	Implication ({Disjunction.left=current} 'or' right=Implication)*
;

Implication returns Expression :
	Conjunction ({Implication.left=current} '=>' right=Implication)?
;

Conjunction returns Expression :
	Comparison ({Conjunction.left = current} 'and' right=Comparison)*
;

Comparison returns Expression :
	Addition (({ComparisonEqual.left=current} '=' 
		| {ComparisonNotEqual.left=current} '<>' 
		| {ComparisonLesser.left=current} '<'
		| {ComparisonLesserEqual.left=current} '<='
		| {ComparisonGreater.left=current} '>'
		| {ComparisonGreaterEqual.left=current} '>='
	) 
		right=Addition
	)?
;

Addition returns Expression :
	Substraction ({Addition.left=current} '+' right=Substraction)*
;

Substraction returns Expression :
	Multiplication ({Substraction.left=current} '-' right=Multiplication)*
;

Multiplication returns Expression:
	Division ({Multiplication.left=current} '*' right=Division)*
;

Division returns Expression:
	Modulo ({Division.left=current} '/' right=Modulo)*
;

Modulo returns Expression:
	UnaryExpression ({Modulo.left=current} '%' right=UnaryExpression)*
;

UnaryExpression returns Expression :
	((({UnaryPlusExpression} '+' 
		| {UnaryMinusExpression} '-'
		| {UnaryNegationExpression} 'not'
		| {UnaryFirstExpression} 'first'
		| {UnaryLengthExpression} 'length'
		| {UnaryCoerceExpression} '$'
		| {UnaryFullExpression} 'full'
		| {UnaryDeQueueExpression} 'dequeue'
		| {UnaryEmptyExpression} 'empty'
	)  child=UnaryExpression ) 
		| 
		Projection)
;

Projection returns Expression:
	AtomicExpression ({Projection.channel=current} '^' 
		field=AtomicExpression )?
		;

// Added to manage the type of current value of a fiacre value during execution		
ValueExpression:
	IdentifierExpression
	| LiteralExpression
	| RecordExpression
	| ArrayExpression
	| QueueExpression
;

AtomicExpression returns Expression:
	IdentifierExpression
	| ReferenceExpression
	| LiteralExpression
	| RecordExpression
	| ArrayExpression
	| QueueExpression
	| EnqueueExpression
	| AppendExpression
	| '(' Expression ')'
;

ReferenceExpression:
	'&' declaration=[ReferenceDeclarationUse]
;

IdentifierExpression:
	// changed order between the first alternative and the second one
	
	(	
		//
		({ConstructionExpression} declaration=[ExpressionDeclarationUse] '('  ( parameters+=Expression (',' parameters+=Expression)* )?  ')')
		|
		(
			(
				declaration=[ExpressionDeclarationUse]
 				(
					('[' {ArrayAccessExpression.child=current} indexes+=Expression (',' indexes+=Expression)*']')
					|
					('.' {RecordAccessExpression.child=current} field=[RecordFieldDeclaration])
				)* 
			)		
		)
	)
;

RecordExpression:
	'{' fields+=FieldExpression (',' fields+=FieldExpression)* '}'
;

FieldExpression:
	//FZ je l'ai repris 
	field=[RecordFieldDeclarationUse] '=' value=Expression // TODO : Inconsistent
;

//ArrayExpression returns Expression :
//	'[' Expression 
//		(
//			{ExplicitArrayExpression.values+=current} (',' values+=Expression)*
//		|
//			({ImplicitArrayExpression.body+=current} '|' index=VariableDeclaration 'in' type=RangeType)
//		)
//	 ']'
//;

ArrayExpression:
	{ArrayExpression} '['  (values+=Expression (',' values+=Expression)*)? ']'
; 
QueueExpression :
	{QueueExpression} '{|' (values+=Expression (',' values+=Expression)*)? '|}'
;

EnqueueExpression :
	'enqueue' '(' element=Expression ',' queue=Expression ')'
;

AppendExpression :
	'append' '(' left=Expression ',' right=Expression ')'
;

LiteralExpression:
	BooleanLiteral
	| NaturalLiteral
;

BooleanLiteral:
	({TrueLiteral} 'true'|{FalseLiteral} 'false')
;

NaturalLiteral:
	value=INT
;

LowerBound:
	NaturalLowerBound
	| DecimalLowerBound
	| VariableLowerBound
;

UpperBound:
	NaturalUpperBound
	| DecimalUpperBound
	| VariableUpperBound
	| InfiniteUpperBound
;

NaturalLowerBound:
	(left?='[' | right?=']') value=INT
;

NaturalUpperBound:
	value=INT (left?='[' | right?=']')
;

DecimalLowerBound:
	(left?='[' | right?=']') value=FLT
;

DecimalUpperBound:
	value=FLT (left?='[' | right?=']')
;

VariableLowerBound:
	(left?='[' | right?=']') variable=[BoundDeclarationUse]
;

VariableUpperBound:
	variable=[BoundDeclarationUse] (left?='[' | right?=']')
;

InfiniteUpperBound:
	{InfiniteUpperBound} '...' '['
;

Requirement:
	'assert' property=[PropertyDeclaration] ('-true' positive=STRING)? ('-false' negative=STRING)?
;

PropertyDeclaration:
	'property' name=ID 'is' property=Property
;

Property:
	QuantifiedProperty
;

QuantifiedProperty returns Property :
	(({AllProperty} 'all'|{ExistsProperty} 'exists') variable=VariableDeclaration 
	'in' type=RangeType '.' child=QuantifiedProperty) 
	| PropertyDisjunction
;

PropertyDisjunction returns Property :
	PropertyImplication ({PropertyDisjunction.left=current} 'or' right=PropertyImplication)*
;

PropertyImplication returns Property :
	PropertyConjunction ({PropertyImplication.left=current} '=>' right=PropertyImplication)?
;

PropertyConjunction returns Property :
	PropertyNegation ({PropertyConjunction.left = current} 'and' right=PropertyNegation)*
;

PropertyNegation returns Property :
	({PropertyNegation} 'not' child=PropertyNegation) | 
	AtomicProperty
;

AtomicProperty returns Property :
	( PatternProperty ) 
	| 
	('(' Property ')')
;
	
PatternProperty :
	LTLPattern | 
	DeadlockFreePattern | 
	InfinitelyOftenPattern | 
	MortalPattern | 
	PresencePattern | 
	AbsencePattern |  
	AlwaysPattern | 
	SequencePattern
;

LTLPattern:
	'ltl' property=LTLUnary
;

DeadlockFreePattern:
	{DeadlockFreePattern} 'deadlockfree'
;

InfinitelyOftenPattern:
	'infinitelyoften' subject=AtomicObservable
;

MortalPattern:
	'mortal' subject=AtomicObservable
;

PresencePattern:
	'present' subject=AtomicObservable
		(
			('lasting' lasting=INT) 
		| 
			(
				('after' after=AtomicObservable) 
				(
					('within' lower=LowerBound ',' upper=UpperBound) 
					| 
					('until' until=AtomicObservable)
				)?
			)
		| 
			(
				('before' before=AtomicObservable) ('within' lower=LowerBound ',' upper=UpperBound)?
			)
		| 
			('between' min=AtomicObservable 'and' max=AtomicObservable)
		)?
;

AbsencePattern:
	'absent' subject=AtomicObservable
		(
			(
				('after' after=AtomicObservable) 
				(
					('within' lower=LowerBound ',' upper=UpperBound) 
					| 
					('until' until=AtomicObservable)
				)?
			)
		| 
			(
				('before' before=AtomicObservable) 
				('for' lower=LowerBound ',' upper=UpperBound)?
			)
		| 
			('between' min=AtomicObservable 'and' max=AtomicObservable)
		)?	
;

AlwaysPattern:
	'always' subject=AtomicObservable
	(
		('before' before=AtomicObservable)
	| 
		('after' after=AtomicObservable ('until' until=AtomicObservable)?)
	| 
		('between' min=AtomicObservable 'and' max=AtomicObservable)
	)?
;

SequencePattern:
	AtomicObservable 
	(
		('leadsto' {LeadsToPattern.subject=current} follower=AtomicObservable
			(
				('before' before=AtomicObservable ('within' lower=LowerBound ',' upper=UpperBound)?)
				|
				('within' lower=LowerBound ',' upper=UpperBound)
				|
				('after' after=AtomicObservable 
					(
						('within' lower=LowerBound ',' upper=UpperBound)
					|
						('until' until=AtomicObservable)	
					)?
				)
				|
				('between' min=AtomicObservable 'and' max=AtomicObservable)
			)?			
		)
	|
		('precedes' {PrecedesPattern.subject=current} follower=AtomicObservable
			(
				('before' before=AtomicObservable)
			| 
				('after' after=AtomicObservable ('until' until=AtomicObservable)?)
			| 
				('between' min=AtomicObservable 'and' max=AtomicObservable)
			)?			
		)
	)
;

LTLProperty :
	LTLQuantified
;

LTLQuantified returns LTLProperty :
	(({LTLAll} 'all'|{LTLExists} 'exists') index=VariableDeclaration 
	'in' type=RangeType '.' child=LTLQuantified) 
	| 
	LTLDisjunction
;

LTLDisjunction returns LTLProperty :
	LTLImplication ({LTLDisjunction.left=current} 'or' right=LTLImplication)*
;

LTLImplication returns LTLProperty :
	LTLConjunction ({LTLImplication.left=current} '=>' right=LTLImplication)?
;

LTLConjunction returns LTLProperty :
	LTLBinary ({LTLConjunction.left = current} 'and' right=LTLBinary)*
;

LTLBinary returns LTLProperty:
	LTLUnary (
		({LTLUntil.left = current} 'until' right=LTLUnary)
		|
		({LTLRelease.left = current} 'release' right=LTLUnary)
		)?
;

LTLUnary returns LTLProperty :
	(({LTLUnaryNegation} 'not' | {LTLUnaryNext} 'next' | {LTLUnaryAlways} '[]' | {LTLUnaryEventually} '<>') operand=LTLUnary) | AtomicLTL
;

AtomicLTL returns LTLProperty :
	{LTLVariable} declaration=[PropertyDeclarationUse]
	| ObservableEvent 
	| '(' LTLProperty ')'
;

StateEvent:
	EnterStateEvent 
	|
	LeaveStateEvent
;

EnterStateEvent:
	'enter' subject=AtomicObservable
;

LeaveStateEvent:
	'leave' subject=AtomicObservable
;

Observable :
	ObservableDisjunction
;

ObservableDisjunction returns Observable :
	ObservableImplication ({ObservableDisjunction.left=current} 'or' right=ObservableImplication)*
;

ObservableImplication returns Observable :
	ObservableConjunction ({ObservableImplication.left=current} '=>' right=ObservableImplication)?
;

ObservableConjunction returns Observable :
	ObservableNegation ({ObservableConjunction.left = current} 'and' right=ObservableNegation)*
;

ObservableNegation returns Observable :
	({ObservableNegation} 'not' child=ObservableNegation) | AtomicObservable 
;

AtomicObservable returns Observable :
	'(' Observable ')' |
	ObservableEvent
;

ObservableEvent :
	PathEvent | StateEvent
;

PathEvent :
	path=Path item=Subject
;

Path:
	(items+=PathItem '/')+
;

PathItem: 
	NaturalItem | NamedItem	
;

NaturalItem:
	value=INT
;

NamedItem:
	declaration=[PathDeclarationUse]
;

Subject:
	StateSubject | ValueSubject | TagSubject | EventSubject
;

StateSubject:
	'state' state=[StateDeclaration]
;

ValueSubject:
	'value' value=AtomicExpression
;

TagSubject:
	'tag' tag=[TaggedStatement]
;

EventSubject:
	'event' event=ID
;

terminal INT returns ecore::EInt : ('0' .. '9')+;

terminal ID returns ecore::EString : (('a' .. 'z') | ('A' .. 'Z') | '_') (('a' .. 'z') | ('A' .. 'Z') | ('0' .. '9') | '_')* ;

terminal FLT returns ecore::EFloat : INT '.' INT;