/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.template.soy.sharedpasses.opti;
import com.google.common.collect.ImmutableMap;
import com.google.template.soy.data.SoyRecord;
import com.google.template.soy.data.SoyValueConverter;
import com.google.template.soy.shared.restricted.SoyJavaPrintDirective;
import com.google.template.soy.shared.restricted.SoyPurePrintDirective;
import com.google.template.soy.sharedpasses.render.Environment;
import com.google.template.soy.sharedpasses.render.RenderException;
import com.google.template.soy.sharedpasses.render.RenderVisitor;
import com.google.template.soy.soytree.CallDelegateNode;
import com.google.template.soy.soytree.CssNode;
import com.google.template.soy.soytree.DebuggerNode;
import com.google.template.soy.soytree.LogNode;
import com.google.template.soy.soytree.MsgFallbackGroupNode;
import com.google.template.soy.soytree.PrintDirectiveNode;
import com.google.template.soy.soytree.PrintNode;
import com.google.template.soy.soytree.SoyNode;
import com.google.template.soy.soytree.TemplateRegistry;
import javax.annotation.Nullable;
/**
* Visitor for prerendering the template subtree rooted at a given SoyNode. This is possible when
* all data values are known at compile time.
*
* <p>Package-private helper for {@link SimplifyVisitor}.
*
* <p>The rendered output will be appended to the Appendable provided to the constructor.
*
*/
final class PrerenderVisitor extends RenderVisitor {
/**
* @param soyJavaDirectivesMap Map of all SoyJavaPrintDirectives (name to directive).
* @param preevalVisitorFactory Factory for creating an instance of PreevalVisitor.
* @param outputBuf The Appendable to append the output to.
* @param templateRegistry A registry of all templates.
*/
PrerenderVisitor(
ImmutableMap<String, ? extends SoyJavaPrintDirective> soyJavaDirectivesMap,
PreevalVisitorFactory preevalVisitorFactory,
Appendable outputBuf,
@Nullable TemplateRegistry templateRegistry) {
super(
soyJavaDirectivesMap,
preevalVisitorFactory,
outputBuf,
templateRegistry,
SoyValueConverter.EMPTY_DICT,
null /* ijData */,
null /* activeDelPackageNames */,
null /* msgBundle */,
null /* xidRenamingMap */,
null /* cssRenamingMap */);
}
@Override
protected PrerenderVisitor createHelperInstance(Appendable outputBuf, SoyRecord data) {
return new PrerenderVisitor(
soyJavaDirectivesMap,
(PreevalVisitorFactory) evalVisitorFactory,
outputBuf,
templateRegistry);
}
@Override
public Void exec(SoyNode soyNode) {
// Set the environment to be empty for each node. This will set all params to Undefined.
env = Environment.prerenderingEnvironment();
// Note: This is a catch-all to turn RuntimeExceptions that aren't RenderExceptions into
// RenderExceptions during prerendering.
try {
return super.exec(soyNode);
} catch (RenderException e) {
throw e;
} catch (RuntimeException e) {
throw RenderException.create("Failed prerender due to exception: " + e.getMessage(), e);
}
}
// -----------------------------------------------------------------------------------------------
// Implementations for specific nodes.
@Override
protected void visitMsgFallbackGroupNode(MsgFallbackGroupNode node) {
throw RenderException.create("Cannot prerender MsgFallbackGroupNode.");
}
@Override
protected void visitCssNode(CssNode node) {
throw RenderException.create("Cannot prerender CssNode.");
}
@Override
protected void visitCallDelegateNode(CallDelegateNode node) {
throw RenderException.create("Cannot prerender CallDelegateNode.");
}
@Override
protected void visitLogNode(LogNode node) {
throw RenderException.create("Cannot prerender LogNode.");
}
@Override
protected void visitDebuggerNode(DebuggerNode node) {
throw RenderException.create("Cannot prerender DebuggerNode.");
}
@Override
protected void visitPrintNode(PrintNode node) {
for (PrintDirectiveNode directiveNode : node.getChildren()) {
if (!isSoyPurePrintDirective(directiveNode)) {
throw RenderException.create("Cannot prerender a node with some impure print directive.");
}
}
super.visitPrintNode(node);
}
@Override
protected void visitPrintDirectiveNode(PrintDirectiveNode node) {
if (!isSoyPurePrintDirective(node)) {
throw RenderException.create("Cannot prerender impure print directive.");
}
super.visitPrintDirectiveNode(node);
}
private boolean isSoyPurePrintDirective(PrintDirectiveNode node) {
SoyJavaPrintDirective directive = soyJavaDirectivesMap.get(node.getName());
return directive != null
&& directive.getClass().isAnnotationPresent(SoyPurePrintDirective.class);
}
}