Implement regular expression interpretation

This commit is contained in:
Ivan Kylchik
2020-06-10 21:52:45 +03:00
parent 4d80d17b23
commit ff6e06aa14
2 changed files with 43 additions and 11 deletions
@@ -5,9 +5,7 @@
package org.jetbrains.kotlin.backend.common.interpreter
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import kotlinx.coroutines.yield
import kotlinx.coroutines.*
import org.jetbrains.kotlin.backend.common.interpreter.builtins.*
import org.jetbrains.kotlin.backend.common.interpreter.stack.*
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
@@ -245,6 +243,20 @@ class IrInterpreter(irModule: IrModuleFragment) {
enumEntry.interpret(data).also { if (it != Code.NEXT) return it }
}
}
"replace" -> {
val states = data.getAll().map { it.state }
val regex = states.filterIsInstance<Wrapper>().single().value as Regex
val input = states.filterIsInstance<Primitive<*>>().single().value.toString()
val transform = states.filterIsInstance<Lambda>().single().irFunction
val matchResultParameter = transform.valueParameters.single()
val result = regex.replace(input) {
val itAsState = Variable(matchResultParameter.descriptor, Wrapper(it, matchResultParameter.type.classOrNull!!.owner))
val newFrame = InterpreterFrame(mutableListOf(itAsState))
runBlocking { transform.interpret(newFrame) }
(newFrame.popReturnValue() as Primitive<*>).value.toString()
}
data.pushReturnValue(result.toState(irBuiltIns.stringType))
}
else -> throw AssertionError("Unsupported intrinsic ${irFunction.name}")
}
@@ -353,8 +365,9 @@ class IrInterpreter(irModule: IrModuleFragment) {
}
private suspend fun interpretValueParameters(parametersContainer: IrMemberAccessExpression, data: Frame): Code {
val defaultValues = (parametersContainer.symbol.owner as IrFunction).valueParameters.map { it.defaultValue }
for (i in (parametersContainer.valueArgumentsCount - 1) downTo 0) {
val code = parametersContainer.getValueArgument(i)?.interpret(data) ?: Code.NEXT
val code = parametersContainer.getValueArgument(i)?.interpret(data) ?: defaultValues[i]!!.expression.interpret(data)
if (code != Code.NEXT) return code
}
return Code.NEXT
@@ -395,8 +408,9 @@ class IrInterpreter(irModule: IrModuleFragment) {
}
val isWrapper = dispatchReceiver is Wrapper && rawExtensionReceiver == null
val isInterfaceDefaultMethod = irFunction.body != null && (irFunction.parent as? IrClass)?.isInterface == true
val code = when {
isWrapper -> (dispatchReceiver as Wrapper).getMethod(irFunction).invokeMethod(irFunction, newFrame)
isWrapper && !isInterfaceDefaultMethod -> (dispatchReceiver as Wrapper).getMethod(irFunction).invokeMethod(irFunction, newFrame)
irFunction.hasAnnotation(evaluateIntrinsicAnnotation) -> Wrapper.getStaticMethod(irFunction).invokeMethod(irFunction, newFrame)
irFunction.isAbstract() -> calculateAbstract(irFunction, newFrame) //abstract check must be before fake overridden check
irFunction.isFakeOverridden() -> calculateOverridden(irFunction as IrFunctionImpl, newFrame)
@@ -615,7 +629,12 @@ class IrInterpreter(irModule: IrModuleFragment) {
}
private suspend fun interpretGetObjectValue(expression: IrGetObjectValue, data: Frame): Code {
val objectState = Common(expression.symbol.owner, mutableListOf()).apply { this.instance = this }
val owner = expression.symbol.owner
if (owner.hasAnnotation(evaluateIntrinsicAnnotation)) {
data.pushReturnValue(Wrapper.getCompanionObject(owner))
return Code.NEXT
}
val objectState = Common(owner, mutableListOf()).apply { this.instance = this }
data.pushReturnValue(objectState)
return Code.NEXT
}
@@ -153,16 +153,21 @@ class Wrapper(val value: Any, override val irClass: IrClass) : Complex(irClass,
private val typeFqName = irClass.fqNameForIrSerialization.toUnsafe()
private val receiverClass = irClass.defaultType.getClass(true)
init {
instance = this
}
fun getMethod(irFunction: IrFunction): MethodHandle? {
// if function is actually a getter, then use property name as method name
val property = (irFunction as? IrFunctionImpl)?.correspondingPropertySymbol?.owner
// if function is actually a getter, then use "get${property.name.capitalize()}" as method name
val propertyName = (irFunction as? IrFunctionImpl)?.correspondingPropertySymbol?.owner?.name?.asString()
val propertyExplicitCall = propertyName?.takeIf { receiverClass.methods.map { it.name }.contains(it) }
val propertyGetCall = "get${propertyName?.capitalize()}".takeIf { receiverClass.methods.map { it.name }.contains(it) }
// intrinsicName is used to get correct java method
// for example: - method 'get' in kotlin StringBuilder is actually 'charAt' in java StringBuilder
// - use getter for private fields such as detailMessage in java.lang.Throwable
val intrinsicName = property?.getEvaluateIntrinsicValue() ?: irFunction.getEvaluateIntrinsicValue()
val intrinsicName = irFunction.getEvaluateIntrinsicValue()
if (intrinsicName?.isEmpty() == true) return null
val methodName = intrinsicName ?: (property ?: irFunction).name.toString()
val methodName = intrinsicName ?: propertyExplicitCall ?: propertyGetCall ?: irFunction.name.toString()
val methodType = irFunction.getMethodType()
return MethodHandles.lookup().findVirtual(receiverClass, methodName, methodType)
@@ -173,6 +178,14 @@ class Wrapper(val value: Any, override val irClass: IrClass) : Complex(irClass,
}
companion object {
private val companionObjectValue = mapOf<String, Any>("kotlin.text.Regex\$Companion" to Regex.Companion)
fun getCompanionObject(irClass: IrClass): Wrapper {
val objectName = irClass.getEvaluateIntrinsicValue()!!
val objectValue = companionObjectValue[objectName] ?: throw AssertionError("Companion object $objectName cannot be interpreted")
return Wrapper(objectValue, irClass)
}
fun getConstructorMethod(irConstructor: IrFunction): MethodHandle {
val methodType = irConstructor.getMethodType()