All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.integratedmodelling.kim.Kim.xtext Maven / Gradle / Ivy

grammar org.integratedmodelling.kim.Kim with org.eclipse.xtext.common.Terminals

generate kim "http://www.integratedmodelling.org/kim/Kim"

Model:
	namespace=Namespace statements+=Statement*;

	// expression syntax: whatever is in square brackets (no folding for now).
// TODO use lexer rule to parse expressions with nested brackets.
terminal EXPR:
	'[' ('\\' ('b' | 't' | 'n' | 'f' | 'r' | 'u' | ']' | '\\') | !('\\' | ']'))* ']';

	// ID admitting hyphens, colons and UTF-8 non-control chars
terminal IDH:
	('a'..'z' | 'A'..'Z' | '_' | "\u00a1".."\u00ff" | '$' | '#') ('a'..'z' | 'A'..'Z' | '_' | '0'..'9' | '.' | '-' | ':' |
	'$' | '#' | '@' | "\u00a1".."\u00ff")*;

	// ID starting with '@' is an annotation ID
terminal ANNOTATION_ID:
	'@' ('a'..'z' | 'A'..'Z' | '_' | "\u00a1".."\u00ff" | '$' | '#') ('a'..'z' | 'A'..'Z' | '_' | '0'..'9' | '-' | ':' |
	'$' | '#' | '@' | "\u00a1".."\u00ff")*;

ValidID:
	IDH /* (=> ('-'|':'|'.') IDH)* */;

Metadata:
	{Metadata} '{' (ids+=ValidID values+=(LiteralOrID | Metadata | List))* '}';

terminal SINT:
	'-' ('0'..'9')+;

terminal GNUMBER:
	'-'? ('0'..'9')* '.' ('0'..'9') ('0'..'9')*;

NUMBER:
	int=INT |
	sint=SINT |
	float=GNUMBER;

List:
	{List} '(' contents+=(LiteralOrIDOrListKW | List)* ')';

Literal:
	number=NUMBER | string=STRING | boolean=('true' | 'false');

LiteralOrIDOrListKW returns Literal:
	number=NUMBER | string=STRING | boolean=('true' | 'false') | from=NUMBER 'to' to=NUMBER | id=ValidID | id='as' |
	comma?=',';

LiteralOrID returns Literal:
	number=NUMBER | string=STRING | boolean=('true' | 'false') | id=ValidID;

	/*
 * enums
 */
REL_OPERATOR:
	(gt?='>' |
	lt?='<' |
	eq?='=' |
	ne?='!=' |
	le?='<=' |
	ge?='>=');

KeyValuePair:
	key=ValidID (interactive?='?=' | '=') value=Value;

ParameterList:
	singleValue=Value |
	pairs+=KeyValuePair (=> ',' pairs+=KeyValuePair)*;

	/*
 * ---------------------------------------
 * Unit of measurement re: isr-108, parseable by Java
 * TODO implement expression syntax and provide validator
 * ---------------------------------------
 */
UnitElement:
	id=ValidID |
	num=NUMBER |
	'(' unit=Unit ')';

enum UnitOp:
	OVER='/' | CARET='^' | STAR='*';

Unit:
	{Unit} (root=UnitElement)? (=> (connectors+=UnitOp) (units+=UnitElement))*;

Currency:
	id=ID ('@' year=INT) |
	concept=ValidID;

Value:
	literal=Literal |
	function=Function |
	expr=EXPR |
	id=ValidID |
	list=List |
	null?='unknown';

	/**
 * Carefully selected keywords to define a concept, which enable automatic definition of
 * fairly complex semantics and validation against upper ontologies. For now implement
 * physical properties, value concepts and basic agent types re: DOLCE types.
 * 
 * A similar thing could be done for properties
 * 
 * This is a lot of keywords, although it's probably good to protect these names from
 * being used as identifiers in anything.
 */
CONCEPT:
	'quality' |
	'class' |
	'quantity' |
	'configuration' |
	EXTENSIVE_PROPERTY |
	INTENSIVE_PROPERTY |
	AGENT_TYPE |
	TRAIT;

TRAIT:
	'ordering' |
	'attribute' |
	'identity' |
	'role' |
	'realm' |
	'domain';

EXTENSIVE_PROPERTY:
	'energy' |
	'entropy' |
	'length' |
	'mass' |
	'volume' |
	'weight' |
	'money' |
	'duration' |
	'area';

INTENSIVE_PROPERTY:
	'acceleration' |
	'priority' |
	'electric-potential' |
	'charge' |
	'resistance' |
	'resistivity' |
	'pressure' |
	'angle' |
	'velocity' |
	'temperature' |
	'viscosity';

AGENT_TYPE:
	'thing' |
	'process' |
	'agent' |
	'event';

	/*
 * ------------------------------------------------------------------------------------------
 * Ontology language - basically a more intuitive and imperative OW2L/Manchester syntax. Does not
 * cover all of OWL2 yet, but should be plenty for modeling. 
 * 
 * deniable is for traits only. If a trait is deniable, 'not Trait' is a trait (of not being Trait).
 * if not deniable, 'not Trait' means being any of the other concrete traits; if there is only one 
 * concrete trait it's an error. If there are two, it means being the other.
 * ------------------------------------------------------------------------------------------
 */
