Created
May 2, 2014 20:01
-
-
Save darius/d181b1e98f598e9dee94 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # (Python 2) | |
| # Developed from an example by Dave Long, but don't blame him! | |
| from dis import cmp_op, dis, hascompare, hasjabs, hasjrel, opmap, HAVE_ARGUMENT | |
| from itertools import chain | |
| import types | |
| class Clutch(object): | |
| def __init__(self, *args, **kwargs): | |
| for arg in args: setattr(self, arg.__name__, arg) | |
| self.__dict__.update(kwargs.iteritems()) | |
| # assembly objects | |
| def assemble(assembly): | |
| return ''.join(assembly.encode(0, dict(assembly.locate(0)))) | |
| class Assembly(Clutch): | |
| def __add__(self, other): return Chain(self, other) | |
| def Chain(assembly1, assembly2): | |
| def locate(start): | |
| return chain(assembly1.locate(start), | |
| assembly2.locate(start + assembly1.length)) | |
| def encode(start, addresses): | |
| return chain(assembly1.encode(start, addresses), | |
| assembly2.encode(start + assembly1.length, addresses)) | |
| return Assembly(locate, encode, | |
| length = assembly1.length + assembly2.length) | |
| def Label(tag): | |
| def locate(start): return ((tag, start),) | |
| def encode(start, addresses): return '' | |
| return Assembly(locate, encode, length = 0) | |
| def make_insn(encoded): | |
| def locate(start): return () | |
| def encode(start, addresses): return encoded | |
| return Assembly(locate, encode, length=len(encoded)) | |
| def make_jump_insn(opcode, tag): | |
| def locate(start): return () | |
| def encode(start, addresses): | |
| base = 0 if opcode in hasjabs else start+3 | |
| return insn_encode(opcode, addresses[tag] - base) | |
| return Assembly(locate, encode, length=3) | |
| def insn_encode(opcode, arg): | |
| return '%c%c%c' % (opcode, arg%256, arg//256) | |
| # Opcodes | |
| def denotation(opcode): | |
| if opcode < HAVE_ARGUMENT: | |
| return make_insn(chr(opcode)) | |
| elif opcode in hascompare: | |
| return lambda arg: make_insn(insn_encode(opcode, cmp_op.index(arg))) | |
| elif opcode in hasjrel or opcode in hasjabs: | |
| return lambda tag: make_jump_insn(opcode, tag) | |
| else: | |
| return lambda arg: make_insn(insn_encode(opcode, arg)) | |
| op = Clutch(**{name: denotation(opcode) for name, opcode in opmap.items()}) | |
| # Example | |
| def make_bop(name, assembly, doc_string): | |
| return types.FunctionType( | |
| types.CodeType(2, # no kwonly in 2.7? | |
| 2, 16, 0, | |
| assemble(assembly), | |
| (doc_string,1), (), ('x','y'), | |
| '<stdin>', name, 1, '', | |
| (), ()), | |
| {}) | |
| def example(f): | |
| print f.__doc__ | |
| print dis(f) | |
| for i in range(3): | |
| print [f(i,j) for j in range(3)] | |
| def cond(test, then, else_): | |
| yes, after = 'yes', 'after' | |
| return (test + op.POP_JUMP_IF_TRUE(yes) | |
| + else_ + op.JUMP_FORWARD(after) | |
| + Label(yes) + then + Label(after)) | |
| def while_(test, body): | |
| return (op.JUMP_FORWARD('testing') | |
| + Label('again') + body | |
| + Label('testing') + test + op.POP_JUMP_IF_TRUE('again')) | |
| min0 = (cond(op.LOAD_FAST(0) + op.LOAD_FAST(1) + op.COMPARE_OP('<='), | |
| op.LOAD_FAST(0), | |
| op.LOAD_FAST(1)) | |
| + op.RETURN_VALUE) | |
| min1 = (while_(op.LOAD_FAST(0) + op.LOAD_FAST(1) + op.COMPARE_OP('>'), | |
| op.LOAD_FAST(0) + op.LOAD_CONST(1) + op.BINARY_SUBTRACT + op.STORE_FAST(0)) | |
| + op.LOAD_FAST(0) + op.RETURN_VALUE) | |
| ## example(make_bop("min1", min1, "min via while_")) | |
| #. min via while_ | |
| #. 1 0 JUMP_FORWARD 10 (to 13) | |
| #. >> 3 LOAD_FAST 0 (x) | |
| #. 6 LOAD_CONST 1 (1) | |
| #. 9 BINARY_SUBTRACT | |
| #. 10 STORE_FAST 0 (x) | |
| #. >> 13 LOAD_FAST 0 (x) | |
| #. 16 LOAD_FAST 1 (y) | |
| #. 19 COMPARE_OP 4 (>) | |
| #. 22 POP_JUMP_IF_TRUE 3 | |
| #. 25 LOAD_FAST 0 (x) | |
| #. 28 RETURN_VALUE | |
| #. None | |
| #. [0, 0, 0] | |
| #. [0, 1, 1] | |
| #. [0, 1, 2] | |
| #. | |
| ## example(make_bop("min0", min0, "min via cond")) | |
| #. min via cond | |
| #. 1 0 LOAD_FAST 0 (x) | |
| #. 3 LOAD_FAST 1 (y) | |
| #. 6 COMPARE_OP 1 (<=) | |
| #. 9 POP_JUMP_IF_TRUE 18 | |
| #. 12 LOAD_FAST 1 (y) | |
| #. 15 JUMP_FORWARD 3 (to 21) | |
| #. >> 18 LOAD_FAST 0 (x) | |
| #. >> 21 RETURN_VALUE | |
| #. None | |
| #. [0, 0, 0] | |
| #. [0, 1, 1] | |
| #. [0, 1, 2] | |
| #. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment