From d7216d5f932de42ea1fd7b8a35bd81c6729d3c07 Mon Sep 17 00:00:00 2001 From: Brandon Wallace Date: Thu, 19 Mar 2026 01:05:46 -0500 Subject: [PATCH 1/3] test: add failing tests for PPP variable-vs-variable comparison support Add 4 TDD tests for the var-vs-var comparison feature (S1-TT2): - test_cmd_if_var_vs_var_eq - test_cmd_if_var_vs_var_ne - test_cmd_if_var_vs_var_contains - test_cmd_if_var_vs_var_not_contains All tests fail because the grammar only accepts SIMPLEVALUE on RHS, not IDENTIFIER. Implementation in S1-T2 will make them pass. --- tests/tests.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/tests.py b/tests/tests.py index 7489c0d..b4b5a42 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -1328,6 +1328,43 @@ class TestPromptPostProcessor(TestPromptPostProcessorBase): ppp=self.nocupppp, ) + # Variable-vs-variable comparison tests + + def test_cmd_if_var_vs_var_eq(self): # var eq var: both set to same value, if-branch taken + self.process( + PromptPair( + "hellohelloYESNO", + "", + ), + PromptPair("YES", ""), + ) + + def test_cmd_if_var_vs_var_ne(self): # var ne var: different values, ne condition true + self.process( + PromptPair( + "appleorangeYESNO", + "", + ), + PromptPair("YES", ""), + ) + + def test_cmd_if_var_vs_var_contains(self): # var contains var: var1 contains var2's value + self.process( + PromptPair( + "hello worldhelloYESNO", + "", + ), + PromptPair("YES", ""), + ) + + def test_cmd_if_var_vs_var_not_contains(self): # var not contains var: var1 does not contain var2's value + self.process( + PromptPair( + "hello worldgoodbyeYESNO", + "", + ), + PromptPair("YES", ""), + ) if __name__ == "__main__": unittest.main() From f444ce02336d2c41ef136e20a190b477c3deea21 Mon Sep 17 00:00:00 2001 From: Brandon Wallace Date: Thu, 19 Mar 2026 03:03:14 -0500 Subject: [PATCH 2/3] feat(ppp): add variable-vs-variable comparison support in conditions Allow bare identifiers as the RHS of comparisons in ppp:if conditions (e.g., ``). The grammar now accepts IDENTIFIER as an alternative to SIMPLEVALUE, and __eval_basiccondition resolves bare identifier values as variable references before comparison. --- docs/SYNTAX.md | 2 +- grammar.lark | 2 +- ppp.py | 16 +++++++++++++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/docs/SYNTAX.md b/docs/SYNTAX.md index 309824d..96534bd 100644 --- a/docs/SYNTAX.md +++ b/docs/SYNTAX.md @@ -209,7 +209,7 @@ The `conditionN` can be: | `variable [not] operation value` | check the variable against a value | | `variable [not] operation (value1,value2,...)` | check the variable against a list of values | -For a simple value the allowed operations are `eq`, `ne`, `gt`, `lt`, `ge`, `le`, `contains` and the value can be a quoted string or an integer. For a list of values the allowed operations are `contains`, `in` and the value of the variable is checked against all the elements of the list until one matches. The operation can be preceded by `not` for readability, instead of using it in the front. +For a simple value the allowed operations are `eq`, `ne`, `gt`, `lt`, `ge`, `le`, `contains` and the value can be a quoted string, an integer, or another variable name (e.g., ``). When the value is a variable name, it is resolved to the variable's current value before comparison. For a list of values the allowed operations are `contains`, `in` and the value of the variable is checked against all the elements of the list until one matches. The operation can be preceded by `not` for readability, instead of using it in the front. You can also build complex conditions joining them with boolean operators and/or/not and parentheses. diff --git a/grammar.lark b/grammar.lark index 7ae47a2..f6d8e13 100644 --- a/grammar.lark +++ b/grammar.lark @@ -112,7 +112,7 @@ operation_and: condition _WHITESPACE "and" _WHITESPACE condition operation_or: condition _WHITESPACE "or" _WHITESPACE condition operation_not: "not" ( ( _WHITESPACE ungrouped_condition ) | ( _WHITESPACE? grouped_condition ) ) truthy_operand: IDENTIFIER -comparison_simple_value: IDENTIFIER _WHITESPACE ( /not/ _WHITESPACE )? /eq|ne|gt|lt|ge|le|contains/ _WHITESPACE SIMPLEVALUE +comparison_simple_value: IDENTIFIER _WHITESPACE ( /not/ _WHITESPACE )? /eq|ne|gt|lt|ge|le|contains/ _WHITESPACE ( SIMPLEVALUE | IDENTIFIER ) comparison_list_value: IDENTIFIER _WHITESPACE ( /not/ _WHITESPACE )? /contains|in/ _WHITESPACE listvalue listvalue.9: "(" _WHITESPACE? SIMPLEVALUE ( _WHITESPACE? "," _WHITESPACE? SIMPLEVALUE )* _WHITESPACE? ")" diff --git a/ppp.py b/ppp.py index 655f739..55c855f 100644 --- a/ppp.py +++ b/ppp.py @@ -1082,6 +1082,20 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in ) ) + def __resolve_cond_value(self, c: str): + """Resolve a condition value: try int first, fall back to variable lookup.""" + try: + return int(c) + except ValueError: + # Bare identifier — resolve as variable reference + if c.startswith("_"): + val = self.__ppp.system_variables.get(c, "") + else: + val = self.__get_user_variable_value(c) + if val is None: + val = "" + return val.lower() if isinstance(val, str) else val + def __eval_basiccondition(self, cond_var: str, cond_comp: str, cond_value: str | list[str]) -> bool: """ Evaluate a condition based on the given variable, comparison, and value. @@ -1133,7 +1147,7 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in ( c[1:-1].lower() if c.startswith('"') or c.startswith("'") - else True if c.lower() == "true" else False if c.lower() == "false" or c == "" else int(c) + else True if c.lower() == "true" else False if c.lower() == "false" or c == "" else self.__resolve_cond_value(c) ) for c in cond_value ) From 1fdf71c76e6d3dd4097b3d29afda2a1eeaf16904 Mon Sep 17 00:00:00 2001 From: Brandon Wallace Date: Thu, 19 Mar 2026 23:59:41 -0500 Subject: [PATCH 3/3] fix: add warn_or_stop for undefined variables in __resolve_cond_value Align RHS variable resolution with LHS behavior in __eval_basiccondition so undefined system/user variables honor the on_warning setting. --- ppp.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ppp.py b/ppp.py index 55c855f..6b3e9ab 100644 --- a/ppp.py +++ b/ppp.py @@ -1089,11 +1089,15 @@ class PromptPostProcessor: # pylint: disable=too-few-public-methods,too-many-in except ValueError: # Bare identifier — resolve as variable reference if c.startswith("_"): - val = self.__ppp.system_variables.get(c, "") + val = self.__ppp.system_variables.get(c, None) + if val is None: + val = "" + self.warn_or_stop(f"Unknown system variable {c}") else: val = self.__get_user_variable_value(c) if val is None: val = "" + self.warn_or_stop(f"Unknown user variable {c}") return val.lower() if isinstance(val, str) else val def __eval_basiccondition(self, cond_var: str, cond_comp: str, cond_value: str | list[str]) -> bool: