All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dev.cel.runtime.CallArgumentChecker Maven / Gradle / Ivy

There is a newer version: 0.7.1
Show newest version
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package dev.cel.runtime;

import dev.cel.expr.ExprValue;
import dev.cel.expr.UnknownSet;
import dev.cel.common.annotations.Internal;
import java.util.ArrayList;
import java.util.Optional;

/**
 * Package private utility class for collecting CelUnknownSets from an argument list in a call-like
 * expression.
 *
 * 

Accumulates arguments via {@link #checkArg(DefaultInterpreter.IntermediateResult)}. After all * args are checked, the result is provided by {@link #maybeUnknowns()} * *

CEL Library Internals. Do Not Use. */ @Internal class CallArgumentChecker { private final ArrayList exprIds; private Optional unknowns; private final RuntimeUnknownResolver resolver; private final boolean acceptPartial; private CallArgumentChecker(RuntimeUnknownResolver resolver, boolean acceptPartial) { exprIds = new ArrayList<>(); unknowns = Optional.empty(); this.resolver = resolver; this.acceptPartial = acceptPartial; } /** * Creates a CallArgumentChecker that only permits 'completeData'. * *

Arguments that are determined as partially unknown (have a subfield that is unknown) are * treated as unknown and added to the accumulated UnknownSet. */ static CallArgumentChecker create(RuntimeUnknownResolver resolver) { return new CallArgumentChecker(resolver, false); } /** * Creates a CallArgumentChecker that permits partial data (e.g. container accesses). * *

Arguments that are determined as unknown (match an unknown type) are treated as unknown and * added to the accumulated UnknownSet. */ static CallArgumentChecker createAcceptingPartial(RuntimeUnknownResolver resolver) { return new CallArgumentChecker(resolver, true); } private static Optional mergeOptionalUnknowns( Optional lhs, Optional rhs) { return lhs.isPresent() ? rhs.isPresent() ? Optional.of(lhs.get().merge(rhs.get())) : lhs : rhs; } /** Determine if the call argument is unknown and accumulate if so. */ void checkArg(DefaultInterpreter.IntermediateResult arg) { // Handle attribute tracked unknowns. Optional argUnknowns = maybeUnknownFromArg(arg); unknowns = mergeOptionalUnknowns(unknowns, argUnknowns); // support for ExprValue unknowns. if (InterpreterUtil.isUnknown(arg.value())) { ExprValue exprValue = (ExprValue) arg.value(); exprIds.addAll(exprValue.getUnknown().getExprsList()); } } private Optional maybeUnknownFromArg(DefaultInterpreter.IntermediateResult arg) { if (arg.value() instanceof CelUnknownSet) { return Optional.of((CelUnknownSet) arg.value()); } if (!acceptPartial) { return resolver.maybePartialUnknown(arg.attribute()); } return Optional.empty(); } /** Returns the accumulated unknown if any. */ Optional maybeUnknowns() { if (unknowns.isPresent()) { return Optional.of(unknowns.get()); } if (!exprIds.isEmpty()) { return Optional.of( ExprValue.newBuilder().setUnknown(UnknownSet.newBuilder().addAllExprs(exprIds)).build()); } return Optional.empty(); } }