1# this is based on jsarray.py 2 3import six 4try: 5 import numpy 6except: 7 pass 8 9if six.PY3: 10 xrange = range 11 import functools 12 13 14def to_arr(this): 15 """Returns Python array from Js array""" 16 return [this.get(str(e)) for e in xrange(len(this))] 17 18 19ARR_STACK = set({}) 20 21 22class TypedArrayPrototype: 23 def toString(): 24 # this function is wrong 25 func = this.get('join') 26 if not func.is_callable(): 27 28 @this.Js 29 def func(): 30 return '[object %s]' % this.Class 31 32 return func.call(this, ()) 33 34 def toLocaleString(locales=None, options=None): 35 array = this.to_object() 36 arr_len = array.get("length").to_uint32() 37 # separator is simply a comma ',' 38 if not arr_len: 39 return '' 40 res = [] 41 for i in xrange(arr_len): 42 element = array[str(i)] 43 if element.is_undefined() or element.is_null(): 44 res.append('') 45 else: 46 cand = element.to_object() 47 str_func = element.get('toLocaleString') 48 if not str_func.is_callable(): 49 raise this.MakeError( 50 'TypeError', 51 'toLocaleString method of item at index %d is not callable' 52 % i) 53 res.append(element.callprop('toLocaleString').value) 54 return ','.join(res) 55 56 def join(separator): 57 ARR_STACK.add(this) 58 array = this.to_object() 59 arr_len = array.get("length").to_uint32() 60 separator = ',' if separator.is_undefined() else separator.to_string( 61 ).value 62 elems = [] 63 for e in xrange(arr_len): 64 elem = array.get(str(e)) 65 if elem in ARR_STACK: 66 s = '' 67 else: 68 s = elem.to_string().value 69 elems.append( 70 s if not (elem.is_undefined() or elem.is_null()) else '') 71 res = separator.join(elems) 72 ARR_STACK.remove(this) 73 return res 74 75 def reverse(): 76 array = this.to_object() # my own algorithm 77 vals = to_arr(array) 78 has_props = [array.has_property(str(e)) for e in xrange(len(array))] 79 vals.reverse() 80 has_props.reverse() 81 for i, val in enumerate(vals): 82 if has_props[i]: 83 array.put(str(i), val) 84 else: 85 array.delete(str(i)) 86 return array 87 88 def slice(start, end): # todo check 89 array = this.to_object() 90 arr_len = array.get("length").to_uint32() 91 relative_start = start.to_int() 92 k = max((arr_len + relative_start), 0) if relative_start < 0 else min( 93 relative_start, arr_len) 94 relative_end = arr_len if end.is_undefined() else end.to_int() 95 final = max((arr_len + relative_end), 0) if relative_end < 0 else min( 96 relative_end, arr_len) 97 res = [] 98 n = 0 99 while k < final: 100 pk = str(k) 101 if array.has_property(pk): 102 res.append(array.get(pk)) 103 k += 1 104 n += 1 105 return res 106 107 def sort(cmpfn): 108 if not this.Class in ('Array', 'Arguments'): 109 return this.to_object() # do nothing 110 arr = [] 111 for i in xrange(len(this)): 112 arr.append(this.get(six.text_type(i))) 113 114 if not arr: 115 return this 116 if not cmpfn.is_callable(): 117 cmpfn = None 118 cmp = lambda a, b: sort_compare(a, b, cmpfn) 119 if six.PY3: 120 key = functools.cmp_to_key(cmp) 121 arr.sort(key=key) 122 else: 123 arr.sort(cmp=cmp) 124 for i in xrange(len(arr)): 125 this.put(six.text_type(i), arr[i]) 126 127 return this 128 129 def indexOf(searchElement): 130 array = this.to_object() 131 arr_len = array.get("length").to_uint32() 132 if arr_len == 0: 133 return -1 134 if len(arguments) > 1: 135 n = arguments[1].to_int() 136 else: 137 n = 0 138 if n >= arr_len: 139 return -1 140 if n >= 0: 141 k = n 142 else: 143 k = arr_len - abs(n) 144 if k < 0: 145 k = 0 146 while k < arr_len: 147 if array.has_property(str(k)): 148 elementK = array.get(str(k)) 149 if searchElement.strict_equality_comparison(elementK): 150 return k 151 k += 1 152 return -1 153 154 def lastIndexOf(searchElement): 155 array = this.to_object() 156 arr_len = array.get("length").to_uint32() 157 if arr_len == 0: 158 return -1 159 if len(arguments) > 1: 160 n = arguments[1].to_int() 161 else: 162 n = arr_len - 1 163 if n >= 0: 164 k = min(n, arr_len - 1) 165 else: 166 k = arr_len - abs(n) 167 while k >= 0: 168 if array.has_property(str(k)): 169 elementK = array.get(str(k)) 170 if searchElement.strict_equality_comparison(elementK): 171 return k 172 k -= 1 173 return -1 174 175 def every(callbackfn): 176 array = this.to_object() 177 arr_len = array.get("length").to_uint32() 178 if not callbackfn.is_callable(): 179 raise this.MakeError('TypeError', 'callbackfn must be a function') 180 T = arguments[1] 181 k = 0 182 while k < arr_len: 183 if array.has_property(str(k)): 184 kValue = array.get(str(k)) 185 if not callbackfn.call( 186 T, (kValue, this.Js(k), array)).to_boolean().value: 187 return False 188 k += 1 189 return True 190 191 def some(callbackfn): 192 array = this.to_object() 193 arr_len = array.get("length").to_uint32() 194 if not callbackfn.is_callable(): 195 raise this.MakeError('TypeError', 'callbackfn must be a function') 196 T = arguments[1] 197 k = 0 198 while k < arr_len: 199 if array.has_property(str(k)): 200 kValue = array.get(str(k)) 201 if callbackfn.call( 202 T, (kValue, this.Js(k), array)).to_boolean().value: 203 return True 204 k += 1 205 return False 206 207 def forEach(callbackfn): 208 array = this.to_object() 209 arr_len = array.get("length").to_uint32() 210 if not callbackfn.is_callable(): 211 raise this.MakeError('TypeError', 'callbackfn must be a function') 212 T = arguments[1] 213 k = 0 214 while k < arr_len: 215 if array.has_property(str(k)): 216 kValue = array.get(str(k)) 217 callbackfn.call(T, (kValue, this.Js(k), array)) 218 k += 1 219 220 def map(callbackfn): 221 array = this.to_object() 222 arr_len = array.get("length").to_uint32() 223 if not callbackfn.is_callable(): 224 raise this.MakeError('TypeError', 'callbackfn must be a function') 225 T = arguments[1] 226 A = this.Js([]) 227 k = 0 228 while k < arr_len: 229 Pk = str(k) 230 if array.has_property(Pk): 231 kValue = array.get(Pk) 232 mappedValue = callbackfn.call(T, (kValue, this.Js(k), array)) 233 A.define_own_property( 234 Pk, { 235 'value': mappedValue, 236 'writable': True, 237 'enumerable': True, 238 'configurable': True 239 }) 240 k += 1 241 return A 242 243 def filter(callbackfn): 244 array = this.to_object() 245 arr_len = array.get("length").to_uint32() 246 if not callbackfn.is_callable(): 247 raise this.MakeError('TypeError', 'callbackfn must be a function') 248 T = arguments[1] 249 res = [] 250 k = 0 251 while k < arr_len: 252 if array.has_property(str(k)): 253 kValue = array.get(str(k)) 254 if callbackfn.call( 255 T, (kValue, this.Js(k), array)).to_boolean().value: 256 res.append(kValue) 257 k += 1 258 return res # converted to js array automatically 259 260 def reduce(callbackfn): 261 array = this.to_object() 262 arr_len = array.get("length").to_uint32() 263 if not callbackfn.is_callable(): 264 raise this.MakeError('TypeError', 'callbackfn must be a function') 265 if not arr_len and len(arguments) < 2: 266 raise this.MakeError( 267 'TypeError', 'Reduce of empty array with no initial value') 268 k = 0 269 if len(arguments) > 1: # initial value present 270 accumulator = arguments[1] 271 else: 272 kPresent = False 273 while not kPresent and k < arr_len: 274 kPresent = array.has_property(str(k)) 275 if kPresent: 276 accumulator = array.get(str(k)) 277 k += 1 278 if not kPresent: 279 raise this.MakeError( 280 'TypeError', 'Reduce of empty array with no initial value') 281 while k < arr_len: 282 if array.has_property(str(k)): 283 kValue = array.get(str(k)) 284 accumulator = callbackfn.call( 285 this.undefined, (accumulator, kValue, this.Js(k), array)) 286 k += 1 287 return accumulator 288 289 def reduceRight(callbackfn): 290 array = this.to_object() 291 arr_len = array.get("length").to_uint32() 292 if not callbackfn.is_callable(): 293 raise this.MakeError('TypeError', 'callbackfn must be a function') 294 if not arr_len and len(arguments) < 2: 295 raise this.MakeError( 296 'TypeError', 'Reduce of empty array with no initial value') 297 k = arr_len - 1 298 if len(arguments) > 1: # initial value present 299 accumulator = arguments[1] 300 else: 301 kPresent = False 302 while not kPresent and k >= 0: 303 kPresent = array.has_property(str(k)) 304 if kPresent: 305 accumulator = array.get(str(k)) 306 k -= 1 307 if not kPresent: 308 raise this.MakeError( 309 'TypeError', 'Reduce of empty array with no initial value') 310 while k >= 0: 311 if array.has_property(str(k)): 312 kValue = array.get(str(k)) 313 accumulator = callbackfn.call( 314 this.undefined, (accumulator, kValue, this.Js(k), array)) 315 k -= 1 316 return accumulator 317 318 319def sort_compare(a, b, comp): 320 if a is None: 321 if b is None: 322 return 0 323 return 1 324 if b is None: 325 if a is None: 326 return 0 327 return -1 328 if a.is_undefined(): 329 if b.is_undefined(): 330 return 0 331 return 1 332 if b.is_undefined(): 333 if a.is_undefined(): 334 return 0 335 return -1 336 if comp is not None: 337 res = comp.call(a.undefined, (a, b)) 338 return res.to_int() 339 x, y = a.to_string(), b.to_string() 340 if x < y: 341 return -1 342 elif x > y: 343 return 1 344 return 0 345