blob: c33c1eb00fcb7d5f66e71eeb2a6a3f9888517b3b [file] [log] [blame]
/*
* Copyright (c) 2005, 2009 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
* Artem Tikhomirov (Borland) - Migration to OCL expressions
*/
package org.eclipse.gmf.internal.xpand.ast;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.gmf.internal.xpand.BuiltinMetaModel;
import org.eclipse.gmf.internal.xpand.expression.ast.Identifier;
import org.eclipse.gmf.internal.xpand.model.AnalysationIssue;
import org.eclipse.gmf.internal.xpand.model.EvaluationException;
import org.eclipse.gmf.internal.xpand.model.ExecutionContext;
import org.eclipse.gmf.internal.xpand.model.Variable;
import org.eclipse.gmf.internal.xpand.model.XpandIterator;
import org.eclipse.gmf.internal.xpand.ocl.ExpressionHelper;
import org.eclipse.ocl.cst.OCLExpressionCS;
import org.eclipse.ocl.ecore.CollectionType;
/**
* @author Sven Efftinge
*/
public class ForEachStatement extends Statement {
public static final String ITERATOR_VAR_NAME = "iterator";
private final Statement[] body;
private final ExpressionHelper target;
private final ExpressionHelper separator;
private final Identifier variable;
private final Identifier iteratorName;
public ForEachStatement(final int start, final int end, final int line, final Identifier variable, final OCLExpressionCS target, final Statement[] body, final OCLExpressionCS separator, final Identifier iterator) {
super(start, end, line);
this.variable = variable;
this.target = new ExpressionHelper(target, this);
this.body = body;
this.separator = separator == null ? null : new ExpressionHelper(separator, this);
iteratorName = iterator;
}
public void analyze(ExecutionContext ctx, final Set<AnalysationIssue> issues) {
EClassifier t = target.analyze(ctx, issues);
if (separator != null) {
final EClassifier sepT = separator.analyze(ctx, issues);
if (ctx.getOCLEnvironment().getOCLStandardLibrary().getString() != sepT) {
issues.add(new AnalysationIssue(AnalysationIssue.Type.INCOMPATIBLE_TYPES, "String expected!", target));
}
}
if (t != null) {
if (t instanceof CollectionType) {
t = ((CollectionType) t).getElementType();
} else {
issues.add(new AnalysationIssue(AnalysationIssue.Type.INCOMPATIBLE_TYPES, "Collection type expected!", target));
return;
}
}
// XXX odd - is t == null ok here?
ctx = ctx.cloneWithVariable(new Variable(variable.getValue(), t, null));
if (iteratorName != null) {
ctx = ctx.cloneWithVariable(new Variable(iteratorName.getValue(), BuiltinMetaModel.ITERATOR_TYPE, null));
}
for (Statement statement : body) {
statement.analyze(ctx, issues);
}
}
@Override
public void evaluateInternal(ExecutionContext ctx) {
Set<AnalysationIssue> issues = new HashSet<AnalysationIssue>();
EClassifier targetType = target.analyze(ctx, issues);
if (issues.size() > 0 || false == targetType instanceof CollectionType) {
throw new EvaluationException("Can't evaluate FOREACH expression: target collection type cannot be defined", target);
}
EClassifier targetElementType = ((CollectionType) targetType).getElementType();
final Object o = target.evaluate(ctx);
if (!(o instanceof Collection<?>)) {
throw new EvaluationException("Collection expected (was: " + o.getClass().getName() + ")!", target);
}
final Collection<?> col = (Collection<?>) o;
final String sep = (String) (separator != null ? separator.evaluate(ctx) : null);
final XpandIterator iterator = new XpandIterator(col.size());
if (iteratorName != null) {
ctx = ctx.cloneWithVariable(new Variable(iteratorName.getValue(), BuiltinMetaModel.ITERATOR_TYPE, iterator));
}
for (final Iterator<?> iter = col.iterator(); iter.hasNext();) {
final Object element = iter.next();
if (!BuiltinMetaModel.isAssignableFrom(ctx, targetElementType, BuiltinMetaModel.getType(ctx, element))) {
throw new EvaluationException("Can't evaluate FOREACH expression: actual collection element type is not assignable to declared collection element type", this);
}
ctx = ctx.cloneWithVariable(new Variable(variable.getValue(), targetElementType, element));
for (int i = 0; i < body.length; i++) {
body[i].evaluate(ctx);
}
if ((sep != null) && iter.hasNext()) {
ctx.getScope().getOutput().write(sep);
}
iterator.increment();
}
}
ExpressionHelper getSeparator() {
return separator;
}
ExpressionHelper getTarget() {
return target;
}
Statement[] getBody() {
return body;
}
}