Advertisement
Guest User

Untitled

a guest
Mar 31st, 2020
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.76 KB | None | 0 0
  1. """
  2. Simplified VM code which works for some cases.
  3. You need extend/rewrite code to pass all cases.
  4. """
  5.  
  6. import builtins
  7. import dis
  8. import types
  9. import typing as tp
  10. import operator
  11. import sys
  12.  
  13.  
  14. class Frame:
  15. def __init__(self, f_code: types.CodeType,
  16. f_locals: tp.Dict[str, tp.Any],
  17. f_globals: tp.Dict[str, tp.Any],
  18. f_prev: tp.Any):
  19. self.f_code = f_code
  20. self.f_globals = f_globals
  21. self.f_locals = f_locals
  22. self.f_prev = f_prev
  23. self.stack: tp.Any = []
  24. self.block_stack: tp.Any = []
  25.  
  26. if f_prev:
  27. self.f_builtins = f_prev.f_builtins
  28. else:
  29. self.f_builtins = builtins.__dict__
  30.  
  31. self.cur_idx = 0
  32. self.co_names = f_code.co_names
  33. self.co_consts = f_code.co_consts
  34. self.co_varnames = f_code.co_varnames
  35. self.instructions = list(dis.get_instructions(f_code))
  36.  
  37.  
  38. def equal_type(l: tp.Any, r: tp.Any) -> bool:
  39. return isinstance(l, type(r))
  40.  
  41.  
  42. class Block(object):
  43. def __init__(self, type: tp.Any, handler: tp.Any, frame: tp.Any) -> None:
  44. self.type = type
  45. self.handler = handler
  46. self.frame = frame
  47.  
  48.  
  49. def build_code_object() -> types.CodeType:
  50. code_str = ''
  51. return compile(code_str, '', 'exec')
  52.  
  53.  
  54. frame_object = Frame(build_code_object(), {}, {}, {})
  55.  
  56.  
  57. class VirtualMachine:
  58. def __init__(self) -> None:
  59. self.frames: tp.Any = []
  60. self.frame = frame_object # Remove it later (change for None)
  61. self.last_exception: tp.Any = ()
  62. self.value = None
  63.  
  64. self.operations = {
  65. 'POWER': operator.pow,
  66. 'MULTIPLY': operator.mul,
  67. 'MATRIX_MULTIPLY': operator.matmul,
  68. 'FLOOR_DIVIDE': operator.floordiv,
  69. 'TRUE_DIVIDE': operator.truediv,
  70. 'MODULO': operator.mod,
  71. 'ADD': operator.add,
  72. 'SUBTRACT': operator.sub,
  73. 'SUBSCR': operator.getitem,
  74. 'LSHIFT': operator.lshift,
  75. 'RSHIFT': operator.rshift,
  76. 'AND': operator.and_,
  77. 'XOR': operator.xor,
  78. 'OR': operator.or_,
  79. }
  80.  
  81. self.compare_funcs = {
  82. '<': operator.lt,
  83. '<=': operator.le,
  84. '==': operator.eq,
  85. '!=': operator.ne,
  86. '>=': operator.ge,
  87. '>': operator.gt,
  88. 'in': lambda x, y: x in y,
  89. 'not in': lambda x, y: x not in y,
  90. 'is': lambda x, y: x is y,
  91. 'is not': lambda x, y: x is not y,
  92. 'exception match': equal_type,
  93. }
  94.  
  95. def run(self, code: types.CodeType) -> None:
  96. """
  97. :param code: code for interpreting
  98. """
  99. frame = Frame(code, {}, {}, None)
  100. self.run_frame(frame)
  101.  
  102. def pop_frame(self) -> tp.Any:
  103. self.frames.pop()
  104. self.frame = self.frames[-1] if self.frames else None
  105.  
  106. def push_frame(self, frame: tp.Any) -> None:
  107. self.frames.append(frame)
  108. self.frame = frame
  109.  
  110. def push(self, *args: tp.Any) -> tp.Any:
  111. for arg in args:
  112. self.frame.stack.append(arg)
  113.  
  114. def pop(self) -> tp.Any:
  115. return self.frame.stack.pop()
  116.  
  117. def popn(self, n: int) -> tp.Any:
  118. return list(reversed([self.pop() for _ in range(n)])) if n else []
  119.  
  120. def top(self) -> tp.Any:
  121. return self.frame.stack[-1]
  122.  
  123. def pop_block(self) -> tp.Any:
  124. return self.frame.block_stack.pop()
  125.  
  126. def push_block(self, type: tp.Any, delta: tp.Any = None) -> tp.Any:
  127. self.frame.block_stack.append(Block(type, delta, self.frame))
  128.  
  129. def parse_byte_and_args(self) -> tp.Tuple[str, tp.Optional[int]]:
  130. instruction = self.frame.instructions[self.frame.cur_idx]
  131. byte_name = instruction.opname
  132. arg = instruction.arg
  133. self.frame.cur_idx += 1
  134. return byte_name, arg
  135.  
  136. def run_func(self, byte_name: str, argument: tp.Optional[int]) -> tp.Any:
  137. try:
  138. result = None
  139. if byte_name.split("_")[0] == "BINARY":
  140. self.run_binary_operation(byte_name)
  141. elif byte_name.split("_")[0] == "INPLACE":
  142. self.run_inplace_operation(byte_name)
  143. else:
  144. bytecode_fn = getattr(self, byte_name.lower() + '_op')
  145. if argument is None:
  146. result = bytecode_fn()
  147. else:
  148. result = bytecode_fn(argument)
  149. except Exception:
  150. result = 'exception'
  151. self.last_exception = sys.exc_info()[:2] + (None,)
  152. return result
  153.  
  154. def handle_exception(self) -> bool:
  155. if self.frame.block_stack:
  156. cur_block = self.pop_block()
  157. if cur_block.type == "except":
  158. self.push_block('except-handler')
  159. exc_type, value, tb = self.last_exception
  160. self.push(tb, value, exc_type)
  161. self.push(tb, value, exc_type)
  162. self.frame.cur_idx = cur_block.delta
  163. return True
  164. return False
  165.  
  166. def run_frame(self, frame: tp.Any) -> tp.Any:
  167. self.push_frame(frame)
  168. func_result: tp.Any = None
  169. while len(self.frame.instructions) > frame.cur_idx:
  170. byte_name, arg = self.parse_byte_and_args()
  171. func_result = self.run_func(byte_name, arg)
  172. if func_result == "exception":
  173. handled = self.handle_exception()
  174. if not handled:
  175. exception, value, traceback = self.last_exception
  176. exc = exception(value)
  177. exc.__traceback__ = traceback
  178. raise exc
  179. if func_result == "yield":
  180. func_result = False
  181. break
  182.  
  183. self.pop_frame()
  184. return func_result
  185.  
  186. def run_binary_operation(self, operation: str) -> None:
  187. arg1, arg2 = self.popn(2)
  188. operation_name = operation.replace("BINARY_", "")
  189. self.push(self.operations[operation_name](arg1, arg2))
  190.  
  191. def run_inplace_operation(self, operation: str) -> None:
  192. arg1, arg2 = self.popn(2)
  193. operation_name = operation.replace("INPLACE_", "")
  194. self.push(self.operations[operation_name](arg1, arg2))
  195.  
  196. def call_function_op(self, arg: int) -> None:
  197. args = self.popn(arg)
  198. f = self.pop()
  199. self.push(f(*args))
  200.  
  201. def load_name_op(self, arg: tp.Any) -> None:
  202. name = self.frame.co_names[arg]
  203. if name in self.frame.f_locals:
  204. val = self.frame.f_locals[name]
  205. elif name in self.frame.f_globals:
  206. val = self.frame.f_globals[name]
  207. elif name in self.frame.f_builtins:
  208. val = self.frame.f_builtins[name]
  209. else:
  210. raise NameError("name '%s' is not defined" % name)
  211. self.push(val)
  212.  
  213. def load_global_op(self, arg: tp.Any) -> None:
  214. name = self.frame.co_names[arg]
  215. if name in self.frame.f_globals:
  216. val = self.frame.f_globals[name]
  217. elif name in self.frame.f_builtins:
  218. val = self.frame.f_builtins[name]
  219. else:
  220. raise NameError("global name '%s' is not defined" % name)
  221.  
  222. self.push(val)
  223.  
  224. def load_const_op(self, arg: tp.Any) -> None:
  225. self.push(self.frame.co_consts[arg])
  226.  
  227. def return_value_op(self) -> tp.Any:
  228. return self.pop()
  229.  
  230. def pop_top_op(self) -> None:
  231. self.pop()
  232.  
  233. def make_function_op(self, arg: int) -> None:
  234. def fill_args() -> None:
  235. if arg & 0x08:
  236. parsed_args['closure'] = self.pop()
  237. if arg & 0x04:
  238. parsed_args['annotations'] = self.pop()
  239. if arg & 0x02:
  240. parsed_args['kwdefaults'] = self.pop()
  241. if arg & 0x01:
  242. parsed_args['defaults'] = self.pop()
  243.  
  244. func_code, func_name = self.popn(2)
  245. parsed_args: tp.Dict[str, tp.Any] = {}
  246. fill_args()
  247.  
  248. func = Function(func_name, func_code, self.frame.f_globals, self, arg, parsed_args)
  249.  
  250. self.push(func)
  251.  
  252. def store_name_op(self, arg: tp.Any) -> None:
  253. self.frame.f_locals[self.frame.co_names[arg]] = self.pop()
  254.  
  255. def store_global_op(self, arg: tp.Any) -> None:
  256. self.frame.f_globals[self.frame.co_names[arg]] = self.pop()
  257.  
  258. def compare_op_op(self, name: tp.Any) -> None:
  259. arg1, arg2 = self.popn(2)
  260. self.push(self.compare_funcs[dis.cmp_op[name]](arg1, arg2))
  261.  
  262.  
  263. class Function(object):
  264. def __init__(self, name: tp.Any, code: tp.Any, globals_nm: tp.Any, vm: tp.Any,
  265. argc: tp.Any, kwargs_defaults: tp.Any) -> None:
  266. self.__name__ = name
  267. self.__doc__ = code.co_consts[0] if code.co_consts else None
  268.  
  269. self.code = code
  270. self.f_globals = dict(globals_nm)
  271. self.f_globals.update(vm.frame.f_locals)
  272. self.f_globals.update({name: self})
  273. self.var_names = self.code.co_varnames
  274. self.f_locals = {"__name__": self.code.co_name}
  275. self.f_locals.update(kwargs_defaults.get("closure", {}))
  276. self.f_locals.update(kwargs_defaults.get("kwdefaults", {}))
  277. self.defaults = kwargs_defaults.get("defaults", ())
  278. self.vm = vm
  279.  
  280. self.args_used = False
  281. if self.code.co_flags & 0x04:
  282. # function uses the *arguments
  283. self.args_used = True
  284.  
  285. self.kwargs_used = False
  286. if self.code.co_flags & 0x08:
  287. # function uses the **keywords
  288. self.kwargs_used = True
  289. self.is_generator = False
  290. if self.code.co_flags & 0x20:
  291. # the function is a generator
  292. self.is_generator = True
  293.  
  294. def __call__(self, *args: tp.Any, **kwargs: tp.Any) -> tp.Any:
  295. self.handle_args_kwargs(*args, **kwargs)
  296. self.frame = Frame(self.code, self.f_locals, self.f_globals, self.vm.frame)
  297.  
  298. return self.vm.run_frame(self.frame)
  299.  
  300. @staticmethod
  301. def check_func(args: tp.Any, code: tp.Any, defaults: tp.Any) -> tp.Any:
  302. if len(args) > code.co_argcount:
  303. raise TypeError()
  304. if len(args) + len(defaults) < code.co_argcount:
  305. raise TypeError()
  306.  
  307. def handle_args_kwargs(self, *args: tp.Any, **kwargs: tp.Any) -> tp.Any:
  308. if not self.args_used:
  309. Function.check_func(args, self.code, self.defaults)
  310. self.f_locals.update({self.var_names[i]: args[i] for i in range(len(args))})
  311. defaults_took = len(args) + len(self.defaults) - self.code.co_argcount
  312. if defaults_took < 0:
  313. raise NotImplementedError
  314. for i in range(len(args), self.code.co_argcount):
  315. self.f_locals[self.var_names[i]] = self.defaults[defaults_took + i - len(args)]
  316.  
  317. for key in self.var_names[:self.code.co_argcount]:
  318. if key in kwargs:
  319. self.f_locals[key] = kwargs[key]
  320. del kwargs[key]
  321.  
  322. if self.kwargs_used:
  323. self.f_locals[self.var_names[self.code.co_argcount]] = kwargs
  324. else:
  325. self.f_locals.update({self.var_names[i]: args[i] for i in range(self.code.co_argcount)})
  326. args_left = args[self.code.co_argcount:]
  327.  
  328. if self.kwargs_used:
  329. for key in self.var_names[self.code.co_argcount:self.code.co_argcount + self.code.co_kwonlyargcount]:
  330. if key in kwargs:
  331. self.f_locals[key] = kwargs[key]
  332. del kwargs[key]
  333. self.f_locals[self.var_names[self.code.co_argcount + self.code.co_kwonlyargcount + 1]] = kwargs
  334. self.f_locals[self.var_names[self.code.co_argcount + self.code.co_kwonlyargcount]] = args_left
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement