Bläddra i källkod

Refs #3357. Port of MatchExpressionParser.

Spencer Rathbun 12 år sedan
förälder
incheckning
c8df32c8b7
2 ändrade filer med 591 tillägg och 721 borttagningar
  1. 2 0
      lib/pipeline/matcher/CLUDGES
  2. 589 721
      lib/pipeline/matcher/MatchExpressionParser.js

+ 2 - 0
lib/pipeline/matcher/CLUDGES

@@ -7,6 +7,8 @@ isAllDigits -> ElementPath.isAllDigits ( now static function )
 
 Status objects are now generic objects having a 'code' property that is a string of the error code that mongo uses (e.g. {code:'OK'}).
 
+StatusWith is now rolled into status as a result field. status.getValue() is now status.result
+
 debugString takes one argument 'level', as does debugAddSpace. Debug statements are printed to console.debug()
 
 

+ 589 - 721
lib/pipeline/matcher/MatchExpressionParser.js

@@ -1,836 +1,704 @@
-"use strict"
-
-
+"use strict";
 
 // Autogenerated by cport.py on 2013-09-17 14:37
 var MatchExpressionParser = module.exports = function (){
 
 }, klass = MatchExpressionParser, base =  Object  , proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
 
-
-
-
+// DEPENDENCIES
+var errors = require("../../Errors.js"),
+	ErrorCodes = errors.ErrorCodes,
+	AndMatchExpression = require("./AndMatchExpression.js"),
+	MatchExpression = require("./MatchExpression.js"),
+	OrMatchExpression = require("./OrMatchExpression.js"),
+	ModMatchExpression = require("./ModMatchExpression.js"),
+	NorMatchExpression = require("./NorMatchExpression.js"),
+	NotMatchExpression = require("./NotMatchExpression.js"),
+	LTMatchExpression = require("./LTMatchExpression.js"),
+	LTEMatchExpression = require("./LTEMatchExpression.js"),
+	GTMatchExpression = require("./GTMatchExpression.js"),
+	GTEMatchExpression = require("./GTEMatchExpression.js"),
+	InMatchExpression = require("./InMatchExpression.js"),
+	SizeMatchExpression = require("./SizeMatchExpression.js"),
+	TypeMatchExpression = require("./TypeMatchExpression.js"),
+	ExistsMatchExpression = require("./ExistsMatchExpression.js"),
+	EqualityMatchExpression = require("./EqualityMatchExpression.js"),
+	ArrayMatchingMatchExpression = require("./ArrayMatchingMatchExpression.js"),
+	RegexMatchExpression = require("./RegexMatchExpression.js"),
+	FalseMatchExpression = require("./FalseMatchExpression.js"),
+	ComparisonMatchExpression = require("./ComparisonMatchExpression.js"),
+	ElemMatchValueMatchExpression = require("./ElemMatchValueMatchExpression.js"),
+	ElemMatchObjectMatchExpression = require("./ElemMatchObjectMatchExpression.js"),
+	AllElemMatchOp = require("./AllElemMatchOp.js"),
+	AtomicMatchExpression = require("./AtomicMatchExpression.js");
 
 /**
- * 
+ *
  * This documentation was automatically generated. Please update when you touch this function.
  * @method _isExpressionDocument
  * @param
  *
  */
-proto._isExpressionDocument = function _isExpressionDocument( /*  const BSONElement& e  */ ){
-
-// File: expression_parser.cpp lines: 340-355
-//     bool MatchExpressionParser::_isExpressionDocument( const BSONElement& e ) {
-//         if ( e.type() != Object )
-//             return false;
-// 
-//         BSONObj o = e.Obj();
-//         if ( o.isEmpty() )
-//             return false;
-// 
-//         const char* name = o.firstElement().fieldName();
-//         if ( name[0] != '$' )
-//             return false;
-// 
-//         if ( mongoutils::str::equals( "$ref", name ) )
-//             return false;
-// 
-//         return true;
-//     }
+proto._isExpressionDocument = function _isExpressionDocument(element){
+	// File: expression_parser.cpp lines: 340-355
+	if (!(element instanceof Object))
+		return false;
 
+	if (element.isEmpty())
+		return false;
 
+	var name = element.keys()[0];
+	if (name[0] != '$')
+		return false;
 
-}
+	if ("$ref" == name)
+		return false;
 
+	return true;
+};
 
 /**
- * 
+ *
  * This documentation was automatically generated. Please update when you touch this function.
  * @method _parse
  * @param
  *
  */