ConceptStatement:
	((abstract?='abstract')? &
	(deniable?='deniable')? &
	(specifier=('deliberative' | 'interactive' | 'reactive' | 'subjective' | 'objective'))?)

	/*
         * root only allowed after 'domain' and once in a domain project.
         * 'identified as' should simply declare an ALIAS for an authority concept. With that a user can declare and name
         * an authority concept, which does not carry the name beyond the usage in namespaces. This guarantees interoperability
         * across applications.
         * 
         * Concept name is stored in rdfs:label annotation but is indexed by the ontologies and it 
         * can be used as an alias in concept retrieval. In a future release we should enable languages
         * (named X in en, Y in es) and allow "jargon files" for external translation. Namespaces should
         * be able to state their language and tune on one of these (and only one) while the "official"
         * label (without 'in') remains available to all.
         * 
         */
	concept=CONCEPT (root?='root' | (declaration=ValidID ('identified' 'as' identifier=STRING 'by' authority=ValidID)?)
	('named' name=(ValidID | STRING))?)
	(docstring=STRING)? &

	/*
			   * child of. Allows "nothing" as the only root-level parent for very special purposes.
			   * Using 'extends' allows to reuse the subclasses of the extended concept and prevents 
			   * adding children of its own (a 'foster parent' of sorts). It should only be permitted for 
			   * subjective orderings.
			   */
	(('is' | extension?='extends') (nothing?='nothing' | parents=ConceptList))? &

	/*
               * traits contextualized. Only applicable to
               * classes. Abstract class must declare exposed traits; concrete class must
               * provide matching values using 'with'
               */
	(('exposes' contextualizedTraits=DerivedConceptList) |
	(specific?='with' contextualizedTraits=NegatableDerivedConceptList))? &

	/*
               * requires identity, context or realm.
               */
	('requires' requirement=IdentityRequirementList)? &

	/*
               * for traits: describes quality
               */
	('describes' describedQuality=DerivedConceptDeclaration)? &

	/*
               * Traits that ARE inherited by this concept. Long version of   for
               * reading clarity if no 'within' part is given.
               * 
               * If the 'within' part is given, the concept is not given any traits but the specified
               * traits are inherited by the observables of any observation of this concept made within
               * those contexts. This will add a restriction to the restrictedObservable rather than 
               * modify this concept.
               * 
               * Not allowed for class (types) which should use 'contextualizes'.
               */
	('inherits' actuallyInheritedTraits=ConceptList)? &

	/*
               * Roles within a context. The concept is not given any traits but the specified
               * traits are inherited by the observables of any observation of this concept made within
               * those contexts. This will add a restriction to the restrictedObservable rather than 
               * modify this concept, and Thinklab will use the restrictions to attribute traits
               * after resolution.
               * 
               * 'in' specifies a context (often a process if role is dynamic but can be a subject or event)
               * 'for' (optional) specifies a target subject/event type within the context; the context itself
               *       is used if not specified.
               */
	('has' 'role' roles=ConceptList ('for' targetObservable=ConceptList)? 'in' restrictedObservable=ConceptList)? &

	/*
               * for processes: confer given trait(s) to (participant subjects).
               */
	('confers' conferredTraits=ConceptList ('to' conferredTargets=ConceptList)?)? &

	/*
               * for processes: creates (event|subject) in context.
               */
	('creates' creates=ConceptList)? &

	/*
               * traits can specify the set of allowed targets here. Also allows qualities and
               * processes to specify their inherent target.
               */
	('applies' 'to' traitTargets=ConceptList)? &

	/*
     * for processes; lists qualities affected;
     * for deliberative agents: lists the subject types whose states this can
     * modify.
     */
	('affects' qualitiesAffected=ConceptList)? &

	/*
               * equivalence
               */
	('equals' equivalences=ConceptList)? &
	('has' (disjoint?='disjoint')? 'children' children=ConceptList)? &
	(restrictions+=RestrictionStatement*)? &
	('with' 'metadata' metadata=Metadata)?;

	/*
 * 'concept' is a reference to a concept that must have been seen before. Can only add children and scoped roles.
 */
ContextualRedeclaration returns ConceptStatement:
	redeclaration?='concept' redeclared=ConceptDeclaration
	(('has' 'role' roles=ConceptList ('for' targetObservable=ConceptList)? 'in' restrictedObservable=ConceptList)? &
	('has' (disjoint?='disjoint')? 'children' children=ConceptList)?);

	/*
  * used for child definitions so that subconcept can be defined without having
  * to repeat the concept keyword.
  */
