docs: @Override
    protected SoyValue visitFunctionNode(FunctionNode node) {
      Object soyFunction = node.getSoyFunction();
      // Handle nonplugin functions.
      if (soyFunction instanceof BuiltinFunction) {
        BuiltinFunction nonpluginFn = (BuiltinFunction) soyFunction;
        switch (nonpluginFn) {
          case IS_FIRST:
            return visitIsFirstFunction(node);
          case IS_LAST:
            return visitIsLastFunction(node);
          case INDEX:
            return visitIndexFunction(node);
          case CHECK_NOT_NULL:
            return visitCheckNotNullFunction(node.getChild(0));
          case CSS:
            return visitCssFunction(node);
          case XID:
            return visitXidFunction(node);
          case IS_PRIMARY_MSG_IN_USE:
            return visitIsPrimaryMsgInUseFunction(node);
          case V1_EXPRESSION:
            throw new UnsupportedOperationException(
                "the v1Expression function can't be used in templates compiled to Java");
          case TO_FLOAT:
            return visitToFloatFunction(node);
          case DEBUG_SOY_TEMPLATE_INFO:
            return BooleanData.forValue(debugSoyTemplateInfo);
          case VE_DATA:
            return NullData.INSTANCE;
          case MSG_WITH_ID:
          case REMAINDER:
            // should have been removed earlier in the compiler
            throw new AssertionError();
        }
        throw new AssertionError();
      } else if (soyFunction instanceof SoyJavaFunction) {
        List<SoyValue> args = this.visitChildren(node);
        SoyJavaFunction fn = (SoyJavaFunction) soyFunction;
        // Note: Arity has already been checked by CheckFunctionCallsVisitor.
        return computeFunctionHelper(fn, args, node);
      } else if (soyFunction instanceof SoyJavaSourceFunction) {
        List<SoyValue> args = this.visitChildren(node);
        SoyJavaSourceFunction fn = (SoyJavaSourceFunction) soyFunction;
        // Note: Arity has already been checked by CheckFunctionCallsVisitor.
        return computeFunctionHelper(fn, args, node);
      } else if (soyFunction instanceof LoggingFunction) {
        return StringData.forValue(((LoggingFunction) soyFunction).getPlaceholder());
      } else {
        throw RenderException.create(
            "Failed to find Soy function with name '"
                + node.getFunctionName()
                + "'"
                + " (function call \""
                + node.toSourceString()
                + "\").");
      }
    }