void parseElement(ParseContext* ctx,
                  BSONElement elem,
                  boost::optional<FieldPath> fullPathToParent,
                  ProjectionPathASTNode* parent) {
    const bool hasPositional = hasPositionalOperator(elem.fieldNameStringData());

    // If there is a positional projection, find only features must be enabled.
    uassert(31324,
            "Cannot use positional projection in aggregation projection",
            (!hasPositional || ctx->policies.findOnlyFeaturesAllowed()));

    // Be sure that uses of positional projection that were correct in versions before 4.4 that are
    // now incorrect get a good error message.
    uassert(31394,
            "As of 4.4, it's illegal to specify positional operator in the middle of a path."
            "Positional projection may only be used at the end, for example: a.b.$. If the query "
            "previously used a form like a.b.$.d, remove the parts following the '$' and the "
            "results will be equivalent.",
            !str::contains(elem.fieldNameStringData(), ".$."));

    if (elem.type() == BSONType::Object) {
        BSONObj subObj = elem.embeddedObject();

        // Make sure this isn't a positional operator. It's illegal to combine positional with
        // any expression.
        uassert(31271,
                "positional projection cannot be used with an expression or sub object",
                !hasPositional);

        parseSubObject(ctx, elem.fieldNameStringData(), fullPathToParent, subObj, parent);
    } else if (isInclusionOrExclusionType(elem.type())) {
        if (elem.trueValue()) {
            parseInclusion(ctx, elem, parent, fullPathToParent);
        } else {
            uassert(31395, "positional projection cannot be used with exclusion", !hasPositional);
            parseExclusion(ctx, elem, parent);
        }
    } else {
        uassert(31308, "positional projection cannot be used with a literal", !hasPositional);

        parseLiteral(ctx, elem, parent);
    }
}
void parseElement(ParseContext* ctx,
                  BSONElement elem,
                  boost::optional<FieldPath> fullPathToParent,
                  ProjectionPathASTNode* parent) {
    const bool hasPositional = hasPositionalOperator(elem.fieldNameStringData());

     
    uassert(31324,
            "Cannot use positional projection in aggregation projection",
            (!hasPositional || ctx->policies.findOnlyFeaturesAllowed()));

     
     
    uassert(31394,
            "As of 4.4, it's illegal to specify positional operator in the middle of a path."
            "Positional projection may only be used at the end, for example: a.b.$. If the query "
            "previously used a form like a.b.$.d, remove the parts following the '$' and the "
            "results will be equivalent.",
            !str::contains(elem.fieldNameStringData(), ".$."));

    if (elem.type() == BSONType::Object) {
        BSONObj subObj = elem.embeddedObject();

         
         
        uassert(31271,
                "positional projection cannot be used with an expression or sub object",
                !hasPositional);

        parseSubObject(ctx, elem.fieldNameStringData(), fullPathToParent, subObj, parent);
    } else if (isInclusionOrExclusionType(elem.type())) {
        if (elem.trueValue()) {
            parseInclusion(ctx, elem, parent, fullPathToParent);
        } else {
            uassert(31395, "positional projection cannot be used with exclusion", !hasPositional);
            parseExclusion(ctx, elem, parent);
        }
    } else {
        uassert(31308, "positional projection cannot be used with a literal", !hasPositional);

        parseLiteral(ctx, elem, parent);
    }
}