Advertisement
Guest User

vm

a guest
Mar 31st, 2020
189
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 19.95 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.  
  11.  
  12. class Frame:
  13.     """
  14.    Frame header in cpython with description
  15.        https://github.com/python/cpython/blob/3.6/Include/frameobject.h#L17
  16.  
  17.    Text description of frame parameters
  18.        https://docs.python.org/3/library/inspect.html?highlight=frame#types-and-members
  19.    """
  20.     def __init__(self,
  21.                  frame_code: types.CodeType,
  22.                  frame_builtins: tp.Dict[str, tp.Any],
  23.                  frame_globals: tp.Dict[str, tp.Any],
  24.                  frame_locals: tp.Dict[str, tp.Any]) -> None:
  25.         self.code = frame_code
  26.         self.builtins = frame_builtins
  27.         self.globals = frame_globals
  28.         self.locals = frame_locals
  29.         self.data_stack: tp.Any = []
  30.         self.return_value = None
  31.         self.block_stack: tp.Any = []
  32.         self.last_exception = None
  33.         self.next_instr = None
  34.         self.jump_pos = 0
  35.  
  36.     def top(self) -> tp.Any:
  37.         return self.data_stack[-1]
  38.  
  39.     def pop(self) -> tp.Any:
  40.         return self.data_stack.pop()
  41.  
  42.     def pop_block_op(self) -> tp.Any:
  43.         return self.block_stack.pop()
  44.  
  45.     """"
  46.    def unwind_block(self, block: tp.Any) -> None:
  47.        if block.type == 'except-handler':
  48.            offset = 3
  49.        else:
  50.            offset = 0
  51.        while len(self.data_stack) > block.level + offset:
  52.            self.pop()
  53.        if block.type == 'except-handler':
  54.            tb, value, exctype = self.popn(3)
  55.            self.last_exception = exctype, value, tb
  56.    """
  57.  
  58.     def push(self, *values: tp.Any) -> None:
  59.         self.data_stack.extend(values)
  60.  
  61.     def popn(self, n: int) -> tp.Any:
  62.         """
  63.        Pop a number of values from the value stack.
  64.        A list of n values is returned, the deepest value first.
  65.        """
  66.         if n > 0:
  67.             returned = self.data_stack[-n:]
  68.             self.data_stack[-n:] = []
  69.             return returned
  70.         else:
  71.             return []
  72.  
  73.     def run(self) -> tp.Any:
  74.         current_pos = 0
  75.         instr_list = list(dis.get_instructions(self.code))
  76.         while current_pos < len(instr_list):
  77.             instruction = instr_list[current_pos]
  78.             if current_pos < len(instr_list) - 1:
  79.                 self.next_instr = instr_list[current_pos + 1].argval
  80.             getattr(self, instruction.opname.lower() + "_op")(instruction.argval)
  81.             if self.jump_pos:
  82.                 current_pos = 0
  83.                 for inst in instr_list:
  84.                     if inst.offset >= self.jump_pos:
  85.                         break
  86.                     current_pos += 1
  87.                 self.jump_pos = 0
  88.             else:
  89.                 current_pos += 1
  90.         return self.return_value
  91.  
  92.     def call_function_op(self, arg: int) -> None:
  93.         """
  94.        Operation description:
  95.            https://docs.python.org/3/library/dis.html#opcode-CALL_FUNCTION
  96.  
  97.        Operation realization:
  98.            https://github.com/python/cpython/blob/3.7/Python/ceval.c#L3121
  99.        """
  100.         arguments = self.popn(arg)
  101.         f = self.pop()
  102.         self.push(f(*arguments))
  103.  
  104.     def call_function_kw_op(self, args: int) -> None:
  105.         keys = self.pop()
  106.         values = self.popn(len(keys))
  107.         arguments = self.popn(args - len(keys))
  108.         kwargs = {key: value for key, value in zip(keys, values)}
  109.         func = self.pop()
  110.         self.push(func(*arguments, **kwargs))
  111.  
  112.     def load_name_op(self, arg: str) -> None:
  113.         """
  114.        Partial realization
  115.  
  116.        Operation description:
  117.            https://docs.python.org/3/library/dis.html#opcode-LOAD_NAME
  118.  
  119.        Operation realization:
  120.            https://github.com/python/cpython/blob/3.7/Python/ceval.c#L2057
  121.        """
  122.         # TODO: parse all scopes
  123.         if arg in self.locals:
  124.             self.push(self.locals[arg])
  125.         elif arg in self.globals:
  126.             self.push(self.globals[arg])
  127.         elif arg in self.builtins:
  128.             self.push(self.builtins[arg])
  129.         else:
  130.             raise NameError
  131.  
  132.     def load_global_op(self, arg: str) -> None:
  133.         """
  134.        Operation description:
  135.            https://docs.python.org/3/library/dis.html#opcode-LOAD_GLOBAL
  136.  
  137.        Operation realization:
  138.            https://github.com/python/cpython/blob/3.7/Python/ceval.c#L2108
  139.        """
  140.         # TODO: parse all scopes
  141.         if arg in self.globals:
  142.             self.push(self.globals[arg])
  143.         elif arg in self.builtins:
  144.             self.push(self.builtins[arg])
  145.         else:
  146.             raise NameError
  147.  
  148.     def load_const_op(self, arg: tp.Any) -> None:
  149.         """
  150.        Operation description:
  151.            https://docs.python.org/3/library/dis.html#opcode-LOAD_CONST
  152.  
  153.        Operation realization:
  154.            https://github.com/python/cpython/blob/3.7/Python/ceval.c#L1088
  155.        """
  156.         self.push(arg)
  157.  
  158.     def load_fast_op(self, name: str) -> None:
  159.         self.push(self.locals[name])
  160.  
  161.     def store_fast_op(self, name: str) -> None:
  162.         if name in self.locals:
  163.             self.locals[name] = self.pop()
  164.         else:
  165.             raise UnboundLocalError
  166.  
  167.     def delete_fast_op(self, name: str) -> None:
  168.         if name in self.locals:
  169.             del self.locals[name]
  170.         else:
  171.             raise UnboundLocalError
  172.  
  173.     def load_attr_op(self, attr: str) -> None:
  174.         obj = self.pop()
  175.         val = getattr(obj, attr)
  176.         self.push(val)
  177.  
  178.     def store_attr_op(self, name: str) -> None:
  179.         val, obj = self.popn(2)
  180.         setattr(obj, name, val)
  181.  
  182.     def delete_attr_op(self, name: str) -> None:
  183.         obj = self.pop()
  184.         delattr(obj, name)
  185.  
  186.     def delete_global_op(self, name: str) -> None:
  187.         del self.globals[name]
  188.  
  189.     def delete_name_op(self, name: str) -> None:
  190.         del self.locals[name]
  191.  
  192.     def return_value_op(self, arg: tp.Any) -> None:
  193.         """
  194.        Operation description:
  195.            https://docs.python.org/3/library/dis.html#opcode-RETURN_VALUE
  196.  
  197.        Operation realization:
  198.            https://github.com/python/cpython/blob/3.7/Python/ceval.c#L1641
  199.        """
  200.         self.return_value = self.pop()
  201.  
  202.     def pop_top_op(self, arg: tp.Any) -> None:
  203.         """
  204.        Operation description:
  205.            https://docs.python.org/3/library/dis.html#opcode-POP_TOP
  206.  
  207.        Operation realization:
  208.            https://github.com/python/cpython/blob/3.7/Python/ceval.c#L1102
  209.        """
  210.         self.pop()
  211.  
  212.     def import_name_op(self, name: str) -> None:
  213.         lvl, froml = self.popn(2)
  214.         self.push(__import__(name, self.globals, self.locals, froml, lvl))
  215.  
  216.     def import_from_op(self, name: str) -> None:
  217.         self.push(getattr(self.top(), name))
  218.  
  219.     def import_star_op(self, arg: tp.Any = None) -> None:
  220.         mod = self.pop()
  221.         for attr in dir(mod):
  222.             if attr[0] != '_':
  223.                 self.locals[attr] = getattr(mod, attr)
  224.  
  225.     def make_function_op(self, arg: int) -> None:
  226.         """
  227.        Operation description:
  228.            https://docs.python.org/3/library/dis.html#opcode-MAKE_FUNCTION
  229.  
  230.        Operation realization:
  231.            https://github.com/python/cpython/blob/3.7/Python/ceval.c#L3203
  232.  
  233.        Parse stack:
  234.            https://github.com/python/cpython/blob/3.7/Objects/call.c#L158
  235.  
  236.        Call function in cpython:
  237.            https://github.com/python/cpython/blob/3.7/Python/ceval.c#L4554
  238.        """
  239.         name = self.pop()  # the qualified name of the function (at TOS)  # noqa
  240.         code = self.pop()  # the code associated with the function (at TOS1)
  241.  
  242.         # TODO: use arg to parse function defaults
  243.         if arg & 0x08:
  244.             pass
  245.         if arg & 0x04:
  246.             pass
  247.         if arg & 0x02:
  248.             kwonly_defaults = self.pop()
  249.         else:
  250.             kwonly_defaults = {}
  251.         if arg & 0x01:
  252.             defaults = self.pop()
  253.         else:
  254.             defaults = ()
  255.         local = self.locals
  256.  
  257.         def f(*args: tp.Any, **kwargs: tp.Any) -> tp.Any:
  258.             # TODO: parse input arguments using code attributes such as co_argcount
  259.  
  260.             parsed_args: tp.Dict[str, tp.Any] = {} # bind_args(code, defaults, kwo)
  261.             f_locals = dict(self.locals)
  262.             f_locals.update(parsed_args)
  263.  
  264.             frame = Frame(code, self.builtins, self.globals, f_locals)  # Run code in prepared environment
  265.             return frame.run()
  266.  
  267.         self.push(f)
  268.  
  269.     def store_name_op(self, arg: str) -> None:
  270.         """
  271.        Operation description:
  272.            https://docs.python.org/3/library/dis.html#opcode-STORE_NAME
  273.  
  274.        Operation realization:
  275.            https://github.com/python/cpython/blob/3.7/Python/ceval.c#L1923
  276.        """
  277.         const = self.pop()
  278.         self.locals[arg] = const
  279.  
  280.     def load_method_op(self, method_name: str) -> None:
  281.         obj = self.pop()
  282.         method = getattr(obj, method_name)
  283.         if hasattr(method, '__self__'):
  284.             self.push(None)
  285.             self.push(method)
  286.         else:
  287.             self.push(method)
  288.             self.push(obj)
  289.  
  290.     def call_method_op(self, argc: int) -> None:
  291.         arguments = self.popn(argc)
  292.         x, y = self.popn(2)
  293.         if y is None:
  294.             self.push(x(*arguments))
  295.         else:
  296.             self.push(y(*arguments))
  297.  
  298.     # Logic
  299.  
  300.     comp_ops = {
  301.         '<': lambda x, y: x < y,
  302.         '<=': lambda x, y: x <= y,
  303.         '==': lambda x, y: x == y,
  304.         '!=': lambda x, y: x != y,
  305.         '>': lambda x, y: x > y,
  306.         '>=': lambda x, y: x >= y,
  307.         'is': lambda x, y: x is y,
  308.         'is not': lambda x, y: x is not y,
  309.         'in': lambda x, y: x in y,
  310.         'not in': lambda x, y: x not in y,
  311.     }
  312.  
  313.     def compare_op_op(self, operation: str) -> None:
  314.         x, y = self.popn(2)
  315.         if operation in self.comp_ops:
  316.             self.push(self.comp_ops[operation](x, y))
  317.         # EXCEPTION!!!
  318.  
  319.     # Unary Operations
  320.  
  321.     def unary_negative_op(self, *args: tp.Any) -> None:
  322.         self.push(-self.pop())
  323.  
  324.     def unary_positive_op(self, *args: tp.Any) -> None:
  325.         self.push(abs(self.pop()))
  326.  
  327.     def unary_not_op(self, *args: tp.Any) -> None:
  328.         self.push(not self.pop())
  329.  
  330.     def unary_invert_op(self, *args: tp.Any) -> None:
  331.         self.push(~self.pop())
  332.  
  333.     # Inplace Operations
  334.  
  335.     def inplace_power_op(self, *args: tp.Any) -> None:
  336.         x, y = self.popn(2)
  337.         self.push(x ** y)
  338.  
  339.     def inplace_multiply_op(self, *args: tp.Any) -> None:
  340.         x, y = self.popn(2)
  341.         self.push(x * y)
  342.  
  343.     def inplace_matrix_multiply_op(self, *args: tp.Any) -> None:
  344.         x, y = self.popn(2)
  345.         self.push(x @ y)
  346.  
  347.     def inplace_floor_divide_op(self, *args: tp.Any) -> None:
  348.         x, y = self.popn(2)
  349.         self.push(x // y)
  350.  
  351.     def inplace_true_divide_op(self, *args: tp.Any) -> None:
  352.         x, y = self.popn(2)
  353.         self.push(x / y)
  354.  
  355.     def inplace_modulo_op(self, *args: tp.Any) -> None:
  356.         x, y = self.popn(2)
  357.         self.push(x % y)
  358.  
  359.     def inplace_add_op(self, *args: tp.Any) -> None:
  360.         x, y = self.popn(2)
  361.         self.push(x + y)
  362.  
  363.     def inplace_subtract_op(self, *args: tp.Any) -> None:
  364.         x, y = self.popn(2)
  365.         self.push(x - y)
  366.  
  367.     def inplace_lshift_op(self, *args: tp.Any) -> None:
  368.         x, y = self.popn(2)
  369.         self.push(x << y)
  370.  
  371.     def inplace_rshift_op(self, *args: tp.Any) -> None:
  372.         x, y = self.popn(2)
  373.         self.push(x >> y)
  374.  
  375.     def inplace_and_op(self, *args: tp.Any) -> None:
  376.         x, y = self.popn(2)
  377.         self.push(x & y)
  378.  
  379.     def inplace_xor_op(self, *args: tp.Any) -> None:
  380.         x, y = self.popn(2)
  381.         self.push(x ^ y)
  382.  
  383.     def inplace_or_op(self, *args: tp.Any) -> None:
  384.         x, y = self.popn(2)
  385.         self.push(x | y)
  386.  
  387.     # Binary Operations
  388.  
  389.     def binary_power_op(self, *args: tp.Any) -> None:
  390.         self.inplace_power_op(args)
  391.  
  392.     def binary_multiply_op(self, *args: tp.Any) -> None:
  393.         self.inplace_multiply_op(args)
  394.  
  395.     def binary_matrix_multiply_op(self, *args: tp.Any) -> None:
  396.         self.inplace_matrix_multiply_op(args)
  397.  
  398.     def binary_floor_divide_op(self, *args: tp.Any) -> None:
  399.         self.inplace_floor_divide_op(args)
  400.  
  401.     def binary_true_divide_op(self, *args: tp.Any) -> None:
  402.         self.inplace_true_divide_op(args)
  403.  
  404.     def binary_modulo_op(self, *args: tp.Any) -> None:
  405.         self.inplace_modulo_op(args)
  406.  
  407.     def binary_add_op(self, *args: tp.Any) -> None:
  408.         self.inplace_add_op(args)
  409.  
  410.     def binary_subtract_op(self, *args: tp.Any) -> None:
  411.         self.inplace_subtract_op(args)
  412.  
  413.     def binary_lshift_op(self, *args: tp.Any) -> None:
  414.         self.inplace_lshift_op(args)
  415.  
  416.     def binary_rshift_op(self, *args: tp.Any) -> None:
  417.         self.inplace_rshift_op(args)
  418.  
  419.     def binary_and_op(self, *args: tp.Any) -> None:
  420.         self.inplace_and_op(args)
  421.  
  422.     def binary_xor_op(self, *args: tp.Any) -> None:
  423.         self.inplace_xor_op(args)
  424.  
  425.     def binary_or_op(self, *args: tp.Any) -> None:
  426.         self.inplace_or_op(args)
  427.  
  428.     def binary_subscr_op(self, *args: tp.Any) -> None:
  429.         x, y = self.popn(2)
  430.         self.push(x[y])
  431.  
  432.     def store_subscr_op(self, *args: tp.Any) -> None:
  433.         x, y = self.popn(2)
  434.         x[y] = self.pop()
  435.         self.push(x)
  436.         self.push(y)
  437.  
  438.     def delete_subscr_op(self, *args: tp.Any) -> None:
  439.         x, y = self.popn(2)
  440.         del x[y]
  441.         self.push(x)
  442.         self.push(y)
  443.  
  444.     def store_global_op(self, name: str) -> None:
  445.         self.globals[name] = self.pop()
  446.  
  447.     # Stack
  448.  
  449.     def dup_top_op(self, *args: tp.Any) -> None:
  450.         self.push(self.top())
  451.  
  452.     def dup_top_two_op(self, *args: tp.Any) -> None:
  453.         x = self.pop()
  454.         y = self.top()
  455.         self.push(x)
  456.         self.push(y)
  457.         self.push(x)
  458.  
  459.     def rot_two_op(self, *args: tp.Any) -> None:
  460.         x, y = self.popn(2)
  461.         self.push(x)
  462.         self.push(y)
  463.  
  464.     def rot_three_op(self, *args: tp.Any) -> None:
  465.         x, y, z = self.popn(3)
  466.         self.push(x)
  467.         self.push(y)
  468.         self.push(z)
  469.  
  470.     def pop_except_op(self) -> None:
  471.         block = self.pop_block_op()
  472.         if block.type != 'except-handler':
  473.             raise Exception("popped block is not an except handler")
  474.         # self.unwind_block(block)
  475.  
  476.     # Jumps
  477.  
  478.     def jump_forward_op(self, ind: int) -> None:
  479.         self.jump_pos = ind
  480.  
  481.     def jump_absolute_op(self, ind: int) -> None:
  482.         self.jump_pos = ind
  483.  
  484.     def pop_jump_if_true_op(self, ind: int) -> None:
  485.         if self.pop():
  486.             self.jump_pos = ind
  487.  
  488.     def pop_jump_if_false_op(self, ind: int) -> None:
  489.         if not self.pop():
  490.             self.jump_pos = ind
  491.  
  492.     def jump_if_true_or_pop_op(self, ind: int) -> None:
  493.         if self.top():
  494.             self.jump_pos = ind
  495.         else:
  496.             self.pop()
  497.  
  498.     def jump_if_false_or_pop(self, ind: int) -> None:
  499.         if not self.top():
  500.             self.jump_pos = ind
  501.         else:
  502.             self.pop()
  503.  
  504.     # Loop
  505.  
  506.     def setup_loop_op(self, *args: tp.Any) -> None:
  507.         pass
  508.  
  509.     def get_iter_op(self, *args: tp.Any) -> None:
  510.         self.push(iter(self.pop()))
  511.  
  512.     def for_iter_op(self, step: int, *args: tp.Any) -> None:
  513.         iterat = self.pop()
  514.         try:
  515.             next_it = iterat.__next__()
  516.             self.push(iterat)
  517.             self.push(next_it)
  518.         except StopIteration:
  519.             self.jump_pos = step
  520.  
  521.     # Building
  522.  
  523.     def build_list_op(self, size: int) -> None:
  524.         self.push(self.popn(size))
  525.  
  526.     def build_list_unpack_op(self, size: int) -> None:
  527.         elems = self.popn(size)
  528.         unp_list: tp.List[tp.Any] = []
  529.         for elem in elems:
  530.             unp_list += elem
  531.         self.push(unp_list)
  532.  
  533.     def list_append_op(self, i: int) -> None:
  534.         new_list = self.pop()
  535.         list.append(new_list[-i], new_list)
  536.         self.push(new_list)
  537.  
  538.     def build_tuple_op(self, size: int) -> None:
  539.         self.push(tuple(self.popn(size)))
  540.  
  541.     def build_tuple_unpack_op(self, size: int) -> None:
  542.         elems = self.popn(size)
  543.         unp_tuple: tp.Tuple[tp.Any, ...] = tuple()
  544.         for elem in elems:
  545.             unp_tuple += elem
  546.         self.push(unp_tuple)
  547.  
  548.     def build_map_op(self, size: int) -> None:
  549.         elems = self.popn(2 * size)
  550.         new_map = {}
  551.         for i in range(0, 2 * size, 2):
  552.             new_map[elems[i]] = elems[i + 1]
  553.         self.push(new_map)
  554.  
  555.     def build_map_unpack_op(self, size: int) -> None:
  556.         elems = self.popn(size)
  557.         unp_map: tp.Dict[tp.Any, tp.Any] = {}
  558.         for elem in elems:
  559.             unp_map.update(elem)
  560.         self.push(unp_map)
  561.  
  562.     def build_const_key_map_op(self, size: int) -> None:
  563.         keys = self.pop()
  564.         values = self.popn(size)
  565.         new_map = {key: value for key, value in zip(keys, values)}
  566.         self.push(new_map)
  567.  
  568.     def build_set_op(self, size: int) -> None:
  569.         self.push(set(self.popn(size)))
  570.  
  571.     def build_set_unpack_op(self, size: int) -> None:
  572.         elems = self.popn(size)
  573.         self.push(set().union(*elems))
  574.  
  575.     def build_slice_op(self, args: int) -> None:
  576.         x, y = self.popn(2)
  577.         if args == 2:
  578.             self.push(slice(x, y))
  579.         elif args == 3:
  580.             z = self.pop()
  581.             self.push(slice(x, y, z))
  582.         else:
  583.             raise Exception('incorrect set of arguments for slice')
  584.  
  585.     def build_string_op(self, size: int) -> None:
  586.         elems = self.popn(size)
  587.         string = ''
  588.         for elem in elems:
  589.             string += elem
  590.         self.push(string)
  591.  
  592.     def load_build_class_op(self, *args: tp.Any) -> None:
  593.         self.push(builtins.__buid_class__())
  594.  
  595.     """
  596.    def format_value_op(self, flags: tp.Any) -> None:
  597.        string = self.pop()
  598.        if flags & 0x03 == 0x00:
  599.            self.push(string)
  600.        elif flags & 0x03 == 0x01:
  601.            self.push(str(string))
  602.        elif flags & 0x03 == 0x02:
  603.            self.push(repr(string))
  604.        elif flags & 0x03 == 0x03:
  605.            self.push(ascii(string))
  606.        if flags & 0x04 == 0x04:
  607.            fmt_spec = self.pop()
  608.            self.push(fmt_spec(string))
  609.    """
  610.  
  611.     def unpack_sequence_op(self, count: int) -> None:
  612.         seq = self.pop()
  613.         for x in reversed(seq):
  614.             self.push(x)
  615.  
  616.     def extended_arg_op(self, ext: tp.Any) -> None:
  617.         instr_arg = self.next_instr
  618.         instr_arg |= ext << 8
  619.         self.next_instr = instr_arg
  620.  
  621.     """"
  622.    def do_raise(self, exc: tp.Any, cause: tp.Any) -> tp.Any:
  623.        if exc is None:
  624.            exc_type, val, tb = self.last_exception
  625.            if exc_type is None:
  626.                return 'exception'
  627.            else:
  628.                return 'reraise'
  629.        elif type(exc) == type:
  630.            exc_type = exc
  631.            val = exc()
  632.        elif isinstance(exc, BaseException):
  633.            exc_type = type(exc)
  634.            val = exc
  635.        else:
  636.            return 'exception'
  637.        if cause:
  638.            if type(cause) == type:
  639.                cause = cause()
  640.            elif not isinstance(cause, BaseException):
  641.                return 'exception'
  642.            val.__cause__ = cause
  643.        self.last_exception = exc_type, val, val.__traceback__
  644.        return 'exception'
  645.  
  646.    def raise_varargs_op(self, argc: int) -> None:
  647.        cause = exc = None
  648.        if argc == 2:
  649.            cause = self.pop()
  650.            exc = self.pop()
  651.        elif argc == 1:
  652.            exc = self.pop()
  653.        return self.do_raise(exc, cause)
  654.        """
  655.  
  656.  
  657. class VirtualMachine:
  658.     def run(self, code_obj: types.CodeType) -> None:
  659.         """
  660.        :param code_text_or_obj: code for interpreting
  661.        """
  662.         globals_context: tp.Dict[str, tp.Any] = {}
  663.         frame = Frame(code_obj, builtins.globals()['__builtins__'], globals_context, globals_context)
  664.         return frame.run()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement