All Downloads are FREE. Search and download functionalities are using the official Maven repository.

prompto.debug.WorkerDebugger Maven / Gradle / Ivy

The newest version!
package prompto.debug;

import java.util.Collection;
import java.util.Collections;

import prompto.debug.ProcessDebugger.DebuggedWorker;
import prompto.debug.event.WorkerCompletedDebugEvent;
import prompto.debug.event.WorkerStartedDebugEvent;
import prompto.debug.stack.IStackFrame;
import prompto.debug.stack.WorkerStack;
import prompto.debug.stack.WorkerStackFrame;
import prompto.debug.variable.IVariable;
import prompto.debug.worker.IWorker;
import prompto.declaration.CategoryDeclaration;
import prompto.declaration.IMethodDeclaration;
import prompto.declaration.TestMethodDeclaration;
import prompto.error.PromptoError;
import prompto.error.TerminatedError;
import prompto.parser.ISection;
import prompto.runtime.Context;
import prompto.utils.Logger;

public class WorkerDebugger implements IWorkerDebugger {

	static Logger logger = new Logger();
	
	WorkerStack stack = new WorkerStack();
	Object lock = new Object();
	WorkerStatus status = WorkerStatus.WORKER_UNREACHABLE;
	boolean suspended = false;
	boolean terminated = false;
	ResumeReason resumeReason;
	IDebugEventListener listener;
	Context context;
	int stepDepth = 0;
	/* 
	 stepDepth represents the stack depth at which we should be stepping 
	 it is normally positive, except when user requests stepOut
	 on stepInto we increase the depth by one such that the next statement in the invoked method will suspend
	 on stepOver we don't increase the depth such that only the next statement in the current method whill suspend
	 on StepOut we invert the value such that leaving the method will suspend
	 on resume we simply zero the depth
	*/
	
	
	@Override
	public WorkerStack getStack() {
		return stack;
	}
	
	@Override
	public Collection getVariables(IStackFrame frame) {
		WorkerStackFrame sf = stack.find(frame);
		if(sf!=null)
			return sf.getVariables();
		// need some debug info
		System.err.println("Could not find frame: " +frame.toString() + " in stack:");
		stack.forEach(f->System.err.println(f.toString()));
		return Collections.emptyList();
	}
	
	
	@Override
	public IVariable getVariable(IStackFrame frame, String variableName) {
		WorkerStackFrame sf = stack.find(frame);
		if(sf!=null)
			return sf.getVariable(variableName);
		// need some debug info
		System.err.println("Could not find frame: " +frame.toString() + " in stack:");
		stack.forEach(f->System.err.println(f.toString()));
		return null;
	}
	
	public void setWorkerStatus(WorkerStatus status) {
		logger.debug(()->"LocalDebugger sets status " + status);
		this.status = status;
	}
	
	@Override
	public WorkerStatus getWorkerStatus() {
		return status;
	}
	
	@Override
	public void suspend() {
		suspended = true;
	}
	
	@Override
	public void terminate() {
		terminated = true;
		doResume(ResumeReason.RESUMED);
	}
	
	public IDebugEventListener getListener() {
		return listener;
	}
	
	public void setListener(IDebugEventListener listener) {
		this.listener = listener;
	}
	
	public void enterTest(Context context, TestMethodDeclaration test) {
		terminateIfRequested();
		this.context = context;
		stack.push(new WorkerStackFrame(context, null, test.getName(), null, stack.size(), test));
		terminateIfRequested();
	}
	
	public void enterMethod(Context context, IMethodDeclaration method) throws PromptoError {
		terminateIfRequested();
		this.context = context;
		CategoryDeclaration category = method.getMemberOf();
		String categoryName = category==null ? null : category.getName();
		stack.push(new WorkerStackFrame(context, categoryName, method.getName(), method.getProto(), stack.size(), method));
		terminateIfRequested();
	}

	public void leaveSection(Context context, ISection section) throws PromptoError {
		terminateIfRequested();
		if(stack.size()>0 && stack.size()==-stepDepth) {
			stepDepth = stack.size();
			suspend(SuspendReason.STEPPED, context, section); // stepping out
		} else
			suspendIfRequested(context, section);
		stack.pop();
		terminateIfRequested();
	}
	
