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