Browse Source

Merge pull request #1761 from svaarala/more-es2015-number-additions

Add remaining missing ES2015 Number constructor properties
pull/1769/head
Sami Vaarala 7 years ago
committed by GitHub
parent
commit
d6c351d4b4
  1. 5
      RELEASES.rst
  2. 61
      src-input/builtins.yaml
  3. 36
      src-input/duk_bi_number.c
  4. 3
      src-input/duk_util.h
  5. 19
      src-input/duk_util_misc.c
  6. 41
      tests/ecmascript/test-bi-number-isfinite.js
  7. 41
      tests/ecmascript/test-bi-number-isinteger.js
  8. 41
      tests/ecmascript/test-bi-number-isnan.js
  9. 57
      tests/ecmascript/test-bi-number-issafeinteger.js
  10. 34
      tests/ecmascript/test-bi-number-values.js
  11. 3
      tests/ecmascript/test-bi-typedarray-coercion.js
  12. 4
      tests/ecmascript/test-bi-typedarray-floatdouble.js
  13. 94
      tests/ecmascript/util-base.js
  14. 4
      tests/ecmascript/util-regexp.js
  15. 6
      tests/ecmascript/util-string.js

5
RELEASES.rst

@ -3190,8 +3190,9 @@ Planned
2.3.0 (XXXX-XX-XX)
------------------
* ES2015 Number built-in bindings: Number.parseInt(), Number.parseFloat()
(GH-1756)
* ES2015 Number constructor properties: EPSILON, MIN_SAFE_INTEGER,
MAX_SAFE_INTEGER, isFinite(), isInteger(), isNaN(), isSafeInteger(),
parseInt(), parseFloat() (GH-1756, GH-1761)
* Fix trailing single line comment handling for Function constructor;
new Function('return "foo" //') previously failed with SyntaxError

61
src-input/builtins.yaml

@ -1522,7 +1522,68 @@ objects:
type: double
bytes: "fff0000000000000" # DBL_NEGATIVE_INFINITY
attributes: ""
- key: "EPSILON"
value:
type: double
bytes: "3cb0000000000000" # 3ff0000000000001 - 3ff0000000000000 = 3cb0000000000000
attributes: ""
es6: true
present_if: DUK_USE_ES6
- key: "MAX_SAFE_INTEGER"
value:
# >>> struct.pack('>d', 9007199254740991.0).encode('hex')
# '433fffffffffffff'
type: double
bytes: "433fffffffffffff"
attributes: ""
es6: true
present_if: DUK_USE_ES6
- key: "MIN_SAFE_INTEGER"
value:
# >>> struct.pack('>d', -9007199254740991.0).encode('hex')
# 'c33fffffffffffff'
type: double
bytes: "c33fffffffffffff"
attributes: ""
es6: true
present_if: DUK_USE_ES6
- key: "isFinite"
value:
type: function
native: duk_bi_number_check_shared
length: 1
magic: 0
attributes: "wc"
es6: true
present_if: DUK_USE_ES6
- key: "isInteger"
value:
type: function
native: duk_bi_number_check_shared
length: 1
magic: 1
attributes: "wc"
es6: true
present_if: DUK_USE_ES6
- key: "isNaN"
value:
type: function
native: duk_bi_number_check_shared
length: 1
magic: 2
attributes: "wc"
es6: true
present_if: DUK_USE_ES6
- key: "isSafeInteger"
value:
type: function
native: duk_bi_number_check_shared
length: 1
magic: 3
attributes: "wc"
es6: true
present_if: DUK_USE_ES6
- key: "parseInt" # Must map to the exactly same object as global parseInt()
value:
type: object

36
src-input/duk_bi_number.c

@ -237,4 +237,40 @@ DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_precision(duk_hthread *thr) {
return 1;
}
/*
* ES2015 isFinite() etc
*/
#if defined(DUK_USE_ES6)
DUK_INTERNAL duk_ret_t duk_bi_number_check_shared(duk_hthread *thr) {
duk_int_t magic;
duk_bool_t ret = 0;
if (duk_is_number(thr, 0)) {
duk_double_t d;
magic = duk_get_current_magic(thr);
d = duk_get_number(thr, 0);
switch (magic) {
case 0: /* isFinite() */
ret = duk_double_is_finite(d);
break;
case 1: /* isInteger() */
ret = duk_double_is_integer(d);
break;
case 2: /* isNaN() */
ret = duk_double_is_nan(d);
break;
default: /* isSafeInteger() */
DUK_ASSERT(magic == 3);
ret = duk_double_is_safe_integer(d);
}
}
duk_push_boolean(thr, ret);
return 1;
}
#endif /* DUK_USE_ES6 */
#endif /* DUK_USE_NUMBER_BUILTIN */

