Skip to content

Commit

Permalink
Add string to boolean conversion function in the standard definition
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 657767450
  • Loading branch information
l46kok authored and copybara-github committed Aug 1, 2024
1 parent ea16dc4 commit 2a1fb74
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 2 deletions.
4 changes: 3 additions & 1 deletion checker/src/main/java/dev/cel/checker/Standard.java
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,9 @@ private static ImmutableList<CelFunctionDecl> coreFunctionDeclarations() {
CelFunctionDecl.newFunctionDeclaration(
Function.BOOL.getFunction(),
CelOverloadDecl.newGlobalOverload(
"bool_to_bool", "type conversion (identity)", SimpleType.BOOL, SimpleType.BOOL)));
"bool_to_bool", "type conversion (identity)", SimpleType.BOOL, SimpleType.BOOL),
CelOverloadDecl.newGlobalOverload(
"string_to_bool", "type conversion", SimpleType.BOOL, SimpleType.STRING)));

// String functions
celFunctionDeclBuilder.add(
Expand Down
1 change: 1 addition & 0 deletions checker/src/test/resources/standardEnvDump.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ declare _||_ {
declare bool {
value type(bool)
function bool_to_bool (bool) -> bool
function string_to_bool (string) -> bool
}
declare bytes {
value type(bytes)
Expand Down
27 changes: 27 additions & 0 deletions runtime/src/main/java/dev/cel/runtime/StandardFunctions.java
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,33 @@ public static void addNonInlined(
private static void addBoolFunctions(Registrar registrar) {
// Identity
registrar.add("bool_to_bool", Boolean.class, (Boolean x) -> x);
// Conversion function
registrar.add(
"string_to_bool",
String.class,
(String str) -> {
// Note: this is a bit less permissive than what cel-go allows (it accepts '1', 't').
switch (str) {
case "true":
case "TRUE":
case "True":
case "t":
case "1":
return true;
case "false":
case "FALSE":
case "False":
case "f":
case "0":
return false;
default:
throw new InterpreterException.Builder(
"Type conversion error from 'string' to 'bool': [%s]", str)
.setErrorCode(CelErrorCode.BAD_FORMAT)
.build();
}
});

// The conditional, logical_or, logical_and, and not_strictly_false functions are special-cased.
registrar.add("logical_not", Boolean.class, (Boolean x) -> !x);

Expand Down
24 changes: 23 additions & 1 deletion runtime/src/test/resources/boolConversions.baseline
Original file line number Diff line number Diff line change
@@ -1,4 +1,26 @@
Source: bool(true)
=====>
bindings: {}
result: true
result: true

Source: bool('true') && bool('TRUE') && bool('True') && bool('t') && bool('1')
=====>
bindings: {}
result: true

Source: bool('false') || bool('FALSE') || bool('False') || bool('f') || bool('0')
=====>
bindings: {}
result: false

Source: bool('TrUe')
=====>
bindings: {}
error: evaluation error: Type conversion error from 'string' to 'bool': [TrUe]
error_code: BAD_FORMAT

Source: bool('FaLsE')
=====>
bindings: {}
error: evaluation error: Type conversion error from 'string' to 'bool': [FaLsE]
error_code: BAD_FORMAT
12 changes: 12 additions & 0 deletions testing/src/main/java/dev/cel/testing/BaseInterpreterTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1568,6 +1568,18 @@ public void bytes() throws Exception {
public void boolConversions() throws Exception {
source = "bool(true)";
runTest(Activation.EMPTY); // Identity

source = "bool('true') && bool('TRUE') && bool('True') && bool('t') && bool('1')";
runTest(Activation.EMPTY); // result is true

source = "bool('false') || bool('FALSE') || bool('False') || bool('f') || bool('0')";
runTest(Activation.EMPTY); // result is false

source = "bool('TrUe')";
runTest(Activation.EMPTY); // exception

source = "bool('FaLsE')";
runTest(Activation.EMPTY); // exception
}

@Test
Expand Down

0 comments on commit 2a1fb74

Please sign in to comment.