From b828b1fba010bcbe42d209a089c996f86e4b5996 Mon Sep 17 00:00:00 2001 From: Poncho Figueroa Date: Thu, 2 Jan 2025 17:09:21 -0800 Subject: [PATCH] Update operator precedence for post fix evaluation Equals '==' operator should have a higher precedence than OR and AND. This fixes a bug where a conditional like "!if RACECAR == RACECAR || RACECAR == STREETCAR" would evaluate the last two operators in the wrong order, returning False when it should be True. Removing extra parenthesis at the end of the tokens as it is modifying the input object and is only needed because an opening one is added to the stack. --- edk2toollib/uefi/edk2/parsers/base_parser.py | 5 +- tests.unit/parsers/test_base_parser.py | 85 ++++++++++++++++++++ 2 files changed, 87 insertions(+), 3 deletions(-) diff --git a/edk2toollib/uefi/edk2/parsers/base_parser.py b/edk2toollib/uefi/edk2/parsers/base_parser.py index ac792b8f..49f85c66 100644 --- a/edk2toollib/uefi/edk2/parsers/base_parser.py +++ b/edk2toollib/uefi/edk2/parsers/base_parser.py @@ -638,8 +638,7 @@ def _TokenizeConditional(cls: "BaseParser", text: str) -> str: @classmethod def _ConvertTokensToPostFix(cls: "BaseParser", tokens: list[str]) -> list[str]: # convert infix into post fix - stack = ["("] - tokens.append(")") # add an extra parathesis + stack = [] expression = [] for token in tokens: # If the incoming symbol is a left parenthesis, push it on the stack. @@ -699,7 +698,7 @@ def _GetOperatorPrecedence(cls: "BaseParser", token: str) -> int: return 100 if token == "NOT": # not is the lowest return -2 - if token == "IN": + if token == "IN" or token == "==" or token == "!=": return 1 return 0 diff --git a/tests.unit/parsers/test_base_parser.py b/tests.unit/parsers/test_base_parser.py index 6a02d627..bdf870ce 100644 --- a/tests.unit/parsers/test_base_parser.py +++ b/tests.unit/parsers/test_base_parser.py @@ -413,6 +413,91 @@ def test_process_and_operation_conditional(self): self.assertFalse(parser.EvaluateConditional("!if FALSE AND FALSE")) self.assertFalse(parser.EvaluateConditional("!if FALSE && FALSE")) + def test_process_equal_or_equal_operation_conditional(self): + parser = BaseParser("") + self.assertTrue(parser.EvaluateConditional("!if RACECAR == RACECAR || RACECAR == STREETCAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR == RACECAR OR RACECAR == STREETCAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR == RACECAR || RACECAR != STREETCAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR == RACECAR OR RACECAR != STREETCAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR != RACECAR || RACECAR == STREETCAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR != RACECAR OR RACECAR == STREETCAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR != RACECAR || RACECAR != STREETCAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR != RACECAR OR RACECAR != STREETCAR")) + + self.assertTrue(parser.EvaluateConditional("!if RACECAR == STREETCAR || RACECAR == RACECAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR == STREETCAR OR RACECAR == RACECAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR == STREETCAR || RACECAR != RACECAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR == STREETCAR OR RACECAR != RACECAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR != STREETCAR || RACECAR == RACECAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR != STREETCAR OR RACECAR == RACECAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR != STREETCAR || RACECAR != RACECAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR != STREETCAR OR RACECAR != RACECAR")) + + self.assertFalse(parser.EvaluateConditional("!if RACECAR == STREETCAR || STREETCAR == RACECAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR == STREETCAR OR STREETCAR == RACECAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR == STREETCAR || STREETCAR != RACECAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR == STREETCAR OR STREETCAR != RACECAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR != STREETCAR || STREETCAR == RACECAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR != STREETCAR OR STREETCAR == RACECAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR != STREETCAR || STREETCAR != RACECAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR != STREETCAR OR STREETCAR != RACECAR")) + + self.assertFalse(parser.EvaluateConditional("!if RACECAR == STREETCAR || RACECAR == STREETCAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR == STREETCAR OR RACECAR == STREETCAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR == STREETCAR || RACECAR != STREETCAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR == STREETCAR OR RACECAR != STREETCAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR != STREETCAR || RACECAR == STREETCAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR != STREETCAR OR RACECAR == STREETCAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR != STREETCAR || RACECAR != STREETCAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR != STREETCAR OR RACECAR != STREETCAR")) + + def test_process_equal_and_equal_operation_conditional(self): + parser = BaseParser("") + self.assertTrue(parser.EvaluateConditional("!if RACECAR == RACECAR && RACECAR != STREETCAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR == RACECAR AND RACECAR != STREETCAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR == RACECAR && RACECAR == STREETCAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR == RACECAR AND RACECAR == STREETCAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR != RACECAR && RACECAR != STREETCAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR != RACECAR AND RACECAR != STREETCAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR != RACECAR && RACECAR == STREETCAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR != RACECAR AND RACECAR == STREETCAR")) + + self.assertFalse(parser.EvaluateConditional("!if RACECAR == STREETCAR && RACECAR == RACECAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR == STREETCAR AND RACECAR == RACECAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR == STREETCAR && RACECAR != RACECAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR == STREETCAR AND RACECAR != RACECAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR != STREETCAR && RACECAR == RACECAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR != STREETCAR AND RACECAR == RACECAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR != STREETCAR && RACECAR != RACECAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR != STREETCAR AND RACECAR != RACECAR")) + + self.assertFalse(parser.EvaluateConditional("!if RACECAR == STREETCAR && STREETCAR == RACECAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR == STREETCAR AND STREETCAR == RACECAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR == STREETCAR && STREETCAR != RACECAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR == STREETCAR AND STREETCAR != RACECAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR != STREETCAR && STREETCAR == RACECAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR != STREETCAR AND STREETCAR == RACECAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR != STREETCAR && STREETCAR != RACECAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR != STREETCAR AND STREETCAR != RACECAR")) + + self.assertFalse(parser.EvaluateConditional("!if RACECAR == STREETCAR && RACECAR == STREETCAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR == STREETCAR AND RACECAR == STREETCAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR == STREETCAR && RACECAR != STREETCAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR == STREETCAR AND RACECAR != STREETCAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR != STREETCAR && RACECAR == STREETCAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR != STREETCAR AND RACECAR == STREETCAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR != STREETCAR && RACECAR != STREETCAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR != STREETCAR AND RACECAR != STREETCAR")) + + self.assertTrue(parser.EvaluateConditional("!if RACECAR == RACECAR && STREETCAR == STREETCAR")) + self.assertTrue(parser.EvaluateConditional("!if RACECAR == RACECAR AND STREETCAR == STREETCAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR == RACECAR && STREETCAR != STREETCAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR == RACECAR AND STREETCAR != STREETCAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR != RACECAR && STREETCAR == STREETCAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR != RACECAR AND STREETCAR == STREETCAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR != RACECAR && STREETCAR != STREETCAR")) + self.assertFalse(parser.EvaluateConditional("!if RACECAR != RACECAR AND STREETCAR != STREETCAR")) + def test_process_invalid_conditional(self): parser = BaseParser("") with self.assertRaises(RuntimeError):