/******************************************************************************* * Copyright (c) 2009-2012 CWI * 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: * * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl - CWI * * Emilie Balland - (CWI) * * Arnold Lankamp - Arnold.Lankamp@cwi.nl * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI *******************************************************************************/ package org.rascalmpl.eclipse.debug.core.model; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Set; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.model.IRegisterGroup; import org.eclipse.debug.core.model.IStackFrame; import org.eclipse.debug.core.model.IThread; import org.eclipse.debug.core.model.IVariable; import org.rascalmpl.debug.IRascalFrame; import org.rascalmpl.interpreter.result.IRascalResult; import org.rascalmpl.uri.URIResolverRegistry; import io.usethesource.vallang.ISourceLocation; public class RascalStackFrame extends RascalDebugElement implements IStackFrame { /** * The thread that created this stack frame. */ private final RascalThread thread; /** * Location information w.r.t. current execution point within this stack frame. */ private final ISourceLocation location; /** * Gives identity to stack frames that are nested due to recursion */ private final IStackFrame parent; private final IVariable[] variables; private final String name; public RascalStackFrame(RascalThread thread, IRascalFrame environment, ISourceLocation location, IStackFrame parent) { super(thread.getDebugTarget()); this.parent = parent; this.thread = thread; /* need to clone to know previous state, in order to compute model deltas */ this.location = location; this.variables = initVariables(environment); this.name = environment.getName(); } private IVariable[] initVariables(IRascalFrame environment) { //manage the list of variables local to the current module Set<String> keys = environment.getFrameVariables(); List<String> vars = new ArrayList<>(keys.size()); vars.addAll(keys); Collections.sort(vars); ArrayList<IVariable> ivars = new ArrayList<>(vars.size() * 2); for (String v : vars) { IRascalResult var = environment.getFrameVariable(v); ivars.add(new RascalVariable(this, v, var.getType(), var.getValue())); } for (String s:environment.getImports()) { IRascalFrame module = thread.getRascalDebugTarget().getEvaluator().getModule(s); if (module != null) { Set<String> variables = module.getFrameVariables(); for (String v:variables) { IRascalResult w = module.getFrameVariable(v); ivars.add(new RascalVariable(this, s + "::" + v, w.getType(), w.getValue())); } } } return ivars.toArray(new IVariable[ivars.size()]); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IStackFrame#getCharEnd() */ public int getCharEnd() throws DebugException { if (location == null) { return -1; } else { return location.getOffset() + location.getLength(); } } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IStackFrame#getCharStart() */ public int getCharStart() throws DebugException { if (location == null) { return -1; } else { return location.getOffset(); } } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IStackFrame#getLineNumber() */ public int getLineNumber() throws DebugException { if (location == null || !location.hasLineColumn()) { return -1; } else { return location.getBeginLine(); } } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IStackFrame#getName() */ public String getName() throws DebugException { return name; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IStackFrame#getRegisterGroups() */ public IRegisterGroup[] getRegisterGroups() throws DebugException { return new IRegisterGroup[] {}; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IStackFrame#getThread() */ public IThread getThread() { return thread; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IStackFrame#getVariables() */ public IVariable[] getVariables() throws DebugException { return variables; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IStackFrame#hasRegisterGroups() */ public boolean hasRegisterGroups() throws DebugException { return false; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IStackFrame#hasVariables() */ public boolean hasVariables() throws DebugException { return variables.length > 0; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IStep#canStepInto() */ public boolean canStepInto() { return getThread().canStepInto(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IStep#canStepOver() */ public boolean canStepOver() { return getThread().canStepOver(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IStep#canStepReturn() */ public boolean canStepReturn() { return getThread().canStepReturn(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IStep#isStepping() */ public boolean isStepping() { return getThread().isStepping(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IStep#stepInto() */ public void stepInto() throws DebugException { getThread().stepInto(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IStep#stepOver() */ public void stepOver() throws DebugException { getThread().stepOver(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IStep#stepReturn() */ public void stepReturn() throws DebugException { getThread().stepReturn(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.ISuspendResume#canResume() */ public boolean canResume() { return getThread().canResume(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.ISuspendResume#canSuspend() */ public boolean canSuspend() { return getThread().canSuspend(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.ISuspendResume#isSuspended() */ public boolean isSuspended() { return getThread().isSuspended(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.ISuspendResume#resume() */ public void resume() throws DebugException { getThread().resume(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.ISuspendResume#suspend() */ public void suspend() throws DebugException { getThread().suspend(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.ITerminate#canTerminate() */ public boolean canTerminate() { return getThread().canTerminate(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.ITerminate#isTerminated() */ public boolean isTerminated() { return getThread().isTerminated(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.ITerminate#terminate() */ public void terminate() throws DebugException { getThread().terminate(); } /** * Returns if there is a supported source location associated with this stack frame. * * @return <code>true</code> if there exists a source file name, otherwise <code>false</code> * @see URIResolverRegistry#getResourceURI(java.net.URI) */ public boolean hasSourceName() { return location != null; } /** * Returns the source file name associated with this stack frame. * * @return the source file name associated, if existent * @see #hasSourceName() */ public String getSourceName() { assert hasSourceName(); return location.top().getURI().toString(); } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) * used by eclipse to refresh the view * (see the fireDeltaUpdatingSelectedFrame of the ThreadEventHandler class) */ public boolean equals(Object obj) { if (obj instanceof RascalStackFrame) { RascalStackFrame sf = (RascalStackFrame) obj; return obj == this || (Arrays.equals(variables, sf.variables) && ((parent == null && sf.parent == null) || (parent != null && sf.parent != null && parent.equals(sf.parent))) && thread == sf.thread && location.equals(sf.location) ); } return false; } @Override public int hashCode() { return 3 + location.hashCode() + ((parent != null) ? 1331 * parent.hashCode() : 1); } }