|
23 | 23 | import com.google.common.collect.ImmutableList; |
24 | 24 | import com.google.common.collect.ImmutableSet; |
25 | 25 | import com.google.errorprone.annotations.CanIgnoreReturnValue; |
| 26 | +import com.google.protobuf.Descriptors.FieldDescriptor; |
| 27 | +import com.google.protobuf.Message; |
26 | 28 | import dev.cel.bundle.Cel; |
27 | 29 | import dev.cel.common.CelAbstractSyntaxTree; |
28 | 30 | import dev.cel.common.CelMutableAst; |
@@ -276,6 +278,38 @@ private static boolean areChildrenArgConstant(CelNavigableMutableExpr expr) { |
276 | 278 | return false; |
277 | 279 | } |
278 | 280 |
|
| 281 | + /** |
| 282 | + * Checks whether the provided identifier node is a loop variable bound by a surrounding |
| 283 | + * comprehension. Identifiers existing strictly within loop initialization bounds (e.g. iterRange) |
| 284 | + * are not considered loop variables. |
| 285 | + */ |
| 286 | + private static boolean isComprehensionBoundLoopVariable(CelNavigableMutableExpr identNode) { |
| 287 | + String identName = identNode.expr().ident().name(); |
| 288 | + CelNavigableMutableExpr child = identNode; |
| 289 | + CelNavigableMutableExpr parent = identNode.parent().orElse(null); |
| 290 | + |
| 291 | + while (parent != null) { |
| 292 | + if (parent.getKind().equals(Kind.COMPREHENSION)) { |
| 293 | + CelMutableComprehension comprehension = parent.expr().comprehension(); |
| 294 | + long childId = child.expr().id(); |
| 295 | + |
| 296 | + boolean isInitializationNode = |
| 297 | + childId == comprehension.iterRange().id() || childId == comprehension.accuInit().id(); |
| 298 | + |
| 299 | + if (!isInitializationNode) { |
| 300 | + if (identName.equals(comprehension.accuVar()) |
| 301 | + || identName.equals(comprehension.iterVar()) |
| 302 | + || identName.equals(comprehension.iterVar2())) { |
| 303 | + return true; |
| 304 | + } |
| 305 | + } |
| 306 | + } |
| 307 | + child = parent; |
| 308 | + parent = parent.parent().orElse(null); |
| 309 | + } |
| 310 | + return false; |
| 311 | + } |
| 312 | + |
279 | 313 | private static boolean isNestedComprehension(CelNavigableMutableExpr expr) { |
280 | 314 | Optional<CelNavigableMutableExpr> maybeParent = expr.parent(); |
281 | 315 | while (maybeParent.isPresent()) { |
@@ -364,6 +398,21 @@ private Optional<CelMutableExpr> maybeAdaptEvaluatedResult(Object result) { |
364 | 398 | CelMutableExpr.ofConstant(CelConstant.ofValue(timestampStrArg))); |
365 | 399 |
|
366 | 400 | return Optional.of(CelMutableExpr.ofCall(timestampCall)); |
| 401 | + } else if (result instanceof Message) { |
| 402 | + Message message = (Message) result; |
| 403 | + List<CelMutableStruct.Entry> structEntries = new ArrayList<>(); |
| 404 | + for (Map.Entry<FieldDescriptor, Object> entry : message.getAllFields().entrySet()) { |
| 405 | + CelMutableExpr adaptedFieldExpr = maybeAdaptEvaluatedResult(entry.getValue()).orElse(null); |
| 406 | + if (adaptedFieldExpr == null) { |
| 407 | + return Optional.empty(); |
| 408 | + } |
| 409 | + structEntries.add( |
| 410 | + CelMutableStruct.Entry.create(0, entry.getKey().getName(), adaptedFieldExpr)); |
| 411 | + } |
| 412 | + return Optional.of( |
| 413 | + CelMutableExpr.ofStruct( |
| 414 | + CelMutableStruct.create( |
| 415 | + message.getDescriptorForType().getFullName(), structEntries))); |
367 | 416 | } |
368 | 417 |
|
369 | 418 | // Evaluated result cannot be folded (e.g: unknowns) |
@@ -733,6 +782,7 @@ private static Object evaluateExpr(Cel cel, CelNavigableMutableExpr navigableMut |
733 | 782 | navigableMutableExpr |
734 | 783 | .allNodes() |
735 | 784 | .filter(node -> node.getKind().equals(Kind.IDENT)) |
| 785 | + .filter(node -> !isComprehensionBoundLoopVariable(node)) |
736 | 786 | .map(node -> node.expr().ident().name()) |
737 | 787 | .map(CelAttributePattern::fromQualifiedIdentifier) |
738 | 788 | .collect(toImmutableList()); |
|
0 commit comments