MCPcopy Create free account
hub / github.com/github/gh-aw / optimizeNotNode

Function optimizeNotNode

pkg/workflow/expression_optimizer.go:383–443  ·  view source on GitHub ↗
(n *NotNode)

Source from the content-addressed store, hash-verified

381}
382
383func optimizeNotNode(n *NotNode) ConditionNode {
384 // Bottom-up: optimise child first.
385 child := optimizeNode(n.Child)
386
387 // Constant folding: !true → false, !false → true
388 if lit, ok := child.(*BooleanLiteralNode); ok {
389 expressionOptimizerLog.Printf("NOT constant folding: !%v → %v", lit.Value, !lit.Value)
390 return &BooleanLiteralNode{Value: !lit.Value}
391 }
392
393 // Double negation: !!A → A
394 if notChild, ok := child.(*NotNode); ok {
395 expressionOptimizerLog.Printf("NOT double negation: !!%s → %s", notChild.Child.Render(), notChild.Child.Render())
396 // Recurse so that the result of eliminating the double negation is
397 // itself a candidate for further simplification.
398 return optimizeNode(notChild.Child)
399 }
400
401 // De Morgan: !(A && B) → !A || !B
402 // Only applied when neither operand contains a status function, since
403 // rearranging status functions changes execution semantics.
404 if andChild, ok := child.(*AndNode); ok && !containsStatusFunc(andChild) {
405 expressionOptimizerLog.Printf("NOT De Morgan (AND): !(%s && %s) → !%s || !%s",
406 andChild.Left.Render(), andChild.Right.Render(),
407 andChild.Left.Render(), andChild.Right.Render())
408 return optimizeNode(&OrNode{
409 Left: &NotNode{Child: andChild.Left},
410 Right: &NotNode{Child: andChild.Right},
411 })
412 }
413
414 // De Morgan: !(A || B) → !A && !B
415 if orChild, ok := child.(*OrNode); ok && !containsStatusFunc(orChild) {
416 expressionOptimizerLog.Printf("NOT De Morgan (OR): !(%s || %s) → !%s && !%s",
417 orChild.Left.Render(), orChild.Right.Render(),
418 orChild.Left.Render(), orChild.Right.Render())
419 return optimizeNode(&AndNode{
420 Left: &NotNode{Child: orChild.Left},
421 Right: &NotNode{Child: orChild.Right},
422 })
423 }
424
425 // De Morgan: !(A || B || ...) → !A && !B && ... (DisjunctionNode form)
426 // Move the empty-terms guard before the containsStatusFunc call to avoid
427 // an unnecessary tree walk when the disjunction is empty.
428 if disjChild, ok := child.(*DisjunctionNode); ok {
429 if len(disjChild.Terms) == 0 {
430 return &NotNode{Child: child}
431 }
432 if !containsStatusFunc(disjChild) {
433 expressionOptimizerLog.Printf("NOT De Morgan (Disjunction): !(disjunction[%d]) → AND chain of negations", len(disjChild.Terms))
434 negations := make([]ConditionNode, len(disjChild.Terms))
435 for i, term := range disjChild.Terms {
436 negations[i] = &NotNode{Child: term}
437 }
438 return optimizeNode(rebuildAndChain(negations))
439 }
440 }

Callers 1

optimizeNodeFunction · 0.85

Calls 5

optimizeNodeFunction · 0.85
containsStatusFuncFunction · 0.85
rebuildAndChainFunction · 0.85
RenderMethod · 0.65
PrintfMethod · 0.45

Tested by

no test coverage detected