/**
 * Copyright (c) 2011-2012 Eclipse contributors and others.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v2.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v20.html
 */
grammar org.eclipse.emf.ecore.xcore.Xcore
  with org.eclipse.xtext.xbase.Xbase

import "http://www.eclipse.org/emf/2002/Ecore"
import "http://www.eclipse.org/emf/2002/GenModel" as genmodel
import "http://www.eclipse.org/xtext/xbase/Xbase" as xbase
import "http://www.eclipse.org/xtext/common/JavaVMTypes" as javaVMTypes
import "http://www.eclipse.org/xtext/xbase/Xtype" as xtype
import "http://www.eclipse.org/emf/2011/Xcore"

XPackage returns XPackage:
	{XPackage}
	(annotations+=XAnnotation)*
	'package'
	name = QualifiedName
	(importDirectives += XImportDirective)*
	(annotationDirectives += XAnnotationDirective)*
	(classifiers += XClassifier)*
;

XAnnotation:
	'@' source=[XAnnotationDirective|XQualifiedName]
	('(' details+=XStringToStringMapEntry (',' details+=XStringToStringMapEntry)* ')')?
;

XStringToStringMapEntry:
	key=QualifiedName
	'='
	value=STRING
;

XImportDirective:
	{XImportDirective}
	'import' (importedNamespace=QualifiedNameWithWildcard | importedObject=[EObject|QualifiedName])
;

XAnnotationDirective:
	=>('annotation' sourceURI=STRING) 'as' name=ValidID
;

XClassifier:
	XClass |
	XDataType |
	XEnum
;

XDataType:
	(annotations+=XAnnotation)*
	'type' name = ID
	('<' typeParameters+=XTypeParameter (',' typeParameters+=XTypeParameter)* '>')?
	'wraps' instanceType=JvmTypeReference
	(
	  /*
	   * In scope for create should be what's visible in XyzFactoryImpl and 'this' will denote the literal value.
	   * The block expression must yield null or an instance of the wrapped type.
	   */
	  (serializable?='create' createBody=XBlockExpression)? &
	  /*
	   * In scope for create should be what's visible in XyzFactoryImpl
	   * and 'this' will denote an instance of the wrapped type.
	   * The block expression must yield a java.lang.String.
	   */
	  ('convert' convertBody=XBlockExpression)?
	)
;

XEnum:
	(annotations+=XAnnotation)*
	'enum' name = ID
	'{'
	  (literals+=XEnumLiteral ((',')? literals+=XEnumLiteral)*)?
	'}'
;

XEnumLiteral:
	(annotations+=XAnnotation)*
    name=ID
    ('as' literal=STRING)?
    ('=' value=SignedInt)?
;

SignedInt returns EInt :
	'-'? INT
;

XClass:
	{XClass}
	(annotations+=XAnnotation)*
	((abstract?='abstract'? 'class') | interface?= 'interface') name = ID
	('<' typeParameters+=XTypeParameter (',' typeParameters+=XTypeParameter)* '>')?
	('extends' superTypes+=XGenericType (',' superTypes+=XGenericType)*)?
	('wraps' instanceType=JvmTypeReference) ?
	'{'
	   (members+=XMember)*
	'}'
;

XMember:
	XOperation |
	XAttribute |
	XReference
;

XAttribute:
	{XAttribute}
	(annotations+=XAnnotation)*
	(
	  (unordered?='unordered')? &
	  (unique?='unique')? &
	  (readonly?='readonly')? &
	  (transient?='transient')? &
	  (volatile?='volatile')? &
	  (unsettable?='unsettable')? &
	  (derived?='derived')? &
	  (iD?='id')?
	)
    type=XGenericType multiplicity=XMultiplicity?
    name=ID
    ('=' defaultValueLiteral=STRING)?
	/*
	 * In scope for getBody should be what's visible in AbcImpl
	 * and 'this' will denote an instance of the feature's type.
	 * The block expression must yield a value of the feature's type.
	 */
	(('get' getBody=XBlockExpression)? &
	 ('set' setBody=XBlockExpression)? &
	 ('isSet' isSetBody=XBlockExpression)? &
	 ('unset' unsetBody=XBlockExpression)?)
;

