from ..base import * from ..conversions import * from ..func_utils import * from pyjsparser import parse from ..byte_trans import ByteCodeGenerator, Code def Function(this, args): # convert arguments to python list of strings a = list(map(to_string, tuple(args))) _body = u';' _args = () if len(a): _body = u'%s;' % a[-1] _args = a[:-1] return executable_function(_body, _args, args.space, global_context=True) def executable_function(_body, _args, space, global_context=True): func_str = u'(function (%s) { ; %s ; });' % (u', '.join(_args), _body) co = executable_code( code_str=func_str, space=space, global_context=global_context) return co() # 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. # todo tape cleanup? we dont know which pieces are needed and which are not so rather impossible without smarter machinery something like GC, # a one solution would be to have a separate tape for functions def executable_code(code_str, space, global_context=True): # parse first to check if any SyntaxErrors parsed = parse(code_str) old_tape_len = len(space.byte_generator.exe.tape) space.byte_generator.record_state() start = space.byte_generator.exe.get_new_label() skip = space.byte_generator.exe.get_new_label() space.byte_generator.emit('JUMP', skip) space.byte_generator.emit('LABEL', start) space.byte_generator.emit(parsed) space.byte_generator.emit('NOP') space.byte_generator.emit('LABEL', skip) space.byte_generator.emit('NOP') space.byte_generator.restore_state() space.byte_generator.exe.compile( start_loc=old_tape_len ) # dont read the code from the beginning, dont be stupid! ctx = space.GlobalObj if global_context else space.exe.current_ctx def ex_code(): ret, status, token = space.byte_generator.exe.execute_fragment_under_context( ctx, start, skip) # todo Clean up the tape! # this is NOT a way to do that because the fragment may contain the executable code! We dont want to remove it #del space.byte_generator.exe.tape[old_tape_len:] if status == 0: return ret elif status == 3: raise token else: raise RuntimeError( 'Unexpected return status during JIT execution: %d' % status) return ex_code def _eval(this, args): code_str = to_string(get_arg(args, 0)) return executable_code(code_str, args.space, global_context=True)() def log(this, args): print(' '.join(map(to_string, args))) return undefined