lib/integral.js
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");
        }
      }
    }
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");
        }
      }
    }
integral(f(x) * (g(x) + h(x)), x) = integral(f(x) * g(x) + f(x) * h(x), x)