use of com.google.template.soy.jbcsrc.restricted.SoyExpression in project closure-templates by google.
the class SoyNodeCompiler method visitPrintNode.
@Override
protected Statement visitPrintNode(PrintNode node) {
if (node.getExpr().getRoot() instanceof FunctionNode) {
FunctionNode fn = (FunctionNode) node.getExpr().getRoot();
if (fn.getSoyFunction() instanceof LoggingFunction) {
return visitLoggingFunction(node, fn, (LoggingFunction) fn.getSoyFunction());
}
}
// evaluates to a SoyValueProvider. This will allow us to render incrementally.
if (areAllPrintDirectivesStreamable(node)) {
Label reattachPoint = new Label();
ExprRootNode expr = node.getExpr();
Optional<Expression> asSoyValueProvider = expressionToSoyValueProviderCompiler.compileAvoidingBoxing(expr, reattachPoint);
if (asSoyValueProvider.isPresent()) {
return renderIncrementally(asSoyValueProvider.get(), node.getChildren(), reattachPoint);
}
}
// otherwise we need to apply some non-streaming print directives, or the expression would
// require boxing to be a print directive (which usually means it is quite trivial).
Label reattachPoint = new Label();
SoyExpression value = compilePrintNodeAsExpression(node, reattachPoint);
// TODO(lukes): call value.render?
AppendableExpression renderSoyValue = appendableExpression.appendString(value.coerceToString()).labelStart(reattachPoint);
Statement stmt;
if (shouldCheckBuffer(node)) {
stmt = detachState.detachLimited(renderSoyValue);
} else {
stmt = renderSoyValue.toStatement();
}
return stmt;
}
use of com.google.template.soy.jbcsrc.restricted.SoyExpression in project closure-templates by google.
the class SoyNodeCompiler method visitForNode.
@Override
protected Statement visitForNode(ForNode node) {
ForNonemptyNode nonEmptyNode = (ForNonemptyNode) node.getChild(0);
Optional<RangeArgs> exprAsRangeArgs = RangeArgs.createFromNode(node);
Scope scope = variables.enterScope();
final Variable indexVar;
final List<Statement> initializers = new ArrayList<>();
final Variable sizeVar;
final Variable itemVar;
if (exprAsRangeArgs.isPresent()) {
final CompiledForeachRangeArgs compiledArgs = calculateRangeArgs(node, scope);
initializers.addAll(compiledArgs.initStatements());
// The size is just the number of items in the range. The logic is a little tricky so we
// implement it in a runtime function: JbcsrcRuntime.rangeLoopLength
sizeVar = scope.createSynthetic(SyntheticVarName.foreachLoopLength(nonEmptyNode), MethodRef.RUNTIME_RANGE_LOOP_LENGTH.invoke(compiledArgs.start(), compiledArgs.end(), compiledArgs.step()), DERIVED);
indexVar = scope.createSynthetic(SyntheticVarName.foreachLoopIndex(nonEmptyNode), constant(0), STORE);
itemVar = scope.create(nonEmptyNode.getVarName(), new Expression(Type.LONG_TYPE, Feature.CHEAP) {
@Override
protected void doGen(CodeBuilder adapter) {
// executes ((long) start + index * step)
compiledArgs.start().gen(adapter);
compiledArgs.step().gen(adapter);
indexVar.local().gen(adapter);
adapter.visitInsn(Opcodes.IMUL);
adapter.visitInsn(Opcodes.IADD);
adapter.cast(Type.INT_TYPE, Type.LONG_TYPE);
}
}, DERIVED);
} else {
SoyExpression expr = exprCompiler.compile(node.getExpr()).unboxAs(List.class);
Variable listVar = scope.createSynthetic(SyntheticVarName.foreachLoopList(nonEmptyNode), expr, STORE);
initializers.add(listVar.initializer());
sizeVar = scope.createSynthetic(SyntheticVarName.foreachLoopLength(nonEmptyNode), MethodRef.LIST_SIZE.invoke(listVar.local()), DERIVED);
indexVar = scope.createSynthetic(SyntheticVarName.foreachLoopIndex(nonEmptyNode), constant(0), STORE);
itemVar = scope.create(nonEmptyNode.getVarName(), MethodRef.LIST_GET.invoke(listVar.local(), indexVar.local()).checkedCast(SOY_VALUE_PROVIDER_TYPE), DERIVED);
}
initializers.add(sizeVar.initializer());
final Statement loopBody = visitChildrenInNewScope(nonEmptyNode);
final Statement exitScope = scope.exitScope();
// it important for this to be generated after exitScope is called (or before enterScope)
final Statement emptyBlock = node.numChildren() == 2 ? visitChildrenInNewScope(node.getChild(1)) : null;
return new Statement() {
@Override
protected void doGen(CodeBuilder adapter) {
for (Statement initializer : initializers) {
initializer.gen(adapter);
}
sizeVar.local().gen(adapter);
Label emptyListLabel = new Label();
adapter.ifZCmp(Opcodes.IFEQ, emptyListLabel);
indexVar.initializer().gen(adapter);
Label loopStart = adapter.mark();
itemVar.initializer().gen(adapter);
loopBody.gen(adapter);
// index++
adapter.iinc(indexVar.local().index(), 1);
indexVar.local().gen(adapter);
sizeVar.local().gen(adapter);
// if index < list.size(), goto loopstart
adapter.ifICmp(Opcodes.IFLT, loopStart);
// exit the loop
exitScope.gen(adapter);
if (emptyBlock != null) {
Label skipIfEmptyBlock = new Label();
adapter.goTo(skipIfEmptyBlock);
adapter.mark(emptyListLabel);
emptyBlock.gen(adapter);
adapter.mark(skipIfEmptyBlock);
} else {
adapter.mark(emptyListLabel);
}
}
};
}
use of com.google.template.soy.jbcsrc.restricted.SoyExpression in project closure-templates by google.
the class SoyNodeCompiler method visitSwitchNode.
@Override
protected Statement visitSwitchNode(SwitchNode node) {
// A few special cases:
// 1. only a {default} block. In this case we can skip all the switch logic and temporaries
// 2. no children. Just return the empty statement
// Note that in both of these cases we do not evalutate (or generate code) for the switch
// expression.
List<BlockNode> children = node.getChildren();
if (children.isEmpty()) {
return Statement.NULL_STATEMENT;
}
if (children.size() == 1 && children.get(0) instanceof SwitchDefaultNode) {
return visitChildrenInNewScope(children.get(0));
}
// otherwise we need to evaluate the switch variable and generate dispatching logic.
SoyExpression switchVar = exprCompiler.compile(node.getExpr());
Scope scope = variables.enterScope();
Variable variable = scope.createSynthetic(SyntheticVarName.forSwitch(node), switchVar, STORE);
Statement initializer = variable.initializer();
switchVar = switchVar.withSource(variable.local());
List<IfBlock> cases = new ArrayList<>();
Optional<Statement> defaultBlock = Optional.absent();
for (SoyNode child : children) {
if (child instanceof SwitchCaseNode) {
SwitchCaseNode caseNode = (SwitchCaseNode) child;
Label reattachPoint = new Label();
List<Expression> comparisons = new ArrayList<>();
for (ExprRootNode caseExpr : caseNode.getExprList()) {
comparisons.add(compareSoyEquals(switchVar, exprCompiler.compile(caseExpr, reattachPoint)));
}
Expression condition = BytecodeUtils.logicalOr(comparisons).labelStart(reattachPoint);
Statement block = visitChildrenInNewScope(caseNode);
cases.add(IfBlock.create(condition, block));
} else {
SwitchDefaultNode defaultNode = (SwitchDefaultNode) child;
defaultBlock = Optional.of(visitChildrenInNewScope(defaultNode));
}
}
Statement exitScope = scope.exitScope();
// generation that we could maybe use
return Statement.concat(initializer, ControlFlow.ifElseChain(cases, defaultBlock), exitScope);
}
use of com.google.template.soy.jbcsrc.restricted.SoyExpression in project closure-templates by google.
the class SoyNodeCompiler method compilePrintNodeAsExpression.
private SoyExpression compilePrintNodeAsExpression(PrintNode node, Label reattachPoint) {
BasicExpressionCompiler basic = exprCompiler.asBasicCompiler(reattachPoint);
SoyExpression value = basic.compile(node.getExpr());
// because instead of wrapping the soy value, we would just wrap the appendable.
for (PrintDirectiveNode printDirective : node.getChildren()) {
value = parameterLookup.getRenderContext().applyPrintDirective(printDirective.getPrintDirective(), value, basic.compileToList(printDirective.getArgs()));
}
return value;
}
use of com.google.template.soy.jbcsrc.restricted.SoyExpression in project closure-templates by google.
the class MapKeysFunction method computeForJbcSrc.
@Override
public SoyExpression computeForJbcSrc(JbcSrcPluginContext context, List<SoyExpression> args) {
SoyExpression soyExpression = args.get(0);
SoyType argType = soyExpression.soyType();
SoyType keyType = ((MapType) argType).getKeyType();
return SoyExpression.forList(keyType == null ? ListType.EMPTY_LIST : ListType.of(keyType), JbcSrcMethods.MAP_KEYS_FN.invoke(soyExpression.box().checkedCast(SoyMap.class)));
}
Aggregations