1from __future__ import unicode_literals
2
3from .base import Scope
4from .func_utils import *
5from .conversions import *
6import six
7from .prototypes.jsboolean import BooleanPrototype
8from .prototypes.jserror import ErrorPrototype
9from .prototypes.jsfunction import FunctionPrototype
10from .prototypes.jsnumber import NumberPrototype
11from .prototypes.jsobject import ObjectPrototype
12from .prototypes.jsregexp import RegExpPrototype
13from .prototypes.jsstring import StringPrototype
14from .prototypes.jsarray import ArrayPrototype
15from .prototypes import jsjson
16from .prototypes import jsutils
17
18from .constructors import jsnumber, jsstring, jsarray, jsboolean, jsregexp, jsmath, jsobject, jsfunction, jsconsole
19
20
21
22def fill_proto(proto, proto_class, space):
23    for i in dir(proto_class):
24        e = getattr(proto_class, i)
25        if six.PY2:
26            if hasattr(e, '__func__'):
27                meth = e.__func__
28            else:
29                continue
30        else:
31            if hasattr(e, '__call__') and not i.startswith('__'):
32                meth = e
33            else:
34                continue
35        meth_name = meth.__name__.strip('_')  # RexExp._exec -> RegExp.exec
36        js_meth = space.NewFunction(meth, space.ctx, (), meth_name, False, ())
37        set_non_enumerable(proto, meth_name, js_meth)
38    return proto
39
40
41def easy_func(f, space):
42    return space.NewFunction(f, space.ctx, (), f.__name__, False, ())
43
44
45def Empty(this, args):
46    return undefined
47
48
49def set_non_enumerable(obj, name, prop):
50    obj.define_own_property(
51        unicode(name), {
52            'value': prop,
53            'writable': True,
54            'enumerable': False,
55            'configurable': True
56        }, True)
57
58
59def set_protected(obj, name, prop):
60    obj.define_own_property(
61        unicode(name), {
62            'value': prop,
63            'writable': False,
64            'enumerable': False,
65            'configurable': False
66        }, True)
67
68
69def fill_space(space, byte_generator):
70    # set global scope
71    global_scope = Scope({}, space, parent=None)
72    global_scope.THIS_BINDING = global_scope
73    global_scope.registers(byte_generator.declared_vars)
74    space.GlobalObj = global_scope
75
76    space.byte_generator = byte_generator
77
78    # first init all protos, later take care of constructors and details
79
80    # Function must be first obviously, we have to use a small trick to do that...
81    function_proto = space.NewFunction(Empty, space.ctx, (), 'Empty', False,
82                                       ())
83    space.FunctionPrototype = function_proto  # this will fill the prototypes of the methods!
84    fill_proto(function_proto, FunctionPrototype, space)
85
86    # Object next
87    object_proto = space.NewObject()  # no proto
88    fill_proto(object_proto, ObjectPrototype, space)
89    space.ObjectPrototype = object_proto
90    function_proto.prototype = object_proto
91
92    # Number
93    number_proto = space.NewObject()
94    number_proto.prototype = object_proto
95    fill_proto(number_proto, NumberPrototype, space)
96    number_proto.value = 0.
97    number_proto.Class = 'Number'
98    space.NumberPrototype = number_proto
99
100    # String
101    string_proto = space.NewObject()
102    string_proto.prototype = object_proto
103    fill_proto(string_proto, StringPrototype, space)
104    string_proto.value = u''
105    string_proto.Class = 'String'
106    space.StringPrototype = string_proto
107
108    # Boolean
109    boolean_proto = space.NewObject()
110    boolean_proto.prototype = object_proto
111    fill_proto(boolean_proto, BooleanPrototype, space)
112    boolean_proto.value = False
113    boolean_proto.Class = 'Boolean'
114    space.BooleanPrototype = boolean_proto
115
116    # Array
117    array_proto = space.NewArray(0)
118    array_proto.prototype = object_proto
119    fill_proto(array_proto, ArrayPrototype, space)
120    space.ArrayPrototype = array_proto
121
122    # JSON
123    json = space.NewObject()
124    json.put(u'stringify', easy_func(jsjson.stringify, space))
125    json.put(u'parse', easy_func(jsjson.parse, space))
126
127    # Utils
128    parseFloat = easy_func(jsutils.parseFloat, space)
129    parseInt = easy_func(jsutils.parseInt, space)
130    isNaN = easy_func(jsutils.isNaN, space)
131    isFinite = easy_func(jsutils.isFinite, space)
132
133    # Error
134    error_proto = space.NewError(u'Error', u'')
135    error_proto.prototype = object_proto
136    error_proto.put(u'name', u'Error')
137    fill_proto(error_proto, ErrorPrototype, space)
138    space.ErrorPrototype = error_proto
139
140    def construct_constructor(typ):
141        def creator(this, args):
142            message = get_arg(args, 0)
143            if not is_undefined(message):
144                msg = to_string(message)
145            else:
146                msg = u''
147            return space.NewError(typ, msg)
148
149        j = easy_func(creator, space)
150        j.name = unicode(typ)
151
152        set_protected(j, 'prototype', space.ERROR_TYPES[typ])
153
154        set_non_enumerable(space.ERROR_TYPES[typ], 'constructor', j)
155
156        def new_create(args, space):
157            message = get_arg(args, 0)
158            if not is_undefined(message):
159                msg = to_string(message)
160            else:
161                msg = u''
162            return space.NewError(typ, msg)
163
164        j.create = new_create
165        return j
166
167    # fill remaining error types
168    error_constructors = {}
169    for err_type_name in (u'Error', u'EvalError', u'RangeError',
170                          u'ReferenceError', u'SyntaxError', u'TypeError',
171                          u'URIError'):
172        extra_err = space.NewError(u'Error', u'')
173        extra_err.put(u'name', err_type_name)
174        setattr(space, err_type_name + u'Prototype', extra_err)
175        error_constructors[err_type_name] = construct_constructor(
176            err_type_name)
177
178    assert space.TypeErrorPrototype is not None
179
180    # RegExp
181    regexp_proto = space.NewRegExp(u'(?:)', u'')
182    regexp_proto.prototype = object_proto
183    fill_proto(regexp_proto, RegExpPrototype, space)
184    space.RegExpPrototype = regexp_proto
185
186    # Json
187
188    # now all these boring constructors...
189
190    # Number
191    number = easy_func(jsnumber.Number, space)
192    space.Number = number
193    number.create = jsnumber.NumberConstructor
194    set_non_enumerable(number_proto, 'constructor', number)
195    set_protected(number, 'prototype', number_proto)
196    # number has some extra constants
197    for k, v in jsnumber.CONSTS.items():
198        set_protected(number, k, v)
199
200    # String
201    string = easy_func(jsstring.String, space)
202    space.String = string
203    string.create = jsstring.StringConstructor
204    set_non_enumerable(string_proto, 'constructor', string)
205    set_protected(string, 'prototype', string_proto)
206    # string has an extra function
207    set_non_enumerable(string, 'fromCharCode',
208                       easy_func(jsstring.fromCharCode, space))
209
210    # Boolean
211    boolean = easy_func(jsboolean.Boolean, space)
212    space.Boolean = boolean
213    boolean.create = jsboolean.BooleanConstructor
214    set_non_enumerable(boolean_proto, 'constructor', boolean)
215    set_protected(boolean, 'prototype', boolean_proto)
216
217    # Array
218    array = easy_func(jsarray.Array, space)
219    space.Array = array
220    array.create = jsarray.ArrayConstructor
221    set_non_enumerable(array_proto, 'constructor', array)
222    set_protected(array, 'prototype', array_proto)
223    array.put(u'isArray', easy_func(jsarray.isArray, space))
224
225    # RegExp
226    regexp = easy_func(jsregexp.RegExp, space)
227    space.RegExp = regexp
228    regexp.create = jsregexp.RegExpCreate
229    set_non_enumerable(regexp_proto, 'constructor', regexp)
230    set_protected(regexp, 'prototype', regexp_proto)
231
232    # Object
233    _object = easy_func(jsobject.Object, space)
234    space.Object = _object
235    _object.create = jsobject.ObjectCreate
236    set_non_enumerable(object_proto, 'constructor', _object)
237    set_protected(_object, 'prototype', object_proto)
238    fill_proto(_object, jsobject.ObjectMethods, space)
239
240    # Function
241    function = easy_func(jsfunction.Function, space)
242    space.Function = function
243
244    # Math
245    math = space.NewObject()
246    math.Class = 'Math'
247    fill_proto(math, jsmath.MathFunctions, space)
248    for k, v in jsmath.CONSTANTS.items():
249        set_protected(math, k, v)
250
251    console = space.NewObject()
252    fill_proto(console, jsconsole.ConsoleMethods, space)
253
254    # set global object
255    builtins = {
256        'String': string,
257        'Number': number,
258        'Boolean': boolean,
259        'RegExp': regexp,
260        'exports': convert_to_js_type({}, space),
261        'Math': math,
262        #'Date',
263        'Object': _object,
264        'Function': function,
265        'JSON': json,
266        'Array': array,
267        'parseFloat': parseFloat,
268        'parseInt': parseInt,
269        'isFinite': isFinite,
270        'isNaN': isNaN,
271        'eval': easy_func(jsfunction._eval, space),
272        'console': console,
273        'log': console.get(u'log'),
274    }
275
276    builtins.update(error_constructors)
277
278    set_protected(global_scope, 'NaN', NaN)
279    set_protected(global_scope, 'Infinity', Infinity)
280    for k, v in builtins.items():
281        set_non_enumerable(global_scope, k, v)
282