/**
Experimenting with C++-like operator overloading...
*/
scope {
//const AP = api.prototypes.Array
const AP = array[].prototype
AP.'operator+' = proc{lhs,rhs}{
assert this === lhs
[print "operator+" this rhs]
[this.push rhs]
return this
}
AP.'operator-' = proc{lhs,rhs}{
assert this === lhs
var i = 0, max = 0+rhs
[print "operator-" this max]
if(max<0){ /* Pop from the end. */
var len = [this.length] - -max;
if(len<0) { len = 0 }
// bug: broken: ((len>=0) ? len : 0) evals to boolean
[this.length len]
//[print 'this.length =' [this.length]]
}
else if(max>0){ /* remove from the front */
while{i<max}{
[this.shift]
i += 1
}
}
return this
}
AP.'operator/' = proc{lhs,rhs}{
assert this === lhs
[print "What should operator/ do for an array?"]
return true
}
AP.'operator%' = proc{lhs,rhs}{
assert this === lhs
[print "What should operator% do for an array?"]
return true
}
/**
operator* is the only commutative operator for
client-specified operators, meaning it is triggered
whether 'this' is on the left or right of its
operator. the (lhs,rhs) parameters will reflect their
given order and 'this' will be set to the object
who's operator was triggered. So 'this' will ===
(at least) one of lhs or rhs.
*/
AP.'operator*' = proc{lhs,rhs}{
assert (this===lhs) || (this===rhs)
assert 'array'===typename this
if(this===rhs) {
throw [api.string.concat
"Non-sensical operation: "
typename lhs
' * '
typename rhs]
}
//$print 'op* args:' typename lhs typename rhs
const other = (lhs===this) ? rhs : lhs
assert other !== this
[print "What should operator* do for an array?"]
return true
}
AP
}
1 && scope {
const a = array[]
$print 'operator+ =' a.'operator+'
assert 'function' === typename a.'operator+'
a += "hi" // const var assignment to self is a no-op here
//a + "hi" // same as a+="hi"
a + "!!!"
a + ":-D"
//a + "again," + "and again," + "and again!" // evals all +'s first
//(a + "again,") + "and again," + "and again!" // but this works
a + "again," + "and again," + "and again!" // and this works
$print 'a =' a
a - -1
$print 'a =' a
a - 1
$print 'a =' a
assert true === a * 3
assert 0 === 2 * a // NON-commutative!
assert true === a % 1
assert true === a / 7
assert 2 === 2 - a // NON-commutative!
$print 'a =' a
}
1 && scope {
var x = array[]
x.'operator<<' = x.'operator+'
x.'operator>>' = x.'operator-'
x + "foo" << "bar" << "baz"
assert 3 === [x.length]
assert "foo" === x.0
assert "baz" === x.2
x >> 1
assert 2 === [x.length]
assert 'bar' === x.0
x >> 2
assert ![x.length]
}