[jsbuilt-ins] a riddle wrapped in mystery inside an enigma
This commit is contained in:
parent
6f2ac27695
commit
0eef083da6
@ -1,40 +1,65 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from types import FunctionType
|
||||||
|
|
||||||
|
|
||||||
class JSBase(object):
|
class JSBase(object):
|
||||||
|
|
||||||
_name = ''
|
def __init__(self, name, value):
|
||||||
|
self.props = self.__class__.props.copy()
|
||||||
def __init__(self):
|
self.name = name
|
||||||
self._props = self.__class__._props.copy()
|
self.value = value
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '[native code]'
|
return '[native code]'
|
||||||
|
|
||||||
_props = {}
|
props = {}
|
||||||
|
|
||||||
|
|
||||||
|
def js(func):
|
||||||
|
def py2js(o):
|
||||||
|
if isinstance(o, (FunctionType, JSBase)):
|
||||||
|
return JSFunctionPrototype(o)
|
||||||
|
elif isinstance(o, dict):
|
||||||
|
return JSObjectPrototype(o)
|
||||||
|
elif isinstance(o, (list, tuple)):
|
||||||
|
return JSArrayPrototype(o)
|
||||||
|
else:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
return py2js(func(*args, **kwargs))
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
class JSProtoBase(JSBase):
|
class JSProtoBase(JSBase):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(JSProtoBase, self).__init__()
|
|
||||||
self._value = {}
|
|
||||||
cls = self.__class__
|
cls = self.__class__
|
||||||
while cls is not JSProtoBase:
|
while cls is not JSProtoBase:
|
||||||
cls = cls.__base__
|
cls = cls.__base__
|
||||||
props = cls._props.copy()
|
props = cls.props.copy()
|
||||||
props.update(self._props)
|
props.update(self.props)
|
||||||
self._props = props
|
self.props = props
|
||||||
|
super(JSProtoBase, self).__init__('', self.props)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
def get_prop(self, prop):
|
def _get_prop(self, prop):
|
||||||
result = self._value.get(prop)
|
result = self.value.get(prop)
|
||||||
return result if result is not None else self._props.get(prop)
|
if result is None:
|
||||||
|
result = self.props.get(prop)
|
||||||
|
return result
|
||||||
|
|
||||||
|
@js
|
||||||
|
def get_prop(self, prop):
|
||||||
|
return self._get_prop(prop)
|
||||||
|
|
||||||
|
@js
|
||||||
def call_prop(self, prop, *args):
|
def call_prop(self, prop, *args):
|
||||||
return self.get_prop(prop)(self, *args)
|
return self._get_prop(prop)(self, *args)
|
||||||
|
|
||||||
|
|
||||||
class JSObjectPrototype(JSProtoBase):
|
class JSObjectPrototype(JSProtoBase):
|
||||||
@ -42,7 +67,7 @@ class JSObjectPrototype(JSProtoBase):
|
|||||||
def __init__(self, value=None):
|
def __init__(self, value=None):
|
||||||
super(JSObjectPrototype, self).__init__()
|
super(JSObjectPrototype, self).__init__()
|
||||||
if value is not None:
|
if value is not None:
|
||||||
self._value = value
|
self.value = value
|
||||||
|
|
||||||
def _to_string(self):
|
def _to_string(self):
|
||||||
return 'object to string'
|
return 'object to string'
|
||||||
@ -54,7 +79,7 @@ class JSObjectPrototype(JSProtoBase):
|
|||||||
return 'object value of'
|
return 'object value of'
|
||||||
|
|
||||||
def _has_own_property(self, v):
|
def _has_own_property(self, v):
|
||||||
return v in self._value
|
return v in self.value
|
||||||
|
|
||||||
def _is_prototype_of(self, v):
|
def _is_prototype_of(self, v):
|
||||||
return 'object has own prop'
|
return 'object has own prop'
|
||||||
@ -62,7 +87,7 @@ class JSObjectPrototype(JSProtoBase):
|
|||||||
def _is_property_enumerable(self, v):
|
def _is_property_enumerable(self, v):
|
||||||
return 'object is property enumerable'
|
return 'object is property enumerable'
|
||||||
|
|
||||||
_props = {
|
props = {
|
||||||
'constructor': __init__,
|
'constructor': __init__,
|
||||||
'toString': _to_string,
|
'toString': _to_string,
|
||||||
'toLocaleString': _to_locale_string,
|
'toLocaleString': _to_locale_string,
|
||||||
@ -75,7 +100,8 @@ class JSObjectPrototype(JSProtoBase):
|
|||||||
|
|
||||||
class JSObject(JSBase):
|
class JSObject(JSBase):
|
||||||
|
|
||||||
_name = 'Object'
|
def __init__(self):
|
||||||
|
super(JSObject, self).__init__(self.name, self.props)
|
||||||
|
|
||||||
def _get_prototype_of(self, o):
|
def _get_prototype_of(self, o):
|
||||||
return 'object get prototype of'
|
return 'object get prototype of'
|
||||||
@ -116,9 +142,10 @@ class JSObject(JSBase):
|
|||||||
def _keys(self, o):
|
def _keys(self, o):
|
||||||
return 'object keys'
|
return 'object keys'
|
||||||
|
|
||||||
_props = {
|
name = 'Object'
|
||||||
|
props = {
|
||||||
'length': 1,
|
'length': 1,
|
||||||
'prototype': JSObjectPrototype(JSObjectPrototype._props),
|
'prototype': JSObjectPrototype.props,
|
||||||
'getPrototypeOf': _get_prototype_of,
|
'getPrototypeOf': _get_prototype_of,
|
||||||
'getOwnPropertyDescriptor': _get_own_property_descriptor,
|
'getOwnPropertyDescriptor': _get_own_property_descriptor,
|
||||||
'getOwnPropertyNames': _get_own_property_names,
|
'getOwnPropertyNames': _get_own_property_names,
|
||||||
@ -140,15 +167,15 @@ class JSFunctionPrototype(JSObjectPrototype):
|
|||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
body = args[-1] if args else ''
|
body = args[-1] if args else ''
|
||||||
if isinstance(body, JSBase):
|
if isinstance(body, JSBase):
|
||||||
super(JSFunctionPrototype, self).__init__(value=body._props)
|
super(JSFunctionPrototype, self).__init__(body.props)
|
||||||
self._fname = body._name
|
self.fname = body.name
|
||||||
else:
|
else:
|
||||||
super(JSFunctionPrototype, self).__init__()
|
super(JSFunctionPrototype, self).__init__()
|
||||||
self._fname = 'anonymous'
|
self.fname = 'anonymous'
|
||||||
|
|
||||||
# FIXME: JSProtoBase sets body to '' instead of None
|
# FIXME: JSProtoBase sets body to '' instead of None
|
||||||
self._body = str(body)
|
self.body = str(body)
|
||||||
self._args = [sarg.strip() for arg in args[:-1] for sarg in str(arg).split(',')]
|
self.args = [sarg.strip() for arg in args[:-1] for sarg in str(arg).split(',')]
|
||||||
# TODO check if self._args can be parsed as formal parameter list
|
# TODO check if self._args can be parsed as formal parameter list
|
||||||
# TODO check if self._body can be parsed as function body
|
# TODO check if self._body can be parsed as function body
|
||||||
# TODO set strict
|
# TODO set strict
|
||||||
@ -159,15 +186,15 @@ class JSFunctionPrototype(JSObjectPrototype):
|
|||||||
def _length(self):
|
def _length(self):
|
||||||
# FIXME: returns maximum instead of "typical" number of arguments
|
# FIXME: returns maximum instead of "typical" number of arguments
|
||||||
# Yeesh, I dare you to find anything like that in the python specification.
|
# Yeesh, I dare you to find anything like that in the python specification.
|
||||||
return len(self._args)
|
return len(self.args)
|
||||||
|
|
||||||
def _to_string(self):
|
def _to_string(self):
|
||||||
if self._body is not None:
|
if self.body is not None:
|
||||||
body = '\n'
|
body = '\n'
|
||||||
body += '\t' + self._body if self._body else self._body
|
body += '\t' + self.body if self.body else self.body
|
||||||
else:
|
else:
|
||||||
body = ''
|
body = ''
|
||||||
return 'function %s(%s) {%s\n}' % (self._fname, ', '.join(self._args), body)
|
return 'function %s(%s) {%s\n}' % (self.fname, ', '.join(self.args), body)
|
||||||
|
|
||||||
def _apply(self, this_arg, arg_array):
|
def _apply(self, this_arg, arg_array):
|
||||||
return 'function apply'
|
return 'function apply'
|
||||||
@ -178,7 +205,7 @@ class JSFunctionPrototype(JSObjectPrototype):
|
|||||||
def _bind(self, this_arg, *args):
|
def _bind(self, this_arg, *args):
|
||||||
return 'function bind'
|
return 'function bind'
|
||||||
|
|
||||||
_props = {
|
props = {
|
||||||
'length': 0,
|
'length': 0,
|
||||||
'constructor': __init__,
|
'constructor': __init__,
|
||||||
'toString': _to_string,
|
'toString': _to_string,
|
||||||
@ -190,11 +217,11 @@ class JSFunctionPrototype(JSObjectPrototype):
|
|||||||
|
|
||||||
class JSFuction(JSObject):
|
class JSFuction(JSObject):
|
||||||
|
|
||||||
_name = 'Function'
|
name = 'Function'
|
||||||
|
|
||||||
_props = {
|
props = {
|
||||||
'length': 1,
|
'length': 1,
|
||||||
'prototype': JSFunctionPrototype(JSFunctionPrototype())
|
'prototype': JSFunctionPrototype()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -202,13 +229,19 @@ class JSArrayPrototype(JSObjectPrototype):
|
|||||||
|
|
||||||
def __init__(self, value=None, length=0):
|
def __init__(self, value=None, length=0):
|
||||||
super(JSArrayPrototype, self).__init__()
|
super(JSArrayPrototype, self).__init__()
|
||||||
self.list = []
|
self.list = [] if value is None else value
|
||||||
self._value['length'] = self._length
|
self.value['length'] = self._length
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _length(self):
|
def _length(self):
|
||||||
return len(self.list)
|
return len(self.list)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'JSArrayPrototype: %s' % self.list
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return 'JSArrayPrototype(%s, %s)' % (self.list, self._length)
|
||||||
|
|
||||||
def _to_string(self):
|
def _to_string(self):
|
||||||
return 'array to string'
|
return 'array to string'
|
||||||
|
|
||||||
@ -250,7 +283,7 @@ class JSArrayPrototype(JSObjectPrototype):
|
|||||||
|
|
||||||
def _last_index_of(self, elem, from_index=None):
|
def _last_index_of(self, elem, from_index=None):
|
||||||
if from_index is None:
|
if from_index is None:
|
||||||
from_index = len(self._value) - 1
|
from_index = len(self.value) - 1
|
||||||
return 'array index of'
|
return 'array index of'
|
||||||
|
|
||||||
def _every(self, callback, this_arg=None):
|
def _every(self, callback, this_arg=None):
|
||||||
@ -274,7 +307,7 @@ class JSArrayPrototype(JSObjectPrototype):
|
|||||||
def _reduce_right(self, callback, init=None):
|
def _reduce_right(self, callback, init=None):
|
||||||
return 'array reduce right'
|
return 'array reduce right'
|
||||||
|
|
||||||
_props = {
|
props = {
|
||||||
'length': 0,
|
'length': 0,
|
||||||
'constructor': __init__,
|
'constructor': __init__,
|
||||||
'toString': _to_string,
|
'toString': _to_string,
|
||||||
@ -303,17 +336,17 @@ class JSArrayPrototype(JSObjectPrototype):
|
|||||||
|
|
||||||
class JSArray(JSObject):
|
class JSArray(JSObject):
|
||||||
|
|
||||||
_name = 'Array'
|
name = 'Array'
|
||||||
|
|
||||||
def _is_array(self, arg):
|
def _is_array(self, arg):
|
||||||
return 'array is array'
|
return 'array is array'
|
||||||
|
|
||||||
_props = {
|
props = {
|
||||||
'length': 1,
|
'length': 1,
|
||||||
'prototype': JSObjectPrototype(JSArrayPrototype._props),
|
'prototype': JSArrayPrototype.props,
|
||||||
'isArray': _is_array
|
'isArray': _is_array
|
||||||
}
|
}
|
||||||
|
|
||||||
global_obj = JSObjectPrototype({'Object': JSFunctionPrototype(JSObject()),
|
global_obj = JSObjectPrototype({'Object': JSObject(),
|
||||||
'Array': JSFunctionPrototype(JSArray()),
|
'Array': JSArray(),
|
||||||
'Function': JSFunctionPrototype(JSFuction())})
|
'Function': JSFuction()})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user