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

Reply via email to