bazarr/libs/js2py/internals/fill_space.py

282 lines
8.8 KiB
Python

from __future__ import unicode_literals
from .base import Scope
from .func_utils import *
from .conversions import *
import six
from .prototypes.jsboolean import BooleanPrototype
from .prototypes.jserror import ErrorPrototype
from .prototypes.jsfunction import FunctionPrototype
from .prototypes.jsnumber import NumberPrototype
from .prototypes.jsobject import ObjectPrototype
from .prototypes.jsregexp import RegExpPrototype
from .prototypes.jsstring import StringPrototype
from .prototypes.jsarray import ArrayPrototype
from .prototypes import jsjson
from .prototypes import jsutils
from .constructors import jsnumber, jsstring, jsarray, jsboolean, jsregexp, jsmath, jsobject, jsfunction, jsconsole
def fill_proto(proto, proto_class, space):
for i in dir(proto_class):
e = getattr(proto_class, i)
if six.PY2:
if hasattr(e, '__func__'):
meth = e.__func__
else:
continue
else:
if hasattr(e, '__call__') and not i.startswith('__'):
meth = e
else:
continue
meth_name = meth.__name__.strip('_') # RexExp._exec -> RegExp.exec
js_meth = space.NewFunction(meth, space.ctx, (), meth_name, False, ())
set_non_enumerable(proto, meth_name, js_meth)
return proto
def easy_func(f, space):
return space.NewFunction(f, space.ctx, (), f.__name__, False, ())
def Empty(this, args):
return undefined
def set_non_enumerable(obj, name, prop):
obj.define_own_property(
unicode(name), {
'value': prop,
'writable': True,
'enumerable': False,
'configurable': True
}, True)
def set_protected(obj, name, prop):
obj.define_own_property(
unicode(name), {
'value': prop,
'writable': False,
'enumerable': False,
'configurable': False
}, True)
def fill_space(space, byte_generator):
# set global scope
global_scope = Scope({}, space, parent=None)
global_scope.THIS_BINDING = global_scope
global_scope.registers(byte_generator.declared_vars)
space.GlobalObj = global_scope
space.byte_generator = byte_generator
# first init all protos, later take care of constructors and details
# Function must be first obviously, we have to use a small trick to do that...
function_proto = space.NewFunction(Empty, space.ctx, (), 'Empty', False,
())
space.FunctionPrototype = function_proto # this will fill the prototypes of the methods!
fill_proto(function_proto, FunctionPrototype, space)
# Object next
object_proto = space.NewObject() # no proto
fill_proto(object_proto, ObjectPrototype, space)
space.ObjectPrototype = object_proto
function_proto.prototype = object_proto
# Number
number_proto = space.NewObject()
number_proto.prototype = object_proto
fill_proto(number_proto, NumberPrototype, space)
number_proto.value = 0.
number_proto.Class = 'Number'
space.NumberPrototype = number_proto
# String
string_proto = space.NewObject()
string_proto.prototype = object_proto
fill_proto(string_proto, StringPrototype, space)
string_proto.value = u''
string_proto.Class = 'String'
space.StringPrototype = string_proto
# Boolean
boolean_proto = space.NewObject()
boolean_proto.prototype = object_proto
fill_proto(boolean_proto, BooleanPrototype, space)
boolean_proto.value = False
boolean_proto.Class = 'Boolean'
space.BooleanPrototype = boolean_proto
# Array
array_proto = space.NewArray(0)
array_proto.prototype = object_proto
fill_proto(array_proto, ArrayPrototype, space)
space.ArrayPrototype = array_proto
# JSON
json = space.NewObject()
json.put(u'stringify', easy_func(jsjson.stringify, space))
json.put(u'parse', easy_func(jsjson.parse, space))
# Utils
parseFloat = easy_func(jsutils.parseFloat, space)
parseInt = easy_func(jsutils.parseInt, space)
isNaN = easy_func(jsutils.isNaN, space)
isFinite = easy_func(jsutils.isFinite, space)
# Error
error_proto = space.NewError(u'Error', u'')
error_proto.prototype = object_proto
error_proto.put(u'name', u'Error')
fill_proto(error_proto, ErrorPrototype, space)
space.ErrorPrototype = error_proto
def construct_constructor(typ):
def creator(this, args):
message = get_arg(args, 0)
if not is_undefined(message):
msg = to_string(message)
else:
msg = u''
return space.NewError(typ, msg)
j = easy_func(creator, space)
j.name = unicode(typ)
set_protected(j, 'prototype', space.ERROR_TYPES[typ])
set_non_enumerable(space.ERROR_TYPES[typ], 'constructor', j)
def new_create(args, space):
message = get_arg(args, 0)
if not is_undefined(message):
msg = to_string(message)
else:
msg = u''
return space.NewError(typ, msg)
j.create = new_create
return j
# fill remaining error types
error_constructors = {}
for err_type_name in (u'Error', u'EvalError', u'RangeError',
u'ReferenceError', u'SyntaxError', u'TypeError',
u'URIError'):
extra_err = space.NewError(u'Error', u'')
extra_err.put(u'name', err_type_name)
setattr(space, err_type_name + u'Prototype', extra_err)
error_constructors[err_type_name] = construct_constructor(
err_type_name)
assert space.TypeErrorPrototype is not None
# RegExp
regexp_proto = space.NewRegExp(u'(?:)', u'')
regexp_proto.prototype = object_proto
fill_proto(regexp_proto, RegExpPrototype, space)
space.RegExpPrototype = regexp_proto
# Json
# now all these boring constructors...
# Number
number = easy_func(jsnumber.Number, space)
space.Number = number
number.create = jsnumber.NumberConstructor
set_non_enumerable(number_proto, 'constructor', number)
set_protected(number, 'prototype', number_proto)
# number has some extra constants
for k, v in jsnumber.CONSTS.items():
set_protected(number, k, v)
# String
string = easy_func(jsstring.String, space)
space.String = string
string.create = jsstring.StringConstructor
set_non_enumerable(string_proto, 'constructor', string)
set_protected(string, 'prototype', string_proto)
# string has an extra function
set_non_enumerable(string, 'fromCharCode',
easy_func(jsstring.fromCharCode, space))
# Boolean
boolean = easy_func(jsboolean.Boolean, space)
space.Boolean = boolean
boolean.create = jsboolean.BooleanConstructor
set_non_enumerable(boolean_proto, 'constructor', boolean)
set_protected(boolean, 'prototype', boolean_proto)
# Array
array = easy_func(jsarray.Array, space)
space.Array = array
array.create = jsarray.ArrayConstructor
set_non_enumerable(array_proto, 'constructor', array)
set_protected(array, 'prototype', array_proto)
array.put(u'isArray', easy_func(jsarray.isArray, space))
# RegExp
regexp = easy_func(jsregexp.RegExp, space)
space.RegExp = regexp
regexp.create = jsregexp.RegExpCreate
set_non_enumerable(regexp_proto, 'constructor', regexp)
set_protected(regexp, 'prototype', regexp_proto)
# Object
_object = easy_func(jsobject.Object, space)
space.Object = _object
_object.create = jsobject.ObjectCreate
set_non_enumerable(object_proto, 'constructor', _object)
set_protected(_object, 'prototype', object_proto)
fill_proto(_object, jsobject.ObjectMethods, space)
# Function
function = easy_func(jsfunction.Function, space)
space.Function = function
# Math
math = space.NewObject()
math.Class = 'Math'
fill_proto(math, jsmath.MathFunctions, space)
for k, v in jsmath.CONSTANTS.items():
set_protected(math, k, v)
console = space.NewObject()
fill_proto(console, jsconsole.ConsoleMethods, space)
# set global object
builtins = {
'String': string,
'Number': number,
'Boolean': boolean,
'RegExp': regexp,
'exports': convert_to_js_type({}, space),
'Math': math,
#'Date',
'Object': _object,
'Function': function,
'JSON': json,
'Array': array,
'parseFloat': parseFloat,
'parseInt': parseInt,
'isFinite': isFinite,
'isNaN': isNaN,
'eval': easy_func(jsfunction._eval, space),
'console': console,
'log': console.get(u'log'),
}
builtins.update(error_constructors)
set_protected(global_scope, 'NaN', NaN)
set_protected(global_scope, 'Infinity', Infinity)
for k, v in builtins.items():
set_non_enumerable(global_scope, k, v)