def RETURN_VALUE(ctx: _VSContext, instruction: dis.Instruction): """ Returns a value. This will set the state of the context. """ ctx._result = ctx.pop() ctx.state = VSCtxState.FINISHED ctx._handling_exception = False return ctx
def run_context(self, context: _VSContext) -> _VSContext: """ Runs the current bytecode for a context. This will instructions off of the instruction stack, until it reaches a context switch. """ # Welcome to the main bulk of Vanstein. # Enjoy your stay! # Switch to running state for this context. context.state = VSCtxState.RUNNING self.current_context = context while True: if context.state is VSCtxState.FINISHED: # Done after a successful RETURN_VALUE. # Break the loop, and return the context. context.finish() return context if context.state is VSCtxState.ERRORED: return context next_instruction = context.next_instruction() self.current_instruction = next_instruction # First, we check if we need to context switch. # Check if it's CALL_FUNCTION. if next_instruction.opname == "CALL_FUNCTION": # This is the instruction for CALL_FUNCTION. No specialized one exists in the instructions.py file. # We need to context switch, so suspend this current one. context.state = VSCtxState.SUSPENDED # Get STACK[-arg] # CALL_FUNCTION(arg) => arg is number of positional arguments to use, so pop that off of the stack. bottom_of_stack = context.stack[-(next_instruction.arg + 1)] # method wrappers die if type(bottom_of_stack) is type: bottom_of_stack = bottom_of_stack.__new__ # Here's some context switching. # First, check if it's a builtin or is a native invoke. # Also, check if we should even do context switching. if inspect.isbuiltin(bottom_of_stack) or hasattr(bottom_of_stack, "_native_invoke")\ or self.do_context_switching is False: # Run it! result = self.__run_natively(context, next_instruction) # Set the result on the context. context.state = VSCtxState.RUNNING # Push the result onto the stack. context.push(result) # Continue the loop to the next instruction. continue if isinstance(bottom_of_stack, VSWrappedFunction): # Call the VSWrappedFunction to get a new context. # We'll manually fill these args. new_ctx = bottom_of_stack() else: # Wrap the function in a context. new_ctx = _VSContext(bottom_of_stack) # Set the previous context, for stack frame chaining. new_ctx.prev_ctx = context # Doubly linked list! context.next_ctx = new_ctx # Set the new state to PENDING so it knows to run it on the next run. new_ctx.state = VSCtxState.PENDING # Add a callback to the new context. # This is so the loop can schedule execution of the new context soon. new_ctx.add_done_callback(context._on_result_cb) new_ctx.add_exception_callback(context._on_exception_cb) # Fill the number of arguments the function call requests. args = [] for _ in range(0, next_instruction.arg): args.append(context.pop()) args = reversed(args) new_ctx.fill_args(*args) # Pop the function object off, too. context.pop() return new_ctx # Else, we run the respective instruction. try: i = getattr(instructions, next_instruction.opname) except AttributeError: raise NotImplementedError(next_instruction.opname) # Call the instruction handler. i(context, next_instruction)