StatusWithExpression ExpressionParser::_parseNot( const char* name,
                                                      const BSONElement& e ) {
        if ( e.type() == RegEx ) {
            StatusWithExpression s = _parseRegexElement( name, e );
            if ( !s.isOK() )
                return s;
            std::auto_ptr<NotExpression> n( new NotExpression() );
            Status s2 = n->init( s.getValue() );
            if ( !s2.isOK() )
                return StatusWithExpression( s2 );
            return StatusWithExpression( n.release() );
        }

        if ( e.type() != Object )
            return StatusWithExpression( ErrorCodes::BadValue, "$not needs a regex or a document" );

        std::auto_ptr<AndExpression> theAnd( new AndExpression() );
        Status s = _parseSub( name, e.Obj(), theAnd.get() );
        if ( !s.isOK() )
            return StatusWithExpression( s );

        std::auto_ptr<NotExpression> theNot( new NotExpression() );
        s = theNot->init( theAnd.release() );
        if ( !s.isOK() )
            return StatusWithExpression( s );

        return StatusWithExpression( theNot.release() );
    }
StatusWithMatchExpression MatchExpressionParser::_parseNot(const char* name,
                                                           const BSONElement& e,
                                                           const CollatorInterface* collator,
                                                           int level) {
    if (e.type() == RegEx) {
        StatusWithMatchExpression s = _parseRegexElement(name, e);
        if (!s.isOK())
            return s;
        std::unique_ptr<NotMatchExpression> n = stdx::make_unique<NotMatchExpression>();
        Status s2 = n->init(s.getValue().release());
        if (!s2.isOK())
            return StatusWithMatchExpression(s2);
        return {std::move(n)};
    }

    if (e.type() != Object)
        return StatusWithMatchExpression(ErrorCodes::BadValue, "$not needs a regex or a document");

    BSONObj notObject = e.Obj();
    if (notObject.isEmpty())
        return StatusWithMatchExpression(ErrorCodes::BadValue, "$not cannot be empty");

    std::unique_ptr<AndMatchExpression> theAnd = stdx::make_unique<AndMatchExpression>();
    Status s = _parseSub(name, notObject, theAnd.get(), collator, level);
    if (!s.isOK())
        return StatusWithMatchExpression(s);

    // TODO: this seems arbitrary?
    // tested in jstests/not2.js
    for (unsigned i = 0; i < theAnd->numChildren(); i++)
        if (theAnd->getChild(i)->matchType() == MatchExpression::REGEX)
            return StatusWithMatchExpression(ErrorCodes::BadValue, "$not cannot have a regex");

    std::unique_ptr<NotMatchExpression> theNot = stdx::make_unique<NotMatchExpression>();
    s = theNot->init(theAnd.release());
    if (!s.isOK())
        return StatusWithMatchExpression(s);

    return {std::move(theNot)};
}
    StatusWithMatchExpression MatchExpressionParser::_parse( const BSONObj& obj, bool topLevel ) {

        std::auto_ptr<AndMatchExpression> root( new AndMatchExpression() );

        BSONObjIterator i( obj );
        while ( i.more() ){

            BSONElement e = i.next();
            if ( e.fieldName()[0] == '$' ) {
                const char * rest = e.fieldName() + 1;

                // TODO: optimize if block?
                if ( mongoutils::str::equals( "or", rest ) ) {
                    if ( e.type() != Array )
                        return StatusWithMatchExpression( ErrorCodes::BadValue,
                                                     "$or needs an array" );
                    std::auto_ptr<OrMatchExpression> temp( new OrMatchExpression() );
                    Status s = _parseTreeList( e.Obj(), temp.get() );
                    if ( !s.isOK() )
                        return StatusWithMatchExpression( s );
                    root->add( temp.release() );
                }
                else if ( mongoutils::str::equals( "and", rest ) ) {
                    if ( e.type() != Array )
                        return StatusWithMatchExpression( ErrorCodes::BadValue,
                                                     "and needs an array" );
                    std::auto_ptr<AndMatchExpression> temp( new AndMatchExpression() );
                    Status s = _parseTreeList( e.Obj(), temp.get() );
                    if ( !s.isOK() )
                        return StatusWithMatchExpression( s );
                    root->add( temp.release() );
                }
                else if ( mongoutils::str::equals( "nor", rest ) ) {
                    if ( e.type() != Array )
                        return StatusWithMatchExpression( ErrorCodes::BadValue,
                                                     "and needs an array" );
                    std::auto_ptr<NorMatchExpression> temp( new NorMatchExpression() );
                    Status s = _parseTreeList( e.Obj(), temp.get() );
                    if ( !s.isOK() )
                        return StatusWithMatchExpression( s );
                    root->add( temp.release() );
                }
                else if ( mongoutils::str::equals( "atomic", rest ) || 
                          mongoutils::str::equals( "isolated", rest ) ) {
                    if ( !topLevel )
                        return StatusWithMatchExpression( ErrorCodes::BadValue,
                                                          "$atomic/$isolated has to be at the top level" );
                    if ( e.trueValue() )
                        root->add( new AtomicMatchExpression() );
                }
                else if ( mongoutils::str::equals( "where", rest ) ) {
                    /*
                    if ( !topLevel )
                        return StatusWithMatchExpression( ErrorCodes::BadValue,
                                                          "$where has to be at the top level" );
                    */
                    StatusWithMatchExpression s = expressionParserWhereCallback( e );
                    if ( !s.isOK() )
                        return s;
                    root->add( s.getValue() );
                }
                else if ( mongoutils::str::equals( "text", rest ) ) {
                    if ( e.type() != Object ) {
                        return StatusWithMatchExpression( ErrorCodes::BadValue,
                                                          "$text expects an object" );
                    }
                    StatusWithMatchExpression s = expressionParserTextCallback( e.Obj() );
                    if ( !s.isOK() ) {
                        return s;
                    }
                    root->add( s.getValue() );
                }
                else if ( mongoutils::str::equals( "comment", rest ) ) {
                }
                else {
                    return StatusWithMatchExpression( ErrorCodes::BadValue,
                                                 mongoutils::str::stream()
                                                 << "unknown top level operator: "
                                                 << e.fieldName() );
                }

                continue;
            }

            if ( _isExpressionDocument( e ) ) {
                Status s = _parseSub( e.fieldName(), e.Obj(), root.get() );
                if ( !s.isOK() )
                    return StatusWithMatchExpression( s );
                continue;
            }

            if ( e.type() == RegEx ) {
                StatusWithMatchExpression result = _parseRegexElement( e.fieldName(), e );
                if ( !result.isOK() )
                    return result;
                root->add( result.getValue() );
                continue;
            }

            std::auto_ptr<ComparisonMatchExpression> eq( new EqualityMatchExpression() );
            Status s = eq->init( e.fieldName(), e );
            if ( !s.isOK() )
                return StatusWithMatchExpression( s );

            root->add( eq.release() );
        }

        if ( root->numChildren() == 1 ) {
            const MatchExpression* real = root->getChild(0);
            root->clearAndRelease();
            return StatusWithMatchExpression( const_cast<MatchExpression*>(real) );
        }

        return StatusWithMatchExpression( root.release() );
    }