Search in sources :

Example 6 with SoyValue

use of com.google.template.soy.data.SoyValue in project closure-templates by google.

the class RenderVisitor method visitForNode.

@Override
protected void visitForNode(ForNode node) {
    Optional<RangeArgs> exprAsRangeArgs = RangeArgs.createFromNode(node);
    if (exprAsRangeArgs.isPresent()) {
        RangeArgs args = exprAsRangeArgs.get();
        int step = args.increment().isPresent() ? evalRangeArg(node, args.increment().get()) : 1;
        int start = args.start().isPresent() ? evalRangeArg(node, args.start().get()) : 0;
        int end = evalRangeArg(node, args.limit());
        int length = end - start;
        if ((length ^ step) < 0) {
            // handle ifempty, if present
            if (node.numChildren() == 2) {
                visit(node.getChild(1));
            }
        } else {
            ForNonemptyNode child = (ForNonemptyNode) node.getChild(0);
            int size = length / step + (length % step == 0 ? 0 : 1);
            for (int i = 0; i < size; ++i) {
                executeForeachBody(child, i, IntegerData.forValue(start + step * i), size);
            }
        }
    } else {
        SoyValue dataRefValue = eval(node.getExpr(), node);
        if (!(dataRefValue instanceof SoyList)) {
            throw RenderException.createWithSource("In 'foreach' command " + node.toSourceString() + ", the data reference does not " + "resolve to a SoyList " + "(encountered type " + dataRefValue.getClass().getName() + ").", node);
        }
        SoyList foreachList = (SoyList) dataRefValue;
        int listLength = foreachList.length();
        if (listLength > 0) {
            // Case 1: Nonempty list.
            ForNonemptyNode child = (ForNonemptyNode) node.getChild(0);
            for (int i = 0; i < listLength; ++i) {
                executeForeachBody(child, i, foreachList.getProvider(i), listLength);
            }
        } else {
            // Case 2: Empty list. If the 'ifempty' node exists, visit it.
            if (node.numChildren() == 2) {
                visit(node.getChild(1));
            }
        }
    }
}
Also used : RangeArgs(com.google.template.soy.shared.RangeArgs) SoyList(com.google.template.soy.data.SoyList) SoyValue(com.google.template.soy.data.SoyValue) ForNonemptyNode(com.google.template.soy.soytree.ForNonemptyNode)

Example 7 with SoyValue

use of com.google.template.soy.data.SoyValue in project closure-templates by google.

the class RenderVisitor method visitMsgFallbackGroupNode.

@Override
protected void visitMsgFallbackGroupNode(MsgFallbackGroupNode node) {
    if (assistantForMsgs == null) {
        assistantForMsgs = new RenderVisitorAssistantForMsgs(this, msgBundle);
    }
    if (!node.getEscapingDirectives().isEmpty()) {
        // The entire message needs to be escaped, so we need to render to a temporary buffer.
        // Fortunately, for most messages (in HTML context) this is unnecessary.
        pushOutputBuf(new StringBuilder());
    }
    assistantForMsgs.visitForUseByMaster(node);
    if (!node.getEscapingDirectives().isEmpty()) {
        // Escape the entire message with the required directives.
        SoyValue wholeMsg = StringData.forValue(popOutputBuf().toString());
        for (SoyPrintDirective directive : node.getEscapingDirectives()) {
            wholeMsg = applyDirective(directive, wholeMsg, ImmutableList.<SoyValue>of(), node);
        }
        append(currOutputBuf, wholeMsg.stringValue());
    }
}
Also used : SoyPrintDirective(com.google.template.soy.shared.restricted.SoyPrintDirective) SoyValue(com.google.template.soy.data.SoyValue)

Example 8 with SoyValue

use of com.google.template.soy.data.SoyValue in project closure-templates by google.

the class RenderVisitor method visitCallDelegateNode.