SubConceptStatement returns ConceptStatement:
	annotations+=Annotation* (abstract?='abstract')?
	(declaration=ValidID ('identified' 'as' identifier=STRING 'by' authority=ValidID)? ('named' name=(ValidID | STRING))?)
	(docstring=STRING)? &
	/*
			   * child of
			   */
	('is' parents=ConceptList)? &

	/*
               * requires identity, context or realm.
               */
	('requires' requirement=IdentityRequirementList)? &

	/*
               * Traits that ARE inherited by this concept. Long version of   for
               * reading clarity if no 'within' part is given.
               * 
               * If the 'within' part is given, the concept is not given any traits but the specified
               * traits are inherited by the observables of any observation of this concept made within
               * those contexts. This will add a restriction to the restrictedObservable rather than 
               * modify this concept.
               */
	('inherits' actuallyInheritedTraits=ConceptList)? &

	/*
               * Roles within a context. The concept is not given any traits but the specified
               * traits are inherited by the observables of any observation of this concept made within
               * those contexts. This will add a restriction to the restrictedObservable rather than 
               * modify this concept, and Thinklab will use the restrictions to attribute traits
               * after resolution.
               */
	('has' 'role' roles=ConceptList ('for' targetObservable=ConceptList)? 'in' restrictedObservable=ConceptList)? &


	/*
     * for processes; lists qualities affected;
     * for deliberative agents: lists the subject types whose states this can
     * modify.
     */
	('affects' qualitiesAffected=DerivedConceptList)? &

	/*
               * for processes: creates (event|subject) in context.
               */
	('creates' creates=ConceptList)? &

	/*
               * for traits, qualities, processes to define their allowed target (trait or inherency).
               */
	('applies' 'to' traitTargets=ConceptList)? &

	/*
               * for processes: confer given trait(s) to (participant subjects). 
               */
	('confers' conferredTraits=ConceptList ('to' (targetType=('source' | 'target'))? (conferredTargets=ConceptList)?)?)? &

	/*
               * equivalence
               */
	('equals' equivalences=ConceptList)? &
	(restrictions+=RestrictionStatement*)? &
	('has' (disjoint?='disjoint')? 'children' children=ConceptList)? &
	('with' 'metadata' metadata=Metadata)?;

IdentityRequirementList:
	requirement+=IdentityRequirement (',' requirement+=IdentityRequirement)*;

IdentityRequirement:
	('identity' | 'attribute' | 'realm' | 'extent' | 'authority') identity=ConceptList;

ConceptIdentifier: 
	(negated?=('no' | 'not'))? id=ValidID;

/**
 * Referring to derived concepts created by built-in observations. 
 */
DerivedConceptIdentifier returns ConceptIdentifier:
	(presence?='presence' 'of' id=ValidID) | 
	(count?='count' 'of' id=ValidID) | 
	(distance?='distance' ('from' | 'to') id=ValidID) | 
	(probability?='probability' 'of' id=ValidID) | (uncertainty?='uncertainty' 'of' id=ValidID) |
	(proportion?=('proportion' | 'percentage') 'of' id=ValidID 'in' id2=ValidID) | 
	(ratio?='ratio' 'of' id=ValidID 'to' id2=ValidID) | 
	(value?='value' 'of' id=ValidID 'over' id2=ValidID) | id=ValidID;

/*
 * concept with optional traits. Accepts 'parent' only in child lists for orderings 
 * and 'down to' only in 'exposes' statements for concrete classes.
 */
ConceptDeclaration:
	(parent?='parent') | 
	ids+=ConceptIdentifier (=> ids+=ConceptIdentifier)* ('of' inherent+=ConceptIdentifier*)?
		(outerContext=OuterContext)? ('down' 'to' downTo=ValidID)?;

/*
 * concept with optional traits. Accepts 'parent' only in child lists for orderings 
 * and 'down to' only in 'exposes' statements for concrete classes.
 */
DerivedConceptDeclaration returns ConceptDeclaration:
	(parent?='parent') | 
	ids+=DerivedConceptIdentifier (=> ids+=DerivedConceptIdentifier)* ('of' inherent+=ConceptIdentifier*)?
		(outerContext=OuterContext)? ('down' 'to' downTo=ValidID)?;

/**
 * Same with possible negation in front.
 */
NegatableConceptDeclaration returns ConceptDeclaration:
	((negated?=('no' | 'not')) | (unknown?=('unknown')) | (all?=('all')))? ids+=ConceptIdentifier (=>
	ids+=ConceptIdentifier)* ('of' inherent+=ConceptIdentifier*)? (outerContext=OuterContext)?;

/*
 * Same with compound qualities.
 */
NegatableDerivedConceptDeclaration returns ConceptDeclaration:
	((negated?=('no' | 'not')) | (unknown?=('unknown')) | (all?=('all')))? ids+=DerivedConceptIdentifier (=>
	ids+=DerivedConceptIdentifier)* ('of' inherent+=ConceptIdentifier*)? (outerContext=OuterContext)?;

OuterContext:
	'within' ids+=ConceptIdentifier (=> ids+=ConceptIdentifier)*;

	/*
 * Ultra-simple restriction statements:
 *
 * uses [only] CCC [for PPP]; // PPP can be a property or a concept
 * uses at [least|most] 1 CCC [for PPP]
 * uses exactly 1 CCC [for PPP]
 * uses 120 for PPP // data property
 *
 * uses = has; requires = functional has; contains = part-of  
 * 
 * if PPP is a concept (much more intuitive), must be restricting a known one and hasPPP is created (or used).
 * 
 * Also hosts the 'uses authority' restriction which is only accepted by domains.
 * 
 */
RestrictionStatement:
	relType=('uses' | 'has' | 'contains') relDefs=RestrictionDefinitionList | 
	'uses' 'authority' authorities+=ValidID (=> ',' authorities += ValidID)* | 
	'uses' value=Literal literal?='for' (subject=ValidID | '(' statement=PropertyStatement ')');

RestrictionDefinitionList:
	definitions+=RestrictionDefinition (',' definitions+=RestrictionDefinition)*;

