/**
 * Copyright (c) 2010 - 2015 committers of YAKINDU and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * Contributors:
 * 	committers of YAKINDU - initial API and implementation
 * 
 */
grammar org.yakindu.base.expressions.Expressions with org.eclipse.xtext.common.Terminals

import "http://www.eclipse.org/emf/2002/Ecore" as ecore
import "http://www.yakindu.org/base/types/2.0.0" as types
import "http://www.yakindu.org/base/expressions/Expressions"

Expression:
	AssignmentExpression;

AssignmentExpression returns Expression:
	ConditionalExpression ({AssignmentExpression.varRef=current} operator=AssignmentOperator
	expression=ConditionalExpression)*;

ConditionalExpression returns Expression:
	LogicalOrExpression ({ConditionalExpression.condition=current} '?' trueCase=LogicalOrExpression ':'
	falseCase=LogicalOrExpression)?;

LogicalOrExpression returns Expression:
	LogicalAndExpression ({LogicalOrExpression.leftOperand=current} LogicalOrOperator
	rightOperand=LogicalAndExpression)*;

LogicalAndExpression returns Expression:
	LogicalNotExpression ({LogicalAndExpression.leftOperand=current}
	LogicalAndOperator rightOperand=LogicalNotExpression)*;

LogicalNotExpression returns Expression:
	BitwiseXorExpression | {LogicalNotExpression} LogicalNotOperator
	operand=BitwiseXorExpression;

BitwiseXorExpression returns Expression:
	BitwiseOrExpression ({BitwiseXorExpression.leftOperand=current} BitwiseXOrOperator
	rightOperand=BitwiseOrExpression)*;

BitwiseOrExpression returns Expression:
	BitwiseAndExpression ({BitwiseOrExpression.leftOperand=current} BitwiseOrOperator
	rightOperand=BitwiseAndExpression)*;

BitwiseAndExpression returns Expression:
	LogicalRelationExpression ({BitwiseAndExpression.leftOperand=current} BitwiseAndOperator
	rightOperand=LogicalRelationExpression)*;

LogicalRelationExpression returns Expression:
	ShiftExpression
	({LogicalRelationExpression.leftOperand=current} operator=RelationalOperator
	rightOperand=ShiftExpression)*;

ShiftExpression returns Expression:
	NumericalAddSubtractExpression ({ShiftExpression.leftOperand=current} operator=ShiftOperator
	rightOperand=NumericalAddSubtractExpression)*;

NumericalAddSubtractExpression returns Expression:
	NumericalMultiplyDivideExpression
	({NumericalAddSubtractExpression.leftOperand=current}
	operator=AdditiveOperator
	rightOperand=NumericalMultiplyDivideExpression)*;

NumericalMultiplyDivideExpression returns Expression:
	NumericalUnaryExpression
	({NumericalMultiplyDivideExpression.leftOperand=current}
	operator=MultiplicativeOperator
	rightOperand=NumericalUnaryExpression)*;

NumericalUnaryExpression returns Expression:
	TypeCastExpression | {NumericalUnaryExpression}
	operator=UnaryOperator operand=TypeCastExpression;

TypeCastExpression returns Expression:
	PrimaryExpression (({TypeCastExpression.operand=current} 'as') type=[types::Type|QID])*;

PrimaryExpression returns Expression:
	PrimitiveValueExpression
	| FeatureCall
	| ParenthesizedExpression;

PrimitiveValueExpression returns Expression:
	{PrimitiveValueExpression} value=Literal;

FeatureCall returns Expression:
	ElementReferenceExpression ({FeatureCall.owner=current} '.' feature=[ecore::EObject]
	(=> operationCall?= '('(args+=Expression (',' args+=Expression)*)?')'
		|
	=> (arrayAccess ?= '[' arraySelector+=Expression ']') => ('[' arraySelector+=Expression ']')* 
	)?)*;

ElementReferenceExpression returns Expression:
	{ElementReferenceExpression} reference=[ecore::EObject|ID]
	(=> operationCall?='('	(args+=Expression (',' args+=Expression)*)?	')' 
		|
	=> (arrayAccess ?= '[' arraySelector+=Expression ']') => ('[' arraySelector+=Expression ']')*
	)?;

ParenthesizedExpression returns Expression:
	{ParenthesizedExpression} '(' expression=Expression ')';

Literal:
	BoolLiteral | IntLiteral | HexLiteral | DoubleLiteral | FloatLiteral | StringLiteral | NullLiteral;

BoolLiteral:
	{BoolLiteral} value=BOOL;

IntLiteral:
	{IntLiteral} value=INT;

DoubleLiteral:
	{DoubleLiteral} value=DOUBLE;

FloatLiteral:
	{FloatLiteral} value=FLOAT;

HexLiteral:
	{HexLiteral} value=HEX;

StringLiteral:
	{StringLiteral} value=STRING;

NullLiteral:
	{NullLiteral} 'null';

LogicalAndOperator:
	'&&';

LogicalOrOperator:
	'||';

LogicalNotOperator:
	'!';

BitwiseXOrOperator:
	'^';

BitwiseOrOperator:
	'|';

BitwiseAndOperator:
	'&';

enum AssignmentOperator:
	assign='='
	| multAssign='*='
	| divAssign='/='
	| modAssign='%='
	| addAssign='+='
	| subAssign='-='
	| leftShiftAssign='<<='
	| rightShiftAssign='>>='
	| andAssign='&='
	| xorAssign='^='
	| orAssign='|=';

enum ShiftOperator:
	left='<<'
	| right='>>';

enum AdditiveOperator:
	plus='+' | minus='-';

enum MultiplicativeOperator:
	mul='*' | div='/' | mod='%';

enum UnaryOperator:
	positive='+' | negative='-' | complement='~';

enum RelationalOperator:
	smaller='<' | smallerEqual='<=' | greater='>' | greaterEqual='>=' |
	equals='==' | notEquals='!=';

terminal BOOL returns ecore::EBoolean:
	'true' | 'false' | 'yes' | 'no';

terminal HEX returns ecore::EInt:
	('0') ('x' | 'X') ('0'..'9' | 'a'..'f' | 'A'..'F')+;

terminal DOUBLE returns ecore::EDouble:
	(INT '.' INT) ('e' ('-' | '+') INT)? ('d' | 'D')?;

terminal FLOAT returns ecore::EFloat:
	(INT '.' INT) ('e' ('-' | '+') INT)? ('f' | 'F')?;

QID:
	ID ('.' ID)*;