3
src-input/duk_util.h

@ -560,5 +560,8 @@ DUK_INTERNAL_DECL duk_double_t duk_double_trunc_towards_zero(duk_double_t x);
DUK_INTERNAL_DECL duk_bool_t duk_double_same_sign(duk_double_t x, duk_double_t y);
DUK_INTERNAL_DECL duk_double_t duk_double_fmin(duk_double_t x, duk_double_t y);
DUK_INTERNAL_DECL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y);
DUK_INTERNAL_DECL duk_bool_t duk_double_is_finite(duk_double_t x);
DUK_INTERNAL_DECL duk_bool_t duk_double_is_integer(duk_double_t x);
DUK_INTERNAL_DECL duk_bool_t duk_double_is_safe_integer(duk_double_t x);
#endif /* DUK_UTIL_H_INCLUDED */

19
src-input/duk_util_misc.c

@ -403,3 +403,22 @@ DUK_INTERNAL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y) {
*/
return (x > y ? x : y);
}
DUK_INTERNAL duk_bool_t duk_double_is_finite(duk_double_t x) {
return !duk_double_is_nan_or_inf(x);
}
DUK_INTERNAL duk_bool_t duk_double_is_integer(duk_double_t x) {
if (duk_double_is_nan_or_inf(x)) {
return 0;
} else {
return duk_js_tointeger_number(x) == x;
}
}
DUK_INTERNAL duk_bool_t duk_double_is_safe_integer(duk_double_t x) {
/* >>> 2**53-1
* 9007199254740991
*/
return duk_double_is_integer(x) && DUK_FABS(x) <= 9007199254740991.0;
}

41
tests/ecmascript/test-bi-number-isfinite.js

@ -0,0 +1,41 @@
/*===
function
propdesc isFinite: value=function:isFinite, writable=true, enumerable=false, configurable=true
propdesc length: value=1, writable=false, enumerable=false, configurable=true
propdesc name: value="isFinite", writable=false, enumerable=false, configurable=true
-Infinity false
-1e+100 true
-1234567890.2 true
-305419896 true
-0 true
0 true
305419896 true
1234567890.2 true
1e+100 true
Infinity false
NaN false
undefined false
null false
"" false
"123" false
true false
false false
[object Object] false
===*/
/*@include util-base.js@*/
print(typeof Number.isFinite);
print(Test.getPropDescString(Number, 'isFinite'));
print(Test.getPropDescString(Number.isFinite, 'length'));
print(Test.getPropDescString(Number.isFinite, 'name'));
[
-1 / 0, -1e100, -1234567890.2, -0x12345678, -0,
+0, 0x12345678, 1234567890.2, 1e100, 1 / 0,
0 / 0,
void 0, null, '', '123', true, false,
{ valueOf: function () { return 123.0; } }
].forEach(function (v) {
print(Test.valueToString(v), Test.valueToString(Number.isFinite(v)));
});

41
tests/ecmascript/test-bi-number-isinteger.js

@ -0,0 +1,41 @@
/*===
function
propdesc isInteger: value=function:isInteger, writable=true, enumerable=false, configurable=true
propdesc length: value=1, writable=false, enumerable=false, configurable=true
propdesc name: value="isInteger", writable=false, enumerable=false, configurable=true
-Infinity false
-1e+100 true
-1234567890.2 false
-305419896 true
-0 true
0 true
305419896 true
1234567890.2 false
1e+100 true
Infinity false
NaN false
undefined false
null false
"" false
"123" false
true false
false false
[object Object] false
===*/
/*@include util-base.js@*/
print(typeof Number.isInteger);
print(Test.getPropDescString(Number, 'isInteger'));
print(Test.getPropDescString(Number.isInteger, 'length'));
print(Test.getPropDescString(Number.isInteger, 'name'));
[
-1 / 0, -1e100, -1234567890.2, -0x12345678, -0,
+0, 0x12345678, 1234567890.2, 1e100, 1 / 0,
0 / 0,
void 0, null, '', '123', true, false,
{ valueOf: function () { return 123.0; } }
].forEach(function (v) {
print(Test.valueToString(v), Test.valueToString(Number.isInteger(v)));
});

41
tests/ecmascript/test-bi-number-isnan.js

