/******************************************************************************* * Copyright (c) 2005 - 2007 committers of openArchitectureWare 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: * committers of openArchitectureWare - initial API and implementation *******************************************************************************/ package org.eclipse.internal.xpand2.debug; import static org.eclipse.emf.mwe.core.debug.processing.EventHandler.NORMAL_FRAME; import java.util.Collection; import java.util.Stack; import org.eclipse.emf.mwe.core.debug.model.SyntaxElement; import org.eclipse.internal.xpand2.ast.ExpandStatement; import org.eclipse.internal.xtend.expression.ast.Expression; import org.eclipse.internal.xtend.expression.ast.ISyntaxElement; import org.eclipse.internal.xtend.expression.debug.BaseSpecialTreatment; import org.eclipse.xpand2.XpandExecutionContext; import org.eclipse.xtend.expression.ExecutionContext; import org.eclipse.xtend.typesystem.Type; /** * An ExpandStatement calls monitor.preTask() always twice in case of isForeach. The first call is for the * Statement itself and the second for every execution of the included definition.<br> * We remember each call on a Stack and use the first entry to store count and number of loops.<br> * This (outer) frame is hiddened.<br> * <br> * We do this whole mechanism (different from the Java behavior) that the user can go over one execution of the * EXPAND with Step_Over and go over all loops with Step_Return. In Java this behavior is not possible. There is * the Ctrl+R functionality, what is not implemented for our debug model.<br> * <br> * We can't use an empty iterator as in Foreach, because an expand could be called iteratively.<br> * Therefore we remember each 2nd time the statement together with it's target element count. * * @author Clemens Kadura (zAJKa) */ public class ExpandSpecial extends BaseSpecialTreatment { private Stack<Wrapper> stack = new Stack<Wrapper>(); private Stack<ISyntaxElement> sstack = new Stack<ISyntaxElement>(); private ISyntaxElement lastSingleDef; private int adaptCnt = 0; @Override public boolean shallNotSuspend(Object element, int flag, ExecutionContext ctx) { if (!(element instanceof ExpandStatement)) return false; ExpandStatement stmt = (ExpandStatement) element; if (!((ExpandStatement) element).isForeach()) { if (flag == NORMAL_FRAME) { Expression target = stmt.getTarget(); Object targetObject = (target != null ? target.evaluate(ctx) : ctx.getVariable(ExecutionContext.IMPLICIT_VARIABLE).getValue()); sstack.push(getEvaluatedDefinition((ExpandStatement) element, targetObject, (XpandExecutionContext) ctx)); } else // we have to remeber this, because it is earlier poped than red lastSingleDef = sstack.pop(); return false; } if (flag == NORMAL_FRAME) { Wrapper current = new Wrapper(); Wrapper last = (!stack.isEmpty()) ? stack.peek() : null; stack.push(current); if (stack.size() % 2 != 0) { current.target = stmt.getTarget().evaluate(ctx); // disable suspension the first time return true; } // 2nd time last.def = getEvaluatedDefinition((ExpandStatement) element, ((Collection<?>) last.target).toArray()[last.count], (XpandExecutionContext) ctx); last.count++; return false; } if (adaptCnt >= stack.size()) adaptCnt--; stack.pop(); return stack.size() % 2 == 0; } @Override public void adaptSyntaxElement(SyntaxElement to, Object element) { if (!(element instanceof ExpandStatement) || !((ExpandStatement) element).isForeach()) return; if (adaptCnt % 2 != 0) to.visible = false; } @Override public String adaptElementName(ISyntaxElement se, ExecutionContext context) { if (!(se instanceof ExpandStatement) || !((ExpandStatement) se).isForeach()) return ""; adaptCnt++; if (adaptCnt % 2 == 0) { Wrapper last = stack.get(adaptCnt - 2); return " " + last.count + " of " + ((Collection<?>) last.target).size(); } return ""; } @Override public ISyntaxElement getSpecialEndSyntaxElement(ISyntaxElement se) { if (!(se instanceof ExpandStatement)) return null; if (((ExpandStatement) se).isForeach()) { return stack.peek().def; } return lastSingleDef; } // ------------------------------------------------------------------------- private ISyntaxElement getEvaluatedDefinition(ExpandStatement stmt, Object targetObject, XpandExecutionContext ctx) { Expression[] pex = stmt.getParameters(); Object[] params = new Object[pex.length]; for (int i = 0; i < pex.length; i++) { params[i] = pex[i].evaluate(ctx); } Type[] paramTypes = new Type[params.length]; for (int i = 0; i < params.length; i++) { paramTypes[i] = ctx.getType(params[i]); } String defName = stmt.getDefinition().getValue(); return ctx.findDefinition(defName, ctx.getType(targetObject), paramTypes); } // ------------------------------------------------------------------------- class Wrapper { public Object target; public ISyntaxElement def; public int count; } }