diff --git a/docs/SYNTAX.md b/docs/SYNTAX.md index 4233f85..d9dbb87 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. When a variable used in an integer comparison is undefined or cannot be converted to an integer (e.g. it contains non-numeric text or is an empty string), the behavior depends on the `on_warning` setting: in `warn` mode the comparison evaluates to false, and in `stop` mode an error is raised. 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 7b1e144..80d8558 100644 --- a/ppp.py +++ b/ppp.py @@ -1082,6 +1082,24 @@ 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, 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: """ Evaluate a condition based on the given variable, comparison, and value. @@ -1133,7 +1151,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 ) diff --git a/tests/tests.py b/tests/tests.py index c037fef..05506ff 100644 --- a/tests/tests.py +++ b/tests/tests.py @@ -1328,6 +1328,44 @@ 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", ""), + ) + # NaN/undefined variable integer comparison tests def test_cmd_if_undefined_var_int_compare_warn(self): # undefined var integer compare with on_warning=warn