Implement ES5 seal, isSealed, freeze and isFrozen

git-svn-id: svn://10.0.0.236/trunk@257548 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
nboyd%atg.com 2009-06-22 01:08:22 +00:00
parent 1bc3ca8133
commit 812bc9fd45
6 changed files with 196 additions and 7 deletions

View File

@ -93,6 +93,14 @@ public class NativeObject extends IdScriptableObject
"defineProperties", 2);
addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_create,
"create", 2);
addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_isSealed,
"isSealed", 1);
addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_isFrozen,
"isFrozen", 1);
addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_seal,
"seal", 1);
addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_freeze,
"freeze", 1);
super.fillConstructorProperties(ctor);
}
@ -364,10 +372,73 @@ public class NativeObject extends IdScriptableObject
if (args.length > 1 && args[1] != Undefined.instance) {
Scriptable props = Context.toObject(args[1], getParentScope());
newObject.defineOwnProperties(cx, ensureScriptableObject(props));
}
}
return newObject;
}
}
case ConstructorId_isSealed:
{
Object arg = args.length < 1 ? Undefined.instance : args[0];
ScriptableObject obj = ensureScriptableObject(arg);
for (Object name: obj.getAllIds()) {
Object configurable = obj.getOwnPropertyDescriptor(cx, name).get("configurable");
if (Boolean.TRUE.equals(configurable))
return false;
}
return !obj.isExtensible();
}
case ConstructorId_isFrozen:
{
Object arg = args.length < 1 ? Undefined.instance : args[0];
ScriptableObject obj = ensureScriptableObject(arg);
for (Object name: obj.getAllIds()) {
ScriptableObject desc = obj.getOwnPropertyDescriptor(cx, name);
if (Boolean.TRUE.equals(desc.get("configurable")))
return false;
if (isDataDescriptor(desc) && Boolean.TRUE.equals(desc.get("writable")))
return false;
}
return !obj.isExtensible();
}
case ConstructorId_seal:
{
Object arg = args.length < 1 ? Undefined.instance : args[0];
ScriptableObject obj = ensureScriptableObject(arg);
for (Object name: obj.getAllIds()) {
ScriptableObject desc = obj.getOwnPropertyDescriptor(cx, name);
if (Boolean.TRUE.equals(desc.get("configurable"))) {
desc.put("configurable", desc, false);
obj.defineOwnProperty(cx, name, desc);
}
}
obj.preventExtensions();
return obj;
}
case ConstructorId_freeze:
{
Object arg = args.length < 1 ? Undefined.instance : args[0];
ScriptableObject obj = ensureScriptableObject(arg);
for (Object name: obj.getAllIds()) {
ScriptableObject desc = obj.getOwnPropertyDescriptor(cx, name);
if (isDataDescriptor(desc) && Boolean.TRUE.equals(desc.get("writable")))
desc.put("writable", desc, false);
if (Boolean.TRUE.equals(desc.get("configurable")))
desc.put("configurable", desc, false);
obj.defineOwnProperty(cx, name, desc);
}
obj.preventExtensions();
return obj;
}
default:
throw new IllegalArgumentException(String.valueOf(id));
@ -425,6 +496,10 @@ public class NativeObject extends IdScriptableObject
ConstructorId_preventExtensions = -7,
ConstructorId_defineProperties= -8,
ConstructorId_create = -9,
ConstructorId_isSealed = -10,
ConstructorId_isFrozen = -11,
ConstructorId_seal = -12,
ConstructorId_freeze = -13,
Id_constructor = 1,
Id_toString = 2,

View File

