[449946] - Control flow is manipulated using exceptions 
diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/QvtOperationalEvaluationVisitorImpl.java b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/QvtOperationalEvaluationVisitorImpl.java
index 028c30f..151f015 100644
--- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/QvtOperationalEvaluationVisitorImpl.java
+++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/QvtOperationalEvaluationVisitorImpl.java
@@ -1113,25 +1113,28 @@
     	if(valueExp != null) {
     		value = visitExpression(valueExp);
     	}
-    	
-		OperationBody body = QvtOperationalParserUtil.findParentElement(returnExp, OperationBody.class);
-		if(body != null) {
-			EList<org.eclipse.ocl.ecore.OCLExpression> content = body.getContent(); 
-			if(!content.isEmpty() && content.get(content.size() - 1) == returnExp) {
-				// return is the last expression in the body, simply return the value
-				return value;
-			}
-		}    	
-
-		// TODO - analyze more complex structured execution flow and
-		// avoid the cost of exception throwing 
-		throw new ReturnExpEvent(value, getOperationalEvaluationEnv());
+    	// Wrap the result of the expression in an OperationCallResult object.
+    	// This type breaks control flow, so the value arrives directly at its
+    	// calling operation, where it is unwrapped again and returned.
+		return new OperationCallResult(value, getOperationalEvaluationEnv());
     }
     
     public Object visitOperationBody(OperationBody operationBody) {
         Object result = null;
         for (OCLExpression<EClassifier> exp : operationBody.getContent()) {
         	result = visitExpression(exp);
+        	
+        	// If control flow was broken (by means of a return statement,
+        	// stop executing the next lines and return this result.
+        	if(result instanceof BreakingResult) {
+	        	if(result instanceof OperationCallResult) {
+	        		result = ((OperationCallResult)result).myResult;
+	        	}
+	        	else {
+	        		result = null;
+	        	}
+	        	break;
+        	}
         }
         
         ImperativeOperation operation = operationBody.getOperation();
@@ -1175,6 +1178,8 @@
     private Object visitBlockExpImpl(EList<org.eclipse.ocl.ecore.OCLExpression> expList, boolean isInImperativeOper) {
     	List<String> scopeVars = null;
     	
+    	Object result = null;
+    	
         for (OCLExpression<EClassifier> exp : expList) {
         	if((exp instanceof VariableInitExp) && !isInImperativeOper) {
         		if(scopeVars == null) {
@@ -1184,7 +1189,13 @@
         		scopeVars.add(varInitExp.getName());
         	}
         	
-        	visitExpression(exp);
+        	result = visitExpression(exp);
+        	if(result instanceof BreakingResult) {
+        		break;
+        	}
+        	// Return null, unless control flow is broken (by break, continue or return).
+        	// When control flow is broken, propagate this upward in the AST.
+        	result = null;
         }
         
         if(scopeVars != null) {
@@ -1194,7 +1205,7 @@
 			}
         }
         
-        return null;
+        return result;
     }
     
     public Object visitComputeExp(ComputeExp computeExp) {
@@ -1206,32 +1217,47 @@
         }
         replaceInEnv(returnedElement.getName(), initExpressionValue, returnedElement.getType());
         
-        visitExpression(computeExp.getBody());
+        Object result = visitExpression(computeExp.getBody());
+        
+        Object returnedValue = getEvaluationEnvironment().remove(returnedElement.getName()); 
+        
+        if(result instanceof BreakingResult) {
+        	// Control flow was broken (break or continue).
+        	// Instead of returning the value, propagate this.
+        	return result;
+        }
 
-        return getEvaluationEnvironment().remove(returnedElement.getName());
+        return returnedValue;
     }
 
     public Object visitWhileExp(WhileExp whileExp) {
+    	Object result = null;
         while (true) {
         	Object condition = visitExpression(whileExp.getCondition());
         	if (Boolean.TRUE.equals(condition)) {
-            	try {
-            		visitExpression(whileExp.getBody());
-            	}
-            	catch (QvtTransitionReachedException ex) {
-            		if (ex.getReason() == QvtTransitionReachedException.REASON_BREAK) {
-            			break;
-            		}
-            		if (ex.getReason() == QvtTransitionReachedException.REASON_CONTINUE) {
-            			continue;
-            		}
+            	result = visitExpression(whileExp.getBody());
+
+            	if(result instanceof BreakingResult) {
+            		// Control flow is being broken (break, continue, or return).
+            		
+            		if(result instanceof BreakResult) {
+            			// Result must be null, unless it comes from a return statement.
+                		result = null;
+                		break;
+                	}
+                	if(result instanceof ContinueResult) {
+            			// Instead of breaking out of the loop, continue with the next iteration.
+                		result = null;
+                    	continue;
+                	}
+            		break;
             	}
             } else {
                 break;
             }
         }
         
-        return null;
+        return result;
     }
     
     private static class SwitchAltExpResult {
@@ -1525,7 +1551,7 @@
 	}
 
 	public Object visitBreakExp(BreakExp astNode) {
-		throw new QvtTransitionReachedException(QvtTransitionReachedException.REASON_BREAK);
+		return BREAK;
 	}
 
 	public Object visitCatchtExp(CatchExp astNode) {
@@ -1534,7 +1560,7 @@
 	}
 
 	public Object visitContinueExp(ContinueExp astNode) {
-		throw new QvtTransitionReachedException(QvtTransitionReachedException.REASON_CONTINUE);
+		return CONTINUE;
 	}
 
 	public Object visitDictLiteralPart(DictLiteralPart astNode) {
@@ -1793,8 +1819,39 @@
 		}
     }
     
