/* * Copyright (c) 2004- michael lawley and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation * which accompanies this distribution, and is available by writing to * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Contributors: * michael lawley * * * */ package tefkat.plugin.debug; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Stack; import java.util.WeakHashMap; import org.eclipse.core.resources.IMarkerDelta; import org.eclipse.debug.core.DebugEvent; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.model.IBreakpoint; import org.eclipse.debug.core.model.IDebugTarget; import org.eclipse.debug.core.model.IMemoryBlock; import org.eclipse.debug.core.model.IProcess; import org.eclipse.debug.core.model.IStackFrame; import org.eclipse.debug.core.model.IThread; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import tefkat.engine.Binding; import tefkat.engine.Node; import tefkat.engine.Tefkat; import tefkat.engine.TefkatListener2; import tefkat.engine.Tree; import tefkat.model.Extent; import tefkat.model.TRule; import tefkat.model.Term; import tefkat.model.Transformation; import tefkat.model.parser.ParserEvent; import tefkat.model.parser.ParserListener; /** * @author lawley * */ public class DebugTarget extends AbstractDebugElement implements IDebugTarget, ParserListener { private ILaunch launch; private IThread[] threads; private Map treeThreadMap = new HashMap(); private Tefkat engine; private Node currentNode = null; // private TRule currentRule = null; private Stack nodes = new Stack(); private Stack trees = new Stack(); private boolean suspended; private Map startCharMap = new WeakHashMap(); private Map endCharMap = new WeakHashMap(); int suspendCount; /** * */ public DebugTarget(ILaunch launch, Tefkat tefkat) { super(null); target = this; this.launch = launch; this.engine = tefkat; // final DebugThread thread = new DebugThread(this); threads = new IThread[] {}; engine.addTefkatListener(new TefkatListener2() { // int depth = 0; boolean initial = true; List threadList = new ArrayList(); public void started() { // System.out.println("STARTED"); suspendCount = 0; initial = true; fireCreationEvent(); engine.pause(); // breakpoint(null); } public void stopped() { fireTerminateEvent(); } public void breakpoint(Term t) { // System.out.println("BREAKPOINT"); suspended = true; DebugThread thread = (DebugThread) treeThreadMap.get(trees.peek()); thread.setStepping(true); fireSuspendEvent(DebugEvent.BREAKPOINT); } public void suspended() { // System.out.println("SUSPENDED"); suspended = true; suspendCount++; DebugThread thread = (DebugThread) treeThreadMap.get(trees.peek()); thread.setStepping(true); if (initial) { initial = false; fireSuspendEvent(DebugEvent.CLIENT_REQUEST); } else { fireSuspendEvent(DebugEvent.STEP_END); } } public void resumed() { suspended = false; DebugThread thread = (DebugThread) treeThreadMap.get(trees.peek()); thread.setStepping(false); fireResumeEvent(DebugEvent.STEP_OVER); } public void info(String message) {} public void warning(String message) {} public void error(String message, Throwable cause) {} public void resourceLoaded(Resource res) {} public void transformationStarted(Transformation transformation, Extent[] srcs, Extent[] tgts, Extent trace, Binding context) {} public void transformationFinished() {} public void evaluateRule(TRule rule, Binding context, boolean cached) { // This is not set correctly for incremental evaluation since we don't // do one rule at a time, but jump between rules // currentRule = rule; } public void evaluateSource(TRule rule, Binding context) {} public void evaluateTarget(TRule rule, Binding context) {} public void enterTerm(Node node) { currentNode = node; nodes.set(nodes.size()-1, node); // depth++; // indent(depth, '>'); // System.err.print(" " + node.selectedLiteral() + " ? "); } public void exitTerm(Node node) { currentNode = node; nodes.set(nodes.size()-1, node); // System.err.println(node.binding()); // indent(depth, '<'); // System.err.println(" " + !node.isFailure()); // depth--; } public void delayTerm(Node node) { currentNode = node; nodes.set(nodes.size()-1, node); // System.err.println(node.binding()); // indent(depth, '-'); // System.err.println(" delayed"); // depth--; } // private void indent(int n, char c) { // for (int i = 0; i < n; i++) { // System.err.print(c); // } // } public void enterTree(Tree tree) { trees.push(tree); nodes.push(null); } public void exitTree(Tree tree) { Object top = trees.pop(); if (!tree.equals(top)) { System.err.println("ERROR: tree stack out of sync"); } nodes.pop(); } public void treeAdded(Tree tree) { DebugThread thread = new DebugThread(String.valueOf(threads.length), target, tree); treeThreadMap.put(tree, thread); threadList.add(thread); threads = (IThread[]) threadList.toArray(threads); } public void treeRemoved(Tree tree) { DebugThread thread = (DebugThread) treeThreadMap.remove(tree); threadList.remove(thread); threads = (IThread[]) threadList.toArray(threads); } }); } /** * Returns the current stack frames in the target. * * @return the current stack frames in the target * @throws DebugException if unable to perform the request */ protected IStackFrame[] getStackFrames(DebugThread thread) throws DebugException { List frames = new ArrayList(); if (thread.equals(treeThreadMap.get(trees.peek()))) { for (Node node = currentNode; node != null; ) { frames.add(new NodeSelectedLiteralStackFrame(thread, node)); node = node.getParentNode(); } } // frames.add(new RuleStackFrame(thread, currentRule)); return (IStackFrame[]) frames.toArray(new IStackFrame[frames.size()]); } protected boolean isCurrentThread(DebugThread thread) { return thread.equals(treeThreadMap.get(trees.peek())); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IDebugTarget#getProcess() */ public IProcess getProcess() { return null; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IDebugTarget#getLaunch() */ public ILaunch getLaunch() { return launch; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IDebugTarget#getThreads() */ public IThread[] getThreads() throws DebugException { return threads; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IDebugTarget#hasThreads() */ public boolean hasThreads() throws DebugException { return getThreads().length > 0; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IDebugTarget#getName() */ public String getName() throws DebugException { return "Tefkat Debug"; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IDebugTarget#supportsBreakpoint(org.eclipse.debug.core.model.IBreakpoint) */ public boolean supportsBreakpoint(IBreakpoint breakpoint) { return false; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.ITerminate#canTerminate() */ public boolean canTerminate() { return !isTerminated(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.ITerminate#isTerminated() */ public boolean isTerminated() { return !engine.getRunning() || engine.getInterrupted(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.ITerminate#terminate() */ public void terminate() throws DebugException { engine.setInterrupted(true); engine.step(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.ISuspendResume#canResume() */ public boolean canResume() { return !isTerminated() && isSuspended(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.ISuspendResume#canSuspend() */ public boolean canSuspend() { return !isTerminated() && !isSuspended(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.ISuspendResume#isSuspended() */ public boolean isSuspended() { return suspended; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.ISuspendResume#resume() */ public void resume() throws DebugException { engine.resume(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.ISuspendResume#suspend() */ public void suspend() throws DebugException { engine.pause(); } public void step() { engine.step(); } public void stepReturn() { engine.stepReturn(); } /* (non-Javadoc) * @see org.eclipse.debug.core.IBreakpointListener#breakpointAdded(org.eclipse.debug.core.model.IBreakpoint) */ public void breakpointAdded(IBreakpoint breakpoint) { } /* (non-Javadoc) * @see org.eclipse.debug.core.IBreakpointListener#breakpointRemoved(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta) */ public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) { } /* (non-Javadoc) * @see org.eclipse.debug.core.IBreakpointListener#breakpointChanged(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta) */ public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) { } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IDisconnect#canDisconnect() */ public boolean canDisconnect() { return false; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IDisconnect#disconnect() */ public void disconnect() throws DebugException { } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IDisconnect#isDisconnected() */ public boolean isDisconnected() { return false; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#supportsStorageRetrieval() */ public boolean supportsStorageRetrieval() { return false; } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#getMemoryBlock(long, long) */ public IMemoryBlock getMemoryBlock(long startAddress, long length) throws DebugException { return null; } /* (non-Javadoc) * @see tefkat.model.parser.ParserListener#matched(tefkat.model.parser.ParserEvent) */ public void matched(ParserEvent event) { System.err.println("matched"); startCharMap.put(event.getObj(), new Integer(event.getStartChar())); endCharMap.put(event.getObj(), new Integer(event.getEndChar())); } public int getStartChar(EObject obj) { System.err.println("getStartChar: " + obj); while (obj != null) { // look up position Integer pos = (Integer) startCharMap.get(obj); if (pos != null) { return pos.intValue(); } // not found so go to parent obj = obj.eContainer(); System.err.println(" " + obj); } System.err.println(" -1"); System.err.println(startCharMap); return -1; } public int getEndChar(EObject obj) { while (obj != null) { // look up position Integer pos = (Integer) endCharMap.get(obj); if (pos != null) { return pos.intValue(); } // not found so go to parent obj = obj.eContainer(); } return -1; } }