{
  ex12.s

  Contents:

     1. a reflective(shell, extension) class A;
     2. a reflective(shell, extension) class D that inherits from A;
     3. an extension class B whose allowed set contains A and that
        defines method interceptAll;
     4. a shell class C whose allowed set contains A.

  Tests:
     1. how subclasses are affected when an extension is put on a
        superclass;
     2. message sends to "object"  in extension classes;
     3. message sends to "super" in subclasses when the superclass was
        attached to an extension;
     4. if superclasses are affected when an extension is put on a
        subclass;
     5. message sends to "object" in an extension class put on a
        class after a shell was put on an object of this class;
     6. message sends to "object" in a shell class put on an
        object after an extension was put on the class of the object;


  }




reflective(shell, extension) class A
  public:
    proc m1()
      begin
      write(1);
      end
    proc m2()
      begin
      write(2);
      end
    proc m3()
      begin
      write(3);
      end
endclass

reflective(shell, extension) class D inherits A
  public:
    proc m2()
      begin
      super.m2();
      write(5);
      end
    proc m3()
      begin
      super.m3();
      write(6);
      end
endclass


extension class B(A)
  public:
    proc interceptAll( mi : Method; vetArg : array(Object)[] ) : Object
      begin
      return mi.invoke(self, vetArg);
      end
endclass


shell class C(A)
  public:
    proc m1()
      begin
      object.m1();
      end
    proc m3()
      begin
      object.m3();
      end
endclass




class Program
  public:
    proc run()
        var a : A;
            d : D;
      begin
      a = A.new();
      d = D.new();

      a.m1();
      a.m2();
      a.m3();

      d.m1();   // A::m1
      d.m2();   // D::m3
      d.m3();   // D::m3

      if Reflect.attachExtension(A, B) == 0 then endif

      a.m1();   // B::m1
      a.m2();   // B::m2
      a.m3();   // B::m3

      d.m1();   // B::m1
      d.m2();   // D::m2
      d.m3();   // D::m3

      if Reflect.attachShell(a, C.new()) == 0 then endif

      a.m1();   // C::m1
      a.m2();   // B::m2
      a.m3();   // C::m3

      if Reflect.removeShell(a) == 0 then endif

      a.m1();   // B::m1
      a.m2();   // B::m2
      a.m3();   // B::m3

      if Reflect.removeExtension(A) == 0 then endif

      a.m1();   // A::m1
      a.m2();   // A::m2
      a.m3();   // A::m3

      d.m1();   // A::m1
      d.m2();   // D::m3
      d.m3();   // D::m3

      if Reflect.attachShell(a, C.new()) == 0 then endif

      a.m1();   // C::m1
      a.m2();   // A::m2
      a.m3();   // C::m3

      d.m1();   // A::m1
      d.m2();   // D::m3
      d.m3();   // D::m3

      if Reflect.attachExtension(A, B) == 0 then endif

      a.m1();   // C::m1
      a.m2();   // B::m2
      a.m3();   // C::m3

      d.m1();   // B::m1
      d.m2();   // D::m3
      d.m3();   // D::m3

      if Reflect.removeShell(a) == 0 then endif

      a.m1();   // B::m1
      a.m2();   // B::m2
      a.m3();   // B::m3

      if Reflect.removeExtension(A) == 0 then endif

      a.m1();   // A::m1
      a.m2();   // A::m2
      a.m3();   // A::m3

      d.m1();   // A::m1
      d.m2();   // D::m3
      d.m3();   // D::m3





      end

endclass