RestrictionDefinition:
	(only?='only' | none?='no' | ((exactly?='exactly' | ('at' atLeast?='least') | ('at' atMost?='most')) howmany=NUMBER))?
	(source=ValidID | dataType=DataType) ('inheriting' traitType=ValidID)? (('for' | 'as') (subject=ValidID))?;

	/*
 * data property are distinguished from object properties by having a type instead
 * of a range. So the minimum property spec is of an object property pointing to owl:Thing.
 * Properties can be chained like concepts - no repetition of keyword and qualifiers for 
 * subsequent ones.
 * 
 */
PropertyStatement:
	(abstract?='abstract')? (modifiers=ModifierList)? 'relationship' id=ValidID (docstring=STRING)? ('is'
	parents=PropertyList)? (('links' domain=ConceptList 'to' range=ConceptList | 'applies' 'to' domain=ConceptList
	(('with' 'range' range=ConceptList) | ('with' data?='type' dataType=DataType))?)? & ('requires'
	requirement=IdentityRequirementList)? & ('inherits' actuallyInheritedTraits=ConceptList)? & ('has'
	(disjoint?='disjoint')? 'children' children=PropertyList)? & ('inverse' 'of' inverse=ValidID)?) ('with' 'metadata'
	metadata=Metadata)? | (abstract?='abstract')? annotation?='annotation' id=ValidID ('is' parents=PropertyList)?
	(('with' 'type' dataType=DataType)? & ('has' (disjoint?='disjoint')? 'children' children=PropertyList)? & ('inverse'
	'of' inverse=ValidID)?) ('with' 'metadata' metadata=Metadata)?;

SubPropertyStatement returns PropertyStatement:
	annotations+=Annotation* (abstract?='abstract')? id=ValidID (docstring=STRING)? ('is' parents=PropertyList)? (('links'
	domain=ConceptList 'to' range=ConceptList | 'applies' 'to' domain=ConceptList (('with' 'range' range=ConceptList) |
	('with' data?='type' dataType=DataType))?)? & ('requires' requirement=IdentityRequirementList)? & ('inherits'
	actuallyInheritedTraits=ConceptList)? & ('has' (disjoint?='disjoint')? 'children' children=PropertyList)? & ('inverse'
	'of' inverse=ValidID)?) ('with' 'metadata' metadata=Metadata)?;

	/**
 * TODO needs either a comma or a | for intersection/union
 */
ConceptList:
	(concept+=ConceptDeclaration | ('(' definitions+=SubConceptStatement ')')) (conjunctions+=(',' | '|')
	(concept+=ConceptDeclaration | ('(' definitions+=SubConceptStatement ')')))*;

DerivedConceptList returns ConceptList:
	(concept+=DerivedConceptDeclaration | ('(' definitions+=SubConceptStatement ')')) (conjunctions+=(',' | '|')
	(concept+=DerivedConceptDeclaration | ('(' definitions+=SubConceptStatement ')')))*;

NegatableConceptList returns ConceptList:
	(concept+=NegatableConceptDeclaration) (=> ',' concept+=NegatableConceptDeclaration)*;

NegatableDerivedConceptList returns ConceptList:
	(concept+=NegatableDerivedConceptDeclaration) (=> ',' concept+=NegatableDerivedConceptDeclaration)*;

PropertyList:
	(property+=ValidID | ('(' definitions+=SubPropertyStatement ')')) (conjunctions+=(',' | '|') (property+=ValidID | ('('
	definitions+=SubPropertyStatement ')')))*;

ModifierList:
	modifier+=PropertyModifier (modifier+=PropertyModifier)*;

	/**
 * Apart from abstract, properties can only be functional or structural. The meaning of
 * 'functional' clashes with the DL meaning: here it means that its model must be a process
 * model. Structural properties can just exist without a process incarnating them. To define
 * a functional property for a concept, use 'requires' ... 'for' . 
 */
enum PropertyModifier:
	FUNCTIONAL='functional' |
	BIDIRECTIONAL='bidirectional' |
	UNIDIRECTIONAL='unidirectional' |
	STRUCTURAL='structural';

	/*
 * a few less and a few more than OWL.
 * TODO see what we want to add. The less keywords, the better.
 * We should also make it possible to add datatypes.
 */
enum DataType:
	TEXT='text' |
	INTEGER='integer' |
	FLOAT='float' |
	DOUBLE='double' |
	BOOLEAN='boolean' |
	DATE='date' |
	POINT='point' |
	LINE='line' |
	POLYGON='polygon';

Annotation:
	id=ANNOTATION_ID ('(' parameters=ParameterList? ')')?;

QualifiedNameList:
	names+=ValidID (=> ',' names+=ValidID)*;

Function:
	id=ValidID '(' parameters=ParameterList? ')';

Contextualization:
	(integrated?='aggregated')? 'over' (domain+=FunctionOrID) (=> ',' (domain+=FunctionOrID))* (actions+=Action (=> ','
	actions+=Action)*)? | ('on' (initialization?='definition' | resolution?='resolution' | event=ConceptDeclaration)
	(actions+=Action (=> ',' actions+=Action)*)?);

FunctionOrID:
	function=Function | functionId=ValidID;

