whole_func_string: function(expr, context, subIntegral) {
        if(expr.type === "OperatorNode" && expr.op === '*') {
          var sumNode = null;
          var otherFactors = null;
          for(var i = 0; i < expr.args.length; i++) {
            if(expr.args[i].type === "OperatorNode" && (expr.args[i].op === '+' || expr.args[i].op === '-'))  {
              sumNode = expr.args[i];
              otherFactors = expr.args.filter(function(expr, index) { return index !== i; });
              break;
            }
          }
  
          if(sumNode !== null) {
            var newTerms = sumNode.args.map(function(term) {
              return new OperatorNode('*', 'multiply', otherFactors.concat([term]));
            });
            return subIntegral(new OperatorNode(sumNode.op, sumNode.fn, newTerms), context, "product distribution");
          }
        }
      }
func_code_string: function(expr, context, subIntegral) {
        if(expr.type === "OperatorNode" && expr.op === '*') {
          var sumNode = null;
          var otherFactors = null;
          for(var i = 0; i < expr.args.length; i++) {
            if(expr.args[i].type === "OperatorNode" && (expr.args[i].op === '+' || expr.args[i].op === '-'))  {
              sumNode = expr.args[i];
              otherFactors = expr.args.filter(function(expr, index) { return index !== i; });
              break;
            }
          }
  
          if(sumNode !== null) {
            var newTerms = sumNode.args.map(function(term) {
              return new OperatorNode('*', 'multiply', otherFactors.concat([term]));
            });
            return subIntegral(new OperatorNode(sumNode.op, sumNode.fn, newTerms), context, "product distribution");
          }
        }
      }
func_documentation_string: integral(f(x) * (g(x) + h(x)), x) = integral(f(x) * g(x) + f(x) * h(x), x)