From 1d6ce96137fc49fcf18edfceac667517dd833b68 Mon Sep 17 00:00:00 2001 From: Sebastian Willing Date: Wed, 6 Dec 2023 15:23:05 +0100 Subject: [PATCH] Evaluate a condition branch only if needed [The CEL language definition](https://github.com/google/cel-spec/blob/master/doc/langdef.md#logical-operators) suggests: > To get traditional left-to-right short-circuiting evaluation of logical operators, as in C or other languages (also called "McCarthy Evaluation"), the expression e1 && e2 can be rewritten `e1 ? e2 : false`. Similarly, `e1 || e2` can be rewritten `e1 ? true : e2`. `cel-python` used to evaluate the full tree before deciding if a branch will be used or not. This PR only evaluates a branch if selected by the condition. Fixes issue https://github.com/cloud-custodian/cel-python/issues/50 --- src/celpy/evaluation.py | 9 +++++++-- type_check/lineprecision.txt | 16 ++++++++-------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/celpy/evaluation.py b/src/celpy/evaluation.py index 40923c8..b1ffcf5 100644 --- a/src/celpy/evaluation.py +++ b/src/celpy/evaluation.py @@ -1322,10 +1322,12 @@ def expr(self, tree: lark.Tree) -> Result: elif len(tree.children) == 3: # full conditionalor "?" conditionalor ":" expr. func = self.functions["_?_:_"] - cond_value, left, right = cast(Tuple[Result, Result, Result], self.visit_children(tree)) + cond_value = self.visit(tree.children[0]) try: - return func(cond_value, left, right) + return self.visit(tree.children[1]) if func(cond_value, True, False) else self.visit(tree.children[2]) except TypeError as ex: + left = self.visit(tree.children[1]) if cond_value else '-' + right = self.visit(tree.children[2]) if cond_value else '-' self.logger.debug("%s(%s, %s) --> %s", func.__name__, left, right, ex) err = ( f"found no matching overload for _?_:_ " @@ -1341,6 +1343,9 @@ def expr(self, tree: lark.Tree) -> Result: column=tree.meta.column, ) + def visit(self, child: Union[str, lark.Tree]): + return super().visit(child) if isinstance(child, lark.Tree) else child + @trace def conditionalor(self, tree: lark.Tree) -> Result: """ diff --git a/type_check/lineprecision.txt b/type_check/lineprecision.txt index 08abb6f..48fae9a 100644 --- a/type_check/lineprecision.txt +++ b/type_check/lineprecision.txt @@ -1,11 +1,11 @@ Name Lines Precise Imprecise Any Empty Unanalyzed ------------------------------------------------------------------- -celpy 252 44 8 6 194 0 -celpy.__main__ 465 162 12 47 243 1 -celpy.adapter 137 26 17 6 85 3 -celpy.c7nlib 1511 315 15 144 1037 0 -celpy.celparser 396 127 1 98 170 0 -celpy.celtypes 1349 364 27 194 729 35 -celpy.evaluation 2237 471 45 404 1302 15 +celpy 293 62 0 18 213 0 +celpy.__main__ 466 163 9 49 244 1 +celpy.adapter 137 24 17 8 85 3 +celpy.c7nlib 1580 333 14 162 1071 0 +celpy.celparser 402 129 5 98 170 0 +celpy.celtypes 1495 414 29 226 788 38 +celpy.evaluation 2439 541 37 459 1391 11 xlate 0 0 0 0 0 0 -xlate.c7n_to_cel 1730 363 115 141 1108 3 +xlate.c7n_to_cel 1730 366 115 146 1100 3