whole_func_string: 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;
    }
func_code_string: 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;
    }
func_documentation_string: 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}