[jsbuilt-ins] adding _type and JSObject constructor
This commit is contained in:
parent
0eef083da6
commit
484a7d21ed
@ -2,6 +2,64 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
from types import FunctionType
|
from types import FunctionType
|
||||||
|
|
||||||
|
from ..compat import compat_str
|
||||||
|
|
||||||
|
|
||||||
|
def _to_js(o):
|
||||||
|
if isinstance(o, JSProtoBase):
|
||||||
|
return o
|
||||||
|
elif o is None:
|
||||||
|
return undefined
|
||||||
|
elif isinstance(o, _native_bool):
|
||||||
|
return JSBooleanPrototype(o)
|
||||||
|
elif isinstance(o, _native_string):
|
||||||
|
return JSStringPrototype(o)
|
||||||
|
elif isinstance(o, _native_number):
|
||||||
|
return JSNumberPrototype(o)
|
||||||
|
elif isinstance(o, _native_object):
|
||||||
|
return JSObjectPrototype(o)
|
||||||
|
elif isinstance(o, _native_function) or (isinstance(o, JSBase) and hasattr(o, 'call')):
|
||||||
|
return JSFunctionPrototype(o)
|
||||||
|
elif isinstance(o, _native_array):
|
||||||
|
return JSArrayPrototype(o)
|
||||||
|
else:
|
||||||
|
raise Exception('Not allowed conversion %s to js' % type(o))
|
||||||
|
|
||||||
|
|
||||||
|
def js(func):
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
return _to_js(func(*args, **kwargs))
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
def _type(o):
|
||||||
|
if o is undefined:
|
||||||
|
return _undefined_type
|
||||||
|
elif o is None or o is null:
|
||||||
|
return _null_type
|
||||||
|
elif isinstance(o, _native_bool) or isinstance(o, JSBooleanPrototype):
|
||||||
|
return _boolean_type
|
||||||
|
elif isinstance(o, _native_string) or isinstance(o, JSStringPrototype):
|
||||||
|
return _string_type
|
||||||
|
elif isinstance(o, _native_number) or isinstance(o, JSNumberPrototype):
|
||||||
|
return _number_type
|
||||||
|
elif isinstance(o, _native_object) or isinstance(o, JSObjectPrototype):
|
||||||
|
return _object_type
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def to_object(o):
|
||||||
|
if o is undefined or o is null:
|
||||||
|
raise Exception('TypeError: Cannot convert undefined or null to object')
|
||||||
|
elif isinstance(o, JSBooleanPrototype):
|
||||||
|
return JSBooleanPrototype(o)
|
||||||
|
elif isinstance(o, JSNumberPrototype):
|
||||||
|
return JSNumberPrototype(o)
|
||||||
|
elif isinstance(o, JSStringPrototype):
|
||||||
|
return JSStringPrototype(o)
|
||||||
|
elif isinstance(o, JSObjectPrototype):
|
||||||
|
return o
|
||||||
|
|
||||||
|
|
||||||
class JSBase(object):
|
class JSBase(object):
|
||||||
|
|
||||||
@ -16,23 +74,6 @@ class JSBase(object):
|
|||||||
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):
|
||||||
@ -42,12 +83,12 @@ class JSProtoBase(JSBase):
|
|||||||
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)
|
super(JSProtoBase, self).__init__('', {})
|
||||||
|
|
||||||
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)
|
||||||
if result is None:
|
if result is None:
|
||||||
result = self.props.get(prop)
|
result = self.props.get(prop)
|
||||||
@ -55,11 +96,24 @@ class JSProtoBase(JSBase):
|
|||||||
|
|
||||||
@js
|
@js
|
||||||
def get_prop(self, prop):
|
def get_prop(self, prop):
|
||||||
return self._get_prop(prop)
|
return self.__get_prop(prop)
|
||||||
|
|
||||||
@js
|
@js
|
||||||
def call_prop(self, prop, *args):
|
def call_prop(self, prop, *args, **kwargs):
|
||||||
return self._get_prop(prop)(self, *args)
|
func = self.__get_prop(prop)
|
||||||
|
if isinstance(func, FunctionType):
|
||||||
|
return func(self, *args, **kwargs)
|
||||||
|
elif isinstance(func, staticmethod):
|
||||||
|
return func.__func__(*args, **kwargs)
|
||||||
|
elif isinstance(func, classmethod):
|
||||||
|
return func.__func__(self.__class__, *args, **kwargs)
|
||||||
|
elif isinstance(func, JSBase) and hasattr(func, 'call'):
|
||||||
|
return func.call(*args, **kwargs)
|
||||||
|
else:
|
||||||
|
# FIXME instead of prop should return the whole expression
|
||||||
|
# needs to use internal exception
|
||||||
|
# interpreter should raise JSTypeError
|
||||||
|
raise Exception('TypeError: %s is not a function' % prop)
|
||||||
|
|
||||||
|
|
||||||
class JSObjectPrototype(JSProtoBase):
|
class JSObjectPrototype(JSProtoBase):
|
||||||
@ -69,6 +123,16 @@ class JSObjectPrototype(JSProtoBase):
|
|||||||
if value is not None:
|
if value is not None:
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _constructor(value=None):
|
||||||
|
value = _to_js(value)
|
||||||
|
if value is undefined or value is null:
|
||||||
|
return JSObjectPrototype()
|
||||||
|
elif isinstance(value, JSObjectPrototype):
|
||||||
|
return value
|
||||||
|
elif isinstance(value, (JSStringPrototype, JSNumberPrototype, JSBooleanPrototype)):
|
||||||
|
return to_object(value)
|
||||||
|
|
||||||
def _to_string(self):
|
def _to_string(self):
|
||||||
return 'object to string'
|
return 'object to string'
|
||||||
|
|
||||||
@ -88,7 +152,7 @@ class JSObjectPrototype(JSProtoBase):
|
|||||||
return 'object is property enumerable'
|
return 'object is property enumerable'
|
||||||
|
|
||||||
props = {
|
props = {
|
||||||
'constructor': __init__,
|
'constructor': _constructor,
|
||||||
'toString': _to_string,
|
'toString': _to_string,
|
||||||
'toLocaleString': _to_locale_string,
|
'toLocaleString': _to_locale_string,
|
||||||
'valueOf': _value_of,
|
'valueOf': _value_of,
|
||||||
@ -103,6 +167,14 @@ class JSObject(JSBase):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(JSObject, self).__init__(self.name, self.props)
|
super(JSObject, self).__init__(self.name, self.props)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def construct(value=None):
|
||||||
|
return JSObjectPrototype._constructor(value)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def call(value=None):
|
||||||
|
return JSObject.construct(value)
|
||||||
|
|
||||||
def _get_prototype_of(self, o):
|
def _get_prototype_of(self, o):
|
||||||
return 'object get prototype of'
|
return 'object get prototype of'
|
||||||
|
|
||||||
@ -145,7 +217,7 @@ class JSObject(JSBase):
|
|||||||
name = 'Object'
|
name = 'Object'
|
||||||
props = {
|
props = {
|
||||||
'length': 1,
|
'length': 1,
|
||||||
'prototype': JSObjectPrototype.props,
|
'prototype': JSObjectPrototype(),
|
||||||
'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,
|
||||||
@ -218,7 +290,6 @@ class JSFunctionPrototype(JSObjectPrototype):
|
|||||||
class JSFuction(JSObject):
|
class JSFuction(JSObject):
|
||||||
|
|
||||||
name = 'Function'
|
name = 'Function'
|
||||||
|
|
||||||
props = {
|
props = {
|
||||||
'length': 1,
|
'length': 1,
|
||||||
'prototype': JSFunctionPrototype()
|
'prototype': JSFunctionPrototype()
|
||||||
@ -336,17 +407,60 @@ class JSArrayPrototype(JSObjectPrototype):
|
|||||||
|
|
||||||
class JSArray(JSObject):
|
class JSArray(JSObject):
|
||||||
|
|
||||||
name = 'Array'
|
|
||||||
|
|
||||||
def _is_array(self, arg):
|
def _is_array(self, arg):
|
||||||
return 'array is array'
|
return 'array is array'
|
||||||
|
|
||||||
|
name = 'Array'
|
||||||
props = {
|
props = {
|
||||||
'length': 1,
|
'length': 1,
|
||||||
'prototype': JSArrayPrototype.props,
|
'prototype': JSArrayPrototype.props,
|
||||||
'isArray': _is_array
|
'isArray': _is_array
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class JSStringPrototype(JSObjectPrototype):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class JSString(JSObject):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class JSBooleanPrototype(JSObjectPrototype):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class JSBoolean(JSObject):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class JSNumberPrototype(JSObjectPrototype):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class JSNumber(JSObject):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
undefined = object()
|
||||||
|
null = object()
|
||||||
|
true = JSBooleanPrototype(True)
|
||||||
|
false = JSBooleanPrototype(False)
|
||||||
|
|
||||||
|
_native_bool = bool
|
||||||
|
_native_string = compat_str
|
||||||
|
_native_number = (int, float)
|
||||||
|
_native_object = dict
|
||||||
|
_native_array = (list, tuple)
|
||||||
|
_native_function = FunctionType
|
||||||
|
|
||||||
|
_undefined_type = object()
|
||||||
|
_null_type = object()
|
||||||
|
_boolean_type = object()
|
||||||
|
_string_type = object()
|
||||||
|
_number_type = object()
|
||||||
|
_object_type = object()
|
||||||
|
|
||||||
global_obj = JSObjectPrototype({'Object': JSObject(),
|
global_obj = JSObjectPrototype({'Object': JSObject(),
|
||||||
'Array': JSArray(),
|
'Array': JSArray(),
|
||||||
'Function': JSFuction()})
|
'Function': JSFuction()})
|
||||||
|
@ -4,6 +4,7 @@ import re
|
|||||||
|
|
||||||
from ..compat import compat_str
|
from ..compat import compat_str
|
||||||
from ..utils import ExtractorError
|
from ..utils import ExtractorError
|
||||||
|
from . import jsbuilt_ins
|
||||||
from .tstream import TokenStream, convert_to_unary
|
from .tstream import TokenStream, convert_to_unary
|
||||||
from .jsgrammar import Token, token_keys
|
from .jsgrammar import Token, token_keys
|
||||||
|
|
||||||
@ -57,7 +58,6 @@ class Reference(object):
|
|||||||
|
|
||||||
class JSInterpreter(object):
|
class JSInterpreter(object):
|
||||||
# TODO support json
|
# TODO support json
|
||||||
undefined = object()
|
|
||||||
|
|
||||||
def __init__(self, code, variables=None):
|
def __init__(self, code, variables=None):
|
||||||
self.code = code
|
self.code = code
|
||||||
@ -156,7 +156,7 @@ class JSInterpreter(object):
|
|||||||
init.append(self._assign_expression(token_stream, stack_top - 1))
|
init.append(self._assign_expression(token_stream, stack_top - 1))
|
||||||
peek_id, peek_value, peek_pos = token_stream.peek()
|
peek_id, peek_value, peek_pos = token_stream.peek()
|
||||||
else:
|
else:
|
||||||
init.append(JSInterpreter.undefined)
|
init.append(jsbuilt_ins.undefined)
|
||||||
|
|
||||||
if peek_id is Token.END:
|
if peek_id is Token.END:
|
||||||
if self._context.no_in:
|
if self._context.no_in:
|
||||||
@ -977,7 +977,7 @@ class JSInterpreter(object):
|
|||||||
if lid[0] is Token.ID and args is None and tail is None:
|
if lid[0] is Token.ID and args is None and tail is None:
|
||||||
key = lid[1]
|
key = lid[1]
|
||||||
if key is not None:
|
if key is not None:
|
||||||
u = Reference(self.undefined, (self.this, key))
|
u = Reference(jsbuilt_ins.undefined, (self.this, key))
|
||||||
leftref = self.this[key] = u
|
leftref = self.this[key] = u
|
||||||
else:
|
else:
|
||||||
raise ExtractorError('Invalid left-hand side in assignment')
|
raise ExtractorError('Invalid left-hand side in assignment')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user