1414
1515package dev .cel .runtime .planner ;
1616
17- import com .google .common .base .Preconditions ;
17+ import static com .google .common .base .Preconditions .checkArgument ;
18+
1819import com .google .common .collect .ImmutableMap ;
1920import com .google .common .collect .Sets ;
2021import com .google .common .primitives .UnsignedLong ;
2324import dev .cel .common .exceptions .CelDuplicateKeyException ;
2425import dev .cel .common .exceptions .CelInvalidArgumentException ;
2526import dev .cel .runtime .AccumulatedUnknowns ;
26- import dev .cel .runtime .CelEvaluationException ;
2727import dev .cel .runtime .GlobalResolver ;
2828import java .util .HashSet ;
2929import java .util .Optional ;
30+ import java .util .Set ;
3031
3132@ Immutable
3233final class EvalCreateMap extends PlannedInterpretable {
@@ -44,45 +45,20 @@ final class EvalCreateMap extends PlannedInterpretable {
4445 private final boolean [] isOptional ;
4546
4647 @ Override
47- Object evalInternal (GlobalResolver resolver , ExecutionFrame frame ) throws CelEvaluationException {
48+ Object evalInternal (GlobalResolver resolver , ExecutionFrame frame ) {
4849 ImmutableMap .Builder <Object , Object > builder =
4950 ImmutableMap .builderWithExpectedSize (keys .length );
5051 HashSet <Object > keysSeen = Sets .newHashSetWithExpectedSize (keys .length );
5152 AccumulatedUnknowns unknowns = null ;
5253
5354 for (int i = 0 ; i < keys .length ; i ++) {
5455 PlannedInterpretable keyInterpretable = keys [i ];
55- Object key = keyInterpretable . eval ( resolver , frame );
56+ Object key = EvalHelpers . evalStrictly ( keyInterpretable , resolver , frame );
5657
5758 if (key instanceof AccumulatedUnknowns ) {
5859 unknowns = AccumulatedUnknowns .maybeMerge (unknowns , key );
5960 } else {
60- if (!(key instanceof String
61- || key instanceof Long
62- || key instanceof UnsignedLong
63- || key instanceof Boolean )) {
64- throw new LocalizedEvaluationException (
65- new CelInvalidArgumentException ("Unsupported key type: " + key ),
66- keyInterpretable .expr ().id ());
67- }
68-
69- boolean isDuplicate = !keysSeen .add (key );
70- if (!isDuplicate ) {
71- if (key instanceof Long ) {
72- long longVal = (Long ) key ;
73- if (longVal >= 0 ) {
74- isDuplicate = keysSeen .contains (UnsignedLong .valueOf (longVal ));
75- }
76- } else if (key instanceof UnsignedLong ) {
77- UnsignedLong ulongVal = (UnsignedLong ) key ;
78- isDuplicate = keysSeen .contains (ulongVal .longValue ());
79- }
80- }
81-
82- if (isDuplicate ) {
83- throw new LocalizedEvaluationException (
84- CelDuplicateKeyException .of (key ), keyInterpretable .expr ().id ());
85- }
61+ validateAndTrackKey (keysSeen , keyInterpretable , key );
8662 }
8763
8864 Object val = EvalHelpers .evalStrictly (values [i ], resolver , frame );
@@ -119,12 +95,61 @@ Object evalInternal(GlobalResolver resolver, ExecutionFrame frame) throws CelEva
11995 return builder .buildOrThrow ();
12096 }
12197
122- static EvalCreateMap create (
98+ private static void validateAndTrackKey (
99+ Set <Object > keysSeen , PlannedInterpretable keyInterpretable , Object key ) {
100+ if (!(key instanceof String
101+ || key instanceof Long
102+ || key instanceof UnsignedLong
103+ || key instanceof Boolean )) {
104+ throw new LocalizedEvaluationException (
105+ new CelInvalidArgumentException ("Unsupported key type: " + key ),
106+ keyInterpretable .expr ().id ());
107+ }
108+
109+ boolean isDuplicate = !keysSeen .add (key );
110+ if (!isDuplicate ) {
111+ if (key instanceof Long ) {
112+ long longVal = (Long ) key ;
113+ if (longVal >= 0 ) {
114+ isDuplicate = keysSeen .contains (UnsignedLong .valueOf (longVal ));
115+ }
116+ } else if (key instanceof UnsignedLong ) {
117+ UnsignedLong ulongVal = (UnsignedLong ) key ;
118+ isDuplicate = keysSeen .contains (ulongVal .longValue ());
119+ }
120+ }
121+
122+ if (isDuplicate ) {
123+ throw new LocalizedEvaluationException (
124+ CelDuplicateKeyException .of (key ), keyInterpretable .expr ().id ());
125+ }
126+ }
127+
128+ static PlannedInterpretable create (
123129 CelExpr expr ,
124130 PlannedInterpretable [] keys ,
125131 PlannedInterpretable [] values ,
126132 boolean [] isOptional ) {
127- return new EvalCreateMap (expr , keys , values , isOptional );
133+ for (int i = 0 ; i < keys .length ; i ++) {
134+ if (!(keys [i ] instanceof EvalConstant )
135+ || !(values [i ] instanceof EvalConstant )
136+ || isOptional [i ]) {
137+ return new EvalCreateMap (expr , keys , values , isOptional );
138+ }
139+ }
140+ ImmutableMap .Builder <Object , Object > builder =
141+ ImmutableMap .builderWithExpectedSize (keys .length );
142+ HashSet <Object > keysSeen = Sets .newHashSetWithExpectedSize (keys .length );
143+ try {
144+ for (int i = 0 ; i < keys .length ; i ++) {
145+ Object key = ((EvalConstant ) keys [i ]).constantValue ();
146+ validateAndTrackKey (keysSeen , keys [i ], key );
147+ builder .put (key , ((EvalConstant ) values [i ]).constantValue ());
148+ }
149+ } catch (LocalizedEvaluationException e ) {
150+ return new EvalCreateMap (expr , keys , values , isOptional );
151+ }
152+ return EvalConstant .create (expr , builder .buildOrThrow ());
128153 }
129154
130155 private EvalCreateMap (
@@ -133,8 +158,8 @@ private EvalCreateMap(
133158 PlannedInterpretable [] values ,
134159 boolean [] isOptional ) {
135160 super (expr );
136- Preconditions . checkArgument (keys .length == values .length );
137- Preconditions . checkArgument (keys .length == isOptional .length );
161+ checkArgument (keys .length == values .length );
162+ checkArgument (keys .length == isOptional .length );
138163 this .keys = keys ;
139164 this .values = values ;
140165 this .isOptional = isOptional ;
0 commit comments