Rikkola commented on code in PR #7160:
URL: https://github.com/apache/incubator-kie/pull/7160#discussion_r4412809227


##########
drools-model/drools-canonical-model/src/main/java/org/drools/model/impl/ViewPatternBuilder.java:
##########
@@ -194,6 +219,235 @@ public static Condition ruleItem2Condition(RuleItem 
ruleItem) {
         throw new UnsupportedOperationException( "Unknown " + ruleItem );
     }
 
+    private static boolean hasPositiveTrigger(SequenceStep step) {
+        if (step instanceof ExistentialExprViewItem) {
+            ExistentialExprViewItem ex = (ExistentialExprViewItem) step;
+            if (ex.getType() == Condition.Type.NOT) {
+                return false;
+            }
+            return true;
+        }
+        if (step instanceof CombinedExprViewItem) {
+            CombinedExprViewItem comb = (CombinedExprViewItem) step;
+            Condition.Type type = comb.getType();
+            if (type == Condition.Type.NOT || type == Condition.Type.NOR
+                    || type == Condition.Type.XOR || type == 
Condition.Type.XNOR) {
+                return false;
+            }
+            if (type == Condition.Type.AND) {
+                // In an AND composite, at least one child must be a positive 
trigger
+                for (org.drools.model.view.ViewItem expr : 
comb.getExpressions()) {
+                    if (expr instanceof SequenceStep) {
+                        if (hasPositiveTrigger((SequenceStep) expr)) {
+                            return true;
+                        }
+                    } else {
+                        return true;
+                    }
+                }
+                return false;
+            }
+            if (type == Condition.Type.OR) {
+                // In an OR composite, all branches must have a positive 
trigger
+                for (org.drools.model.view.ViewItem expr : 
comb.getExpressions()) {
+                    if (expr instanceof SequenceStep) {
+                        if (!hasPositiveTrigger((SequenceStep) expr)) {
+                            return false;
+                        }
+                    }
+                }
+                return true;
+            }
+        }
+        return true;
+    }
+
+    private static boolean isAbsenceStep(SequenceStep step) {
+        if (step instanceof ExistentialExprViewItem) {
+            return ((ExistentialExprViewItem) step).getType() == 
Condition.Type.NOT;
+        }
+        if (step instanceof CombinedExprViewItem) {
+            Condition.Type type = ((CombinedExprViewItem) step).getType();
+            return type == Condition.Type.NOT || type == Condition.Type.NOR;
+        }
+        throw new IllegalStateException("Unexpected SequenceStep type: " + 
step.getClass());
+    }
+
+    private static void 
validateActivationMatching(org.drools.model.view.ViewItem item) {
+        if (item instanceof CombinedExprViewItem) {
+            CombinedExprViewItem comb = (CombinedExprViewItem) item;
+            Condition.Type type = comb.getType();
+            for (org.drools.model.view.ViewItem expr : comb.getExpressions()) {
+                validateActivationMatching(expr);
+            }
+            if (type == Condition.Type.XOR) {
+                int matchedChildren = 0;
+                for (org.drools.model.view.ViewItem expr : 
comb.getExpressions()) {
+                    if (matchesOnActivation(expr)) {
+                        matchedChildren++;
+                    }
+                }
+                if (matchedChildren >= 2) {
+                    throw new IllegalArgumentException(
+                        "sequence(): oneOf() has " + matchedChildren + " 
children that match on step activation (0 inputs), " +
+                        "causing an immediate over-match veto upon activation. 
oneOf() requires exactly one child to match.");
+                }
+            }
+        }
+    }
+
+    private static boolean matchesOnActivation(org.drools.model.view.ViewItem 
item) {
+        if (item instanceof CombinedExprViewItem) {
+            CombinedExprViewItem comb = (CombinedExprViewItem) item;
+            Condition.Type type = comb.getType();
+            if (type == Condition.Type.XNOR) {
+                int matched = 0;
+                int total = comb.getExpressions().length;
+                for (org.drools.model.view.ViewItem expr : 
comb.getExpressions()) {
+                    if (matchesOnActivation(expr)) {
+                        matched++;
+                    }
+                }
+                return matched == 0 || matched == total;
+            }
+            if (type == Condition.Type.XOR) {
+                int matched = 0;
+                for (org.drools.model.view.ViewItem expr : 
comb.getExpressions()) {
+                    if (matchesOnActivation(expr)) {
+                        matched++;
+                    }
+                }
+                return matched == 1;
+            }
+            if (type == Condition.Type.AND) {
+                for (org.drools.model.view.ViewItem expr : 
comb.getExpressions()) {
+                    if (!matchesOnActivation(expr)) {
+                        return false;
+                    }
+                }
+                return comb.getExpressions().length > 0;
+            }
+            if (type == Condition.Type.OR) {
+                for (org.drools.model.view.ViewItem expr : 
comb.getExpressions()) {
+                    if (matchesOnActivation(expr)) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+            if (type == Condition.Type.NOT || type == Condition.Type.NOR) {
+                return false;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Rewrites runs of revertible gate steps (such as {@code oneOf()} / XOR 
and {@code noneOrAll()} / XNOR)
+     * by folding them together with their immediately following positive 
trigger into an {@code and(...)}
+     * composite step.
+     * <p>
+     * Standalone XOR/XNOR gates are non-propagating on their own within the 
sequence pipeline and require
+     * a following positive pattern step to act as the activation trigger. 
This transformation:
+     * <ul>
+     *   <li>Separates and emits any interleaved absence guards ({@code 
NOT}/{@code NOR}/{@code absent()})
+     *       before the folded composite so that compiler accumulation loops 
build them as independent
+     *       veto side-channels.</li>
+     *   <li>Folds consecutive XOR/XNOR gate steps and the subsequent positive 
trigger step into a single
+     *       {@link CombinedExprViewItem} of type {@link 
Condition.Type#AND}.</li>
+     * </ul>
+     *
+     * @param steps the original sequence steps
+     * @return the rewritten sequence steps with folded gate composites
+     */
+    private static SequenceStep[] rewriteRevertingGateSteps(SequenceStep[] 
steps) {
+        boolean hasXor = false;
+        for (int i = 0; i < steps.length; i++) {
+            SequenceStep step = steps[i];
+            if (step instanceof CombinedExprViewItem) {
+                Condition.Type t = ((CombinedExprViewItem) step).getType();
+                if ((t == Condition.Type.XOR || t == Condition.Type.XNOR) && i 
+ 1 < steps.length) {

Review Comment:
   And is now flattened to prevent this issue.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to