Action:
/*
     * 'set' assumes that the dependencies will be enough to compute the value; 'change' will
     * require the observable to be resolved externally.
     * 
     * fv 10/26/15: adding 'using' to specify alternative language/extension
     *              support external script (extension used to attribute language) when Value is a literal string, which is never
     * 				a good return value.
     */
	(change?='change' | set?='set') (changed=ValidID)? 'to' value=Value ('using' extension=ValidID)? (=>
	condition=Condition)? | integrate?='integrate' (changed=ValidID)? 'as' value=Value ('using' extension=ValidID)? (=>
	condition=Condition)? | do?='do' value=Value ('using' extension=ValidID)? (=> condition=Condition)? |
	/*
	 * 'move away' sounds a lot nicer than 'die'
	 */
	move?='move' (where=Value | away?='away') (=> condition=Condition)?;

	/*
 * Namespace - entry point of all files. Only interactive session may start without this statement.
 * A namespace may be a scenario - if so, nothing changes except its models will never be used from
 * the DB unless the scenario is being computed (should be 'observe ... in scenario ....).
 */
Namespace:
	annotations+=Annotation* ((private?='private')? & (inactive?='void')?) ('namespace' | scenario?='scenario')
	name=ValidID (docstring=STRING)? (('using' importList=ImportList)? & ('covering' coverageList=CoverageList)? &
	('exports' exportList+=ValidID (=> ',' exportList+=ValidID)*)? & ('in' 'domain' (rootDomain?='root' |
	domainConcept=ValidID))? & ('disjoint' 'with' disjointNamespaces=QualifiedNameList)? & ('version' version=ValidID)? & // FIXME needs a proper version ID rule
	('resolve' ('from' lookupNamespace+=ValidID*)? ('outside' blacklistNamespace+=ValidID*)? ('using' weights=Metadata)?)?
	& ('train' 'in' trainingNamespace+=ValidID*)?) ('with' 'metadata' metadata=Metadata)? ';';

CoverageList:
	coverage+=Coverage (=> ',' coverage+=Coverage)*;

Coverage:
	id=ValidID | function=Function;

ImportList:
	imports+=Import (=> ',' imports+=Import)*;

Import:
	((imports=List | star?='*') 'from')? imported=ValidID;

ModelObservableAdditional returns ModelObservable:
/* concept ID. The 'using' clause can only be used from the second observable on (the first 'uses' the model itself) */
	declaration=ConceptDeclaration (optional?='optional')? /* ) */ |
	/* inline (simple) model - in parentheses without 'model' keyword, named for output name, only from the second observable on. */
	inlineModel=InlineModel (optional?='optional')? ('named' observableName=ValidID);

ModelObservable:
/* datasource or function generating an observer */
	function=Function |
	/* concept ID. The 'using' clause can only be used from the second observable on (the first 'uses' the model itself) */
	declaration=ConceptDeclaration |
	/* annotate an inline number or concept as a localized observation of something. */
	literal=Literal |
	/* inlined concept statement */
	'(' conceptStatement=ConceptStatement ')';

	/**
 * TODO enable annotations to go with the namespace (those would be the ones before the 
 * namespace statement or at the end when there is no object to attach them to). This
 * can be done by making an annotation a statement.
 */
Statement:
	annotations+=Annotation* (concept=ConceptStatement ';' | concept=ContextualRedeclaration ';' |
	contextualization=ContextualizeStatement ';' | property=PropertyStatement ';' | model=ModelStatement ';' |
	observe=ObserveStatement ';' | define=DefineStatement ';');

	/**
 * The models in 'using' are used as a context model to choose the
 * generator contextually. There is no other use for dependencies in a model; observers
 * use those as actual dependencies.
 * 
 * 'as' is optional (if not there, define an agent (subject) with the dependencies; in that
 * case, using should be like in observation generator.)
 * 
 * If the observable is *, this is used as the top-level obs and the observable is generated
 * as an instance of the union of the observable for the observers, which must be capable of
 * producing the observables.
 * 
 */
ModelStatement:

/*
	 * Models are semantic annotations, so an alternative 'annotate' keyword can be used. The
	 * model ID is taken from the first 'named' attribute
	 * encountered in the observables, or from the observable concept name
	 * if that is not specified.
	 */
	((private?='private')? & (inactive?='void')?) 'model' (observables+=ModelObservable ('named' name=ValidID)? (=> ','
	observables+=ModelObservableAdditional)*) ('observing' dependencies+=Dependency (=> ',' dependencies+=Dependency)*)?

	/*
		 * contextualization actions and accessor specifications 
		 * can only be there in agent models; in data models,
		 * actions and accessors belong to the observers.
		 * 
		 * FIXME in agent models, the 'over' contextualizers shouldn't need to come
		 * after the 'using'. Bit complicated to do right.
		 */
	(('as' observers=ObservationGeneratorSwitch) | (('using' (accessor=Function | lookup=LookupFunction))? &
	(contextualizers+=Contextualization (contextualizers+=Contextualization)*)?)) ('with' 'metadata' metadata=Metadata)? |

	/*
	 * short version that takes the observable from the observer. Only for qualities obviously.
	 */
	((private?='private')? & (inactive?='void')?) interpreter?='model' ('named' name=ValidID)?
	(observers=ObservationGeneratorSwitch)
	/* more fluent at times. Models will need to use properly and flag redefinitions as errors. */
	('named' name2=ValidID)? ('with' 'metadata' metadata=Metadata)? |

	/*
     * Reification model - annotates sources of dumb objects to things.
     */
	((private?='private')? & (inactive?='void')?) 'model' reification?='each' ((agentSource=Function ('named'
	name=ValidID)? 'as' observable+=ConceptDeclaration) | (observable+=ConceptDeclaration ('named' name=ValidID)?))
	('observing' dependencies+=Dependency (=> ',' dependencies+=Dependency)*)? (=> 'interpret'
	attributeTranslators+=AttributeTranslator (',' attributeTranslators+=AttributeTranslator)*)?
	(contextualizers+=Contextualization (contextualizers+=Contextualization)*)? (('with' 'metadata' metadata=Metadata)? &
	('using' (accessor=Function | lookup=LookupFunction))?);

