docs: @Override
    protected Expression visitFunctionNode(FunctionNode node) {
      Object soyFunction = node.getSoyFunction();
  
      if (soyFunction instanceof BuiltinFunction) {
        switch ((BuiltinFunction) soyFunction) {
          case IS_FIRST:
            return visitIsFirstFunction(node);
          case IS_LAST:
            return visitIsLastFunction(node);
          case INDEX:
            return visitIndexFunction(node);
          case CHECK_NOT_NULL:
            return visitCheckNotNullFunction(node);
          case CSS:
            return visitCssFunction(node);
          case XID:
            return visitXidFunction(node);
          case V1_EXPRESSION:
            return visitV1ExpressionFunction(node);
          case IS_PRIMARY_MSG_IN_USE:
            return visitIsPrimaryMsgInUseFunction(node);
          case TO_FLOAT:
            // this is a no-op in js
            return visit(node.getChild(0));
          case DEBUG_SOY_TEMPLATE_INFO:
            return GOOG_DEBUG.and(JsRuntime.SOY_DEBUG_SOY_TEMPLATE_INFO, codeGenerator);
          case VE_DATA:
            return visitVeDataFunction(node);
          case REMAINDER:
          case MSG_WITH_ID:
            // should have been removed earlier in the compiler
            throw new AssertionError();
        }
        throw new AssertionError();
  
      } else if (soyFunction instanceof LoggingFunction) {
        return stringLiteral(((LoggingFunction) soyFunction).getPlaceholder());
      } else if (soyFunction instanceof SoyJavaScriptSourceFunction) {
        return javascriptValueFactory.applyFunction(
            node.getSourceLocation(),
            node.getFunctionName(),
            (SoyJavaScriptSourceFunction) soyFunction,
            visitChildren(node),
            codeGenerator);
      } else {
        if (!(soyFunction instanceof SoyJsSrcFunction)) {
          errorReporter.report(
              node.getSourceLocation(),
              SOY_JS_SRC_FUNCTION_NOT_FOUND,
              node.getFunctionName(),
              soyFunction == null ? "missing implementation" : soyFunction.getClass().getName());
          // use a fake function and keep going
          soyFunction = getUnknownFunction(node.getFunctionName(), node.numChildren());
        }
  
        return SoyJsPluginUtils.applySoyFunction(
            (SoyJsSrcFunction) soyFunction,
            visitChildren(node),
            node.getSourceLocation(),
            errorReporter);
      }
    }