Last active
December 20, 2015 18:48
-
-
Save mariechatfield/6178151 to your computer and use it in GitHub Desktop.
Clean up Sk.misceval.richCompareBool and make behave like Python when comparing objects of different built-in types. Also improve error messages when attempting to compare invalid types.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sk.abstr.typeName = function(v) { | |
var vtypename; | |
if (v instanceof Sk.builtin.nmber) { | |
vtypename = v.skType; | |
} else if (v.tp$name !== undefined) { | |
vtypename = v.tp$name; | |
} else { | |
vtypename = "<invalid type>"; | |
}; | |
return vtypename; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sk.builtin.type = function(name, bases, dict) | |
{ | |
if (bases === undefined && dict === undefined) | |
{ | |
// 1 arg version of type() | |
// the argument is an object, not a name and returns a type object | |
var obj = name; | |
if (obj.constructor === Sk.builtin.nmber) | |
{ | |
if (obj.skType === Sk.builtin.nmber.int$) | |
{ | |
return Sk.builtin.int_.prototype.ob$type; | |
} | |
else | |
{ | |
return Sk.builtin.float_.prototype.ob$type; | |
} | |
} | |
return obj.ob$type; | |
} | |
else |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sk.misceval.richCompareBool = function(v, w, op) | |
{ | |
// v and w must be Python objects. will return Javascript true or false for internal use only | |
// if you want to return a value from richCompareBool to Python you must wrap as Sk.builtin.bool first | |
goog.asserts.assert((v !== null) && (v !== undefined), "passed undefined or null parameter to Sk.misceval.richCompareBool"); | |
goog.asserts.assert((w !== null) && (w !== undefined), "passed undefined or null parameter to Sk.misceval.richCompareBool"); | |
var v_type = new Sk.builtin.type(v); | |
var w_type = new Sk.builtin.type(w); | |
// Python has specific rules when comparing two different builtin types | |
// currently, this code will execute even if the objects are not builtin types | |
// but will fall through and not return anything in this section | |
if ((v_type !== w_type) | |
&& (op === 'GtE' || op === 'Gt' || op === 'LtE' || op === 'Lt')) | |
{ | |
// note: sets are omitted here because they can only be compared to other sets | |
var numeric_types = [Sk.builtin.float_.prototype.ob$type, | |
Sk.builtin.int_.prototype.ob$type, | |
Sk.builtin.lng.prototype.ob$type, | |
Sk.builtin.bool.prototype.ob$type]; | |
var sequence_types = [Sk.builtin.dict.prototype.ob$type, | |
Sk.builtin.enumerate.prototype.ob$type, | |
Sk.builtin.list.prototype.ob$type, | |
Sk.builtin.str.prototype.ob$type, | |
Sk.builtin.tuple.prototype.ob$type]; | |
var v_num_type = numeric_types.indexOf(v_type); | |
var v_seq_type = sequence_types.indexOf(v_type); | |
var w_num_type = numeric_types.indexOf(w_type); | |
var w_seq_type = sequence_types.indexOf(w_type); | |
// NoneTypes are considered less than any other type in Python | |
// note: this only handles comparing NoneType with any non-NoneType. | |
// Comparing NoneType with NoneType is handled further down. | |
if (v_type === Sk.builtin.none.prototype.ob$type) | |
{ | |
switch (op) | |
{ | |
case 'Lt': return true; | |
case 'LtE': return true; | |
case 'Gt': return false; | |
case 'GtE': return false; | |
} | |
} | |
if (w_type === Sk.builtin.none.prototype.ob$type) | |
{ | |
switch (op) | |
{ | |
case 'Lt': return false; | |
case 'LtE': return false; | |
case 'Gt': return true; | |
case 'GtE': return true; | |
} | |
} | |
// numeric types are always considered smaller than sequence types in Python | |
if (v_num_type !== -1 && w_seq_type !== -1) | |
{ | |
switch (op) | |
{ | |
case 'Lt': return true; | |
case 'LtE': return true; | |
case 'Gt': return false; | |
case 'GtE': return false; | |
} | |
} | |
if (v_seq_type !== -1 && w_num_type !== -1) | |
{ | |
switch (op) | |
{ | |
case 'Lt': return false; | |
case 'LtE': return false; | |
case 'Gt': return true; | |
case 'GtE': return true; | |
} | |
} | |
// in Python, different sequence types are ordered alphabetically | |
// by name so that dict < list < str < tuple | |
if (v_seq_type !== -1 && w_seq_type !== -1) | |
{ | |
switch (op) | |
{ | |
case 'Lt': return v_seq_type < w_seq_type; | |
case 'LtE': return v_seq_type <= w_seq_type; | |
case 'Gt': return v_seq_type > w_seq_type; | |
case 'GtE': return v_seq_type >= w_seq_type; | |
} | |
} | |
} | |
// handle identity and membership comparisons | |
if (op === 'Is') { | |
if (v instanceof Sk.builtin.nmber && w instanceof Sk.builtin.nmber) | |
{ | |
return (v.numberCompare(w) === 0) && (v.skType === w.skType); | |
} | |
else if (v instanceof Sk.builtin.lng && w instanceof Sk.builtin.lng) | |
{ | |
return v.longCompare(w) === 0; | |
} | |
return v === w; | |
} | |
if (op === 'IsNot') { | |
if (v instanceof Sk.builtin.nmber && w instanceof Sk.builtin.nmber) | |
{ | |
return (v.numberCompare(w) !== 0) || (v.skType !== w.skType); | |
} | |
else if (v instanceof Sk.builtin.lng && w instanceof Sk.builtin.lng) | |
{ | |
return v.longCompare(w) !== 0; | |
} | |
return v !== w; | |
} | |
if (op === "In") | |
return Sk.abstr.sequenceContains(w, v); | |
if (op === "NotIn") | |
return !Sk.abstr.sequenceContains(w, v); | |
// use comparison methods if they are given for either object | |
var res; | |
if (v.tp$richcompare && (res = v.tp$richcompare(w, op)) !== undefined) | |
{ | |
return res; | |
} | |
if (w.tp$richcompare && (res = w.tp$richcompare(v, Sk.misceval.swappedOp_[op])) !== undefined) | |
{ | |
return res; | |
} | |
// depending on the op, try left:op:right, and if not, then | |
// right:reversed-top:left | |
var op2method = { | |
'Eq': '__eq__', | |
'NotEq': '__ne__', | |
'Gt': '__gt__', | |
'GtE': '__ge__', | |
'Lt': '__lt__', | |
'LtE': '__le__' | |
}; | |
var method = op2method[op]; | |
var swapped_method = op2method[Sk.misceval.swappedOp_[op]]; | |
if (v[method]) | |
{ | |
return Sk.misceval.callsim(v[method], v, w); | |
} | |
else if (w[swapped_method]) | |
{ | |
return Sk.misceval.callsim(w[swapped_method], w, v); | |
} | |
if (v['__cmp__']) | |
{ | |
var ret = Sk.misceval.callsim(v['__cmp__'], v, w); | |
ret = Sk.builtin.asnum$(ret); | |
if (op === 'Eq') return ret === 0; | |
else if (op === 'NotEq') return ret !== 0; | |
else if (op === 'Lt') return ret < 0; | |
else if (op === 'Gt') return ret > 0; | |
else if (op === 'LtE') return ret <= 0; | |
else if (op === 'GtE') return ret >= 0; | |
} | |
if (w['__cmp__']) | |
{ | |
// note, flipped on return value and call | |
var ret = Sk.misceval.callsim(w['__cmp__'], w, v); | |
ret = Sk.builtin.asnum$(ret); | |
if (op === 'Eq') return ret === 0; | |
else if (op === 'NotEq') return ret !== 0; | |
else if (op === 'Lt') return ret > 0; | |
else if (op === 'Gt') return ret < 0; | |
else if (op === 'LtE') return ret >= 0; | |
else if (op === 'GtE') return ret <= 0; | |
} | |
// handle special cases for comparing None with None or Bool with Bool | |
if (((v instanceof Sk.builtin.none) && (w instanceof Sk.builtin.none)) | |
|| ((v instanceof Sk.builtin.bool) && (w instanceof Sk.builtin.bool))) | |
{ | |
// Javascript happens to return the same values when comparing null | |
// with null or true/false with true/false as Python does when | |
// comparing None with None or True/False with True/False | |
if (op === 'Eq') | |
return v.v === w.v; | |
if (op === 'NotEq') | |
return v.v !== w.v; | |
if (op === 'Gt') | |
return v.v > w.v; | |
if (op === 'GtE') | |
return v.v >= w.v; | |
if (op === 'Lt') | |
return v.v < w.v; | |
if (op === 'LtE') | |
return v.v <= w.v; | |
} | |
// handle equality comparisons for any remaining objects | |
if (op === 'Eq') | |
{ | |
if ((v instanceof Sk.builtin.str) && (w instanceof Sk.builtin.str)) | |
return v.v === w.v; | |
return v === w; | |
} | |
if (op === 'NotEq') | |
{ | |
if ((v instanceof Sk.builtin.str) && (w instanceof Sk.builtin.str)) | |
return v.v !== w.v; | |
return v !== w; | |
} | |
var vname = Sk.abstr.typeName(v); | |
var wname = Sk.abstr.typeName(w); | |
throw new Sk.builtin.ValueError("don't know how to compare '" + vname + "' and '" + wname + "'"); | |
}; | |
goog.exportSymbol("Sk.misceval.richCompareBool", Sk.misceval.richCompareBool); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment