use of com.google.template.soy.jssrc.dsl.VariableDeclaration in project closure-templates by google.
the class GenJsCodeVisitor method handleForeachLoop.
/**
* Example:
*
* <pre>
* {for $foo in $boo.foos}
* ...
* {/for}
* </pre>
*
* might generate
*
* <pre>
* for (var foo2Index = 0; foo2Index < foo2ListLen; foo2Index++) {
* var foo2Data = foo2List[foo2Index];
* ...
* }
* </pre>
*/
private CodeChunk handleForeachLoop(ForNonemptyNode node, CodeChunk.WithValue limit, Function<CodeChunk.WithValue, CodeChunk.WithValue> getDataItemFunction) {
// Build some local variable names.
String varName = node.getVarName();
String varPrefix = varName + node.getForNodeId();
// TODO(user): A more consistent pattern for local variable management.
String loopIndexName = varPrefix + "Index";
String dataName = varPrefix + "Data";
CodeChunk.WithValue loopIndex = id(loopIndexName);
VariableDeclaration data = VariableDeclaration.builder(dataName).setRhs(getDataItemFunction.apply(loopIndex)).build();
// Populate the local var translations with the translations from this node.
templateTranslationContext.soyToJsVariableMappings().put(varName, id(dataName)).put(varName + "__isFirst", loopIndex.doubleEquals(number(0))).put(varName + "__isLast", loopIndex.doubleEquals(limit.minus(number(1)))).put(varName + "__index", loopIndex);
// Generate the loop body.
CodeChunk foreachBody = CodeChunk.statements(data, visitChildrenReturningCodeChunk(node));
// Create the entire for block.
return forLoop(loopIndexName, limit, foreachBody);
}
use of com.google.template.soy.jssrc.dsl.VariableDeclaration in project closure-templates by google.
the class GenJsCodeVisitor method genParamTypeChecks.
/**
* Generate code to verify the runtime types of the input params. Also typecasts the input
* parameters and assigns them to local variables for use in the template.
*
* @param node the template node.
*/
@CheckReturnValue
protected CodeChunk genParamTypeChecks(TemplateNode node) {
ImmutableList.Builder<CodeChunk> declarations = ImmutableList.builder();
for (TemplateParam param : node.getAllParams()) {
if (param.declLoc() != TemplateParam.DeclLoc.HEADER) {
continue;
}
String paramName = param.name();
SoyType paramType = param.type();
CodeChunk.Generator generator = templateTranslationContext.codeGenerator();
CodeChunk.WithValue paramChunk = TranslateExprNodeVisitor.genCodeForParamAccess(paramName, param.isInjected());
JsType jsType = getJsType(paramType);
// The opt_param.name value that will be type-tested.
String paramAlias = genParamAlias(paramName);
CodeChunk.WithValue coerced = jsType.getValueCoercion(paramChunk, generator);
if (coerced != null) {
// since we have coercion logic, dump into a temporary
paramChunk = generator.declarationBuilder().setRhs(coerced).build().ref();
}
// The param value to assign
CodeChunk.WithValue value;
Optional<CodeChunk.WithValue> typeAssertion = jsType.getTypeAssertion(paramChunk, generator);
// The type-cast expression.
if (typeAssertion.isPresent()) {
value = SOY_ASSERTS_ASSERT_TYPE.call(typeAssertion.get(), stringLiteral(paramName), paramChunk, stringLiteral(jsType.typeExpr()));
} else {
value = paramChunk;
}
VariableDeclaration.Builder declarationBuilder = VariableDeclaration.builder(paramAlias).setRhs(value).setGoogRequires(jsType.getGoogRequires());
declarationBuilder.setJsDoc("/** @type {" + jsType.typeExpr() + "} */");
VariableDeclaration declaration = declarationBuilder.build();
declarations.add(declaration);
templateTranslationContext.soyToJsVariableMappings().put(paramName, id(paramAlias));
}
return CodeChunk.statements(declarations.build());
}
use of com.google.template.soy.jssrc.dsl.VariableDeclaration in project closure-templates by google.
the class AssistantForHtmlMsgs method generateMsgGroupCode.
/**
* Returns a code chunk of idom instructions that output the contents of a translated message as
* HTML. For example:
*
* <pre>
* {msg desc="Says hello to a person."}Hello {$name}!{/msg}
* </pre>
*
* compiles to
*
* <pre>
* /** @desc Says hello to a person. *{@literal /}
* var MSG_EXTERNAL_6936162475751860807 = goog.getMsg(
* 'Hello {$name}!',
* {'name': '\u00010\u0001'});
* var lastIndex_1153 = 0, partRe_1153 = /\x01\d+\x01/g, match_1153;
* do {
* match_1153 = partRe_1153.exec(MSG_EXTERNAL_6936162475751860807) || undefined;
* incrementalDom.text(goog.string.unescapeEntities(
* MSG_EXTERNAL_6936162475751860807.substring(
* lastIndex_1153, match_1153 && match_1153.index)));
* lastIndex_1153 = partRe_1153.lastIndex;
* switch (match_1153 && match_1153[0]) {
* case '\u00010\u0001':
* var dyn8 = opt_data.name;
* if (typeof dyn8 == 'function') dyn8();
* else if (dyn8 != null) incrementalDom.text(dyn8);
* break;
* }
* } while (match_1153);
* </pre>
*
* Each interpolated MsgPlaceholderNode (either for HTML tags or for print statements) compiles to
* a separate {@code case} statement.
*/
CodeChunk generateMsgGroupCode(MsgFallbackGroupNode node) {
Preconditions.checkState(placeholderNames.isEmpty(), "This class is not reusable.");
// Non-HTML {msg}s should be extracted into LetContentNodes and handled by jssrc.
Preconditions.checkArgument(node.getHtmlContext() == HtmlContext.HTML_PCDATA, "AssistantForHtmlMsgs is only for HTML {msg}s.");
// All of these helper variables must have uniquely-suffixed names because {msg}s can be nested.
// It'd be nice to move this codegen to a Soy template...
// The raw translated text, with placeholder placeholders.
CodeChunk.WithValue translationVar = super.generateMsgGroupVariable(node);
// If there are no placeholders, we don't need anything special (but we still need to unescape).
if (placeholderNames.isEmpty()) {
CodeChunk.WithValue unescape = GOOG_STRING_UNESCAPE_ENTITIES.call(translationVar);
return INCREMENTAL_DOM_TEXT.call(unescape);
}
// it into a fresh variable.
if (!translationVar.isCheap()) {
translationVar = translationContext.codeGenerator().declarationBuilder().setRhs(translationVar).build().ref();
}
// Declare everything.
// The mutable (tracking index of last match) regex to find the placeholder placeholders.
VariableDeclaration regexVar = VariableDeclaration.builder("partRe_" + node.getId()).setRhs(CodeChunk.regexLiteral(PLACEHOLDER_REGEX)).build();
// The current placeholder from the regex.
VariableDeclaration matchVar = VariableDeclaration.builder("match_" + node.getId()).build();
// The index of the end of the previous placeholder, where the next raw text run starts.
VariableDeclaration lastIndexVar = VariableDeclaration.builder("lastIndex_" + node.getId()).setRhs(CodeChunk.number(0)).build();
List<CodeChunk> doBody = new ArrayList<>();
// match_XXX = partRe_XXX.exec(MSG_EXTERNAL_XXX) || undefined;
doBody.add(matchVar.ref().assign(regexVar.ref().dotAccess("exec").call(translationVar).or(CodeChunk.id("undefined"), translationContext.codeGenerator())));
// Replace null with undefined. This is necessary to make substring() treat falsy as an omitted
// parameter, so that it goes until the end of the string. Otherwise, the non-numeric parameter
// would be coerced to zero.
// Emit the (possibly-empty) run of raw text since the last placeholder, until this placeholder,
// or until the end of the source string.
CodeChunk.WithValue endIndex = matchVar.ref().and(matchVar.ref().dotAccess("index"), translationContext.codeGenerator());
CodeChunk.WithValue unescape = GOOG_STRING_UNESCAPE_ENTITIES.call(translationVar.dotAccess("substring").call(lastIndexVar.ref(), endIndex));
doBody.add(INCREMENTAL_DOM_TEXT.call(unescape));
doBody.add(lastIndexVar.ref().assign(regexVar.ref().dotAccess("lastIndex")));
// switch (match_XXX && match_XXX[0]) { ... }
SwitchBuilder switchBuilder = CodeChunk.switch_(matchVar.ref().and(matchVar.ref().bracketAccess(CodeChunk.number(0)), translationContext.codeGenerator()));
for (Map.Entry<String, MsgPlaceholderNode> ph : placeholderNames.entrySet()) {
switchBuilder.case_(CodeChunk.stringLiteral(ph.getKey()), master.visitForUseByAssistantsAsCodeChunk(ph.getValue()));
}
doBody.add(switchBuilder.build());
return CodeChunk.statements(CodeChunk.statements(translationVar.initialStatements()), regexVar, lastIndexVar, matchVar, DoWhile.builder().setCondition(matchVar.ref()).setBody(CodeChunk.statements(doBody)).build());
}
use of com.google.template.soy.jssrc.dsl.VariableDeclaration in project closure-templates by google.
the class GenIncrementalDomCodeVisitor method generateFunctionBody.
@Override
protected CodeChunk generateFunctionBody(TemplateNode node) {
IncrementalDomCodeBuilder jsCodeBuilder = getJsCodeBuilder();
boolean isTextTemplate = isTextContent(node.getContentKind());
CodeChunk typeChecks = genParamTypeChecks(node);
// the transformation.
if (isTextTemplate) {
// We do our own initialization below, so mark it as such.
jsCodeBuilder.pushOutputVar("output").setOutputVarInited();
}
CodeChunk body = visitChildrenReturningCodeChunk(node);
if (isTextTemplate) {
VariableDeclaration declare = VariableDeclaration.builder("output").setRhs(LITERAL_EMPTY_STRING).build();
jsCodeBuilder.popOutputVar();
body = CodeChunk.statements(declare, body, return_(sanitize(declare.ref(), node.getContentKind())));
}
return CodeChunk.statements(typeChecks, body);
}
Aggregations