├── test ├── other.py ├── for_control.py ├── func_2.py ├── simpe_obj.py ├── adv_obj.py ├── func_5.py ├── func_1.py ├── unary_ops.py ├── func_0.py ├── while_control.py ├── func_4.py ├── func_3.py ├── if_control.py ├── exception_control.py ├── class_0.py ├── inplace_ops.py ├── binary_ops.py └── slice_ops.py ├── .gitignore ├── icons ├── cut.gif ├── about.gif ├── copy.gif ├── paste.gif ├── redo.gif ├── save.gif ├── undo.gif ├── new_file.gif ├── find_text.gif └── open_file.gif ├── .travis.yml ├── README.md ├── vx └── caller.py ├── UnitTest.py ├── PyMro.py ├── OpCode.py ├── PyObject.py ├── PyEditor.py ├── InsightPyc.py └── PyVM2.py /test/other.py: -------------------------------------------------------------------------------- 1 | 2 | a = {1, 2} 3 | print a 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | .settings 3 | .project 4 | .pydevproject -------------------------------------------------------------------------------- /test/for_control.py: -------------------------------------------------------------------------------- 1 | lst = [1,2,4,5] 2 | for i in lst: 3 | print i -------------------------------------------------------------------------------- /icons/cut.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VxCoder/PythonVM/HEAD/icons/cut.gif -------------------------------------------------------------------------------- /icons/about.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VxCoder/PythonVM/HEAD/icons/about.gif -------------------------------------------------------------------------------- /icons/copy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VxCoder/PythonVM/HEAD/icons/copy.gif -------------------------------------------------------------------------------- /icons/paste.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VxCoder/PythonVM/HEAD/icons/paste.gif -------------------------------------------------------------------------------- /icons/redo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VxCoder/PythonVM/HEAD/icons/redo.gif -------------------------------------------------------------------------------- /icons/save.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VxCoder/PythonVM/HEAD/icons/save.gif -------------------------------------------------------------------------------- /icons/undo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VxCoder/PythonVM/HEAD/icons/undo.gif -------------------------------------------------------------------------------- /icons/new_file.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VxCoder/PythonVM/HEAD/icons/new_file.gif -------------------------------------------------------------------------------- /icons/find_text.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VxCoder/PythonVM/HEAD/icons/find_text.gif -------------------------------------------------------------------------------- /icons/open_file.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VxCoder/PythonVM/HEAD/icons/open_file.gif -------------------------------------------------------------------------------- /test/func_2.py: -------------------------------------------------------------------------------- 1 | def f(a=1, b=2): 2 | print a + b 3 | 4 | f() 5 | 6 | f(b=4) 7 | -------------------------------------------------------------------------------- /test/simpe_obj.py: -------------------------------------------------------------------------------- 1 | i = "1" 2 | s = "Python" 3 | d = {} 4 | l = [1, 2] 5 | print i, s, d, l -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: "2.7" 3 | install: true 4 | script: python UnitTest.py -------------------------------------------------------------------------------- /test/adv_obj.py: -------------------------------------------------------------------------------- 1 | i = 1 2 | s = "Python" 3 | d = {"1": 1, "2": 2} 4 | l = [1, 2] 5 | print i, s, d, l -------------------------------------------------------------------------------- /test/func_5.py: -------------------------------------------------------------------------------- 1 | def foo(): 2 | for i in [1, 2, 3]: 3 | yield i 4 | 5 | bar = foo() 6 | # print next(bar) 7 | -------------------------------------------------------------------------------- /test/func_1.py: -------------------------------------------------------------------------------- 1 | def f(name, age): 2 | age += 5 3 | print '[', name, ',', age, ']' 4 | 5 | age = 5 6 | print age 7 | f("Robert", age) 8 | print age -------------------------------------------------------------------------------- /test/unary_ops.py: -------------------------------------------------------------------------------- 1 | a = 1 2 | print a 3 | a = +a 4 | print a 5 | a = -a 6 | print a 7 | a = not a 8 | print a 9 | a= ~ a 10 | print a 11 | 12 | -------------------------------------------------------------------------------- /test/func_0.py: -------------------------------------------------------------------------------- 1 | def f(): 2 | print 'in f' 3 | 4 | 5 | def g(): 6 | print 'in g' 7 | f() 8 | 9 | 10 | def h(): 11 | print 'in h' 12 | g() 13 | 14 | h() 15 | -------------------------------------------------------------------------------- /test/while_control.py: -------------------------------------------------------------------------------- 1 | i = 0 2 | while i < 10: 3 | i += 1 4 | if i == 5: 5 | continue 6 | if i == 8: 7 | break 8 | print i 9 | 10 | print "hello world" -------------------------------------------------------------------------------- /test/func_4.py: -------------------------------------------------------------------------------- 1 | def get_func(arg): 2 | value = "inner" 3 | 4 | def inner_func(): 5 | print arg 6 | print value 7 | 8 | return inner_func 9 | 10 | show_value = get_func("params") 11 | show_value() 12 | -------------------------------------------------------------------------------- /test/func_3.py: -------------------------------------------------------------------------------- 1 | def Py_Func(value, *lst, **keys): 2 | print value 3 | print lst 4 | print keys 5 | 6 | Py_Func(-1, 1, 2, a=3, b=4) 7 | 8 | 9 | def Test_Func(a, b=1, *args, **kwargs): 10 | c = a + b 11 | print c 12 | 13 | 14 | Test_Func(1, 2, 3, 4, c=1) 15 | -------------------------------------------------------------------------------- /test/if_control.py: -------------------------------------------------------------------------------- 1 | a = 11 2 | if a > 10: 3 | print "**************a>10" 4 | 5 | if a <= 20: 6 | print "a <= 20" 7 | 8 | if a != 1: 9 | print "a != 1" 10 | 11 | if a == 11: 12 | print "a == 11" 13 | 14 | if a == 12: 15 | print "a == 12" 16 | else: 17 | print "unknow a" -------------------------------------------------------------------------------- /test/exception_control.py: -------------------------------------------------------------------------------- 1 | try: 2 | 1 / 0 3 | except Exception: 4 | pass 5 | finally: 6 | print 'the finally code' 7 | 8 | print 'hello' 9 | 10 | 11 | def hello(): 12 | 1 / 0 13 | 14 | 15 | def world(): 16 | hello() 17 | 18 | 19 | def foo(): 20 | world() 21 | 22 | 23 | def bar(): 24 | foo() 25 | bar() 26 | -------------------------------------------------------------------------------- /test/class_0.py: -------------------------------------------------------------------------------- 1 | # class A(object): 2 | # name = 'Python' 3 | # 4 | # def __init__(self): 5 | # print 'A:: __init__' 6 | # 7 | # def f(self): 8 | # print 'A::f' 9 | # 10 | # def g(self, aValue): 11 | # self.value = aValue 12 | # print self.value 13 | # 14 | # 15 | # a = A() 16 | # a.f() 17 | # a.g(10) 18 | -------------------------------------------------------------------------------- /test/inplace_ops.py: -------------------------------------------------------------------------------- 1 | a = "hello" 2 | a += 'world' 3 | print a, 4 | 5 | a = 2 6 | a **= 2 7 | print a, 8 | a -= 1 9 | print a, 10 | a *= 2 11 | print a, 12 | a /= 2 13 | print a, 14 | a //= 2 15 | print a, 16 | a %= 2 17 | print a, 18 | a &= 2 19 | print a, 20 | a |= 2 21 | print a, 22 | a ^= 2 23 | print a, 24 | a <<= 1 25 | print a, 26 | a >>= 1 27 | print a 28 | 29 | -------------------------------------------------------------------------------- /test/binary_ops.py: -------------------------------------------------------------------------------- 1 | a = 5 2 | b = a 3 | d = {a: b} 4 | c = a ** b 5 | print c 6 | c = a + b 7 | print c 8 | c = a - b 9 | print c 10 | c = a * b 11 | print c 12 | c = a / b 13 | print c 14 | c = a // b 15 | print c 16 | c = a % b 17 | print c 18 | c = a & b 19 | print c 20 | c = a | b 21 | print c 22 | c = a ^ b 23 | print c 24 | c = a << b 25 | print c 26 | c = a >> b 27 | print c 28 | c = d[a] 29 | print c 30 | -------------------------------------------------------------------------------- /test/slice_ops.py: -------------------------------------------------------------------------------- 1 | lst = [1, 2, 3, 4, 5, 6] 2 | print lst[0:-1:2] 3 | 4 | a_list = ['1', '2', '3', '4', '5', '6'] 5 | a_list[1:] = lst[1:] 6 | print a_list 7 | 8 | a_list[:3] = lst[:3] 9 | print a_list 10 | 11 | a_list[2:4] = lst[2:4] 12 | print a_list 13 | 14 | a_list[:] = lst[:] 15 | print a_list 16 | 17 | del lst[1:] 18 | print lst 19 | 20 | del lst[:3] 21 | print lst 22 | 23 | del a_list[2:4] 24 | print a_list 25 | 26 | del a_list[:] 27 | print a_list 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ![](https://img.shields.io/badge/python-2.7-brightgreen.svg) 3 | ![](https://travis-ci.org/VxCoder/PythonVM.svg?branch=master) 4 | # PythonVM 5 | 通过python实现python虚拟机 6 | 7 | # 暂时实现的功能 8 | 主要功能脚本:InsightPyc.py 9 | 10 | ## PYC文件解析 11 | 1. 打开pyc文件并显示解析结果 12 | 2. 打开py文件,生成pyc文件并解析显示 13 | 3. 显示python汇编代码(py方式打开,可以有源码对照) 14 | 15 | ## 模拟运行 16 | 1. 模拟运行功能, 现支持的汇编指令(参见OpCode.py 有#标志的指令) 17 | 18 | 19 | ## 源码文件编辑 20 | 1. 有个运行界面了 21 | 22 | 23 | # 有空要开发的功能 24 | 1. 完善pyc中剩余类型的解析 25 | 2. 参考byterun项目/ceval.c 实行python执行引擎(这么大的功能,就这么一笔带过了) 26 | 3. 完善GUI显示 27 | 4. 支持python3.x 28 | 5. 从汇编代码中逆推出源代码 29 | 6. co_consts 附带类型 30 | 31 | -------------------------------------------------------------------------------- /vx/caller.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """ 3 | f_locals 居然是浅拷贝 4 | """ 5 | import sys 6 | 7 | 8 | def g(): 9 | 10 | frame = sys._getframe() 11 | caller = frame.f_back 12 | print "caller's local namespace: ", caller.f_locals 13 | caller.f_locals['a'][0] = 100 14 | caller.f_locals['b'] = 4 15 | caller.f_builtins['list'] = tuple 16 | 17 | 18 | def f(): 19 | a = [1, 2] 20 | b = 2 21 | print "before call g()!a = {}, b={}".format(a, b) 22 | g() 23 | print "after call g()!a = {}, b={}".format(a, b) 24 | c = list([3, 4]) 25 | print c 26 | 27 | 28 | f() 29 | 30 | if __name__ == "__main__": 31 | f() 32 | -------------------------------------------------------------------------------- /UnitTest.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | 3 | import re 4 | import os 5 | import subprocess 6 | 7 | from PyVM2 import PythonVM 8 | from InsightPyc import PycParser, PycShowApplication 9 | 10 | space = re.compile(r'\s') 11 | outstring = [] 12 | 13 | 14 | def outstream(message, newline=True): 15 | message = str(message) 16 | message += ('\n' if newline else ' ') 17 | outstring.append(message) 18 | 19 | 20 | def main_test(): 21 | global outstring 22 | 23 | success = 0 24 | failed = 0 25 | 26 | for file_name in os.listdir('test'): 27 | # 异常暂时不比对,但功能已完成 28 | if not file_name.endswith('.py') or file_name == 'exception_control.py': 29 | continue 30 | 31 | # 获取python 虚拟机的输出 32 | py_path = os.path.join('.', 'test', file_name) 33 | try: 34 | real_output = subprocess.check_output(['python', py_path]) 35 | except subprocess.CalledProcessError as error: 36 | real_output = error.output 37 | 38 | # 获取我的虚拟机的输出 39 | pyc_path = PycShowApplication.generate_pyc(py_path) 40 | pycode_object = PycParser(pyc_path).insign() 41 | PythonVM(pycode_object, outstream, py_path).run_code() 42 | vm_output = "".join(outstring) 43 | 44 | # 比对输出是否一致 45 | if space.sub('', vm_output) == space.sub('', real_output): 46 | success += 1 47 | print "pass {}".format(py_path) 48 | else: 49 | failed += 1 50 | print "failed {}".format(py_path) 51 | print ">>>>>>>>>>>>>>>>>real>>>>>>>>\n{}".format(real_output.strip()) 52 | print "<<<<<<<<<<<<<<<= len(Lns): 83 | raise TypeError("Cannot create a consistent method resolution") 84 | 85 | h = head(Lns[index]) 86 | 87 | # 如果当前头在其他继承链的尾部,说明存在一个菱形继承,那采用广度搜索 88 | for i, Ln in enumerate(Lns): 89 | if i == index: 90 | continue 91 | 92 | # 这就是实现广度搜索的关键一步 93 | if h in tail(Ln): 94 | index += 1 95 | break 96 | else: 97 | new_Lns = [] 98 | for Ln in Lns: 99 | if h != head(Ln): 100 | new_Lns.append(Ln) 101 | continue 102 | if tail(Ln): 103 | new_Lns.append(tail(Ln)) 104 | 105 | Lns = new_Lns 106 | lst.append(h) 107 | index = 0 108 | 109 | return lst 110 | 111 | 112 | def L(C, inherit): 113 | """ 114 | @ 我实现的C3算法 115 | """ 116 | lst = [C] 117 | 118 | if len(inherit[C]): 119 | # 通过递归实现深度搜索, 从而保证单调性 120 | Lns = [L(base, inherit) for base in inherit[C]] 121 | # Lns.append(inherit[C]) 122 | 123 | # 通过merge算法,实现菱形继承时,方法不能覆盖问题 124 | lst += merge(Lns, inherit) 125 | 126 | return lst 127 | 128 | 129 | def main(): 130 | for inherit in inherits: 131 | inherit_dict = create_dict(inherit) 132 | print_mro(create_classs("A", inherit_dict)) 133 | print(" ".join(L("A", inherit_dict))) 134 | 135 | 136 | if __name__ == "__main__": 137 | main() 138 | -------------------------------------------------------------------------------- /OpCode.py: -------------------------------------------------------------------------------- 1 | 2 | op_code = { 3 | 0: "STOP_CODE", # this is an error 4 | 1: "POP_TOP", # 5 | 2: "ROT_TWO", # 6 | 3: "ROT_THREE", # 7 | 4: "DUP_TOP", # 8 | 5: "ROT_FOUR", # 9 | 9: "NOP", # 10 | 10: "UNARY_POSITIVE", # 11 | 11: "UNARY_NEGATIVE", # 12 | 12: "UNARY_NOT", # 13 | 13: "UNARY_CONVERT", # 14 | 15: "UNARY_INVERT", # 15 | 19: "BINARY_POWER", # 16 | 20: "BINARY_MULTIPLY", # 17 | 21: "BINARY_DIVIDE", # 18 | 22: "BINARY_MODULO", # 19 | 23: "BINARY_ADD", # 20 | 24: "BINARY_SUBTRACT", # 21 | 25: "BINARY_SUBSCR", # 22 | 26: "BINARY_FLOOR_DIVIDE", # 23 | 27: "BINARY_TRUE_DIVIDE", # 24 | 28: "INPLACE_FLOOR_DIVIDE", # 25 | 29: "INPLACE_TRUE_DIVIDE", # 26 | 30: "SLICE", # 27 | 31: "SLICE_1", # 28 | 32: "SLICE_2", # 29 | 33: "SLICE_3", # 30 | 40: "STORE_SLICE", # 31 | 41: "STORE_SLICE_1", # 32 | 42: "STORE_SLICE_2", # 33 | 43: "STORE_SLICE_3", # 34 | 50: "DELETE_SLICE", # 35 | 51: "DELETE_SLICE_1", # 36 | 52: "DELETE_SLICE_2", # 37 | 53: "DELETE_SLICE_3", # 38 | 54: "STORE_MAP", 39 | 55: "INPLACE_ADD", # 40 | 56: "INPLACE_SUBTRACT", # 41 | 57: "INPLACE_MULTIPLY", # 42 | 58: "INPLACE_DIVIDE", # 43 | 59: "INPLACE_MODULO", # 44 | 60: "STORE_SUBSCR", 45 | 61: "DELETE_SUBSCR", 46 | 62: "BINARY_LSHIFT", # 47 | 63: "BINARY_RSHIFT", # 48 | 64: "BINARY_AND", # 49 | 65: "BINARY_XOR", # 50 | 66: "BINARY_OR", # 51 | 67: "INPLACE_POWER", # 52 | 68: "GET_ITER", # 53 | 70: "PRINT_EXPR", 54 | 71: "PRINT_ITEM", # 55 | 72: "PRINT_NEWLINE", # 56 | 73: "PRINT_ITEM_TO", 57 | 74: "PRINT_NEWLINE_TO", 58 | 75: "INPLACE_LSHIFT", # 59 | 76: "INPLACE_RSHIFT", # 60 | 77: "INPLACE_AND", # 61 | 78: "INPLACE_XOR", # 62 | 79: "INPLACE_OR", # 63 | 80: "BREAK_LOOP", # 64 | 81: "WITH_CLEANUP", 65 | 82: "LOAD_LOCALS", 66 | 83: "RETURN_VALUE", # 67 | 84: "IMPORT_STAR", 68 | 85: "EXEC_STMT", 69 | 86: "YIELD_VALUE", 70 | 87: "POP_BLOCK", # 71 | 88: "END_FINALLY", # 72 | 89: "BUILD_CLASS", 73 | 90: "HAVE_ARGUMENT", # Opcodes from here have an argument: 74 | 90: "STORE_NAME", # 75 | 91: "DELETE_NAME", 76 | 92: "UNPACK_SEQUENCE", 77 | 93: "FOR_ITER", # 78 | 94: "LIST_APPEND", 79 | 95: "STORE_ATTR", 80 | 96: "DELETE_ATTR", 81 | 97: "STORE_GLOBAL", 82 | 98: "DELETE_GLOBAL", 83 | 99: "DUP_TOPX", 84 | 100: "LOAD_CONST", # 85 | 101: "LOAD_NAME", # 86 | 102: "BUILD_TUPLE", # 87 | 103: "BUILD_LIST", # 88 | 104: "BUILD_SET", # 89 | 105: "BUILD_MAP", # 90 | 106: "LOAD_ATTR", 91 | 107: "COMPARE_OP", # 92 | 108: "IMPORT_NAME", 93 | 109: "IMPORT_FROM", 94 | 110: "JUMP_FORWARD", # 95 | 111: "JUMP_IF_FALSE_OR_POP", 96 | 112: "JUMP_IF_TRUE_OR_POP", 97 | 113: "JUMP_ABSOLUTE", # 98 | 114: "POP_JUMP_IF_FALSE", # 99 | 115: "POP_JUMP_IF_TRUE", # 100 | 116: "LOAD_GLOBAL", # 101 | 119: "CONTINUE_LOOP", 102 | 120: "SETUP_LOOP", # 103 | 121: "SETUP_EXCEPT", 104 | 122: "SETUP_FINALLY", 105 | 124: "LOAD_FAST", # 106 | 125: "STORE_FAST", # 107 | 126: "DELETE_FAST", 108 | 130: "RAISE_VARARGS", # 109 | 131: "CALL_FUNCTION", # 110 | 132: "MAKE_FUNCTION", # 111 | 133: "BUILD_SLICE", # 112 | 134: "MAKE_CLOSURE", # 113 | 135: "LOAD_CLOSURE", # 114 | 136: "LOAD_DEREF", # 115 | 137: "STORE_DEREF", # 116 | 140: "CALL_FUNCTION_VAR", 117 | 141: "CALL_FUNCTION_KW", 118 | 142: "CALL_FUNCTION_VAR_KW", 119 | 143: "SETUP_WITH", 120 | 145: "EXTENDED_ARG", 121 | 146: "SET_ADD", 122 | 147: "MAP_ADD" 123 | } 124 | 125 | 126 | def has_arg(op): 127 | return op >= 90 128 | 129 | 130 | def has_const(): 131 | return [100] 132 | 133 | 134 | def has_names(): 135 | return [90, 101] 136 | -------------------------------------------------------------------------------- /PyObject.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | 3 | from collections import namedtuple 4 | 5 | 6 | class PyTraceback(object): 7 | 8 | def __init__(self, next, frame): 9 | self.tb_next = next 10 | self.tb_frame = frame 11 | self.tb_lasti = frame.f_lasti 12 | self.tb_lineno = self.get_line_number(frame) 13 | 14 | def get_line_number(self, frame): 15 | return self.addr2line(frame.f_code, frame.f_lasti) 16 | 17 | def addr2line(self, code, lasti): 18 | size = len(code.co_lnotab) 19 | line = code.co_firstlineno 20 | lnotab = code.co_lnotab 21 | index = 0 22 | addr = 0 23 | 24 | while index < size: 25 | addr += ord(lnotab[index]) 26 | if addr > lasti: 27 | break 28 | line += ord(lnotab[index + 1]) 29 | index += 2 30 | 31 | return line 32 | 33 | 34 | class PyThreadState(object): 35 | 36 | """ 37 | PyThreadState 类似于线程 38 | """ 39 | 40 | THREAD_STATES = [] 41 | CUR_THREAD_STATE = None 42 | 43 | def __init__(self): 44 | self.frame = None 45 | self.curexc_type = None # 异常类型 46 | self.curexc_value = None # 异常值 47 | self.curexc_traceback = None # 异常回溯 48 | 49 | self.THREAD_STATES.append(self) 50 | self.__class__.CUR_THREAD_STATE = 0 51 | 52 | def fetch_error(self): 53 | curexc_type = self.curexc_type 54 | curexc_value = self.curexc_value 55 | curexc_traceback = self.curexc_traceback 56 | 57 | self.curexc_type = None 58 | self.curexc_value = None 59 | self.curexc_traceback = None 60 | 61 | return curexc_type, curexc_value, curexc_traceback 62 | 63 | def store_error(self, curexc_type, curexc_value, curexc_traceback=None): 64 | self.curexc_type = curexc_type 65 | self.curexc_value = curexc_value 66 | 67 | @classmethod 68 | def GET_THREAD_STATE(cls): 69 | return cls.THREAD_STATES[cls.CUR_THREAD_STATE] 70 | 71 | 72 | class PyGenObject(object): 73 | 74 | def __init__(self, frame): 75 | 76 | self.gi_frame = frame 77 | self.gi_running = False 78 | self.gi_code = frame.f_code 79 | self.gi_weakreflist = None 80 | 81 | def __iter__(self): 82 | return self 83 | 84 | def next(self): 85 | tstate = PyThreadState.GET_THREAD_STATE() 86 | frame = self.gi_frame 87 | result = None 88 | 89 | if self.gi_running: 90 | tstate.store_error(ValueError, "generator already executing") 91 | return None 92 | 93 | # 生成器返回到最近的调用者,而不是它的创建者 94 | frame.f_tstate = tstate 95 | frame.f_back = tstate.frame 96 | 97 | self.gi_running = 1 98 | #result = PyEval_EvalFrameEx(f, exc); 99 | self.gi_running = 0 100 | 101 | frame.f_back = None 102 | frame.f_tstate = None 103 | 104 | return result 105 | 106 | 107 | class PyFunctionObject(object): 108 | 109 | def __init__(self, code, globals): 110 | self.func_code = code # 运行代码 111 | self.func_globals = globals # 全局变量 112 | self.func_name = code.co_name # 函数名 113 | self.func_defaults = [] # 默认参数 114 | self.func_closure = None 115 | 116 | def set_closure(self, cells): 117 | self.func_closure = cells 118 | 119 | 120 | PyBlock = namedtuple("PyBlock", "b_type, b_handler, b_level") 121 | 122 | 123 | class PyCellObject(object): 124 | 125 | def __init__(self, *args): 126 | if len(args): 127 | self.ob_ref = args[0] 128 | 129 | def set(self, obj): 130 | self.ob_ref = obj 131 | 132 | def get(self): 133 | return self.ob_ref # 获取前,应该已经设置过了 134 | 135 | 136 | class PyFrameObject(object): 137 | """ 138 | python 运行栈对象 139 | f_back: 前一个运行栈 140 | f_code: 代码段 141 | f_builtins: 内建命名空间 142 | f_globals: 全局命名空间 143 | f_locals: 局部命名空间 144 | f_stack: 运行时栈 145 | f_lasti: 最后执行的代码地址 146 | block_stack: 代码block对象 147 | """ 148 | 149 | def __init__(self, thread_state, f_code, f_globals, f_locals): 150 | self.f_tstate = thread_state 151 | self.f_back = thread_state.frame # 之前的运行栈 152 | 153 | self.f_code = f_code # 运行代码 154 | 155 | self.f_locals = f_locals # 局部命名空间 156 | self.f_globals = f_globals # 全局命名空间 157 | self.f_builtins = None # 内建命名空间 158 | 159 | if self.f_back == None: 160 | 161 | self.f_builtins = __builtins__ 162 | else: 163 | self.f_builtins = self.f_back.f_builtins 164 | 165 | self.f_stack = [] 166 | self.f_lasti = -1 167 | 168 | # 静态局部变量保存地方 169 | # CO_OPTIMIZED | CO_NEWLOCALS 生效时,LOAD|STORE_FAST 使用 170 | extras = f_code.co_nlocals + len(f_code.co_cellvars) + len(f_code.co_freevars) 171 | self.f_fast_local = [None for _ in range(extras)] 172 | 173 | self.block_stack = [] # 代码块 174 | 175 | 176 | class PyCodeObject(object): 177 | 178 | CO_OPTIMIZED = 0x0001 # 局部变量快速读取 179 | CO_NEWLOCALS = 0x0002 # 局部变量快速读取 180 | CO_VARARGS = 0x0004 # 扩展位置参数 181 | CO_VARKEYWORDS = 0x0008 # 扩展键参数 182 | CO_NESTED = 0x0010 # 闭包函数标志 183 | CO_GENERATOR = 0x0020 # 生成器 184 | CO_NOFREE = 0x0040 # 没有闭包 185 | 186 | def __init__(self): 187 | self.co_co_argcount = None 188 | self.co_nlocals = None 189 | self.co_stacksize = None 190 | self.co_flags = None 191 | self.co_code = None 192 | self.co_consts = None 193 | self.co_names = None 194 | self.co_varnames = None 195 | self.co_freevars = None 196 | self.co_cellvars = None 197 | self.co_filename = None 198 | self.co_name = None 199 | self.co_firstlineno = None 200 | self.co_lnotab = None 201 | self.version = None 202 | self.mtime = None 203 | -------------------------------------------------------------------------------- /PyEditor.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | 3 | import tkFont 4 | from Tkinter import * 5 | from ttk import * 6 | 7 | 8 | class PyEditor(Frame): 9 | 10 | COLOR_SCHEMES = { 11 | 'Default': '#000000.#FFFFFF', 12 | 'Greygarious': '#83406A.#D1D4D1', 13 | 'Aquamarine': '#5B8340.#D1E7E0', 14 | 'Bold Beige': '#4B4620.#FFF0E1', 15 | 'Cobalt Blue': '#ffffBB.#3333aa', 16 | 'Olive Green': '#D1E7E0.#5B8340', 17 | 'Night Mode': '#FFFFFF.#000000', 18 | } 19 | 20 | def __init__(self, master=None): 21 | Frame.__init__(self, master) 22 | 23 | self.pack() 24 | self.init_resource() 25 | self.init_style() 26 | self.create_widgets() 27 | 28 | def init_style(self): 29 | self.background = "#272822" 30 | self.main_color = "#A7EC21" 31 | self.font = tkFont.Font(family='Helvetica', size=12, weight='bold') 32 | 33 | Style().configure("Frame", background=self.background, foreground="#52E3F6", font=self.font) 34 | 35 | def init_resource(self): 36 | self.new_file_icon = PhotoImage(file='icons/new_file.gif') 37 | self.open_file_icon = PhotoImage(file='icons/open_file.gif') 38 | self.save_file_icon = PhotoImage(file='icons/save.gif') 39 | self.cut_icon = PhotoImage(file='icons/cut.gif') 40 | self.copy_icon = PhotoImage(file='icons/copy.gif') 41 | self.paste_icon = PhotoImage(file='icons/paste.gif') 42 | self.undo_icon = PhotoImage(file='icons/undo.gif') 43 | self.redo_icon = PhotoImage(file='icons/redo.gif') 44 | 45 | def create_widgets(self): 46 | menu_bar = Menu() 47 | 48 | file_menu = Menu(menu_bar, tearoff=0) 49 | file_menu.add_command(label='New', 50 | accelerator='Ctrl+N', 51 | compound='left', 52 | image=self.new_file_icon, 53 | underline=0, 54 | command=self.new_file) 55 | file_menu.add_command(label='Open', 56 | accelerator='Ctrl+O', 57 | compound='left', 58 | image=self.open_file_icon, 59 | underline=0) 60 | file_menu.add_command(label='Save', 61 | accelerator='Ctrl+S', 62 | compound='left', 63 | image=self.save_file_icon, 64 | underline=0) 65 | file_menu.add_command(label='Save as', accelerator='Shift+Ctrl+S') 66 | file_menu.add_separator() 67 | file_menu.add_command(label='Exit', accelerator='Alt+F4') 68 | menu_bar.add_cascade(label='File', menu=file_menu) 69 | 70 | edit_menu = Menu(menu_bar, tearoff=0) 71 | edit_menu.add_command(label='Undo', accelerator='Ctrl+Z', 72 | compound='left', image=self.undo_icon) 73 | edit_menu.add_command(label='Redo', accelerator='Ctrl+Y', 74 | compound='left', image=self.redo_icon) 75 | edit_menu.add_separator() 76 | edit_menu.add_command(label='Cut', accelerator='Ctrl+X', 77 | compound='left', image=self.cut_icon) 78 | edit_menu.add_command(label='Copy', accelerator='Ctrl+C', 79 | compound='left', image=self.copy_icon) 80 | edit_menu.add_command(label='Paste', accelerator='Ctrl+V', 81 | compound='left', image=self.paste_icon) 82 | edit_menu.add_separator() 83 | edit_menu.add_command(label='Find', underline=0, accelerator='Ctrl+F') 84 | edit_menu.add_separator() 85 | edit_menu.add_command(label='Select All', underline=7, accelerator='Ctrl+A') 86 | menu_bar.add_cascade(label='Edit', menu=edit_menu) 87 | 88 | view_menu = Menu(menu_bar, tearoff=0) 89 | self.show_line_number = IntVar() 90 | self.show_line_number.set(1) 91 | view_menu.add_checkbutton(label='Show Line Number', variable=self.show_line_number) 92 | self.show_cursor_info = IntVar() 93 | self. show_cursor_info.set(1) 94 | view_menu.add_checkbutton(label='Show Cursor Location at Bottom', variable=self.show_cursor_info) 95 | self.highlight_line = IntVar() 96 | view_menu.add_checkbutton(label='Highlight Current Line', onvalue=1, 97 | offvalue=0, variable=self.highlight_line) 98 | themes_menu = Menu(menu_bar, tearoff=0) 99 | view_menu.add_cascade(label='Themes', menu=themes_menu) 100 | self.theme_choice = StringVar() 101 | self.theme_choice.set('Default') 102 | for k in sorted(self.COLOR_SCHEMES): 103 | themes_menu.add_radiobutton(label=k, variable=self.theme_choice) 104 | menu_bar.add_cascade(label='View', menu=view_menu) 105 | 106 | about_menu = Menu(menu_bar, tearoff=0) 107 | about_menu.add_command(label='About') 108 | about_menu.add_command(label='Help') 109 | menu_bar.add_cascade(label='About', menu=about_menu) 110 | 111 | self.master.config(menu=menu_bar) 112 | 113 | shortcut_bar = Frame(height=25) 114 | shortcut_bar.pack(expand=False, fill=X) 115 | 116 | line_number_bar = Text(width=4, padx=3, takefocus=0, border=0, 117 | background='khaki', state=DISABLED, wrap=NONE) 118 | line_number_bar.pack(side=LEFT, fill=Y) 119 | 120 | content_text = Text(wrap=WORD) 121 | content_text.pack(expand=True, fill=BOTH) 122 | 123 | scroll_bar = Scrollbar(content_text) 124 | content_text.configure(yscrollcommand=scroll_bar.set) 125 | scroll_bar.config(command=content_text.yview) 126 | scroll_bar.pack(side=RIGHT, fill=Y) 127 | 128 | def new_file(self): 129 | print("new_file") 130 | 131 | @classmethod 132 | def run(cls): 133 | root = Tk() 134 | root.title("Python Editor") 135 | root.geometry('400x400') 136 | root.resizable(width=True, height=True) 137 | app = cls(master=root) 138 | app.mainloop() 139 | 140 | 141 | def main(): 142 | PyEditor.run() 143 | 144 | 145 | if __name__ == "__main__": 146 | main() 147 | -------------------------------------------------------------------------------- /InsightPyc.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | import os 3 | import sys 4 | import imp 5 | import time 6 | import marshal 7 | import struct 8 | import tkFont 9 | import py_compile 10 | 11 | import tkFileDialog as filedialog 12 | from Tkinter import * 13 | from tkMessageBox import * 14 | from ttk import * 15 | 16 | 17 | import OpCode 18 | from PyVM2 import PythonVM 19 | from PyEditor import PyEditor 20 | from PyObject import PyCodeObject 21 | 22 | 23 | MAGIC2VERSION = { 24 | 20121: 'Python 1.5/1.5.1/1.5.2', 25 | 50428: 'Python 1.6', 26 | 50823: 'Python 2.0/2.0.1', 27 | 60202: 'Python 2.1/2.1.1/2.1.2', 28 | 60717: 'Python 2.2', 29 | 62011: 'Python 2.3a0', 30 | 62021: 'Python 2.3a0', 31 | 62041: 'Python 2.4a0', 32 | 62051: 'Python 2.4a3', 33 | 62061: 'Python 2.4b1', 34 | 62071: 'Python 2.5a0', 35 | 62081: 'Python 2.5a0 (ast-branch)', 36 | 62091: 'Python 2.5a0 (with)', 37 | 62092: 'Python 2.5a0 (changed WITH_CLEANUP opcode)', 38 | 62101: 'Python 2.5b3 (fix wrong code: for x, in ...)', 39 | 62111: 'Python 2.5b3 (fix wrong code: x += yield)', 40 | 62121: 'Python 2.5c1 (fix wrong lnotab with for loops and storing constants that should have been removed)', 41 | 62131: 'Python 2.5c2 (fix wrong code: for x, in ... in listcomp/genexp)', 42 | 62151: 'Python 2.6a0 (peephole optimizations and STORE_MAP opcode)', 43 | 62161: 'Python 2.6a1 (WITH_CLEANUP optimization)', 44 | 62171: 'Python 2.7a0 (optimize list comprehensions/change LIST_APPEND)', 45 | 62181: 'Python 2.7a0 (optimize conditional branches:introduce POP_JUMP_IF_FALSE and POP_JUMP_IF_TRUE)', 46 | 62191: 'Python 2.7a0 (introduce SETUP_WITH)', 47 | 62201: 'Python 2.7a0 (introduce BUILD_SET)', 48 | 62211: 'Python 2.7a0 (introduce MAP_ADD and SET_ADD)', 49 | } 50 | 51 | 52 | class PycParser(object): 53 | MAGIC_SLICE = slice(2) # pyc 文件的魔数 54 | MTIME_SLICE = slice(4, 8) # pyc 文件的创建时间 55 | 56 | def __init__(self, pyc_path): 57 | self.pyc_path = pyc_path 58 | self.internedStringList = [] 59 | 60 | def read_long(self): 61 | data = struct.unpack("> 31: 86 | int_data = - ((int_data ^ 0xffffffff) + 1) 87 | 88 | return int_data 89 | 90 | def read_STRING_type(self): 91 | strlen = self.read_long() 92 | string = struct.unpack("<{}s".format(strlen), self.pyc_data[:strlen])[0] 93 | self.pyc_data = self.pyc_data[strlen:] 94 | return string 95 | 96 | def read_UNICODE_type(self): 97 | string = self.read_STRING_type() 98 | return string 99 | 100 | def read_STRINGREF_type(self): 101 | stringref = self.read_long() 102 | string = self.internedStringList[stringref] 103 | return string 104 | 105 | def read_INTERNED_type(self): 106 | string = self.read_STRING_type() 107 | self.internedStringList.append(string) 108 | return string 109 | 110 | def read_TUPLE_type(self): 111 | tuplelen = self.read_long() 112 | tuple_data = tuple([self.read_object() for _ in range(tuplelen)]) 113 | return tuple_data 114 | 115 | def read_LIST_type(self): 116 | listlen = self.read_long() 117 | list_data = [self.read_object() for _ in range(listlen)] 118 | return list_data 119 | 120 | def read_CODE_type(self): 121 | pycode_object = PyCodeObject() 122 | pycode_object.co_argcount = self.read_long() 123 | pycode_object.co_nlocals = self.read_long() 124 | pycode_object.co_stacksize = self.read_long() 125 | pycode_object.co_flags = self.read_long() 126 | pycode_object.co_code = self.read_object() 127 | pycode_object.co_consts = self.read_object() 128 | pycode_object.co_names = self.read_object() 129 | pycode_object.co_varnames = self.read_object() 130 | pycode_object.co_freevars = self.read_object() 131 | pycode_object.co_cellvars = self.read_object() 132 | pycode_object.co_filename = self.read_object() 133 | pycode_object.co_name = self.read_object() 134 | pycode_object.co_firstlineno = self.read_long() 135 | pycode_object.co_lnotab = self.read_object() 136 | 137 | return pycode_object 138 | 139 | PY_TYPE_MAP = { 140 | # TYPE_STOPITER 'S'- 141 | # TYPE_ELLIPSIS '.'- 142 | # TYPE_INT64 'I'- 143 | # TYPE_FLOAT 'f'- 144 | # TYPE_BINARY_FLOAT 'g'- 145 | # TYPE_COMPLEX 'x'- 146 | # TYPE_BINARY_COMPLEX 'y'- 147 | # TYPE_LONG 'l'- 148 | # TYPE_DICT '{'- 149 | # TYPE_UNKNOWN '?'- 150 | # TYPE_SET '<'- 151 | # TYPE_FROZENSET '>'- 152 | '0': read_NULL_type, 153 | 'N': read_NONE_type, 154 | 'F': read_FALSE_type, 155 | 'T': read_TRUE_type, 156 | 'i': read_INT_type, 157 | 'c': read_CODE_type, 158 | 't': read_INTERNED_type, 159 | 's': read_STRING_type, 160 | '(': read_TUPLE_type, 161 | '[': read_LIST_type, 162 | 'R': read_STRINGREF_type, 163 | 'u': read_UNICODE_type, 164 | } 165 | 166 | def read_object(self): 167 | object_type = self.pyc_data[0] 168 | 169 | read_func = self.PY_TYPE_MAP.get(object_type, None) 170 | if not read_func: 171 | print("unknow type {}".format(object_type)) 172 | sys.exit(2) 173 | 174 | self.pyc_data = self.pyc_data[1:] 175 | return read_func(self) 176 | 177 | def insign(self): 178 | 179 | self.pyc_data = None 180 | try: 181 | with open(self.pyc_path, 'rb') as fp: 182 | self.pyc_data = memoryview(fp.read()) 183 | except IOError: 184 | print("{} file not find\n".format(self.pyc_path)) 185 | 186 | except Exception as error: 187 | print(type(error), error.message) 188 | 189 | if not self.pyc_data: 190 | sys.exit(1) 191 | return 192 | 193 | magic = struct.unpack(" 13: 269 | outstr = "{}\t{}\t\t{}".format(last, opname, index) 270 | else: 271 | outstr = "{}\t{}\t\t\t{}".format(last, opname, index) 272 | 273 | if 'arg' in locals(): 274 | if isinstance(arg, PyCodeObject): 275 | outstr += "\t(Code object)".format(arg) 276 | elif isinstance(arg, str): 277 | outstr += "\t('{}')".format(arg) 278 | else: 279 | outstr += "\t({})".format(arg) 280 | del arg 281 | 282 | last += 3 283 | co_code = co_code[3:] 284 | else: 285 | outstr = "{}\t{}".format(last, opname) 286 | last += 1 287 | co_code = co_code[1:] 288 | 289 | show_tree.insert(parent_id, END, text=outstr) 290 | 291 | return last 292 | 293 | def dis_code_with_source(self, pycode_object, show_tree, parent_id, filename): 294 | 295 | last = 0 296 | lineno = 1 297 | source = open(filename) 298 | lntoab = memoryview(pycode_object.co_lnotab) 299 | co_code = memoryview(pycode_object.co_code) 300 | 301 | for _ in xrange(pycode_object.co_firstlineno - 1): 302 | source.readline() 303 | lineno += 1 304 | 305 | while lntoab: 306 | code_offset = ord(lntoab[0]) 307 | if code_offset == 0: 308 | break 309 | 310 | source_offset = ord(lntoab[1]) 311 | 312 | for _ in xrange(source_offset): 313 | line = source.readline() 314 | if line.strip(): 315 | show_tree.insert(parent_id, END, text="*{}\t{}".format(lineno, line)) 316 | lineno += 1 317 | 318 | last = self.dis_code(pycode_object, show_tree, parent_id, co_code=co_code[:code_offset], last=last) 319 | co_code = co_code[code_offset:] 320 | 321 | lntoab = lntoab[2:] 322 | 323 | for line in source: 324 | if line.strip(): 325 | show_tree.insert(parent_id, END, text="*{}\t{}".format(lineno, line)) 326 | lineno += 1 327 | else: 328 | break 329 | source.close() 330 | 331 | self.dis_code(pycode_object, show_tree, parent_id, co_code=co_code, last=last) 332 | 333 | def show_pyc_code(self, pycode_object, parent_id='', py_path=None): 334 | show_tree = self.show_tree 335 | if not parent_id: 336 | parent = show_tree.insert(parent_id, 0, text=pycode_object.co_filename, open=True) 337 | self.insert_params(parent, "版本信息", pycode_object.version, tab=3) 338 | self.insert_params(parent, "修改时间", pycode_object.mtime, tab=3) 339 | self.parent = parent 340 | else: 341 | parent = show_tree.insert(parent_id, 0, text=pycode_object.co_name, open=False) 342 | 343 | tmp_id = self.insert_params(parent, "co_argcount", "位置参数和键参数的个数(不包括*args, **kwargs)") 344 | show_tree.insert(tmp_id, END, text="value\t\t{}".format(pycode_object.co_argcount)) 345 | 346 | tmp_id = self.insert_params(parent, "co_nlocals", "所有局部变量的个数,包括所有入参(*args, **kwargs各算一个参数)") 347 | show_tree.insert(tmp_id, END, text="value\t\t{}".format(pycode_object.co_nlocals)) 348 | 349 | tmp_id = self.insert_params(parent, "co_stacksize", "需要的栈空间大小") 350 | show_tree.insert(tmp_id, END, text="value\t\t{}".format(pycode_object.co_stacksize)) 351 | 352 | tmp_id = self.insert_params(parent, "co_flags", "各类标志", tab=3) 353 | show_tree.insert(tmp_id, END, text="value\t\t{}".format(hex(pycode_object.co_flags))) 354 | 355 | tmp_id = self.insert_params(parent, "co_firstlineno", "代码块在对应源文件中的起始行") 356 | show_tree.insert(tmp_id, END, text="value\t\t{}".format(pycode_object.co_firstlineno)) 357 | 358 | tmp_id = self.insert_params(parent, "co_filename", "完整源文件路径名") 359 | show_tree.insert(tmp_id, END, text="value\t\t{}".format(pycode_object.co_filename)) 360 | 361 | tmp_id = self.insert_params(parent, "co_consts", "所有常量数据(所包含的代码块数据也在其中)") 362 | for const_item in pycode_object.co_consts: 363 | if isinstance(const_item, PyCodeObject): 364 | self.show_pyc_code(const_item, tmp_id, py_path) 365 | elif isinstance(const_item, str): 366 | show_tree.insert(tmp_id, END, text="'{}'".format(const_item)) 367 | elif isinstance(const_item, (int, tuple, long)): 368 | show_tree.insert(tmp_id, END, text=str(const_item)) 369 | elif type(const_item) == bytes: 370 | show_tree.insert(tmp_id, END, text=const_item) 371 | elif const_item == None: 372 | show_tree.insert(tmp_id, END, text='None') 373 | else: 374 | print("unhandle type", type(const_item)) 375 | 376 | tmp_id = self.insert_params(parent, "co_names", "所有变量名") 377 | for name in pycode_object.co_names: 378 | show_tree.insert(tmp_id, END, text=name) 379 | 380 | tmp_id = self.insert_params(parent, "co_varnames", "约束变量 -本代码段中被赋值,但没有被内层代码段引用的变量") 381 | for name in pycode_object.co_varnames: 382 | show_tree.insert(tmp_id, END, text=name) 383 | 384 | tmp_id = self.insert_params(parent, "co_cellvars", "内层约束变量 -本代码段中被赋值,且被内层代码段引用的变量") 385 | for name in pycode_object.co_cellvars: 386 | show_tree.insert(tmp_id, END, text=name) 387 | 388 | tmp_id = self.insert_params(parent, "co_freevars", "自由变量- 本代码段中被引用,在外层代码段中被赋值的变量") 389 | for name in pycode_object.co_freevars: 390 | show_tree.insert(tmp_id, END, text=name) 391 | 392 | tmp_id = self.insert_params(parent, "co_code", "字节码指令", tab=3, open=not parent_id) 393 | if py_path: 394 | self.dis_code_with_source(pycode_object, show_tree, tmp_id, py_path) 395 | else: 396 | self.dis_code(pycode_object, show_tree, tmp_id) 397 | 398 | self.show_tree.insert(parent, END, text="") # 留白 399 | 400 | @classmethod 401 | def generate_pyc(cls, py_path): 402 | pyc_name = None 403 | 404 | try: 405 | # 将源码编译成pycode对象 406 | with open(py_path) as source_fp: 407 | source = source_fp.read() 408 | code = compile(source, py_path, 'exec') 409 | 410 | # 将pycode对象保存为pyc格式 411 | pyc_name = os.path.splitext(py_path)[0] + '.pyc' 412 | with open(pyc_name, "wb") as code_fp: 413 | # 按照ceval.c 写入方式 414 | code_fp.write(imp.get_magic()) 415 | py_compile.wr_long(code_fp, 0) 416 | marshal.dump(code, code_fp) 417 | code_fp.flush() 418 | code_fp.seek(4, 0) 419 | py_compile.wr_long(code_fp, int(time.time())) 420 | 421 | except IOError as error: 422 | showerror("生成PYC失败", "文件处理失败!{}".format(error)) 423 | except Exception as error: 424 | showerror("生成PYC失败", "{}".format(error)) 425 | 426 | return pyc_name 427 | 428 | def show_pyc(self, pyc_path, py_path=None): 429 | 430 | self.pycode_object = PycParser(pyc_path).insign() 431 | if self.parent: 432 | self.show_tree.delete(self.parent) 433 | self.parent = None 434 | self.run_button.config(state='normal') 435 | 436 | self.show_pyc_code(self.pycode_object, py_path=py_path) 437 | 438 | def open_py(self): 439 | py_path = filedialog.askopenfilename() 440 | if not py_path: 441 | return 442 | 443 | py_path = py_path.encode() 444 | pyc_path = self.generate_pyc(py_path) 445 | if pyc_path: 446 | self.py_path = py_path 447 | self.show_pyc(pyc_path, py_path) 448 | self.edit_button.config(state='normal') 449 | 450 | def open_pyc(self): 451 | pyc_path = filedialog.askopenfilename() 452 | if not pyc_path: 453 | return 454 | 455 | self.py_path = None 456 | pyc_path = pyc_path.encode() 457 | self.show_pyc(pyc_path) 458 | self.edit_button.config(state='disable') 459 | 460 | def outstream(self, message, newline=True): 461 | message = str(message) 462 | message += ('\n' if newline else ' ') 463 | self.out_stream.insert(END, message) 464 | self.out_stream.see(END) 465 | 466 | def run_code(self): 467 | 468 | if not hasattr(self, "out_vbar"): 469 | Label(text='运行输出').pack(fill=X) 470 | 471 | out_frame = Frame() 472 | self.out_vbar = Scrollbar(out_frame) 473 | self.out_vbar.pack(side=RIGHT, fill=Y) 474 | 475 | self.out_stream = Text(out_frame, height=6, background=self.background, font=self.font, foreground=self.main_color) 476 | self.out_stream.pack(side=LEFT, fill=X, expand=True) 477 | 478 | self.out_stream['yscrollcommand'] = self.out_vbar.set 479 | self.out_vbar['command'] = self.out_stream.yview 480 | 481 | out_frame.pack(fill=X) 482 | 483 | PythonVM(self.pycode_object, self.outstream, self.py_path).run_code() 484 | 485 | def edit_file(self): 486 | pass 487 | # PyEditor.run() 488 | 489 | 490 | def main(): 491 | print sys.modules 492 | root = Tk() 493 | root.title("Pyc Insight") 494 | root.geometry('800x400+100+100') 495 | root.resizable(width=True, height=True) 496 | app = PycShowApplication(master=root) 497 | app.mainloop() 498 | 499 | 500 | if __name__ == "__main__": 501 | main() 502 | -------------------------------------------------------------------------------- /PyVM2.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | import sys 3 | import operator 4 | import traceback 5 | 6 | import OpCode 7 | from PyObject import PyThreadState, PyFunctionObject, PyFrameObject, PyBlock, PyCellObject, PyTraceback, PyCodeObject, PyGenObject 8 | 9 | 10 | class Singleton(object): 11 | __instance = None 12 | 13 | def __new__(cls, *args, **kwd): 14 | if Singleton.__instance is None: 15 | Singleton.__instance = object.__new__(cls, *args, **kwd) 16 | return Singleton.__instance 17 | 18 | 19 | class PythonVM(object): 20 | 21 | """ 22 | PythonVM 类似于CPU,执行code,切换运行时frame 23 | """ 24 | 25 | WHY_NOT = None # No error 26 | WHY_EXCEPTION = 0x0002 # Exception occurred 27 | WHY_RERAISE = 0x0004 # Exception re-raised by 'finally' 28 | WHY_RETURN = 0x0008 # 'return' statement 29 | WHY_BREAK = 0x0010 # 'break' statement 30 | WHY_CONTINUE = 0x0020 # 'continue' statement 31 | WHY_YIELD = 0x0040 # 'yield' operator 32 | 33 | TYPE_SETUP_LOOP = 'loop' 34 | TYPE_SETUP_FINALLY = 'finally' 35 | TYPE_SETUP_EXCEPT = 'except' 36 | 37 | SHOW_DETAIL = False 38 | 39 | def __init__(self, pycode_object, outstream, source_file=None): 40 | self.pycode_object = pycode_object 41 | self.outstream = outstream 42 | self.source_file = source_file 43 | self.thread_state = PyThreadState() 44 | 45 | def get_thread_state(self): 46 | return self.thread_state 47 | 48 | def run_code(self, globals=None): 49 | 50 | globals = globals or {} # 最外层的Frame,globals == locals 51 | 52 | frame = PyFrameObject(thread_state=self.get_thread_state(), 53 | f_code=self.pycode_object, 54 | f_globals=globals, 55 | f_locals=globals) 56 | 57 | why = self.eval_frame(frame, 0) 58 | 59 | if why == self.WHY_EXCEPTION: 60 | # 堆栈展开 61 | tstate = self.get_thread_state() 62 | 63 | error_type, error_value, error_tb = self.fetch_error() 64 | 65 | if self.source_file: 66 | fp = open(self.source_file) 67 | 68 | while error_tb: 69 | 70 | self.outstream('File "{}", line {}, in {}'.format( 71 | error_tb.tb_frame.f_code.co_filename, 72 | error_tb.tb_lineno, 73 | error_tb.tb_frame.f_code.co_name)) 74 | 75 | if self.source_file: 76 | for _ in range(error_tb.tb_lineno): 77 | line = fp.readline() 78 | self.outstream('\t{}'.format(line.strip())) 79 | fp.seek(0, 0) 80 | 81 | error_tb = error_tb.tb_next 82 | 83 | self.outstream("{}: {}".format(error_type, error_value)) 84 | 85 | def fetch_error(self): 86 | return self.get_thread_state().fetch_error() 87 | 88 | def store_error(self, error_type, error_value): 89 | self.get_thread_state().store_error(error_type, error_value) 90 | 91 | def error_occurred(self): 92 | return self.get_thread_state().curexc_type 93 | 94 | def trace_back_here(self, frame): 95 | tstate = self.get_thread_state() 96 | 97 | oldtb = tstate.curexc_traceback 98 | tb = PyTraceback(oldtb, frame) 99 | tstate.curexc_traceback = tb 100 | 101 | def parse_code_and_args(self): 102 | co_code = self.frame.f_code.co_code 103 | f_lasti = self.frame.f_lasti 104 | 105 | arg = None 106 | 107 | code = ord(co_code[f_lasti]) 108 | opname = OpCode.op_code[code] 109 | 110 | if OpCode.has_arg(code): 111 | arg = (ord(co_code[f_lasti + 2]) << 8) + ord(co_code[f_lasti + 1]) 112 | self.frame.f_lasti += 3 113 | else: 114 | self.frame.f_lasti += 1 115 | 116 | return opname, arg 117 | 118 | def dispatch(self, opname, arg): 119 | why = None 120 | 121 | try: 122 | if opname.startswith('UNARY_'): 123 | self.unaryOperator(opname[6:]) 124 | elif opname.startswith('BINARY_'): 125 | self.binaryOperator(opname[7:]) 126 | elif opname.startswith('INPLACE_'): 127 | self.inplaceOperator(opname[8:]) 128 | elif 'SLICE' in opname and opname != 'BUILD_SLICE': 129 | self.sliceOperator(opname) 130 | else: 131 | op_func = getattr(self, opname, None) 132 | 133 | if not op_func: 134 | print "not support {} now".format(opname) 135 | else: 136 | why = op_func(arg) if arg != None else op_func() 137 | 138 | except Exception: 139 | error_info = sys.exc_info() 140 | self.store_error(error_info[0], error_info[1]) 141 | 142 | print traceback.print_tb(sys.exc_info()[2]) 143 | why = self.WHY_EXCEPTION 144 | 145 | return why 146 | 147 | def eval_frame(self, frame, throwflag): 148 | self.get_thread_state().frame = frame 149 | 150 | self.frame = frame 151 | self.frame.f_lasti += 1 152 | 153 | while True: 154 | opname, arg = self.parse_code_and_args() 155 | 156 | why = self.dispatch(opname, arg) 157 | 158 | if why == self.WHY_NOT: 159 | if not self.error_occurred(): 160 | continue 161 | 162 | why = self.WHY_EXCEPTION 163 | 164 | if why == self.WHY_EXCEPTION: 165 | # 保存异常Frame,展开异常堆栈用 166 | self.trace_back_here(self.frame) 167 | 168 | if why == self.WHY_RERAISE: 169 | why = self.WHY_EXCEPTION 170 | 171 | while (why != self.WHY_NOT) and len(self.frame.block_stack): 172 | block = self.pop_block(self.frame) 173 | 174 | # 恢复到进入代码块前的堆栈状态 175 | while self.stack_level() > block.b_level: 176 | self.pop() 177 | 178 | # 针对块内的break操作 179 | if block.b_type == self.TYPE_SETUP_LOOP and why == self.WHY_BREAK: 180 | why = self.WHY_NOT 181 | self.jumpto(block.b_handler) 182 | break 183 | 184 | # 块内有异常发生 185 | if (block.b_type == self.TYPE_SETUP_FINALLY) or (block.b_type == self.TYPE_SETUP_EXCEPT and why == self.WHY_EXCEPTION): 186 | if why == self.WHY_EXCEPTION: 187 | exc, val, tb = self.fetch_error() 188 | self.push(tb) 189 | self.push(val) 190 | self.push(exc) 191 | 192 | why = self.WHY_NOT 193 | self.jumpto(block.b_handler) 194 | break 195 | 196 | if why != self.WHY_NOT: 197 | break 198 | 199 | self.get_thread_state().frame = frame.f_back 200 | return why 201 | 202 | def get_const(self, index): 203 | return self.frame.f_code.co_consts[index] 204 | 205 | def get_name(self, index): 206 | return self.frame.f_code.co_names[index] 207 | 208 | def build_class(self, methods, bases, name): 209 | 210 | # get meta 211 | if "__metaclass__" in methods: 212 | metaclass = methods['__metaclass__'] 213 | elif len(bases) > 0: 214 | metaclass = bases[0].__class__ 215 | if not metaclass: 216 | metaclass = type(bases[0]) 217 | else: 218 | metaclass = self.frame.f_globals.get('__metaclass__', None) 219 | if not metaclass: 220 | metaclass = type 221 | 222 | klass = metaclass(name, bases, methods) 223 | 224 | return klass 225 | 226 | def top(self): 227 | return self.frame.f_stack[-1] 228 | 229 | def set_top(self, value): 230 | self.frame.f_stack[-1] = value 231 | 232 | def push(self, value): 233 | self.frame.f_stack.append(value) 234 | 235 | def pop(self): 236 | return self.frame.f_stack.pop() 237 | 238 | def popn(self, n): 239 | if n: 240 | ret = self.frame.f_stack[-n:] 241 | self.frame.f_stack[-n:] = [] 242 | return ret 243 | else: 244 | return [] 245 | 246 | def get_fast_local(self, index): 247 | return self.frame.f_fast_local[index] 248 | 249 | def get_freevars(self, index): 250 | index = self.frame.f_code.co_nlocals + index 251 | return self.frame.f_fast_local[index] 252 | 253 | def set_fast_local(self, index, value): 254 | self.frame.f_fast_local[index] = value 255 | 256 | def jumpto(self, dest): 257 | self.frame.f_lasti = dest 258 | 259 | def jumpby(self, dest): 260 | self.frame.f_lasti += dest 261 | 262 | def stack_level(self): 263 | return len(self.frame.f_stack) 264 | 265 | def setup_block(self, frame, b_type, b_handler, b_level): 266 | block = PyBlock(b_type, b_handler, b_level) 267 | frame.block_stack.append(block) 268 | 269 | def eval_code(self, code, globals, locals, 270 | args, argcount, kws, kwcount, 271 | defs, defcount, closure): 272 | frame = PyFrameObject(self.get_thread_state(), code, globals, locals) 273 | 274 | while True: 275 | 276 | if (code.co_argcount > 0) or (code.co_flags & (PyCodeObject.CO_VARARGS | PyCodeObject.CO_VARKEYWORDS)): 277 | n = argcount 278 | kwd_dict = None 279 | # 设置扩展键参数为局部变量 280 | if code.co_flags & PyCodeObject.CO_VARKEYWORDS: 281 | kwd_dict = {} 282 | kwd_pos = code.co_argcount 283 | if code.co_flags & PyCodeObject.CO_VARARGS: 284 | kwd_pos += 1 285 | frame.f_fast_local[kwd_pos] = kwd_dict 286 | 287 | # 检测参数是否过多 288 | if argcount > code.co_argcount: 289 | if not (code.co_flags & PyCodeObject.CO_VARARGS): 290 | self.store_error(TypeError, 291 | "{} takes {} {} " 292 | "argument{} ({} given)".format( 293 | code.co_name, 294 | "at most" if defcount else 'exactly', 295 | code.co_argcount, 296 | "" if code.co_argcount == 1 else 's', 297 | argcount + kwcount)) 298 | break 299 | n = code.co_argcount 300 | 301 | frame.f_fast_local[:n] = args[:n] 302 | # 设置扩展参数为局部变量 303 | if code.co_flags & PyCodeObject.CO_VARARGS: 304 | u = tuple(args[n: argcount]) 305 | frame.f_fast_local[code.co_argcount] = u 306 | 307 | indexs = [] 308 | #---------------------- 键参数处理-----------------------# 309 | for i in range(kwcount): 310 | keyword = kws[2 * i] 311 | value = kws[2 * i + 1] 312 | 313 | # 获取键参数在局部变量列表里的索引 314 | index = None 315 | try: 316 | index = code.co_varnames.index(keyword) 317 | except ValueError: 318 | if kwd_dict == None: 319 | self.store_error(TypeError, 320 | "{} got an unexpected " 321 | "keyword argument '{}'".format(code.co_name, keyword)) 322 | break 323 | else: 324 | kwd_dict[keyword] = value 325 | 326 | if index: 327 | # 判断键参数是否有重复 328 | if index in indexs: 329 | self.store_error(TypeError, 330 | "{} got multiple " 331 | "values for keyword " 332 | "argument '{}".format(code.co_name, keyword)) 333 | break 334 | indexs.append(index) 335 | 336 | frame.f_fast_local[index] = value 337 | 338 | #------------------ 传入参数小于声明的参数,需要使用默认参数-------------# 339 | if argcount < code.co_argcount: 340 | # 位置参数 = 参数总数 - 被设置了默认值的位置参数(键参数) 341 | pos_args = code.co_argcount - defcount 342 | if argcount < pos_args: # 声明的位置参数 大于传入的位置参数 343 | self.store_error(TypeError, "param not enough") 344 | break 345 | 346 | replace = 0 347 | # 传入的位置参数大于声明的位置参数 , 说明要替换部分的默认参数 348 | if argcount > pos_args: 349 | replace = argcount - pos_args 350 | 351 | for x in range(replace, defcount): 352 | if pos_args + x not in indexs: # 之前键参数以修改过默认参数的跳过 353 | frame.f_fast_local[pos_args + x] = defs[x] 354 | 355 | # 设置内层约束变量 356 | if len(code.co_cellvars): 357 | nargs = code.co_argcount 358 | if code.co_flags & PyCodeObject.CO_VARARGS: 359 | nargs += 1 360 | if code.co_flags & PyCodeObject.CO_VARKEYWORDS: 361 | nargs += 1 362 | 363 | for index, cellname in enumerate(code.co_cellvars): 364 | found = 0 365 | if cellname in code.co_varnames: 366 | i = code.co_varnames.index(cellname) 367 | cell = PyCellObject(frame.f_fast_local[i]) 368 | else: 369 | cell = PyCellObject() 370 | 371 | frame.f_fast_local[code.co_nlocals + index] = cell 372 | 373 | # 设置自由变量 374 | if len(code.co_freevars): 375 | for index, cell in enumerate(closure): 376 | i = frame.f_code.co_nlocals + len(code.co_cellvars) + index 377 | frame.f_fast_local[i] = cell 378 | 379 | # 生成器对象 380 | if code.co_flags & PyCodeObject.CO_GENERATOR: 381 | frame.f_back = None 382 | return PyGenObject(frame) 383 | 384 | return self.eval_frame(frame, 0) 385 | 386 | def fast_function(self, func, stack, n, na, nk): 387 | co = func.func_code 388 | globals = func.func_globals 389 | argdefs = func.func_defaults 390 | 391 | if ((argdefs == None) 392 | and (co.co_argcount == n) 393 | and (nk == 0) 394 | and (co.co_flags == (PyCodeObject.CO_OPTIMIZED | PyCodeObject.CO_NEWLOCALS | PyCodeObject.CO_NOFREE))): 395 | frame = PyFrameObject(self.get_thread_state(), co, globals, None) 396 | frame.f_fast_local[:] = stack[-n:] # 将父堆栈的参数拷贝到子堆栈的位置参数中 397 | return self.eval_frame(frame, 0) 398 | else: 399 | return self.eval_code(co, # code object 400 | globals, # globals 401 | None, # locals 402 | stack[-n:], na, # args & argcount 403 | stack[-2 * nk:], nk, # kws & ckcount 404 | argdefs, len(argdefs), # defs & defcount 405 | func.func_closure) # clousure 406 | 407 | def call_function(self, stack, oparg): 408 | nk, na = divmod(oparg, 256) 409 | n = na + 2 * nk 410 | 411 | func = stack[-n - 1] 412 | 413 | x = self.fast_function(func, stack, n, na, nk) 414 | 415 | # 弹出子函数参数和子函数,堆栈恢复 416 | stack = stack[:-n - 1] 417 | return x 418 | 419 | def pop_block(self, frame): 420 | return frame.block_stack.pop() 421 | 422 | def detail_print(self, name, *args): 423 | if self.SHOW_DETAIL: 424 | print name 425 | 426 | UNARY_OPERATORS = { 427 | 'POSITIVE': operator.pos, # +a 428 | 'NEGATIVE': operator.neg, # -a 429 | 'NOT': operator.not_, # not a 430 | 'CONVERT': repr, 431 | 'INVERT': operator.invert, # ~ a 432 | } 433 | 434 | def unaryOperator(self, op): 435 | value = self.top() 436 | self.set_top(self.UNARY_OPERATORS[op](value)) 437 | 438 | BINARY_OPERATORS = { 439 | 'POWER': pow, # a**b 440 | 'MULTIPLY': operator.mul, # a * b 441 | 'DIVIDE': operator.div, # a / b __future__.division 没有生效 442 | 'FLOOR_DIVIDE': operator.floordiv, # a // b 443 | 'TRUE_DIVIDE': operator.truediv, # a/b __future__.division 生效 444 | 'MODULO': operator.mod, # a % b 445 | 'ADD': operator.add, # a + b 446 | 'SUBTRACT': operator.sub, # a - b 447 | 'SUBSCR': operator.getitem, # a[b] 448 | 'LSHIFT': operator.lshift, # a << b 449 | 'RSHIFT': operator.rshift, # a >> b 450 | 'AND': operator.and_, # a & b 451 | 'XOR': operator.xor, # a ^ b 452 | 'OR': operator.or_, # a | b 453 | } 454 | 455 | def binaryOperator(self, op): 456 | x, y = self.popn(2) 457 | self.push(self.BINARY_OPERATORS[op](x, y)) 458 | 459 | def inplaceOperator(self, op): 460 | y = self.pop() 461 | x = self.top() 462 | self.set_top(self.BINARY_OPERATORS[op](x, y)) 463 | 464 | COMPARE_OPERATORS = [ 465 | operator.lt, 466 | operator.le, 467 | operator.eq, 468 | operator.ne, 469 | operator.gt, 470 | operator.ge, 471 | lambda x, y: x in y, 472 | lambda x, y: x not in y, 473 | lambda x, y: x is y, 474 | lambda x, y: x is not y, 475 | lambda x, y: issubclass(x, Exception) and issubclass(x, y), 476 | ] 477 | 478 | def COMPARE_OP(self, opnum): 479 | self.detail_print("COMPARE_OP") 480 | y = self.pop() 481 | x = self.top() 482 | self.set_top(self.COMPARE_OPERATORS[opnum](x, y)) 483 | 484 | # cpython 会预测下条跳转指令, 这里不做类似优化了 485 | 486 | def sliceOperator(self, opname): 487 | start = 0 488 | end = None 489 | 490 | count = ord(opname[-1]) - ord('0') 491 | 492 | if count == 1: 493 | start = self.pop() 494 | elif count == 2: 495 | end = self.pop() 496 | elif count == 3: 497 | end = self.pop() 498 | start = self.pop() 499 | 500 | l = self.pop() 501 | if end is None: 502 | end = len(l) 503 | if opname.startswith('STORE_'): 504 | l[start:end] = self.pop() 505 | 506 | elif opname.startswith('DELETE_'): 507 | del l[start:end] 508 | 509 | else: 510 | self.push(l[start:end]) 511 | 512 | def POP_JUMP_IF_FALSE(self, addr): 513 | self.detail_print("POP_JUMP_IF_FALSE") 514 | 515 | value = self.pop() 516 | if not value: 517 | self.jumpto(addr) 518 | 519 | def POP_JUMP_IF_TRUE(self, addr): 520 | self.detail_print("POP_JUMP_IF_TRUE") 521 | 522 | val = self.pop() 523 | if val: 524 | self.jumpto(addr) 525 | 526 | def JUMP_FORWARD(self, addr): 527 | self.detail_print("JUMP_FORWARD") 528 | self.jumpby(addr) 529 | 530 | def SETUP_LOOP(self, dest): 531 | self.detail_print("SETUP_LOOP") 532 | self.setup_block(self.frame, self.TYPE_SETUP_LOOP, self.frame.f_lasti + dest, self.stack_level()) 533 | 534 | def SETUP_FINALLY(self, dest): 535 | self.detail_print("SETUP_FINALLY") 536 | self.setup_block(self.frame, self.TYPE_SETUP_FINALLY, self.frame.f_lasti + dest, self.stack_level()) 537 | 538 | def SETUP_EXCEPT(self, dest): 539 | self.detail_print("SETUP_EXCEPT") 540 | self.setup_block(self.frame, self.TYPE_SETUP_EXCEPT, self.frame.f_lasti + dest, self.stack_level()) 541 | 542 | # no test 543 | def RAISE_VARARGS(self, argc): 544 | self.detail_print("RAISE_VARARGS") 545 | 546 | exctype = None 547 | value = None 548 | tb = None 549 | 550 | if argc == 1: 551 | exctype = self.pop() 552 | elif argc == 2: 553 | value = self.pop() 554 | exctype = self.pop() 555 | elif argc == 3: 556 | tb = self.pop() 557 | value = self.pop() 558 | exctype = self.pop() 559 | elif argc != 0: 560 | print "!!!!!!" 561 | 562 | self.store_error(exctype, value, tb) 563 | 564 | return self.WHY_EXCEPTION 565 | 566 | def END_FINALLY(self): 567 | self.detail_print("END_FINALLY") 568 | v = self.pop() 569 | 570 | # 异常没有处理掉时,退出时重新抛出 571 | if v is None: 572 | return self.WHY_NOT 573 | elif issubclass(v, BaseException): 574 | val = self.pop() 575 | tb = self.pop() 576 | self.store_error(v, value, tb) 577 | 578 | return self.WHY_RERAISE 579 | 580 | def GET_ITER(self): 581 | self.detail_print("GET_ITER") 582 | 583 | value = self.top() 584 | value_iter = iter(value) 585 | if value_iter: 586 | self.set_top(value_iter) 587 | else: 588 | self.pop() 589 | 590 | def FOR_ITER(self, dest): 591 | self.detail_print("FOR_ITER") 592 | 593 | it = self.top() 594 | 595 | try: 596 | value = next(it) 597 | self.push(value) 598 | except StopIteration: 599 | self.pop() 600 | self.jumpby(dest) 601 | 602 | def POP_BLOCK(self): 603 | self.detail_print("POP_BLOCK") 604 | 605 | block = self.pop_block(self.frame) 606 | while self.stack_level() > block.b_level: 607 | self.pop() 608 | 609 | def BREAK_LOOP(self): 610 | self.detail_print("BREAK_LOOP") 611 | 612 | return self.WHY_BREAK 613 | 614 | def JUMP_ABSOLUTE(self, dest): 615 | self.detail_print("JUMP_ABSOLUTE") 616 | 617 | self.jumpto(dest) 618 | 619 | def POP_TOP(self): 620 | self.detail_print("POP_TOP") 621 | 622 | self.pop() 623 | 624 | def NOP(self): 625 | self.detail_print("NOP") 626 | 627 | pass 628 | 629 | def DUP_TOP(self): 630 | self.detail_print("DUP_TOP") 631 | self.push(self.top()) 632 | 633 | def ROT_TWO(self): 634 | self.detail_print("ROT_TWO") 635 | 636 | a, b = self.popn(2) 637 | self.push(b, a) 638 | 639 | def ROT_THREE(self): 640 | self.detail_print("ROT_THREE") 641 | 642 | a, b, c = self.popn(3) 643 | self.push(c, a, b) 644 | 645 | def ROT_FOUR(self): 646 | self.detail_print("ROT_FOUR") 647 | 648 | a, b, c, d = self.popn(4) 649 | self.push(d, a, b, c) 650 | 651 | def LOAD_CONST(self, index): 652 | self.detail_print("LOAD_CONST") 653 | 654 | value = self.get_const(index) 655 | self.push(value) 656 | 657 | def STORE_NAME(self, index): 658 | self.detail_print("STORE_NAME") 659 | 660 | name = self.get_name(index) 661 | value = self.pop() 662 | self.frame.f_locals[name] = value 663 | 664 | def STORE_MAP(self): 665 | self.detail_print("STORE_MAP") 666 | 667 | map, val, key = self.popn(3) 668 | map[key] = val 669 | self.push(map) 670 | 671 | def STORE_DEREF(self, index): 672 | self.detail_print("STORE_DEREF") 673 | value = self.pop() 674 | cell = self.get_freevars(index) 675 | cell.set(value) 676 | 677 | def STORE_SUBSCR(self): 678 | self.detail_print("STORE_SUBSCR") 679 | 680 | val, map, subscr = self.popn(3) 681 | map[subscr] = val 682 | 683 | def LOAD_DEREF(self, index): 684 | cell = self.get_freevars(index) 685 | obj = cell.get() 686 | self.push(obj) 687 | 688 | def LOAD_NAME(self, index): 689 | self.detail_print("LOAD_NAME") 690 | 691 | name = self.get_name(index) 692 | frame = self.frame 693 | if name in frame.f_locals: 694 | value = frame.f_locals[name] 695 | elif name in frame.f_globals: 696 | value = frame.f_globals[name] 697 | elif name in frame.f_builtins: 698 | value = frame.f_builtins[name] 699 | else: 700 | raise NameError("name '{}' is not defined".format(name)) 701 | self.push(value) 702 | 703 | def LOAD_GLOBAL(self, args): 704 | self.detail_print("LOAD_GLOBAL") 705 | 706 | name = self.get_name(args) 707 | self.push(self.frame.f_globals[name]) 708 | 709 | def LOAD_LOCALS(self): 710 | self.detail_print("LOAD_LOCALS") 711 | self.push(self.frame.f_locals) 712 | 713 | def LOAD_FAST(self, index): 714 | self.detail_print("LOAD_FAST") 715 | 716 | value = self.get_fast_local(index) 717 | self.push(value) 718 | 719 | def LOAD_CLOSURE(self, index): 720 | self.detail_print("LOAD_CLOSURE") 721 | 722 | cell = self.get_freevars(index) 723 | self.push(cell) 724 | 725 | def MAKE_CLOSURE(self, arg_num): 726 | self.detail_print("MAKE_CLOSURE") 727 | 728 | co = self.pop() 729 | func = PyFunctionObject(co, self.frame.f_globals) 730 | 731 | cells = self.pop() 732 | func.set_closure(cells) 733 | 734 | if arg_num > 0: 735 | func.func_defaults = self.popn(arg_num) 736 | 737 | self.push(func) 738 | 739 | def STORE_FAST(self, index): 740 | self.detail_print("STORE_FAST") 741 | 742 | value = self.pop() 743 | self.set_fast_local(index, value) 744 | 745 | def BUILD_MAP(self, _): 746 | self.detail_print("BUILD_MAP") 747 | 748 | self.push({}) 749 | 750 | def BUILD_TUPLE(self, num): 751 | self.detail_print("BUILD_TUPLE") 752 | 753 | value = self.popn(num) 754 | self.push(tuple(value)) 755 | 756 | def BUILD_LIST(self, num): 757 | self.detail_print("BUILD_LIST") 758 | 759 | value = self.popn(num) 760 | self.push(value) 761 | 762 | def BUILD_SET(self, num): 763 | self.detail_print("BUILD_SET") 764 | 765 | values = self.popn(num) 766 | self.push(set(values)) 767 | 768 | def BUILD_CLASS(self): 769 | methods = self.top() 770 | bases = self.pop() 771 | name = self.pop() 772 | klass = self.build_class(methods, bases, name) 773 | self.set_top(klass) 774 | 775 | def MAKE_FUNCTION(self, oparg): 776 | self.detail_print("MAKE_FUNCTION") 777 | 778 | code = self.pop() 779 | func = PyFunctionObject(code, self.frame.f_globals) 780 | 781 | if func and oparg > 0: 782 | func.func_defaults = self.popn(oparg) 783 | 784 | self.push(func) 785 | 786 | def CALL_FUNCTION(self, oparg): 787 | self.detail_print("CALL_FUNCTION") 788 | 789 | sp = self.frame.f_stack 790 | x = self.call_function(sp, oparg) 791 | 792 | self.frame = self.get_thread_state().frame 793 | 794 | if x == self.WHY_RETURN: 795 | self.push(self.ret_value) 796 | else: 797 | self.push(x) 798 | 799 | def BUILD_SLICE(self, oparg): 800 | step = None 801 | if oparg == 3: 802 | step = self.pop() 803 | end = self.pop() 804 | start = self.top() 805 | self.set_top(slice(start, end, step)) 806 | 807 | def PRINT_ITEM(self): 808 | value = self.pop() 809 | self.outstream(value, False) 810 | 811 | def PRINT_NEWLINE(self): 812 | self.outstream('') 813 | 814 | def RETURN_VALUE(self): 815 | self.ret_value = self.pop() 816 | return self.WHY_RETURN 817 | --------------------------------------------------------------------------------