/**
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Copyright (C) 2007 Matthias Braeuer (braeuer.matthias@web.de). *
* All rights reserved. *
* *
* This work was done as a project at the Chair for Software Technology, *
* Dresden University Of Technology, Germany (http://st.inf.tu-dresden.de). *
* It is understood that any modification not identified as such is not *
* covered by the preceding statement. *
* *
* This work is free software; you can redistribute it and/or modify it *
* under the terms of the GNU Library General Public License as published *
* by the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This work is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public *
* License for more details. *
* *
* You should have received a copy of the GNU Library General Public License *
* along with this library; if not, you can view it online at *
* http://www.fsf.org/licensing/licenses/gpl.html. *
* *
* To submit a bug report, send a comment, or get the latest news on this *
* project, please visit the website: http://dresden-ocl.sourceforge.net. *
* For more information on OCL and related projects visit the OCL Portal: *
* http://st.inf.tu-dresden.de/ocl *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* $Id$
*/
package org.dresdenocl.essentialocl.expressions.impl;
import org.eclipse.emf.ecore.EClass;
import org.dresdenocl.essentialocl.expressions.IteratorExp;
import org.dresdenocl.essentialocl.expressions.WellformednessException;
import org.dresdenocl.essentialocl.types.CollectionType;
import org.dresdenocl.essentialocl.types.OrderedSetType;
import org.dresdenocl.essentialocl.types.SequenceType;
import org.dresdenocl.essentialocl.types.SetType;
import org.dresdenocl.pivotmodel.Type;
/**
* <!-- begin-user-doc --> An implementation of the model object '
* <em><b>Iterator Exp</b></em>'. <!-- end-user-doc -->
* <p>
* </p>
*
* @generated
*/
public class IteratorExpImpl extends LoopExpImpl implements IteratorExp {
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
* @generated
*/
protected IteratorExpImpl() {
super();
}
/**
* Overridden to determine the type of the <code>IteratorExp</code>
* according to the OCL specification (Section 8.3). Note that the
* specification is incomplete and this implementation adds a few more
* rules.
*
* <p>
* [1] If the iterator is �forAll,� �isUnique,� or �exists� the type of the
* iterator must be Boolean.
*
* <pre>
* context IteratorExp
* inv: name = �exists� or name = �forAll� or name = �isUnique�
* implies type.oclIsKindOf(PrimitiveType) and type.name = �Boolean�
* </pre>
*
* [2] The result type of the collect operation on a sequence type is a
* sequence, the result type of �collect� on any other collection type is a
* Bag. The type of the body is always the type of the elements in the
* return collection.
*
* <pre>
* context IteratorExp
* inv: name = �collect� implies
* if source.type.oclIsKindOf(SequenceType) then
* type = expression.type.collectionType->select(oclIsTypeOf(SequenceType))->first()
* else
* type = expression.type.collectionType->select(oclIsTypeOf(BagType))->first()
* endif
* </pre>
*
* [3] The �select� and �reject� iterators have the same type as its source.
*
* <pre>
* context IteratorExp
* inv: name = �select� or name = �reject� implies type = source.type
* </pre>
*
* </p>
*
* @see org.dresdenocl.essentialocl.expressions.impl.OclExpressionImpl#evaluateType()
*/
@Override
protected Type evaluateType() {
Type type, sourceType, elementType, bodyType;
// check for wellformedness of loop expression
validateWellformednessRules();
// determine the types of the source collection, its elements and the
// body
// expression
sourceType = source.getType();
elementType = ((CollectionType) sourceType).getElementType();
bodyType = body.getType();
// implement rule [1], but additionally check for iterator expression
// "one"
if (name.equals("exists") || name.equals("forAll") || name.equals("isUnique") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|| name.equals("one")) { //$NON-NLS-1$
type = getValidOclLibrary().getOclBoolean();
}
// additional rule missing in the spec
else if (name.equals("any")) { //$NON-NLS-1$
type = elementType;
}
// implement rule [3]
else if (name.equals("select") || name.equals("reject")) { //$NON-NLS-1$ //$NON-NLS-2$
type = sourceType;
}
// additional rule missing in the spec
else if (name.equals("sortedBy")) { //$NON-NLS-1$
if (sourceType instanceof SetType
|| sourceType instanceof OrderedSetType) {
type = getValidOclLibrary().getOrderedSetType(elementType);
}
else {
type = getValidOclLibrary().getSequenceType(elementType);
}
}
else if (name.equals("closure")) {
if (sourceType instanceof SequenceType
|| sourceType instanceof OrderedSetType) {
type = getValidOclLibrary().getOrderedSetType(elementType);
}
else {
type = getValidOclLibrary().getSetType(elementType);
}
}
// additional rule missing in the spec
else if (name.equals("collectNested")) { //$NON-NLS-1$
if (sourceType instanceof SequenceType
|| sourceType instanceof OrderedSetType) {
type = getValidOclLibrary().getSequenceType(bodyType);
}
else {
type = getValidOclLibrary().getBagType(bodyType);
}
}
// implement rule [2]
else if (name.equals("collect")) { //$NON-NLS-1$
Type resultElementType;
// flatten the type of the body expression
if (bodyType instanceof CollectionType) {
resultElementType = ((CollectionType) bodyType)
.getElementType();
}
else {
resultElementType = bodyType;
}
// we enhance rule [2] with a treatment of ordered sets
if (sourceType instanceof SequenceType
|| sourceType instanceof OrderedSetType) {
type = getValidOclLibrary().getSequenceType(resultElementType);
}
else {
type = getValidOclLibrary().getBagType(resultElementType);
}
}
else {
throw new WellformednessException(this,
"Unknown iterator expression: '" + name + "'."); //$NON-NLS-1$//$NON-NLS-2$
}
return type;
}
/**
* Overridden to additionally check the following wellformedness rule
*
* <p>
* [4] The type of the body of the select, reject, exists, and forAll must
* be boolean.
*
* <pre>
* context IteratorExp
* inv: name = �exists� or name = �forAll� or name = �select� or name = �reject�
* implies body.type.name = �Boolean�
* </pre>
*
* </p>
*
* @see org.dresdenocl.essentialocl.expressions.impl.LoopExpImpl#validateWellformednessRules()
*/
@Override
protected void validateWellformednessRules() {
super.validateWellformednessRules();
// validate [4], but also check for iterator expressions "any" and "one"
if (name.equals("exists") || name.equals("forAll") || name.equals("select") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|| name.equals("reject") || name.equals("any") || name.equals("one")) { //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
if (body.getType() != oclLibrary.getOclBoolean()) {
throw new WellformednessException(
this,
"The body expression of an '" //$NON-NLS-1$
+ name
+ "' iterator expression must have the type Boolean."); //$NON-NLS-1$
}
// no else.
}
/* Check result type of closure iterator. */
if (name.equals("closure")) {
String msg = "The body expression of a closure iterator expression must conform to the source expression's element type.";
Type bodyType = body.getType();
Type sourceType = source.getType();
Type sourceElementType = ((CollectionType) sourceType)
.getElementType();
if (!bodyType.conformsTo(sourceElementType)
&& !(bodyType instanceof CollectionType)) {
throw new WellformednessException(this, msg);
}
else if (bodyType instanceof CollectionType) {
Type bodyElementType = ((CollectionType) bodyType)
.getElementType();
if (!bodyElementType.conformsTo(sourceElementType)) {
throw new WellformednessException(this, msg);
}
// no else.
}
// no else.
}
// no else.
/* Check count of variables. */
if (name.equals("any") || name.equals("collect")
|| name.equals("collectNested") || name.equals("closure")
|| name.equals("isUnique") || name.equals("one")
|| name.equals("reject") || name.equals("select")
|| name.equals("sortedBy")) {
if (this.getIterator().size() > 1) {
throw new WellformednessException(this, "The iterator " + name
+ " may have at most one iterator variable.");
}
// no else.
}
// no else.
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
* @generated
*/
@Override
protected EClass eStaticClass() {
return ExpressionsPackageImpl.Literals.ITERATOR_EXP;
}
} // IteratorExpImpl