	public void enterStatement(Context context, ISection section) throws PromptoError {
		terminateIfRequested();
		this.context = context;
		IStackFrame previous = stack.pop();
		stack.push(new WorkerStackFrame(context, previous.getCategoryName(), previous.getMethodName(), previous.getMethodProto(), previous.getMethodLine(), stack.size(), section));
		if(stack.size()>0 && stack.size()<=stepDepth)
			suspend(SuspendReason.STEPPED, context, section);
		else if(section.isBreakpoint()) {
			stepDepth = stack.size();
			suspend(SuspendReason.BREAKPOINT, context, section);
		} else
			suspendIfRequested(context, section);
		terminateIfRequested();
	}

	public void leaveStatement(Context context, ISection section) throws PromptoError {
		terminateIfRequested();
		if(stack.size()>0 && stack.size()==-stepDepth) {
			stepDepth = stack.size();
			suspend(SuspendReason.STEPPED, context, section);
		} else
			suspendIfRequested(context, section);
		terminateIfRequested();
	}
	
	private void terminateIfRequested() throws TerminatedError {
		if(terminated) {
			setWorkerStatus(WorkerStatus.WORKER_COMPLETED);
			throw new TerminatedError();
		}
	}

	private void suspendIfRequested(Context context, ISection section) {
		if(suspended) {
			suspended = false;
			stepDepth = stack.size();
			suspend(SuspendReason.SUSPENDED, context, section);
		}
		
	}

	public void suspend(SuspendReason reason, final Context context, ISection section) {
		logger.debug(()->"acquiring lock");
		synchronized(lock) {
			setWorkerStatus(WorkerStatus.WORKER_SUSPENDED);
			if(listener!=null)
				listener.onWorkerSuspendedEvent(DebuggedWorker.wrap(Thread.currentThread()), reason);
			try {
				logger.debug(()->"waiting lock");
				lock.wait();
				logger.debug(()->"waiting lock");
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {
				setWorkerStatus( WorkerStatus.WORKER_RUNNING);
				if(listener!=null)
					listener.onWorkerResumedEvent(DebuggedWorker.wrap(Thread.currentThread()), resumeReason);
			}
		}
	}	
	
	@Override
	public boolean isStepping() {
		return stepDepth!=0;
	}
	
	@Override
	public boolean canSuspend() {
		return !isSuspended();
	}

	@Override
	public boolean isSuspended() {
		return status==WorkerStatus.WORKER_SUSPENDED;
	}

	@Override
	public boolean canResume() {
		return isSuspended();
	}
	
	@Override
	public void resume() {
		stepDepth = 0;
		doResume(ResumeReason.RESUMED);
	}
	
	@Override
	public boolean canStepOver() {
		return isSuspended();
	}
	
	@Override
	public void stepOver() {
		stepDepth = stack.size();
		doResume(ResumeReason.STEP_OVER);
	}

	@Override
	public boolean canStepInto() {
		return isSuspended();
	}
	
	@Override
	public void stepInto() {
		stepDepth = Math.abs(stepDepth) + 1;
		doResume(ResumeReason.STEP_INTO);
	}
	
	@Override
	public boolean canStepOut() {
		return isSuspended();
	}
	
	@Override
	public void stepOut() {
		stepDepth = -(Math.abs(stepDepth) - 1);
		doResume(ResumeReason.STEP_OUT);
	}
	
	public void doResume(ResumeReason reason) {
		this.resumeReason = reason;
		logger.debug(()->"acquiring lock");
		synchronized(lock) {
			logger.debug(()->"notifying lock");
			lock.notify();
			logger.debug(()->"releasing lock");
		}
	}

	
	@Override
	public int getLineInFile() {
		IStackFrame frame = stack.peek();
		return frame==null ? -1 : frame.getStatementLine();
	}
	
	
	@Override
	public int getLineInMethod() {
		IStackFrame frame = stack.peek();
		return frame==null ? -1 : 1 + frame.getMethodLine() - frame.getStatementLine();
	}
	
	public void notifyStarted(WorkerStartedDebugEvent event) {
		setWorkerStatus(WorkerStatus.WORKER_RUNNING);
		if(listener!=null) {
			IWorker worker = DebuggedWorker.parse(event.getWorkerId());
			listener.onWorkerStartedEvent(worker); 
		}
	}
	
	public void notifyCompleted(WorkerCompletedDebugEvent event) {
		ProcessDebugger.getInstance().unregister(Thread.currentThread());
		if(listener!=null) {
			IWorker worker = DebuggedWorker.parse(event.getWorkerId());
			listener.onWorkerCompletedEvent(worker); 
		}
	}



	
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy