Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrated DistributiveLaw to jbool implementation #1513

Merged
merged 2 commits into from
Sep 5, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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