@Override
protected void visitCallDelegateNode(CallDelegateNode node) {
    ExprRootNode variantExpr = node.getDelCalleeVariantExpr();
    String variant;
    if (variantExpr == null) {
        variant = "";
    } else {
        try {
            SoyValue variantData = eval(variantExpr, node);
            if (variantData instanceof IntegerData) {
                // An integer constant is being used as variant. Use the value string representation as
                // variant.
                variant = String.valueOf(variantData.longValue());
            } else {
                // Variant is either a StringData or a SanitizedContent. Use the value as a string. If
                // the value is not a string, and exception will be thrown.
                variant = variantData.stringValue();
            }
        } catch (SoyDataException e) {
            throw RenderException.createWithSource(String.format("Variant expression \"%s\" doesn't evaluate to a valid type " + "(Only string and integer are supported).", variantExpr.toSourceString()), e, node);
        }
    }
    DelTemplateKey delegateKey = DelTemplateKey.create(node.getDelCalleeName(), variant);
    TemplateDelegateNode callee;
    try {
        callee = templateRegistry.selectDelTemplate(delegateKey, activeDelPackageSelector);
    } catch (IllegalArgumentException e) {
        throw RenderException.createWithSource(e.getMessage(), e, node);
    }
    if (callee != null) {
        visitCallNodeHelper(node, callee);
    } else if (node.allowEmptyDefault()) {
        // no active delegate implementation, so the call output is empty string
        return;
    } else {
        throw RenderException.createWithSource("Found no active impl for delegate call to \"" + node.getDelCalleeName() + (variant.isEmpty() ? "" : ":" + variant) + "\" (and delcall does not set allowemptydefault=\"true\").", node);
    }
}
Also used : TemplateDelegateNode(com.google.template.soy.soytree.TemplateDelegateNode) IntegerData(com.google.template.soy.data.restricted.IntegerData) DelTemplateKey(com.google.template.soy.soytree.TemplateDelegateNode.DelTemplateKey) SoyValue(com.google.template.soy.data.SoyValue) SoyDataException(com.google.template.soy.data.SoyDataException) ExprRootNode(com.google.template.soy.exprtree.ExprRootNode)

Example 9 with SoyValue

use of com.google.template.soy.data.SoyValue in project closure-templates by google.

the class RenderVisitor method checkStrictParamType.

/**
 * Check that the given {@code paramValue} matches the static type of {@code param}.
 */
private void checkStrictParamType(final TemplateNode node, final TemplateParam param, @Nullable SoyValueProvider paramValue) {
    Kind kind = param.type().getKind();
    if (kind == Kind.ANY || kind == Kind.UNKNOWN) {
        // Nothing to check.  ANY and UKNOWN match all types.
        return;
    }
    if (paramValue == null) {
        paramValue = NullData.INSTANCE;
    } else if (paramValue instanceof SoyAbstractCachingValueProvider) {
        SoyAbstractCachingValueProvider typedValue = (SoyAbstractCachingValueProvider) paramValue;
        if (!typedValue.isComputed()) {
            // in order to preserve laziness we tell the value provider to assert the type when
            // computation is triggered
            typedValue.addValueAssertion(new ValueAssertion() {

                @Override
                public void check(SoyValue value) {
                    checkValueType(param, value, node);
                }
            });
            return;
        }
    }
    checkValueType(param, paramValue.resolve(), node);
}
Also used : ValueAssertion(com.google.template.soy.data.SoyAbstractCachingValueProvider.ValueAssertion) Kind(com.google.template.soy.types.SoyType.Kind) ContentKind(com.google.template.soy.data.SanitizedContent.ContentKind) SanitizedContentKind(com.google.template.soy.base.internal.SanitizedContentKind) SoyAbstractCachingValueProvider(com.google.template.soy.data.SoyAbstractCachingValueProvider) SoyValue(com.google.template.soy.data.SoyValue)

Example 10 with SoyValue

use of com.google.template.soy.data.SoyValue in project closure-templates by google.

the class RenderVisitor method visitCallNodeHelper.

