Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions runtime/src/main/java/dev/cel/runtime/planner/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ java_library(
"//runtime:interpretable",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_guava_guava",
"@maven//:org_jspecify_jspecify",
],
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import dev.cel.common.values.CelValueConverter;
import dev.cel.runtime.GlobalResolver;
import java.util.NoSuchElementException;
import org.jspecify.annotations.Nullable;

@Immutable
final class NamespacedAttribute implements Attribute {
Expand All @@ -34,6 +35,14 @@ final class NamespacedAttribute implements Attribute {
private final CelValueConverter celValueConverter;
private final CelTypeProvider typeProvider;

ImmutableList<Qualifier> qualifiers() {
return qualifiers;
}

ImmutableSet<String> candidateVariableNames() {
return namespacedNames;
}

@Override
public Object resolve(GlobalResolver ctx, ExecutionFrame frame) {
GlobalResolver inputVars = ctx;
Expand All @@ -59,41 +68,56 @@ public Object resolve(GlobalResolver ctx, ExecutionFrame frame) {
}
}

CelType type = typeProvider.findType(name).orElse(null);
if (type != null) {
if (qualifiers.isEmpty()) {
// Resolution of a fully qualified type name: foo.bar.baz
return TypeType.create(type);
} else {
// This is potentially a fully qualified reference to an enum value
if (type instanceof EnumType && qualifiers.size() == 1) {
EnumType enumType = (EnumType) type;
String strQualifier = (String) qualifiers.get(0).value();
return enumType
.findNumberByName(strQualifier)
.orElseThrow(
() ->
new NoSuchElementException(
String.format(
"Field %s was not found on enum %s",
enumType.name(), strQualifier)));
}
}

throw new IllegalStateException(
"Unexpected type resolution when there were remaining qualifiers: " + type.name());
// Attempt to resolve the qualify type name if the name is not a variable identifier
value = findIdent(name);
if (value != null) {
return value;
}
}

return MissingAttribute.newMissingAttribute(namespacedNames);
}

ImmutableList<Qualifier> qualifiers() {
return qualifiers;
private @Nullable Object findIdent(String name) {
CelType type = typeProvider.findType(name).orElse(null);
// If the name resolves directly, this is a fully qualified type name
// (ex: 'int' or 'google.protobuf.Timestamp')
if (type != null) {
if (qualifiers.isEmpty()) {
// Resolution of a fully qualified type name: foo.bar.baz
return TypeType.create(type);
}

throw new IllegalStateException(
"Unexpected type resolution when there were remaining qualifiers: " + type.name());
}

// The name itself could be a fully qualified reference to an enum value
// (e.g: my.enum_type.BAR)
int lastDotIndex = name.lastIndexOf('.');
if (lastDotIndex > 0) {
String enumTypeName = name.substring(0, lastDotIndex);
String enumValueQualifier = name.substring(lastDotIndex + 1);

return typeProvider
.findType(enumTypeName)
.filter(EnumType.class::isInstance)
.map(EnumType.class::cast)
.map(enumType -> getEnumValue(enumType, enumValueQualifier))
.orElse(null);
}

return null;
}

ImmutableSet<String> candidateVariableNames() {
return namespacedNames;
private static Long getEnumValue(EnumType enumType, String field) {
return enumType
.findNumberByName(field)
.map(Integer::longValue)
.orElseThrow(
() ->
new NoSuchElementException(
String.format("Field %s was not found on enum %s", enumType.name(), field)));
}

private GlobalResolver unwrapToNonLocal(GlobalResolver resolver) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,33 @@ public void plan_ident_enum() throws Exception {

Object result = program.eval();

assertThat(result).isEqualTo(1);
assertThat(result).isEqualTo(1L);
}

@Test
public void plan_ident_enumContainer() throws Exception {
CelContainer container = CelContainer.ofName(GlobalEnum.getDescriptor().getFullName());
CelCompiler compiler =
CelCompilerFactory.standardCelCompilerBuilder()
.addMessageTypes(TestAllTypes.getDescriptor())
.setContainer(container)
.build();
CelAbstractSyntaxTree ast = compile(compiler, GlobalEnum.GAR.name());
ProgramPlanner planner =
ProgramPlanner.newPlanner(
TYPE_PROVIDER,
VALUE_PROVIDER,
newDispatcher(),
CEL_VALUE_CONVERTER,
container,
CEL_OPTIONS,
ImmutableSet.of());

Program program = planner.plan(ast);

Object result = program.eval();

assertThat(result).isEqualTo(1L);
}

@Test
Expand Down
Loading