lib/integral.js
function _integral(expr, context, lastRuleComment) {
    var exprString = expr.toString({
      parenthesis: 'all',
      handler: function(node, options) {
        if(node.type === 'ParenthesisNode') {
          return '(' + node.content.toString(options) + ')';
        }
      }
    });

    var debugComment = lastRuleComment ? lastRuleComment + ": " : "";
    debugComment += "find integral of " + exprString + "  d" + context.variable.name;
    context.printDebug(debugComment);
    context.debugIndent++;

    // Check if we already tried to integrate this expression
    if(context.subIntegral[exprString] !== undefined) {
      // This could be null, indicating that we couldn't find an integral for
      // it (or we are currenly working on it a few levels of recursion up!)
      context.printDebug("Precomputed: " + context.subIntegral[exprString]);
      context.debugIndent--;
      return context.subIntegral[exprString];
    }

    // Remember that we are working on this integral, just haven't found a
    // solution yet!
    context.subIntegral[exprString] = null;

    for(var i = 0; i < context.rules.length; i++) {
      var result = context.rules[i](expr, context, _integral);
      if(result !== undefined && result !== null) {
        // Remember this solution!
        context.subIntegral[exprString] = result;

        context.printDebug("Computed: " + result.toString({parenthesis: 'all'}));
        context.debugIndent--;
        return result;
      }
    }

    // We couldn't find a solution :(
    context.printDebug("No integral found");
    context.debugIndent--;
    return null;
  }
function _integral(expr, context, lastRuleComment) {
    var exprString = expr.toString({
      parenthesis: 'all',
      handler: function(node, options) {
        if(node.type === 'ParenthesisNode') {
          return '(' + node.content.toString(options) + ')';
        }
      }
    });

    var debugComment = lastRuleComment ? lastRuleComment + ": " : "";
    debugComment += "find integral of " + exprString + "  d" + context.variable.name;
    context.printDebug(debugComment);
    context.debugIndent++;

    // Check if we already tried to integrate this expression
    if(context.subIntegral[exprString] !== undefined) {
      // This could be null, indicating that we couldn't find an integral for
      // it (or we are currenly working on it a few levels of recursion up!)
      context.printDebug("Precomputed: " + context.subIntegral[exprString]);
      context.debugIndent--;
      return context.subIntegral[exprString];
    }

    // Remember that we are working on this integral, just haven't found a
    // solution yet!
    context.subIntegral[exprString] = null;

    for(var i = 0; i < context.rules.length; i++) {
      var result = context.rules[i](expr, context, _integral);
      if(result !== undefined && result !== null) {
        // Remember this solution!
        context.subIntegral[exprString] = result;

        context.printDebug("Computed: " + result.toString({parenthesis: 'all'}));
        context.debugIndent--;
        return result;
      }
    }

    // We couldn't find a solution :(
    context.printDebug("No integral found");
    context.debugIndent--;
    return null;
  }
Helper function that runs the main loop for the integrator. It scans over the
rules until one of them produces an integral or until no more rules are left.

@param {Node} expr The expression to be integrated.
@param {IntegrationContext}