You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
282 lines
8.8 KiB
282 lines
8.8 KiB
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)
|