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];
}
}