Search in sources :

Example 1 with Decl

use of com.google.api.expr.v1alpha1.Decl 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 2 with Decl

use of com.google.api.expr.v1alpha1.Decl 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 3 with Decl

use of com.google.api.expr.v1alpha1.Decl in project cel-java by projectnessie.

the class CheckerEnv method sanitizeFunction.

// sanitizeFunction replaces well-known types referenced by message name with their equivalent
// CEL built-in type instances.
Decl sanitizeFunction(Decl decl) {
    FunctionDecl fn = decl.getFunction();
    // Determine whether the declaration requires replacements from proto-based message type
    // references to well-known CEL type references.
    boolean needsSanitizing = false;
    for (Overload o : fn.getOverloadsList()) {
        if (isObjectWellKnownType(o.getResultType())) {
            needsSanitizing = true;
            break;
        }
        for (Type p : o.getParamsList()) {
            if (isObjectWellKnownType(p)) {
                needsSanitizing = true;
                break;
            }
        }
    }
    // Early return if the declaration requires no modification.
    if (!needsSanitizing) {
        return decl;
    }
    // Sanitize all of the overloads if any overload requires an update to its type references.
    List<Overload> overloads = new ArrayList<>(fn.getOverloadsCount());
    for (Overload o : fn.getOverloadsList()) {
        boolean sanitized = false;
        Type rt = o.getResultType();
        if (isObjectWellKnownType(rt)) {
            rt = getObjectWellKnownType(rt);
            sanitized = true;
        }
        List<Type> params = new ArrayList<>(o.getParamsCount());
        for (Type p : o.getParamsList()) {
            if (isObjectWellKnownType(p)) {
                params.add(getObjectWellKnownType(p));
                sanitized = true;
            } else {
                params.add(p);
            }
        }
        // If sanitized, replace the overload definition.
        Overload ov;
        if (sanitized) {
            if (o.getIsInstanceFunction()) {
                ov = Decls.newInstanceOverload(o.getOverloadId(), params, rt);
            } else {
                ov = Decls.newOverload(o.getOverloadId(), params, rt);
            }
        } else {
            // Otherwise, preserve the original overload.
            ov = o;
        }
        overloads.add(ov);
    }
    return Decls.newFunction(decl.getName(), overloads);
}
Also used : Types.formatCheckedType(org.projectnessie.cel.checker.Types.formatCheckedType) Type(com.google.api.expr.v1alpha1.Type) ErrType(org.projectnessie.cel.common.types.Err.ErrType) Overload(com.google.api.expr.v1alpha1.Decl.FunctionDecl.Overload) ArrayList(java.util.ArrayList) FunctionDecl(com.google.api.expr.v1alpha1.Decl.FunctionDecl)

Example 4 with Decl

use of com.google.api.expr.v1alpha1.Decl in project cel-java by projectnessie.

the class CheckerEnv method addOverload.

/**
 * addOverload adds overload to function declaration f. Returns one or more errorMsg values if the
 * overload overlaps with an existing overload or macro.
 */
Decl addOverload(Decl f, Overload overload, List<String> errMsgs) {
    FunctionDecl function = f.getFunction();
    Mapping emptyMappings = newMapping();
    Type overloadFunction = Decls.newFunctionType(overload.getResultType(), overload.getParamsList());
    Type overloadErased = substitute(emptyMappings, overloadFunction, true);
    boolean hasErr = false;
    for (Overload existing : function.getOverloadsList()) {
        Type existingFunction = Decls.newFunctionType(existing.getResultType(), existing.getParamsList());
        Type existingErased = substitute(emptyMappings, existingFunction, true);
        boolean overlap = isAssignable(emptyMappings, overloadErased, existingErased) != null || isAssignable(emptyMappings, existingErased, overloadErased) != null;
        if (overlap && overload.getIsInstanceFunction() == existing.getIsInstanceFunction()) {
            errMsgs.add(overlappingOverloadError(f.getName(), overload.getOverloadId(), overloadFunction, existing.getOverloadId(), existingFunction));
            hasErr = true;
        }
    }
    for (Macro macro : Macro.AllMacros) {
        if (macro.function().equals(f.getName()) && macro.isReceiverStyle() == overload.getIsInstanceFunction() && macro.argCount() == overload.getParamsCount()) {
            errMsgs.add(overlappingMacroError(f.getName(), macro.argCount()));
            hasErr = true;
        }
    }
    if (hasErr) {
        return f;
    }
    function = function.toBuilder().addOverloads(overload).build();
    f = f.toBuilder().setFunction(function).build();
    return f;
}
Also used : Types.formatCheckedType(org.projectnessie.cel.checker.Types.formatCheckedType) Type(com.google.api.expr.v1alpha1.Type) ErrType(org.projectnessie.cel.common.types.Err.ErrType) Overload(com.google.api.expr.v1alpha1.Decl.FunctionDecl.Overload) Macro(org.projectnessie.cel.parser.Macro) Mapping.newMapping(org.projectnessie.cel.checker.Mapping.newMapping) FunctionDecl(com.google.api.expr.v1alpha1.Decl.FunctionDecl)

Example 5 with Decl

use of com.google.api.expr.v1alpha1.Decl in project cel-java by projectnessie.

the class CheckerEnv method lookupIdent.

/**
 * LookupIdent returns a Decl proto for typeName as an identifier in the Env. Returns nil if no
 * such identifier is found in the Env.
 */
public Decl lookupIdent(String name) {
    for (String candidate : container.resolveCandidateNames(name)) {
        Decl ident = declarations.findIdent(candidate);
        if (ident != null) {
            return ident;
        }
        // Next try to import the name as a reference to a message type. If found,
        // the declaration is added to the outest (global) scope of the
        // environment, so next time we can access it faster.
        Type t = provider.findType(candidate);
        if (t != null) {
            Decl decl = Decls.newVar(candidate, t);
            declarations.addIdent(decl);
            return decl;
        }
        // Next try to import this as an enum value by splitting the name in a type prefix and
        // the enum inside.
        Val enumValue = provider.enumValue(candidate);
        if (enumValue.type() != ErrType) {
            Decl decl = Decls.newIdent(candidate, Decls.Int, Constant.newBuilder().setInt64Value(enumValue.intValue()).build());
            declarations.addIdent(decl);
            return decl;
        }
    }
    return null;
}
Also used : Val(org.projectnessie.cel.common.types.ref.Val) Types.formatCheckedType(org.projectnessie.cel.checker.Types.formatCheckedType) Type(com.google.api.expr.v1alpha1.Type) ErrType(org.projectnessie.cel.common.types.Err.ErrType) FunctionDecl(com.google.api.expr.v1alpha1.Decl.FunctionDecl) Decl(com.google.api.expr.v1alpha1.Decl) IdentDecl(com.google.api.expr.v1alpha1.Decl.IdentDecl)

Aggregations

Decl (com.google.api.expr.v1alpha1.Decl)10 Type (com.google.api.expr.v1alpha1.Type)9 IdentDecl (com.google.api.expr.v1alpha1.Decl.IdentDecl)8 FunctionDecl (com.google.api.expr.v1alpha1.Decl.FunctionDecl)5 Types.formatCheckedType (org.projectnessie.cel.checker.Types.formatCheckedType)5 Overload (com.google.api.expr.v1alpha1.Decl.FunctionDecl.Overload)4 ArrayList (java.util.ArrayList)4 ErrType (org.projectnessie.cel.common.types.Err.ErrType)4 CheckedExpr (com.google.api.expr.v1alpha1.CheckedExpr)3 Expr (com.google.api.expr.v1alpha1.Expr)3 MapType (com.google.api.expr.v1alpha1.Type.MapType)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 Mapping.newMapping (org.projectnessie.cel.checker.Mapping.newMapping)2 TypeRegistry (org.projectnessie.cel.common.types.ref.TypeRegistry)2 Macro (org.projectnessie.cel.parser.Macro)2 Call (com.google.api.expr.v1alpha1.Expr.Call)1 CreateStruct (com.google.api.expr.v1alpha1.Expr.CreateStruct)1