/* Demonstrate operator overloading... */
if(1){
assert "3.00.1" === "3.0"+0.1 /* bug chasing */;
var pCount = 0, mCount = 0, o = {
a: 0,
// Binary X+Y
'operator+': proc(l,r){
assert 2 === argv.length();
++pCount;
return this.a + r;
},
// X+=Y
'operator+=': proc(l,r){
//print('operator+=',argv);
assert 2 === argv.length();
++pCount;
this.a += r;
return this;
},
// X-Y
'operator-': proc(l,r){
//print('operator-',argv);
assert 2 === argv.length();
++mCount;
return this.a - r;
},
// X-=Y
'operator-=': proc(l,r){
//print('operator+=',argv);
assert 2 === argv.length();
++mCount;
this.a -= r;
return this;
},
// ++X if no args, X++ if 1 arg (===this).
'operator++': proc(){
const argc = argv.length();
//print('operator++',argc ? 'postfix' : 'prefix', argv);
++pCount;
argc ? this.a++ : ++this.a;
return this;
},
// --X if no args, X-- if 1 arg (===this).
'operator--': proc(){
const argc = argv.length();
//print('operator--',argc ? 'postfix' : 'prefix', argv);
++mCount;
//argc ? this.a-- : --this.a;
--this.a;
return this;
},
// -X
'-operator': proc(){
//print('-operator', argv);
return -this.a;
},
// X==Y
'operator==': proc(l,r){
assert l === this;
// very minimal impl which does not detect
// an RHS of the same class as this.
return ((typename this) === (typename r))
? this.a === r.a
: this.a == r;
},
// X!=Y
'operator!=': proc(l,r){
return !(l==r);
},
// X<Y
'operator<': proc(l,r){
//assert l === this;
return ((typename this) === (typename r))
? this.a < r.a
: this.a < r;
},
// X>Y
'operator>': proc(l,r){
//assert l === this;
return ((typename this) === (typename r))
? this.a > r.a
: this.a > r;
}
};
//print("Properties:", o.propertyKeys());
assert(!o.prototype.'operator+');
assert o === ++o;
assert 1 === o.a;
assert 1 === pCount;
assert o++ === o;
assert 2 === o.a;
assert 2 === pCount;
assert o === o--;
assert 1 === o.a;
assert 1 === mCount;
assert o === --o;
// bug: can't yet distinguish -unary from --prefix
assert 0 === o.a;
assert 2 === mCount;
//assert 2 === (o += 2);
//print('o =',o);
assert o === (o += 2);
//print('o =',o);
assert 4 === o + 2;
assert 2 === o.a;
assert 1 === o - 1;
//assert 'CWAL_RC_NOT_FOUND' === catch{-o/*no such operator*/}.codeString();
assert 'CWAL_RC_NOT_FOUND' === catch{+o/*no such operator*/}.codeString();
//print("Properties:", o.propertyKeys());
assert 2 === o.a;
o -= 1;
assert 1 === o.a;
assert -1 === -o;
assert 1 === o.a;
assert !(o < 1);
assert o == 1;
assert o != 2;
assert o < 2;
assert o > 0;
assert catch{o * 1 /* no such op */};
assert catch{o / 1 /* no such op */};
assert catch{o % 1 /* no such op */};
assert catch{o << 1 /* no such op */};
assert catch{o >> 1 /* no such op */};
}
scope {
const sproto = "".prototype;
assert catch{"" * 3 /* no such op (yet) */};
sproto.'operator*' = proc f(s,rhs){
(rhs>0) || throw "Expecting positive RHS for STRING*N op.";
f.buf || (f.buf = buffer(100));
f.buf.reset();
for(var i = 0; i < rhs; ++i ){
f.buf.append(s);
}
return f.buf.toString();
}.importSymbols({buffer: s2.Buffer.new});
assert '***' === "*" * 3;
assert catch{'*' * -1 /* negative index */};
assert "3.00.1" === "3.0"+0.1 /* checking for a misplaced bug */;
unset sproto.'operator*';
}
var three = 3;
scope {
var ar = [];
ar.'operator+=' = proc(l,r){
l.push(r);
return this;
};
ar.'operator<<' = proc(l,r){
return l.push(r);
};
ar += 1;
ar << 2;
assert '12' === ar.join('');
var out;
ar.'operator>>' = proc(l,r){
//var code = r+" = l.pop()";
//print('code =',code);
//return eval -> code;
return eval -> r+"=l.pop()";
};
1 ? (ar >> nameof out) // yet another (obscure) use for nameof
: ar.pop();
assert 2 === out;
assert 1 === ar.length();
assert 1 === ar.0;
//print(out,ar);
//print(__FLC, refcount three);
ar[3] = three;
//print(__FLC, refcount three);
;1;1;1;
//print(__FLC, refcount three);
ar.clear();
//print(__FLC, refcount three);
assert catch{ar & 1/* no such operator (yet) */};
ar.'operator&' = proc(l,r){
return this;
};
assert ar === ar & 1;
}
//print(__FLC, refcount three);
assert 3 === three;
scope {
// Overloading math ops on functions...
var x, setX = proc(){return x = argv.0};
setX.'operator+' = proc(self,arg){return this(arg)};
setX+1;
assert 1 === x;
assert 0 === setX + 0;
assert 1 === setX + -1 + 1 * 2;
}
scope {
// Overload-only -> op...
var x, setX = proc(){return x = argv.0};
setX.'operator->' = proc(self,arg){return this(arg)};
setX->1;
assert 1 === x;
assert 0 === setX -> 0;
assert -1 === setX ->( -1 * 1 ) /* -> has . precedence */;
unset setX;
// Overload-only =~ ("contains") and !~ ("does not contain") ops...
var o = {
a: [1,2,3],
'operator=~':proc(self,arg){
return this.a.indexOf(arg)>=0;
}
};
assert o =~ 1;
assert o =~ 3;
assert !(o =~ -1);
assert catch{o !~ 1 /* no such operator yet */};
o.'operator!~' =proc(self,arg){
return this.a.indexOf(arg)<0;
};
assert o !~ -1;
assert !(o !~ 1);
assert o =~ 1 && o !~ -1; // has comparison precedence
}
scope {
// C++-style streams...
var b = s2.Buffer.new(20);
// Remember that buffers are not containers:
b.prototype.'operator<<' = proc(self,arg){
return this.append(arg);
};
b << "a" << "bc" << "def";
assert "abcdef" === b.toString();
b.reset();
b << 1 << 2+3;
assert "15" === b.toString();
unset b.prototype.'operator<<';
// Alternate implementation:
var o = {
buf: b.reset(),
'operator<<': proc(self,arg){
this.buf.append(arg);
return this;
}
};
o << "a" << "bc" << "def";
assert "abcdef" === b.toString();
b.reset();
o << 1 << 2+3;
assert "15" === b.toString();
unset b.prototype.'operator<<';
}
0 && scope {
// experimental, doesn't yet work how i would like
// Certain parts of this require enabling/disabling
// specific ifdefs in s2_eval.c and/or s2_ops.c
var o = {
__typename: 'Bob',
'operator->': proc(self,arg){
return this.sub[arg];
},
sub:{
__typename: 'Sub',
x: -1,
f: proc(){
print(__FLC,'this =',this);
assert 'Bob' === typename this;
return 1;
}
}
};
print(o->'f');
assert 'function' === typename o->'f';
assert 1 === o->f(); // works, yet...
assert 1 === o->'f'(); // works
o->x = 1; // assigns in o (or errors, depending on how we assign engine->dotOpLhs)
o->x++; // as well.
// i understand why, but a fix seems rather intrusive. i'd rather have it not behave
// like the dot, i think.
print(__FLC,'o =',o);
};