@ -1653,15 +1653,15 @@ public abstract class ScriptableObject implements Scriptable, Serializable,
return attributes;
}
private boolean isDataDescriptor(ScriptableObject desc) {
protected boolean isDataDescriptor(ScriptableObject desc) {
return hasProperty(desc, "value") || hasProperty(desc, "writable");
}
private boolean isAccessorDescriptor(ScriptableObject desc) {
protected boolean isAccessorDescriptor(ScriptableObject desc) {
return hasProperty(desc, "get") || hasProperty(desc, "set");
}
private boolean isGenericDescriptor(ScriptableObject desc) {
protected boolean isGenericDescriptor(ScriptableObject desc) {
return !isDataDescriptor(desc) && !isAccessorDescriptor(desc);
}

View File

@ -0,0 +1,27 @@
js> load('testsrc/doctests/util.js');
js> Object.freeze;
function freeze() { [native code for Object.freeze, arity=1] }
js> [undefined, null, true, 1, 'hello'].forEach(function(value) {
> expectTypeError(function() { Object.freeze(value) })
> })
js> expectTypeError(function() { Object.freeze() })
js> var x = {}
js> var y = Object.freeze(x)
js> x === y
true
js> var obj = Object.defineProperty({}, 'a', {configurable:true, writable:true})
js> var _ = Object.freeze(obj)
js> var a = Object.getOwnPropertyDescriptor(obj, 'a');
js> a.configurable
false
js> a.writable
false
js> Object.isExtensible(obj)
false
js> Object.isFrozen(obj)
true

View File

@ -0,0 +1,37 @@
js> load('testsrc/doctests/util.js');
js> Object.isFrozen
function isFrozen() { [native code for Object.isFrozen, arity=1] }
js> expectTypeError(function() { Object.isFrozen() });
js> [undefined, null, true, 1, 'hello'].forEach(function(value) {
> expectTypeError(function() { Object.isFrozen(value) })
> })
js> Object.isFrozen({})
false
js> var obj = Object.preventExtensions({});
js> Object.isFrozen(obj);
true
js> var obj = Object.defineProperty({}, 'a', {configurable:true, writable:false})
js> var _ = Object.preventExtensions(obj);
js> Object.isFrozen(obj);
false
js> var obj = Object.defineProperty({}, 'a', {configurable:false, writable:true})
js> var _ = Object.preventExtensions(obj);
js> Object.isFrozen(obj);
false
js> var obj = Object.defineProperty({}, 'a', {configurable:false, writable:false})
js> var _ = Object.preventExtensions(obj);
js> Object.isFrozen(obj);
true
js> var obj = Object.defineProperty({}, 'a', {configurable:false, set: function(){} })
js> var _ = Object.preventExtensions(obj);
js> Object.isFrozen(obj);
true

View File

@ -0,0 +1,26 @@
js> load('testsrc/doctests/util.js');
js> Object.isSealed
function isSealed() { [native code for Object.isSealed, arity=1] }
js> expectTypeError(function() { Object.isSealed() });
js> [undefined, null, true, 1, 'hello'].forEach(function(value) {
> expectTypeError(function() { Object.isSealed(value) })
> })
js> Object.isSealed({})
false
js> var obj = Object.preventExtensions({});
js> Object.isSealed(obj);
true
js> var obj = Object.defineProperty({}, 'a', {configurable:false});
js> var _ = Object.preventExtensions(obj);
js> Object.isSealed(obj);
true
js> var obj = Object.defineProperty({}, 'a', {configurable:true});
js> var _ = Object.preventExtensions(obj);
js> Object.isSealed(obj);
false

View File

@ -0,0 +1,24 @@
js> load('testsrc/doctests/util.js');
js> Object.seal;
function seal() { [native code for Object.seal, arity=1] }
js> [undefined, null, true, 1, 'hello'].forEach(function(value) {
> expectTypeError(function() { Object.seal(value) })
> })
js> expectTypeError(function() { Object.seal() })
js> var x = {}
js> var y = Object.seal(x)
js> x === y
true
js> var obj = Object.defineProperty({}, 'a', {configurable:true})
js> var _ = Object.seal(obj)
js> Object.getOwnPropertyDescriptor(obj, 'a').configurable
false
js> Object.isExtensible(obj)
false
js> Object.isSealed(obj)
true