@ -0,0 +1,41 @@
/*===
function
propdesc isNaN: value=function:isNaN, writable=true, enumerable=false, configurable=true
propdesc length: value=1, writable=false, enumerable=false, configurable=true
propdesc name: value="isNaN", writable=false, enumerable=false, configurable=true
-Infinity false
-1e+100 false
-1234567890.2 false
-305419896 false
-0 false
0 false
305419896 false
1234567890.2 false
1e+100 false
Infinity false
NaN true
undefined false
null false
"" false
"123" false
true false
false false
[object Object] false
===*/
/*@include util-base.js@*/
print(typeof Number.isNaN);
print(Test.getPropDescString(Number, 'isNaN'));
print(Test.getPropDescString(Number.isNaN, 'length'));
print(Test.getPropDescString(Number.isNaN, 'name'));
[
-1 / 0, -1e100, -1234567890.2, -0x12345678, -0,
+0, 0x12345678, 1234567890.2, 1e100, 1 / 0,
0 / 0,
void 0, null, '', '123', true, false,
{ valueOf: function () { return 123.0; } }
].forEach(function (v) {
print(Test.valueToString(v), Test.valueToString(Number.isNaN(v)));
});

57
tests/ecmascript/test-bi-number-issafeinteger.js

@ -0,0 +1,57 @@
/*===
function
propdesc isSafeInteger: value=function:isSafeInteger, writable=true, enumerable=false, configurable=true
propdesc length: value=1, writable=false, enumerable=false, configurable=true
propdesc name: value="isSafeInteger", writable=false, enumerable=false, configurable=true
-Infinity false
-1e+100 false
-1234567890.2 false
-305419896 true
-0 true
0 true
305419896 true
1234567890.2 false
1e+100 false
Infinity false
NaN false
-9007199254740992 false
-9007199254740991 true
-9007199254740990 true
9007199254740992 false
9007199254740991 true
9007199254740990 true
undefined false
null false
"" false
"123" false
true false
false false
[object Object] false
===*/
/*@include util-base.js@*/
print(typeof Number.isSafeInteger);
print(Test.getPropDescString(Number, 'isSafeInteger'));
print(Test.getPropDescString(Number.isSafeInteger, 'length'));
print(Test.getPropDescString(Number.isSafeInteger, 'name'));
[
-1 / 0, -1e100, -1234567890.2, -0x12345678, -0,
+0, 0x12345678, 1234567890.2, 1e100, 1 / 0,
0 / 0,
// Specific corner case values: note that fractions are not actually
// significant so it suffices to test for integers.
-9007199254740992.0,
-9007199254740991.0,
-9007199254740990.0,
9007199254740992.0,
9007199254740991.0,
9007199254740990.0,
void 0, null, '', '123', true, false,
{ valueOf: function () { return 123.0; } }
].forEach(function (v) {
print(Test.valueToString(v), Test.valueToString(Number.isSafeInteger(v)));
});

34
tests/ecmascript/test-bi-number-values.js

@ -1,29 +1,25 @@
/*===
MAX_VALUE -> number 1.7976931348623157e+308
writable=false, enumerable=false, configurable=false
MIN_VALUE -> number 5e-324
writable=false, enumerable=false, configurable=false
NaN -> number NaN
writable=false, enumerable=false, configurable=false
POSITIVE_INFINITY -> number Infinity
writable=false, enumerable=false, configurable=false
NEGATIVE_INFINITY -> number -Infinity
writable=false, enumerable=false, configurable=false
propdesc MAX_VALUE: value=1.7976931348623157e+308, writable=false, enumerable=false, configurable=false
propdesc MIN_VALUE: value=5e-324, writable=false, enumerable=false, configurable=false
propdesc NaN: value=NaN, writable=false, enumerable=false, configurable=false
propdesc POSITIVE_INFINITY: value=Infinity, writable=false, enumerable=false, configurable=false
propdesc NEGATIVE_INFINITY: value=-Infinity, writable=false, enumerable=false, configurable=false
propdesc EPSILON: value=2.220446049250313e-16, writable=false, enumerable=false, configurable=false
propdesc MAX_SAFE_INTEGER: value=9007199254740991, writable=false, enumerable=false, configurable=false
propdesc MIN_SAFE_INTEGER: value=-9007199254740991, writable=false, enumerable=false, configurable=false
===*/
/*@include util-base.js@*/
function valueTest() {
var names = [ 'MAX_VALUE', 'MIN_VALUE', 'NaN', 'POSITIVE_INFINITY', 'NEGATIVE_INFINITY' ];
var names = [
'MAX_VALUE', 'MIN_VALUE', 'NaN', 'POSITIVE_INFINITY', 'NEGATIVE_INFINITY',
'EPSILON', 'MAX_SAFE_INTEGER', 'MIN_SAFE_INTEGER'
];
var i;
var pd, v;
for (i = 0; i < names.length; i++) {
pd = Object.getOwnPropertyDescriptor(Number, names[i]);
if (!pd) { print('does not exist'); continue; }
v = pd.value;
print(names[i], '->', typeof v, v);
print('writable=' + pd.writable +
', enumerable=' + pd.enumerable +
', configurable=' + pd.configurable);
print(Test.getPropDescString(Number, names[i]));
}
}

