예제 #1
0
def abs_i_cmp(b: bc.Instr):
    arg: bc.Compare = b.arg
    f = cmp_map[arg]
    a2 = yield am.pop()
    a1 = yield am.pop()
    a = yield from f(a1, a2)
    yield am.push(a)
예제 #2
0
def abs_i_inplace_binary(b: bc.Instr):
    a2 = yield am.pop()
    a1 = yield am.pop()
    f = ibin_map.get(b.name, None)
    if f is None:
        raise ValueError(f"unknown binary instruction {b}")
    c = yield from f(a1, a2)
    yield am.push(c)
예제 #3
0
def pop_n(n: int):
    xs = []
    for i in range(n):
        a = yield am.pop()
        xs.append(a)
    xs.reverse()
    return xs
예제 #4
0
def abs_i_unary(b: bc.Instr):
    a = yield am.pop()
    f = u_map.get(b.name, None)
    if f is None:
        raise ValueError(f"unknown unary instruction {b}")
    a = yield from f(a)
    yield am.push(a)
예제 #5
0
def abs_i_jump(b: bc.Instr):
    label_name = label_to_name(b.arg)
    if b.name in (InstrNames.JUMP_FORWARD, InstrNames.JUMP_ABSOLUTE):
        yield am.jump(label_name)

    elif b.name == InstrNames.POP_JUMP_IF_FALSE:
        a = yield am.pop()
        a = yield from RT.py_not(a)
        yield am.jump_if(label_name, a)
    elif b.name == InstrNames.POP_JUMP_IF_TRUE:
        a = yield am.pop()
        yield am.jump_if(label_name, a)
    elif b.name == InstrNames.JUMP_IF_FALSE_OR_POP:
        a = yield am.pop()
        o = yield from RT.py_not(a)
        yield am.jump_if_push(label_name, o, a)
    elif b.name == InstrNames.JUMP_IF_TRUE_OR_POP:
        a = yield am.pop()
        yield am.jump_if_push(label_name, a, a)
    else:
        raise ValueError(f"unknown jump instruction {b}")
예제 #6
0
 def unwind():
     # python 'with' block exits with a pushed 'None'
     yield am.pop()
     yield am.pop_block()
     yield from RT.py_exit(var)