XReference:
	{XReference}
	(annotations+=XAnnotation)*
	((containment?='contains' resolveProxies?='resolving'?) |
	 (resolveProxies?='resolving' containment?='contains') |
	 (container?='container' resolveProxies?='resolving'?) |
	 (resolveProxies?='resolving' container?='container') |
	 ('refers' local?='local'?) |
	 (local?='local' 'refers'))
	(
	  (unordered?='unordered')? &
	  (unique?='unique')? &
	  (readonly?='readonly')? &
	  (transient?='transient')? &
	  (volatile?='volatile')? &
	  (unsettable?='unsettable')? &
	  (derived?='derived')?
	)
	type=XGenericType
	multiplicity=XMultiplicity?
    name=ID
    (
      'opposite' opposite=[genmodel::GenFeature|ValidID]
    )?
    (
      'keys' keys+=[genmodel::GenFeature|ValidID] (',' keys+=[genmodel::GenFeature|ValidID])*
    )?
	/*
	 * In scope for getBody should be what's visible in AbcImpl
	 * and 'this' will denote an instance of the feature's type.
	 * The block expression must yield a value of the feature's type.
	 */
	(('get' getBody=XBlockExpression)? &
	 ('set' setBody=XBlockExpression)? &
	 ('isSet' isSetBody=XBlockExpression)? &
	 ('unset' unsetBody=XBlockExpression)?)
;

XOperation:
	{XOperation}
	(annotations+=XAnnotation)*
	'op'
	(
	  unordered?='unordered' unique?='unique'? |
	  unique?='unique' unordered?='unordered'?
	)?
	('<' typeParameters+=XTypeParameter (',' typeParameters+=XTypeParameter)* '>')?
	(type=XGenericType | 'void')
	multiplicity=XMultiplicity?
	name=ID
	'(' (parameters+=XParameter (',' parameters+=XParameter)*)? ')'
	('throws' exceptions+=XGenericType (',' exceptions+=XGenericType)*)?
	/*
	 * This is the logic for the operation.
	 * How are we going to resolve all references that are in scope for Xbase language?
	 * Will things like variables that are actually there in generated in the Impl class be accessible directly?
	 */
	(body=XBlockExpression)?
;

XParameter:
	(annotations+=XAnnotation)*
	(
	  unordered?='unordered' unique?='unique'? |
	  unique?='unique' unordered?='unordered'?
	)?
    type=XGenericType
    multiplicity=XMultiplicity?
    name=ID
;

XTypeParameter :
	(annotations+=XAnnotation)*
	name=ID ('extends' bounds+=XGenericType ('&' bounds+=XGenericType)*)?
;

XMultiplicity returns XMultiplicity:
	'['
	('?' | '*' | '+' | (INT ('..' (INT | '?' | '*'))?))?
	']'
;

@Override 
XBlockExpression returns xbase::XBlockExpression:
 {xbase::XBlockExpression}
 '{'
  (expressions+=XExpressionOrVarDeclaration ';'?)*
 '}'
;

XGenericType returns XGenericType:
  type=[genmodel::GenBase|XQualifiedName] (=>'<' typeArguments+=XGenericTypeArgument (',' typeArguments+=XGenericTypeArgument)* '>')?
;

XGenericTypeArgument returns XGenericType :
	XGenericType |
	XGenericWildcardTypeArgument
;

XGenericWildcardTypeArgument returns XGenericType :
   {XGenericType}
   '?' ('extends' upperBound=XGenericType | 'super' lowerBound=XGenericType)?
;

XQualifiedName:
	XID ('.' XID)*
;

XID:
	ID | 'get' | 'isSet' | 'set' | 'unset'
;

@Override 
ValidID:
	XID | 'void'
;

@Override 
FeatureCallID:
	ValidID | 'abstract' | 'annotation' | 'as' | 'class' | 'container' | 'contains' | 'convert' | 'create' | 'derived' | 'enum' | 'extends' | 'extension' | 'id' | 'import' | 'keys' |
	'interface'| 'local' | 'op' | 'opposite' | 'package' | 'readonly' | 'refers' | 'resolving' | 'static' | 'throws' | 'transient' | 'unique' | 'unordered' | 'unsettable'|
	'volatile' | 'wraps'
;
