use of com.google.api.expr.v1alpha1.Expr.Call in project cel-java by projectnessie.
the class Checker method checkSelect.
void checkSelect(Expr.Builder e) {
Select.Builder sel = e.getSelectExprBuilder();
// Before traversing down the tree, try to interpret as qualified name.
String qname = Container.toQualifiedName(e.build());
if (qname != null) {
Decl ident = env.lookupIdent(qname);
if (ident != null) {
if (sel.getTestOnly()) {
errors.expressionDoesNotSelectField(location(e));
setType(e, Decls.Bool);
return;
}
// Rewrite the node to be a variable reference to the resolved fully-qualified
// variable name.
setType(e, ident.getIdent().getType());
setReference(e, newIdentReference(ident.getName(), ident.getIdent().getValue()));
String identName = ident.getName();
e.getIdentExprBuilder().setName(identName);
return;
}
}
// Interpret as field selection, first traversing down the operand.
check(sel.getOperandBuilder());
Type targetType = getType(sel.getOperandBuilder());
// Assume error type by default as most types do not support field selection.
Type resultType = Decls.Error;
switch(kindOf(targetType)) {
case kindMap:
// Maps yield their value type as the selection result type.
MapType mapType = targetType.getMapType();
resultType = mapType.getValueType();
break;
case kindObject:
// Objects yield their field type declaration as the selection result type, but only if
// the field is defined.
FieldType fieldType = lookupFieldType(location(e), targetType.getMessageType(), sel.getField());
if (fieldType != null) {
resultType = fieldType.type;
}
break;
case kindTypeParam:
// Set the operand type to DYN to prevent assignment to a potentionally incorrect type
// at a later point in type-checking. The isAssignable call will update the type
// substitutions for the type param under the covers.
isAssignable(Decls.Dyn, targetType);
// Also, set the result type to DYN.
resultType = Decls.Dyn;
break;
default:
// in order to allow forward progress on the check.
if (isDynOrError(targetType)) {
resultType = Decls.Dyn;
} else {
errors.typeDoesNotSupportFieldSelection(location(e), targetType);
}
break;
}
if (sel.getTestOnly()) {
resultType = Decls.Bool;
}
setType(e, resultType);
}
use of com.google.api.expr.v1alpha1.Expr.Call in project cel-java by projectnessie.
the class Checker method resolveOverload.
OverloadResolution resolveOverload(Location loc, Decl fn, Expr.Builder target, List<Expr.Builder> args) {
List<Type> argTypes = new ArrayList<>();
if (target != null) {
Type argType = getType(target);
if (argType == null) {
throw new ErrException("Could not resolve type for target '%s'", target);
}
argTypes.add(argType);
}
for (int i = 0; i < args.size(); i++) {
Expr.Builder arg = args.get(i);
Type argType = getType(arg);
if (argType == null) {
throw new ErrException("Could not resolve type for argument %d '%s'", i, arg);
}
argTypes.add(argType);
}
Type resultType = null;
Reference checkedRef = null;
for (Overload overload : fn.getFunction().getOverloadsList()) {
if ((target == null && overload.getIsInstanceFunction()) || (target != null && !overload.getIsInstanceFunction())) {
// not a compatible call style.
continue;
}
Type overloadType = Decls.newFunctionType(overload.getResultType(), overload.getParamsList());
if (overload.getTypeParamsCount() > 0) {
// Instantiate overload's type with fresh type variables.
Mapping substitutions = newMapping();
for (String typePar : overload.getTypeParamsList()) {
substitutions.add(Decls.newTypeParamType(typePar), newTypeVar());
}
overloadType = substitute(substitutions, overloadType, false);
}
List<Type> candidateArgTypes = overloadType.getFunction().getArgTypesList();
if (isAssignableList(argTypes, candidateArgTypes)) {
if (checkedRef == null) {
checkedRef = newFunctionReference(Collections.singletonList(overload.getOverloadId()));
} else {
checkedRef = checkedRef.toBuilder().addOverloadId(overload.getOverloadId()).build();
}
// First matching overload, determines result type.
Type fnResultType = substitute(mappings, overloadType.getFunction().getResultType(), false);
if (resultType == null) {
resultType = fnResultType;
} else if (!isDyn(resultType) && !fnResultType.equals(resultType)) {
resultType = Decls.Dyn;
}
}
}
if (resultType == null) {
errors.noMatchingOverload(loc, fn.getName(), argTypes, target != null);
// resultType = Decls.Error;
return null;
}
return newResolution(checkedRef, resultType);
}
use of com.google.api.expr.v1alpha1.Expr.Call in project cel-java by projectnessie.
the class Checker method checkComprehension.
void checkComprehension(Expr.Builder e) {
Comprehension.Builder comp = e.getComprehensionExprBuilder();
check(comp.getIterRangeBuilder());
check(comp.getAccuInitBuilder());
Type accuType = getType(comp.getAccuInitBuilder());
Type rangeType = getType(comp.getIterRangeBuilder());
Type varType;
switch(kindOf(rangeType)) {
case kindList:
varType = rangeType.getListType().getElemType();
break;
case kindMap:
// Ranges over the keys.
varType = rangeType.getMapType().getKeyType();
break;
case kindDyn:
case kindError:
case kindTypeParam:
// Set the range type to DYN to prevent assignment to a potentionally incorrect type
// at a later point in type-checking. The isAssignable call will update the type
// substitutions for the type param under the covers.
isAssignable(Decls.Dyn, rangeType);
// Set the range iteration variable to type DYN as well.
varType = Decls.Dyn;
break;
default:
errors.notAComprehensionRange(location(comp.getIterRangeBuilder()), rangeType);
varType = Decls.Error;
break;
}
// Create a scope for the comprehension since it has a local accumulation variable.
// This scope will contain the accumulation variable used to compute the result.
env = env.enterScope();
env.add(Decls.newVar(comp.getAccuVar(), accuType));
// Create a block scope for the loop.
env = env.enterScope();
env.add(Decls.newVar(comp.getIterVar(), varType));
// Check the variable references in the condition and step.
check(comp.getLoopConditionBuilder());
assertType(comp.getLoopConditionBuilder(), Decls.Bool);
check(comp.getLoopStepBuilder());
assertType(comp.getLoopStepBuilder(), accuType);
// Exit the loop's block scope before checking the result.
env = env.exitScope();
check(comp.getResultBuilder());
// Exit the comprehension scope.
env = env.exitScope();
setType(e, getType(comp.getResultBuilder()));
}
use of com.google.api.expr.v1alpha1.Expr.Call in project cel-java by projectnessie.
the class Types method internalIsAssignable.
/**
* internalIsAssignable returns true if t1 is assignable to t2.
*/
static boolean internalIsAssignable(Mapping m, Type t1, Type t2) {
// Early terminate the call to avoid cases of infinite recursion.
if (t1.equals(t2)) {
return true;
}
// Process type parameters.
Kind kind1 = kindOf(t1);
Kind kind2 = kindOf(t2);
if (kind2 == Kind.kindTypeParam) {
Type t2Sub = m.find(t2);
if (t2Sub != null) {
// If the types are compatible, pick the more general type and return true
if (internalIsAssignable(m, t1, t2Sub)) {
m.add(t2, mostGeneral(t1, t2Sub));
return true;
}
return false;
}
if (notReferencedIn(m, t2, t1)) {
m.add(t2, t1);
return true;
}
}
if (kind1 == Kind.kindTypeParam) {
// For the lower type bound, we currently do not perform adjustment. The restricted
// way we use type parameters in lower type bounds, it is not necessary, but may
// become if we generalize type unification.
Type t1Sub = m.find(t1);
if (t1Sub != null) {
// If the types are compatible, pick the more general type and return true
if (internalIsAssignable(m, t1Sub, t2)) {
m.add(t1, mostGeneral(t1Sub, t2));
return true;
}
return false;
}
if (notReferencedIn(m, t1, t2)) {
m.add(t1, t2);
return true;
}
}
// Next check for wildcard types.
if (isDynOrError(t1) || isDynOrError(t2)) {
return true;
}
// Test for when the types do not need to agree, but are more specific than dyn.
switch(kind1) {
case kindNull:
return internalIsAssignableNull(t2);
case kindPrimitive:
return internalIsAssignablePrimitive(t1.getPrimitive(), t2);
case kindWrapper:
return internalIsAssignable(m, Decls.newPrimitiveType(t1.getWrapper()), t2);
default:
if (kind1 != kind2) {
return false;
}
}
// Test for when the types must agree.
switch(kind1) {
// ERROR, TYPE_PARAM, and DYN handled above.
case kindAbstract:
return internalIsAssignableAbstractType(m, t1.getAbstractType(), t2.getAbstractType());
case kindFunction:
return internalIsAssignableFunction(m, t1.getFunction(), t2.getFunction());
case kindList:
return internalIsAssignable(m, t1.getListType().getElemType(), t2.getListType().getElemType());
case kindMap:
return internalIsAssignableMap(m, t1.getMapType(), t2.getMapType());
case kindObject:
return t1.getMessageType().equals(t2.getMessageType());
case kindType:
// type cannot affect method resolution or assignability.
return true;
case kindWellKnown:
return t1.getWellKnown() == t2.getWellKnown();
default:
return false;
}
}
use of com.google.api.expr.v1alpha1.Expr.Call in project cel-java by projectnessie.
the class ConformanceServerTest method Parse.
/**
* TestParse tests the Parse method.
*/
@Test
void Parse() {
ParseRequest req = ParseRequest.newBuilder().setCelSource("1 + 1").build();
ParseResponse res = stub.parse(req);
assertThat(res.isInitialized()).isTrue();
assertThat(res.getParsedExpr().isInitialized()).isTrue();
// Could check against 'parsed' above,
// but the expression ids are arbitrary,
// and explicit comparison logic is about as
// much work as normalization would be.
assertThat(res.getParsedExpr().getExpr().isInitialized()).isTrue();
assertThat(res.getParsedExpr().getExpr().getExprKindCase()).isSameAs(ExprKindCase.CALL_EXPR);
Call c = res.getParsedExpr().getExpr().getCallExpr();
assertThat(c.getTarget().isInitialized()).isTrue();
assertThat(c.getFunction()).isEqualTo("_+_");
assertThat(c.getArgsCount()).isEqualTo(2);
for (Expr a : c.getArgsList()) {
assertThat(a.getExprKindCase()).isSameAs(ExprKindCase.CONST_EXPR);
Constant l = a.getConstExpr();
assertThat(l.getConstantKindCase()).isSameAs(ConstantKindCase.INT64_VALUE);
assertThat(l.getInt64Value()).isEqualTo(1);
}
}
Aggregations