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)