Support the logical not operator in profile activation conditions - #12737
Support the logical not operator in profile activation conditions#12737SEPURI-SAI-KRISHNA wants to merge 1 commit into
Conversation
The condition tokenizer already treats ! as an operator character and
emits a bare "!" token when it is not followed by "=", but no parser
rule ever consumed it. parseUnary() handled only "-", so a "!" fell
through to parseTerm(), failed to parse as a number, and ended up in
parseVariableOrUnknownFunction().
Writing the natural form of a negated condition:
<condition>!exists('some/path')</condition>
therefore failed with "Unknown variable: !", which is confusing since
nothing in the expression is a variable. The workaround was the not()
function.
Handle "!" in parseUnary() as sugar for the existing not() function,
reusing the same toBoolean() coercion so no new semantics are
introduced. Handling it in parseUnary() gives it the same precedence as
in Java: tighter than arithmetic, comparison, && and ||. Recursing into
parseUnary() allows stacking such as !!x.
!= is unaffected, because the tokenizer emits it as a single token
before a bare "!" can be produced.
gnodet
left a comment
There was a problem hiding this comment.
Clean, well-implemented addition of the logical ! operator to the ConditionParser. The implementation correctly mirrors the existing not() function by calling the same toBoolean() coercion, and the recursive parseUnary() call naturally supports stacking (!!, !!!).
The placement in parseUnary() gives ! the expected Java-like precedence (tighter than arithmetic, comparison, &&, and ||), and the tokenizer already correctly emits != as a single token before a bare ! can be produced, so no regression is possible there.
The four new test methods provide strong coverage of basic negation, equivalence with not(), precedence interactions, and type coercion. Nice touch using contains('Hello, World!', ...) to exercise ! inside string literals.
Minor nit: testNotEqualsStillParsesAsOneOperator is redundant with existing assertions in testStringComparison and testArithmeticComparisons, though it serves as a self-documenting regression guard for this change.
Thorough PR description with correct scoping — the pre-existing compare() issue is correctly identified as out of scope.
This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.
Claude Code on behalf of gnodet
Fixes #12736
What
Adds handling for the
!operator toConditionParser.parseUnary().Why
The tokenizer already treats
!as an operator and emits a bare!token, but no parser ruleconsumes it. Writing the natural form of a negated condition:
fails with
Unknown variable: !, which is confusing — nothing in the expression is a variable.!is defined here as sugar for thenot()function that already exists, using the sametoBoolean()coercion, so this adds no new capability and no new semantics. It is handled inparseUnary(), giving it the same precedence as in Java: tighter than arithmetic, comparison,&&and||.!=is unaffected — the tokenizer emits it as a single token before a bare!can be produced.Tests
Four tests added to
ConditionParserTest, all failing before the change:testLogicalNotOperator— basic negation, stacking (!!,!!!), and negating a function calltestLogicalNotOperatorMatchesNotFunction— pins!xto the same result asnot(x)testLogicalNotOperatorPrecedence— precedence against&&,||and parenthesised groupstestLogicalNotOperatorCoercion— string/number coercion matchesnot()The negation tests deliberately use
contains('Hello, World!', ..), which puts a!inside astring literal, to confirm the tokenizer still leaves quoted
!alone.Out of scope — a separate bug found while testing this
compare()handlesNumbervsNumberandStringvsString, but has noBooleanbranch, socomparing two booleans throws on the unmodified parser:
This is pre-existing and independent of
!. It is deliberately NOT fixed in this PR, and thetests here avoid boolean-to-boolean comparison. Candidate for a fourth PR.
PR checklist — APPEND THIS TO THE END OF THE PR DESCRIPTION
This is the repo's
pull_request_template.mdchecklist. Paste it below the body above.Following this checklist to help us incorporate your
contribution quickly and easily:
Note that commits might be squashed by a maintainer on merge.
This may not always be possible but is a best-practice.
mvn verifyto make sure basic checks pass.A more thorough check will be performed on your pull request automatically.
If your pull request is about ~20 lines of code you don't need to sign an
Individual Contributor License Agreement if you are unsure
please ask on the developers list.
To make clear that you license your contribution under
the Apache License Version 2.0, January 2004
you have to acknowledge this by using the following check-box.
I hereby declare this contribution to be licenced under the Apache License Version 2.0, January 2004
In any other case, please file an Apache Individual Contributor License Agreement.