-proto._parse = function _parse( /*  const BSONObj& obj, bool topLevel  */ ){
-
-// File: expression_parser.cpp lines: 217-319
-//     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( "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() );
-//     }
-
-
-
-}
-
+proto._parse = function _parse(obj, topLevel){
+	// File: expression_parser.cpp lines: 217-319
+	var rest, temp, status, element, eq, real;
+	var root = new AndMatchExpression();
+
+	for (var i = 0; i < obj.length; i++) {
+		element = obj[i];
+		if (element[0] == '$' ) {
+			rest = element.substr(1, element.length);
+
+			// TODO: optimize if block?
+			if ("or" == rest) {
+				if (!(element instanceof Array))
+					return {code:ErrorCodes.BadValue, description:"$or needs an array"};
+				temp = new OrMatchExpression();
+				status = this._parseTreeList(element, temp.get());
+				if (status.code != ErrorCodes.OK)
+					return status;
+				root.add(temp.release());
+			}
+			else if ("and" == rest) {
+				if (!(element instanceof Array))
+					return {code:ErrorCodes.BadValue, description:"and needs an array"};
+				temp = new AndMatchExpression();
+				status = this._parseTreeList(element, temp.get());
+				if (status.code != ErrorCodes.OK)
+					return status;
+				root.add(temp.release());
+			}
+			else if ("nor" == rest) {
+				if (!(element instanceof Array))
+					return {code:ErrorCodes.BadValue, description:"and needs an array"};
+				temp = new NorMatchExpression();
+				status = this._parseTreeList(element, temp.get());
+				if (status.code != ErrorCodes.OK)
+					return status;
+				root.add(temp.release());
+			}
+			else if (("atomic" == rest) || ("isolated" == rest)) {
+				if (!topLevel)
+					return {code:ErrorCodes.BadValue, description:"$atomic/$isolated has to be at the top level"};
+				if (element)
+					root.add(new AtomicMatchExpression());
+			}
+			else if ("where" == rest) {
+				/*
+				if ( !topLevel )
+					return StatusWithMatchExpression( ErrorCodes::BadValue, "$where has to be at the top level" );
+				*/
+				status = this.expressionParserWhereCallback(element);
+				if (status.code != ErrorCodes.OK)
+					return status;
+				root.add(status.result);
+			}
+			else if ("comment" == rest) {
+			}
+			else {
+				return {code:ErrorCodes.BadValue, description:"unknown top level operator: " + element};
+			}
+
+			continue;
+		}
+
+		if (this._isExpressionDocument(element)) {
+			status = this._parseSub(element, element, root.get());
+			if (status.code != ErrorCodes.OK)
+				return status;
+			continue;
+		}
+
+		if (element instanceof RegExp) {
+			status = this._parseRegexElement(element, element);
+			if (status.code != ErrorCodes.OK)
+				return status;
+			root.add(status.result);
+			continue;
+		}
+
+		eq = new EqualityMatchExpression();
+		status = eq.init(element, element);
+		if (status.code != ErrorCodes.OK)
+			return status;
+
+		root.add(eq.release());
+	}
+
+	if (root.numChildren() == 1) {
+		real = new MatchExpression(root.getChild(0));
+		root.clearAndRelease();
+		return {code:ErrorCodes.OK, result:real};
+	}
+
+	return {code:ErrorCodes.OK, result:root.release()};
+};
 
 /**
- * 
+ *
  * This documentation was automatically generated. Please update when you touch this function.
  * @method _parseAll
  * @param
  *
  */
-proto._parseAll = function _parseAll( /*  const char* name,$/;" */ ){
-
-// File: expression_parser.cpp lines: 512-583
-//     StatusWithMatchExpression MatchExpressionParser::_parseAll( const char* name,
-//                                                       const BSONElement& e ) {
-//         if ( e.type() != Array )
-//             return StatusWithMatchExpression( ErrorCodes::BadValue, "$all needs an array" );
-// 
-//         BSONObj arr = e.Obj();
-//         if ( arr.firstElement().type() == Object &&
-//              mongoutils::str::equals( "$elemMatch",
-//                                       arr.firstElement().Obj().firstElement().fieldName() ) ) {
-//             // $all : [ { $elemMatch : {} } ... ]
-// 
-//             std::auto_ptr<AllElemMatchOp> temp( new AllElemMatchOp() );
-//             Status s = temp->init( name );
-//             if ( !s.isOK() )
-//                 return StatusWithMatchExpression( s );
-// 
-//             BSONObjIterator i( arr );
-//             while ( i.more() ) {
-//                 BSONElement hopefullyElemMatchElement = i.next();
-// 
-//                 if ( hopefullyElemMatchElement.type() != Object ) {
-//                     // $all : [ { $elemMatch : ... }, 5 ]
-//                     return StatusWithMatchExpression( ErrorCodes::BadValue,
-//                                                  "$all/$elemMatch has to be consistent" );
-//                 }
-// 
-//                 BSONObj hopefullyElemMatchObj = hopefullyElemMatchElement.Obj();
-//                 if ( !mongoutils::str::equals( "$elemMatch",
-//                                                hopefullyElemMatchObj.firstElement().fieldName() ) ) {
-//                     // $all : [ { $elemMatch : ... }, { x : 5 } ]
-//                     return StatusWithMatchExpression( ErrorCodes::BadValue,
-//                                                  "$all/$elemMatch has to be consistent" );
-//                 }
-// 
-//                 StatusWithMatchExpression inner = _parseElemMatch( "", hopefullyElemMatchObj.firstElement() );
-//                 if ( !inner.isOK() )
-//                     return inner;
-//                 temp->add( static_cast<ArrayMatchingMatchExpression*>( inner.getValue() ) );
-//             }
-// 
-//             return StatusWithMatchExpression( temp.release() );
-//         }
-// 
-//         std::auto_ptr<AndMatchExpression> myAnd( new AndMatchExpression() );
-//         BSONObjIterator i( arr );
-//         while ( i.more() ) {
-//             BSONElement e = i.next();
-// 
-//             if ( e.type() == RegEx ) {
-//                 std::auto_ptr<RegexMatchExpression> r( new RegexMatchExpression() );
-//                 Status s = r->init( name, e );
-//                 if ( !s.isOK() )
-//                     return StatusWithMatchExpression( s );
-//                 myAnd->add( r.release() );
-//             }
-//             else if ( e.type() == Object && e.Obj().firstElement().getGtLtOp(-1) != -1 ) {
-//                 return StatusWithMatchExpression( ErrorCodes::BadValue, "no $ expressions in $all" );
-//             }
-//             else {
-//                 std::auto_ptr<EqualityMatchExpression> x( new EqualityMatchExpression() );
-//                 Status s = x->init( name, e );
-//                 if ( !s.isOK() )
-//                     return StatusWithMatchExpression( s );
-//                 myAnd->add( x.release() );
-//             }
-//         }
-// 
-//         if ( myAnd->numChildren() == 0 ) {
-//             return StatusWithMatchExpression( new FalseMatchExpression() );
-//         }
-// 
-//         return StatusWithMatchExpression( myAnd.release() );
-//     }
-
-
-
-}
-
+proto._parseAll = function _parseAll(name, element){
+	// File: expression_parser.cpp lines: 512-583
+	var status, i;
+
+	if (!(element instanceof Array))
+		return {code:ErrorCodes.BadValue, description:"$all needs an array"};
+
+	var arr = element;
+	if ((arr[0] instanceof Object) && ("$elemMatch" == arr[0].keys()[0])) {
+		// $all : [ { $elemMatch : {} } ... ]
+
+		var temp = new AllElemMatchOp();
+		status = temp.init(name);
+		if (status.code != ErrorCodes.OK)
+			return status;
+
+		for (i = 0; i < arr.length; i++) {
+			var hopefullyElemMatchElement = arr[i];
+
+			if (!(hopefullyElemMatchElement instanceof Object)) {
+				// $all : [ { $elemMatch : ... }, 5 ]
+				return {code:ErrorCodes.BadValue, description:"$all/$elemMatch has to be consistent"};
+			}
+
+			if ("$elemMatch" != hopefullyElemMatchElement.keys()[0]) {
+				// $all : [ { $elemMatch : ... }, { x : 5 } ]
+				return {code:ErrorCodes.BadValue, description:"$all/$elemMatch has to be consistent"};
+			}
+
+			status = this._parseElemMatch("", hopefullyElemMatchElement[hopefullyElemMatchElement.keys()[0]]); // TODO: wrong way to do this?
+			if (status.code != ErrorCodes.OK)
+				return status;
+			temp.add(new ArrayMatchingMatchExpression(status.result));
+		}
+
+		return {code:ErrorCodes.OK, result:temp.release()};
+	}
+
+	var myAnd = new AndMatchExpression();
+	for (i = 0; i < arr.length; i++) {
+		var e = arr[i];
+
+		if (e instanceof RegExp) {
+			var r = new RegexMatchExpression();
+			status = r.init(name, e);
+			if (status.code != ErrorCodes.OK)
+				return status;
+			myAnd.add(r.release());
+		}
+		else if ((e instanceof Object) && (e.keys()[0].getGtLtOp(-1) != -1)) {
+			return {code:ErrorCodes.BadValue, description:"no $ expressions in $all"};
+		}
+		else {
+			var x = new EqualityMatchExpression();
+			status = x.init(name, e);
+			if (status.code != ErrorCodes.OK)
+				return status;
+			myAnd.add(x.release());
+		}
+	}
+
+	if (myAnd.numChildren() === 0) {
+		return {code:ErrorCodes.OK, result:new FalseMatchExpression()};
+	}
+
+	return {code:ErrorCodes.OK, result:myAnd.release()};
+};
 
 /**
- * 
+ *
  * This documentation was automatically generated. Please update when you touch this function.
  * @method _parseArrayFilterEntries
  * @param
  *
  */
-proto._parseArrayFilterEntries = function _parseArrayFilterEntries( /*  ArrayFilterEntries* entries,$/;" */ ){
-
-// File: expression_parser.cpp lines: 445-468
-//     Status MatchExpressionParser::_parseArrayFilterEntries( ArrayFilterEntries* entries,
-//                                                             const BSONObj& theArray ) {
-// 
-//         BSONObjIterator i( theArray );
-//         while ( i.more() ) {
-//             BSONElement e = i.next();
-// 
-//             if ( e.type() == RegEx ) {
-//                 std::auto_ptr<RegexMatchExpression> r( new RegexMatchExpression() );
-//                 Status s = r->init( "", e );
-//                 if ( !s.isOK() )
-//                     return s;
-//                 s =  entries->addRegex( r.release() );
-//                 if ( !s.isOK() )
-//                     return s;
-//             }
-//             else {
-//                 Status s = entries->addEquality( e );
-//                 if ( !s.isOK() )
-//                     return s;
-//             }
-//         }
-//         return Status::OK();
-// 
-//     }
-
-
-
-}
-
+proto._parseArrayFilterEntries = function _parseArrayFilterEntries(entries, theArray){
+	// File: expression_parser.cpp lines: 445-468
+	var status, e, r;
+	for (var i = 0; i < theArray.length; i++) {
+		e = theArray[i];
+
+		if (e instanceof RegExp ) {
+			r = new RegexMatchExpression();
+			status = r.init("", e);
+			if (status.code != ErrorCodes.OK)
+				return status;
+			status = entries.addRegex(r.release());
+			if (status.code != ErrorCodes.OK)
+				return status;
+		}
+		else {
+			status = entries.addEquality(e);
+			if (status.code != ErrorCodes.OK)
+				return status;
+		}
+	}
+	return {code:ErrorCodes.OK};
+};
 
 /**
- * 
+ *
  * This documentation was automatically generated. Please update when you touch this function.
  * @method _parseComparison
  * @param
  *
  */
-proto._parseComparison = function _parseComparison( /*  const char* name,$/;" */ ){
-
-// File: expression_parser.cpp lines: 34-43
-//     StatusWithMatchExpression MatchExpressionParser::_parseComparison( const char* name,
-//                                                                        ComparisonMatchExpression* cmp,
-//                                                                        const BSONElement& e ) {
-//         std::auto_ptr<ComparisonMatchExpression> temp( cmp );
-// 
-//         Status s = temp->init( name, e );
-//         if ( !s.isOK() )
-//             return StatusWithMatchExpression(s);
-// 
-//         return StatusWithMatchExpression( temp.release() );
-//     }
-
-
+proto._parseComparison = function _parseComparison(name, cmp, element){
+	// File: expression_parser.cpp lines: 34-43
+	var temp = new ComparisonMatchExpression(cmp);
 
-}
+	var status = temp.init(name, element);
+	if (status.code != ErrorCodes.OK)
+		return status;
 
+	return {code:ErrorCodes.OK, result:temp.release()};
+};
 
 /**
- * 
+ *
  * This documentation was automatically generated. Please update when you touch this function.
  * @method _parseElemMatch
  * @param
  *
  */
