def _make_function(self, instr): """ Functions should have strict names. """ yield instructions.LOAD_CONST(strict).steal(instr) # TOS = strict # TOS1 = func_name yield instructions.ROT_TWO() # TOS = func_name # TOS1 = strict yield instructions.CALL_FUNCTION(1) # TOS = strict(func_name) yield instr # TOS = new_function yield instructions.LOAD_CONST(thunk_type.fromexpr) # TOS thunk_type.fromexpr # TOS1 new_function yield instructions.ROT_TWO() # TOS new_function # TOS1 thunk_type.fromexpr yield instructions.CALL_FUNCTION(1)
def visit_STORE_MAP(self, instr): # TOS = k # TOS1 = v # TOS2 = m # TOS3 = m yield instructions.ROT_THREE().steal(instr) # TOS = v # TOS1 = m # TOS2 = k # TOS3 = m yield instructions.ROT_THREE() # TOS = m # TOS1 = k # TOS2 = v # TOS3 = m yield instructions.ROT_TWO() # TOS = k # TOS1 = m # TOS2 = v # TOS3 = m yield instructions.STORE_SUBSCR()
def _store_map(self, instr): # TOS = k # TOS1 = v # TOS2 = m # TOS3 = m yield instructions.ROT_THREE().steal(instr) # TOS = v # TOS1 = m # TOS2 = k # TOS3 = m yield instructions.ROT_THREE() # TOS = m # TOS1 = k # TOS2 = v # TOS3 = m yield instructions.ROT_TWO() # TOS = k # TOS1 = m # TOS2 = v # TOS3 = m yield instructions.STORE_SUBSCR()
def _start_comprehension(self, instr, *instrs): yield instructions.LOAD_CONST(self.astype).steal(instr) # TOS = self.astype yield instructions.CALL_FUNCTION(0) # TOS = m = self.astype() yield instructions.STORE_FAST('__map__') body, map_add = instrs[:-1], instrs[-1] for item in self.patterndispatcher(body): yield item # TOS = k # TOS1 = v yield instructions.LOAD_FAST('__map__').steal(map_add) # TOS = __map__ # TOS1 = k # TOS2 = v yield instructions.ROT_TWO() # TOS = k # TOS1 = __map__ # TOS2 = v yield instructions.STORE_SUBSCR() self.begin(IN_COMPREHENSION)
def _build_list(self, instr): if instr.arg == 0: yield instrs.LOAD_CONST(jl.jlist).steal(instr) yield instrs.CALL_FUNCTION(0) elif instr.arg == 1: yield instrs.LOAD_CONST(jl.jlist._from_starargs).steal(instr) yield instrs.ROT_TWO() yield instrs.CALL_FUNCTION(1) elif instr.arg == 2: yield instrs.LOAD_CONST(jl.jlist._from_starargs).steal(instr) yield instrs.ROT_THREE() yield instrs.CALL_FUNCTION(2) else: yield instr yield instrs.LOAD_CONST(jl.jlist) yield instrs.ROT_TWO() yield instrs.CALL_FUNCTION(1)
def py_call(): start = instructions.BUILD_LIST(0) # validate that nargs is >= 0 to avoid infinite loop yield instructions.DUP_TOP() yield instructions.LOAD_CONST(0) yield instructions.COMPARE_OP.LT yield instructions.POP_JUMP_IF_FALSE(start) yield instructions.LOAD_CONST('nargs must be >= 0; got %s') yield instructions.ROT_TWO() yield instructions.BINARY_MODULO() yield instructions.LOAD_CONST(ValueError) yield instructions.ROT_TWO() yield instructions.CALL_FUNCTION(1) yield instructions.RAISE_VARARGS(1) # create a list to hold the function and arguments; append the function # first yield start yield from _nrot() yield instructions.LIST_APPEND(1) yield instructions.STORE_FAST('tmp') # use the nargs as a counter; append elements until nargs == 0 loop = instructions.DUP_TOP() yield loop yield instructions.LOAD_CONST(0) yield instructions.COMPARE_OP.EQ call_impl = instructions.POP_TOP() yield instructions.POP_JUMP_IF_TRUE(call_impl) yield instructions.LOAD_CONST(1) yield instructions.BINARY_SUBTRACT() yield instructions.LOAD_FAST('tmp') yield from _nrot() yield instructions.LIST_APPEND(1) yield instructions.POP_TOP() yield instructions.JUMP_ABSOLUTE(loop) # *unpack the argument list into `py_call_impl` yield call_impl yield instructions.LOAD_CONST(py_call_impl) yield instructions.LOAD_FAST('tmp') yield instructions.CALL_FUNCTION_VAR(0) yield next_instruction()
def _tail(): for _ in range(memory - len(list(_sparse_args(instrs))) - 15): yield instructions.NOP() yield handle_exception_instr yield from _nip() yield instructions.LOAD_CONST(handle_exception) yield instructions.ROT_TWO() yield instructions.CALL_FUNCTION(1) yield instructions.POP_TOP() yield instructions.POP_EXCEPT() yield instructions.JUMP_ABSOLUTE(setup_except_instr)
def _build(self, instr): yield instr # TOS = new_list yield instructions.LOAD_CONST(self.xform) # TOS = astype # TOS1 = new_list yield instructions.ROT_TWO() # TOS = new_list # TOS1 = astype yield instructions.CALL_FUNCTION(1)
def _unary_not(self, instr): """ Replace the `not` operator to act on the values that the thunks. represent. This makes `not` lazy. """ yield instructions.LOAD_CONST(_lazy_not).steal(instr) # TOS = _lazy_not # TOS1 = arg yield instructions.ROT_TWO() # TOS = arg # TOS1 = _lazy_not yield instructions.CALL_FUNCTION(1)
def _return_value(self, instr): # TOS = collection yield instructions.LOAD_CONST(self.xform).steal(instr) # TOS = self.xform # TOS1 = collection yield instructions.ROT_TWO() # TOS = collection # TOS1 = self.xform yield instructions.CALL_FUNCTION(1) # TOS = self.xform(collection) yield instr
def pushcfa(): yield instructions.DUP_TOP() yield instructions.LOAD_CONST(Word) yield instructions.LOAD_CONST(isinstance) yield instructions.ROT_THREE() yield instructions.CALL_FUNCTION(2) not_word_instr = instructions.LOAD_CONST(NotAWord) yield instructions.POP_JUMP_IF_FALSE(not_word_instr) yield instructions.LOAD_ATTR('addr') yield next_instruction() yield not_word_instr yield instructions.ROT_TWO() yield instructions.CALL_FUNCTION(1) yield instructions.RAISE_VARARGS(1)
def build_seq(self, instr): # TOS v_0 # ... # TOSn v_n yield instructions.BUILD_TUPLE(instr.arg).steal(instr) # TOS (v_0, ..., v_n) yield instructions.LOAD_CONST(partial(thunk_type, type_)) # TOS partial(thunk_type, type_) # TOS1 (v_0, ..., v_n) yield instructions.ROT_TWO() # TOS (v_0, ..., v_n) # TOS1 partial(thunk_type, type_) yield instructions.CALL_FUNCTION(1)
def _build_map(self, instr): # TOS k_0 # TOS1 v_0 # ... # TOSn k_n # TOSm v_n yield instr # TOS dict_ yield instructions.LOAD_CONST(partial(thunk_type, dict), ) # TOS partial(thunk_type, dict) # TOS1 dict_ yield instructions.ROT_TWO() # TOS dict_ # TOS1 partial(thunk_type, dict) yield instructions.CALL_FUNCTION_KW(0)
def _build_map(self, instr): # TOS = vn # TOS1 = kn # ... # TOSN = v0 # TOSN + 1 = k0 # Construct a tuple of (k0, v0, k1, v1, ..., kn, vn) for # each of the key: value pairs in the dictionary. yield instructions.BUILD_TUPLE(instr.arg * 2).steal(instr) # TOS = (k0, v0, k1, v1, ..., kn, vn) yield instructions.LOAD_CONST(self._construct_map) # TOS = self._construct_map # TOS1 = (k0, v0, k1, v1, ..., kn, vn) yield instructions.ROT_TWO() # TOS = (k0, v0, k1, v1, ..., kn, vn) # TOS1 = self._construct_map yield instructions.CALL_FUNCTION(1)
def quote(): yield instructions.LOAD_CONST(push_return_addr) yield instructions.CALL_FUNCTION() yield instructions.POP_TOP() yield instructions.JUMP_ABSOLUTE(word_instrs['word'][0]) # We need to duplicate the word on the stack for proper error handling # later. # We dup it once giving us 2 copies on the stack for: # find # unknown word error yield instructions.DUP_TOP() yield instructions.LOAD_CONST(push_return_addr) yield instructions.CALL_FUNCTION(0) yield instructions.POP_TOP() yield instructions.JUMP_ABSOLUTE(word_instrs['find'][0]) yield instructions.DUP_TOP() yield instructions.LOAD_CONST(None) yield instructions.COMPARE_OP.IS unknown_word_instr = instructions.POP_TOP() yield instructions.POP_JUMP_IF_TRUE(unknown_word_instr) # clear the word strings from the stack yield from _nip() yield instructions.LOAD_CONST(push_return_addr) yield instructions.CALL_FUNCTION(0) yield instructions.POP_TOP() yield instructions.JUMP_ABSOLUTE(word_instrs['>cfa'][0]) yield next_instruction() yield instructions.POP_JUMP_IF_TRUE(unknown_word_instr) # clear the word string left for the unknown word case yield from _nip() yield next_instruction() yield unknown_word_instr yield instructions.LOAD_CONST(UnknownWord) yield instructions.ROT_TWO() yield instructions.CALL_FUNCTION(1) yield instructions.RAISE_VARARGS(1)
def inline_write_short_from_stack(): yield instructions.LOAD_CONST(comma_impl) yield instructions.ROT_TWO() yield instructions.CALL_FUNCTION(1) yield instructions.STORE_FAST('here')
def _build_list_in_comprehension(self, build_instr, load_instr): yield instrs.LOAD_CONST(jl.jlist).steal(build_instr) yield instrs.CALL_FUNCTION(0) yield instrs.DUP_TOP() yield instrs.DUP_TOP() # TOS = <jlist> # TOS1 = <jlist> # TOS2 = <jlist> yield instrs.LOAD_ATTR('append') yield instrs.STORE_FAST('.append') # TOS = <jlist> # TOS1 = <jlist> yield load_instr # TOS = .0 # TOS1 = <jlist> # TOS2 = <jlist> yield instrs.DUP_TOP() # TOS = .0 # TOS1 = .0 # TOS2 = <jlist> # TOS3 = <jlist> yield instrs.ROT_THREE() # TOS = .0 # TOS1 = <jlist> # TOS2 = .0 # TOS3 = <jlist> yield instrs.LOAD_CONST(operator.length_hint) yield instrs.ROT_TWO() yield instrs.CALL_FUNCTION(1) # TOS = <length_hint> # TOS1 = <jlist> # TOS2 = .0 # TOS3 = <jlist> yield instrs.ROT_TWO() # TOS = <jlist> # TOS1 = <length_hint> # TOS2 = .0 # TOS3 = <jlist> if sys.version_info >= (3, 7): yield instrs.LOAD_METHOD('_reserve') # TOS = <jlist._reserve> # TOS1 = <length_hint> # TOS2 = .0 # TOS3 = <jlist> yield instrs.ROT_TWO() # TOS = <length_hint> # TOS1 = <jlist._reserve> # TOS2 = .0 # TOS3 = <jlist> yield instrs.CALL_METHOD(1) # TOS = None # TOS1 = .0 # TOS3 = <jlist> else: yield instrs.LOAD_ATTR('_reserve') # TOS = <jlist._reserve> # TOS1 = <length_hint> # TOS2 = .0 # TOS3 = <jlist> yield instrs.ROT_TWO() # TOS = <length_hint> # TOS1 = <jlist._reserve> # TOS2 = .0 # TOS3 = <jlist> yield instrs.CALL_FUNCTION(1) # TOS = None # TOS1 = .0 # TOS3 = <jlist> yield instrs.POP_TOP()
def __start(*, counting_run=False): yield setup_except_instr first = instructions.LOAD_CONST(push_return_addr) yield first yield instructions.CALL_FUNCTION() yield instructions.POP_TOP() yield instructions.JUMP_ABSOLUTE(word_instrs['word'][0]) # We need to duplicate the word on the stack for proper error handling # later. # We dup it twice giving us 3 copies on the stack for: # find # literal lookup # unknown word error yield instructions.DUP_TOP() yield instructions.DUP_TOP() yield instructions.LOAD_CONST(push_return_addr) yield instructions.CALL_FUNCTION(0) yield instructions.POP_TOP() yield instructions.JUMP_ABSOLUTE(word_instrs['find'][0]) yield instructions.DUP_TOP() yield instructions.LOAD_CONST(None) yield instructions.COMPARE_OP.IS process_lit_instr = instructions.POP_TOP() yield instructions.POP_JUMP_IF_TRUE(process_lit_instr) # clear the word strings from the stack yield instructions.ROT_THREE() yield instructions.POP_TOP() yield instructions.POP_TOP() yield instructions.DUP_TOP() yield instructions.LOAD_ATTR('addr') yield instructions.LOAD_CONST(1) yield instructions.BINARY_SUBTRACT() yield instructions.LOAD_FAST('immediate') immediate_with_nip_instr = instructions.ROT_TWO() yield instructions.POP_JUMP_IF_TRUE(immediate_with_nip_instr) yield instructions.ROT_TWO() yield instructions.LOAD_ATTR('immediate') immediate_instr = instructions.LOAD_CONST(push_return_addr) yield instructions.POP_JUMP_IF_TRUE(immediate_instr) yield instructions.LOAD_CONST(push_return_addr) yield instructions.CALL_FUNCTION(0) yield instructions.POP_TOP() yield instructions.JUMP_ABSOLUTE(word_instrs[','][0]) yield instructions.JUMP_ABSOLUTE(first) yield immediate_with_nip_instr yield instructions.POP_TOP() yield immediate_instr yield instructions.CALL_FUNCTION() yield instructions.POP_TOP() yield instructions.YIELD_VALUE() # We need to add some padding so that the return adress gets # computed correctly. Maybe we should have two functions like: # push_return_jmp_addr/push_return_yield_addr to handle this. yield instructions.NOP() yield instructions.NOP() yield instructions.JUMP_ABSOLUTE(first) yield process_lit_instr yield instructions.LOAD_CONST(process_lit) yield instructions.ROT_TWO() yield instructions.CALL_FUNCTION(1) yield instructions.DUP_TOP() yield instructions.LOAD_CONST(NotImplemented) yield instructions.COMPARE_OP.IS unknown_word_instr = instructions.POP_TOP() yield instructions.POP_JUMP_IF_TRUE(unknown_word_instr) # clear the word string left for the unknown word case yield from _nip() yield instructions.LOAD_FAST('immediate') yield instructions.POP_JUMP_IF_TRUE(first) yield instructions.LOAD_CONST(append_lit) yield instructions.ROT_TWO() yield instructions.CALL_FUNCTION(1) yield from inline_write_short( None if counting_run else len(list(_sparse_args(__start(counting_run=True)))) - 1, ) yield from inline_write_short_from_stack() yield instructions.JUMP_ABSOLUTE(first) yield unknown_word_instr yield instructions.LOAD_CONST(UnknownWord) yield instructions.ROT_TWO() yield instructions.CALL_FUNCTION(1) yield instructions.RAISE_VARARGS(1) # this is the bytecode side of the literal implementation which # appears to be dead code but does get jumped to if counting_run: return yield instructions.LOAD_CONST(lit_impl) yield instructions.LOAD_CONST(pop_return_addr) yield instructions.CALL_FUNCTION(0) yield instructions.CALL_FUNCTION(1) yield instructions.UNPACK_SEQUENCE(2) yield instructions.YIELD_VALUE()
def _list_append_in_comprehension(self, instr): yield instrs.LOAD_FAST('.append').steal(instr) yield instrs.ROT_TWO() yield instrs.CALL_FUNCTION(1) yield instrs.POP_TOP()
def py_import(): yield instructions.LOAD_CONST(__import__) yield instructions.ROT_TWO() yield instructions.CALL_FUNCTION(1) yield next_instruction()
def bread(): yield instructions.LOAD_CONST(bread_impl) yield instructions.ROT_TWO() yield instructions.CALL_FUNCTION(1) yield next_instruction()
def over(): yield instructions.ROT_TWO() yield instructions.DUP_TOP() yield instructions.ROT_THREE() yield next_instruction()
def bcomma(): yield instructions.LOAD_CONST(bcomma_impl) yield instructions.ROT_TWO() yield instructions.CALL_FUNCTION(1) yield instructions.STORE_FAST('here') yield next_instruction()
def create(): yield instructions.LOAD_CONST(create_impl) yield instructions.ROT_TWO() yield instructions.CALL_FUNCTION(1) yield instructions.STORE_FAST('latest') yield next_instruction()
def _nip(): yield instructions.ROT_TWO() yield instructions.POP_TOP()
def branch(): yield instructions.LOAD_CONST(branch_impl) yield instructions.ROT_TWO() yield instructions.CALL_FUNCTION() yield instructions.YIELD_VALUE()