Support filter and filterNotOperations

This commit is contained in:
Vitaliy.Bibaev
2017-11-16 16:41:08 +03:00
committed by Yan Zhulanow
parent 6be340f079
commit 86ec8eab6e
5 changed files with 111 additions and 24 deletions
@@ -1,11 +1,11 @@
package com.intellij.debugger.streams.kotlin.lib
import com.intellij.debugger.streams.kotlin.resolve.FilterOrderResolver
import com.intellij.debugger.streams.kotlin.trace.impl.handler.collections.*
import com.intellij.debugger.streams.kotlin.trace.impl.interpret.FilterTraceInterpreter
import com.intellij.debugger.streams.lib.IntermediateOperation
import com.intellij.debugger.streams.lib.TerminalOperation
import com.intellij.debugger.streams.lib.impl.LibrarySupportBase
import com.intellij.debugger.streams.resolve.FilterResolver
import com.intellij.debugger.streams.resolve.ValuesOrderResolver
import com.intellij.debugger.streams.trace.CallTraceInterpreter
import com.intellij.debugger.streams.trace.IntermediateCallHandler
@@ -19,7 +19,8 @@ import com.intellij.debugger.streams.wrapper.TerminatorStreamCall
*/
class KotlinCollectionLibrarySupport : LibrarySupportBase() {
init {
addOperation(FilterOperation("filter", FilterCallHandler()))
addOperation(FilterOperation("filter", FilterCallHandler(), true))
addOperation(FilterOperation("filterNot", FilterCallHandler(), false))
}
private fun addOperation(operation: CollectionOperation) {
@@ -40,9 +41,9 @@ class KotlinCollectionLibrarySupport : LibrarySupportBase() {
wrapper.createTerminatorHandler(call, resultExpression, dsl)
}
private class FilterOperation(name: String, handler: BothSemanticsHandler)
private class FilterOperation(name: String, handler: BothSemanticsHandler, valueToAccept: Boolean)
: CollectionOperation(name, handler) {
override val traceInterpreter: CallTraceInterpreter = FilterTraceInterpreter()
override val valuesOrderResolver: ValuesOrderResolver = FilterOrderResolver()
override val traceInterpreter: CallTraceInterpreter = FilterTraceInterpreter(valueToAccept)
override val valuesOrderResolver: ValuesOrderResolver = FilterResolver()
}
}
@@ -1,13 +0,0 @@
package com.intellij.debugger.streams.kotlin.resolve
import com.intellij.debugger.streams.resolve.ValuesOrderResolver
import com.intellij.debugger.streams.trace.TraceInfo
/**
* @author Vitaliy.Bibaev
*/
class FilterOrderResolver : ValuesOrderResolver {
override fun resolve(info: TraceInfo): ValuesOrderResolver.Result {
return ValuesOrderResolver.Result.of(emptyMap(), emptyMap())
}
}
@@ -1,22 +1,66 @@
package com.intellij.debugger.streams.kotlin.trace.impl.interpret
import com.intellij.debugger.streams.trace.CallTraceInterpreter
import com.intellij.debugger.streams.trace.TraceElement
import com.intellij.debugger.streams.trace.TraceInfo
import com.intellij.debugger.streams.trace.impl.interpret.ValuesOrderInfo
import com.intellij.debugger.streams.trace.impl.TraceElementImpl
import com.intellij.debugger.streams.trace.impl.interpret.ex.UnexpectedValueTypeException
import com.intellij.debugger.streams.wrapper.StreamCall
import com.sun.jdi.ArrayReference
import com.sun.jdi.BooleanValue
import com.sun.jdi.IntegerValue
import com.sun.jdi.Value
/**
* @author Vitaliy.Bibaev
*/
class FilterTraceInterpreter : CallTraceInterpreter {
class FilterTraceInterpreter(private val predicateValueToAccept: Boolean) : CallTraceInterpreter {
override fun resolve(call: StreamCall, value: Value): TraceInfo {
if (value !is ArrayReference) throw UnexpectedValueTypeException("array reference excepted, but actual: ${value.type().name()}")
val times = value.getValue(0)
val values = value.getValue(1)
val predicateResults = value.getValue(0)
return ValuesOrderInfo.empty(call)
val before = resolveValuesBefore(value.getValue(0))
val filteringMap = value.getValue(1)
val after = resolveValuesAfter(before, filteringMap)
return ValuesOrder(call, before, after)
}
private fun resolveValuesBefore(map: Value): Map<Int, TraceElement> {
val (keys, objects) = InterpreterUtil.extractMap(map)
val result: MutableList<TraceElement> = mutableListOf()
for (i in 0.until(keys.length())) {
val time = keys.getValue(i)
val value = objects.getValue(i)
if (time !is IntegerValue) throw UnexpectedValueTypeException("time should be represented by integer value")
result.add(TraceElementImpl(time.value(), value))
}
return InterpreterUtil.createIndexByTime(result)
}
private fun resolveValuesAfter(before: Map<Int, TraceElement>, filteringMap: Value): Map<Int, TraceElement> {
val predicateValues = extractPredicateValues(filteringMap)
val result = linkedMapOf<Int, TraceElement>()
for ((beforeTime, value) in before) {
val predicateValue = predicateValues[beforeTime]
if (predicateValue == predicateValueToAccept) {
result[beforeTime + 1] = value
}
}
return result
}
private fun extractPredicateValues(filteringMap: Value): Map<Int, Boolean> {
val (keys, values) = InterpreterUtil.extractMap(filteringMap)
val result = mutableMapOf<Int, Boolean>()
for (i in 0.until(keys.length())) {
val time = keys.getValue(i)
val value = values.getValue(i)
if (time !is IntegerValue) throw UnexpectedValueTypeException("time should be represented by integer value")
if (value !is BooleanValue) throw UnexpectedValueTypeException("predicate value should be represented by boolean value")
result[time.value()] = value.value()
}
return result
}
}
@@ -0,0 +1,32 @@
package com.intellij.debugger.streams.kotlin.trace.impl.interpret
import com.intellij.debugger.streams.trace.TraceElement
import com.intellij.debugger.streams.trace.impl.interpret.ex.UnexpectedValueException
import com.sun.jdi.ArrayReference
import com.sun.jdi.Value
/**
* @author Vitaliy.Bibaev
*/
object InterpreterUtil {
fun extractMap(value: Value): MapRepresentation {
if (value !is ArrayReference || value.length() != 2) {
throw UnexpectedValueException("Map should be represented by array with two nested arrays: keys and values")
}
val keys = value.getValue(0)
val values = value.getValue(1)
if (keys !is ArrayReference || values !is ArrayReference || keys.length() != values.length()) {
throw UnexpectedValueException("Keys and values should be arrays with equal counts of elements")
}
return MapRepresentation(keys, values)
}
fun createIndexByTime(elements: List<TraceElement>): Map<Int, TraceElement> =
elements.associate { elem -> elem.time to elem }
data class MapRepresentation(val keys: ArrayReference, val values: ArrayReference)
}
@@ -0,0 +1,23 @@
package com.intellij.debugger.streams.kotlin.trace.impl.interpret
import com.intellij.debugger.streams.trace.TraceElement
import com.intellij.debugger.streams.trace.TraceInfo
import com.intellij.debugger.streams.wrapper.StreamCall
/**
* @author Vitaliy.Bibaev
*/
class ValuesOrder(private val call: StreamCall,
private val before: Map<Int, TraceElement>,
private val after: Map<Int, TraceElement>)
: TraceInfo {
override fun getValuesOrderBefore(): Map<Int, TraceElement> = before
override fun getCall(): StreamCall = call
override fun getValuesOrderAfter(): Map<Int, TraceElement> = after
override fun getDirectTrace(): MutableMap<TraceElement, MutableList<TraceElement>>? = null
override fun getReverseTrace(): MutableMap<TraceElement, MutableList<TraceElement>>? = null
}