/* * <copyright> * * Copyright (c) 2005-2008 Sven Efftinge 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: * Sven Efftinge - Initial API and implementation * Alexander Shatalin (Borland) * * </copyright> */ package org.eclipse.gmf.internal.xpand.expression.ast; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.Set; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EcorePackage; import org.eclipse.gmf.internal.xpand.BuiltinMetaModel; import org.eclipse.gmf.internal.xpand.expression.AnalysationIssue; import org.eclipse.gmf.internal.xpand.expression.EvaluationException; import org.eclipse.gmf.internal.xpand.expression.ExecutionContext; import org.eclipse.gmf.internal.xpand.expression.SyntaxConstants; import org.eclipse.gmf.internal.xpand.expression.Variable; import org.eclipse.gmf.internal.xpand.migration.CollectionExpressionTrace; /** * @author Sven Efftinge * @author Arno Haase */ public class CollectionExpression extends FeatureCall { private Expression closure; private String eleName; public CollectionExpression(final int end, final int endOffset, final Identifier opNAme, final String eleName, final Expression closure, final Expression target) { super(opNAme.getStart(), end, opNAme.getLine(), opNAme.getStartOffset(), endOffset, opNAme, target); this.eleName = eleName; this.closure = closure; } @Override public String toString() { return super.toString() + "(" + (eleName != null ? eleName + "|" : "") + closure + ")"; } @Override public Object evaluateInternal(final ExecutionContext ctx) { Object targetObj = null; if (getTarget() == null) { final Variable v = ctx.getVariable(ExecutionContext.IMPLICIT_VARIABLE); if (v != null) { targetObj = v.getValue(); } } else { targetObj = getTarget().evaluate(ctx); } if (targetObj == null) { return null; } if (!(targetObj instanceof Collection)) { throw new EvaluationException("Couldn't call '" + this.toString() + "' on an object of java type " + targetObj.getClass().getName(), this); } if (getName().getValue().equals(SyntaxConstants.COLLECT)) { return executeCollect((Collection) targetObj, ctx); } else if (getName().getValue().equals(SyntaxConstants.SELECT)) { return executeSelect((Collection) targetObj, ctx); } else if (getName().getValue().equals(SyntaxConstants.REJECT)) { return executeReject((Collection) targetObj, ctx); } else if (getName().getValue().equals(SyntaxConstants.EXISTS)) { return executeExists((Collection) targetObj, ctx); } else if (getName().getValue().equals(SyntaxConstants.NOT_EXISTS)) { return executeNotExists((Collection) targetObj, ctx); } else if (getName().getValue().equals(SyntaxConstants.FOR_ALL)) { return executeForAll((Collection) targetObj, ctx); } else { throw new EvaluationException("Unkown collection operation : " + getName().getValue(), this); } } private Object executeForAll(final Collection collection, ExecutionContext ctx) { for (final Iterator iter = collection.iterator(); iter.hasNext();) { ctx = ctx.cloneWithVariable(new Variable(getElementName(), iter.next())); final Object result = closure.evaluate(ctx); if (!(result instanceof Boolean) || !((Boolean) result).booleanValue()) { return Boolean.FALSE; } } return Boolean.TRUE; } private Object executeExists(final Collection collection, ExecutionContext ctx) { for (final Iterator iter = collection.iterator(); iter.hasNext();) { ctx = ctx.cloneWithVariable(new Variable(getElementName(), iter.next())); final Object result = closure.evaluate(ctx); if ((result instanceof Boolean) && ((Boolean) result).booleanValue()) { return Boolean.TRUE; } } return Boolean.FALSE; } private Object executeNotExists(final Collection collection, ExecutionContext ctx) { for (final Iterator iter = collection.iterator(); iter.hasNext();) { ctx = ctx.cloneWithVariable(new Variable(getElementName(), iter.next())); final Object result = closure.evaluate(ctx); if ((result instanceof Boolean) && ((Boolean) result).booleanValue()) { return Boolean.FALSE; } } return Boolean.TRUE; } private Object executeReject(final Collection<?> collection, ExecutionContext ctx) { final Collection resultCol = new ArrayList<Object>(collection); for (Object ele : collection) { ctx = ctx.cloneWithVariable(new Variable(getElementName(), ele)); final Object result = closure.evaluate(ctx); if ((result instanceof Boolean) && ((Boolean) result).booleanValue()) { resultCol.remove(ele); } } return resultCol; } private Object executeSelect(final Collection collection, ExecutionContext ctx) { final Collection<Object> resultCol = new ArrayList<Object>(); for (final Iterator iter = collection.iterator(); iter.hasNext();) { final Object ele = iter.next(); ctx = ctx.cloneWithVariable(new Variable(getElementName(), ele)); final Object result = closure.evaluate(ctx); if ((result instanceof Boolean) && ((Boolean) result).booleanValue()) { resultCol.add(ele); } } return resultCol; } private Object executeCollect(final Collection collection, ExecutionContext ctx) { final Collection<Object> resultCol = new ArrayList<Object>(); for (final Iterator iter = collection.iterator(); iter.hasNext();) { final Object ele = iter.next(); ctx = ctx.cloneWithVariable(new Variable(getElementName(), ele)); resultCol.add(closure.evaluate(ctx)); } return resultCol; } @Override public EClassifier analyze(ExecutionContext ctx, final Set<AnalysationIssue> issues) { EClassifier targetType = null; if (getTarget() == null) { final Variable v = ctx.getVariable(ExecutionContext.IMPLICIT_VARIABLE); if (v != null) { targetType = (EClassifier) v.getValue(); } } else { targetType = getTarget().analyze(ctx, issues); } if (targetType == null) { return createAnalyzeTrace(ctx, new CollectionExpressionTrace(null, CollectionExpressionTrace.Type.UNDESOLVED_TARGET_TYPE)); } if (!(BuiltinMetaModel.isParameterizedType(targetType))) { issues.add(new AnalysationIssue(AnalysationIssue.Type.INCOMPATIBLE_TYPES, "Collection type expected! was : " + targetType, getTarget())); return null; } final EClassifier innerEClassifier = BuiltinMetaModel.getInnerType(targetType); EClassifier result = null; ctx = ctx.cloneWithVariable(new Variable(getElementName(), innerEClassifier)); final EClassifier closureEClassifier = closure.analyze(ctx, issues); if (getName().getValue().equals(SyntaxConstants.COLLECT)) { if (targetType.getName().endsWith(BuiltinMetaModel.SET)) { return createAnalyzeTrace(ctx, new CollectionExpressionTrace(BuiltinMetaModel.getSetType(closureEClassifier), CollectionExpressionTrace.Type.COLLECT_REF)); } else if (targetType.getName().endsWith(BuiltinMetaModel.LIST)) { return createAnalyzeTrace(ctx, new CollectionExpressionTrace(BuiltinMetaModel.getListType(closureEClassifier), CollectionExpressionTrace.Type.COLLECT_REF)); } else { return createAnalyzeTrace(ctx, new CollectionExpressionTrace(BuiltinMetaModel.getCollectionType(closureEClassifier), CollectionExpressionTrace.Type.COLLECT_REF)); } } else if (getName().getValue().equals(SyntaxConstants.SELECT) || getName().getValue().equals(SyntaxConstants.REJECT)) { return createAnalyzeTrace(ctx, new CollectionExpressionTrace(targetType, CollectionExpressionTrace.getType(this))); } else if (getName().getValue().equals(SyntaxConstants.TYPE_SELECT)) { // [AS]: Should not be here - separate TypeSelectExpression present in AST. if (closureEClassifier == null) { return null; } return BuiltinMetaModel.getListType(closureEClassifier); } else if (getName().getValue().equals(SyntaxConstants.EXISTS) || getName().getValue().equals(SyntaxConstants.NOT_EXISTS) || getName().getValue().equals(SyntaxConstants.FOR_ALL)) { if (!BuiltinMetaModel.isAssignableFrom(EcorePackage.eINSTANCE.getEBoolean(), closureEClassifier)) { issues.add(new AnalysationIssue(AnalysationIssue.Type.INCOMPATIBLE_TYPES, "Boolean type expected! was : " + closureEClassifier, closure)); } createAnalyzeTrace(ctx, new CollectionExpressionTrace(result = EcorePackage.eINSTANCE.getEBoolean(), CollectionExpressionTrace.getType(this))); } else { issues.add(new AnalysationIssue(AnalysationIssue.Type.INTERNAL_ERROR, "Unknown operation : " + getName().getValue(), this)); } return result; } public String getElementName() { return eleName != null ? eleName : SyntaxConstants.DEFAULT_ELE_NAME; } public Expression getClosure() { return closure; } }