Search in sources :

Example 6 with Call

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);
}
Also used : CheckerEnv.getObjectWellKnownType(org.projectnessie.cel.checker.CheckerEnv.getObjectWellKnownType) CheckerEnv.isObjectWellKnownType(org.projectnessie.cel.checker.CheckerEnv.isObjectWellKnownType) CheckerEnv.dynElementType(org.projectnessie.cel.checker.CheckerEnv.dynElementType) Type(com.google.api.expr.v1alpha1.Type) MapType(com.google.api.expr.v1alpha1.Type.MapType) FieldType(org.projectnessie.cel.common.types.ref.FieldType) Select(com.google.api.expr.v1alpha1.Expr.Select) IdentDecl(com.google.api.expr.v1alpha1.Decl.IdentDecl) Decl(com.google.api.expr.v1alpha1.Decl) MapType(com.google.api.expr.v1alpha1.Type.MapType) FieldType(org.projectnessie.cel.common.types.ref.FieldType)

Example 7 with Call

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);
}
Also used : CheckerEnv.getObjectWellKnownType(org.projectnessie.cel.checker.CheckerEnv.getObjectWellKnownType) CheckerEnv.isObjectWellKnownType(org.projectnessie.cel.checker.CheckerEnv.isObjectWellKnownType) CheckerEnv.dynElementType(org.projectnessie.cel.checker.CheckerEnv.dynElementType) Type(com.google.api.expr.v1alpha1.Type) MapType(com.google.api.expr.v1alpha1.Type.MapType) FieldType(org.projectnessie.cel.common.types.ref.FieldType) Expr(com.google.api.expr.v1alpha1.Expr) CheckedExpr(com.google.api.expr.v1alpha1.CheckedExpr) Overload(com.google.api.expr.v1alpha1.Decl.FunctionDecl.Overload) ErrException(org.projectnessie.cel.common.types.Err.ErrException) Reference(com.google.api.expr.v1alpha1.Reference) ArrayList(java.util.ArrayList) Mapping.newMapping(org.projectnessie.cel.checker.Mapping.newMapping)

Example 8 with Call

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()));
}
Also used : CheckerEnv.getObjectWellKnownType(org.projectnessie.cel.checker.CheckerEnv.getObjectWellKnownType) CheckerEnv.isObjectWellKnownType(org.projectnessie.cel.checker.CheckerEnv.isObjectWellKnownType) CheckerEnv.dynElementType(org.projectnessie.cel.checker.CheckerEnv.dynElementType) Type(com.google.api.expr.v1alpha1.Type) MapType(com.google.api.expr.v1alpha1.Type.MapType) FieldType(org.projectnessie.cel.common.types.ref.FieldType) Comprehension(com.google.api.expr.v1alpha1.Expr.Comprehension)

Example 9 with Call

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;
    }
}
Also used : AbstractType(com.google.api.expr.v1alpha1.Type.AbstractType) PrimitiveType(com.google.api.expr.v1alpha1.Type.PrimitiveType) Type(com.google.api.expr.v1alpha1.Type) WellKnownType(com.google.api.expr.v1alpha1.Type.WellKnownType) FunctionType(com.google.api.expr.v1alpha1.Type.FunctionType) MapType(com.google.api.expr.v1alpha1.Type.MapType)

Example 10 with Call

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);
    }
}
Also used : Call(com.google.api.expr.v1alpha1.Expr.Call) ExprCall(org.projectnessie.cel.TestExpr.ExprCall) ParsedExpr(com.google.api.expr.v1alpha1.ParsedExpr) Expr(com.google.api.expr.v1alpha1.Expr) CheckedExpr(com.google.api.expr.v1alpha1.CheckedExpr) Constant(com.google.api.expr.v1alpha1.Constant) ParseRequest(com.google.api.expr.v1alpha1.ParseRequest) ParseResponse(com.google.api.expr.v1alpha1.ParseResponse) Test(org.junit.jupiter.api.Test)

Aggregations

CheckedExpr (com.google.api.expr.v1alpha1.CheckedExpr)7 Expr (com.google.api.expr.v1alpha1.Expr)7 ParsedExpr (com.google.api.expr.v1alpha1.ParsedExpr)6 Type (com.google.api.expr.v1alpha1.Type)6 Call (com.google.api.expr.v1alpha1.Expr.Call)5 MapType (com.google.api.expr.v1alpha1.Type.MapType)4 ArrayList (java.util.ArrayList)3 CheckerEnv.dynElementType (org.projectnessie.cel.checker.CheckerEnv.dynElementType)3 CheckerEnv.getObjectWellKnownType (org.projectnessie.cel.checker.CheckerEnv.getObjectWellKnownType)3 CheckerEnv.isObjectWellKnownType (org.projectnessie.cel.checker.CheckerEnv.isObjectWellKnownType)3 FieldType (org.projectnessie.cel.common.types.ref.FieldType)3 Val (org.projectnessie.cel.common.types.ref.Val)3 Decl (com.google.api.expr.v1alpha1.Decl)2 IdentDecl (com.google.api.expr.v1alpha1.Decl.IdentDecl)2 Comprehension (com.google.api.expr.v1alpha1.Expr.Comprehension)2 Select (com.google.api.expr.v1alpha1.Expr.Select)2 ParseRequest (com.google.api.expr.v1alpha1.ParseRequest)2 ParseResponse (com.google.api.expr.v1alpha1.ParseResponse)2 Reference (com.google.api.expr.v1alpha1.Reference)2 Test (org.junit.jupiter.api.Test)2