예제 #7
0
    def abs_i(self, b: t.Union[bc.Instr, bc.SetLineno]):
        current_lineno = b.lineno
        if current_lineno != self.lineno:
            self.lineno = current_lineno
            yield am.set_lineno(current_lineno)

        if b.name == InstrNames.COMPARE_OP:
            yield from abs_i_cmp(b)
        elif "JUMP" in b.name:
            yield from abs_i_jump(b)
        elif b.name.startswith('UNARY'):
            yield from abs_i_unary(b)
        elif b.name.startswith('BINARY'):
            yield from abs_i_binary(b)
        elif b.name.startswith('INPLACE'):
            yield from abs_i_inplace_binary(b)
        elif b.name == InstrNames.ROT_TWO:
            a1 = yield am.pop()
            a2 = yield am.pop()
            yield am.push(a2)
            yield am.push(a1)
        elif b.name == InstrNames.ROT_THREE:
            a1 = yield am.pop()
            a2 = yield am.pop()
            a3 = yield am.pop()
            yield am.push(a3)
            yield am.push(a1)
            yield am.push(a2)
        elif b.name == InstrNames.NOP:
            pass
        elif b.name == InstrNames.DUP_TOP:
            a = yield am.pop()
            yield am.push(a)
            yield am.push(a)
        elif b.name == InstrNames.DUP_TOP_TWO:
            a = yield am.peek(1)
            yield am.push(a)
            yield am.push(a)

        elif b.name == InstrNames.GET_YIELD_FROM_ITER:
            a = yield am.pop()
            a = yield from RT.py_iter(a)
            yield am.push(a)
        elif b.name == InstrNames.STORE_SUBSCR:
            tos = yield am.pop()
            tos1 = yield am.pop()
            tos2 = yield am.pop()
            yield from RT.py_setitem(tos1, tos, tos2)
        elif b.name == InstrNames.DELETE_SUBSCR:
            tos = yield am.pop()
            tos1 = yield am.pop()
            yield from RT.py_delitem(tos1, tos)
        elif b.name == InstrNames.PRINT_EXPR:
            tos = yield am.pop()
            yield from RT.py_printexpr(tos)
        elif b.name == InstrNames.SET_ADD:
            tos = yield am.pop()
            subj = yield am.peek(b.arg)  # TODO: check correctness
            yield from RT.py_set_add(subj, tos)
        elif b.name == InstrNames.LIST_APPEND:
            tos = yield am.pop()
            subj = yield am.peek(b.arg)
            yield from RT.py_list_append(subj, tos)
        elif b.name == InstrNames.MAP_ADD:
            tos = yield am.pop()
            tos1 = yield am.pop()
            subj = yield am.peek(b.arg)
            yield from RT.py_map_add(subj, tos, tos1)
        elif b.name == InstrNames.RETURN_VALUE:
            a = yield am.pop()
            yield am.ret(a)
        elif b.name == InstrNames.YIELD_VALUE:
            a = yield am.pop()
            yield am.yield_return(a)

        elif b.name == InstrNames.YIELD_FROM:
            a = yield am.pop()
            yield from RT.yield_from(a)
        elif b.name == InstrNames.STORE_NAME:
            assert isinstance(b.arg, str)
            raise NotImplemented
        elif b.name == InstrNames.DELETE_NAME:
            raise NotImplemented
        elif b.name == InstrNames.UNPACK_SEQUENCE:
            val = yield am.pop()
            val = yield from RT.py_to_tuple(val)
            for idx in range(b.arg):
                idx = yield am.const(idx)
                a = yield from RT.py_subscr(val, idx)
                yield am.push(a)
        elif b.name == InstrNames.UNPACK_EX:
            val = yield am.pop()
            val = yield from RT.py_to_tuple(val)
            n = yield from RT.py_len(val)
            tail = b.arg // 256
            init = b.arg % 256
            start_idx = None
            for start_idx in range(init):
                start_idx = am.const(start_idx)
                a = yield from RT.py_subscr(val, start_idx)
                yield am.push(a)

            start_idx = yield am.const(start_idx)

            tail = yield am.const(tail)
            _1 = yield am.const(1)
            end_idx = yield from RT.py_sub(n, tail)
            a = yield from RT.py_build_slice(start_idx, _1, end_idx)
            yield am.push(a)

            for end_idx in range(init):
                off = yield am.const(end_idx + 1)
                end_idx = yield from RT.py_sub(n, off)
                a = yield from RT.py_subscr(val, end_idx)
                yield am.push(a)

        elif b.name == InstrNames.FORMAT_VALUE:
            a = yield am.pop()
            if b.arg & 0x03 == 0x00:
                a = yield from RT.py_format(a)
            elif b.arg & 0x03 == 0x01:
                a = yield from RT.py_to_str(a)
                a = yield from RT.py_format(a)
            elif b.arg & 0x03 == 0x02:
                a = yield from RT.py_to_repr(a)
                a = yield from RT.py_format(a)
            elif b.arg & 0x03 == 0x03:
                a = yield from RT.py_to_ascii(a)
                a = yield from RT.py_format(a)
            elif b.arg & 0x04 == 0x04:
                a = yield from RT.py_to_ascii(a)
                a = yield from RT.py_format(a)
            else:
                raise ValueError(f"invalid format flag {b.arg}")
            yield am.push(a)
        elif b.name == InstrNames.BUILD_SLICE:
            tos = yield am.pop()
            tos1 = yield am.pop()
            tos2 = yield am.pop()
            a = yield from RT.py_build_slice(tos2, tos1, tos)
            yield am.push(a)
        elif b.name == InstrNames.LOAD_METHOD:
            a = yield am.pop()
            yield from RT.py_load_method_(a, b.arg)
        elif b.name == InstrNames.CALL_METHOD:
            xs = yield from pop_n(b.arg + 2)
            a = yield from RT.py_call_method(*xs)
            yield am.push(a)
        elif b.name == InstrNames.MAKE_FUNCTION:
            arg = b.arg
            if arg & 0x01:
                raise NotImplemented
            if arg & 0x02:
                raise NotImplemented
            if arg & 0x04:
                raise NotImplemented
            if arg & 0x08:
                name = yield am.pop()
                name = yield am.from_const(name)
                code = yield am.pop()
                code = yield am.from_const(code)
                assert isinstance(code, types.CodeType)
                closure = yield am.pop()
                fpr = yield from RT.py_mk_func(name, code)
                a = yield from RT.py_mk_closure(closure, fpr)

            else:
                name = yield am.pop()
                name = yield am.from_const(name)
                code = yield am.pop()
                code = yield am.from_const(code)
                assert isinstance(code, types.CodeType)
                a = yield from RT.py_mk_func(name, code)
            yield am.push(a)

        elif b.name == InstrNames.CALL_FUNCTION:
            c = b.arg
            xs = yield from pop_n(c)
            f = yield am.pop()
            a = yield from RT.py_call_func(f, *xs)
            yield am.push(a)

        elif b.name == InstrNames.LOAD_CLOSURE:
            arg = b.arg
            assert isinstance(arg, (bc.CellVar, bc.FreeVar))
            a = yield am.reg_of(arg.name)
            yield am.push(a)

        elif b.name == InstrNames.LOAD_DEREF:
            arg = b.arg
            assert isinstance(arg, (bc.CellVar, bc.FreeVar))
            a = yield am.load(arg.name)
            yield am.push(a)

        elif b.name == InstrNames.STORE_DEREF:
            arg = b.arg
            assert isinstance(arg, (bc.CellVar, bc.FreeVar))

            a = yield am.pop()
            yield am.store(arg.name, a)

        elif b.name == InstrNames.LOAD_FAST:
            assert isinstance(b.arg, str)
            reg = yield am.reg_of(b.arg)
            yield am.push(reg)

        elif b.name == InstrNames.STORE_FAST:
            assert isinstance(b.arg, str)
            v = yield am.pop()
            yield am.assign(b.arg, v)

        elif b.name == InstrNames.LOAD_GLOBAL:
            arg = b.arg
            assert isinstance(arg, str)
            yield am.require_global(arg)
            a = yield am.from_higher("", arg)
            yield am.push(a)

        elif b.name == InstrNames.STORE_GLOBAL:
            yield am.require_global(b.arg)
            raise NotImplemented

        elif b.name == InstrNames.LOAD_CONST:
            arg = b.arg
            a = yield am.const(arg)
            yield am.push(a)

        elif b.name == InstrNames.STORE_ATTR:
            tos = yield am.pop()
            val = yield am.pop()
            yield from RT.py_store_attr(tos, val, b.arg)

        elif b.name == InstrNames.LOAD_ATTR:
            tos = yield am.pop()
            a = yield from RT.py_get_attr(tos, b.arg)
            yield am.push(a)

        elif b.name == InstrNames.DELETE_ATTR:
            tos = yield am.pop()
            yield from RT.py_del_attr(tos, b.arg)

        elif b.name == InstrNames.BUILD_TUPLE:
            xs = yield from pop_n(b.arg)
            a = yield from RT.py_mk_tuple(xs)
            yield am.push(a)

        elif b.name == InstrNames.BUILD_LIST:
            xs = yield from pop_n(b.arg)
            a = yield from RT.py_mk_list(xs)
            yield am.push(a)

        elif b.name == InstrNames.BUILD_SET:
            xs = yield from pop_n(b.arg)
            a = yield from RT.py_mk_set(xs)
            yield am.push(a)

        elif b.name == InstrNames.BUILD_MAP:
            xs = yield from pop_n(2 * b.arg)
            ks = xs[::2]
            vs = xs[1::2]
            ks = yield from RT.py_mk_tuple(ks)
            vs = yield from RT.py_mk_tuple(vs)
            a = yield from RT.py_mk_map(ks, vs)
            yield am.push(a)

        elif b.name == InstrNames.BUILD_CONST_KEY_MAP:
            ks = yield am.pop()
            vs = yield from pop_n(b.arg)
            vs = yield from RT.py_mk_tuple(vs)
            a = yield from RT.py_mk_map(ks, vs)
            yield a.push(a)

        elif b.name == InstrNames.BUILD_STRING:
            xs = yield from pop_n(b.arg)
            a = yield from RT.py_cat_strs(xs)
            yield am.push(a)

        elif b.name == InstrNames.FOR_ITER:
            f = yield am.pop()
            a = yield from RT.py_call_func(f)
            label = b.arg
            assert isinstance(label, bc.BasicBlock)
            check_if_nothing = yield from RT.py_is_none(a)
            yield am.jump_if(label_to_name(label), check_if_nothing)
            _0 = yield am.const(0)
            _1 = yield am.const(1)
            elt = yield from RT.py_subscr(a, _0)
            st = yield from RT.py_subscr(a, _1)
            yield am.push(st)
            yield am.push(elt)

        elif b.name == InstrNames.GET_ITER:
            a = yield am.pop()
            a = yield from RT.py_get_no_exception_iter(a)
            yield am.push(a)

        elif b.name == InstrNames.SETUP_LOOP:
            pass
        elif b.name == InstrNames.POP_BLOCK:
            pass
        elif b.name == InstrNames.POP_TOP:
            yield am.pop()
        elif b.name == InstrNames.SETUP_WITH:
            arg = b.arg
            assert isinstance(arg, bc.BasicBlock)
            end_label = label_to_name(arg)
            meta = yield am.meta()
            var = yield am.pop()

            def unwind():
                # python 'with' block exits with a pushed 'None'
                yield am.pop()
                yield am.pop_block()
                yield from RT.py_exit(var)

            meta[end_label] = unwind
            entered = yield from RT.py_enter(var)
            yield am.push(entered)
            yield am.push_block(end_label)
        elif b.name == InstrNames.END_FINALLY:
            exc = yield am.pop_exception()
            label_no_ext = yield am.alloc()
            py_none = yield from RT.py_none()
            exc_is_none = yield from RT.py_is(py_none, exc)
            yield am.jump_if(label_no_ext, exc_is_none)
            yield from RT.py_throw(exc)
            yield am.label(label_no_ext)

        elif b.name == InstrNames.SETUP_FINALLY:
            arg = b.arg
            assert isinstance(arg, bc.BasicBlock)
            end_label = label_to_name(arg)
            meta = yield am.meta()

            def unwind():
                yield am.pop_block()

            meta[end_label] = unwind
            yield am.push_block(end_label)
        elif b.name == InstrNames.SETUP_EXCEPT:
            arg = b.arg
            assert isinstance(arg, bc.BasicBlock)
            end_label = label_to_name(arg)
            meta = yield am.meta()

            def unwind():
                yield am.pop_block()
                exc = yield am.pop_exception(must=True)
                py_none = yield from RT.py_none()
                yield am.push(py_none)
                yield am.push(exc)
                yield am.push(py_none)

            meta[end_label] = unwind
            yield am.push_block(end_label)
        elif b.name in (InstrNames.WITH_CLEANUP_FINISH,
                        InstrNames.WITH_CLEANUP_START, InstrNames.POP_EXCEPT):
            pass
        elif b.name == InstrNames.RAISE_VARARGS:
            c = b.arg
            if c is not 1:
                raise ValueError(
                    "Raise statement must take 1 argument due to the limitations of current implementation."
                )
            err = yield am.pop()
            yield from RT.py_throw(err)
        else:
            raise NotImplementedError(f"instruction {b} not supported yet")