3
tests/ecmascript/test-bi-typedarray-coercion.js

@ -6,6 +6,7 @@
* expect string.
*/
/*@include util-base.js@*/
/*@include util-buffer.js@*/
/*@include util-string.js@*/
@ -1974,7 +1975,7 @@ function coercionTest() {
}
vals.forEach(function (v, j) {
b[0] = v;
print(j, v, '->', numberToString(b[0]));
print(j, v, '->', Test.valueToString(b[0]));
});
});
}

4
tests/ecmascript/test-bi-typedarray-floatdouble.js

@ -2,8 +2,8 @@
* Test float assignment and reading it back.
*/
/*@include util-base.js@*/
/*@include util-buffer.js@*/
/*@include util-string.js@*/
/*---
{
@ -98,7 +98,7 @@ function floatDoubleTest() {
values.forEach(function (v, i) {
v1[0] = v;
print(i, numberToString(v), numberToString(v1[0]));
print(i, Test.valueToString(v), Test.valueToString(v1[0]));
});
}

94
tests/ecmascript/util-base.js

@ -0,0 +1,94 @@
/*
* Basic test utilities in a global 'Test' binding.
*/
(function initTest() {
var GLOBAL = new Function('return this')();
var Test = GLOBAL.Test;
if (typeof Test !== 'object') {
Test = {};
Object.defineProperty(GLOBAL, 'Test', {
value: Test, writable: false, enumerable: false, configurable: false
});
}
// Summarize any value to a printable string, avoiding side effects where
// possible, preserving details like zero sign.
function valueToString(x) {
if (x === void 0) {
return 'undefined';
} else if (x === null) {
return 'null';
} else if (typeof x === 'boolean') {
return String(x);
} else if (typeof x === 'number') {
if (x !== 0) {
return String(x);
} else {
return (1 / x > 0) ? '0' : '-0';
}
} else if (typeof x === 'string') {
return JSON.stringify(x);
} else if (typeof x === 'symbol') {
return String(x);
} else if (typeof x === 'object') {
return Object.prototype.toString.call(x);
} else if (typeof x === 'function') {
var pd = Object.getOwnPropertyDescriptor(x, 'name');
if (pd && typeof pd.value === 'string') {
return 'function:' + pd.value;
} else {
return 'function';
}
} else if (typeof x === 'pointer') {
if (String(x) === 'null') {
return 'pointer:null';
} else {
return 'pointer:non-null'; // specific pointer is very rarely interesting for tests
}
} else if (typeof x === 'buffer') {
// No longer used in Duktape 2.x.
return 'buffer:' + x.length;
} else {
return 'unknown:' + String(x);
}
}
// Get property descriptor string for arbitrary object and key.
function getPropDescString(obj, key) {
if (obj === void 0) {
return 'propdesc ' + key + ': undefined object';
} else if (obj === null) {
return 'propdesc ' + key + ': null object';
} else {
try {
var pd = Object.getOwnPropertyDescriptor(obj, key);
var parts = [];
if (typeof pd.value !== 'undefined') {
parts.push('value=' + valueToString(pd.value));
}
if (typeof pd.writable !== 'undefined') {
parts.push('writable=' + valueToString(pd.writable));
}
if (typeof pd.enumerable !== 'undefined') {
parts.push('enumerable=' + valueToString(pd.enumerable));
}
if (typeof pd.configurable !== 'undefined') {
parts.push('configurable=' + valueToString(pd.configurable));
}
if (typeof pd.get !== 'undefined') {
parts.push('get=' + valueToString(pd.get));
}
if (typeof pd.set !== 'undefined') {
parts.push('set=' + valueToString(pd.set));
}
return 'propdesc ' + key + ': ' + parts.join(', ');
} catch (e) {
return 'propdesc ' + key + ': ' + String(e);
}
}
}
Test.valueToString = valueToString;
Test.getPropDescString = getPropDescString;
}());

4
tests/ecmascript/util-regexp.js

@ -1,5 +1,7 @@
if (typeof RegExpUtil !== 'object') {
RegExpUtil = {};
Object.defineProperty(new Function('return this')(), 'RegExpUtil', {
value: {}, writable: false, enumerable: false, configurable: false
});
}
// Get a list of character repeats in an input string. For example, for

6
tests/ecmascript/util-string.js

@ -15,12 +15,6 @@ function checksumString(x) {
return res;
}
// Number to string, preserve negative zero sign.
function numberToString(v) {
if (v !== 0) { return String(v); }
return (1 / v > 0) ? '0' : '-0';
}
// Escape a string with codepoint escaping.
function safeEscapeString(s) {
var tmp = [];

Loading…
Cancel
Save