return IsAccessorDescriptor(desc) && IsDataDescriptor(desc);
}
+
// ES5 8.10.4
function FromPropertyDescriptor(desc) {
if (IS_UNDEFINED(desc)) return desc;
}
+// For Harmony proxies.
+function ToCompletePropertyDescriptor(obj) {
+ var desc = ToPropertyDescriptor(obj)
+ if (IsGenericDescriptor(desc) || IsDataDescriptor(desc)) {
+ if (!("value" in desc)) desc.value = void 0;
+ if (!("writable" in desc)) desc.writable = false;
+ } else {
+ // Is accessor descriptor.
+ if (!("get" in desc)) desc.get = void 0;
+ if (!("set" in desc)) desc.set = void 0;
+ }
+ if (!("enumerable" in desc)) desc.enumerable = false;
+ if (!("configurable" in desc)) desc.configurable = false;
+ return desc;
+}
+
+
function PropertyDescriptor() {
// Initialize here so they are all in-object and have the same map.
// Default values from ES5 8.6.1.
// ES5 section 8.12.2.
function GetProperty(obj, p) {
+ if (%IsJSProxy(obj)) {
+ var handler = %GetHandler(obj);
+ var getProperty = handler.getPropertyDescriptor;
+ if (IS_UNDEFINED(getProperty)) {
+ throw MakeTypeError("handler_trap_missing",
+ [handler, "getPropertyDescriptor"]);
+ }
+ var descriptor = getProperty.call(handler, p);
+ if (IS_UNDEFINED(descriptor)) return descriptor;
+ var desc = ToCompletePropertyDescriptor(descriptor);
+ if (!desc.configurable) {
+ throw MakeTypeError("proxy_prop_not_configurable",
+ [handler, "getPropertyDescriptor", p, descriptor]);
+ }
+ return desc;
+ }
var prop = GetOwnProperty(obj);
if (!IS_UNDEFINED(prop)) return prop;
- var proto = obj.__proto__;
+ var proto = %GetPrototype(obj);
if (IS_NULL(proto)) return void 0;
return GetProperty(proto, p);
}
// ES5 section 8.12.6
function HasProperty(obj, p) {
+ if (%IsJSProxy(obj)) {
+ var handler = %GetHandler(obj)
+ var has = handler.has
+ if (IS_UNDEFINED(has)) has = DerivedHasTrap
+ return ToBoolean(has.call(handler, obj, p))
+ }
var desc = GetProperty(obj, p);
return IS_UNDEFINED(desc) ? false : true;
}
function ObjectGetPrototypeOf(obj) {
if (!IS_SPEC_OBJECT(obj))
throw MakeTypeError("obj_ctor_property_non_object", ["getPrototypeOf"]);
- return obj.__proto__;
+ return %GetPrototype(obj);
}
}
+// For Harmony proxies
+function ToStringArray(obj, trap) {
+ if (!IS_SPEC_OBJECT(obj)) {
+ throw MakeTypeError("proxy_non_object_prop_names", [obj, trap]);
+ }
+ var n = ToUint32(obj.length);
+ var array = new $Array(n);
+ var names = {}
+ for (var index = 0; index < n; index++) {
+ var s = ToString(obj[index]);
+ if (s in names) {
+ throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s])
+ }
+ array[index] = s;
+ names.s = 0;
+ }
+ return array;
+}
+
+
// ES5 section 15.2.3.4.
function ObjectGetOwnPropertyNames(obj) {
if (!IS_SPEC_OBJECT(obj))
throw MakeTypeError("obj_ctor_property_non_object", ["getOwnPropertyNames"]);
+ // Special handling for proxies.
+ if (%IsJSProxy(obj)) {
+ var handler = %GetHandler(obj);
+ var getOwnPropertyNames = handler.getOwnPropertyNames;
+ if (IS_UNDEFINED(getOwnPropertyNames)) {
+ throw MakeTypeError("handler_trap_missing",
+ [handler, "getOwnPropertyNames"]);
+ }
+ var names = getOwnPropertyNames.call(handler);
+ return ToStringArray(names, "getOwnPropertyNames");
+ }
+
// Find all the indexed properties.
// Get the local element names.
// assertEquals(Object.getOwnPropertyDescriptor(o, "b").value, 42)
}
-TestGet({get: function(r, k) { return 42 }})
-TestGet({getPropertyDescriptor: function(k) { return {value: 42} }})
-TestGet({getPropertyDescriptor: function(k) { return {get value() { return 42 }} }})
-TestGet({get: undefined, getPropertyDescriptor: function(k) { return {value: 42} }})
+TestGet({
+ get: function(r, k) { return 42 }
+})
+TestGet({
+ get: function(r, k) { return this.get2(r, k) },
+ get2: function(r, k) { return 42 }
+})
+TestGet({
+ getPropertyDescriptor: function(k) { return {value: 42} }
+})
+TestGet({
+ getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) },
+ getPropertyDescriptor2: function(k) { return {value: 42} }
+})
+TestGet({
+ getPropertyDescriptor: function(k) {
+ return {get value() { return 42 }}
+ }
+})
+TestGet({
+ get: undefined,
+ getPropertyDescriptor: function(k) { return {value: 42} }
+})
-TestGet(Proxy.create({get: function(pr, pk) { return function(r, k) { return 42 } }}))
+TestGet(Proxy.create({
+ get: function(pr, pk) {
+ return function(r, k) { return 42 }
+ }
+}))
// assertEquals(44, val)
}
-TestSet({set: function(r, k, v) { key = k; val = v; return true }})
-TestSet({getOwnPropertyDescriptor: function(k) { return {writable: true} },
- defineProperty: function(k, desc) { key = k, val = desc.value }})
-TestSet({getOwnPropertyDescriptor: function(k) { return {get writable() { return true }} },
- defineProperty: function(k, desc) { key = k, val = desc.value }})
-TestSet({getOwnPropertyDescriptor: function(k) { return {set: function(v) { key = k, val = v }} }})
-TestSet({getOwnPropertyDescriptor: function(k) { return null },
- getPropertyDescriptor: function(k) { return {writable: true} },
- defineProperty: function(k, desc) { key = k, val = desc.value }})
-TestSet({getOwnPropertyDescriptor: function(k) { return null },
- getPropertyDescriptor: function(k) { return {get writable() { return true }} },
- defineProperty: function(k, desc) { key = k, val = desc.value }})
-TestSet({getOwnPropertyDescriptor: function(k) { return null },
- getPropertyDescriptor: function(k) { return {set: function(v) { key = k, val = v }} }})
-TestSet({getOwnPropertyDescriptor: function(k) { return null },
- getPropertyDescriptor: function(k) { return null },
- defineProperty: function(k, desc) { key = k, val = desc.value }})
+TestSet({
+ set: function(r, k, v) { key = k; val = v; return true }
+})
+TestSet({
+ set: function(r, k, v) { return this.set2(r, k, v) },
+ set2: function(r, k, v) { key = k; val = v; return true }
+})
+TestSet({
+ getOwnPropertyDescriptor: function(k) { return {writable: true} },
+ defineProperty: function(k, desc) { key = k; val = desc.value }
+})
+TestSet({
+ getOwnPropertyDescriptor: function(k) {
+ return this.getOwnPropertyDescriptor2(k)
+ },
+ getOwnPropertyDescriptor2: function(k) { return {writable: true} },
+ defineProperty: function(k, desc) { this.defineProperty2(k, desc) },
+ defineProperty2: function(k, desc) { key = k; val = desc.value }
+})
+TestSet({
+ getOwnPropertyDescriptor: function(k) {
+ return {get writable() { return true }}
+ },
+ defineProperty: function(k, desc) { key = k; val = desc.value }
+})
+TestSet({
+ getOwnPropertyDescriptor: function(k) {
+ return {set: function(v) { key = k; val = v }}
+ }
+})
+TestSet({
+ getOwnPropertyDescriptor: function(k) { return null },
+ getPropertyDescriptor: function(k) { return {writable: true} },
+ defineProperty: function(k, desc) { key = k; val = desc.value }
+})
+TestSet({
+ getOwnPropertyDescriptor: function(k) { return null },
+ getPropertyDescriptor: function(k) {
+ return {get writable() { return true }}
+ },
+ defineProperty: function(k, desc) { key = k; val = desc.value }
+})
+TestSet({
+ getOwnPropertyDescriptor: function(k) { return null },
+ getPropertyDescriptor: function(k) {
+ return {set: function(v) { key = k; val = v }}
+ }
+})
+TestSet({
+ getOwnPropertyDescriptor: function(k) { return null },
+ getPropertyDescriptor: function(k) { return null },
+ defineProperty: function(k, desc) { key = k, val = desc.value }
+})
-TestSet(Proxy.create({get: function(pr, pk) { return function(r, k, v) { key = k; val = v; return true } }}))
+TestSet(Proxy.create({
+ get: function(pr, pk) {
+ return function(r, k, v) { key = k; val = v; return true }
+ }
+}))
// Comparison.
-var o1 = Proxy.create({})
-var o2 = Proxy.create({})
+function TestComparison(eq) {
+ var o1 = Proxy.create({})
+ var o2 = Proxy.create({})
-assertTrue(o1 == o1)
-assertTrue(o2 == o2)
-assertTrue(!(o1 == o2))
-assertTrue(!(o1 == {}))
-assertTrue(!({} == o2))
-assertTrue(!({} == {}))
+ assertTrue(eq(o1, o1))
+ assertTrue(eq(o2, o2))
+ assertTrue(!eq(o1, o2))
+ assertTrue(!eq(o1, {}))
+ assertTrue(!eq({}, o2))
+ assertTrue(!eq({}, {}))
+}
-assertTrue(o1 === o1)
-assertTrue(o2 === o2)
-assertTrue(!(o1 === o2))
-assertTrue(!(o1 === {}))
-assertTrue(!({} === o2))
-assertTrue(!({} === {}))
+TestComparison(function(o1, o2) { return o1 == o2 })
+TestComparison(function(o1, o2) { return o1 === o2 })
+TestComparison(function(o1, o2) { return !(o1 != o2) })
+TestComparison(function(o1, o2) { return !(o1 !== o2) })
assertTrue("object" == typeof Proxy.create({}))
// No function proxies yet.
+
+
+
+// Instanceof (instanceof).
+
+function TestInstanceof() {
+ var o = {}
+ var p1 = Proxy.create({})
+ var p2 = Proxy.create({}, o)
+ var p3 = Proxy.create({}, p2)
+
+ var f = function() {}
+ f.prototype = o
+ var f1 = function() {}
+ f1.prototype = p1
+ var f2 = function() {}
+ f2.prototype = p2
+
+ assertTrue(o instanceof Object)
+ assertFalse(o instanceof f)
+ assertFalse(o instanceof f1)
+ assertFalse(o instanceof f2)
+ assertFalse(p1 instanceof Object)
+ assertFalse(p1 instanceof f)
+ assertFalse(p1 instanceof f1)
+ assertFalse(p1 instanceof f2)
+ assertTrue(p2 instanceof Object)
+ assertTrue(p2 instanceof f)
+ assertFalse(p2 instanceof f1)
+ assertFalse(p2 instanceof f2)
+ assertTrue(p3 instanceof Object)
+ assertTrue(p3 instanceof f)
+ assertFalse(p3 instanceof f1)
+ assertTrue(p3 instanceof f2)
+}
+
+TestInstanceof()
+
+
+
+// Prototype (Object.getPrototypeOf).
+
+function TestPrototype() {
+ var o = {}
+ var p1 = Proxy.create({})
+ var p2 = Proxy.create({}, o)
+ var p3 = Proxy.create({}, p2)
+ var p4 = Proxy.create({}, 666)
+
+ assertSame(Object.getPrototypeOf(o), Object.prototype)
+ assertSame(Object.getPrototypeOf(p1), null)
+ assertSame(Object.getPrototypeOf(p2), o)
+ assertSame(Object.getPrototypeOf(p3), p2)
+ assertSame(Object.getPrototypeOf(p4), null)
+}
+
+TestPrototype()
+
+
+
+// Property names (Object.getOwnPropertyNames).
+
+function TestPropertyNames(names, handler) {
+ var p = Proxy.create(handler)
+ assertArrayEquals(names, Object.getOwnPropertyNames(p))
+}
+
+TestPropertyNames([], {
+ getOwnPropertyNames: function() { return [] }
+})
+TestPropertyNames(["a", "zz", " ", "0"], {
+ getOwnPropertyNames: function() { return ["a", "zz", " ", 0] }
+})
+TestPropertyNames(["throw", "function "], {
+ getOwnPropertyNames: function() { return this.getOwnPropertyNames2() },
+ getOwnPropertyNames2: function() { return ["throw", "function "] }
+})
+TestPropertyNames(["[object Object]"], {
+ get getOwnPropertyNames() {
+ return function() { return [{}] }
+ }
+})