Exemple #1
0
def RAISE_VARARGS(ctx: _VSContext, instruction: dis.Instruction):
    """
    Raises an exception to either the current scope or the outer scope.
    """
    # This is relatively simple.
    # We ignore the argc == 3, and pretend it's argc == 2
    argc = instruction.arg
    if argc == 3:
        # f**k you
        ctx.pop()
        argc = 2

    if argc == 2:
        # FROM exception is Top of stack now.
        fr = ctx.pop()
        # The real exception is top of stack now.
        exc = ctx.pop()
        exc.__cause__ = fr

    elif argc == 1:
        exc = ctx.pop()
    else:
        # Bare raise.
        exc = ctx._exception_state

    # Inject the exception.
    safe_raise(ctx, exc)
    # Raise the exception.

    return exc
Exemple #2
0
def DUP_TOP(ctx: _VSContext, instruction: dis.Instruction):
    """
    Duplicates the top-most item on the stack.
    """
    item = ctx.pop()
    ctx.push(item)
    ctx.push(item)
    return ctx
Exemple #3
0
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
Exemple #4
0
def POP_JUMP_IF_FALSE(ctx: _VSContext, instruction: dis.Instruction):
    """
    Jumps to the specified instruction if False-y is on the top of the stack.
    """
    i = ctx.pop()
    if i:
        # Truthy, don't jump.
        return ctx

    # Jump!
    ctx.instruction_pointer = get_instruction_index_by_offset(ctx, instruction)

    return ctx
Exemple #5
0
def LOAD_FAST(ctx: _VSContext, instruction: dis.Instruction):
    """
    Loads from VARNAMES.
    """
    item = ctx.varnames[instruction.arg]
    if item == NO_RESULT:
        safe_raise(
            ctx,
            NameError("name '{}' is not defined".format(
                ctx.co_varnames[instruction.arg])))
        return ctx
    ctx.push(item)
    return ctx
Exemple #6
0
def POP_JUMP_IF_TRUE(ctx: _VSContext, instruction: dis.Instruction):
    """
    Jumps to the specified instruction if True-y is on the top of the stack.
    """

    i = ctx.pop()
    if not i:
        # Falsey, stay where we are.
        return ctx

    # Jump, again.
    ctx.instruction_pointer = get_instruction_index_by_offset(ctx, instruction)

    return ctx
Exemple #7
0
def LOAD_GLOBAL(ctx: _VSContext, instruction: dis.Instruction):
    """
    Loads a global from `ctx.__globals__`.
    """
    name = ctx.co_names[instruction.arg]
    try:
        item = ctx.get_global(name)
    except KeyError:
        # todo: safe_raise
        return safe_raise(ctx,
                          NameError("name '{}' is not defined".format(name)))

    ctx.push(item)
    return ctx
Exemple #8
0
def JUMP_FORWARD(ctx: _VSContext, instruction: dis.Instruction):
    """
    Jumps forward to the specified instruction.
    """
    ctx.instruction_pointer = get_instruction_index_by_offset(ctx, instruction)

    return ctx
Exemple #9
0
def safe_raise(ctx: _VSContext, exception: BaseException):
    """
    Attempts to "safely" raise an exception into the context.

    If the exception is being handled by a `try` block, it will automatically move the pointer to the Except block
    that is consistent with it.

    Otherwise, it will attempt to bubble it out of the stack.
    :param ctx: The context to raise into.
    :param exception: The exception to raise.
    :return: The context.
    """
    # Create a traceback for this exception.
    exception._tb = create_traceback(ctx)
    # Inject the exception.
    ctx.inject_exception(exception)
    return ctx
Exemple #10
0
def SETUP_EXCEPT(ctx: _VSContext, instruction: dis.Instruction):
    """
    Sets a context up for an except.
    """
    # Update the exception pointer with the calculated offset.
    # This is where we will jump to if an error is encountered.
    ctx.exc_next_pointer = get_instruction_index_by_offset(ctx, instruction)

    return ctx
Exemple #11
0
def POP_EXCEPT(ctx: _VSContext, instruction: dis.Instruction):
    """
    Pops an except block.
    """
    # Here, we can make several assumptions:
    # 1) The exception has been handled.
    # 2) We can empty the exception state.
    # 3) The function can continue on as normal.

    # This means the exception state is cleared, handling_exception is removed, and it is safe to jump forward as
    # appropriate.
    ctx._exception_state = None
    ctx._handling_exception = False

    # Also, remove the exception pointer.
    # That way, it won't try to safely handle an exception that happens later on.
    ctx.exc_next_pointer = None

    return ctx
Exemple #12
0
def COMPARE_OP(ctx: _VSContext, instruction: dis.Instruction):
    """
    Implements comparison operators.
    """
    # TODO: Rewrite COMPARE_OP into Vanstein-ran function calls.
    # TODO: Add all of the comparison functions.
    if instruction.arg == 10:
        # Pop the too match off.
        to_match = ctx.pop()
        # This is what we check.
        raised = ctx.pop()

        from collections import Iterable

        if not isinstance(to_match, Iterable):
            to_match = (to_match, )

        for e in to_match:
            # PyType_IsSubType
            if issubclass(type(raised), e):
                ctx.push(True)
                break
        else:
            ctx.push(False)

    return ctx
Exemple #13
0
    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)
Exemple #14
0
def STORE_NAME(ctx: _VSContext, instruction: dis.Instruction):
    ctx.names[instruction.arg] = ctx.pop()
    return ctx
Exemple #15
0
def STORE_FAST(ctx: _VSContext, instruction: dis.Instruction):
    """
    Stores data in co_varnames.
    """
    ctx.varnames[instruction.arg] = ctx.pop()
    return ctx
Exemple #16
0
def POP_TOP(ctx: _VSContext, instruction: dis.Instruction):
    """
    Pops off the top of the stack.
    """
    ctx.pop()
    return ctx
Exemple #17
0
def LOAD_CONST(ctx: _VSContext, instruction: dis.Instruction):
    """
    Loads a const from `ctx.co_consts`.
    """
    ctx.push(ctx.co_consts[instruction.arg])
    return ctx