Index: src/v8natives.js |
=================================================================== |
--- src/v8natives.js (revision 3427) |
+++ src/v8natives.js (working copy) |
@@ -41,6 +41,7 @@ |
const $isNaN = GlobalIsNaN; |
const $isFinite = GlobalIsFinite; |
+ |
// ---------------------------------------------------------------------------- |
@@ -280,6 +281,208 @@ |
} |
+// ES5 8.10.1. |
+function IsAccessorDescriptor(desc) { |
+ if (IS_UNDEFINED(desc)) return false; |
+ return desc.getSet_ || desc.setSet_; |
+} |
+ |
+ |
+// ES5 8.10.2. |
+function IsDataDescriptor(desc) { |
+ if (IS_UNDEFINED(desc)) return false; |
+ return desc.valueSet_ || desc.writableSet_; |
+} |
+ |
+ |
+// ES5 8.10.3. |
+function IsGenericDescriptor(desc) { |
+ return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc)); |
+} |
+ |
+ |
+function IsInconsistentDescriptor(desc) { |
+ return IsAccessorDescriptor(desc) && IsDataDescriptor(desc); |
+} |
+ |
+ |
+// ES5 8.10.5. |
+function ToPropertyDescriptor(obj) { |
+ if (!IS_OBJECT(obj)) { |
+ throw MakeTypeError(property_desc_object, [obj]); |
+ } |
+ var desc = new PropertyDescriptor(); |
+ |
+ var enumerable = obj.enumerable; |
+ if (!IS_UNDEFINED(enumerable) || "enumerable" in obj) { |
+ desc.setEnumerable(ToBoolean(enumerable)); |
+ } |
+ |
+ var configurable = obj.configurable; |
+ if (!IS_UNDEFINED(configurable) || "configurable" in obj) { |
+ desc.setConfigurable(ToBoolean(configurable)); |
+ } |
+ |
+ var value = obj.value; |
+ if (value !== void 0 || value in obj) desc.setValue(value); |
Christian Plesner Hansen
2009/12/08 20:44:40
IS_UNDEFINED
|
+ |
+ var writable = obj.writable; |
+ if (!IS_UNDEFINED(writable) || "writable" in obj) { |
+ desc.setWritable(ToBoolean(writable)); |
+ } |
+ |
+ var get = obj.get; |
+ if (!IS_UNDEFINED(get) || "get" in obj) { |
+ if (!IS_UNDEFINED(get) && !IS_FUNCTION(get)) { |
+ throw MakeTypeError("getter_must_be_callable", [get]); |
+ } |
+ desc.setGet(get); |
+ } |
+ |
+ var set = obj.set; |
+ if (!IS_UNDEFINED(set) || "set" in obj) { |
+ if (set !== void 0 && !IS_FUNCTION(set)) { |
Christian Plesner Hansen
2009/12/08 20:44:40
IS_UNDEFINED
|
+ throw MakeTypeError("setter_must_be_callable", [set]); |
+ } |
+ desc.setSet(set); |
+ } |
+ |
+ if (IsInconsistentDescriptor(desc)) { |
+ throw MakeTypeError("value_and_getter_setter", [obj]); |
+ } |
+ return desc; |
+} |
+ |
+ |
+function PropertyDescriptor() { |
+ // Initialize here so they are all in-object and have the same map. |
+ // Default values from ES5 8.6.1. |
+ this.value_ = void 0; |
+ this.valueSet_ = false; |
+ this.writable_ = false; |
+ this.writableSet_ = false; |
+ this.enumerable_ = false; |
+ this.configurable_ = false; |
+ this.get_ = void 0; |
+ this.getSet_ = false; |
Christian Plesner Hansen
2009/12/08 20:44:40
Calling a boolean xxxSet is not a particularly obv
|
+ this.set_ = void 0; |
+ this.setSet_ = false; |
+} |
+ |
+ |
+PropertyDescriptor.prototype.setValue = function(value) { |
+ this.value_ = value; |
+ this.valueSet_ = true; |
+} |
+ |
+ |
+PropertyDescriptor.prototype.getValue = function() { |
+ return this.value_; |
+} |
+ |
+ |
+PropertyDescriptor.prototype.setEnumerable = function(enumerable) { |
+ this.enumerable_ = enumerable; |
+} |
+ |
+ |
+PropertyDescriptor.prototype.isEnumerable = function () { |
+ return this.enumerable_; |
+} |
+ |
+ |
+PropertyDescriptor.prototype.setWritable = function(writable) { |
+ this.writable_ = writable; |
+ this.writableSet_ = true; |
+} |
+ |
+ |
+PropertyDescriptor.prototype.isWritable = function() { |
+ return this.writable_; |
+} |
+ |
+ |
+PropertyDescriptor.prototype.setConfigurable = function(configurable) { |
+ this.configurable_ = configurable; |
+} |
+ |
+ |
+PropertyDescriptor.prototype.isConfigurable = function() { |
+ return this.configurable_; |
+} |
+ |
+ |
+PropertyDescriptor.prototype.setGet = function(get) { |
+ this.get_ = get; |
+ this.getSet_ = true; |
+} |
+ |
+ |
+PropertyDescriptor.prototype.getGet = function() { |
+ return this.get_; |
+} |
+ |
+ |
+PropertyDescriptor.prototype.setSet = function(set) { |
+ this.set_ = set; |
+ this.setSet_ = true; |
+} |
+ |
+ |
+PropertyDescriptor.prototype.getSet = function() { |
+ return this.set_; |
+} |
+ |
+ |
+// ES5 8.12.9. This version cannot cope with the property p already |
+// being present on obj. |
+function DefineOwnProperty(obj, p, desc, should_throw) { |
+ var flag = desc.isEnumerable() ? 0 : DONT_ENUM; |
+ if (IsDataDescriptor(desc)) { |
+ flag |= desc.isWritable() ? 0 : (DONT_DELETE | READ_ONLY); |
+ %SetProperty(obj, p, desc.getValue(), flag); |
+ } else { |
+ if (IS_FUNCTION(desc.getGet())) %DefineAccessor(obj, p, GETTER, desc.getGet(), flag); |
+ if (IS_FUNCTION(desc.getSet())) %DefineAccessor(obj, p, SETTER, desc.getSet(), flag); |
+ } |
+ return true; |
+} |
+ |
+ |
+// ES5 section 15.2.3.5. |
+function ObjectCreate(proto, properties) { |
+ if (!IS_OBJECT(proto) && !IS_NULL(proto)) { |
+ throw MakeTypeError("proto_object_or_null", [proto]); |
+ } |
+ var obj = new $Object(); |
+ obj.__proto__ = proto; |
+ if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties); |
+ return obj; |
+} |
+ |
+ |
+// ES5 section 15.2.3.7. This version cannot cope with the properies already |
+// being present on obj. Therefore it is not exposed as |
+// Object.defineProperties yet. |
+function ObjectDefineProperties(obj, properties) { |
+ var props = ToObject(properties); |
+ var key_values = []; |
+ for (var key in props) { |
+ if (%HasLocalProperty(props, key)) { |
+ key_values.push(key); |
+ var value = props[key]; |
+ var desc = ToPropertyDescriptor(value); |
+ key_values.push(desc); |
+ } |
+ } |
+ for (var i = 0; i < key_values.length; i += 2) { |
+ var key = key_values[i]; |
+ var desc = key_values[i + 1]; |
+ DefineOwnProperty(obj, key, desc, true); |
+ } |
+} |
+ |
+ |
%SetCode($Object, function(x) { |
if (%_IsConstructCall()) { |
if (x == null) return this; |
@@ -309,7 +512,8 @@ |
"__lookupSetter__", ObjectLookupSetter |
)); |
InstallFunctions($Object, DONT_ENUM, $Array( |
- "keys", ObjectKeys |
+ "keys", ObjectKeys, |
+ "create", ObjectCreate |
)); |
} |