Skip to content

Commit

Permalink
Include identity functions in the standard definitions
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 657756541
  • Loading branch information
l46kok authored and copybara-github committed Jul 31, 2024
1 parent f78c6c4 commit a5dea4b
Show file tree
Hide file tree
Showing 11 changed files with 147 additions and 1 deletion.
4 changes: 4 additions & 0 deletions checker/src/main/java/dev/cel/checker/Env.java
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,10 @@ boolean enableTimestampEpoch() {
return celOptions.enableTimestampEpoch();
}

boolean enableUnsignedLongs() {
return celOptions.enableUnsignedLongs();
}

/** Add an identifier {@code decl} to the environment. */
@CanIgnoreReturnValue
private Env addIdent(CelIdentDecl celIdentDecl) {
Expand Down
41 changes: 40 additions & 1 deletion checker/src/main/java/dev/cel/checker/Standard.java
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,14 @@ public static Env add(Env env) {
timestampConversionDeclarations(env.enableTimestampEpoch()).forEach(env::add);
numericComparisonDeclarations(env.enableHeterogeneousNumericComparisons()).forEach(env::add);

if (env.enableUnsignedLongs()) {
env.add(
CelFunctionDecl.newFunctionDeclaration(
Function.INT.getFunction(),
CelOverloadDecl.newGlobalOverload(
"int64_to_int64", "type conversion (identity)", SimpleType.INT, SimpleType.INT)));
}

return env;
}

Expand Down Expand Up @@ -384,6 +392,8 @@ private static ImmutableList<CelFunctionDecl> coreFunctionDeclarations() {
celFunctionDeclBuilder.add(
CelFunctionDecl.newFunctionDeclaration(
Function.UINT.getFunction(),
CelOverloadDecl.newGlobalOverload(
"uint64_to_uint64", "type conversion (identity)", SimpleType.UINT, SimpleType.UINT),
CelOverloadDecl.newGlobalOverload(
"int64_to_uint64", "type conversion", SimpleType.UINT, SimpleType.INT),
CelOverloadDecl.newGlobalOverload(
Expand All @@ -395,6 +405,11 @@ private static ImmutableList<CelFunctionDecl> coreFunctionDeclarations() {
celFunctionDeclBuilder.add(
CelFunctionDecl.newFunctionDeclaration(
Function.DOUBLE.getFunction(),
CelOverloadDecl.newGlobalOverload(
"double_to_double",
"type conversion (identity)",
SimpleType.DOUBLE,
SimpleType.DOUBLE),
CelOverloadDecl.newGlobalOverload(
"int64_to_double", "type conversion", SimpleType.DOUBLE, SimpleType.INT),
CelOverloadDecl.newGlobalOverload(
Expand All @@ -406,6 +421,11 @@ private static ImmutableList<CelFunctionDecl> coreFunctionDeclarations() {
celFunctionDeclBuilder.add(
CelFunctionDecl.newFunctionDeclaration(
Function.STRING.getFunction(),
CelOverloadDecl.newGlobalOverload(
"string_to_string",
"type conversion (identity)",
SimpleType.STRING,
SimpleType.STRING),
CelOverloadDecl.newGlobalOverload(
"int64_to_string", "type conversion", SimpleType.STRING, SimpleType.INT),
CelOverloadDecl.newGlobalOverload(
Expand Down Expand Up @@ -442,6 +462,8 @@ private static ImmutableList<CelFunctionDecl> coreFunctionDeclarations() {
celFunctionDeclBuilder.add(
CelFunctionDecl.newFunctionDeclaration(
Function.BYTES.getFunction(),
CelOverloadDecl.newGlobalOverload(
"bytes_to_bytes", "type conversion (identity)", SimpleType.BYTES, SimpleType.BYTES),
CelOverloadDecl.newGlobalOverload(
"string_to_bytes", "type conversion", SimpleType.BYTES, SimpleType.STRING)));

Expand All @@ -456,12 +478,24 @@ private static ImmutableList<CelFunctionDecl> coreFunctionDeclarations() {
celFunctionDeclBuilder.add(
CelFunctionDecl.newFunctionDeclaration(
Function.DURATION.getFunction(),
CelOverloadDecl.newGlobalOverload(
"duration_to_duration",
"type conversion (identity)",
SimpleType.DURATION,
SimpleType.DURATION),
CelOverloadDecl.newGlobalOverload(
"string_to_duration",
"type conversion, duration should be end with \"s\", which stands for seconds",
SimpleType.DURATION,
SimpleType.STRING)));

// Conversions to boolean
celFunctionDeclBuilder.add(
CelFunctionDecl.newFunctionDeclaration(
Function.BOOL.getFunction(),
CelOverloadDecl.newGlobalOverload(
"bool_to_bool", "type conversion (identity)", SimpleType.BOOL, SimpleType.BOOL)));

// String functions
celFunctionDeclBuilder.add(
CelFunctionDecl.newFunctionDeclaration(
Expand Down Expand Up @@ -693,7 +727,12 @@ private static ImmutableList<CelFunctionDecl> timestampConversionDeclarations(bo
"Type conversion of strings to timestamps according to RFC3339. Example:"
+ " \"1972-01-01T10:00:20.021-05:00\".",
SimpleType.TIMESTAMP,
SimpleType.STRING));
SimpleType.STRING),
CelOverloadDecl.newGlobalOverload(
"timestamp_to_timestamp",
"type conversion (identity)",
SimpleType.TIMESTAMP,
SimpleType.TIMESTAMP));
if (withEpoch) {
timestampBuilder.addOverloads(
CelOverloadDecl.newGlobalOverload(
Expand Down
8 changes: 8 additions & 0 deletions checker/src/test/resources/standardEnvDump.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -143,21 +143,25 @@ declare _||_ {
}
declare bool {
value type(bool)
function bool_to_bool (bool) -> bool
}
declare bytes {
value type(bytes)
function bytes_to_bytes (bytes) -> bytes
function string_to_bytes (string) -> bytes
}
declare contains {
function contains_string string.(string) -> bool
}
declare double {
value type(double)
function double_to_double (double) -> double
function int64_to_double (int) -> double
function uint64_to_double (uint) -> double
function string_to_double (string) -> double
}
declare duration {
function duration_to_duration (google.protobuf.Duration) -> google.protobuf.Duration
function string_to_duration (string) -> google.protobuf.Duration
}
declare dyn {
Expand Down Expand Up @@ -217,6 +221,7 @@ declare int {
function double_to_int64 (double) -> int
function string_to_int64 (string) -> int
function timestamp_to_int64 (google.protobuf.Timestamp) -> int
function int64_to_int64 (int) -> int
}
declare list {
value type(list(dyn))
Expand Down Expand Up @@ -248,6 +253,7 @@ declare startsWith {
}
declare string {
value type(string)
function string_to_string (string) -> string
function int64_to_string (int) -> string
function uint64_to_string (uint) -> string
function double_to_string (double) -> string
Expand All @@ -257,6 +263,7 @@ declare string {
}
declare timestamp {
function string_to_timestamp (string) -> google.protobuf.Timestamp
function timestamp_to_timestamp (google.protobuf.Timestamp) -> google.protobuf.Timestamp
function int64_to_timestamp (int) -> google.protobuf.Timestamp
}
declare type {
Expand All @@ -265,6 +272,7 @@ declare type {
}
declare uint {
value type(uint)
function uint64_to_uint64 (uint) -> uint
function int64_to_uint64 (int) -> uint
function double_to_uint64 (double) -> uint
function string_to_uint64 (string) -> uint
Expand Down
22 changes: 22 additions & 0 deletions runtime/src/main/java/dev/cel/runtime/StandardFunctions.java
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ public static void addNonInlined(
}

private static void addBoolFunctions(Registrar registrar) {
// Identity
registrar.add("bool_to_bool", Boolean.class, (Boolean x) -> x);
// The conditional, logical_or, logical_and, and not_strictly_false functions are special-cased.
registrar.add("logical_not", Boolean.class, (Boolean x) -> !x);

Expand All @@ -167,6 +169,8 @@ private static void addBoolFunctions(Registrar registrar) {
}

private static void addBytesFunctions(Registrar registrar) {
// Identity
registrar.add("bytes_to_bytes", ByteString.class, (ByteString x) -> x);
// Bytes ordering functions: <, <=, >=, >
registrar.add(
"less_bytes",
Expand Down Expand Up @@ -205,6 +209,8 @@ private static void addBytesFunctions(Registrar registrar) {
}

private static void addDoubleFunctions(Registrar registrar, CelOptions celOptions) {
// Identity
registrar.add("double_to_double", Double.class, (Double x) -> x);
// Double ordering functions.
registrar.add("less_double", Double.class, Double.class, (Double x, Double y) -> x < y);
registrar.add("less_equals_double", Double.class, Double.class, (Double x, Double y) -> x <= y);
Expand Down Expand Up @@ -245,6 +251,8 @@ private static void addDoubleFunctions(Registrar registrar, CelOptions celOption
}

private static void addDurationFunctions(Registrar registrar) {
// Identity
registrar.add("duration_to_duration", Duration.class, (Duration x) -> x);
// Duration ordering functions: <, <=, >=, >
registrar.add(
"less_duration",
Expand Down Expand Up @@ -307,6 +315,12 @@ private static void addDurationFunctions(Registrar registrar) {
}

private static void addIntFunctions(Registrar registrar, CelOptions celOptions) {
// Identity
if (celOptions.enableUnsignedLongs()) {
// Note that we require UnsignedLong flag here to avoid ambiguous overloads against
// "uint64_to_int64", because they both use the same Java Long class.
registrar.add("int64_to_int64", Long.class, (Long x) -> x);
}
// Comparison functions.
registrar.add("less_int64", Long.class, Long.class, (Long x, Long y) -> x < y);
registrar.add("less_equals_int64", Long.class, Long.class, (Long x, Long y) -> x <= y);
Expand Down Expand Up @@ -499,6 +513,8 @@ private static void addMapFunctions(
}

private static void addStringFunctions(Registrar registrar, CelOptions celOptions) {
// Identity
registrar.add("string_to_string", String.class, (String x) -> x);
// String ordering functions: <, <=, >=, >.
registrar.add(
"less_string", String.class, String.class, (String x, String y) -> x.compareTo(y) < 0);
Expand Down Expand Up @@ -547,6 +563,8 @@ private static void addStringFunctions(Registrar registrar, CelOptions celOption
// timestamp_to_milliseconds overload
@SuppressWarnings("JavaLocalDateTimeGetNano")
private static void addTimestampFunctions(Registrar registrar) {
// Identity
registrar.add("timestamp_to_timestamp", Timestamp.class, (Timestamp x) -> x);
// Timestamp relation operators: <, <=, >=, >
registrar.add(
"less_timestamp",
Expand Down Expand Up @@ -714,6 +732,8 @@ private static void addTimestampFunctions(Registrar registrar) {
}

private static void addSignedUintFunctions(Registrar registrar, CelOptions celOptions) {
// Identity
registrar.add("uint64_to_uint64", Long.class, (Long x) -> x);
// Uint relation operators: <, <=, >=, >
registrar.add(
"less_uint64",
Expand Down Expand Up @@ -833,6 +853,8 @@ private static void addSignedUintFunctions(Registrar registrar, CelOptions celOp
}

private static void addUintFunctions(Registrar registrar, CelOptions celOptions) {
// Identity
registrar.add("uint64_to_uint64", UnsignedLong.class, (UnsignedLong x) -> x);
registrar.add(
"less_uint64",
UnsignedLong.class,
Expand Down
4 changes: 4 additions & 0 deletions runtime/src/test/resources/boolConversions.baseline
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Source: bool(true)
=====>
bindings: {}
result: true
5 changes: 5 additions & 0 deletions runtime/src/test/resources/bytesConversions.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,8 @@ Source: bytes('abc\303')
=====>
bindings: {}
result: abcÃ

Source: bytes(bytes('abc\303'))
=====>
bindings: {}
result: abcÃ
5 changes: 5 additions & 0 deletions runtime/src/test/resources/doubleConversions.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,8 @@ Source: double('bad')
bindings: {}
error: evaluation error: For input string: "bad"
error_code: BAD_FORMAT

Source: double(1.5)
=====>
bindings: {}
result: 1.5
5 changes: 5 additions & 0 deletions runtime/src/test/resources/stringConversions.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,8 @@ Source: string(duration('1000000s'))
=====>
bindings: {}
result: 1000000s

Source: string('hello')
=====>
bindings: {}
result: hello
17 changes: 17 additions & 0 deletions runtime/src/test/resources/timeConversions.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,20 @@ declare t1 {
bindings: {}
error: evaluation error: invalid duration format
error_code: BAD_FORMAT

Source: duration(duration('15.0s'))
declare t1 {
value google.protobuf.Timestamp
}
=====>
bindings: {}
result: seconds: 15


Source: timestamp(timestamp(123))
declare t1 {
value google.protobuf.Timestamp
}
=====>
bindings: {}
result: seconds: 123
10 changes: 10 additions & 0 deletions runtime/src/test/resources/uint64Conversions.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,13 @@ Source: uint('f1')
bindings: {}
error: evaluation error: f1
error_code: BAD_FORMAT

Source: uint(1u)
=====>
bindings: {}
result: 1

Source: uint(dyn(1u))
=====>
bindings: {}
result: 1
27 changes: 27 additions & 0 deletions testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1261,6 +1261,12 @@ public void timeConversions() throws Exception {
// Not supported.
source = "duration('inf')";
runTest(Activation.EMPTY);

source = "duration(duration('15.0s'))"; // Identity
runTest(Activation.EMPTY);

source = "timestamp(timestamp(123))"; // Identity
runTest(Activation.EMPTY);
}

@Test
Expand Down Expand Up @@ -1491,6 +1497,12 @@ public void uint64Conversions() throws Exception {

source = "uint('f1')"; // should error
runTest(Activation.EMPTY);

source = "uint(1u)"; // identity
runTest(Activation.EMPTY);

source = "uint(dyn(1u))"; // identity, check dynamic dispatch
runTest(Activation.EMPTY);
}

@Test
Expand All @@ -1506,6 +1518,9 @@ public void doubleConversions() throws Exception {

source = "double('bad')";
runTest(Activation.EMPTY);

source = "double(1.5)"; // Identity
runTest(Activation.EMPTY);
}

@Test
Expand Down Expand Up @@ -1536,6 +1551,9 @@ public void stringConversions() throws Exception {

source = "string(duration('1000000s'))";
runTest(Activation.EMPTY);

source = "string('hello')"; // Identity
runTest(Activation.EMPTY);
}

@Test
Expand All @@ -1546,10 +1564,19 @@ public void bytes() throws Exception {
runTest(Activation.EMPTY);
}

@Test
public void boolConversions() throws Exception {
source = "bool(true)";
runTest(Activation.EMPTY); // Identity
}

@Test
public void bytesConversions() throws Exception {
source = "bytes('abc\\303')";
runTest(Activation.EMPTY); // string converts to abcà in bytes form.

source = "bytes(bytes('abc\\303'))"; // Identity
runTest(Activation.EMPTY);
}

@Test
Expand Down

0 comments on commit a5dea4b

Please sign in to comment.