// for IntelliJ
@SuppressWarnings("ConstantConditions")
private void visitCallNodeHelper(CallNode node, TemplateNode callee) {
    // ------ Build the call data. ------
    SoyRecord dataToPass;
    if (node.isPassingAllData()) {
        dataToPass = data;
    } else if (node.isPassingData()) {
        SoyValue dataRefValue = eval(node.getDataExpr(), node);
        if (!(dataRefValue instanceof SoyRecord)) {
            throw RenderException.create("In 'call' command " + node.toSourceString() + ", the data reference does not resolve to a SoyRecord.").addStackTraceElement(node);
        }
        dataToPass = (SoyRecord) dataRefValue;
    } else {
        dataToPass = null;
    }
    SoyRecord callData;
    int numChildren = node.numChildren();
    if (numChildren == 0) {
        // --- Cases 1 and 2: Not passing params. ---
        if (dataToPass == null) {
            // Case 1: Not passing data and not passing params.
            callData = ParamStore.EMPTY_INSTANCE;
        } else {
            // Case 2: Passing data and not passing params.
            callData = dataToPass;
        }
    } else {
        // --- Cases 3 and 4: Passing params. ---
        ParamStore mutableCallData;
        if (dataToPass == null) {
            // Case 3: Not passing data and passing params.
            mutableCallData = new BasicParamStore(numChildren);
        } else {
            // Case 4: Passing data and passing params.
            mutableCallData = new AugmentedParamStore(dataToPass, numChildren);
        }
        for (CallParamNode child : node.getChildren()) {
            if (child instanceof CallParamValueNode) {
                mutableCallData.setField(child.getKey().identifier(), lazyEval(((CallParamValueNode) child).getExpr(), child));
            } else if (child instanceof CallParamContentNode) {
                mutableCallData.setField(child.getKey().identifier(), renderRenderUnitNode((CallParamContentNode) child));
            } else {
                throw new AssertionError();
            }
        }
        callData = mutableCallData;
    }
    if (node.getEscapingDirectives().isEmpty()) {
        // No escaping at the call site -- render directly into the output buffer.
        RenderVisitor rv = this.createHelperInstance(currOutputBuf, callData);
        try {
            rv.renderTemplate(callee, node.getParamsToRuntimeCheck(callee));
        } catch (RenderException re) {
            // this template call.
            throw re.addStackTraceElement(node);
        }
    } else {
        // Escaping the call site's result, such as at a strict template boundary.
        // TODO: Some optimization is needed here before Strict Soy can be widely used:
        // - Only create this temporary buffer when contexts mismatch. We could run a pre-pass that
        // eliminates escaping directives when all callers are known.
        // - Instead of creating a temporary buffer and copying, wrap with an escaping StringBuilder.
        StringBuilder calleeBuilder = new StringBuilder();
        RenderVisitor rv = this.createHelperInstance(calleeBuilder, callData);
        try {
            rv.renderTemplate(callee, node.getParamsToRuntimeCheck(callee));
        } catch (RenderException re) {
            // this template call.
            throw re.addStackTraceElement(node);
        }
        ContentKind calleeKind = fromSanitizedContentKind(callee.getContentKind());
        SoyValue resultData = calleeKind != null ? UnsafeSanitizedContentOrdainer.ordainAsSafe(calleeBuilder.toString(), calleeKind) : StringData.forValue(calleeBuilder.toString());
        for (SoyPrintDirective directive : node.getEscapingDirectives()) {
            resultData = applyDirective(directive, resultData, ImmutableList.<SoyValue>of(), node);
        }
        append(currOutputBuf, resultData, node);
    }
}
Also used : SoyRecord(com.google.template.soy.data.SoyRecord) CallParamNode(com.google.template.soy.soytree.CallParamNode) CallParamValueNode(com.google.template.soy.soytree.CallParamValueNode) SoyValue(com.google.template.soy.data.SoyValue) BasicParamStore(com.google.template.soy.data.internal.BasicParamStore) AugmentedParamStore(com.google.template.soy.data.internal.AugmentedParamStore) CallParamContentNode(com.google.template.soy.soytree.CallParamContentNode) SoyPrintDirective(com.google.template.soy.shared.restricted.SoyPrintDirective) ParamStore(com.google.template.soy.data.internal.ParamStore) AugmentedParamStore(com.google.template.soy.data.internal.AugmentedParamStore) BasicParamStore(com.google.template.soy.data.internal.BasicParamStore) ContentKind(com.google.template.soy.data.SanitizedContent.ContentKind) SanitizedContentKind(com.google.template.soy.base.internal.SanitizedContentKind)

Aggregations

SoyValue (com.google.template.soy.data.SoyValue)61 Test (org.junit.Test)31 StringData (com.google.template.soy.data.restricted.StringData)5 ExprNode (com.google.template.soy.exprtree.ExprNode)4 SoyLegacyObjectMap (com.google.template.soy.data.SoyLegacyObjectMap)3 SoyList (com.google.template.soy.data.SoyList)3 ParentExprNode (com.google.template.soy.exprtree.ExprNode.ParentExprNode)3 ImmutableMap (com.google.common.collect.ImmutableMap)2 SanitizedContentKind (com.google.template.soy.base.internal.SanitizedContentKind)2 SanitizedContent (com.google.template.soy.data.SanitizedContent)2 ContentKind (com.google.template.soy.data.SanitizedContent.ContentKind)2 SoyDataException (com.google.template.soy.data.SoyDataException)2 SoyDict (com.google.template.soy.data.SoyDict)2 SoyRecord (com.google.template.soy.data.SoyRecord)2 FloatData (com.google.template.soy.data.restricted.FloatData)2 IntegerData (com.google.template.soy.data.restricted.IntegerData)2 SoyString (com.google.template.soy.data.restricted.SoyString)2 UndefinedData (com.google.template.soy.data.restricted.UndefinedData)2 ExprRootNode (com.google.template.soy.exprtree.ExprRootNode)2 SoyPrintDirective (com.google.template.soy.shared.restricted.SoyPrintDirective)2