Revert "Test - CF per XBOX"

This reverts commit ef822e749d.
This commit is contained in:
Alhaziel
2019-12-03 18:47:48 +01:00
parent ef822e749d
commit 917f1a2c4b
208 changed files with 78 additions and 115980 deletions
+1
View File
@@ -0,0 +1 @@
__author__ = 'Piotr Dabkowski'
+476
View File
@@ -0,0 +1,476 @@
import six
if six.PY3:
xrange = range
import functools
def to_arr(this):
"""Returns Python array from Js array"""
return [this.get(str(e)) for e in xrange(len(this))]
ARR_STACK = set({})
class ArrayPrototype:
def toString():
# this function is wrong but I will leave it here fore debugging purposes.
func = this.get('join')
if not func.is_callable():
@this.Js
def func():
return '[object %s]' % this.Class
return func.call(this, ())
def toLocaleString():
array = this.to_object()
arr_len = array.get('length').to_uint32()
# separator is simply a comma ','
if not arr_len:
return ''
res = []
for i in xrange(arr_len):
element = array[str(i)]
if element.is_undefined() or element.is_null():
res.append('')
else:
cand = element.to_object()
str_func = element.get('toLocaleString')
if not str_func.is_callable():
raise this.MakeError(
'TypeError',
'toLocaleString method of item at index %d is not callable'
% i)
res.append(element.callprop('toLocaleString').value)
return ','.join(res)
def concat():
array = this.to_object()
A = this.Js([])
items = [array]
items.extend(to_arr(arguments))
n = 0
for E in items:
if E.Class == 'Array':
k = 0
e_len = len(E)
while k < e_len:
if E.has_property(str(k)):
A.put(str(n), E.get(str(k)))
n += 1
k += 1
else:
A.put(str(n), E)
n += 1
return A
def join(separator):
ARR_STACK.add(this)
array = this.to_object()
arr_len = array.get('length').to_uint32()
separator = ',' if separator.is_undefined() else separator.to_string(
).value
elems = []
for e in xrange(arr_len):
elem = array.get(str(e))
if elem in ARR_STACK:
s = ''
else:
s = elem.to_string().value
elems.append(
s if not (elem.is_undefined() or elem.is_null()) else '')
res = separator.join(elems)
ARR_STACK.remove(this)
return res
def pop(): #todo check
array = this.to_object()
arr_len = array.get('length').to_uint32()
if not arr_len:
array.put('length', this.Js(arr_len))
return None
ind = str(arr_len - 1)
element = array.get(ind)
array.delete(ind)
array.put('length', this.Js(arr_len - 1))
return element
def push(item): # todo check
array = this.to_object()
arr_len = array.get('length').to_uint32()
to_put = arguments.to_list()
i = arr_len
for i, e in enumerate(to_put, arr_len):
array.put(str(i), e)
if to_put:
i += 1
array.put('length', this.Js(i))
return i
def reverse():
array = this.to_object() # my own algorithm
vals = to_arr(array)
has_props = [array.has_property(str(e)) for e in xrange(len(array))]
vals.reverse()
has_props.reverse()
for i, val in enumerate(vals):
if has_props[i]:
array.put(str(i), val)
else:
array.delete(str(i))
return array
def shift(): #todo check
array = this.to_object()
arr_len = array.get('length').to_uint32()
if not arr_len:
array.put('length', this.Js(0))
return None
first = array.get('0')
for k in xrange(1, arr_len):
from_s, to_s = str(k), str(k - 1)
if array.has_property(from_s):
array.put(to_s, array.get(from_s))
else:
array.delete(to)
array.delete(str(arr_len - 1))
array.put('length', this.Js(str(arr_len - 1)))
return first
def slice(start, end): # todo check
array = this.to_object()
arr_len = array.get('length').to_uint32()
relative_start = start.to_int()
k = max((arr_len + relative_start), 0) if relative_start < 0 else min(
relative_start, arr_len)
relative_end = arr_len if end.is_undefined() else end.to_int()
final = max((arr_len + relative_end), 0) if relative_end < 0 else min(
relative_end, arr_len)
res = []
n = 0
while k < final:
pk = str(k)
if array.has_property(pk):
res.append(array.get(pk))
k += 1
n += 1
return res
def sort(cmpfn):
if not this.Class in ('Array', 'Arguments'):
return this.to_object() # do nothing
arr = []
for i in xrange(len(this)):
arr.append(this.get(six.text_type(i)))
if not arr:
return this
if not cmpfn.is_callable():
cmpfn = None
cmp = lambda a, b: sort_compare(a, b, cmpfn)
if six.PY3:
key = functools.cmp_to_key(cmp)
arr.sort(key=key)
else:
arr.sort(cmp=cmp)
for i in xrange(len(arr)):
this.put(six.text_type(i), arr[i])
return this
def splice(start, deleteCount):
# 1-8
array = this.to_object()
arr_len = array.get('length').to_uint32()
relative_start = start.to_int()
actual_start = max(
(arr_len + relative_start), 0) if relative_start < 0 else min(
relative_start, arr_len)
actual_delete_count = min(
max(deleteCount.to_int(), 0), arr_len - actual_start)
k = 0
A = this.Js([])
# 9
while k < actual_delete_count:
if array.has_property(str(actual_start + k)):
A.put(str(k), array.get(str(actual_start + k)))
k += 1
# 10-11
items = to_arr(arguments)[2:]
items_len = len(items)
# 12
if items_len < actual_delete_count:
k = actual_start
while k < (arr_len - actual_delete_count):
fr = str(k + actual_delete_count)
to = str(k + items_len)
if array.has_property(fr):
array.put(to, array.get(fr))
else:
array.delete(to)
k += 1
k = arr_len
while k > (arr_len - actual_delete_count + items_len):
array.delete(str(k - 1))
k -= 1
# 13
elif items_len > actual_delete_count:
k = arr_len - actual_delete_count
while k > actual_start:
fr = str(k + actual_delete_count - 1)
to = str(k + items_len - 1)
if array.has_property(fr):
array.put(to, array.get(fr))
else:
array.delete(to)
k -= 1
# 14-17
k = actual_start
while items:
E = items.pop(0)
array.put(str(k), E)
k += 1
array.put('length', this.Js(arr_len - actual_delete_count + items_len))
return A
def unshift():
array = this.to_object()
arr_len = array.get('length').to_uint32()
argCount = len(arguments)
k = arr_len
while k > 0:
fr = str(k - 1)
to = str(k + argCount - 1)
if array.has_property(fr):
array.put(to, array.get(fr))
else:
array.delete(to)
k -= 1
j = 0
items = to_arr(arguments)
while items:
E = items.pop(0)
array.put(str(j), E)
j += 1
array.put('length', this.Js(arr_len + argCount))
return arr_len + argCount
def indexOf(searchElement):
array = this.to_object()
arr_len = array.get('length').to_uint32()
if arr_len == 0:
return -1
if len(arguments) > 1:
n = arguments[1].to_int()
else:
n = 0
if n >= arr_len:
return -1
if n >= 0:
k = n
else:
k = arr_len - abs(n)
if k < 0:
k = 0
while k < arr_len:
if array.has_property(str(k)):
elementK = array.get(str(k))
if searchElement.strict_equality_comparison(elementK):
return k
k += 1
return -1
def lastIndexOf(searchElement):
array = this.to_object()
arr_len = array.get('length').to_uint32()
if arr_len == 0:
return -1
if len(arguments) > 1:
n = arguments[1].to_int()
else:
n = arr_len - 1
if n >= 0:
k = min(n, arr_len - 1)
else:
k = arr_len - abs(n)
while k >= 0:
if array.has_property(str(k)):
elementK = array.get(str(k))
if searchElement.strict_equality_comparison(elementK):
return k
k -= 1
return -1
def every(callbackfn):
array = this.to_object()
arr_len = array.get('length').to_uint32()
if not callbackfn.is_callable():
raise this.MakeError('TypeError', 'callbackfn must be a function')
T = arguments[1]
k = 0
while k < arr_len:
if array.has_property(str(k)):
kValue = array.get(str(k))
if not callbackfn.call(
T, (kValue, this.Js(k), array)).to_boolean().value:
return False
k += 1
return True
def some(callbackfn):
array = this.to_object()
arr_len = array.get('length').to_uint32()
if not callbackfn.is_callable():
raise this.MakeError('TypeError', 'callbackfn must be a function')
T = arguments[1]
k = 0
while k < arr_len:
if array.has_property(str(k)):
kValue = array.get(str(k))
if callbackfn.call(
T, (kValue, this.Js(k), array)).to_boolean().value:
return True
k += 1
return False
def forEach(callbackfn):
array = this.to_object()
arr_len = array.get('length').to_uint32()
if not callbackfn.is_callable():
raise this.MakeError('TypeError', 'callbackfn must be a function')
T = arguments[1]
k = 0
while k < arr_len:
if array.has_property(str(k)):
kValue = array.get(str(k))
callbackfn.call(T, (kValue, this.Js(k), array))
k += 1
def map(callbackfn):
array = this.to_object()
arr_len = array.get('length').to_uint32()
if not callbackfn.is_callable():
raise this.MakeError('TypeError', 'callbackfn must be a function')
T = arguments[1]
A = this.Js([])
k = 0
while k < arr_len:
Pk = str(k)
if array.has_property(Pk):
kValue = array.get(Pk)
mappedValue = callbackfn.call(T, (kValue, this.Js(k), array))
A.define_own_property(
Pk, {
'value': mappedValue,
'writable': True,
'enumerable': True,
'configurable': True
})
k += 1
return A
def filter(callbackfn):
array = this.to_object()
arr_len = array.get('length').to_uint32()
if not callbackfn.is_callable():
raise this.MakeError('TypeError', 'callbackfn must be a function')
T = arguments[1]
res = []
k = 0
while k < arr_len:
if array.has_property(str(k)):
kValue = array.get(str(k))
if callbackfn.call(
T, (kValue, this.Js(k), array)).to_boolean().value:
res.append(kValue)
k += 1
return res # converted to js array automatically
def reduce(callbackfn):
array = this.to_object()
arr_len = array.get('length').to_uint32()
if not callbackfn.is_callable():
raise this.MakeError('TypeError', 'callbackfn must be a function')
if not arr_len and len(arguments) < 2:
raise this.MakeError(
'TypeError', 'Reduce of empty array with no initial value')
k = 0
if len(arguments) > 1: # initial value present
accumulator = arguments[1]
else:
kPresent = False
while not kPresent and k < arr_len:
kPresent = array.has_property(str(k))
if kPresent:
accumulator = array.get(str(k))
k += 1
if not kPresent:
raise this.MakeError(
'TypeError', 'Reduce of empty array with no initial value')
while k < arr_len:
if array.has_property(str(k)):
kValue = array.get(str(k))
accumulator = callbackfn.call(
this.undefined, (accumulator, kValue, this.Js(k), array))
k += 1
return accumulator
def reduceRight(callbackfn):
array = this.to_object()
arr_len = array.get('length').to_uint32()
if not callbackfn.is_callable():
raise this.MakeError('TypeError', 'callbackfn must be a function')
if not arr_len and len(arguments) < 2:
raise this.MakeError(
'TypeError', 'Reduce of empty array with no initial value')
k = arr_len - 1
if len(arguments) > 1: # initial value present
accumulator = arguments[1]
else:
kPresent = False
while not kPresent and k >= 0:
kPresent = array.has_property(str(k))
if kPresent:
accumulator = array.get(str(k))
k -= 1
if not kPresent:
raise this.MakeError(
'TypeError', 'Reduce of empty array with no initial value')
while k >= 0:
if array.has_property(str(k)):
kValue = array.get(str(k))
accumulator = callbackfn.call(
this.undefined, (accumulator, kValue, this.Js(k), array))
k -= 1
return accumulator
def sort_compare(a, b, comp):
if a is None:
if b is None:
return 0
return 1
if b is None:
if a is None:
return 0
return -1
if a.is_undefined():
if b.is_undefined():
return 0
return 1
if b.is_undefined():
if a.is_undefined():
return 0
return -1
if comp is not None:
res = comp.call(a.undefined, (a, b))
return res.to_int()
x, y = a.to_string(), b.to_string()
if x < y:
return -1
elif x > y:
return 1
return 0
+19
View File
@@ -0,0 +1,19 @@
# this is based on jsarray.py
import six
if six.PY3:
xrange = range
import functools
def to_arr(this):
"""Returns Python array from Js array"""
return [this.get(str(e)) for e in xrange(len(this))]
ARR_STACK = set({})
class ArrayBufferPrototype:
pass
+10
View File
@@ -0,0 +1,10 @@
class BooleanPrototype:
def toString():
if this.Class != 'Boolean':
raise this.Js(TypeError)('this must be a boolean')
return 'true' if this.value else 'false'
def valueOf():
if this.Class != 'Boolean':
raise this.Js(TypeError)('this must be a boolean')
return this.value
+10
View File
@@ -0,0 +1,10 @@
class ErrorPrototype:
def toString():
if this.TYPE != 'Object':
raise this.MakeError(
'TypeError', 'Error.prototype.toString called on non-object')
name = this.get('name')
name = 'Error' if name.is_undefined() else name.to_string().value
msg = this.get('message')
msg = '' if msg.is_undefined() else msg.to_string().value
return name + (name and msg and ': ') + msg
+52
View File
@@ -0,0 +1,52 @@
# python 3 support
import six
if six.PY3:
basestring = str
long = int
xrange = range
unicode = str
# todo fix apply and bind
class FunctionPrototype:
def toString():
if not this.is_callable():
raise TypeError('toString is not generic!')
args = ', '.join(this.code.__code__.co_varnames[:this.argcount])
return 'function %s(%s) ' % (this.func_name, args) + this.source
def call():
arguments_ = arguments
if not len(arguments):
obj = this.Js(None)
else:
obj = arguments[0]
if len(arguments) <= 1:
args = ()
else:
args = tuple([arguments_[e] for e in xrange(1, len(arguments_))])
return this.call(obj, args)
def apply():
if not len(arguments):
obj = this.Js(None)
else:
obj = arguments[0]
if len(arguments) <= 1:
args = ()
else:
appl = arguments[1]
args = tuple([appl[e] for e in xrange(len(appl))])
return this.call(obj, args)
def bind(thisArg):
target = this
if not target.is_callable():
raise this.MakeError(
'Object must be callable in order to be used with bind method')
if len(arguments) <= 1:
args = ()
else:
args = tuple([arguments[e] for e in xrange(1, len(arguments))])
return this.PyJsBoundFunction(target, thisArg, args)
+219
View File
@@ -0,0 +1,219 @@
import json
from ..base import Js
indent = ''
# python 3 support
import six
if six.PY3:
basestring = str
long = int
xrange = range
unicode = str
def parse(text):
reviver = arguments[1]
s = text.to_string().value
try:
unfiltered = json.loads(s)
except:
raise this.MakeError('SyntaxError',
'Could not parse JSON string - Invalid syntax')
unfiltered = to_js(this, unfiltered)
if reviver.is_callable():
root = this.Js({'': unfiltered})
return walk(root, '', reviver)
else:
return unfiltered
def stringify(value, replacer, space):
global indent
stack = set([])
indent = ''
property_list = replacer_function = this.undefined
if replacer.is_object():
if replacer.is_callable():
replacer_function = replacer
elif replacer.Class == 'Array':
property_list = []
for e in replacer:
v = replacer[e]
item = this.undefined
if v._type() == 'Number':
item = v.to_string()
elif v._type() == 'String':
item = v
elif v.is_object():
if v.Class in ('String', 'Number'):
item = v.to_string()
if not item.is_undefined() and item.value not in property_list:
property_list.append(item.value)
if space.is_object():
if space.Class == 'Number':
space = space.to_number()
elif space.Class == 'String':
space = space.to_string()
if space._type() == 'Number':
space = this.Js(min(10, space.to_int()))
gap = max(int(space.value), 0) * ' '
elif space._type() == 'String':
gap = space.value[:10]
else:
gap = ''
return this.Js(
Str('', this.Js({
'': value
}), replacer_function, property_list, gap, stack, space))
def Str(key, holder, replacer_function, property_list, gap, stack, space):
value = holder[key]
if value.is_object():
to_json = value.get('toJSON')
if to_json.is_callable():
value = to_json.call(value, (key, ))
if not replacer_function.is_undefined():
value = replacer_function.call(holder, (key, value))
if value.is_object():
if value.Class == 'String':
value = value.to_string()
elif value.Class == 'Number':
value = value.to_number()
elif value.Class == 'Boolean':
value = value.to_boolean()
if value.is_null():
return 'null'
elif value.Class == 'Boolean':
return 'true' if value.value else 'false'
elif value._type() == 'String':
return Quote(value)
elif value._type() == 'Number':
if not value.is_infinity():
return value.to_string()
return 'null'
if value.is_object() and not value.is_callable():
if value.Class == 'Array':
return ja(value, stack, gap, property_list, replacer_function,
space)
else:
return jo(value, stack, gap, property_list, replacer_function,
space)
return None # undefined
def jo(value, stack, gap, property_list, replacer_function, space):
global indent
if value in stack:
raise value.MakeError('TypeError',
'Converting circular structure to JSON')
stack.add(value)
stepback = indent
indent += gap
if not property_list.is_undefined():
k = property_list
else:
k = [e.value for e in value]
partial = []
for p in k:
str_p = value.Js(
Str(p, value, replacer_function, property_list, gap, stack, space))
if not str_p.is_undefined():
member = json.dumps(p) + ':' + (
' ' if gap else
'') + str_p.value # todo not sure here - what space character?
partial.append(member)
if not partial:
final = '{}'
else:
if not gap:
final = '{%s}' % ','.join(partial)
else:
sep = ',\n' + indent
properties = sep.join(partial)
final = '{\n' + indent + properties + '\n' + stepback + '}'
stack.remove(value)
indent = stepback
return final
def ja(value, stack, gap, property_list, replacer_function, space):
global indent
if value in stack:
raise value.MakeError('TypeError',
'Converting circular structure to JSON')
stack.add(value)
stepback = indent
indent += gap
partial = []
length = len(value)
for index in xrange(length):
index = str(index)
str_index = value.Js(
Str(index, value, replacer_function, property_list, gap, stack,
space))
if str_index.is_undefined():
partial.append('null')
else:
partial.append(str_index.value)
if not partial:
final = '[]'
else:
if not gap:
final = '[%s]' % ','.join(partial)
else:
sep = ',\n' + indent
properties = sep.join(partial)
final = '[\n' + indent + properties + '\n' + stepback + ']'
stack.remove(value)
indent = stepback
return final
def Quote(string):
return string.Js(json.dumps(string.value))
def to_js(this, d):
if isinstance(d, dict):
return this.Js(dict((k, this.Js(v)) for k, v in six.iteritems(d)))
return this.Js(d)
def walk(holder, name, reviver):
val = holder.get(name)
if val.Class == 'Array':
for i in xrange(len(val)):
i = unicode(i)
new_element = walk(val, i, reviver)
if new_element.is_undefined():
val.delete(i)
else:
new_element.put(i, new_element)
elif val.is_object():
for key in val:
new_element = walk(val, key, reviver)
if new_element.is_undefined():
val.delete(key)
else:
val.put(key, new_element)
return reviver.call(holder, (name, val))
JSON = Js({})
JSON.define_own_property(
'parse', {
'value': Js(parse),
'enumerable': False,
'writable': True,
'configurable': True
})
JSON.define_own_property(
'stringify', {
'value': Js(stringify),
'enumerable': False,
'writable': True,
'configurable': True
})
+146
View File
@@ -0,0 +1,146 @@
import six
if six.PY3:
basestring = str
long = int
xrange = range
unicode = str
RADIX_SYMBOLS = {
0: '0',
1: '1',
2: '2',
3: '3',
4: '4',
5: '5',
6: '6',
7: '7',
8: '8',
9: '9',
10: 'a',
11: 'b',
12: 'c',
13: 'd',
14: 'e',
15: 'f',
16: 'g',
17: 'h',
18: 'i',
19: 'j',
20: 'k',
21: 'l',
22: 'm',
23: 'n',
24: 'o',
25: 'p',
26: 'q',
27: 'r',
28: 's',
29: 't',
30: 'u',
31: 'v',
32: 'w',
33: 'x',
34: 'y',
35: 'z'
}
def to_str_rep(num):
if num.is_nan():
return num.Js('NaN')
elif num.is_infinity():
sign = '-' if num.value < 0 else ''
return num.Js(sign + 'Infinity')
elif isinstance(num.value,
(long, int)) or num.value.is_integer(): # dont print .0
return num.Js(unicode(int(num.value)))
return num.Js(unicode(num.value)) # accurate enough
class NumberPrototype:
def toString(radix):
if this.Class != 'Number':
raise this.MakeError('TypeError',
'Number.prototype.valueOf is not generic')
if radix.is_undefined():
return to_str_rep(this)
r = radix.to_int()
if r == 10:
return to_str_rep(this)
if r not in xrange(2, 37):
raise this.MakeError(
'RangeError',
'Number.prototype.toString() radix argument must be between 2 and 36'
)
num = this.to_int()
if num < 0:
num = -num
sign = '-'
else:
sign = ''
res = ''
while num:
s = RADIX_SYMBOLS[num % r]
num = num // r
res = s + res
return sign + (res if res else '0')
def valueOf():
if this.Class != 'Number':
raise this.MakeError('TypeError',
'Number.prototype.valueOf is not generic')
return this.value
def toLocaleString():
return this.to_string()
def toFixed(fractionDigits):
if this.Class != 'Number':
raise this.MakeError(
'TypeError',
'Number.prototype.toFixed called on incompatible receiver')
digs = fractionDigits.to_int()
if digs < 0 or digs > 20:
raise this.MakeError(
'RangeError',
'toFixed() digits argument must be between 0 and 20')
elif this.is_infinity():
return 'Infinity' if this.value > 0 else '-Infinity'
elif this.is_nan():
return 'NaN'
return format(this.value, '-.%df' % digs)
def toExponential(fractionDigits):
if this.Class != 'Number':
raise this.MakeError(
'TypeError',
'Number.prototype.toExponential called on incompatible receiver'
)
digs = fractionDigits.to_int()
if digs < 0 or digs > 20:
raise this.MakeError(
'RangeError',
'toFixed() digits argument must be between 0 and 20')
elif this.is_infinity():
return 'Infinity' if this.value > 0 else '-Infinity'
elif this.is_nan():
return 'NaN'
return format(this.value, '-.%de' % digs)
def toPrecision(precision):
if this.Class != 'Number':
raise this.MakeError(
'TypeError',
'Number.prototype.toPrecision called on incompatible receiver')
if precision.is_undefined():
return this.to_string()
prec = precision.to_int()
if this.is_nan():
return 'NaN'
elif this.is_infinity():
return 'Infinity' if this.value > 0 else '-Infinity'
digs = prec - len(str(int(this.value)))
if digs >= 0:
return format(this.value, '-.%df' % digs)
else:
return format(this.value, '-.%df' % (prec - 1))
+28
View File
@@ -0,0 +1,28 @@
class ObjectPrototype:
def toString():
return '[object %s]' % this.Class
def valueOf():
return this.to_object()
def toLocaleString():
return this.callprop('toString')
def hasOwnProperty(prop):
return this.get_own_property(prop.to_string().value) is not None
def isPrototypeOf(obj):
#a bit stupid specification but well
# for example Object.prototype.isPrototypeOf.call((5).__proto__, 5) gives false
if not obj.is_object():
return False
while 1:
obj = obj.prototype
if obj is None or obj.is_null():
return False
if obj is this:
return True
def propertyIsEnumerable(prop):
cand = this.own.get(prop.to_string().value)
return cand is not None and cand.get('enumerable')
+45
View File
@@ -0,0 +1,45 @@
class RegExpPrototype:
def toString():
flags = u''
try:
if this.glob:
flags += u'g'
if this.ignore_case:
flags += u'i'
if this.multiline:
flags += u'm'
except:
pass
v = this.value if this.value else '(?:)'
return u'/%s/' % v + flags
def test(string):
return Exec(this, string) is not this.null
def exec2(string
): # will be changed to exec in base.py. cant name it exec here
return Exec(this, string)
def Exec(this, string):
if this.Class != 'RegExp':
raise this.MakeError('TypeError',
'RegExp.prototype.exec is not generic!')
string = string.to_string()
length = len(string)
i = this.get('lastIndex').to_int() if this.glob else 0
matched = False
while not matched:
if i < 0 or i > length:
this.put('lastIndex', this.Js(0))
return this.null
matched = this.match(string.value, i)
i += 1
start, end = matched.span() #[0]+i-1, matched.span()[1]+i-1
if this.glob:
this.put('lastIndex', this.Js(end))
arr = this.Js(
[this.Js(e) for e in [matched.group()] + list(matched.groups())])
arr.put('index', this.Js(start))
arr.put('input', string)
return arr
+306
View File
@@ -0,0 +1,306 @@
# -*- coding: utf-8 -*-
from .jsregexp import Exec
import re
DIGS = set('0123456789')
WHITE = u"\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF"
def replacement_template(rep, source, span, npar):
"""Takes the replacement template and some info about the match and returns filled template
"""
n = 0
res = ''
while n < len(rep) - 1:
char = rep[n]
if char == '$':
if rep[n + 1] == '$':
res += '$'
n += 2
continue
elif rep[n + 1] == '`':
# replace with string that is BEFORE match
res += source[:span[0]]
n += 2
continue
elif rep[n + 1] == '\'':
# replace with string that is AFTER match
res += source[span[1]:]
n += 2
continue
elif rep[n + 1] in DIGS:
dig = rep[n + 1]
if n + 2 < len(rep) and rep[n + 2] in DIGS:
dig += rep[n + 2]
num = int(dig)
# we will not do any replacements if we dont have this npar or dig is 0
if not num or num > len(npar):
res += '$' + dig
else:
# None - undefined has to be replaced with ''
res += npar[num - 1] if npar[num - 1] else ''
n += 1 + len(dig)
continue
res += char
n += 1
if n < len(rep):
res += rep[-1]
return res
###################################################
class StringPrototype:
def toString():
if this.Class != 'String':
raise this.MakeError('TypeError',
'String.prototype.toString is not generic')
return this.value
def valueOf():
if this.Class != 'String':
raise this.MakeError('TypeError',
'String.prototype.valueOf is not generic')
return this.value
def charAt(pos):
this.cok()
pos = pos.to_int()
s = this.to_string()
if 0 <= pos < len(s.value):
char = s.value[pos]
if char not in s.CHAR_BANK:
s.Js(char) # add char to char bank
return s.CHAR_BANK[char]
return s.CHAR_BANK['']
def charCodeAt(pos):
this.cok()
pos = pos.to_int()
s = this.to_string()
if 0 <= pos < len(s.value):
return s.Js(ord(s.value[pos]))
return s.NaN
def concat():
this.cok()
s = this.to_string()
res = s.value
for e in arguments.to_list():
res += e.to_string().value
return res
def indexOf(searchString, position):
this.cok()
s = this.to_string().value
search = searchString.to_string().value
pos = position.to_int()
return this.Js(s.find(search, min(max(pos, 0), len(s))))
def lastIndexOf(searchString, position):
this.cok()
s = this.to_string().value
search = searchString.to_string().value
pos = position.to_number()
pos = 10**15 if pos.is_nan() else pos.to_int()
return s.rfind(search, 0, min(max(pos, 0) + 1, len(s)))
def localeCompare(that):
this.cok()
s = this.to_string()
that = that.to_string()
if s < that:
return this.Js(-1)
elif s > that:
return this.Js(1)
return this.Js(0)
def match(regexp):
this.cok()
s = this.to_string()
r = this.RegExp(regexp) if regexp.Class != 'RegExp' else regexp
if not r.glob:
return Exec(r, s)
r.put('lastIndex', this.Js(0))
found = []
previous_last_index = 0
last_match = True
while last_match:
result = Exec(r, s)
if result.is_null():
last_match = False
else:
this_index = r.get('lastIndex').value
if this_index == previous_last_index:
r.put('lastIndex', this.Js(this_index + 1))
previous_last_index += 1
else:
previous_last_index = this_index
matchStr = result.get('0')
found.append(matchStr)
if not found:
return this.null
return found
def replace(searchValue, replaceValue):
# VERY COMPLICATED. to check again.
this.cok()
string = this.to_string()
s = string.value
res = ''
if not replaceValue.is_callable():
replaceValue = replaceValue.to_string().value
func = False
else:
func = True
# Replace all ( global )
if searchValue.Class == 'RegExp' and searchValue.glob:
last = 0
for e in re.finditer(searchValue.pat, s):
res += s[last:e.span()[0]]
if func:
# prepare arguments for custom func (replaceValue)
args = (e.group(), ) + e.groups() + (e.span()[1], string)
# convert all types to JS
args = map(this.Js, args)
res += replaceValue(*args).to_string().value
else:
res += replacement_template(replaceValue, s, e.span(),
e.groups())
last = e.span()[1]
res += s[last:]
return this.Js(res)
elif searchValue.Class == 'RegExp':
e = re.search(searchValue.pat, s)
if e is None:
return string
span = e.span()
pars = e.groups()
match = e.group()
else:
match = searchValue.to_string().value
ind = s.find(match)
if ind == -1:
return string
span = ind, ind + len(match)
pars = ()
res = s[:span[0]]
if func:
args = (match, ) + pars + (span[1], string)
# convert all types to JS
this_ = this
args = tuple([this_.Js(x) for x in args])
res += replaceValue(*args).to_string().value
else:
res += replacement_template(replaceValue, s, span, pars)
res += s[span[1]:]
return res
def search(regexp):
this.cok()
string = this.to_string()
if regexp.Class == 'RegExp':
rx = regexp
else:
rx = this.RegExp(regexp)
res = re.search(rx.pat, string.value)
if res is not None:
return this.Js(res.span()[0])
return -1
def slice(start, end):
this.cok()
s = this.to_string()
start = start.to_int()
length = len(s.value)
end = length if end.is_undefined() else end.to_int()
#From = max(length+start, 0) if start<0 else min(length, start)
#To = max(length+end, 0) if end<0 else min(length, end)
return s.value[start:end]
def split(separator, limit):
# its a bit different that re.split!
this.cok()
S = this.to_string()
s = S.value
lim = 2**32 - 1 if limit.is_undefined() else limit.to_uint32()
if not lim:
return []
if separator.is_undefined():
return [s]
len_s = len(s)
res = []
R = separator if separator.Class == 'RegExp' else separator.to_string()
if not len_s:
if SplitMatch(s, 0, R) is None:
return [S]
return []
p = q = 0
while q != len_s:
e, cap = SplitMatch(s, q, R)
if e is None or e == p:
q += 1
continue
res.append(s[p:q])
p = q = e
if len(res) == lim:
return res
for element in cap:
res.append(this.Js(element))
if len(res) == lim:
return res
res.append(s[p:])
return res
def substring(start, end):
this.cok()
s = this.to_string().value
start = start.to_int()
length = len(s)
end = length if end.is_undefined() else end.to_int()
fstart = min(max(start, 0), length)
fend = min(max(end, 0), length)
return this.Js(s[min(fstart, fend):max(fstart, fend)])
def substr(start, length):
#I hate this function and its description in specification
r1 = this.to_string().value
r2 = start.to_int()
r3 = 10**20 if length.is_undefined() else length.to_int()
r4 = len(r1)
r5 = r2 if r2 >= 0 else max(0, r2 + r4)
r6 = min(max(r3, 0), r4 - r5)
if r6 <= 0:
return ''
return r1[r5:r5 + r6]
def toLowerCase():
this.cok()
return this.Js(this.to_string().value.lower())
def toLocaleLowerCase():
this.cok()
return this.Js(this.to_string().value.lower())
def toUpperCase():
this.cok()
return this.Js(this.to_string().value.upper())
def toLocaleUpperCase():
this.cok()
return this.Js(this.to_string().value.upper())
def trim():
this.cok()
return this.Js(this.to_string().value.strip(WHITE))
def SplitMatch(s, q, R):
# s is Py String to match, q is the py int match start and R is Js RegExp or String.
if R.Class == 'RegExp':
res = R.match(s, q)
return (None, ()) if res is None else (res.span()[1], res.groups())
# R is just a string
if s[q:].startswith(R.value):
return q + len(R.value), ()
return None, ()
+344
View File
@@ -0,0 +1,344 @@
# this is based on jsarray.py
import six
try:
import numpy
except:
pass
if six.PY3:
xrange = range
import functools
def to_arr(this):
"""Returns Python array from Js array"""
return [this.get(str(e)) for e in xrange(len(this))]
ARR_STACK = set({})
class TypedArrayPrototype:
def toString():
# this function is wrong
func = this.get('join')
if not func.is_callable():
@this.Js
def func():
return '[object %s]' % this.Class
return func.call(this, ())
def toLocaleString(locales=None, options=None):
array = this.to_object()
arr_len = array.get("length").to_uint32()
# separator is simply a comma ','
if not arr_len:
return ''
res = []
for i in xrange(arr_len):
element = array[str(i)]
if element.is_undefined() or element.is_null():
res.append('')
else:
cand = element.to_object()
str_func = element.get('toLocaleString')
if not str_func.is_callable():
raise this.MakeError(
'TypeError',
'toLocaleString method of item at index %d is not callable'
% i)
res.append(element.callprop('toLocaleString').value)
return ','.join(res)
def join(separator):
ARR_STACK.add(this)
array = this.to_object()
arr_len = array.get("length").to_uint32()
separator = ',' if separator.is_undefined() else separator.to_string(
).value
elems = []
for e in xrange(arr_len):
elem = array.get(str(e))
if elem in ARR_STACK:
s = ''
else:
s = elem.to_string().value
elems.append(
s if not (elem.is_undefined() or elem.is_null()) else '')
res = separator.join(elems)
ARR_STACK.remove(this)
return res
def reverse():
array = this.to_object() # my own algorithm
vals = to_arr(array)
has_props = [array.has_property(str(e)) for e in xrange(len(array))]
vals.reverse()
has_props.reverse()
for i, val in enumerate(vals):
if has_props[i]:
array.put(str(i), val)
else:
array.delete(str(i))
return array
def slice(start, end): # todo check
array = this.to_object()
arr_len = array.get("length").to_uint32()
relative_start = start.to_int()
k = max((arr_len + relative_start), 0) if relative_start < 0 else min(
relative_start, arr_len)
relative_end = arr_len if end.is_undefined() else end.to_int()
final = max((arr_len + relative_end), 0) if relative_end < 0 else min(
relative_end, arr_len)
res = []
n = 0
while k < final:
pk = str(k)
if array.has_property(pk):
res.append(array.get(pk))
k += 1
n += 1
return res
def sort(cmpfn):
if not this.Class in ('Array', 'Arguments'):
return this.to_object() # do nothing
arr = []
for i in xrange(len(this)):
arr.append(this.get(six.text_type(i)))
if not arr:
return this
if not cmpfn.is_callable():
cmpfn = None
cmp = lambda a, b: sort_compare(a, b, cmpfn)
if six.PY3:
key = functools.cmp_to_key(cmp)
arr.sort(key=key)
else:
arr.sort(cmp=cmp)
for i in xrange(len(arr)):
this.put(six.text_type(i), arr[i])
return this
def indexOf(searchElement):
array = this.to_object()
arr_len = array.get("length").to_uint32()
if arr_len == 0:
return -1
if len(arguments) > 1:
n = arguments[1].to_int()
else:
n = 0
if n >= arr_len:
return -1
if n >= 0:
k = n
else:
k = arr_len - abs(n)
if k < 0:
k = 0
while k < arr_len:
if array.has_property(str(k)):
elementK = array.get(str(k))
if searchElement.strict_equality_comparison(elementK):
return k
k += 1
return -1
def lastIndexOf(searchElement):
array = this.to_object()
arr_len = array.get("length").to_uint32()
if arr_len == 0:
return -1
if len(arguments) > 1:
n = arguments[1].to_int()
else:
n = arr_len - 1
if n >= 0:
k = min(n, arr_len - 1)
else:
k = arr_len - abs(n)
while k >= 0:
if array.has_property(str(k)):
elementK = array.get(str(k))
if searchElement.strict_equality_comparison(elementK):
return k
k -= 1
return -1
def every(callbackfn):
array = this.to_object()
arr_len = array.get("length").to_uint32()
if not callbackfn.is_callable():
raise this.MakeError('TypeError', 'callbackfn must be a function')
T = arguments[1]
k = 0
while k < arr_len:
if array.has_property(str(k)):
kValue = array.get(str(k))
if not callbackfn.call(
T, (kValue, this.Js(k), array)).to_boolean().value:
return False
k += 1
return True
def some(callbackfn):
array = this.to_object()
arr_len = array.get("length").to_uint32()
if not callbackfn.is_callable():
raise this.MakeError('TypeError', 'callbackfn must be a function')
T = arguments[1]
k = 0
while k < arr_len:
if array.has_property(str(k)):
kValue = array.get(str(k))
if callbackfn.call(
T, (kValue, this.Js(k), array)).to_boolean().value:
return True
k += 1
return False
def forEach(callbackfn):
array = this.to_object()
arr_len = array.get("length").to_uint32()
if not callbackfn.is_callable():
raise this.MakeError('TypeError', 'callbackfn must be a function')
T = arguments[1]
k = 0
while k < arr_len:
if array.has_property(str(k)):
kValue = array.get(str(k))
callbackfn.call(T, (kValue, this.Js(k), array))
k += 1
def map(callbackfn):
array = this.to_object()
arr_len = array.get("length").to_uint32()
if not callbackfn.is_callable():
raise this.MakeError('TypeError', 'callbackfn must be a function')
T = arguments[1]
A = this.Js([])
k = 0
while k < arr_len:
Pk = str(k)
if array.has_property(Pk):
kValue = array.get(Pk)
mappedValue = callbackfn.call(T, (kValue, this.Js(k), array))
A.define_own_property(
Pk, {
'value': mappedValue,
'writable': True,
'enumerable': True,
'configurable': True
})
k += 1
return A
def filter(callbackfn):
array = this.to_object()
arr_len = array.get("length").to_uint32()
if not callbackfn.is_callable():
raise this.MakeError('TypeError', 'callbackfn must be a function')
T = arguments[1]
res = []
k = 0
while k < arr_len:
if array.has_property(str(k)):
kValue = array.get(str(k))
if callbackfn.call(
T, (kValue, this.Js(k), array)).to_boolean().value:
res.append(kValue)
k += 1
return res # converted to js array automatically
def reduce(callbackfn):
array = this.to_object()
arr_len = array.get("length").to_uint32()
if not callbackfn.is_callable():
raise this.MakeError('TypeError', 'callbackfn must be a function')
if not arr_len and len(arguments) < 2:
raise this.MakeError(
'TypeError', 'Reduce of empty array with no initial value')
k = 0
if len(arguments) > 1: # initial value present
accumulator = arguments[1]
else:
kPresent = False
while not kPresent and k < arr_len:
kPresent = array.has_property(str(k))
if kPresent:
accumulator = array.get(str(k))
k += 1
if not kPresent:
raise this.MakeError(
'TypeError', 'Reduce of empty array with no initial value')
while k < arr_len:
if array.has_property(str(k)):
kValue = array.get(str(k))
accumulator = callbackfn.call(
this.undefined, (accumulator, kValue, this.Js(k), array))
k += 1
return accumulator
def reduceRight(callbackfn):
array = this.to_object()
arr_len = array.get("length").to_uint32()
if not callbackfn.is_callable():
raise this.MakeError('TypeError', 'callbackfn must be a function')
if not arr_len and len(arguments) < 2:
raise this.MakeError(
'TypeError', 'Reduce of empty array with no initial value')
k = arr_len - 1
if len(arguments) > 1: # initial value present
accumulator = arguments[1]
else:
kPresent = False
while not kPresent and k >= 0:
kPresent = array.has_property(str(k))
if kPresent:
accumulator = array.get(str(k))
k -= 1
if not kPresent:
raise this.MakeError(
'TypeError', 'Reduce of empty array with no initial value')
while k >= 0:
if array.has_property(str(k)):
kValue = array.get(str(k))
accumulator = callbackfn.call(
this.undefined, (accumulator, kValue, this.Js(k), array))
k -= 1
return accumulator
def sort_compare(a, b, comp):
if a is None:
if b is None:
return 0
return 1
if b is None:
if a is None:
return 0
return -1
if a.is_undefined():
if b.is_undefined():
return 0
return 1
if b.is_undefined():
if a.is_undefined():
return 0
return -1
if comp is not None:
res = comp.call(a.undefined, (a, b))
return res.to_int()
x, y = a.to_string(), b.to_string()
if x < y:
return -1
elif x > y:
return 1
return 0