+    /**
+     * Tag interface which represents an evaluation result which,
+     * when encountered, breaks control flow.
+     * 
+     * Examples of this are break, continue, and return.
+     */
+    public static interface BreakingResult {
+    	
+    }
+    
+    /**
+     * Type of result which represents the situation in which a break statement is encountered.
+     */
+    public static class BreakResult implements BreakingResult {
+    	BreakResult() { }
+    }
+    
+    protected final static BreakResult BREAK = new BreakResult();
+    
+    /**
+     * Type of result which represents the situation in which a continue statement is encountered.
+     */
+    public static class ContinueResult implements BreakingResult {
+    	ContinueResult() { }
+    }
+    
+    protected final static ContinueResult CONTINUE = new ContinueResult();
 
-    protected static class OperationCallResult {
+    /**
+     * The result of an operation call.
+     * Represents the situation where a return statement was encountered.
+     */
+    public static class OperationCallResult implements BreakingResult {
     	public Object myResult;
     	public QvtOperationalEvaluationEnv myEvalEnv;
     	
@@ -1866,9 +1923,6 @@
         	
         	callResult = (OperationCallResult)result;
         }
-        catch (ReturnExpEvent e) {
-        	callResult = e.getResult();
-        }
         catch (StackOverflowError e) {
         	throwQVTException(new QvtStackOverFlowError(e));
         }
@@ -2489,26 +2543,6 @@
 				}
 			}
 		}
-	}    
-    
-
-	/**
-	 * TODO - Avoid using this exception return expression to interrupt execution flow for 
-	 * immediate return from an operation.
-	 * Though, if the last statement in a body is return expression, no exception is thrown, we
-	 * should try to avoid this cost to be paid in general
-	 */
-	private static class ReturnExpEvent extends QvtRuntimeException {
-		private static final long serialVersionUID = 2971434369853642555L;		
-		private final OperationCallResult fResult;
-		
-		ReturnExpEvent(Object returnValue, QvtOperationalEvaluationEnv evalEnv) {
-			fResult = new OperationCallResult(returnValue, evalEnv);
-		}
-		
-		public OperationCallResult getResult() {
-			return fResult;
-		}
 	}
 
 }
diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/QvtTransitionReachedException.java b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/QvtTransitionReachedException.java
deleted file mode 100644
index 5f797d8..0000000
--- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/QvtTransitionReachedException.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2009 Borland Software Corporation 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:
- *     Borland Software Corporation - initial API and implementation
- *******************************************************************************/
-
-package org.eclipse.m2m.internal.qvt.oml.evaluator;
-
-
-public class QvtTransitionReachedException extends QvtRuntimeException {
-
-	private static final long serialVersionUID = 460249893891473965L;
-
-	public static final int REASON_BREAK = 1;
-	
-	public static final int REASON_CONTINUE = 2;
-
-	public QvtTransitionReachedException(int reason) {
-		myReason = reason;
-	}
-	
-	public int getReason() {
-		return myReason;
-	}
-	
-	private final int myReason;
-	
-}
diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/iterators/QvtImperativeIteratorTemplate.java b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/iterators/QvtImperativeIteratorTemplate.java
index 6392757..3b22f86 100644
--- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/iterators/QvtImperativeIteratorTemplate.java
+++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/iterators/QvtImperativeIteratorTemplate.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2009 Borland Software Corporation and others.
+ * Copyright (c) 2008, 2015 Borland Software Corporation and others.
  * 
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -18,6 +18,7 @@
 import org.eclipse.emf.ecore.EParameter;
 import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalEvaluationEnv;
 import org.eclipse.m2m.internal.qvt.oml.ast.parser.QvtOperationalUtil;
+import org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.BreakingResult;
 import org.eclipse.ocl.EvaluationEnvironment;
 import org.eclipse.ocl.EvaluationVisitor;
 import org.eclipse.ocl.expressions.OCLExpression;
