@Override protected final Optional<Expression> visitConditionalOpNode(ConditionalOpNode node) { if (allowsDetaches()) { Optional<Expression> trueBranch = visit(node.getChild(1)); Optional<Expression> falseBranch = visit(node.getChild(2)); // We only compile as an SVP if both branches are able to be compiled as such. Technically, // we could also support cases where only one branch is compilable to an SVP, but i doubt // that would be that important. if (!trueBranch.isPresent() || !falseBranch.isPresent()) { return Optional.absent(); } Expression condition = detachingExprCompiler.compile(node.getChild(0)).convert(boolean.class); return Optional.of(BytecodeUtils.ternary(condition, trueBranch.get(), falseBranch.get())); } return visitExprNode(node); }
@Override protected Optional<Expression> visitNullCoalescingOpNode(NullCoalescingOpNode node) { // All non-trivial ?: will require detaches for the left hand side. if (allowsDetaches()) { // for '$foo ?: $bar' we always have to eagerly evaluate $foo but $bar could be lazy. // of course if $foo is not null, then we will need to box it, however the current support // for ?: in ExpressionCompiler also always boxes everything so we aren't really losing // anything here. Optional<Expression> right = visit(node.getRightChild()); if (!right.isPresent()) { return Optional.absent(); } Expression left = detachingExprCompiler.compile(node.getLeftChild()).box().cast(SoyValueProvider.class); return Optional.of(BytecodeUtils.firstNonNull(left, right.get())); } return visitExprNode(node); }