Skip to content

Commit

Permalink
Migrated DistributiveLaw to jbool implementation (#1513)
Browse files Browse the repository at this point in the history
  • Loading branch information
nulls authored Sep 5, 2022
1 parent b5ef51d commit 2ae3500
Showing 1 changed file with 1 addition and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@ import org.cqfn.diktat.ruleset.rules.DiktatRule
import org.cqfn.diktat.ruleset.utils.KotlinParser
import org.cqfn.diktat.ruleset.utils.findAllNodesWithCondition
import org.cqfn.diktat.ruleset.utils.logicalInfixMethods
import com.bpodgursky.jbool_expressions.And
import com.bpodgursky.jbool_expressions.Expression
import com.bpodgursky.jbool_expressions.NExpression
import com.bpodgursky.jbool_expressions.Or
import com.bpodgursky.jbool_expressions.options.ExprOptions
import com.bpodgursky.jbool_expressions.parsers.ExprParser
import com.bpodgursky.jbool_expressions.parsers.TokenMapper
import com.bpodgursky.jbool_expressions.rules.DeMorgan
import com.bpodgursky.jbool_expressions.rules.DistributiveLaw
import com.bpodgursky.jbool_expressions.rules.Rule
import com.bpodgursky.jbool_expressions.rules.RuleList
import com.bpodgursky.jbool_expressions.rules.RulesHelper
Expand All @@ -29,8 +27,6 @@ import org.jetbrains.kotlin.psi.KtParenthesizedExpression
import org.jetbrains.kotlin.psi.KtPrefixExpression
import org.jetbrains.kotlin.psi.psiUtil.parents

typealias ExpressionCreator<K> = (List<Expression<K>?>) -> Expression<K>

/**
* Rule that checks if the boolean expression can be simplified.
*/
Expand Down Expand Up @@ -258,77 +254,6 @@ class BooleanExpressionsRule(configRules: List<RulesConfig>) : DiktatRule(
}
}

/**
* Rule that checks that the expression can be simplified by distributive law.
* Distributive law - A && B || A && C -> A && (B || C) or (A || B) && (A || C) -> A || (B && C)
*/
@Suppress("UnsafeCallOnNullableType")
private class DistributiveLaw<K> : Rule<NExpression<K>, K>() {
override fun applyInternal(input: NExpression<K>, options: ExprOptions<K>): Expression<K> {
val exprFactory = options.exprFactory!!
val orExpressionCreator: ExpressionCreator<K> = { expressions -> exprFactory.or(expressions.toTypedArray()) }
val andExpressionCreator: ExpressionCreator<K> = { expressions -> exprFactory.and(expressions.toTypedArray()) }
return when (input) {
is And -> applyInternal(input, orExpressionCreator, andExpressionCreator)
is Or -> applyInternal(input, andExpressionCreator, orExpressionCreator)
else -> throw UnsupportedOperationException("Not supported input expression: ${input.exprType}")
}
}

private fun applyInternal(
input: NExpression<K>,
upperExpressionCreator: ExpressionCreator<K>,
innerExpressionCreator: ExpressionCreator<K>
): Expression<K> {
// we can be here only after `isApply` -- common exists
val commonExpression = findCommonExpression(input.children)!!
return upperExpressionCreator(
listOf(commonExpression,
innerExpressionCreator(
input.expressions.map { excludeChild(it, upperExpressionCreator, commonExpression) }
)))
}

private fun excludeChild(
expression: Expression<K>,
expressionCreator: ExpressionCreator<K>,
childToExclude: Expression<K>
): Expression<K> {
val leftChildren = expression.children.filterNot { it.equals(childToExclude) }
return if (leftChildren.size == 1) {
leftChildren.first()
} else {
expressionCreator(leftChildren)
}
}

/**
* Checks the input expression
*/
override fun isApply(inputNullable: Expression<K>?): Boolean = inputNullable?.let { input ->
when (input) {
is And -> isApplicable<And<K>, Or<K>>(input)
is Or -> isApplicable<Or<K>, And<K>>(input)
else -> false
}
} ?: false

private inline fun <E : NExpression<K>, reified C : NExpression<K>> isApplicable(input: E): Boolean {
val children = input.children ?: return false
if (children.size < 2 || children.any { it !is C }) {
return false
}
return findCommonExpression(children) != null
}

private fun findCommonExpression(children: List<Expression<K>>): Expression<K>? = children.drop(1)
.fold(children[0].children) { commons, child ->
commons.filter { childResult ->
child.children.any { it.equals(childResult) }
}
}.firstOrNull()
}

companion object {
const val NAME_ID = "boolean-expressions-rule"

Expand Down

0 comments on commit 2ae3500

Please sign in to comment.