@@ -53,6 +54,11 @@
         	bodyVal = getEvalEnvironment().getValueOf(iterators.get(0).getName());
         }
 
+        if(bodyVal instanceof BreakingResult) {
+        	// Control flow was broken (break, continue, return); propagate this.
+        	return bodyVal;
+        }
+        
         advanceTarget(target, bodyVal);
 
         // get the new result value
diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/iterators/QvtIterationTemplate.java b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/iterators/QvtIterationTemplate.java
index c26ec3e..aa47e58 100644
--- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/iterators/QvtIterationTemplate.java
+++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/iterators/QvtIterationTemplate.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2009 Borland Software Corporation and others.
+ * Copyright (c) 2007, 2015 Borland Software Corporation and others.
  * 
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -22,7 +22,8 @@
 
 import org.eclipse.emf.ecore.EClassifier;
 import org.eclipse.emf.ecore.EParameter;
-import org.eclipse.m2m.internal.qvt.oml.evaluator.QvtTransitionReachedException;
+import org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.BreakingResult;
+import org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.ContinueResult;
 import org.eclipse.ocl.EvaluationEnvironment;
 import org.eclipse.ocl.EvaluationVisitor;
 import org.eclipse.ocl.expressions.OCLExpression;
@@ -80,17 +81,16 @@
             while (true) {
             	Object resultVal = null;
             	boolean isUpdateResultVal = true;
-            	try {
-            		resultVal = evaluateResultTemplate(iterators, target, resultName, condition, body, isOne);
-            	}
-            	catch (QvtTransitionReachedException ex) {
-            		if (ex.getReason() == QvtTransitionReachedException.REASON_BREAK) {
-            			setDone(true);
-            		}
-            		if (ex.getReason() == QvtTransitionReachedException.REASON_CONTINUE) {
-            		}
+        		resultVal = evaluateResultTemplate(iterators, target, resultName, condition, body, isOne);
+        		
+        		if(resultVal instanceof BreakingResult) {
+        			// Control flow was broken (break, continue, or return). 
+        			if(!(resultVal instanceof ContinueResult)) {
+        				// No continue, so no more iterations.
+        				setDone(true);
+        			}
             		isUpdateResultVal = false;
-            	}
+        		}
 
                 // set the result variable in the environment with the result value
                 if (isUpdateResultVal) {
diff --git a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/iterators/QvtIterationTemplateForExp.java b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/iterators/QvtIterationTemplateForExp.java
index 65d5474..4ef3a82 100644
--- a/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/iterators/QvtIterationTemplateForExp.java
+++ b/plugins/org.eclipse.m2m.qvt.oml/src/org/eclipse/m2m/internal/qvt/oml/evaluator/iterators/QvtIterationTemplateForExp.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008 Borland Software Corporation and others.
+ * Copyright (c) 2008, 2015 Borland Software Corporation and others.
  * 
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -15,6 +15,7 @@
 
 import org.eclipse.emf.ecore.EClassifier;
 import org.eclipse.emf.ecore.EParameter;
+import org.eclipse.m2m.internal.qvt.oml.evaluator.QvtOperationalEvaluationVisitorImpl.BreakingResult;
 import org.eclipse.ocl.EvaluationVisitor;
 import org.eclipse.ocl.expressions.OCLExpression;
 import org.eclipse.ocl.expressions.Variable;
@@ -47,10 +48,13 @@
             isConditionOk = (conditionVal instanceof Boolean) && (Boolean) conditionVal;
         }
         if (isConditionOk) {
-            getEvaluationVisitor().visitExpression(body);
+            Object result = getEvaluationVisitor().visitExpression(body);
             if (isOne) {
                 setDone(true);
             }
+            if(result instanceof BreakingResult) {
+            	return result;
+            }
         }
         return null;
     }
diff --git a/tests/org.eclipse.m2m.tests.qvt.oml/parserTestData/models/continue_break/continue_break.qvto b/tests/org.eclipse.m2m.tests.qvt.oml/parserTestData/models/continue_break/continue_break.qvto
index c1bef6d..e2ee1fc 100644
--- a/tests/org.eclipse.m2m.tests.qvt.oml/parserTestData/models/continue_break/continue_break.qvto
+++ b/tests/org.eclipse.m2m.tests.qvt.oml/parserTestData/models/continue_break/continue_break.qvto
@@ -1,6 +1,6 @@
 transformation continue_break();
 
-mapping main() { 
+main() { 
 
 	var index := 0;
 	while(true) { 
@@ -22,6 +22,12 @@
 	};
 	assert fatal (index = 7);
 
+	col->forEach(i) {
+		if i = 1 then break endif;
+		index := index + 1;
+	};
+	assert fatal (index = 7);
+
 	var col1 := col->collectselect(i;
 		res = compute (x : String := i.toString()) {
 			if i > 2 then break else continue endif;