Skip to content

Instantly share code, notes, and snippets.

@felko
Last active June 25, 2016 15:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save felko/8998194d45e26ef5fe8f097358113ada to your computer and use it in GitHub Desktop.
Save felko/8998194d45e26ef5fe8f097358113ada to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3.4
# coding: utf-8
from collections import ChainMap
class Bytecode:
def __init__(self, instructions):
self.instructions = instructions
def __str__(self):
s = ''
for instr in self.instructions:
s += str(instr) + '\n'
return s
class Instruction:
pass
class Load(Instruction):
def __init__(self, id):
self.id = id
def __str__(self):
return 'LOAD {}'.format(self.id)
class Store(Instruction):
def __init__(self, id):
self.id = id
def __str__(self):
return 'STORE {}'.format(self.id)
class Add(Instruction):
def __str__(self):
return 'ADD'
class Sub(Instruction):
def __str__(self):
return 'SUB'
class Mul(Instruction):
def __str__(self):
return 'MUL'
class Div(Instruction):
def __str__(self):
return 'DIV'
class Pow(Instruction):
def __str__(self):
return 'POW'
class Call(Instruction):
def __init__(self, n):
self.n = n
def __str__(self):
return 'CALL {}'.format(self.n)
class PushInt(Instruction):
def __init__(self, value):
self.value = value
def __str__(self):
return 'PUSH_INT {}'.format(self.value)
class PushScope(Instruction):
def __str__(self):
return 'PUSH_SCOPE'
class PopScope(Instruction):
def __str__(self):
return 'POP_SCOPE'
class Pop(Instruction):
def __str__(self):
return 'POP'
class Proc(Instruction):
def __init__(self, params, instructions):
self.params = params
self.instructions = instructions
def __str__(self):
s = 'PROC [\n'
Proc.str_depth += 1
for instr in self.instructions:
s += Proc.str_depth * ' ' + str(instr) + '\n'
s += ']'
Proc.str_depth -= 1
return s
def __repr__(self):
return '<proc>'
str_depth = 0
class VM:
executers = {}
def __init__(self, bytecode):
self.bytecode = bytecode
self.stack = []
self.env = ChainMap()
@classmethod
def register(cls, optype):
def _executer_wrapper(fn):
cls.executers[optype] = fn
return fn
return _executer_wrapper
def execute(self, op):
self.executers[type(op)](self, op)
if isinstance(op, Proc):
print(str(op) + ' ' * 19 + '{:<70}{:<70}'.format(str(self.stack), str(self.env.maps)))
else:
print('{:<20}{:<70}{:<70}'.format(str(op), str(self.stack), str(self.env.maps)))
def run(self):
for op in self.bytecode.instructions:
self.execute(op)
@VM.register(Load)
def execute_load(vm, load):
obj = vm.env[load.id]
vm.stack.append(obj)
@VM.register(Store)
def execute_store(vm, store):
obj = vm.stack[-1]
vm.env.maps[0][store.id] = obj
@VM.register(Add)
def execute_add(vm, add):
x, y = vm.stack[-2:]
vm.stack.append(x + y)
@VM.register(Sub)
def execute_sub(vm, sub):
x, y = vm.stack[-2:]
vm.stack.append(x - y)
@VM.register(Mul)
def execute_mul(vm, mul):
x, y = vm.stack[-2:]
vm.stack.append(x * y)
@VM.register(Div)
def execute_div(vm, div):
x, y = vm.stack[-2:]
vm.stack.append(x // y)
@VM.register(Pow)
def execute_pow(vm, pow):
x, y = vm.stack[-2:]
vm.stack.append(x ** y)
@VM.register(Call)
def execute_add(vm, call):
stack_tmp = vm.stack.copy()
*args, proc = vm.stack[-call.n - 1:]
vm.env.maps.insert(0, dict(zip(proc.params, args)))
for instr in proc.instructions:
vm.execute(instr)
res = vm.stack[-1]
vm.env.maps.pop(0)
vm.stack = stack_tmp
vm.stack.append(res)
@VM.register(PushInt)
def execute_push_int(vm, push):
vm.stack.append(push.value)
@VM.register(PushScope)
def execute_push_scope(vm, push):
vm.env.maps.insert(0, {})
@VM.register(PopScope)
def execute_pop_scope(vm, pop):
vm.env.maps.pop(0)
@VM.register(Pop)
def execute_push(vm, pop):
vm.stack.pop()
@VM.register(Proc)
def execute_proc(vm, proc):
vm.stack.append(proc)
if __name__ == '__main__':
bc = Bytecode([
Proc(['x', 'y'], [
Load('x'),
Load('y'),
Add()
]),
Store('add'),
Pop(),
PushInt(5),
PushInt(7),
Load('add'),
Call(2)
])
vm = VM(bc)
vm.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment