Search in sources :

Example 1 with SanitizedType

use of com.google.template.soy.types.SanitizedType in project closure-templates by google.

the class SoyExpression method unboxAs.

// TODO(lukes): split this into a set of specialized methods, one per target type like we did
// for the 'coerce' methods.
/**
 * Unboxes this to a {@link SoyExpression} with a runtime type of {@code asType}.
 *
 * <p>This method is appropriate when you know (likely via inspection of the {@link #soyType()},
 * or other means) that the value does have the appropriate type but you prefer to interact with
 * it as its unboxed representation. If you simply want to 'coerce' the given value to a new type
 * consider {@link #coerceToBoolean()} {@link #coerceToDouble()} or {@link #coerceToString()}
 * which are designed for that use case.
 */
public SoyExpression unboxAs(Class<?> asType) {
    checkArgument(!SoyValue.class.isAssignableFrom(asType), "Cannot use unboxAs() to convert to a SoyValue: %s, use .box() instead", asType);
    // SoyExpressions that are already unboxed fall into this case.
    if (BytecodeUtils.isDefinitelyAssignableFrom(Type.getType(asType), soyRuntimeType.runtimeType())) {
        return this;
    }
    // Attempting to unbox an unboxed proto
    if (asType.equals(Message.class) && soyRuntimeType.isKnownProto() && !isBoxed()) {
        return this;
    }
    if (!isBoxed()) {
        throw new IllegalStateException("Trying to unbox an unboxed value (" + soyRuntimeType + ") into " + asType + " doesn't make sense. Should you be using a type coercion? e.g. coerceToBoolean()");
    }
    if (asType.equals(boolean.class)) {
        return forBool(delegate.invoke(MethodRef.SOY_VALUE_BOOLEAN_VALUE));
    }
    if (asType.equals(long.class)) {
        return forInt(delegate.invoke(MethodRef.SOY_VALUE_LONG_VALUE));
    }
    if (asType.equals(double.class)) {
        return forFloat(delegate.invoke(MethodRef.SOY_VALUE_FLOAT_VALUE));
    }
    if (delegate.isNonNullable()) {
        if (asType.equals(String.class)) {
            Expression unboxedString = delegate.invoke(MethodRef.SOY_VALUE_STRING_VALUE);
            // We need to ensure that santized types don't lose their content kinds
            return soyRuntimeType.isKnownSanitizedContent() ? forSanitizedString(unboxedString, ((SanitizedType) soyType()).getContentKind()) : forString(unboxedString);
        }
        if (asType.equals(List.class)) {
            return unboxAsList();
        }
        if (asType.equals(Message.class)) {
            SoyRuntimeType runtimeType = getUnboxedType(soyType());
            return forProto(runtimeType, delegate.invoke(MethodRef.SOY_PROTO_VALUE_GET_PROTO).checkedCast(runtimeType.runtimeType()));
        }
    } else {
        // else it must be a List/Proto/String all of which must preserve null through the unboxing
        // operation
        // TODO(lukes): this violates the expression contract since we jump to a label outside the
        // scope of the expression
        final Label end = new Label();
        Expression nonNullDelegate = new Expression(resultType(), features()) {

            @Override
            protected void doGen(CodeBuilder adapter) {
                delegate.gen(adapter);
                BytecodeUtils.nullCoalesce(adapter, end);
            }
        };
        return withSource(nonNullDelegate).asNonNullable().unboxAs(asType).asNullable().labelEnd(end);
    }
    throw new UnsupportedOperationException("Can't unbox " + soyRuntimeType + " as " + asType);
}
Also used : SanitizedType(com.google.template.soy.types.SanitizedType) Label(org.objectweb.asm.Label)

Aggregations

SanitizedType (com.google.template.soy.types.SanitizedType)1 Label (org.objectweb.asm.Label)1