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:
Robert Fancsik
2019-01-16 10:09:23 +01:00
committed by Robert Sipka
parent 08c7183ef8
commit 7e3d688e5b
43 changed files with 1896 additions and 212 deletions
@@ -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);
}
+60
View File
@@ -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);
+122
View File
@@ -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]);