Created
April 4, 2014 14:41
-
-
Save zelark/9976074 to your computer and use it in GitHub Desktop.
python virtual machine
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# http://tech.blog.aknin.name/2010/04/02/pythons-innards-introduction/ | |
# http://tech.blog.aknin.name/category/my-projects/pythons-innards/ | |
# http://akaptur.github.io/blog/2013/08/14/python-bytecode-fun-with-dis/ | |
# from vm import VirtualMachine | |
# vm = VirtualMachine() | |
# vm.byte_LOAD_CONST('a') | |
# vm.byte_LOAD_CONST('b') | |
# vm.byte_BUILD_LIST(2) | |
# vm.byte_BUILD_LIST(0) | |
# vm.byte_ROT_TWO() | |
# vm.byte_STORE_NAME('x') | |
# vm.byte_STORE_NAME('y') | |
class VirtualMachine(object): | |
def __init__(self): | |
# The call stack of frames. | |
self.frames = [] | |
# The current frame. | |
self.frame = None | |
# The data stack. | |
self.stack = [] | |
self.return_value = None | |
self.last_exception = None | |
#my frame locals | |
self.f_locals = {} | |
def top(self): | |
"""Return the value at the top of the stack, with no changes.""" | |
return self.stack[-1] | |
def pop(self, i=0): | |
"""Pop a value from the stack. | |
Default to the top of the stack, but `i` can be a count from the top | |
instead. | |
""" | |
return self.stack.pop(-1-i) | |
def push(self, *vals): | |
"""Push values onto the value stack.""" | |
self.stack.extend(vals) | |
def popn(self, n): | |
"""Pop a number of values from the value stack. | |
A list of `n` values is returned, the deepest value first. | |
""" | |
if n: | |
ret = self.stack[-n:] | |
self.stack[-n:] = [] | |
return ret | |
else: | |
return [] | |
def peek(self, n): | |
"""Get a value `n` entries down in the stack, without changing the stack.""" | |
return self.stack[-n] | |
## Stack manipulation | |
def byte_LOAD_NAME(self, name): | |
frame = self.frame | |
if name in frame.f_locals: | |
val = frame.f_locals[name] | |
elif name in frame.f_globals: | |
val = frame.f_globals[name] | |
elif name in frame.f_builtins: | |
val = frame.f_builtins[name] | |
else: | |
raise NameError("name '%s' is not defined" % name) | |
self.push(val) | |
def byte_STORE_NAME(self, name): | |
self.frame.f_locals[name] = self.pop() | |
def byte_LOAD_CONST(self, const): | |
self.push(const) | |
def byte_ROT_TWO(self): | |
a, b = self.popn(2) | |
self.push(b, a) | |
## Names | |
def byte_LOAD_NAME(self, name): | |
frame = self.frame | |
if name in frame.f_locals: | |
val = frame.f_locals[name] | |
elif name in frame.f_globals: | |
val = frame.f_globals[name] | |
elif name in frame.f_builtins: | |
val = frame.f_builtins[name] | |
else: | |
raise NameError("name '%s' is not defined" % name) | |
self.push(val) | |
def byte_STORE_NAME(self, name): | |
#self.frame.f_locals[name] = self.pop() | |
self.f_locals[name] = self.pop() | |
## Building | |
def byte_BUILD_LIST(self, count): | |
elts = self.popn(count) | |
self.push(elts) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
how to use it?