private Object getCollectionPropertyAO(Object ctx, String prop)
      throws IllegalAccessException, InvocationTargetException {
    if (prop.length() > 0) {
      ctx = getBeanProperty(ctx, prop);
      first = false;
    }

    currType = null;

    assert debug("\n  **  ENTER -> {collection:<<" + prop + ">>; ctx=" + ctx + "}");

    int _start = ++cursor;

    skipWhitespace();

    if (cursor == end)
      throw new CompileException("unterminated '['", expr, st);

    if (scanTo(']'))
      throw new CompileException("unterminated '['", expr, st);

    String tk = new String(expr, _start, cursor - _start);

    assert debug("{collection token:<<" + tk + ">>}");

    if (ctx == null) return null;

    ExecutableStatement compiled = (ExecutableStatement) subCompileExpression(tk.toCharArray());
    Object item = compiled.getValue(ctx, variableFactory);

    ++cursor;

    if (ctx instanceof Map) {
      if (hasPropertyHandler(Map.class)) {
        return propHandlerByteCode(tk, ctx, Map.class);
      }
      else {
        if (first) {
          assert debug("ALOAD 1");
          mv.visitVarInsn(ALOAD, 1);
        }

        assert debug("CHECKCAST java/util/Map");
        mv.visitTypeInsn(CHECKCAST, "java/util/Map");

        Class c = writeLiteralOrSubexpression(compiled);
        if (c != null && c.isPrimitive()) {
          wrapPrimitive(c);
        }

        assert debug("INVOKEINTERFACE: Map.get");
        mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
      }

      return ((Map) ctx).get(item);
    }
    else if (ctx instanceof List) {
      if (hasPropertyHandler(List.class)) {
        return propHandlerByteCode(tk, ctx, List.class);
      }
      else {
        if (first) {
          assert debug("ALOAD 1");
          mv.visitVarInsn(ALOAD, 1);
        }

        assert debug("CHECKCAST java/util/List");
        mv.visitTypeInsn(CHECKCAST, "java/util/List");

        writeLiteralOrSubexpression(compiled, int.class);

        assert debug("INVOKEINTERFACE: java/util/List.get");
        mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "get", "(I)Ljava/lang/Object;");

        return ((List) ctx).get(convert(item, Integer.class));
      }
    }
    else if (ctx.getClass().isArray()) {
      if (hasPropertyHandler(Array.class)) {
        return propHandlerByteCode(tk, ctx, Array.class);
      }
      else {
        if (first) {
          assert debug("ALOAD 1");
          mv.visitVarInsn(ALOAD, 1);
        }

        assert debug("CHECKCAST " + getDescriptor(ctx.getClass()));
        mv.visitTypeInsn(CHECKCAST, getDescriptor(ctx.getClass()));

        writeLiteralOrSubexpression(compiled, int.class, item.getClass());

        Class cls = getBaseComponentType(ctx.getClass());
        if (cls.isPrimitive()) {
          if (cls == int.class) {
            assert debug("IALOAD");
            mv.visitInsn(IALOAD);
          }
          else if (cls == char.class) {
            assert debug("CALOAD");
            mv.visitInsn(CALOAD);
          }
          else if (cls == boolean.class) {
            assert debug("BALOAD");
            mv.visitInsn(BALOAD);
          }
          else if (cls == double.class) {
            assert debug("DALOAD");
            mv.visitInsn(DALOAD);
          }
          else if (cls == float.class) {
            assert debug("FALOAD");
            mv.visitInsn(FALOAD);
          }
          else if (cls == short.class) {
            assert debug("SALOAD");
            mv.visitInsn(SALOAD);
          }
          else if (cls == long.class) {
            assert debug("LALOAD");
            mv.visitInsn(LALOAD);
          }
          else if (cls == byte.class) {
            assert debug("BALOAD");
            mv.visitInsn(BALOAD);
          }

          wrapPrimitive(cls);
        }
        else {
          assert debug("AALOAD");
          mv.visitInsn(AALOAD);
        }

        return Array.get(ctx, convert(item, Integer.class));
      }
    }
    else if (ctx instanceof CharSequence) {
      if (hasPropertyHandler(CharSequence.class)) {
        return propHandlerByteCode(tk, ctx, CharSequence.class);
      }
      else {
        if (first) {
          assert debug("ALOAD 1");
          mv.visitVarInsn(ALOAD, 1);
        }

        assert debug("CHECKCAST java/lang/CharSequence");
        mv.visitTypeInsn(CHECKCAST, "java/lang/CharSequence");

        if (item instanceof Integer) {
          intPush((Integer) item);

          assert debug("INVOKEINTERFACE java/lang/CharSequence.charAt");
          mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/CharSequence", "charAt", "(I)C");

          wrapPrimitive(char.class);

          return ((CharSequence) ctx).charAt((Integer) item);
        }
        else {
          writeLiteralOrSubexpression(compiled, Integer.class);
          unwrapPrimitive(int.class);

          assert debug("INVOKEINTERFACE java/lang/CharSequence.charAt");
          mv.visitMethodInsn(INVOKEINTERFACE, "java/lang/CharSequence", "charAt", "(I)C");

          wrapPrimitive(char.class);

          return ((CharSequence) ctx).charAt(convert(item, Integer.class));
        }
      }
    }
    else {
      TypeDescriptor tDescr = new TypeDescriptor(expr, start, end - start, 0);
      if (tDescr.isArray()) {
        try {
          Class cls = getClassReference((Class) ctx, tDescr, variableFactory, pCtx);
          //   rootNode = new StaticReferenceAccessor(cls);
          ldcClassConstant(cls);
          return cls;
        }
        catch (Exception e) {
          //fall through
        }
      }

      throw new CompileException("illegal use of []: unknown type: "
          + (ctx == null ? null : ctx.getClass().getName()), expr, st);
    }
  }


  @SuppressWarnings({"unchecked"}