ContextualizeStatement:
	((private?='private')? & (inactive?='void')?) 'contextualize' concept=DerivedConceptDeclaration
	((roleStatement+=RoleStatement)* & (resolutionStatement+=ResolutionStatement)*);

ResolutionStatement:
	'resolve' 'to' resolutions+=ConditionalResolution (=> ',' resolutions+=ConditionalResolution) ('observing'
	dependencies+=Dependency (=> ',' dependencies+=Dependency)*)? (contextualizers+=Contextualization
	(contextualizers+=Contextualization)*)? ('using' (accessor=Function | lookup=LookupFunction))?;

ConditionalResolution:
	concreteConcept=ConceptDeclaration ('if' expr=EXPR | otherwise?='otherwise')?;

RoleStatement:
	'with' 'role' role=ConceptList ('for' targetObservable=ConceptList)? 'in' restrictedObservable=ConceptList;

	/*
 * attribute is either a quality observer for de-reification or a property to define an annotation
 * for the objects.
 * 
 */
AttributeTranslator:
	attributeId=ValidID 'as' (observers=ObservationGenerator | property=ValidID);

Observation:
	function=Function | observer=ObservationGenerator | id=ValidID;

	/**
 * define  can be used for many things that describe objects used in the implementation, e.g.
 * Storyline or WebApplication - it basically creates an instance using a map, and that can be passed
 * to any function.
 */
DefineStatement:
	'define' ((name=ValidID 'as' (value=Value | table=Table)));

	/*
* Asserts the definition of an object, which will generate one when evaluated. Can
* optionally specify which model to use to resolve functional properties in the observable.
* 
* FIXME should have: 
* 'with' ... more objects + relationship (optional)
* 'using' attributeId=ValidID 'as' observer=ObservationGenerator )
*/
ObserveStatement:
	'observe' concept=ConceptDeclaration 'named' name=ValidID ('extends' parents=QualifiedNameList)?
	(contextualizers+=Contextualization (contextualizers+=Contextualization)*)? & ('with' states+=State (=> ','
	states+=State)*)? & (roles+=RoleStatement)*;

SubObserveStatement returns ObserveStatement:
	'(' concept=ConceptDeclaration 'named' name=ValidID
	//		('extends' parents=QualifiedNameList)? 
	(contextualizers+=Contextualization (contextualizers+=Contextualization)*)? & ('with' states+=State (=> ','
	states+=State)*)? (roles+=RoleStatement)* ')';

State:
	(literal=LiteralOrID | function=Function) 'as' observer=ObservationGenerator | (observation=SubObserveStatement);

	/*
 * Specialized observers */
ObservationGenerator:
	measurement=MeasureStatement | ranking=RankStatement | classification=ClassifyStatement | valuation=ValueStatement |
	distance=DistanceStatement | presence=PresenceStatement | count=CountStatement | ratio=RatioStatement |
	proportion=ProportionStatement | uncertainty=UncertaintyStatement | probability=ProbabilityStatement;

	/**
 * FIXME - all the 'by' trait should be mandatory with discretizations, and the trait should
 * be validated as an ordering. Applies to all numeric observers.
 */
MeasureStatement returns Observer:
	'measure' observable=Observable 'in' unit=Unit ('discretized' ('by' trait=TraitDef)? 'into'
	discretization=Classification)? ((=> 'using' (accessor=Function | lookup=LookupFunction))? & (=> 'observing'
	dependencies+=Dependency (=> ',' dependencies+=Dependency)*)?) (=> contextualizers+=Contextualization
	(contextualizers+=Contextualization)*)?;

	/**
 * Distance observer only accepts a subject concept or an observation ID as observable. We check it
 * directly in the model generator. Units must be compatible with lenghts.
 */
