if(!s2.propertyInterceptor){
    /**
       property interceptor support will almost certainly never be
       enabled - the chances of unwanted side effects, especially
       within cwal's limited key/value property model are simply too
       high. Also, the performance hit it applies to the library is
       not something i'm willing to accept for a sugar-only feature
       like this one. It might be more feasible if cwal had a
       higher-level properties API, instead of simply key/value pairs,
       but that's too heavy-weight for cwal's design goals.
    */
    // print("s2.propertyInterceptor() not enabled.");
    /* No 'return' - it messes up one of the unit tests. */
}else{
    affirm typeinfo(isfunction const mkint = s2.propertyInterceptor);

    scope {
        const o = {
            a: 1
        };
        assert mkint === mkint(o, 'b', proc(){
            if(argv.length()){
                // setter...
                interceptee.a = argv.0;
                //throw "testing";
                return /* return val is ignored for setters! */;
            }
            // getter...
            return interceptee.a;
        });
        assert 1 === o.b;
        o.b = 12;
        //throw {o};
        assert 12 === o.a;
        ++o.a;
        ++o.b; /* well that wasn't supposed to work. */
        o.b++; /* well that wasn't supposed to work. */
        assert 15 === o.b;
        assert o.a === o.b;

        const x = {prototype:o, foo: 7};
        assert o.a === x.b;
        x.b *= 2;
        assert 30 === o.a;
        assert 30 === x.b;
        o.a *= 2;
        assert 60 === o.a;
    }

    scope {
        const pro = {foo: 7};
        const x = {prototype: pro};

        mkint(pro, 'y', proc(){
            affirm pro === interceptee;
            affirm x === this;
            //return this.y;
            //throw {x: typename this.y};
            // this.y is NOT supposed to be resolving
            // as a Function here, but should recurse.
            return this.y(@argv);
        });
        x.y2 = mkint(proc(){
            affirm this === interceptee;
            affirm x === this;
            return this.y;
        });
        mkint(x, 'r', proc(){
            affirm this === interceptee;
            affirm x === this;
            return this.r /* why is this access not triggering the
                             interceptor again? It's most certainly
                             not by design. */;
        });
        mkint(x, 'zz', proc(){
            //break; // error info here is not useful.
            affirm this === interceptee;
            affirm x === this;
            if(argv.length()){
                this.foo = argv.0;
                return;
            }
            return this.foo;
        });
        x.zzz = mkint(proc(){
            //break; // error info here is not useful.
            affirm this === interceptee;
            affirm x === this;
            if(argv.length()){
                this.zz = argv.0;
                return;
            }
            return this.zz;
        });
        assert 7 === x.zzz;
        var ex;
        //why not triggering the interceptor here!?!?!?
        //ex = catch{x.y}.codeString();
        //assert typeinfo(isexception ex);
        //assert 'CWAL_RC_CYCLES_DETECTED' === ex.codeString();
        ex = catch{x.y2};
        assert typeinfo(isexception ex);
        assert 'CWAL_RC_CYCLES_DETECTED' === ex.codeString();
        assert typeinfo(isfunction x.r)
        /* This assertion is unexpected/wrong: i'm expecting an exception. */;
        unset ex;
        var i = 0;
        foreach(x=>k,v) print(++i, __FLC, k, typeinfo(name v));
        assert !i /* foreach skips over interceptors */;

        x.zzz = 3;
        assert 3 === x.zz;
        assert 3 === x.foo;

        foreach(x=>k,v) print(++i, __FLC, k, typeinfo(name v));
        assert 1===i /* .foo prop */;

    }

    scope {
        const ar = [1,2,3];
        ar.L = mkint(proc(){
            const x = 0 ? this : interceptee;
            affirm typeinfo(isarray interceptee);
            if(argv.length()){
                // setter...
                //print(__FLC,"setting",x,".length(",argv.0,")");
                x.length(argv.0);
                //throw "testing";
                return/* return val is ignored for setters! */;
                
            }
            // getter...
            //print(__FLC,"getting",x,".length()");
            return x.length();
        });
        assert 3 === ar.L;
        ar.L = 5;
        assert 5 === ar.length();
        assert undefined === foreach(ar=>k,v){
            k === 'L' && break k;
        } /* foreach() (currently) explicitly skips over interceptors */;
        var obj = {prototype:ar, x:1};
        foreach(obj=>k,v){
            assert k !== 'L';
        };

        var newLen = 2;
        obj.L = newLen;
        assert obj.L === ar.length();
        assert 2 === ar.L;
        assert ar.L === obj.length();
        assert ar.L === obj.L;
        obj.L *= newLen;
        newLen *= newLen;
        assert newLen === ar.L;
        assert newLen === ar.length();
        assert 2 === ar.1;
        assert undefined === ar[ar.L-1];

    }

    scope {
        const str = "abcdef";
        str.prototype.L = mkint(proc(){
            affirm "".prototype === interceptee;
            affirm typeinfo(isstring this);
            if(argv.length()){
                // setter...
                throw "Strings are immutable - cannot set their length.";
                
            }
            // getter...
            return this.length();
        });
        assert 6 === str.L;
        assert catch str.L = 1;
        assert str[5] === str[str.L-1];
    }

}
