111 lines
3.5 KiB
Python
111 lines
3.5 KiB
Python
from __future__ import unicode_literals
|
|
|
|
from .base import undefined, null
|
|
from .internals import to_string, throw_type_error
|
|
from .base import native_function, JSBase
|
|
from .utils import to_js
|
|
from .jsobject import JSObject, JSObjectPrototype
|
|
|
|
|
|
class JSFunctionPrototype(JSObjectPrototype):
|
|
|
|
def __init__(self, name, body, formal_args):
|
|
if name is None and body is None and formal_args is None:
|
|
# prototype
|
|
super(JSFunctionPrototype, self).__init__()
|
|
self.f_name = ''
|
|
self.body = ''
|
|
else:
|
|
if isinstance(body, JSBase):
|
|
super(JSFunctionPrototype, self).__init__(body.own)
|
|
self.body = '[native code]'
|
|
elif isinstance(body, native_function):
|
|
super(JSFunctionPrototype, self).__init__()
|
|
self.body = '[native code]'
|
|
else:
|
|
super(JSFunctionPrototype, self).__init__()
|
|
body = to_js(body)
|
|
self.body = to_string(body) if body is not undefined or body is not null else ''
|
|
self.f_name = name
|
|
self.arguments = list(formal_args)
|
|
proto = JSObject.construct()
|
|
proto.own['constructor'] = self
|
|
self.own = {'length': self._length,
|
|
'prototype': proto
|
|
}
|
|
# TODO Handle strict mode
|
|
strict = True
|
|
if strict:
|
|
thrower = throw_type_error
|
|
self.own['caller'] = thrower
|
|
self.own['arguments'] = thrower
|
|
# FIXME: JSProtoBase sets body to '' instead of None
|
|
# TODO check if self._args can be parsed as formal parameter list
|
|
# TODO check if self._body can be parsed as function body
|
|
# TODO set strict
|
|
# TODO throw strict mode exceptions
|
|
# (double argument, "eval" or "arguments" in arguments, function identifier is "eval" or "arguments")
|
|
|
|
@property
|
|
def _length(self):
|
|
return len(self.arguments)
|
|
|
|
@staticmethod
|
|
def _constructor(arguments=None):
|
|
return JSFunction.construct(arguments)
|
|
|
|
def _to_string(self):
|
|
if self.body is not None:
|
|
body = '\n'
|
|
body += '\t' + self.body if self.body else self.body
|
|
else:
|
|
body = ''
|
|
return 'function %s(%s) {%s\n}' % (
|
|
self.f_name,
|
|
', '.join(self.arguments),
|
|
body)
|
|
|
|
def _apply(self, this_arg, arg_array):
|
|
return 'function apply'
|
|
|
|
def _call(self, this_arg, *args):
|
|
return 'function call'
|
|
|
|
def _bind(self, this_arg, *args):
|
|
return 'function bind'
|
|
|
|
jsclass = 'Function'
|
|
own = {
|
|
'length': 0,
|
|
'constructor': _constructor,
|
|
'toString': _to_string,
|
|
'apply': _apply,
|
|
'call': _call,
|
|
'bind': _bind
|
|
}
|
|
|
|
|
|
class JSFunction(JSObject):
|
|
|
|
@staticmethod
|
|
def call(formal_args=None):
|
|
return JSFunction.construct(formal_args)
|
|
|
|
@staticmethod
|
|
def construct(formal_args=None):
|
|
if formal_args is not None and formal_args:
|
|
body = formal_args[-1]
|
|
formal_args = []
|
|
for arg in formal_args[:-1]:
|
|
formal_args.extend(a.strip() for a in arg.split(','))
|
|
else:
|
|
body = ''
|
|
formal_args = []
|
|
return JSFunctionPrototype('anonymous', body, formal_args)
|
|
|
|
name = JSFunctionPrototype.jsclass
|
|
own = {
|
|
'length': 1,
|
|
'prototype': JSFunctionPrototype(None, None, None)
|
|
}
|