-proto._parseElemMatch = function _parseElemMatch( /*  const char* name,$/;" */ ){
-
-// File: expression_parser.cpp lines: 471-509
-//     StatusWithMatchExpression MatchExpressionParser::_parseElemMatch( const char* name,
-//                                                             const BSONElement& e ) {
-//         if ( e.type() != Object )
-//             return StatusWithMatchExpression( ErrorCodes::BadValue, "$elemMatch needs an Object" );
-// 
-//         BSONObj obj = e.Obj();
-//         if ( _isExpressionDocument( e ) ) {
-//             // value case
-// 
-//             AndMatchExpression theAnd;
-//             Status s = _parseSub( "", obj, &theAnd );
-//             if ( !s.isOK() )
-//                 return StatusWithMatchExpression( s );
-// 
-//             std::auto_ptr<ElemMatchValueMatchExpression> temp( new ElemMatchValueMatchExpression() );
-//             s = temp->init( name );
-//             if ( !s.isOK() )
-//                 return StatusWithMatchExpression( s );
-// 
-//             for ( size_t i = 0; i < theAnd.numChildren(); i++ ) {
-//                 temp->add( theAnd.getChild( i ) );
-//             }
-//             theAnd.clearAndRelease();
-// 
-//             return StatusWithMatchExpression( temp.release() );
-//         }
-// 
-//         // object case
-// 
-//         StatusWithMatchExpression sub = _parse( obj, false );
-//         if ( !sub.isOK() )
-//             return sub;
-// 
-//         std::auto_ptr<ElemMatchObjectMatchExpression> temp( new ElemMatchObjectMatchExpression() );
-//         Status status = temp->init( name, sub.getValue() );
-//         if ( !status.isOK() )
-//             return StatusWithMatchExpression( status );
-// 
-//         return StatusWithMatchExpression( temp.release() );
-//     }
-
-
-
-}
+proto._parseElemMatch = function _parseElemMatch(name, element){
+	// File: expression_parser.cpp lines: 471-509
+	var temp, status;
+	if (!(element instanceof Object))
+		return {code:ErrorCodes.BadValue, description:"$elemMatch needs an Object"};
+
+	if (this._isExpressionDocument(element)) {
+		// value case
+
+		var theAnd = new AndMatchExpression();
+		status = this._parseSub("", element, theAnd);
+		if (status.code != ErrorCodes.OK)
+			return status;
+
+		temp = new ElemMatchValueMatchExpression();
+		status = temp.init(name);
+		if (status.code != ErrorCodes.OK)
+			return status;
+
+		for (var i = 0; i < theAnd.numChildren(); i++ ) {
+			temp.add(theAnd.getChild(i));
+		}
+		theAnd.clearAndRelease();
+
+		return {code:ErrorCodes.OK, result:temp.release()};
+	}
+
+	// object case
+
+	status = this._parse(element, false);
+	if (status.code != ErrorCodes.OK)
+		return status;
+
+	temp = new ElemMatchObjectMatchExpression();
+	status = temp.init(name, status.result);
+	if (status.code != ErrorCodes.OK)
+		return status;
 
+	return {code:ErrorCodes.OK, result:temp.release()};
+};
 
 /**
- * 
+ *
  * This documentation was automatically generated. Please update when you touch this function.
  * @method _parseMOD
  * @param
  *
  */
-proto._parseMOD = function _parseMOD( /*  const char* name,$/;" */ ){
-
-// File: expression_parser.cpp lines: 360-387
-//     StatusWithMatchExpression MatchExpressionParser::_parseMOD( const char* name,
-//                                                       const BSONElement& e ) {
-// 
-//         if ( e.type() != Array )
-//             return StatusWithMatchExpression( ErrorCodes::BadValue, "malformed mod, needs to be an array" );
-// 
-//         BSONObjIterator i( e.Obj() );
-// 
-//         if ( !i.more() )
-//             return StatusWithMatchExpression( ErrorCodes::BadValue, "malformed mod, not enough elements" );
-//         BSONElement d = i.next();
-//         if ( !d.isNumber() )
-//             return StatusWithMatchExpression( ErrorCodes::BadValue, "malformed mod, divisor not a number" );
-// 
-//         if ( !i.more() )
-//             return StatusWithMatchExpression( ErrorCodes::BadValue, "malformed mod, not enough elements" );
-//         BSONElement r = i.next();
-//         if ( !d.isNumber() )
-//             return StatusWithMatchExpression( ErrorCodes::BadValue, "malformed mod, remainder not a number" );
-// 
-//         if ( i.more() )
-//             return StatusWithMatchExpression( ErrorCodes::BadValue, "malformed mod, too many elements" );
-// 
-//         std::auto_ptr<ModMatchExpression> temp( new ModMatchExpression() );
-//         Status s = temp->init( name, d.numberInt(), r.numberInt() );
-//         if ( !s.isOK() )
-//             return StatusWithMatchExpression( s );
-//         return StatusWithMatchExpression( temp.release() );
-//     }
-
-
-
-}
-
+proto._parseMOD = function _parseMOD(name, element){
+	// File: expression_parser.cpp lines: 360-387
+
+	if (!(element instanceof Array))
+		return {code:ErrorCodes.BadValue, result:"malformed mod, needs to be an array"};
+	if (element.length < 2)
+		return {code:ErrorCodes.BadValue, result:"malformed mod, not enough elements"};
+	if (element.length > 2)
+		return {code:ErrorCodes.BadValue, result:"malformed mod, too many elements"};
+	if (!(element[0] instanceof Number))
+		return {code:ErrorCodes.BadValue, result:"malformed mod, divisor not a number"};
+	if (!(element[1] instanceof Number))
+		return {code:ErrorCodes.BadValue, result:"malformed mod, remainder not a number"};
+
+	var temp = new ModMatchExpression();
+	var status = temp.init( name, element[0], element[1]);
+	if (status.code != ErrorCodes.OK)
+		return status;
+
+	return {code:ErrorCodes.OK, result:temp.release()};
+};
 
 /**
- * 
+ *
  * This documentation was automatically generated. Please update when you touch this function.
  * @method _parseNot
  * @param
  *
  */
-proto._parseNot = function _parseNot( /*  const char* name,$/;" */ ){
-
-// File: expression_parser_tree.cpp lines: 55-91
-//     StatusWithMatchExpression MatchExpressionParser::_parseNot( const char* name,
-//                                                       const BSONElement& e ) {
-//         if ( e.type() == RegEx ) {
-//             StatusWithMatchExpression s = _parseRegexElement( name, e );
-//             if ( !s.isOK() )
-//                 return s;
-//             std::auto_ptr<NotMatchExpression> n( new NotMatchExpression() );
-//             Status s2 = n->init( s.getValue() );
-//             if ( !s2.isOK() )
-//                 return StatusWithMatchExpression( s2 );
-//             return StatusWithMatchExpression( n.release() );
-//         }
-// 
-//         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::auto_ptr<AndMatchExpression> theAnd( new AndMatchExpression() );
-//         Status s = _parseSub( name, notObject, theAnd.get() );
-//         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::auto_ptr<NotMatchExpression> theNot( new NotMatchExpression() );
-//         s = theNot->init( theAnd.release() );
-//         if ( !s.isOK() )
-//             return StatusWithMatchExpression( s );
-// 
-//         return StatusWithMatchExpression( theNot.release() );
-//     }
-
-
-
-}
-
+proto._parseNot = function _parseNot(name, element){
+	// File: expression_parser_tree.cpp lines: 55-91
+	var status;
+	if (element instanceof RegExp) {
+		status = this._parseRegexElement(name, element);
+		if (status.code != ErrorCodes.OK)
+			return status;
+		var n = new NotMatchExpression();
+		status = n.init(status.result);
+		if (status.code != ErrorCodes.OK)
+			return status;
+		return {code:ErrorCodes.OK, result:n.release()};
+	}
+
+	if (!(element instanceof Object))
+		return {code:ErrorCodes.BadValue, result:"$not needs a regex or a document"};
+
+	if (element == {})
+		return {code:ErrorCodes.BadValue, result:"$not cannot be empty"};
+
+	var theAnd = new AndMatchExpression();
+	status = this._parseSub(name, element, theAnd.get());
+	if (status.code != ErrorCodes.OK)
+		return status;
+
+	// TODO: this seems arbitrary?
+	// tested in jstests/not2.js
+	for (var i = 0; i < theAnd.numChildren(); i++)
+		if (theAnd.getChild(i).matchType == MatchExpression.REGEX)
+			return {code:ErrorCodes.BadValue, result:"$not cannot have a regex"};
+
+	var theNot = new NotMatchExpression();
+	status = theNot.init(theAnd.release());
+	if (status.code != ErrorCodes.OK)
+		return status;
+
+	return {code:ErrorCodes.OK, result:theNot.release()};
+};
 
 /**
- * 
+ *
  * This documentation was automatically generated. Please update when you touch this function.
  * @method _parseRegexDocument
  * @param
  *
  */
-proto._parseRegexDocument = function _parseRegexDocument( /*  const char* name,$/;" */ ){
-
-// File: expression_parser.cpp lines: 402-442
-//     StatusWithMatchExpression MatchExpressionParser::_parseRegexDocument( const char* name,
-//                                                                 const BSONObj& doc ) {
-//         string regex;
-//         string regexOptions;
-// 
-//         BSONObjIterator i( doc );
-//         while ( i.more() ) {
-//             BSONElement e = i.next();
-//             switch ( e.getGtLtOp() ) {
-//             case BSONObj::opREGEX:
-//                 if ( e.type() == String ) {
-//                     regex = e.String();
-//                 }
-//                 else if ( e.type() == RegEx ) {
-//                     regex = e.regex();
-//                     regexOptions = e.regexFlags();
-//                 }
-//                 else {
-//                     return StatusWithMatchExpression( ErrorCodes::BadValue,
-//                                                       "$regex has to be a string" );
-//                 }
-// 
-//                 break;
-//             case BSONObj::opOPTIONS:
-//                 if ( e.type() != String )
-//                     return StatusWithMatchExpression( ErrorCodes::BadValue,
-//                                                       "$options has to be a string" );
-//                 regexOptions = e.String();
-//                 break;
-//             default:
-//                 break;
-//             }
-// 
-//         }
-// 
-//         std::auto_ptr<RegexMatchExpression> temp( new RegexMatchExpression() );
-//         Status s = temp->init( name, regex, regexOptions );
-//         if ( !s.isOK() )
-//             return StatusWithMatchExpression( s );
-//         return StatusWithMatchExpression( temp.release() );
-// 
-//     }
-
-
-
-}
-
+proto._parseRegexDocument = function _parseRegexDocument(name, doc){
+	// File: expression_parser.cpp lines: 402-442
+	var regex, regexOptions, e;
+
+	for (var i = 0; i < doc.length; i++) {
+		e = doc[i];
+		switch (e.getGtLtOp()) {
+		case 'opREGEX':
+			if (e instanceof String) {
+				regex = e;
+			}
+			else if (e instanceof RegExp) {
+				var str = e.toString(),
+					flagIndex = 0;
+				for (var c = str.length; c > 0; c--){
+					if (str[c] == '/') {
+						flagIndex = c;
+						break;
+					}
+				}
+				regex = str.substr(1, flagIndex-1);
+				regexOptions = str.substr(flagIndex, str.length);
+			}
+			else {
+				return {code:ErrorCodes.BadValue, description:"$regex has to be a string"};
+			}
+
+			break;
+		case 'opOPTIONS':
+			if (!(e instanceof String))
+				return {code:ErrorCodes.BadValue, description:"$options has to be a string"};
+			regexOptions = e;
+			break;
+		default:
+			break;
+		}
+	}
+
+	var temp = new RegexMatchExpression();
+	var status = temp.init(name, regex, regexOptions);
+	if (status.code != ErrorCodes.OK)
+		return status;
+
+	return {code:ErrorCodes.OK, result:temp.release()};
+};
 
 /**
- * 
+ *
  * This documentation was automatically generated. Please update when you touch this function.
  * @method _parseRegexElement
  * @param
  *
  */
-proto._parseRegexElement = function _parseRegexElement( /*  const char* name,$/;" */ ){
-
-// File: expression_parser.cpp lines: 390-399
-//     StatusWithMatchExpression MatchExpressionParser::_parseRegexElement( const char* name,
-//                                                                const BSONElement& e ) {
-//         if ( e.type() != RegEx )
-//             return StatusWithMatchExpression( ErrorCodes::BadValue, "not a regex" );
-// 
-//         std::auto_ptr<RegexMatchExpression> temp( new RegexMatchExpression() );
-//         Status s = temp->init( name, e.regex(), e.regexFlags() );
-//         if ( !s.isOK() )
-//             return StatusWithMatchExpression( s );
-//         return StatusWithMatchExpression( temp.release() );
-//     }
-
-
-
-}
-
+proto._parseRegexElement = function _parseRegexElement(name, element){
+	// File: expression_parser.cpp lines: 390-399
+	if (!(element instanceof RegExp))
+		return {code:ErrorCodes.BadValue, description:"not a regex"};
+
+	var str = element.toString(),
+		flagIndex = 0;
+	for (var c = str.length; c > 0; c--){
+		if (str[c] == '/') {
+			flagIndex = c;
+			break;
+		}
+	}
+	var regex = str.substr(1, flagIndex-1),
+		regexOptions = str.substr(flagIndex, str.length),
+		temp = new RegexMatchExpression(),
+		status = temp.init(name, regex, regexOptions);
+
+	if (status.code != ErrorCodes.OK)
+		return status;
+
+	return {code:ErrorCodes.OK, result:temp.release()};
+};
 
 /**
- * 
+ *
  * This documentation was automatically generated. Please update when you touch this function.
  * @method _parseSub
  * @param
  *
  */
-proto._parseSub = function _parseSub( /*  const char* name,$/;" */ ){
+proto._parseSub = function _parseSub(name, sub, root){
+	// File: expression_parser.cpp lines: 322-337
+	for (var i = 0; i < sub.length; i++) {
+		var deep = sub[i];
 
-// File: expression_parser.cpp lines: 322-337
-//     Status MatchExpressionParser::_parseSub( const char* name,
-//                                              const BSONObj& sub,
-//                                              AndMatchExpression* root ) {
-//         BSONObjIterator j( sub );
-//         while ( j.more() ) {
-//             BSONElement deep = j.next();
-// 
-//             StatusWithMatchExpression s = _parseSubField( sub, root, name, deep );
-//             if ( !s.isOK() )
-//                 return s.getStatus();
-// 
-//             if ( s.getValue() )
-//                 root->add( s.getValue() );
-//         }
-// 
-//         return Status::OK();
-//     }
+		var status = this._parseSubField(sub, root, name, deep);
+		if (status.code != ErrorCodes.OK)
+			return status;
 
+		if (status.result)
+			root.add(status.result);
+	}
 
-
-}
-
+	return {code:ErrorCodes.OK};
+};
 
 /**
- * 
+ *
  * This documentation was automatically generated. Please update when you touch this function.
  * @method _parseSubField
  * @param
  *
  */
-proto._parseSubField = function _parseSubField( /*  const BSONObj& context,$/;" */ ){
-
-// File: expression_parser.cpp lines: 46-214
-//     StatusWithMatchExpression MatchExpressionParser::_parseSubField( const BSONObj& context,
-//                                                                      const AndMatchExpression* andSoFar,
-//                                                                      const char* name,
-//                                                                      const BSONElement& e ) {
-// 
-//         // TODO: these should move to getGtLtOp, or its replacement
-// 
-//         if ( mongoutils::str::equals( "$eq", e.fieldName() ) )
-//             return _parseComparison( name, new EqualityMatchExpression(), e );
-// 
-//         if ( mongoutils::str::equals( "$not", e.fieldName() ) ) {
-//             return _parseNot( name, e );
-//         }
-// 
-//         int x = e.getGtLtOp(-1);
-//         switch ( x ) {
-//         case -1:
-//             return StatusWithMatchExpression( ErrorCodes::BadValue,
-//                                               mongoutils::str::stream() << "unknown operator: "
-//                                               << e.fieldName() );
-//         case BSONObj::LT:
-//             return _parseComparison( name, new LTMatchExpression(), e );
-//         case BSONObj::LTE:
-//             return _parseComparison( name, new LTEMatchExpression(), e );
-//         case BSONObj::GT:
-//             return _parseComparison( name, new GTMatchExpression(), e );
-//         case BSONObj::GTE:
-//             return _parseComparison( name, new GTEMatchExpression(), e );
-//         case BSONObj::NE: {
-//             StatusWithMatchExpression s = _parseComparison( name, new EqualityMatchExpression(), e );
-//             if ( !s.isOK() )
-//                 return s;
-//             std::auto_ptr<NotMatchExpression> n( new NotMatchExpression() );
-//             Status s2 = n->init( s.getValue() );
-//             if ( !s2.isOK() )
-//                 return StatusWithMatchExpression( s2 );
-//             return StatusWithMatchExpression( n.release() );
-//         }
-//         case BSONObj::Equality:
-//             return _parseComparison( name, new EqualityMatchExpression(), e );
-// 
-//         case BSONObj::opIN: {
-//             if ( e.type() != Array )
-//                 return StatusWithMatchExpression( ErrorCodes::BadValue, "$in needs an array" );
-//             std::auto_ptr<InMatchExpression> temp( new InMatchExpression() );
-//             Status s = temp->init( name );
-//             if ( !s.isOK() )
-//                 return StatusWithMatchExpression( s );
-//             s = _parseArrayFilterEntries( temp->getArrayFilterEntries(), e.Obj() );
-//             if ( !s.isOK() )
-//                 return StatusWithMatchExpression( s );
-//             return StatusWithMatchExpression( temp.release() );
-//         }
-// 
-//         case BSONObj::NIN: {
-//             if ( e.type() != Array )
-//                 return StatusWithMatchExpression( ErrorCodes::BadValue, "$nin needs an array" );
-//             std::auto_ptr<InMatchExpression> temp( new InMatchExpression() );
-//             Status s = temp->init( name );
-//             if ( !s.isOK() )
-//                 return StatusWithMatchExpression( s );
-//             s = _parseArrayFilterEntries( temp->getArrayFilterEntries(), e.Obj() );
-//             if ( !s.isOK() )
-//                 return StatusWithMatchExpression( s );
-// 
-//             std::auto_ptr<NotMatchExpression> temp2( new NotMatchExpression() );
-//             s = temp2->init( temp.release() );
-//             if ( !s.isOK() )
-//                 return StatusWithMatchExpression( s );
-// 
-//             return StatusWithMatchExpression( temp2.release() );
-//         }
-// 
-//         case BSONObj::opSIZE: {
-//             int size = 0;
-//             if ( e.type() == String ) {
-//                 // matching old odd semantics
-//                 size = 0;
-//             }
-//             else if ( e.type() == NumberInt || e.type() == NumberLong ) {
-//                 size = e.numberInt();
-//             }
-//             else if ( e.type() == NumberDouble ) {
-//                 if ( e.numberInt() == e.numberDouble() ) {
-//                     size = e.numberInt();
-//                 }
-//                 else {
-//                     // old semantcs require exact numeric match
-//                     // so [1,2] != 1 or 2
-//                     size = -1;
-//                 }
-//             }
-//             else {
-//                 return StatusWithMatchExpression( ErrorCodes::BadValue, "$size needs a number" );
-//             }
-// 
-//             std::auto_ptr<SizeMatchExpression> temp( new SizeMatchExpression() );
-//             Status s = temp->init( name, size );
-//             if ( !s.isOK() )
-//                 return StatusWithMatchExpression( s );
-//             return StatusWithMatchExpression( temp.release() );
-//         }
-// 
-//         case BSONObj::opEXISTS: {
-//             if ( e.eoo() )
-//                 return StatusWithMatchExpression( ErrorCodes::BadValue, "$exists can't be eoo" );
-//             std::auto_ptr<ExistsMatchExpression> temp( new ExistsMatchExpression() );
-//             Status s = temp->init( name );
-//             if ( !s.isOK() )
-//                 return StatusWithMatchExpression( s );
-//             if ( e.trueValue() )
-//                 return StatusWithMatchExpression( temp.release() );
-//             std::auto_ptr<NotMatchExpression> temp2( new NotMatchExpression() );
-//             s = temp2->init( temp.release() );
-//             if ( !s.isOK() )
-//                 return StatusWithMatchExpression( s );
-//             return StatusWithMatchExpression( temp2.release() );
-//         }
-// 
-//         case BSONObj::opTYPE: {
-//             if ( !e.isNumber() )
-//                 return StatusWithMatchExpression( ErrorCodes::BadValue, "$type has to be a number" );
-//             int type = e.numberInt();
-//             if ( e.type() != NumberInt && type != e.number() )
-//                 type = -1;
-//             std::auto_ptr<TypeMatchExpression> temp( new TypeMatchExpression() );
-//             Status s = temp->init( name, type );
-//             if ( !s.isOK() )
-//                 return StatusWithMatchExpression( s );
-//             return StatusWithMatchExpression( temp.release() );
-//         }
-// 
-// 
-//         case BSONObj::opMOD:
-//             return _parseMOD( name, e );
-// 
-//         case BSONObj::opOPTIONS: {
-//             // TODO: try to optimize this
-//             // we have to do this since $options can be before or after a $regex
-//             // but we validate here
-//             BSONObjIterator i( context );
-//             while ( i.more() ) {
-//                 BSONElement temp = i.next();
-//                 if ( temp.getGtLtOp( -1 ) == BSONObj::opREGEX )
-//                     return StatusWithMatchExpression( NULL );
-//             }
-// 
-//             return StatusWithMatchExpression( ErrorCodes::BadValue, "$options needs a $regex" );
-//         }
-// 
-//         case BSONObj::opREGEX: {
-//             return _parseRegexDocument( name, context );
-//         }
-// 
-//         case BSONObj::opELEM_MATCH:
-//             return _parseElemMatch( name, e );
-// 
-//         case BSONObj::opALL:
-//             return _parseAll( name, e );
-// 
-//         case BSONObj::opWITHIN:
-//         case BSONObj::opGEO_INTERSECTS:
-//         case BSONObj::opNEAR:
-//             return expressionParserGeoCallback( name, x, context );
-// 
-//         }
-// 
-//         return StatusWithMatchExpression( ErrorCodes::BadValue,
-//                                           mongoutils::str::stream() << "not handled: " << e.fieldName() );
-//     }
-
-
-
-}
-
+proto._parseSubField = function _parseSubField(context, andSoFar, name, element){
+	// File: expression_parser.cpp lines: 46-214
+	// TODO: these should move to getGtLtOp, or its replacement
+
+	if ("$eq" == element)
+		return this._parseComparison(name, new EqualityMatchExpression(), element);
+
+	if ("$not" == element) {
+		return this._parseNot(name, element);
+	}
+
+	var x = element.getGtLtOp(-1),
+		status, temp, temp2;
+	switch (x) {
+	case -1:
+		return {code:ErrorCodes.BadValue, description:"unknown operator: " + element};
+	case 'LT':
+		return this._parseComparison(name, new LTMatchExpression(), element);
+	case 'LTE':
+		return this._parseComparison(name, new LTEMatchExpression(), element);
+	case 'GT':
+		return this._parseComparison(name, new GTMatchExpression(), element);
+	case 'GTE':
+		return this._parseComparison(name, new GTEMatchExpression(), element);
+	case 'NE':
+		status = this._parseComparison(name, new EqualityMatchExpression(), element);
+		if (status.code != ErrorCodes.OK)
+			return status;
+		var n = new NotMatchExpression();
+		status = n.init(status.result);
+		if (status.code != ErrorCodes.OK)
+			return status;
+		return {code:ErrorCodes.OK, result:n.release()};
+	case 'Equality':
+		return this._parseComparison(name, new EqualityMatchExpression(), element);
+
+	case 'opIN':
+		if (!(element instanceof Array))
+			return {code:ErrorCodes.BadValue, description:"$in needs an array"};
+		temp = new InMatchExpression();
+		status = temp.init(name);
+		if (status.code != ErrorCodes.OK)
+			return status;
+		status = this._parseArrayFilterEntries(temp.getArrayFilterEntries(), element);
+		if (status.code != ErrorCodes.OK)
+			return status;
+		return {code:ErrorCodes.OK, result:temp.release()};
+
+	case 'NIN':
+		if (!(element instanceof Array))
+			return {code:ErrorCodes.BadValue, description:"$nin needs an array"};
+		temp = new InMatchExpression();
+		status = temp.init(name);
+		if (status.code != ErrorCodes.OK)
+			return status;
+		status = this._parseArrayFilterEntries(temp.getArrayFilterEntries(), element);
+		if (status.code != ErrorCodes.OK)
+			return status;
+
+		temp2 = new NotMatchExpression();
+		status = temp2.init(temp.release());
+		if (status.code != ErrorCodes.OK)
+			return status;
+
+		return {code:ErrorCodes.OK, result:temp2.release()};
+
+	case 'opSIZE':
+		var size = 0;
+		if (element instanceof String)
+			// matching old odd semantics
+			size = 0;
+		else if (element instanceof Number)
+			size = element;
+		else {
+			return {code:ErrorCodes.BadValue, description:"$size needs a number"};
+		}
+
+		temp = new SizeMatchExpression();
+		status = temp.init(name, size);
+		if (status.code != ErrorCodes.OK)
+			return status;
+
+		return {code:ErrorCodes.OK, result:temp.release()};
+
+	case 'opEXISTS':
+		if (element == {})
+			return {code:ErrorCodes.BadValue, description:"$exists can't be eoo"};
+		temp = new ExistsMatchExpression();
+		status = temp.init(name);
+		if (status.code != ErrorCodes.OK)
+			return status;
+		if (element)
+			return {code:ErrorCodes.OK, result:temp.release()};
+		temp2 = new NotMatchExpression();
+		status = temp2.init(temp.release());
+		if (status.code != ErrorCodes.OK)
+			return status;
+		return {code:ErrorCodes.OK, result:temp2.release()};
+
+	case 'opTYPE':
+		if (!(element instanceof Number))
+			return {code:ErrorCodes.BadValue, description:"$type has to be a number"};
+		var type = element;
+		temp = new TypeMatchExpression();
+		status = temp.init(name, type);
+		if (status.code != ErrorCodes.OK)
+			return status;
+		return {code:ErrorCodes.OK, result:temp.release()};
+
+	case 'opMOD':
+		return this._parseMOD(name, element);
+
+	case 'opOPTIONS':
+		// TODO: try to optimize this
+		// we have to do this since $options can be before or after a $regex
+		// but we validate here
+		for(var i = 0; i < context.length; i++) {
+			temp = context[i];
+			if (temp.getGtLtOp(-1) == 'opREGEX')
+				return {code:ErrorCodes.OK, result:null};
+		}
+
+		return {code:ErrorCodes.BadValue, description:"$options needs a $regex"};
+
+	case 'opREGEX':
+		return this._parseRegexDocument(name, context);
+
+	case 'opELEM_MATCH':
+		return this._parseElemMatch(name, element);
+
+	case 'opALL':
+		return this._parseAll(name, element);
+
+	case 'opWITHIN':
+	case 'opGEO_INTERSECTS':
+	case 'opNEAR':
+		return this.expressionParserGeoCallback(name, x, context);
+
+	} // end switch
+
+	return {code:ErrorCodes.BadValue, description:"not handled: " + element};
+};
 
 /**
- * 
+ *
  * This documentation was automatically generated. Please update when you touch this function.
  * @method _parseTreeList
  * @param
  *
  */
-proto._parseTreeList = function _parseTreeList( /*  const BSONObj& arr, ListOfMatchExpression* out  */ ){
-
-// File: expression_parser_tree.cpp lines: 33-52
-//     Status MatchExpressionParser::_parseTreeList( const BSONObj& arr, ListOfMatchExpression* out ) {
-//         if ( arr.isEmpty() )
-//             return Status( ErrorCodes::BadValue,
-//                            "$and/$or/$nor must be a nonempty array" );
-// 
-//         BSONObjIterator i( arr );
-//         while ( i.more() ) {
-//             BSONElement e = i.next();
-// 
-//             if ( e.type() != Object )
-//                 return Status( ErrorCodes::BadValue,
-//                                "$or/$and/$nor entries need to be full objects" );
-// 
-//             StatusWithMatchExpression sub = _parse( e.Obj(), false );
-//             if ( !sub.isOK() )
-//                 return sub.getStatus();
-// 
-//             out->add( sub.getValue() );
-//         }
-//         return Status::OK();
-//     }
-
-
-
-}
+proto._parseTreeList = function _parseTreeList(arr, out){
+	// File: expression_parser_tree.cpp lines: 33-52
+	if (arr.length === 0)
+		return {code:ErrorCodes.BadValue, description:"$and/$or/$nor must be a nonempty array"};
+
+	var status, element;
+	for (var i = 0; i < arr.length; i++) {
+		element = arr[i];
+
+		if (!(element instanceof Object))
+			return {code:ErrorCodes.BadValue, description:"$or/$and/$nor entries need to be full objects"};
 
+		status = this._parse(element, false);
+		if (status.code != ErrorCodes.OK)
+			return status;
+
+		out.add(status.result);
+	}
+	return {code:ErrorCodes.OK};
+};
 
 /**
- * 
+ *
  * This documentation was automatically generated. Please update when you touch this function.
  * @method parse
  * @param
  *
  */
-proto.parse = function parse( /*  const BSONObj& obj  */ ){
-// File: expression_parser.h lines: 40-41
-//         static StatusWithMatchExpression parse( const BSONObj& obj ) {
-//             return _parse( obj, true );
-//         }
-
-
-
-
-}
+proto.parse = function parse(obj){
+	// File: expression_parser.h lines: 40-41
+    return this._parse(obj, true);
+};