org.jetbrains.kotlinx.jupyter.util.AcceptanceRules.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlin-jupyter-api Show documentation
Show all versions of kotlin-jupyter-api Show documentation
API for libraries supporting Kotlin Jupyter notebooks
package org.jetbrains.kotlinx.jupyter.util
import kotlinx.serialization.Serializable
import org.jetbrains.kotlinx.jupyter.api.TypeName
import org.jetbrains.kotlinx.jupyter.api.libraries.VariablesSubstitutionAware
/**
* Acceptance rule either says it accepts an object or delegates it to some other rule returning null
*/
fun interface AcceptanceRule {
fun accepts(obj: T): Boolean?
}
/**
* Acceptance rule that has only two answers: yes/no (depending on the [acceptsFlag]) and "don't know"
*/
interface FlagAcceptanceRule : AcceptanceRule {
val acceptsFlag: Boolean
fun appliesTo(obj: T): Boolean
override fun accepts(obj: T): Boolean? {
return if (appliesTo(obj)) acceptsFlag else null
}
}
/**
* Acceptance rule for type names
*/
class NameAcceptanceRule(
override val acceptsFlag: Boolean,
private val appliesPredicate: (TypeName) -> Boolean,
) : FlagAcceptanceRule {
override fun appliesTo(obj: TypeName): Boolean {
return appliesPredicate(obj)
}
}
/**
* Acceptance rule for type names based on [pattern].
* Pattern may consist of any characters and of 3 special combinations:
* 1) `?` - any single character or no character
* 2) `*` - any character sequence excluding dot (`.`)
* 3) `**` - any character sequence
*
* For example, pattern `org.jetbrains.kotlin?.**.jupyter.*` matches following names:
* - `org.jetbrains.kotlin.my.package.jupyter.Integration`
* - `org.jetbrains.kotlinx.some_package.jupyter.SomeClass`
*
* It doesn't match name `org.jetbrains.kotlin.my.package.jupyter.integration.MyClass`
*/
@Serializable(PatternNameAcceptanceRuleSerializer::class)
class PatternNameAcceptanceRule(
override val acceptsFlag: Boolean,
val pattern: String,
) : FlagAcceptanceRule, VariablesSubstitutionAware {
private val regex by lazy {
buildString {
var i = 0
while (i < pattern.length) {
val c = pattern[i]
val nextC = pattern.getOrNull(i + 1)
when (c) {
'.' -> append("\\.")
'*' ->
when (nextC) {
'*' -> {
append(".*")
++i
}
else -> append("[^.]*")
}
'?' -> append(".?")
'[', ']', '(', ')', '{', '}', '\\', '$', '^', '+', '|' -> {
append('\\')
append(c)
}
else -> append(c)
}
++i
}
}.toRegex()
}
override fun appliesTo(obj: TypeName): Boolean {
return regex.matches(obj)
}
override fun replaceVariables(mapping: Map): PatternNameAcceptanceRule {
val newPattern = replaceVariables(pattern, mapping)
if (pattern == newPattern) return this
return PatternNameAcceptanceRule(acceptsFlag, newPattern)
}
}
/**
* List of acceptance rules:
* 1) accepts [obj] if latest not-null acceptance result is `true`
* 2) doesn't accept [obj] if latest not-null acceptance result is `false`
* 3) returns `null` if all acceptance results are `null` or the iterable is empty
*/
fun Iterable>.accepts(obj: T): Boolean? {
return unionAcceptance(map { it.accepts(obj) })
}
fun unionAcceptance(results: Iterable): Boolean? {
return results.filterNotNull().lastOrNull()
}
fun unionAcceptance(vararg result: Boolean?): Boolean? {
return unionAcceptance(result.toList())
}