2020import dev .cel .common .types .CelType ;
2121import dev .cel .common .types .CelTypeProvider ;
2222import dev .cel .common .types .EnumType ;
23+ import dev .cel .common .types .SimpleType ;
2324import dev .cel .common .types .TypeType ;
2425import dev .cel .common .values .CelValue ;
2526import dev .cel .common .values .CelValueConverter ;
2627import dev .cel .runtime .GlobalResolver ;
2728import java .util .NoSuchElementException ;
29+ import org .jspecify .annotations .Nullable ;
2830
2931@ Immutable
3032final class NamespacedAttribute implements Attribute {
@@ -34,6 +36,14 @@ final class NamespacedAttribute implements Attribute {
3436 private final CelValueConverter celValueConverter ;
3537 private final CelTypeProvider typeProvider ;
3638
39+ ImmutableList <Qualifier > qualifiers () {
40+ return qualifiers ;
41+ }
42+
43+ ImmutableSet <String > candidateVariableNames () {
44+ return namespacedNames ;
45+ }
46+
3747 @ Override
3848 public Object resolve (GlobalResolver ctx , ExecutionFrame frame ) {
3949 GlobalResolver inputVars = ctx ;
@@ -59,41 +69,62 @@ public Object resolve(GlobalResolver ctx, ExecutionFrame frame) {
5969 }
6070 }
6171
62- CelType type = typeProvider .findType (name ).orElse (null );
63- if (type != null ) {
64- if (qualifiers .isEmpty ()) {
65- // Resolution of a fully qualified type name: foo.bar.baz
66- return TypeType .create (type );
67- } else {
68- // This is potentially a fully qualified reference to an enum value
69- if (type instanceof EnumType && qualifiers .size () == 1 ) {
70- EnumType enumType = (EnumType ) type ;
71- String strQualifier = (String ) qualifiers .get (0 ).value ();
72- return enumType
73- .findNumberByName (strQualifier )
74- .orElseThrow (
75- () ->
76- new NoSuchElementException (
77- String .format (
78- "Field %s was not found on enum %s" ,
79- enumType .name (), strQualifier )));
80- }
81- }
82-
83- throw new IllegalStateException (
84- "Unexpected type resolution when there were remaining qualifiers: " + type .name ());
72+ // Attempt to resolve the qualify type name if the name is not a variable identifier
73+ value = findIdent (name );
74+ if (value != null ) {
75+ return value ;
8576 }
8677 }
8778
8879 return MissingAttribute .newMissingAttribute (namespacedNames );
8980 }
9081
91- ImmutableList <Qualifier > qualifiers () {
92- return qualifiers ;
82+ private @ Nullable Object findIdent (String name ) {
83+ CelType type = typeProvider .findType (name ).orElse (null );
84+ // If the name resolves directly, this is a fully qualified type name
85+ // (ex: 'int' or 'google.protobuf.Timestamp')
86+ if (type != null ) {
87+ if (qualifiers .isEmpty ()) {
88+ // Resolution of a fully qualified type name: foo.bar.baz
89+ if (type instanceof TypeType ) {
90+ // Coalesce all type(foo) "type" into a sentinel runtime type to allow for
91+ // erasure based type comparisons
92+ return TypeType .create (SimpleType .DYN );
93+ }
94+
95+ return TypeType .create (type );
96+ }
97+
98+ throw new IllegalStateException (
99+ "Unexpected type resolution when there were remaining qualifiers: " + type .name ());
100+ }
101+
102+ // The name itself could be a fully qualified reference to an enum value
103+ // (e.g: my.enum_type.BAR)
104+ int lastDotIndex = name .lastIndexOf ('.' );
105+ if (lastDotIndex > 0 ) {
106+ String enumTypeName = name .substring (0 , lastDotIndex );
107+ String enumValueQualifier = name .substring (lastDotIndex + 1 );
108+
109+ return typeProvider
110+ .findType (enumTypeName )
111+ .filter (EnumType .class ::isInstance )
112+ .map (EnumType .class ::cast )
113+ .map (enumType -> getEnumValue (enumType , enumValueQualifier ))
114+ .orElse (null );
115+ }
116+
117+ return null ;
93118 }
94119
95- ImmutableSet <String > candidateVariableNames () {
96- return namespacedNames ;
120+ private static Long getEnumValue (EnumType enumType , String field ) {
121+ return enumType
122+ .findNumberByName (field )
123+ .map (Integer ::longValue )
124+ .orElseThrow (
125+ () ->
126+ new NoSuchElementException (
127+ String .format ("Field %s was not found on enum %s" , enumType .name (), field )));
97128 }
98129
99130 private GlobalResolver unwrapToNonLocal (GlobalResolver resolver ) {
0 commit comments