Advertisement
Guest User

Untitled

a guest
Mar 31st, 2020
256
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.19 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. import collections
  13.  
  14.  
  15. class Frame:
  16. def __init__(self, f_code: types.CodeType,
  17. f_locals: tp.Dict[str, tp.Any],
  18. f_globals: tp.Dict[str, tp.Any],
  19. f_prev: tp.Any):
  20. self.f_code = f_code
  21. self.f_globals = f_globals
  22. self.f_locals = f_locals
  23. self.f_prev = f_prev
  24. self.stack: tp.Any = []
  25. self.block_stack: tp.Any = []
  26.  
  27. if f_prev:
  28. self.builtins = f_prev.builtins
  29. else:
  30. self.builtins = builtins.__dict__
  31.  
  32. self.cur_idx = 0
  33. self.co_names = f_code.co_names
  34. self.co_consts = f_code.co_consts
  35. self.co_varnames = f_code.co_varnames
  36. self.instructions = list(dis.get_instructions(f_code))
  37.  
  38.  
  39. def equal_type(l: tp.Any, r: tp.Any) -> bool:
  40. return isinstance(l, type(r))
  41.  
  42.  
  43. class Block(object):
  44. def __init__(self, type: tp.Any, handler: tp.Any, frame: tp.Any) -> None:
  45. self.type = type
  46. self.handler = handler
  47. self.frame = frame
  48.  
  49.  
  50. def build_code_object() -> types.CodeType:
  51. code_str = ''
  52. return compile(code_str, '', 'exec')
  53.  
  54.  
  55. frame_object = Frame(build_code_object(), {}, {}, {})
  56.  
  57.  
  58. class VirtualMachine:
  59. def __init__(self) -> None:
  60. self.frames: tp.Any = []
  61. self.frame = frame_object # Remove it later (change for None)
  62. self.last_exception: tp.Any = ()
  63. self.value = None
  64.  
  65. self.operations = {
  66. 'POWER': operator.pow,
  67. 'MULTIPLY': operator.mul,
  68. 'MATRIX_MULTIPLY': operator.matmul,
  69. 'FLOOR_DIVIDE': operator.floordiv,
  70. 'TRUE_DIVIDE': operator.truediv,
  71. 'MODULO': operator.mod,
  72. 'ADD': operator.add,
  73. 'SUBTRACT': operator.sub,
  74. 'SUBSCR': operator.getitem,
  75. 'LSHIFT': operator.lshift,
  76. 'RSHIFT': operator.rshift,
  77. 'AND': operator.and_,
  78. 'XOR': operator.xor,
  79. 'OR': operator.or_,
  80. }
  81.  
  82. self.compare_funcs = {
  83. '<': operator.lt,
  84. '<=': operator.le,
  85. '==': operator.eq,
  86. '!=': operator.ne,
  87. '>=': operator.ge,
  88. '>': operator.gt,
  89. 'in': lambda x, y: x in y,
  90. 'not in': lambda x, y: x not in y,
  91. 'is': lambda x, y: x is y,
  92. 'is not': lambda x, y: x is not y,
  93. 'exception match': equal_type,
  94. }
  95.  
  96. def run(self, code: types.CodeType) -> None:
  97. """
  98. :param code: code for interpreting
  99. """
  100. frame = Frame(code, {}, {}, None)
  101. self.run_frame(frame)
  102.  
  103. def pop_frame(self) -> tp.Any:
  104. self.frames.pop()
  105. self.frame = self.frames[-1] if self.frames else None
  106.  
  107. def push_frame(self, frame: tp.Any) -> None:
  108. self.frames.append(frame)
  109. self.frame = frame
  110.  
  111. def push(self, *args: tp.Any) -> tp.Any:
  112. for arg in args:
  113. self.frame.stack.append(arg)
  114.  
  115. def pop(self) -> tp.Any:
  116. return self.frame.stack.pop()
  117.  
  118. def popn(self, n: int) -> tp.Any:
  119. return list(reversed([self.pop() for _ in range(n)])) if n else []
  120.  
  121. def top(self) -> tp.Any:
  122. return self.frame.stack[-1]
  123.  
  124. def pop_block(self) -> tp.Any:
  125. return self.frame.block_stack.pop()
  126.  
  127. def push_block(self, type: tp.Any, delta: tp.Any = None) -> tp.Any:
  128. self.frame.block_stack.append(Block(type, delta, self.frame))
  129.  
  130. def parse_byte_and_args(self) -> tp.Tuple[str, tp.Optional[int]]:
  131. instruction = self.frame.instructions[self.frame.cur_idx]
  132. byte_name = instruction.opname
  133. arg = instruction.arg
  134. self.frame.cur_idx += 1
  135. return byte_name, arg
  136.  
  137. def run_func(self, byte_name: str, argument: tp.Optional[int]) -> str:
  138. try:
  139. result = ''
  140. if byte_name.split("_")[0] == "BINARY":
  141. self.run_binary_operation(byte_name)
  142. elif byte_name.split("_")[0] == "INPLACE":
  143. self.run_inplace_operation(byte_name)
  144. else:
  145. bytecode_fn = getattr(self, byte_name)
  146. result = bytecode_fn() if argument is None else bytecode_fn(argument)
  147. except Exception:
  148. result = 'exception'
  149. self.last_exception = sys.exc_info()[:2] + (None,)
  150. return result
  151.  
  152. def handle_exception(self) -> bool:
  153. if self.frame.block_stack:
  154. cur_block = self.pop_block()
  155. if cur_block.type == "except":
  156. self.push_block('except-handler')
  157. exc_type, value, tb = self.last_exception
  158. self.push(tb, value, exc_type)
  159. self.push(tb, value, exc_type)
  160. self.frame.cur_idx = cur_block.delta
  161. return True
  162. return False
  163.  
  164. def run_frame(self, frame: tp.Any) -> tp.Any:
  165. self.push_frame(frame)
  166. func_result: tp.Any = None
  167. while len(self.frame.instructions) > frame.cur_idx:
  168. byte_name, arg = self.parse_byte_and_args()
  169. func_result = self.run_func(byte_name, arg)
  170. if func_result == "exception":
  171. handled = self.handle_exception()
  172. if not handled:
  173. exception, value, traceback = self.last_exception
  174. exc = exception(value)
  175. exc.__traceback__ = traceback
  176. raise exc
  177. if func_result == "yield":
  178. func_result = False
  179. break
  180.  
  181. self.pop_frame()
  182. return func_result
  183.  
  184. def find_associated(self, name: str) -> str:
  185. if name in self.frame.f_locals:
  186. val = self.frame.f_locals[name]
  187. elif name in self.frame.co_varnames:
  188. raise UnboundLocalError("local variable '%s' referenced before assignment" % name)
  189. elif name in self.frame.f_globals:
  190. val = self.frame.f_globals[name]
  191. elif name in self.frame.builtins:
  192. val = self.frame.builtins[name]
  193. else:
  194. raise NameError("variable '%s' is not defined" % name)
  195. return val
  196.  
  197. def run_binary_operation(self, operation: str) -> None:
  198. arg1, arg2 = self.popn(2)
  199. operation_name = operation.replace("BINARY_", "")
  200. self.push(self.operations[operation_name](arg1, arg2))
  201.  
  202. def run_inplace_operation(self, operation: str) -> None:
  203. arg1, arg2 = self.popn(2)
  204. operation_name = operation.replace("INPLACE_", "")
  205. self.push(self.operations[operation_name](arg1, arg2))
  206.  
  207. def NOP(self) -> None:
  208. pass
  209.  
  210. def POP_TOP(self) -> None:
  211. self.pop()
  212.  
  213. def ROT_TWO(self) -> None:
  214. """Swaps the two top - most stack items."""
  215. tos1, tos = self.popn(2)
  216. self.push(tos)
  217. self.push(tos1)
  218.  
  219. def ROT_THREE(self) -> None:
  220. """
  221. Lifts second and third stack item one position up, moves top down to position three.
  222. """
  223. tos2, tos1, tos = self.popn(3)
  224. self.push(tos, tos2, tos1)
  225. self.push(tos, tos2, tos1)
  226.  
  227. def DUP_TOP(self) -> None:
  228. """Duplicates the reference on top of the stack."""
  229. self.push(self.top())
  230.  
  231. def DUP_TOP_TWO(self) -> None:
  232. """Duplicates the two references on top of the stack,
  233. leaving them in the same order."""
  234. tos1, tos = self.popn(2)
  235. self.push(tos1, tos, tos1, tos)
  236.  
  237. def UNARY_POSITIVE(self) -> None:
  238. """Implements TOS = +TOS."""
  239. self.push(+self.pop())
  240.  
  241. def UNARY_NEGATIVE(self) -> None:
  242. """Implements TOS = -TOS."""
  243. self.push(-self.pop())
  244.  
  245. def UNARY_NOT(self) -> None:
  246. """Implements TOS = not TOS."""
  247. self.push(not self.pop())
  248.  
  249. def UNARY_INVERT(self) -> None:
  250. """Implements TOS = ~TOS."""
  251. self.push(~self.pop())
  252.  
  253. def GET_ITER(self) -> None:
  254. """Implements TOS = iter(TOS)."""
  255. self.push(iter(self.pop()))
  256.  
  257. def GET_YIELD_FROM_ITER(self) -> None:
  258. """
  259. If TOS is a generator iterator or coroutine object it is left as is.
  260. Otherwise, implements TOS = iter(TOS).
  261. """
  262. if not isinstance(self.top(), collections.Iterable):
  263. self.GET_ITER()
  264.  
  265. def LOAD_NAME(self, namei: tp.Any) -> None:
  266. """Pushes the value associated with co_names[namei] onto the stack."""
  267. name = self.frame.co_names[namei]
  268. self.push(self.find_associated(name))
  269.  
  270. def LOAD_CONST(self, consti: tp.Any) -> None:
  271. """Pushes co_consts[consti] onto the stack."""
  272. self.push(self.frame.co_consts[consti])
  273.  
  274. def CALL_FUNCTION(self, argc: int) -> None:
  275. args = self.popn(argc)
  276. func = self.pop()
  277. val = func(*args)
  278. self.push(val)
  279.  
  280. def RETURN_VALUE(self) -> None:
  281. return self.pop()
  282.  
  283. def YIELD_VALUE(self) -> str:
  284. """Pops TOS and yields it from a generator."""
  285. self.value = self.pop()
  286. return "yield"
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement