public ArrayAddExpressionEvaluator(
     JsonNodeFactory factory, FieldTreeNode context, ArrayAddExpression expr) {
   this.factory = factory;
   if (expr.getOp() == UpdateOperator._insert) {
     // Path should include an index
     if (expr.getField().isIndex(expr.getField().numSegments() - 1)) {
       arrayField = expr.getField().prefix(-1);
       insertionIndex = expr.getField().getIndex(expr.getField().numSegments() - 1);
     } else {
       throw new EvaluationError(CrudConstants.ERR_REQUIRED_INSERTION_INDEX + expr.getField());
     }
   } else {
     arrayField = expr.getField();
     insertionIndex = -1;
   }
   if (arrayField.nAnys() > 0) {
     throw new EvaluationError(CrudConstants.ERR_PATTERN_NOT_EXPECTED + arrayField);
   }
   FieldTreeNode ftn = context.resolve(arrayField);
   if (ftn instanceof ArrayField) {
     fieldMd = (ArrayField) ftn;
     // Array size field should be at the same level as the array field
     MutablePath abs = new MutablePath();
     fieldMd.getFullPath(abs);
     absArrayField = abs.mutableCopy();
     abs.setLast(abs.getLast() + "#");
     // At this point, arraySizeField is derived from metadata,
     // so it has * as array indexes
     arraySizeField = abs.immutableCopy();
     values = new ArrayList<>(expr.getValues().size());
     initializeArrayField(context, expr);
   } else {
     throw new EvaluationError(CrudConstants.ERR_REQUIRED_ARRAY + arrayField);
   }
 }