Skip to content

Commit c26053d

Browse files
committed
Implement basic evaluate for qualified expressions
Fixes #33
1 parent 3d3cb64 commit c26053d

File tree

4 files changed

+51
-1
lines changed

4 files changed

+51
-1
lines changed

adapter/src/main/kotlin/org/javacs/ktda/adapter/KotlinDebugAdapter.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,18 @@ class KotlinDebugAdapter(
354354

355355
override fun loadedSources(args: LoadedSourcesArguments): CompletableFuture<LoadedSourcesResponse> = notImplementedDAPMethod()
356356

357-
override fun evaluate(args: EvaluateArguments): CompletableFuture<EvaluateResponse> = notImplementedDAPMethod()
357+
override fun evaluate(args: EvaluateArguments): CompletableFuture<EvaluateResponse> = async.compute {
358+
val variable = (args.frameId
359+
.let(converter::toInternalStackFrame)
360+
?: throw KotlinDAException("Could not find stack frame with ID ${args.frameId}"))
361+
.evaluate(args.expression)
362+
?.let(converter::toDAPVariable)
363+
364+
EvaluateResponse().apply {
365+
result = variable?.value ?: "unknown"
366+
variablesReference = variable?.variablesReference ?: 0
367+
}
368+
}
358369

359370
override fun stepInTargets(args: StepInTargetsArguments): CompletableFuture<StepInTargetsResponse> = notImplementedDAPMethod()
360371

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package org.javacs.ktda.core.scope
2+
3+
data class BasicVariableTreeNode(
4+
override val name: String,
5+
override val value: String? = null,
6+
override val type: String? = null,
7+
override val childs: List<VariableTreeNode>? = null
8+
) : VariableTreeNode

adapter/src/main/kotlin/org/javacs/ktda/core/stack/StackFrame.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,6 @@ interface StackFrame {
77
val name: String
88
val position: Position?
99
val scopes: List<VariableTreeNode>
10+
11+
fun evaluate(expression: String): VariableTreeNode?
1012
}

adapter/src/main/kotlin/org/javacs/ktda/jdi/stack/JDIStackFrame.kt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,35 @@ class JDIStackFrame(
1616
override val scopes: List<VariableTreeNode> by lazy { listOf(
1717
JDILocalScope(frame)
1818
) }
19+
1920
// TODO: Scope "Fields"
2021
// TODO: Argument values?
22+
23+
private fun evaluateQualified(qualName: List<String>, variables: List<VariableTreeNode> = scopes.flatMap { it.childs ?: emptyList() }): VariableTreeNode? =
24+
qualName.firstOrNull().let { qual ->
25+
val rest = qualName.drop(1)
26+
variables
27+
.filter { it.name == qual }
28+
.mapNotNull { if (rest.isEmpty()) it else evaluateQualified(rest, it.childs ?: emptyList()) }
29+
.firstOrNull()
30+
}
31+
32+
override fun evaluate(expression: String): VariableTreeNode? {
33+
// TODO: Implement proper expression parsing
34+
//
35+
// Note that expression parsing is not part of the JDI
36+
// (see https://www.oracle.com/technetwork/java/javase/tech/faqs-jsp-142584.html#QV1)
37+
// There is a JDI-compatible expression parser in the JDPA examples.
38+
// Unfortunately, however, it is not exported by the jdk/jdi module
39+
// and as such cannot be imported:
40+
//
41+
// com.sun.tools.example.debug.expr.ExpressionParser
42+
//
43+
// Creating JDI values from primitives and strings is possible though,
44+
// using VirtualMachine.mirrorOf.
45+
46+
val qualified = expression.split(".")
47+
return evaluateQualified(qualified)
48+
?: evaluateQualified(listOf("this") + qualified)
49+
}
2150
}

0 commit comments

Comments
 (0)