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 import prototypes.jsjson as jsjson import prototypes.jsutils as jsutils from constructors import jsnumber from constructors import jsstring from constructors import jsarray from constructors import jsboolean from constructors import jsregexp from constructors import jsmath from constructors import jsobject from constructors import jsfunction from constructors import 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) j.prototype = space.ERROR_TYPES[typ] 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)