Skip to content

Commit 1f3e08f

Browse files
committed
Plan map creation
1 parent f968d4d commit 1f3e08f

5 files changed

Lines changed: 127 additions & 26 deletions

File tree

runtime/src/main/java/dev/cel/runtime/planner/BUILD.bazel

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ java_library(
1717
":eval_and",
1818
":eval_attribute",
1919
":eval_const",
20+
":eval_create_map",
2021
":eval_create_struct",
2122
":eval_or",
2223
":eval_unary",
@@ -216,6 +217,22 @@ java_library(
216217
],
217218
)
218219

220+
java_library(
221+
name = "eval_create_map",
222+
srcs = ["EvalCreateMap.java"],
223+
deps = [
224+
":attribute",
225+
":cel_value_interpretable",
226+
"//common/values",
227+
"//common/values:cel_value",
228+
"//common/values:cel_value_provider",
229+
"//runtime:evaluation_exception",
230+
"//runtime:interpretable",
231+
"@maven//:com_google_errorprone_error_prone_annotations",
232+
"@maven//:com_google_guava_guava",
233+
],
234+
)
235+
219236
java_library(
220237
name = "eval_helpers",
221238
srcs = ["EvalHelpers.java"],
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package dev.cel.runtime.planner;
2+
3+
import com.google.common.collect.ImmutableMap;
4+
import com.google.errorprone.annotations.Immutable;
5+
import dev.cel.common.values.CelValue;
6+
import dev.cel.common.values.ImmutableMapValue;
7+
import dev.cel.runtime.CelEvaluationException;
8+
import dev.cel.runtime.GlobalResolver;
9+
10+
@Immutable
11+
final class EvalCreateMap implements CelValueInterpretable {
12+
13+
14+
@SuppressWarnings("Immutable")
15+
private final CelValueInterpretable[] keys;
16+
17+
@SuppressWarnings("Immutable")
18+
private final CelValueInterpretable[] values;
19+
20+
@Override
21+
public CelValue eval(GlobalResolver resolver) throws CelEvaluationException {
22+
ImmutableMap.Builder<CelValue, CelValue> builder = ImmutableMap.builder();
23+
for (int i = 0; i < keys.length; i++) {
24+
builder.put(keys[i].eval(resolver), values[i].eval(resolver));
25+
}
26+
return ImmutableMapValue.create(builder.build());
27+
}
28+
29+
static EvalCreateMap create(
30+
CelValueInterpretable[] keys,
31+
CelValueInterpretable[] values
32+
) {
33+
return new EvalCreateMap(keys, values);
34+
}
35+
36+
private EvalCreateMap(
37+
CelValueInterpretable[] keys,
38+
CelValueInterpretable[] values
39+
) {
40+
this.keys = keys;
41+
this.values = values;
42+
}
43+
}

runtime/src/main/java/dev/cel/runtime/planner/EvalCreateStruct.java

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,27 @@
88
import java.util.Collections;
99
import java.util.HashMap;
1010
import java.util.Map;
11-
import java.util.Map.Entry;
1211

1312
@Immutable
1413
final class EvalCreateStruct implements CelValueInterpretable {
1514

1615
private final CelValueProvider valueProvider;
1716
private final String typeName;
1817

19-
// Regular hashmap used for performance. Planner must not mutate the map post-construction.
18+
19+
@SuppressWarnings("Immutable")
20+
private final String[] keys;
21+
2022
@SuppressWarnings("Immutable")
21-
private final Map<String, CelValueInterpretable> fields;
23+
private final CelValueInterpretable[] values;
24+
2225

2326
@Override
2427
public CelValue eval(GlobalResolver resolver) throws CelEvaluationException {
2528
Map<String, Object> fieldValues = new HashMap<>();
26-
for (Entry<String, CelValueInterpretable> entry : fields.entrySet()) {
27-
Object value = entry.getValue().eval(resolver).value();
28-
fieldValues.put(entry.getKey(), value);
29+
for (int i = 0; i < keys.length; i++) {
30+
Object value = values[i].eval(resolver).value();
31+
fieldValues.put(keys[i], value);
2932
}
3033

3134
return valueProvider.newValue(typeName, Collections.unmodifiableMap(fieldValues))
@@ -35,18 +38,21 @@ public CelValue eval(GlobalResolver resolver) throws CelEvaluationException {
3538
static EvalCreateStruct create(
3639
CelValueProvider valueProvider,
3740
String typeName,
38-
Map<String, CelValueInterpretable> fields
41+
String[] keys,
42+
CelValueInterpretable[] values
3943
) {
40-
return new EvalCreateStruct(valueProvider, typeName, fields);
44+
return new EvalCreateStruct(valueProvider, typeName, keys, values);
4145
}
4246

4347
private EvalCreateStruct(
4448
CelValueProvider valueProvider,
4549
String typeName,
46-
Map<String, CelValueInterpretable> fields
50+
String[] keys,
51+
CelValueInterpretable[] values
4752
) {
4853
this.valueProvider = valueProvider;
4954
this.typeName = typeName;
50-
this.fields = fields;
55+
this.keys = keys;
56+
this.values = values;
5157
}
5258
}

runtime/src/main/java/dev/cel/runtime/planner/ProgramPlanner.java

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import dev.cel.common.ast.CelConstant;
1111
import dev.cel.common.ast.CelExpr;
1212
import dev.cel.common.ast.CelExpr.CelCall;
13+
import dev.cel.common.ast.CelExpr.CelMap;
1314
import dev.cel.common.ast.CelExpr.CelStruct;
1415
import dev.cel.common.ast.CelExpr.CelStruct.Entry;
1516
import dev.cel.common.ast.CelReference;
@@ -24,8 +25,8 @@
2425
import dev.cel.runtime.CelLiteRuntime.Program;
2526
import dev.cel.runtime.DefaultDispatcher;
2627

27-
import java.util.Collections;
2828
import java.util.HashMap;
29+
import java.util.List;
2930
import java.util.NoSuchElementException;
3031
import java.util.Optional;
3132

@@ -54,16 +55,16 @@ private CelValueInterpretable plan(
5455
case LIST:
5556
break;
5657
case STRUCT:
57-
return planCreateObject(celExpr, ctx);
58+
return planCreateStruct(celExpr, ctx);
5859
case MAP:
59-
break;
60+
return planCreateMap(celExpr, ctx);
6061
case COMPREHENSION:
6162
break;
6263
case NOT_SET:
6364
throw new UnsupportedOperationException("Unsupported kind: " + celExpr.getKind());
6465
}
6566

66-
throw new IllegalArgumentException("foo");
67+
throw new IllegalArgumentException("Not yet implemented");
6768
}
6869

6970
private CelValueInterpretable planIdent(
@@ -149,20 +150,39 @@ private CelValueInterpretable planCall(CelExpr expr, PlannerContext ctx) {
149150
}
150151
}
151152

152-
private CelValueInterpretable planCreateObject(CelExpr celExpr, PlannerContext ctx) {
153+
private CelValueInterpretable planCreateStruct(CelExpr celExpr, PlannerContext ctx) {
153154
CelStruct struct = celExpr.struct();
154-
// TODO: maybe do this via type provider?
155+
// TODO: maybe perform the check via type provider?
155156
valueProvider.newValue(struct.messageName(), new HashMap<>())
156157
.orElseThrow(() -> new IllegalArgumentException("Undefined type name: " + struct.messageName()));
157158

158-
HashMap<String, CelValueInterpretable> fieldMap = new HashMap<>();
159-
for (Entry entry : struct.entries()) {
160-
CelValueInterpretable value = plan(entry.value(), ctx);
161-
fieldMap.put(entry.fieldKey(), value);
159+
List<Entry> entries = struct.entries();
160+
String[] keys = new String[entries.size()];
161+
CelValueInterpretable[] values = new CelValueInterpretable[entries.size()];
162+
163+
for (int i = 0; i < entries.size(); i++) {
164+
Entry entry = entries.get(i);
165+
keys[i] = entry.fieldKey();
166+
values[i] = plan(entry.value(), ctx);
167+
}
168+
169+
return EvalCreateStruct.create(valueProvider, struct.messageName(), keys, values);
170+
}
171+
172+
private CelValueInterpretable planCreateMap(CelExpr celExpr, PlannerContext ctx) {
173+
CelMap map = celExpr.map();
174+
175+
List<CelMap.Entry> entries = map.entries();
176+
CelValueInterpretable[] keys = new CelValueInterpretable[entries.size()];
177+
CelValueInterpretable[] values = new CelValueInterpretable[entries.size()];
178+
179+
for (int i = 0; i < entries.size(); i++) {
180+
CelMap.Entry entry = entries.get(i);
181+
keys[i] = plan(entry.key(), ctx);
182+
values[i] = plan(entry.value(), ctx);
162183
}
163184

164-
return EvalCreateStruct.create(valueProvider, struct.messageName(),
165-
Collections.unmodifiableMap(fieldMap));
185+
return EvalCreateMap.create(keys, values);
166186
}
167187

168188
/**

runtime/src/test/java/dev/cel/runtime/planner/ProgramPlannerTest.java

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import java.nio.charset.StandardCharsets;
5353

5454
import dev.cel.runtime.DefaultDispatcher;
55+
import java.util.Map;
5556
import org.junit.Test;
5657
import org.junit.runner.RunWith;
5758

@@ -211,7 +212,7 @@ public void planIdent_variable() throws Exception {
211212
}
212213

213214
@Test
214-
public void planCreateObject() throws Exception {
215+
public void planCreateStruct() throws Exception {
215216
CelAbstractSyntaxTree ast = compile("cel.expr.conformance.proto3.TestAllTypes{}");
216217
Program program = PLANNER.plan(ast);
217218

@@ -221,13 +222,27 @@ public void planCreateObject() throws Exception {
221222
}
222223

223224
@Test
224-
public void planCreateObject_withFields() throws Exception {
225-
CelAbstractSyntaxTree ast = compile("cel.expr.conformance.proto3.TestAllTypes{single_string: 'foo'}");
225+
public void planCreateStruct_withFields() throws Exception {
226+
CelAbstractSyntaxTree ast = compile("cel.expr.conformance.proto3.TestAllTypes{"
227+
+ "single_string: 'foo',"
228+
+ "single_bool: true"
229+
+ "}");
226230
Program program = PLANNER.plan(ast);
227231

228232
Object result = program.eval();
229233

230-
assertThat(result).isEqualTo(TestAllTypes.newBuilder().setSingleString("foo").build());
234+
assertThat(result).isEqualTo(TestAllTypes.newBuilder().setSingleString("foo").setSingleBool(true).build());
235+
}
236+
237+
@Test
238+
public void planCreateMap() throws Exception {
239+
CelAbstractSyntaxTree ast = compile("{'foo': 1, true: 'bar'}");
240+
241+
Program program = PLANNER.plan(ast);
242+
243+
Map<Object, Object> result = (Map<Object, Object>) program.eval();
244+
245+
assertThat(result).containsExactly("foo", 1L, true, "bar").inOrder();
231246
}
232247

233248
@SuppressWarnings("ImmutableEnumChecker") // Test only

0 commit comments

Comments
 (0)