Skip to content

Commit ed99a45

Browse files
l46kokcopybara-github
authored andcommitted
Support attribute qualification, plan select, allow parsed-only ident resolution on enums
PiperOrigin-RevId: 840949005
1 parent 298c386 commit ed99a45

File tree

16 files changed

+724
-91
lines changed

16 files changed

+724
-91
lines changed

common/src/main/java/dev/cel/common/values/CelValueConverter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
@SuppressWarnings("unchecked") // Unchecked cast of generics due to type-erasure (ex: MapValue).
3434
@Internal
3535
@Immutable
36-
abstract class CelValueConverter {
36+
public abstract class CelValueConverter {
3737

3838
/** Adapts a {@link CelValue} to a plain old Java Object. */
3939
public Object unwrap(CelValue celValue) {

runtime/src/main/java/dev/cel/runtime/CelEvaluationExceptionBuilder.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,16 @@ public static CelEvaluationExceptionBuilder newBuilder(String message, Object...
8383
*/
8484
@Internal
8585
public static CelEvaluationExceptionBuilder newBuilder(CelRuntimeException celRuntimeException) {
86+
// TODO: Temporary until migration is complete.
8687
Throwable cause = celRuntimeException.getCause();
87-
return new CelEvaluationExceptionBuilder(cause.getMessage())
88-
.setCause(cause)
89-
.setErrorCode(celRuntimeException.getErrorCode());
88+
String message =
89+
cause == null
90+
? celRuntimeException.getMessage()
91+
: celRuntimeException.getCause().getMessage();
92+
93+
return new CelEvaluationExceptionBuilder(message)
94+
.setErrorCode(celRuntimeException.getErrorCode())
95+
.setCause(cause);
9096
}
9197

9298
private CelEvaluationExceptionBuilder(String message) {

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

Lines changed: 2 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -14,64 +14,13 @@
1414

1515
package dev.cel.runtime.planner;
1616

17-
18-
import com.google.common.collect.ImmutableList;
1917
import com.google.errorprone.annotations.Immutable;
20-
import dev.cel.common.types.CelTypeProvider;
21-
import dev.cel.common.types.TypeType;
2218
import dev.cel.runtime.GlobalResolver;
2319

20+
/** Represents a resolvable symbol or path (such as a variable or a field selection). */
2421
@Immutable
2522
interface Attribute {
2623
Object resolve(GlobalResolver ctx);
2724

28-
final class MaybeAttribute implements Attribute {
29-
private final ImmutableList<Attribute> attributes;
30-
31-
@Override
32-
public Object resolve(GlobalResolver ctx) {
33-
for (Attribute attr : attributes) {
34-
Object value = attr.resolve(ctx);
35-
if (value != null) {
36-
return value;
37-
}
38-
}
39-
40-
// TODO: Handle unknowns
41-
throw new UnsupportedOperationException("Unknown attributes is not supported yet");
42-
}
43-
44-
MaybeAttribute(ImmutableList<Attribute> attributes) {
45-
this.attributes = attributes;
46-
}
47-
}
48-
49-
final class NamespacedAttribute implements Attribute {
50-
private final ImmutableList<String> namespacedNames;
51-
private final CelTypeProvider typeProvider;
52-
53-
@Override
54-
public Object resolve(GlobalResolver ctx) {
55-
for (String name : namespacedNames) {
56-
Object value = ctx.resolve(name);
57-
if (value != null) {
58-
// TODO: apply qualifiers
59-
return value;
60-
}
61-
62-
TypeType type = typeProvider.findType(name).map(TypeType::create).orElse(null);
63-
if (type != null) {
64-
return type;
65-
}
66-
}
67-
68-
// TODO: Handle unknowns
69-
throw new UnsupportedOperationException("Unknown attributes is not supported yet");
70-
}
71-
72-
NamespacedAttribute(CelTypeProvider typeProvider, ImmutableList<String> namespacedNames) {
73-
this.typeProvider = typeProvider;
74-
this.namespacedNames = namespacedNames;
75-
}
76-
}
25+
Attribute addQualifier(Qualifier qualifier);
7726
}

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

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,35 +15,46 @@
1515
package dev.cel.runtime.planner;
1616

1717
import com.google.common.collect.ImmutableList;
18+
import com.google.common.collect.ImmutableSet;
1819
import com.google.errorprone.annotations.Immutable;
1920
import dev.cel.common.CelContainer;
2021
import dev.cel.common.types.CelTypeProvider;
21-
import dev.cel.runtime.planner.Attribute.MaybeAttribute;
22-
import dev.cel.runtime.planner.Attribute.NamespacedAttribute;
22+
import dev.cel.common.values.CelValueConverter;
2323

2424
@Immutable
2525
final class AttributeFactory {
2626

27-
private final CelContainer unusedContainer;
27+
private final CelContainer container;
2828
private final CelTypeProvider typeProvider;
29+
private final CelValueConverter celValueConverter;
2930

3031
NamespacedAttribute newAbsoluteAttribute(String... names) {
31-
return new NamespacedAttribute(typeProvider, ImmutableList.copyOf(names));
32+
return new NamespacedAttribute(typeProvider, celValueConverter, ImmutableSet.copyOf(names));
3233
}
3334

34-
MaybeAttribute newMaybeAttribute(String... names) {
35-
// TODO: Resolve container names
35+
RelativeAttribute newRelativeAttribute(PlannedInterpretable operand) {
36+
return new RelativeAttribute(operand, celValueConverter);
37+
}
38+
39+
MaybeAttribute newMaybeAttribute(String name) {
3640
return new MaybeAttribute(
37-
ImmutableList.of(new NamespacedAttribute(typeProvider, ImmutableList.copyOf(names))));
41+
this,
42+
ImmutableList.of(
43+
new NamespacedAttribute(
44+
typeProvider, celValueConverter, container.resolveCandidateNames(name))));
3845
}
3946

4047
static AttributeFactory newAttributeFactory(
41-
CelContainer celContainer, CelTypeProvider typeProvider) {
42-
return new AttributeFactory(celContainer, typeProvider);
48+
CelContainer celContainer,
49+
CelTypeProvider typeProvider,
50+
CelValueConverter celValueConverter) {
51+
return new AttributeFactory(celContainer, typeProvider, celValueConverter);
4352
}
4453

45-
private AttributeFactory(CelContainer container, CelTypeProvider typeProvider) {
46-
this.unusedContainer = container;
54+
private AttributeFactory(
55+
CelContainer container, CelTypeProvider typeProvider, CelValueConverter celValueConverter) {
56+
this.container = container;
4757
this.typeProvider = typeProvider;
58+
this.celValueConverter = celValueConverter;
4859
}
4960
}

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

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,11 @@ java_library(
2626
":eval_unary",
2727
":eval_var_args_call",
2828
":eval_zero_arity",
29+
":interpretable_attribute",
2930
":planned_interpretable",
3031
":planned_program",
32+
":qualifier",
33+
":string_qualifier",
3134
"//:auto_value",
3235
"//common:cel_ast",
3336
"//common:container",
@@ -36,11 +39,11 @@ java_library(
3639
"//common/ast",
3740
"//common/types",
3841
"//common/types:type_providers",
42+
"//common/values",
3943
"//common/values:cel_value_provider",
4044
"//runtime:dispatcher",
4145
"//runtime:evaluation_exception",
4246
"//runtime:evaluation_exception_builder",
43-
"//runtime:interpretable",
4447
"//runtime:program",
4548
"//runtime:resolved_overload",
4649
"@maven//:com_google_code_findbugs_annotations",
@@ -84,28 +87,67 @@ java_library(
8487
],
8588
)
8689

90+
java_library(
91+
name = "interpretable_attribute",
92+
srcs = ["InterpretableAttribute.java"],
93+
deps = [
94+
":planned_interpretable",
95+
":qualifier",
96+
"@maven//:com_google_errorprone_error_prone_annotations",
97+
],
98+
)
99+
87100
java_library(
88101
name = "attribute",
89102
srcs = [
90103
"Attribute.java",
91104
"AttributeFactory.java",
105+
"MaybeAttribute.java",
106+
"MissingAttribute.java",
107+
"NamespacedAttribute.java",
108+
"RelativeAttribute.java",
92109
],
93110
deps = [
111+
":eval_helpers",
112+
":planned_interpretable",
113+
":qualifier",
94114
"//common:container",
115+
"//common/exceptions:attribute_not_found",
95116
"//common/types",
96117
"//common/types:type_providers",
118+
"//common/values",
119+
"//common/values:cel_value",
97120
"//runtime:interpretable",
98121
"@maven//:com_google_errorprone_error_prone_annotations",
99122
"@maven//:com_google_guava_guava",
100123
],
101124
)
102125

126+
java_library(
127+
name = "qualifier",
128+
srcs = ["Qualifier.java"],
129+
deps = [
130+
"@maven//:com_google_errorprone_error_prone_annotations",
131+
],
132+
)
133+
134+
java_library(
135+
name = "string_qualifier",
136+
srcs = ["StringQualifier.java"],
137+
deps = [
138+
":qualifier",
139+
"//common/exceptions:attribute_not_found",
140+
"//common/values",
141+
],
142+
)
143+
103144
java_library(
104145
name = "eval_attribute",
105146
srcs = ["EvalAttribute.java"],
106147
deps = [
107148
":attribute",
108-
":planned_interpretable",
149+
":interpretable_attribute",
150+
":qualifier",
109151
"//runtime:evaluation_listener",
110152
"//runtime:function_resolver",
111153
"//runtime:interpretable",

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,18 @@
2020
import dev.cel.runtime.GlobalResolver;
2121

2222
@Immutable
23-
final class EvalAttribute extends PlannedInterpretable {
23+
final class EvalAttribute extends InterpretableAttribute {
2424

2525
private final Attribute attr;
2626

2727
@Override
2828
public Object eval(GlobalResolver resolver) {
29-
return attr.resolve(resolver);
29+
Object resolved = attr.resolve(resolver);
30+
if (resolved instanceof MissingAttribute) {
31+
((MissingAttribute) resolved).resolve(resolver);
32+
}
33+
34+
return resolved;
3035
}
3136

3237
@Override
@@ -46,9 +51,16 @@ public Object eval(
4651
GlobalResolver resolver,
4752
CelFunctionResolver lateBoundFunctionResolver,
4853
CelEvaluationListener listener) {
54+
// TODO: Implement support
4955
throw new UnsupportedOperationException("Not yet supported");
5056
}
5157

58+
@Override
59+
public EvalAttribute addQualifier(long exprId, Qualifier qualifier) {
60+
Attribute newAttribute = attr.addQualifier(qualifier);
61+
return create(exprId, newAttribute);
62+
}
63+
5264
static EvalAttribute create(long exprId, Attribute attr) {
5365
return new EvalAttribute(exprId, attr);
5466
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package dev.cel.runtime.planner;
16+
17+
import com.google.errorprone.annotations.Immutable;
18+
19+
@Immutable
20+
abstract class InterpretableAttribute extends PlannedInterpretable {
21+
22+
abstract InterpretableAttribute addQualifier(long exprId, Qualifier qualifier);
23+
24+
InterpretableAttribute(long exprId) {
25+
super(exprId);
26+
}
27+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package dev.cel.runtime.planner;
16+
17+
import com.google.common.collect.ImmutableList;
18+
import com.google.errorprone.annotations.Immutable;
19+
import dev.cel.runtime.GlobalResolver;
20+
21+
/**
22+
* An attribute that attempts to resolve a variable against a list of potential namespaced
23+
* attributes. This is used during parsed-only evaluation.
24+
*/
25+
@Immutable
26+
final class MaybeAttribute implements Attribute {
27+
private final AttributeFactory attrFactory;
28+
private final ImmutableList<NamespacedAttribute> attributes;
29+
30+
@Override
31+
public Object resolve(GlobalResolver ctx) {
32+
MissingAttribute maybeError = null;
33+
for (NamespacedAttribute attr : attributes) {
34+
Object value = attr.resolve(ctx);
35+
if (value == null) {
36+
continue;
37+
}
38+
39+
if (value instanceof MissingAttribute) {
40+
maybeError = (MissingAttribute) value;
41+
// When the variable is missing in a maybe attribute, defer erroring.
42+
// The variable may exist in other namespaced attributes.
43+
continue;
44+
}
45+
46+
return value;
47+
}
48+
49+
return maybeError;
50+
}
51+
52+
@Override
53+
public Attribute addQualifier(Qualifier qualifier) {
54+
Object strQualifier = qualifier.value();
55+
ImmutableList.Builder<String> augmentedNamesBuilder = ImmutableList.builder();
56+
ImmutableList.Builder<NamespacedAttribute> attributesBuilder = ImmutableList.builder();
57+
for (NamespacedAttribute attr : attributes) {
58+
if (strQualifier instanceof String && attr.qualifiers().isEmpty()) {
59+
for (String varName : attr.candidateVariableNames()) {
60+
augmentedNamesBuilder.add(varName + "." + strQualifier);
61+
}
62+
}
63+
64+
attributesBuilder.add(attr.addQualifier(qualifier));
65+
}
66+
ImmutableList<String> augmentedNames = augmentedNamesBuilder.build();
67+
ImmutableList.Builder<NamespacedAttribute> namespacedAttributeBuilder = ImmutableList.builder();
68+
if (!augmentedNames.isEmpty()) {
69+
namespacedAttributeBuilder.add(
70+
attrFactory.newAbsoluteAttribute(augmentedNames.toArray(new String[0])));
71+
}
72+
73+
namespacedAttributeBuilder.addAll(attributesBuilder.build());
74+
return new MaybeAttribute(attrFactory, namespacedAttributeBuilder.build());
75+
}
76+
77+
MaybeAttribute(AttributeFactory attrFactory, ImmutableList<NamespacedAttribute> attributes) {
78+
this.attrFactory = attrFactory;
79+
this.attributes = attributes;
80+
}
81+
}

0 commit comments

Comments
 (0)