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

js.prompto.debug.Debugger Maven / Gradle / Ivy

package prompto.debug;

import prompto.declaration.IMethodDeclaration;
import prompto.error.PromptoError;
import prompto.error.TerminatedError;
import prompto.parser.ISection;
import prompto.runtime.Context;

public class Debugger {

	Stack stack = new Stack();
	Object blocker = new Object();
	Status status = Status.STARTING;
	ResumeReason resumeReason;
	IDebugEventListener listener;
	// positive for stepping on enterXXX
	// negative for stepping on leaveXXX
	// necessary to avoid stepping twice on the same statement
	int stepDepth = 1;
	boolean suspended = false;
	boolean terminated = false;
	
	public static enum Status {
		STARTING,
		RUNNING,
		SUSPENDED,
		TERMINATING,
		TERMINATED;
		
		@Override
		public String toString() {
			return name().substring(0,1) + name().substring(1).toLowerCase();
		}
	}
	
	public Stack getStack() {
		return stack;
	}
	
	public Status getStatus() {
		return status;
	}
	
	public void suspend() {
		suspended = true;
	}
	
	public boolean isTerminated() {
		return status==Status.TERMINATED;
	}
	
	public void terminate() {
		terminated = true;
	}
	
	public IDebugEventListener getListener() {
		return listener;
	}
	
	public void setListener(IDebugEventListener listener) {
		this.listener = listener;
	}
	
	public void enterMethod(Context context, IMethodDeclaration method) throws PromptoError {
		terminateIfRequested();
		stack.push(new StackFrame(context, method.getName(), method));
		if(stack.size()>0 && stack.size()<=stepDepth)
			suspend(SuspendReason.STEPPING, context, method);
		else if(method.isBreakpoint())
			suspend(SuspendReason.BREAKPOINT, context, method);
		else
			suspendIfRequested(context, method);
		terminateIfRequested();
	}

	public void leaveMethod(Context context, ISection section) throws PromptoError {
		terminateIfRequested();
		if(stack.size()>0 && stack.size()==-stepDepth)
			suspend(SuspendReason.STEPPING, context, section);
		else
			suspendIfRequested(context, section);
		stack.pop();
		terminateIfRequested();
	}
	
	public void enterStatement(Context context, ISection section) throws PromptoError {
		terminateIfRequested();
		StackFrame previous = stack.pop();
		stack.push(new StackFrame(context, previous.getMethodName(), section));
		if(stack.size()>0 && stack.size()<=stepDepth)
			suspend(SuspendReason.STEPPING, context, section);
		else if(section.isBreakpoint())
			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)
			suspend(SuspendReason.STEPPING, context, section);
		else
			suspendIfRequested(context, section);
		terminateIfRequested();
	}
	
	private void terminateIfRequested() throws TerminatedError {
		if(terminated) {
			status = Status.TERMINATING;
			throw new TerminatedError();
		}
	}

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

	public void suspend(SuspendReason reason, final Context context, ISection section) {
		synchronized(blocker) {
			status = Status.SUSPENDED;
			if(listener!=null)
				listener.handleSuspendEvent(reason, context, section);
			try {
				blocker.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {
				status = Status.RUNNING;
				if(listener!=null)
					listener.handleResumeEvent(resumeReason, context, section);
			}
		}
	}	
	
	public boolean isStepping() {
		return stepDepth!=0;
	}
	
	public boolean canSuspend() {
		return !isSuspended();
	}

	public boolean isSuspended() {
		return status==Status.SUSPENDED;
	}

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

	public boolean canStepInto() {
		return isSuspended();
	}
	
	public void stepInto() {
		stepDepth = Math.abs(stepDepth) + 1;
		doResume(ResumeReason.STEP_INTO);
	}
	
	public boolean canStepOut() {
		return isSuspended();
	}
	
	public void stepOut() {
		stepDepth = -(Math.abs(stepDepth) - 1);
		doResume(ResumeReason.STEP_OUT);
	}

	public void doResume(ResumeReason reason) {
		this.resumeReason = reason;
		synchronized(blocker) {
			blocker.notify();
		}
	}

	public int getLine() {
		StackFrame frame = stack.peek();
		return frame==null ? -1 : frame.getLine();
	}

	public void terminated() {
		status = Status.TERMINATED;
		if(listener!=null)
			listener.handleTerminateEvent();
	}
	
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy