use of nl.ramsolutions.sw.magik.debugadapter.slap.ISlapResponse in project magik-tools by StevenLooman.
the class ThreadManager method stackTrace.
/**
* Get a stack trace for a given thread.
* @param threadId Thread ID.
* @return StackFrames for thread.
* @throws IOException -
* @throws InterruptedException -
* @throws ExecutionException -
*/
List<StackFrame> stackTrace(final long threadId) throws IOException, InterruptedException, ExecutionException {
final CompletableFuture<ISlapResponse> threadStackFuture = this.slapProtocol.getThreadStack(threadId);
final ThreadStackResponse threadStack = (ThreadStackResponse) threadStackFuture.get();
// Do conversion here due to filtering on language + getting source,
// instead of Lsp4jConversion.
final List<StackFrame> stackFrames = new ArrayList<>();
for (final ThreadStackResponse.StackElement stackElement : threadStack.getStackFrames()) {
if (!stackElement.getLanguage().equals(LANGUAGE_MAGIK) || stackElement.getName().equals(UNKNOWN_EXEMPLAR_UNKNOWN_METHOD) || stackElement.getName().equals(LOOPBODY)) {
continue;
}
Path path = null;
try {
String method = stackElement.getName();
if (!method.equals(UNNAMED_PROC)) {
final int indexDot = method.indexOf(".");
final int indexBracket = method.indexOf("[");
final int index = indexDot != -1 ? indexDot + 1 : indexBracket;
if (!method.contains(":") && index != -1) {
// Do some extra work to determine package.
final int level = stackElement.getLevel();
final String methodName = ":|" + method.substring(index) + "|";
final String expr = String.format(EVAL_EXEMPLAR_PACKAGE, methodName);
LOGGER.debug("Eval expression: {}", expr);
final EvalResponse eval = (EvalResponse) this.slapProtocol.evaluate(threadId, level, expr).get();
method = eval.getResult() + ":" + method;
// Bonus: update exemplar name with package.
stackElement.setName(method);
}
// Clear any spaces (before `<<`/`^<<`). Lazy approach...
method = method.replace(" ", "");
// Get source file for method.
final CompletableFuture<ISlapResponse> sourceFileFuture = this.slapProtocol.getSourceFile(method);
final SourceFileResponse sourceFile = (SourceFileResponse) sourceFileFuture.get();
final String filename = sourceFile.getFilename();
path = Path.of(filename);
}
} catch (ExecutionException exception) {
final Throwable cause = exception.getCause();
if (cause instanceof SlapErrorException && ((SlapErrorException) cause).getError().getErrorMessage() != ErrorMessage.METHOD_NOT_FOUND) {
throw exception;
}
}
// This sets the frameId to the given stack frames.
final StackFrame stackFrame = Lsp4jConversion.toLsp4j(threadId, stackElement, path);
stackFrames.add(stackFrame);
}
return stackFrames;
}
use of nl.ramsolutions.sw.magik.debugadapter.slap.ISlapResponse in project magik-tools by StevenLooman.
the class ThreadManager method threads.
/**
* Get the Thread currently active.
* @return {{Thread}}s
* @throws IOException -
* @throws InterruptedException -
* @throws ExecutionException -
*/
List<Thread> threads() throws IOException, InterruptedException, ExecutionException {
// Get all thread IDs.
final CompletableFuture<ISlapResponse> futureThreadList = this.slapProtocol.getThreadList();
final ThreadListResponse threadList = (ThreadListResponse) futureThreadList.get();
// Get all thread info for each received thread ID.
final List<Thread> threads = new ArrayList<>();
for (long threadId : threadList.getThreadIds()) {
final CompletableFuture<ISlapResponse> threadInfoFuture = this.slapProtocol.getThreadInfo(threadId);
try {
final ThreadInfoResponse threadInfo = (ThreadInfoResponse) threadInfoFuture.get();
LOGGER.trace("Got thread, id: {}, thread info: {}", threadId, threadInfo);
final Thread thread = Lsp4jConversion.toLsp4j(threadId, threadInfo);
threads.add(thread);
} catch (ExecutionException exception) {
LOGGER.trace("Exception while getting thread, id: {}, exception: {}", threadId, exception.getMessage());
final Throwable cause = exception.getCause();
if (!(cause instanceof SlapErrorException && ((SlapErrorException) cause).getError().getErrorMessage() == ErrorMessage.UNKNOWN_ERROR)) {
throw exception;
}
}
}
return threads;
}
use of nl.ramsolutions.sw.magik.debugadapter.slap.ISlapResponse in project magik-tools by StevenLooman.
the class BreakpointManager method sendSetBreakpoint.
private MagikBreakpoint sendSetBreakpoint(final String method, final int line) throws IOException, InterruptedException, ExecutionException {
LOGGER.trace("Send set breakpoint: method: {}, line: {}", method, line);
final MagikBreakpoint magikBreakpoint = new MagikBreakpoint(method, line);
try {
final CompletableFuture<ISlapResponse> breakpointSetFuture = this.slapProtocol.setBreakpoint(method, line);
final BreakpointSetResponse breakpointSet = (BreakpointSetResponse) breakpointSetFuture.get();
final long breakpointId = breakpointSet.getBreakpointId();
magikBreakpoint.setBreakpointId(breakpointId);
} catch (ExecutionException exception) {
final Throwable cause = exception.getCause();
if (cause instanceof SlapErrorException) {
// Do nothing, verified will become false, error will be shown to user.
final SlapErrorException slapErrorException = (SlapErrorException) cause;
final String message = slapErrorException.getError().getErrorMessage().name();
magikBreakpoint.setMessage(message);
} else {
throw exception;
}
}
LOGGER.trace("Created breakpoint: {}", magikBreakpoint);
return magikBreakpoint;
}
use of nl.ramsolutions.sw.magik.debugadapter.slap.ISlapResponse in project magik-tools by StevenLooman.
the class BreakpointManagerTest method testAddBreakpointMethodNotFound.
@Test
void testAddBreakpointMethodNotFound() throws IOException, InterruptedException, ExecutionException {
final TestSlapProtocol slapProtocol = new TestSlapProtocol() {
@Override
public CompletableFuture<ISlapResponse> setBreakpoint(String method, int line) {
final ErrorResponse errorResponse = new ErrorResponse(RequestType.BREAKPOINT_SET, ErrorMessage.METHOD_NOT_FOUND);
final SlapErrorException exception = new SlapErrorException(errorResponse);
final CompletableFuture<ISlapResponse> future = new CompletableFuture<>();
future.completeExceptionally(exception);
return future;
}
};
final BreakpointManager manager = new BreakpointManager(slapProtocol, null);
final SourceBreakpoint sourceBreakpoint = new SourceBreakpoint();
sourceBreakpoint.setLine(18);
final Source source = new Source();
source.setPath(getPath("magik-debug-adapter/src/test/resources/bpt.magik").toString());
final BreakpointManager.MagikBreakpoint breakpoint = manager.addBreakpoint(source, sourceBreakpoint);
assertThat(breakpoint.getMethodName()).isEqualTo("user:bpt.t()");
assertThat(breakpoint.getMethodLine()).isEqualTo(18);
assertThat(breakpoint.getCondition()).isNull();
assertThat(breakpoint.getMessage()).isEqualTo("METHOD_NOT_FOUND");
assertThat(breakpoint.getBreakpointId()).isEqualTo(ISlapProtocol.INVALID_BREAKPOINT_ID);
}
use of nl.ramsolutions.sw.magik.debugadapter.slap.ISlapResponse in project magik-tools by StevenLooman.
the class ThreadManagerTest method testStackTrace.
@Test
void testStackTrace() throws IOException, InterruptedException, ExecutionException {
final TestSlapProtocol slapProtocol = new TestSlapProtocol() {
@Override
public CompletableFuture<ISlapResponse> getThreadStack(long threadId) throws IOException {
final ThreadStackResponse response = new ThreadStackResponse(List.of(new ThreadStackResponse.StackElement(0, 0, "object.m1()", "Magik"), new ThreadStackResponse.StackElement(1, 100, "java/lang/Object;m2", "Java"), new ThreadStackResponse.StackElement(2, 30, "object.m2()", "Magik"), new ThreadStackResponse.StackElement(3, 200, "java/lang/Object;m1", "Java")));
return CompletableFuture.completedFuture(response);
}
@Override
public CompletableFuture<ISlapResponse> evaluate(final long threadId, final int level, final String expression) throws IOException {
final EvalResponse response = new EvalResponse("sw");
return CompletableFuture.completedFuture(response);
}
@Override
public CompletableFuture<ISlapResponse> getSourceFile(final String method) throws IOException {
String result = null;
if ("sw:object.m1()".equals(method)) {
result = "file1.magik";
} else if ("sw:object.m2()".equals(method)) {
result = "file2.magik";
}
final SourceFileResponse response = new SourceFileResponse(result);
return CompletableFuture.completedFuture(response);
}
};
final ThreadManager manager = new ThreadManager(slapProtocol, null);
final List<StackFrame> stackFrames = manager.stackTrace(1);
assertThat(stackFrames).hasSize(2);
final StackFrame frame0 = stackFrames.get(0);
assertThat(frame0.getId()).isEqualTo(Lsp4jConversion.threadIdLevelToFrameId(1, 0));
assertThat(frame0.getName()).isEqualTo("sw:object.m1()");
assertThat(frame0.getSource().getPath()).isEqualTo("file1.magik");
final StackFrame frame1 = stackFrames.get(1);
assertThat(frame1.getId()).isEqualTo(Lsp4jConversion.threadIdLevelToFrameId(1, 2));
assertThat(frame1.getName()).isEqualTo("sw:object.m2()");
assertThat(frame1.getSource().getPath()).isEqualTo("file2.magik");
}
Aggregations