Correct infinity comparisons and toNumber

This commit is contained in:
Valerie R Young 2018-11-13 13:00:20 -05:00
parent 1b44841034
commit 43c5d5c053

View file

@ -30,6 +30,7 @@ class Cast {
static toNumber (value) { static toNumber (value) {
// If value is already a number we don't need to coerce it with // If value is already a number we don't need to coerce it with
// Number(). // Number().
if (typeof value === 'number') { if (typeof value === 'number') {
// Scratch treats NaN as 0, when needed as a number. // Scratch treats NaN as 0, when needed as a number.
// E.g., 0 + NaN -> 0. // E.g., 0 + NaN -> 0.
@ -38,8 +39,14 @@ class Cast {
} }
return value; return value;
} }
let n;
const n = Number(value); if (Cast.isInfinity(value)) {
n = Infinity;
} else if (Cast.isNegativeInfinity(value)) {
n = -Infinity;
} else {
n = Number(value);
}
if (_NumberIsNaN(n)) { if (_NumberIsNaN(n)) {
// Scratch treats NaN as 0, when needed as a number. // Scratch treats NaN as 0, when needed as a number.
// E.g., 0 + NaN -> 0. // E.g., 0 + NaN -> 0.
@ -117,6 +124,24 @@ class Cast {
return val === null || (typeof val === 'string' && val.trim().length === 0); return val === null || (typeof val === 'string' && val.trim().length === 0);
} }
/**
* Determine if a Scratch argument is infinity.
* @param {*} val value to check.
* @return {boolean} True if the argument is any capitalization of infinity.
*/
static isInfinity (val) {
return val === Infinity || (typeof val === 'string' && val.toLowerCase() === 'infinity');
}
/**
* Determine if a Scratch argument is negative infinity.
* @param {*} val value to check.
* @return {boolean} True if the argument is a '-' folled by any capitalization of infinity.
*/
static isNegativeInfinity (val) {
return val === -Infinity || (typeof val === 'string' && val.toLowerCase() === '-infinity');
}
/** /**
* Compare two values, using Scratch cast, case-insensitive string compare, etc. * Compare two values, using Scratch cast, case-insensitive string compare, etc.
* In Scratch 2.0, this is captured by `interp.compare.` * In Scratch 2.0, this is captured by `interp.compare.`
@ -125,8 +150,10 @@ class Cast {
* @returns {number} Negative number if v1 < v2; 0 if equal; positive otherwise. * @returns {number} Negative number if v1 < v2; 0 if equal; positive otherwise.
*/ */
static compare (v1, v2) { static compare (v1, v2) {
let n1 = Number(v1); // If Cast.toNumber returns '0', then the value might be NaN. If the value is NaN,
let n2 = Number(v2); // this comparison algorithm needs to know.
let n1 = Cast.toNumber(v1) || Number(v1);
let n2 = Cast.toNumber(v2) || Number(v2);
if (n1 === 0 && Cast.isWhiteSpace(v1)) { if (n1 === 0 && Cast.isWhiteSpace(v1)) {
n1 = NaN; n1 = NaN;
} else if (n2 === 0 && Cast.isWhiteSpace(v2)) { } else if (n2 === 0 && Cast.isWhiteSpace(v2)) {
@ -145,8 +172,16 @@ class Cast {
return 0; return 0;
} }
// Compare as numbers. // Compare as numbers.
return n1 - n2; const r = n1 - n2;
if (isNaN(r)) {
if (n1 === Infinity && n2 === Infinity) {
return 0;
}
if (n1 === -Infinity && n2 === -Infinity) {
return 0;
}
}
return r;
} }
/** /**