DistanceStatement returns Observer:
	'distance' ('to' | 'from') concept=ConceptDeclaration 'in' unit=Unit ('discretized' ('by' trait=TraitDef)? 'into'
	discretization=Classification)? ((=> 'using' (accessor=Function | lookup=LookupFunction))? & (=> 'observing'
	dependencies+=Dependency (=> ',' dependencies+=Dependency)*)?) (=> contextualizers+=Contextualization
	(contextualizers+=Contextualization)*)?;

	/*
 * presence is a binary coding - true or false. Simplest case of a (mandatorily) de-reifying observer.
 * rank is a quantitative, monotonic, linear (for now) assessment of a quantity with only relative value.
 * count expects its observable to describe an individual unit or something that is countable. If it doesn
 *       not have a 'per' unit, it must be 'aggregated over' all the relevant extent domains.
 * ratios and proportions trigger further validation and allow specifying the individual components so that
 *        more can be done in the future (look for the individual ones and build a model that does the
 *        right thing).
 * 
 * Observable sanity in ratios and proportions:
 * 
 * 	ratio: 'O' -> O is already a ratio observable -> O
 * 		   'T O' -> the ratio of the O's that have T vs. those that don't -> TORatio
 *         'T1 O to T2' -> ratio of those O's that have T1 vs. those that have T2 -> T1ToT2ORatio
 * 
 * proportion/percentage should only admit 'T O' with explicit trait. think about "Proportion people higher than 2m" - the 2m should be 
 * 			the model part for a "high enough" trait
 * 
 * uncertainty is used to annotate uncertainty data or to trigger their production from specialized observers
 *        such as BNs when used as input. 
 * 
 * Both presence and uncertainty must specify the inherent subject (which in the case of uncertainty
 * may be a quality). The others have the 'of' spec optional, whose absence means they're inherent 
 * to THING (the root subject type).
 * 
 */
PresenceStatement returns Observer:
// if derived, the observable must not be a presence; otherwise it must
	'presence' (derived?='of')? concept=ConceptDeclaration ((=> 'using' (accessor=Function | lookup=LookupFunction))? & (=>
	'observing' dependencies+=Dependency (=> ',' dependencies+=Dependency)*)?) (=> contextualizers+=Contextualization
	(contextualizers+=Contextualization)*)?;

RankStatement returns Observer:
	'rank' observable=Observable (from=NUMBER 'to' to=NUMBER)? (integer?='integer')? ('discretized' ('by' trait=TraitDef)?
	'into' discretization=Classification)? ((=> 'using' (accessor=Function | lookup=LookupFunction))? & (=> 'observing'
	dependencies+=Dependency (=> ',' dependencies+=Dependency)*)?) (=> contextualizers+=Contextualization
	(contextualizers+=Contextualization)*)?;

RatioStatement returns Observer:
	'ratio'
	// there is no such thing as a "natural" ratio, so the direct version should not exist.
	'of' concept=ConceptDeclaration 'to' other=ConceptDeclaration ('discretized' ('by' trait=TraitDef)? 'into'
	discretization=Classification)? ((=> 'using' (accessor=Function | lookup=LookupFunction))? & (=> 'observing'
	dependencies+=Dependency (=> ',' dependencies+=Dependency)*)?) (=> contextualizers+=Contextualization
	(contextualizers+=Contextualization)*)?;

ProportionStatement returns Observer:
	(type='proportion' | type='percentage') (('of' concept=ConceptDeclaration 'in' other=ConceptDeclaration) |
	observable=Observable) ('discretized' ('by' trait=TraitDef)? 'into' discretization=Classification)? ((=> 'using'
	(accessor=Function | lookup=LookupFunction))? & (=> 'observing' dependencies+=Dependency (=> ','
	dependencies+=Dependency)*)?) (=> contextualizers+=Contextualization (contextualizers+=Contextualization)*)?;

CountStatement returns Observer:
	'count' concept=ConceptDeclaration ('per' distributionUnit=Unit)? ('discretized' ('by' trait=TraitDef)? 'into'
	discretization=Classification)? ((=> 'using' (accessor=Function | lookup=LookupFunction))? & (=> 'observing'
	dependencies+=Dependency (=> ',' dependencies+=Dependency)*)?) (=> contextualizers+=Contextualization
	(contextualizers+=Contextualization)*)?;

UncertaintyStatement returns Observer:
// if not derived, the observable must be an uncertainty
	'uncertainty' (derived?='of')? concept=DerivedConceptDeclaration ('discretized' ('by' trait=TraitDef)? 'into'
	discretization=Classification)? ((=> 'using' (accessor=Function | lookup=LookupFunction))? & (=> 'observing'
	dependencies+=Dependency (=> ',' dependencies+=Dependency)*)?) (=> contextualizers+=Contextualization
	(contextualizers+=Contextualization)*)?;

ProbabilityStatement returns Observer:
// if not derived, the observable must be a probability
	'probability' (derived?='of')? concept=ConceptDeclaration ('discretized' ('by' trait=TraitDef)? 'into'
	discretization=Classification)? ((=> 'using' (accessor=Function | lookup=LookupFunction))? & (=> 'observing'
	dependencies+=Dependency (=> ',' dependencies+=Dependency)*)?) (=> contextualizers+=Contextualization
	(contextualizers+=Contextualization)*)?;

ValueStatement returns Observer:
	'value' observable=DerivedObservable ('over' other=DerivedConceptDeclaration)? ('in' currency=Currency)? (from=NUMBER
	'to'
	to=NUMBER)? ('discretized' ('by' trait=TraitDef)? 'into' discretization=Classification)? ((=> 'using'
	(accessor=Function | lookup=LookupFunction))? & (=> 'observing' dependencies+=Dependency (=> ','
	dependencies+=Dependency)*)?) (=> contextualizers+=Contextualization (contextualizers+=Contextualization)*)?;

	/*
 * 12/19/12: can now specify 'according to' instead of the classification to use a metadata field
 * in the concept hierarchy to specify the encoding.
 * 15/1/14: classification according to trait is now specified using 'by' - e.g. classify im.geo:Elevation of im.geo:Mountain by im:Level
 */
ClassifyStatement returns Observer:
	('classify' | discretizer?='discretize') observable=DerivedObservable
	// more than one trait is possible and they can be an authority's identity.
	('by' (traits+=TraitDef (',' traits+=TraitDef)*))? (('into' classification=Classification) | ('according' 'to'
	metadataProperty=ValidID))? ((=> 'using' (accessor=Function | lookup=LookupFunction))? & (=> 'observing'
	dependencies+=Dependency (=> ',' dependencies+=Dependency)*)?) (=> contextualizers+=Contextualization
	(contextualizers+=Contextualization)*)?;

	/*
 * if isIdentity, the id must name an authority
 * downTo can be used to select a level of detail both in traits/orderings and authority mediated
 */
TraitDef:
	id=ValidID (isIdentity?='identity')? ('down' 'to' downTo=ValidID)?;

Observable:
	concept=ConceptDeclaration | '(' mediated=ObservationGeneratorSwitch ')' | '(' conceptStatement=ConceptStatement ')';

DerivedObservable returns Observable:
	concept=DerivedConceptDeclaration | '(' mediated=ObservationGeneratorSwitch ')' | '('
	conceptStatement=ConceptStatement ')';
	/*
 * A list of observation-generating models with optional 'when' clause (or no-op 'otherwise'), separated by commas
 */
ObservationGeneratorSwitch:
	mediated+=ObservationGeneratorConditional (=> ',' mediated+=ObservationGeneratorConditional)*;

	/**
 * The form in parentheses is provided to resolve the potential ambiguity of having an 'if' conditional
 * at the end of the observer which could be meant for the model but would be attributed to an
 * unconditional action in the observer that precedes it.
 */
ObservationGeneratorConditional:
	observable=ObservationGenerator when=WhenExpression? | '(' observable=ObservationGenerator ')' when=WhenExpression?;

InlineModel:
	'(' ((concept=ConceptDeclaration | value=Literal) 'as')? observer=ObservationGenerator ')';

	/*
 * "Bare" dependencies:
 * the  by  form is automatically promoted to a classification that gives the
 * (abstract) trait to the observable. If this form is given, an inherent subject can also be
 * specified using 'of' (otherwise it must be left to the explicit observer). Everything else 
 * is resolved to either a model or a concept that must have a model in the same namespace;
 * 
 * Other than the above, a well-formed dependency must state the observer, so that we know if
 * and how to mediate the states.
 * 
 */
Dependency:
	(((generic?='every')? concept=ConceptDeclaration ('by' trait=TraitDef)?) | inlineModel=InlineModel) (('named'
	formalname=ValidID)? & ('at' (each?='each')? dcontext=ConceptDeclaration ('where' whereCondition=Value)?)? & ('for'
	property=ValidID)? & ('as' traitConferred=ValidID)? & (optional='optional' | 'required')?);

ClassifierRHS:
	num=NUMBER | (boolean='true' | boolean='false') | int0=NUMBER (leftLimit='inclusive' | 'exclusive')? 'to' int1=NUMBER
	(rightLimit='inclusive' | 'exclusive')? | 'in' set=List | string=STRING | concept=NegatableConceptDeclaration | '('
	toResolve+=ConceptDeclarationUnion (=> ',' toResolve+=ConceptDeclarationUnion)* ')' | op=REL_OPERATOR
	expression=NUMBER | nodata='unknown' | star?='*';

ClassifierRHSReduced returns ClassifierRHS:
	num=NUMBER | (boolean='true' | boolean='false') | int0=NUMBER (leftLimit='inclusive' | 'exclusive')? 'to' int1=NUMBER
	(rightLimit='inclusive' | 'exclusive')? | 'in' set=List | string=STRING | concept=NegatableConceptDeclaration |
	op=REL_OPERATOR expression=NUMBER | nodata='unknown' | star?='*';

ConceptDeclarationUnion:
	concept+=NegatableConceptDeclaration (=> 'or' concept+=NegatableConceptDeclaration)*;

Classifier:
	declaration=ConceptDeclaration (otherwise?='otherwise' | ('if' | negated?='unless') classifier=ClassifierRHS)?;

Classification:
	classifiers+=Classifier (=> ',' classifiers+=Classifier)*;

WhenExpression:
	condition=Condition | otherwise?='otherwise';

Condition:
	('if' | negated?='unless') (subject=LiteralOrID)? 'in' (context=ValidID | set=LiteralList) | ('if' |
	negated?='unless') (subject=LiteralOrID)? 'is' match=LiteralOrID | ('if' | negated?='unless') (subject=LiteralOrID)?
	'between' from=Value 'and' to=Value | ('if' | negated?='unless') expression=Value;

LiteralList:
	expressions+=Literal (',' expressions+=Literal)*;

Table:
	'table' '(' ((args+=ValidID (',' args+=ValidID)*) | (expr+=EXPR (expr+=EXPR)*)) ')' ':' elements+=ClassifierRHSReduced
	(=> ',' elements+=ClassifierRHSReduced)*;

LookupFunction:
	'lookup' '(' args+=(ValidID | '?') (',' args+=(ValidID | '?'))* ')' 'into' (table=Table | ref=ValidID) | 'lookup'
	(id=ValidID | expression=EXPR) 'into' function=Function;