whole_func_string: function(expr, context, subIntegral) {
        if(expr.type === "OperatorNode" && expr.op === "*") {
          var factors = getFactors(expr);
          if(factors.length > expr.args.length) {
            return subIntegral(new OperatorNode('*', 'multiply', factors), context, "product flattening");
          }
        }
  
        function getFactors(expr) {
          if(expr.type === "OperatorNode" && expr.op === "*") {
            return expr.args.reduce(function(factors, expr) {
              return factors.concat(getFactors(expr));
            }, []);
          } else if (expr.type === "ParenthesisNode") {
            return getFactors(expr.content)
          } else {
            return [expr];
          }
        }
      }
func_code_string: function(expr, context, subIntegral) {
        if(expr.type === "OperatorNode" && expr.op === "*") {
          var factors = getFactors(expr);
          if(factors.length > expr.args.length) {
            return subIntegral(new OperatorNode('*', 'multiply', factors), context, "product flattening");
          }
        }
  
        function getFactors(expr) {
          if(expr.type === "OperatorNode" && expr.op === "*") {
            return expr.args.reduce(function(factors, expr) {
              return factors.concat(getFactors(expr));
            }, []);
          } else if (expr.type === "ParenthesisNode") {
            return getFactors(expr.content)
          } else {
            return [expr];
          }
        }
      }
func_documentation_string: integral(f(x) * (g(x) * h(x)), x) = integral(f(x) * g(x) * h(x), x)