Author: Stephan <[email protected]> Branch: Changeset: r362:6bb16769d0c0 Date: 2013-02-27 20:06 +0100 http://bitbucket.org/pypy/lang-js/changeset/6bb16769d0c0/
Log: back array by dict access array with integer index diff --git a/js/jsobj.py b/js/jsobj.py --- a/js/jsobj.py +++ b/js/jsobj.py @@ -12,10 +12,39 @@ @jit.elidable def is_array_index(p): - try: - return unicode(str(uint32(abs(int(str(p)))))) == p - except ValueError: - return False + return make_array_index(p) != NOT_ARRAY_INDEX + + +NOT_ARRAY_INDEX = -1 + + +def _get_from_desc(desc, this): + from js.object_space import newundefined + if desc is None: + return newundefined() + + if is_data_descriptor(desc): + return desc.value + + if desc.has_set_getter() is False: + return newundefined() + + getter = desc.getter + res = getter.Call(this=this) + return res + + [email protected]_safe +def make_array_index(idx): + if len(idx) == 0: + return -1 + + IDX_LIT = '0123456789' + + for c in idx: + if c not in IDX_LIT: + return NOT_ARRAY_INDEX + return int(idx) @jit.elidable @@ -163,13 +192,18 @@ jit.promote(proto_desc) [email protected] def reject(throw, msg=u''): if throw: raise JsTypeError(msg) return False +def _ireject(throw, idx): + if throw: + raise JsTypeError(unicode(str(idx))) + return False + + class W_BasicObject(W_Root): _type_ = 'object' _class_ = 'Object' @@ -200,22 +234,14 @@ # 8.12.3 def get(self, p): - from js.object_space import newundefined assert p is not None and isinstance(p, unicode) desc = self.get_property(p) - if desc is None: - return newundefined() + return _get_from_desc(desc, self) - if is_data_descriptor(desc): - return desc.value - - if desc.has_set_getter() is False: - return newundefined() - - getter = desc.getter - res = getter.Call(this=self) - return res + def w_get(self, w_p): + name = w_p.to_string() + return self.get(name) # 8.12.1 def get_own_property(self, p): @@ -282,8 +308,8 @@ def put(self, p, v, throw=False): assert p is not None and isinstance(p, unicode) - if self.can_put(p) is False: - if throw is True: + if not self.can_put(p): + if throw: raise JsTypeError(u"can't put %s" % (p, )) else: return @@ -303,6 +329,10 @@ new_desc = DataPropertyDescriptor(v, True, True, True) self.define_own_property(p, new_desc, throw) + def w_put(self, w_p, v, throw=False): + name = w_p.to_string() + self.put(name, v, throw) + # 8.12.4 def can_put(self, p): from js.object_space import isundefined, isnull_or_undefined @@ -1252,12 +1282,307 @@ _class_ = 'Array' def __init__(self, length=w_0): + self._array_props_ = {} + #self._array_props_ = [] + W_BasicObject.__init__(self) assert isinstance(length, W_Root) desc = PropertyDescriptor(value=length, writable=True, enumerable=False, configurable=False) W_BasicObject.define_own_property(self, u'length', desc) + ####### dict + def _add_prop(self, name, value): + idx = make_array_index(name) + if idx != NOT_ARRAY_INDEX: + self._add_iprop(idx, value) + else: + W_BasicObject._add_prop(self, name, value) + + def _add_iprop(self, idx, value): + assert isinstance(idx, int) + self._array_props_[idx] = value + + def _get_prop(self, name): + idx = make_array_index(name) + if idx != NOT_ARRAY_INDEX: + return self._get_iprop(idx) + else: + return W_BasicObject._get_prop(self, name) + + def _get_iprop(self, idx): + assert isinstance(idx, int) + assert idx >= 0 + return self._array_props_.get(idx, None) + + def _set_prop(self, name, value): + idx = make_array_index(name) + if idx != NOT_ARRAY_INDEX: + self._set_iprop(idx, value) + else: + W_BasicObject._set_prop(self, name, value) + + def _set_iprop(self, idx, value): + assert isinstance(idx, int) + assert idx >= 0 + self._array_props_[idx] = value + + def _del_prop(self, name): + idx = make_array_index(name) + if idx != NOT_ARRAY_INDEX: + self._del_iprop(idx) + else: + W_BasicObject._del_prop(self, name) + + def _del_iprop(self, idx): + assert isinstance(idx, int) + assert idx >= 0 + try: + del self._array_props_[idx] + except KeyError: + pass + + def _named_properties_dict(self): + from js.object_space import isnull_or_undefined + my_d = {} + for i in self._array_props_.keys(): + my_d[unicode(str(i))] = None + + for i in self._property_map_.keys(): + my_d[i] = None + + proto = self.prototype() + if not isnull_or_undefined(proto): + assert isinstance(proto, W_BasicObject) + proto_d = proto._named_properties_dict() + else: + proto_d = {} + + my_d.update(proto_d) + + return my_d + + def _get_idx_property(self, idx): + from js.object_space import isnull + + prop = self._get_own_idx_property(idx) + if prop is not None: + return prop + + proto = self.prototype() + if isnull(proto): + return None + + if isinstance(proto, W__Array): + return proto._get_idx_property(idx) + + assert isinstance(proto, W_BasicObject) + p = unicode(str(idx)) + return proto.get_property(p) + + def w_get(self, w_p): + if isinstance(w_p, W_IntNumber): + idx = w_p.ToInteger() + if idx >= 0: + desc = self._get_idx_property(idx) + return _get_from_desc(desc, self) + + return W_BasicObject.w_get(self, w_p) + + def w_put(self, w_p, v, throw=False): + if isinstance(w_p, W_IntNumber): + idx = w_p.ToInteger() + if idx >= 0: + if not self._can_idx_put(idx): + if throw: + raise JsTypeError(u"can't put %s" % (str(idx), )) + else: + return + + own_desc = self._get_own_idx_property(idx) + if is_data_descriptor(own_desc) is True: + value_desc = PropertyDescriptor(value=v) + self._define_own_idx_property(idx, value_desc, throw) + return + + desc = self._get_idx_property(idx) + if is_accessor_descriptor(desc) is True: + setter = desc.setter + assert setter is not None + setter.Call(this=self, args=[v]) + + else: + new_desc = DataPropertyDescriptor(v, True, True, True) + self._define_own_idx_property(idx, new_desc, throw) + + else: + W_BasicObject.w_put(self, w_p, v, throw) + + def _can_idx_put(self, idx): + from js.object_space import isundefined, isnull_or_undefined + desc = self._get_own_idx_property(idx) + if desc is not None: + if is_accessor_descriptor(desc) is True: + if isundefined(desc.setter): + return False + else: + return True + return desc.writable + + proto = self.prototype() + + if isnull_or_undefined(proto): + return self.extensible() + + assert isinstance(proto, W_BasicObject) + + if isinstance(proto, W__Array): + inherited = proto._get_idx_property(idx) + else: + p = unicode(str(idx)) + inherited = proto.get_property(p) + + if inherited is None: + return self.extensible() + + if is_accessor_descriptor(inherited) is True: + if isundefined(inherited.setter): + return False + else: + return True + else: + if self.extensible() is False: + return False + else: + return inherited.writable + + def _define_own_idx_property(self, idx, desc, throw=False): + from js.object_space import _w + old_len_desc = self.get_own_property(u'length') + assert old_len_desc is not None + old_len = old_len_desc.value.ToUInt32() + + # a + index = idx + # b + if index >= old_len and old_len_desc.writable is False: + return _ireject(throw, idx) + + # c + succeeded = self._define_own_int_property(idx, desc, False) + # d + if succeeded is False: + return _ireject(throw, idx) + + # e + if index >= old_len: + old_len_desc.value = _w(index + 1) + res = W_BasicObject.define_own_property(self, u'length', old_len_desc, False) + assert res is True + # f + return True + + def _define_own_int_property(self, idx, desc, throw=False): + current = self._get_own_idx_property(idx) + extensible = self.extensible() + + # 3. + if current is None and extensible is False: + return _ireject(throw, idx) + + # 4. + if current is None and extensible is True: + # 4.a + if is_generic_descriptor(desc) or is_data_descriptor(desc): + new_prop = DataProperty( + desc.value, + desc.writable, + desc.enumerable, + desc.configurable + ) + self._add_iprop(idx, new_prop) + # 4.b + else: + assert is_accessor_descriptor(desc) is True + new_prop = AccessorProperty( + desc.getter, + desc.setter, + desc.enumerable, + desc.configurable + ) + self._add_iprop(idx, new_prop) + # 4.c + return True + + # 5. + if desc.is_empty(): + return True + + # 6. + if desc == current: + return True + + # 7. + if current.configurable is False: + if desc.configurable is True: + return _ireject(throw, idx) + if desc.has_set_enumerable() and (not(current.enumerable) == desc.enumerable): + return _ireject(throw, idx) + + # 8. + if is_generic_descriptor(desc): + pass + # 9. + elif is_data_descriptor(current) != is_data_descriptor(desc): + # 9.a + if current.configurable is False: + return _ireject(throw, idx) + # 9.b + if is_data_descriptor(current): + raise NotImplementedError(self.__class__) + # 9.c + else: + raise NotImplementedError(self.__class__) + # 10 + elif is_data_descriptor(current) and is_data_descriptor(desc): + # 10.a + if current.configurable is False: + # 10.a.i + if current.writable is False and desc.writable is True: + return _ireject(throw, idx) + # 10.a.ii + if current.writable is False: + if desc.has_set_value() and desc.value != current.value: + return _ireject(throw, idx) + # 10.b + else: + pass + # 11 + elif is_accessor_descriptor(current) and is_accessor_descriptor(desc): + # 11.a + if current.configurable is False: + # 11.a.i + if desc.has_set_setter() and desc.setter != current.setter: + return _ireject(throw, idx) + # 11.a.ii + if desc.has_set_getter() and desc.getter != current.getter: + return _ireject(throw, idx) + # 12 + prop = self._get_iprop(idx) + prop.update_with_descriptor(desc) + + # 13 + return True + + def _get_own_idx_property(self, idx): + assert isinstance(idx, int) + assert idx >= 0 + prop = self._get_iprop(idx) + if prop is None: + return + + return prop.to_property_descriptor() + # 15.4.5.1 def define_own_property(self, p, desc, throw=False): from js.object_space import _w @@ -1319,27 +1644,9 @@ # 4 elif is_array_index(p): - assert p is not None and isinstance(p, unicode) + index = uint32(int(p)) + return self._define_own_idx_property(index, desc, False) - # a - index = uint32(int(p)) - # b - if index >= old_len and old_len_desc.writable is False: - return reject(throw, p) - - # c - succeeded = W_BasicObject.define_own_property(self, p, desc, False) - # d - if succeeded is False: - return reject(throw, p) - - # e - if index >= old_len: - old_len_desc.value = _w(index + 1) - res = W_BasicObject.define_own_property(self, u'length', old_len_desc, False) - assert res is True - # f - return True # 5 return W_BasicObject.define_own_property(self, p, desc, throw) diff --git a/js/opcodes.py b/js/opcodes.py --- a/js/opcodes.py +++ b/js/opcodes.py @@ -255,8 +255,9 @@ def eval(self, ctx): w_obj = ctx.stack_pop().ToObject() - name = ctx.stack_pop().to_string() - value = w_obj.get(name) + w_name = ctx.stack_pop() + value = w_obj.w_get(w_name) + ctx.stack_append(value) def __str__(self): @@ -502,14 +503,12 @@ def eval(self, ctx): left = ctx.stack_pop() - member = ctx.stack_pop() - name = member.to_string() - #assert isinstance(name, unicode) + w_name = ctx.stack_pop() value = ctx.stack_pop() l_obj = left.ToObject() - l_obj.put(name, value) + l_obj.w_put(w_name, value) ctx.stack_append(value) diff --git a/test/test_array.py b/test/test_array.py --- a/test/test_array.py +++ b/test/test_array.py @@ -1,19 +1,34 @@ from test.test_interp import assertv, assertp + def test_array_push(capsys): assertv("var x = []; x.push(42); x.length;", 1) assertv("var x = []; x.push(42); x[0];", 42) assertv("var x = [1,2,3]; x.push(42); x[3];", 42) assertp("var x = []; x.push(4); x.push(3); x.push(2); x.push(1); print(x)", '4,3,2,1', capsys) + def test_array_pop(): assertv("var x = [4,3,2,1]; x.pop(); x.length;", 3) assertv("var x = [4,3,2,1]; x.pop();", 1) assertv("var x = [4,3,2,1]; x.pop(); x.pop(); x.pop(); x.pop();", 4) assertv("var x = [4,3,2,1]; x.pop(); x.pop(); x.pop(); x.pop(); x.length", 0) + def test_array_length(): assertv("var x = []; x.length;", 0) - assertv("var x = [1,2,3]; x.length;", 3); - assertv("var x = []; x[0] = 1; x[1] = 2; x[2] = 3; x.length;", 3); - assertv("var x = []; x[2] = 3; x.length;", 3); + assertv("var x = [1,2,3]; x.length;", 3) + assertv("var x = []; x[0] = 1; x[1] = 2; x[2] = 3; x.length;", 3) + assertv("var x = []; x[2] = 3; x.length;", 3) + + +def test_make_array_index(): + from js.jsobj import make_array_index, NOT_ARRAY_INDEX + assert make_array_index('12345') == 12345 + assert make_array_index(u'12345') == 12345 + assert make_array_index('12a45') == NOT_ARRAY_INDEX + assert make_array_index('012345') == 12345 + assert make_array_index('') == NOT_ARRAY_INDEX + assert make_array_index(' ') == NOT_ARRAY_INDEX + assert make_array_index('x') == NOT_ARRAY_INDEX + assert make_array_index('abc123') == NOT_ARRAY_INDEX diff --git a/test/test_w_array.py b/test/test_w_array.py new file mode 100644 --- /dev/null +++ b/test/test_w_array.py @@ -0,0 +1,41 @@ +from js.jsobj import W__Array +from js.property import DataProperty +from js.object_space import _w + + +def test_array_get(): + a = W__Array() + a._set_prop(u'23', DataProperty(42, True, True, True)) + assert a.get(u'23') == 42 + + +def test_array_iprop(): + d = DataProperty(42, True, True, True) + a = W__Array() + a._set_iprop(23, d) + assert a._get_iprop(23) is d + assert a._get_prop(u'23') is d + assert a.get(u'23') == 42 + + +def test_array_w_get(): + d = DataProperty(42, True, True, True) + a = W__Array() + a._set_iprop(23, d) + assert a.w_get(_w(23)) == 42 + assert a.w_get(_w(u'23')) == 42 + + +def test_array_put(): + a = W__Array() + a.put(u'23', 42) + assert a.get(u'23') == 42 + assert a.w_get(_w(u'23')) == 42 + + +def test_array_w_put(): + a = W__Array() + a.w_put(_w(23), 42) + assert a.get(u'23') == 42 + assert a.w_get(_w(23)) == 42 + assert a.w_get(_w(u'23')) == 42 _______________________________________________ pypy-commit mailing list [email protected] http://mail.python.org/mailman/listinfo/pypy-commit
