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
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,8 @@ public final class CelInvalidArgumentException extends CelRuntimeException {
public CelInvalidArgumentException(Throwable cause) {
super(cause, CelErrorCode.INVALID_ARGUMENT);
}

public CelInvalidArgumentException(String message) {
super(message, CelErrorCode.INVALID_ARGUMENT);
}
}
57 changes: 46 additions & 11 deletions common/src/main/java/dev/cel/common/values/CelValueConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,24 +41,39 @@ public static CelValueConverter getDefaultInstance() {
return DEFAULT_INSTANCE;
}

/** Adapts a {@link CelValue} to a plain old Java Object. */
public Object unwrap(CelValue celValue) {
Preconditions.checkNotNull(celValue);
/**
* Unwraps the {@code value} into its plain old Java Object representation.
*
* <p>The value may be a {@link CelValue}, a {@link Collection} or a {@link Map}.
*/
public Object maybeUnwrap(Object value) {
if (value instanceof CelValue) {
return unwrap((CelValue) value);
}

if (celValue instanceof OptionalValue) {
OptionalValue<Object, Object> optionalValue = (OptionalValue<Object, Object>) celValue;
if (optionalValue.isZeroValue()) {
return Optional.empty();
if (value instanceof Collection) {
Collection<Object> collection = (Collection<Object>) value;
ImmutableList.Builder<Object> builder =
ImmutableList.builderWithExpectedSize(collection.size());
for (Object element : collection) {
builder.add(maybeUnwrap(element));
}

return Optional.of(optionalValue.value());
return builder.build();
}

if (celValue instanceof ErrorValue) {
return celValue;
if (value instanceof Map) {
Map<Object, Object> map = (Map<Object, Object>) value;
ImmutableMap.Builder<Object, Object> builder =
ImmutableMap.builderWithExpectedSize(map.size());
for (Map.Entry<Object, Object> entry : map.entrySet()) {
builder.put(maybeUnwrap(entry.getKey()), maybeUnwrap(entry.getValue()));
}

return builder.buildOrThrow();
}

return celValue.value();
return value;
}

/**
Expand Down Expand Up @@ -101,6 +116,26 @@ protected Object normalizePrimitive(Object value) {
return value;
}

/** Adapts a {@link CelValue} to a plain old Java Object. */
private static Object unwrap(CelValue celValue) {
Preconditions.checkNotNull(celValue);

if (celValue instanceof OptionalValue) {
OptionalValue<Object, Object> optionalValue = (OptionalValue<Object, Object>) celValue;
if (optionalValue.isZeroValue()) {
return Optional.empty();
}

return Optional.of(optionalValue.value());
}

if (celValue instanceof ErrorValue) {
return celValue;
}

return celValue.value();
}

private ImmutableList<Object> toListValue(Collection<Object> iterable) {
Preconditions.checkNotNull(iterable);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,16 @@ public void toRuntimeValue_optionalValue() {
@Test
@SuppressWarnings("unchecked") // Test only
public void unwrap_optionalValue() {
Optional<Long> result = (Optional<Long>) CEL_VALUE_CONVERTER.unwrap(OptionalValue.create(2L));
Optional<Long> result =
(Optional<Long>) CEL_VALUE_CONVERTER.maybeUnwrap(OptionalValue.create(2L));

assertThat(result).isEqualTo(Optional.of(2L));
}

@Test
@SuppressWarnings("unchecked") // Test only
public void unwrap_emptyOptionalValue() {
Optional<Long> result = (Optional<Long>) CEL_VALUE_CONVERTER.unwrap(OptionalValue.EMPTY);
Optional<Long> result = (Optional<Long>) CEL_VALUE_CONVERTER.maybeUnwrap(OptionalValue.EMPTY);

assertThat(result).isEqualTo(Optional.empty());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class ProtoCelValueConverterTest {

@Test
public void unwrap_nullValue() {
NullValue nullValue = (NullValue) PROTO_CEL_VALUE_CONVERTER.unwrap(NullValue.NULL_VALUE);
NullValue nullValue = (NullValue) PROTO_CEL_VALUE_CONVERTER.maybeUnwrap(NullValue.NULL_VALUE);

// Note: No conversion is attempted. We're using dev.cel.common.values.NullValue.NULL_VALUE as
// the
Expand Down
11 changes: 0 additions & 11 deletions conformance/src/test/java/dev/cel/conformance/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -175,18 +175,7 @@ _TESTS_TO_SKIP_PLANNER = [
"timestamps/timestamp_range/sub_time_duration_under",

# Skip until fixed.
"fields/qualified_identifier_resolution/map_key_float",
"fields/qualified_identifier_resolution/map_key_null",
"fields/qualified_identifier_resolution/map_value_repeat_key_heterogeneous",
"optionals/optionals/map_null_entry_no_such_key",
"optionals/optionals/map_present_key_invalid_field",
"parse/receiver_function_names",
"proto2/extensions_get/package_scoped_test_all_types_ext",
"proto2/extensions_get/package_scoped_repeated_test_all_types",
"proto2/extensions_get/message_scoped_nested_ext",
"proto2/extensions_get/message_scoped_repeated_test_all_types",
"proto2_ext/get_ext/package_scoped_repeated_test_all_types",
"proto2_ext/get_ext/message_scoped_repeated_test_all_types",

# TODO: Fix null assignment to a field
"proto2/set_null/single_message",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import dev.cel.runtime.CelFunctionBinding;
import dev.cel.runtime.CelRuntime;
import dev.cel.runtime.CelRuntimeFactory;
import dev.cel.runtime.CelRuntimeImpl;
import org.junit.Test;
import org.junit.runner.RunWith;

Expand All @@ -60,9 +61,14 @@ public final class CelProtoExtensionsTest {
.addVar("msg", StructTypeReference.create("cel.expr.conformance.proto2.TestAllTypes"))
.setContainer(CelContainer.ofName("cel.expr.conformance.proto2"))
.build();

private static final CelRuntime CEL_RUNTIME =
CelRuntimeFactory.standardCelRuntimeBuilder()
CelRuntimeImpl.newBuilder()
.setOptions(
CelOptions.current()
.enableTimestampEpoch(true)
.enableHeterogeneousNumericComparisons(true)
.build())
// CEL-Internal-2
.addFileTypes(TestAllTypesExtensions.getDescriptor())
.build();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import dev.cel.common.exceptions.CelAttributeNotFoundException;
import dev.cel.common.values.BaseProtoCelValueConverter;
import dev.cel.common.values.BaseProtoMessageValueProvider;
import dev.cel.common.values.CelValue;
import dev.cel.common.values.CelValueProvider;
import dev.cel.common.values.CombinedCelValueProvider;
import dev.cel.common.values.SelectableValue;
Expand Down Expand Up @@ -64,7 +63,7 @@ static CelValueRuntimeTypeProvider newInstance(CelValueProvider valueProvider) {

@Override
public Object createMessage(String messageName, Map<String, Object> values) {
return maybeUnwrapCelValue(
return protoCelValueConverter.maybeUnwrap(
valueProvider
.newValue(messageName, values)
.orElseThrow(
Expand All @@ -87,7 +86,7 @@ public Object selectField(Object message, String fieldName) {
SelectableValue<String> selectableValue = getSelectableValueOrThrow(message, fieldName);
Object value = selectableValue.select(fieldName);

return maybeUnwrapCelValue(value);
return protoCelValueConverter.maybeUnwrap(value);
}

@Override
Expand Down Expand Up @@ -120,24 +119,12 @@ public Object adapt(String messageName, Object message) {
}

if (message instanceof MessageLite) {
return maybeUnwrapCelValue(protoCelValueConverter.toRuntimeValue(message));
return protoCelValueConverter.maybeUnwrap(protoCelValueConverter.toRuntimeValue(message));
}

return message;
}

/**
* DefaultInterpreter cannot handle CelValue and instead expects plain Java objects.
*
* <p>This will become unnecessary once we introduce a rewrite of a Cel runtime.
*/
private Object maybeUnwrapCelValue(Object object) {
if (object instanceof CelValue) {
return protoCelValueConverter.unwrap((CelValue) object);
}
return object;
}

private static void throwInvalidFieldSelection(String fieldName) {
throw CelAttributeNotFoundException.forFieldResolution(fieldName);
}
Expand Down
3 changes: 1 addition & 2 deletions runtime/src/main/java/dev/cel/runtime/planner/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,6 @@ java_library(
"//common/types",
"//common/types:type_providers",
"//common/values",
"//common/values:cel_value",
"//runtime:interpretable",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_guava_guava",
Expand Down Expand Up @@ -334,6 +333,7 @@ java_library(
":localized_evaluation_exception",
":planned_interpretable",
"//common/exceptions:duplicate_key",
"//common/exceptions:invalid_argument",
"//runtime:evaluation_exception",
"//runtime:interpretable",
"@maven//:com_google_errorprone_error_prone_annotations",
Expand Down Expand Up @@ -379,7 +379,6 @@ java_library(
"//common:error_codes",
"//common/exceptions:runtime_exception",
"//common/values",
"//common/values:cel_value",
"//runtime:evaluation_exception",
"//runtime:interpretable",
"//runtime:resolved_overload",
Expand Down
34 changes: 30 additions & 4 deletions runtime/src/main/java/dev/cel/runtime/planner/EvalCreateMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import com.google.common.primitives.UnsignedLong;
import com.google.errorprone.annotations.Immutable;
import dev.cel.common.exceptions.CelDuplicateKeyException;
import dev.cel.common.exceptions.CelInvalidArgumentException;
import dev.cel.runtime.CelEvaluationException;
import dev.cel.runtime.GlobalResolver;
import java.util.HashSet;
Expand Down Expand Up @@ -46,13 +48,37 @@ public Object eval(GlobalResolver resolver, ExecutionFrame frame) throws CelEval
HashSet<Object> keysSeen = Sets.newHashSetWithExpectedSize(keys.length);

for (int i = 0; i < keys.length; i++) {
Object key = keys[i].eval(resolver, frame);
Object val = values[i].eval(resolver, frame);
PlannedInterpretable keyInterpretable = keys[i];
Object key = keyInterpretable.eval(resolver, frame);
if (!(key instanceof String
|| key instanceof Long
|| key instanceof UnsignedLong
|| key instanceof Boolean)) {
throw new LocalizedEvaluationException(
new CelInvalidArgumentException("Unsupported key type: " + key),
keyInterpretable.exprId());
}

if (!keysSeen.add(key)) {
throw new LocalizedEvaluationException(CelDuplicateKeyException.of(key), keys[i].exprId());
boolean isDuplicate = !keysSeen.add(key);
if (!isDuplicate) {
if (key instanceof Long) {
long longVal = (Long) key;
if (longVal >= 0) {
isDuplicate = keysSeen.contains(UnsignedLong.valueOf(longVal));
}
} else if (key instanceof UnsignedLong) {
UnsignedLong ulongVal = (UnsignedLong) key;
isDuplicate = keysSeen.contains(ulongVal.longValue());
}
}

if (isDuplicate) {
throw new LocalizedEvaluationException(
CelDuplicateKeyException.of(key), keyInterpretable.exprId());
}

Object val = values[i].eval(resolver, frame);

if (isOptional[i]) {
if (!(val instanceof Optional)) {
throw new IllegalArgumentException(
Expand Down
19 changes: 8 additions & 11 deletions runtime/src/main/java/dev/cel/runtime/planner/EvalHelpers.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import com.google.common.base.Joiner;
import dev.cel.common.CelErrorCode;
import dev.cel.common.exceptions.CelRuntimeException;
import dev.cel.common.values.CelValue;
import dev.cel.common.values.CelValueConverter;
import dev.cel.common.values.ErrorValue;
import dev.cel.runtime.CelEvaluationException;
Expand Down Expand Up @@ -56,23 +55,21 @@ static Object evalStrictly(
}
}

static Object dispatch(CelResolvedOverload overload, CelValueConverter valueConverter, Object[] args) throws CelEvaluationException {
static Object dispatch(
CelResolvedOverload overload, CelValueConverter valueConverter, Object[] args)
throws CelEvaluationException {
try {
Object result = overload.getDefinition().apply(args);
Object runtimeValue = valueConverter.toRuntimeValue(result);
if (runtimeValue instanceof CelValue) {
return valueConverter.unwrap((CelValue) runtimeValue);
}

return runtimeValue;
return valueConverter.maybeUnwrap(valueConverter.toRuntimeValue(result));
} catch (CelRuntimeException e) {
// Function dispatch failure that's already been handled -- just propagate.
throw e;
} catch (RuntimeException e) {
// Unexpected function dispatch failure.
throw new IllegalArgumentException(String.format(
"Function '%s' failed with arg(s) '%s'",
overload.getOverloadId(), Joiner.on(", ").join(args)),
throw new IllegalArgumentException(
String.format(
"Function '%s' failed with arg(s) '%s'",
overload.getOverloadId(), Joiner.on(", ").join(args)),
e);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import dev.cel.common.types.EnumType;
import dev.cel.common.types.SimpleType;
import dev.cel.common.types.TypeType;
import dev.cel.common.values.CelValue;
import dev.cel.common.values.CelValueConverter;
import dev.cel.runtime.GlobalResolver;
import java.util.NoSuchElementException;
Expand Down Expand Up @@ -148,11 +147,7 @@ private static Object applyQualifiers(
obj = qualifier.qualify(obj);
}

if (obj instanceof CelValue) {
obj = celValueConverter.unwrap((CelValue) obj);
}

return obj;
return celValueConverter.maybeUnwrap(obj);
}

static NamespacedAttribute create(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.Immutable;
import dev.cel.common.values.CelValue;
import dev.cel.common.values.CelValueConverter;
import dev.cel.runtime.GlobalResolver;

Expand All @@ -41,10 +40,7 @@ public Object resolve(GlobalResolver ctx, ExecutionFrame frame) {
}

// TODO: Handle unknowns
if (obj instanceof CelValue) {
obj = celValueConverter.unwrap((CelValue) obj);
}
return obj;
return celValueConverter.maybeUnwrap(obj);
}

@Override
Expand Down
Loading
Loading