Implement the Symbol builtin object (#2601)
This patch contains the base functionalities that the new builtin object requires.
Currently unavailable:
- print (Symbol('foo')) - this features requires the refactor of the print handler function
- Several global symbol based builtin routines (follow up patch)
JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu
This commit is contained in:
committed by
Robert Sipka
parent
08c7183ef8
commit
7e3d688e5b
@@ -0,0 +1,119 @@
|
||||
/* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Test array
|
||||
var a = Symbol ('a');
|
||||
var b = Symbol ('b');
|
||||
var c = Symbol ('c');
|
||||
var d = Symbol ();
|
||||
|
||||
var arr = [a, b, c, d];
|
||||
var props = Object.getOwnPropertySymbols (arr);
|
||||
// props should not contain: a, b, c, d
|
||||
assert (props.indexOf ('0') === -1);
|
||||
assert (props.indexOf ('1') === -1);
|
||||
assert (props.indexOf ('2') === -1);
|
||||
assert (props.indexOf ('length') === -1);
|
||||
assert (props.length === 0);
|
||||
|
||||
// Test object
|
||||
var obj = {};
|
||||
obj[a] = 'a';
|
||||
obj[b] = 'b';
|
||||
obj[c] = 'c';
|
||||
obj[d] = 'd';
|
||||
props = Object.getOwnPropertySymbols (obj);
|
||||
// props should contain: a, b, c, d and the order is not defined!
|
||||
assert (props.indexOf(a) !== -1);
|
||||
assert (props.indexOf(b) !== -1);
|
||||
assert (props.indexOf(c) !== -1);
|
||||
assert (props.indexOf(d) !== -1);
|
||||
assert (props.length === 4);
|
||||
|
||||
// Test same descriptions
|
||||
var fooSymbol1 = Symbol ('foo');
|
||||
var fooSymbol2 = Symbol ('foo');
|
||||
var fooSymbol3 = Symbol ('foo');
|
||||
var fooSymbol4 = Symbol ('foo');
|
||||
|
||||
var obj = {}
|
||||
obj[fooSymbol1] = 'foo';
|
||||
obj[fooSymbol2] = 'bar';
|
||||
obj[fooSymbol3] = 'foobar';
|
||||
obj[fooSymbol4] = 'barfoo';
|
||||
|
||||
props = Object.getOwnPropertySymbols (obj);
|
||||
assert (props.indexOf (fooSymbol1) !== -1);
|
||||
assert (props.indexOf (fooSymbol2) !== -1);
|
||||
assert (props.indexOf (fooSymbol3) !== -1);
|
||||
assert (props.indexOf (fooSymbol4) !== -1);
|
||||
assert (props.length === 4);
|
||||
|
||||
var mixed_object = {};
|
||||
var foo = Symbol ('foo');
|
||||
var bar = Symbol.for ('bar');
|
||||
|
||||
mixed_object[foo] = 'localSymbol';
|
||||
mixed_object[bar] = 'globalSymbol';
|
||||
mixed_object['foo'] = 'string';
|
||||
|
||||
var props = Object.getOwnPropertySymbols (mixed_object);
|
||||
|
||||
assert (typeof props[0] === 'symbol')
|
||||
assert (props.indexOf(foo) !== -1);
|
||||
assert (props.indexOf(bar) !== -1);
|
||||
assert (props.indexOf('foo') === -1);
|
||||
assert (props.length === 2)
|
||||
|
||||
// Test prototype chain
|
||||
function Parent() {}
|
||||
Parent.prototype.inheritedMethod = function() {};
|
||||
|
||||
function Child() {
|
||||
this[a] = 5;
|
||||
this[b] = function() {};
|
||||
}
|
||||
Child.prototype = new Parent;
|
||||
Child.prototype.prototypeMethod = function() {};
|
||||
|
||||
props = Object.getOwnPropertySymbols (new Child());
|
||||
// props should contain: a, b and the order is not defined!
|
||||
assert (props.indexOf(a) !== -1);
|
||||
assert (props.indexOf(b) !== -1);
|
||||
|
||||
assert (props.length === 2);
|
||||
|
||||
// Test non-emumerable symbols
|
||||
var object = {};
|
||||
var foo = Symbol ('foo');
|
||||
var foo2 = Symbol ('foo2');
|
||||
object[foo] = 'EnumerableSymbolProp';
|
||||
Object.defineProperty(object, foo2, { value : 'NonEnumerableSymbolProp' });
|
||||
|
||||
props = Object.getOwnPropertySymbols (object);
|
||||
|
||||
assert (props.indexOf(foo) !== -1);
|
||||
assert (props.indexOf(foo2) !== -1);
|
||||
assert (props.length === 2);
|
||||
assert (Object.getOwnPropertyDescriptor (object, foo).enumerable === true);
|
||||
assert (Object.getOwnPropertyDescriptor (object, foo2).enumerable === false);
|
||||
|
||||
// Test non-object argument
|
||||
try {
|
||||
Object.getOwnPropertySymbols ('hello');
|
||||
assert (false);
|
||||
} catch (e) {
|
||||
assert (e instanceof TypeError);
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
try {
|
||||
Symbol.for (Symbol('foo'));
|
||||
assert (false);
|
||||
} catch (e) {
|
||||
assert (e instanceof TypeError)
|
||||
}
|
||||
|
||||
var a = Symbol.for ('foo');
|
||||
var b = Symbol.for ('foo');
|
||||
|
||||
assert (a === b);
|
||||
assert (a == b);
|
||||
|
||||
assert (Symbol.keyFor (a) === 'foo');
|
||||
assert (Symbol.keyFor (b) === 'foo');
|
||||
|
||||
// Test non-string arguments
|
||||
var c = Symbol.for (5);
|
||||
var d = Symbol.for (5.58);
|
||||
var e = Symbol.for ({});
|
||||
|
||||
assert (Symbol.keyFor (c) === '5');
|
||||
assert (Symbol.keyFor (d) === '5.58');
|
||||
assert (Symbol.keyFor (e) === '[object Object]');
|
||||
|
||||
// Test global symbol table
|
||||
var array = [];
|
||||
for (var i = 0; i < 15; i++) {
|
||||
array[i] = Symbol.for ('foo' + i);
|
||||
|
||||
for (var j = 0; j < i; j++) {
|
||||
assert (array[j] !== array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Symbol.keyFor ('NonSymbolValue');
|
||||
assert (false);
|
||||
} catch (e) {
|
||||
assert (e instanceof TypeError);
|
||||
}
|
||||
|
||||
for (var i = 0; i < 15; i++) {
|
||||
assert (Symbol.keyFor (array[i]) === ('foo' + i));
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
try {
|
||||
Symbol.prototype[Symbol.toPrimitive].call ('NonSymbolValue');
|
||||
assert (false);
|
||||
} catch (e) {
|
||||
assert (e instanceof TypeError);
|
||||
}
|
||||
|
||||
try {
|
||||
Symbol.prototype[Symbol.toPrimitive].call ({});
|
||||
assert (false);
|
||||
} catch (e) {
|
||||
assert (e instanceof TypeError);
|
||||
}
|
||||
|
||||
var foo = Symbol ('foo');
|
||||
assert (foo[Symbol.toPrimitive] () === foo);
|
||||
|
||||
var fooObj = Object (foo);
|
||||
assert (fooObj[Symbol.toPrimitive] () === foo);
|
||||
@@ -0,0 +1,34 @@
|
||||
/* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
try {
|
||||
Symbol.prototype.toString.call ('NonSymbolValue');
|
||||
assert (false);
|
||||
} catch (e) {
|
||||
assert (e instanceof TypeError);
|
||||
}
|
||||
|
||||
try {
|
||||
Symbol.prototype.toString.call ({});
|
||||
assert (false);
|
||||
} catch (e) {
|
||||
assert (e instanceof TypeError);
|
||||
}
|
||||
|
||||
var foo = Symbol ('foo');
|
||||
assert (foo.toString () === "Symbol(foo)");
|
||||
|
||||
var fooObj = Object (foo);
|
||||
assert (fooObj.toString () === "Symbol(foo)");
|
||||
@@ -0,0 +1,34 @@
|
||||
/* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
try {
|
||||
Symbol.prototype.valueOf.call ('NonSymbolValue');
|
||||
assert (false);
|
||||
} catch (e) {
|
||||
assert (e instanceof TypeError);
|
||||
}
|
||||
|
||||
try {
|
||||
Symbol.prototype.valueOf.call ({});
|
||||
assert (false);
|
||||
} catch (e) {
|
||||
assert (e instanceof TypeError);
|
||||
}
|
||||
|
||||
var foo = Symbol ('foo');
|
||||
assert (foo.valueOf () === foo);
|
||||
|
||||
var fooObj = Object (foo);
|
||||
assert (fooObj.valueOf () === foo);
|
||||
@@ -0,0 +1,122 @@
|
||||
/* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var a = Symbol ('foo');
|
||||
var b = Symbol ('bar');
|
||||
|
||||
assert (a !== b);
|
||||
assert (a === a);
|
||||
assert (typeof a === 'symbol');
|
||||
assert (a.toString() == 'Symbol(foo)');
|
||||
assert (Object.prototype.toString.call (a) === "[object Symbol]");
|
||||
assert (JSON.stringify (a) === undefined);
|
||||
|
||||
var obj = { c : 10, d : 20};
|
||||
obj[a] = 'EnumerableSymbolProp';
|
||||
assert (obj[a] === 'EnumerableSymbolProp');
|
||||
|
||||
// Symbol properties are not listed via for in
|
||||
Object.defineProperty(obj, b, { value : 'NonEnumerableSymbolProp' });
|
||||
|
||||
var counter = 0;
|
||||
|
||||
for (var v in obj) {
|
||||
assert (v === 'c' || v === 'd');
|
||||
counter++;
|
||||
}
|
||||
|
||||
assert (counter === 2);
|
||||
|
||||
var keys = Object.keys (obj);
|
||||
assert (keys.length === 2);
|
||||
assert (keys[0] === 'c' || keys[0] === 'd');
|
||||
assert (keys[1] === 'd' || keys[1] === 'c');
|
||||
|
||||
var c = Symbol ('bar');
|
||||
var obj2 = {};
|
||||
obj2[b] = 'foo';
|
||||
obj2[c] = 'bar';
|
||||
|
||||
assert (obj2[b] == 'foo');
|
||||
assert (obj2[c] == 'bar');
|
||||
|
||||
try {
|
||||
new Date (Symbol ('2018-11-09'));
|
||||
assert (false);
|
||||
} catch (e) {
|
||||
assert (e instanceof TypeError);
|
||||
}
|
||||
|
||||
try {
|
||||
a + 'append_string';
|
||||
assert (false);
|
||||
} catch (e) {
|
||||
assert (e instanceof TypeError);
|
||||
}
|
||||
|
||||
assert (Object (a) == a);
|
||||
assert (Object (a) !== a);
|
||||
|
||||
// Test built-in symbols
|
||||
var a = ['hasInstance',
|
||||
'isConcatSpreadable',
|
||||
'iterator',
|
||||
'match',
|
||||
'replace',
|
||||
'search',
|
||||
'species',
|
||||
'split',
|
||||
'toPrimitive',
|
||||
'toStringTag',
|
||||
'unscopables'];
|
||||
|
||||
a.forEach (function (e) {
|
||||
assert (Symbol[e].toString() === ('Symbol(Symbol.' + e +')'));
|
||||
assert (typeof Symbol[e] === 'symbol');
|
||||
});
|
||||
|
||||
var obj = {};
|
||||
Object.defineProperty(obj, a, { 'get' : function () {throw new ReferenceError ('foo'); } });
|
||||
Object.defineProperty(obj, b, { value : 5 });
|
||||
assert (obj[b] === 5);
|
||||
|
||||
try {
|
||||
obj[a];
|
||||
assert (false);
|
||||
} catch (e) {
|
||||
assert (e instanceof ReferenceError);
|
||||
assert (e.message === 'foo');
|
||||
}
|
||||
|
||||
var descriptor = Object.getOwnPropertyDescriptor(obj, b);
|
||||
|
||||
assert (descriptor.configurable === false);
|
||||
assert (descriptor.enumerable === false);
|
||||
assert (descriptor.writable === false);
|
||||
assert (descriptor.value === 5);
|
||||
|
||||
var foo = Symbol ('foo');
|
||||
assert (foo[Symbol.toStringTag] === 'Symbol');
|
||||
|
||||
// Test same descriptions
|
||||
var symA = Symbol ('foobar');
|
||||
var symB = Symbol ('foobar');
|
||||
assert (symA !== symB);
|
||||
assert (symA != symB);
|
||||
|
||||
var obj = { foobar : 55 };
|
||||
obj[symA] = 77;
|
||||
assert (obj["foobar"] !== obj[symA]);
|
||||
assert (obj["foobar"] != obj[symA]);
|
||||
Reference in New Issue
Block a user