1from ..base import *
2from ..conversions import *
3from ..func_utils import *
4from pyjsparser import parse
5from ..byte_trans import ByteCodeGenerator, Code
6
7
8def Function(this, args):
9    # convert arguments to python list of strings
10    a = map(to_string, tuple(args))
11    _body = u';'
12    _args = ()
13    if len(a):
14        _body = u'%s;' % a[-1]
15        _args = a[:-1]
16    return executable_function(_body, _args, args.space, global_context=True)
17
18
19def executable_function(_body, _args, space, global_context=True):
20    func_str = u'(function (%s) { ; %s ; });' % (u', '.join(_args), _body)
21
22    co = executable_code(
23        code_str=func_str, space=space, global_context=global_context)
24    return co()
25
26
27# you can use this one lovely piece of function to compile and execute code on the fly! Watch out though as it may generate lots of code.
28# todo tape cleanup? we dont know which pieces are needed and which are not so rather impossible without smarter machinery something like GC,
29# a one solution would be to have a separate tape for functions
30def executable_code(code_str, space, global_context=True):
31    # parse first to check if any SyntaxErrors
32    parsed = parse(code_str)
33
34    old_tape_len = len(space.byte_generator.exe.tape)
35    space.byte_generator.record_state()
36    start = space.byte_generator.exe.get_new_label()
37    skip = space.byte_generator.exe.get_new_label()
38    space.byte_generator.emit('JUMP', skip)
39    space.byte_generator.emit('LABEL', start)
40    space.byte_generator.emit(parsed)
41    space.byte_generator.emit('NOP')
42    space.byte_generator.emit('LABEL', skip)
43    space.byte_generator.emit('NOP')
44    space.byte_generator.restore_state()
45
46    space.byte_generator.exe.compile(
47        start_loc=old_tape_len
48    )  # dont read the code from the beginning, dont be stupid!
49
50    ctx = space.GlobalObj if global_context else space.exe.current_ctx
51
52    def ex_code():
53        ret, status, token = space.byte_generator.exe.execute_fragment_under_context(
54            ctx, start, skip)
55        # todo Clean up the tape!
56        # this is NOT a way to do that because the fragment may contain the executable code! We dont want to remove it
57        #del space.byte_generator.exe.tape[old_tape_len:]
58        if status == 0:
59            return ret
60        elif status == 3:
61            raise token
62        else:
63            raise RuntimeError(
64                'Unexpected return status during JIT execution: %d' % status)
65
66    return ex_code
67
68
69def _eval(this, args):
70    code_str = to_string(get_arg(args, 0))
71    return executable_code(code_str, args.space, global_context=True)()
72
73
74def log(this, args):
75    print(' '.join(map(to_string, args)))
76    return undefined
77