Skip to content

Commit

Permalink
Refactor stackframe request handler
Browse files Browse the repository at this point in the history
  • Loading branch information
jbeers committed Apr 2, 2024
1 parent 8402d73 commit 0f04450
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 70 deletions.
37 changes: 33 additions & 4 deletions src/main/java/ortus/boxlang/debugger/BoxLangDebugger.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
import com.sun.jdi.Method;
import com.sun.jdi.ReferenceType;
import com.sun.jdi.StackFrame;
import com.sun.jdi.StringReference;
import com.sun.jdi.ThreadReference;
import com.sun.jdi.Value;
import com.sun.jdi.VirtualMachine;
Expand Down Expand Up @@ -474,7 +473,7 @@ public Optional<Location> pauseThread( int threadId ) {
} );
}

public List<StackFrameTuple> getBoxLangStackFrames( int threadId ) throws IncompatibleThreadStateException {
public List<StackFrameTuple> getBoxLangStackFrames( int threadId ) {
return this.cacheOrGetThread( threadId ).getBoxLangStackFrames();
}

Expand Down Expand Up @@ -695,7 +694,36 @@ public WrappedValue findVariableyName( StackFrameTuple tuple, String name ) {

}

public WrappedValue upateVariableByReference( int variableReference, Value key, StringReference value ) {
public String getStackFrameName( StackFrameTuple tuple ) {
BoxLangType blType = determineBoxLangType( tuple.location().declaringType() );

if ( blType == BoxLangType.UDF ) {
return getObjectFromStackFrame( tuple.stackFrame )
.property( "name" )
.property( "originalValue" )
.asStringReference().value();
} else if ( blType == BoxLangType.CLOSURE ) {
String calledName = getContextForStackFrame( tuple )
.invoke( "findClosestFunctionName" )
.invoke( "getOriginalValue" )
.asStringReference()
.value();

return calledName + " (closure)";
} else if ( blType == BoxLangType.LAMBDA ) {
String calledName = getContextForStackFrame( tuple )
.invoke( "findClosestFunctionName" )
.invoke( "getOriginalValue" )
.asStringReference()
.value();

return calledName + " (lambda)";
}

return null;
}

public WrappedValue upateVariableByReference( int variableReference, String key, String value ) {
WrappedValue container = JDITools.getSeen( variableReference );

if ( container == null ) {
Expand All @@ -706,7 +734,8 @@ public WrappedValue upateVariableByReference( int variableReference, Value key,
container.invokeByNameAndArgs(
"assign",
Arrays.asList( "ortus.boxlang.runtime.context.IBoxContext", "ortus.boxlang.runtime.scopes.Key", "java.lang.Object" ),
Arrays.asList( getContextForStackFrame( this.cacheOrGetThread( getPausedThreadReference() ).getBoxLangStackFrames().get( 0 ) ).value(), key, value )
Arrays.asList( getContextForStackFrame( this.cacheOrGetThread( getPausedThreadReference() ).getBoxLangStackFrames().get( 0 ) ).value(),
mirrorOfKey( key ), vm.mirrorOf( value ) )
);

return null;
Expand Down
106 changes: 40 additions & 66 deletions src/main/java/ortus/boxlang/debugger/DebugAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.apache.commons.lang3.NotImplementedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sun.jdi.IncompatibleThreadStateException;
import com.sun.jdi.InvocationException;
import com.sun.jdi.Location;
import com.sun.jdi.ObjectReference;
Expand All @@ -44,6 +44,7 @@
import ortus.boxlang.compiler.IBoxpiler;
import ortus.boxlang.compiler.SourceMap;
import ortus.boxlang.compiler.javaboxpiler.JavaBoxpiler;
import ortus.boxlang.debugger.BoxLangDebugger.StackFrameTuple;
import ortus.boxlang.debugger.JDITools.WrappedValue;
import ortus.boxlang.debugger.event.Event;
import ortus.boxlang.debugger.event.StoppedEvent;
Expand Down Expand Up @@ -81,7 +82,6 @@
import ortus.boxlang.debugger.types.StackFrame;
import ortus.boxlang.debugger.types.Variable;
import ortus.boxlang.runtime.BoxRuntime;
import ortus.boxlang.runtime.types.BoxLangType;

/**
* Implements Microsoft's Debug Adapter Protocol https://microsoft.github.io/debug-adapter-protocol/
Expand Down Expand Up @@ -263,8 +263,8 @@ public void visit( TerminateRequest debugRequest ) {
public void visit( SetVariableRequest debugRequest ) {
this.debugger.upateVariableByReference(
debugRequest.arguments.variablesReference,
this.debugger.mirrorOfKey( debugRequest.arguments.name ),
this.debugger.vm.mirrorOf( debugRequest.arguments.value )
debugRequest.arguments.name,
debugRequest.arguments.value
);

var variables = JDITools.getVariablesFromSeen( debugRequest.arguments.variablesReference );
Expand Down Expand Up @@ -445,68 +445,10 @@ public void visit( ThreadsRequest debugRequest ) {
* @param debugRequest
*/
public void visit( StackTraceRequest debugRequest ) {
try {

List<StackFrame> stackFrames = this.debugger.getBoxLangStackFrames( debugRequest.arguments.threadId ).stream()
.map( ( tuple ) -> {
com.sun.jdi.StackFrame stackFrame = tuple.stackFrame();
com.sun.jdi.Location location = tuple.location();
StackFrame sf = new StackFrame();
SourceMap map = boxpiler.getSourceMapFromFQN( location.declaringType().name() );
String fileName = Path.of( map.source ).getFileName().toString();

sf.id = tuple.id();
sf.line = location.lineNumber();
sf.column = 1;
sf.name = location.method().name();

Integer sourceLine = map.convertJavaLineToSourceLine( sf.line );
if ( sourceLine != null ) {
sf.line = sourceLine;
}

BoxLangType blType = this.debugger.determineBoxLangType( location.declaringType() );

if ( blType == BoxLangType.UDF ) {
sf.name = this.debugger.getObjectFromStackFrame( stackFrame )
.property( "name" )
.property( "originalValue" )
.asStringReference().value();
sf.source = new Source();
} else if ( blType == BoxLangType.CLOSURE ) {
// TODO figure out how to get the name of the closure from a parent context
String calledName = this.debugger.getContextForStackFrame( tuple )
.invoke( "findClosestFunctionName" ).invoke( "getOriginalValue" )
.asStringReference().value();

sf.name = calledName + " (closure)";
sf.source = new Source();
} else if ( blType == BoxLangType.LAMBDA ) {
String calledName = this.debugger.getContextForStackFrame( tuple )
.invoke( "findClosestFunctionName" ).invoke( "getOriginalValue" )
.asStringReference().value();
sf.name = calledName + " (lambda)";
sf.source = new Source();
} else if ( map != null && map.isTemplate() ) {
sf.name = map.getFileName();
sf.source = new Source();

}

if ( sf.source != null ) {
sf.source.path = map.source.toString();
sf.source.name = fileName;
}

return sf;
} )
.collect( Collectors.toList() );
new StackTraceResponse( debugRequest, stackFrames ).send( this.outputStream );
} catch ( IncompatibleThreadStateException e ) {
new StackTraceResponse( debugRequest, new ArrayList<StackFrame>() ).send( this.outputStream );
// TODO Auto-generated catch block
e.printStackTrace();
}
List<StackFrame> stackFrames = this.debugger.getBoxLangStackFrames( debugRequest.arguments.threadId ).stream()
.map( convertStackFrameTupleToDAPStackFrame( boxpiler, debugger ) )
.collect( Collectors.toList() );
new StackTraceResponse( debugRequest, stackFrames ).send( this.outputStream );
}

public void visit( ScopeRequest debugRequest ) {
Expand All @@ -532,6 +474,38 @@ private IVMInitializationStrategy getInitStrategy( LaunchRequest launchRequest )
throw new RuntimeException( "Invalid launch request arguments" );
}

public Function<StackFrameTuple, StackFrame> convertStackFrameTupleToDAPStackFrame( IBoxpiler boxpiler, BoxLangDebugger debugger ) {
return ( tuple ) -> {
StackFrame sf = new StackFrame();
sf.id = tuple.id();
sf.column = 1;

SourceMap map = boxpiler.getSourceMapFromFQN( tuple.location().declaringType().name() );

sf.line = tuple.location().lineNumber();
Integer sourceLine = map.convertJavaLineToSourceLine( sf.line );
if ( sourceLine != null ) {
sf.line = sourceLine;
}

sf.name = tuple.location().method().name();
String stackFrameName = debugger.getStackFrameName( tuple );
if ( stackFrameName != null ) {
sf.name = stackFrameName;
} else if ( map != null && map.isTemplate() ) {
sf.name = map.getFileName();
}

sf.source = new Source();
if ( sf.source != null ) {
sf.source.path = map.source.toString();
sf.source.name = Path.of( map.source ).getFileName().toString();
}

return sf;
};
}

public static Scope convertScopeToDAPScope( WrappedValue scopeValue ) {
Scope scope = new Scope();
scope.name = scopeValue.invoke( "getName" ).invoke( "getName" ).asStringReference().value();
Expand Down

0 comments on commit 0f04450

Please sign in to comment.