Skip to content

Instantly share code, notes, and snippets.

@Butjok
Created November 14, 2015 02:37
Show Gist options
  • Save Butjok/822a39b2dafbfb85cb43 to your computer and use it in GitHub Desktop.
Save Butjok/822a39b2dafbfb85cb43 to your computer and use it in GitHub Desktop.
def pairs(l):
return zip(l[::2], l[1::2])
def vm(ops, env={}):
class closure:
def __init__(self, pc, env): self.pc, self.env = pc, env
def popn(n):
if len(stack) < n: print 'not enough elements for pop: %d needed, %d left' % (n, len(stack))
top = stack[-n:]
stack[-n:] = []
return top
pc, stack, fstack = 0, [], []
labels = {op[1]: index for index, op in enumerate(ops) if op[0] == 'label'}
while pc < len(ops):
op, args, pc = ops[pc][0], ops[pc][1:], pc + 1
arg = args[0] if args else None
if op == 'label':
pass
elif op == 'val':
stack.append(arg)
elif op == 'fn':
stack.append(closure(labels[arg], env))
elif op == 'set' or op == 'get':
e = env
while e is not None and arg not in e:
e = e[''] if '' in e else None
if op == 'set': (env if e is None else e)[arg] = stack.pop()
elif op == 'get':
if e: stack.append(e[arg])
else: print('undefined variable %s' % arg)
elif op == 'arr':
stack.append(popn(arg))
elif op == 'map':
stack.append(dict(pairs(popn(arg * 2))))
elif op == 'call' or op == 'tcall':
fn = stack.pop()
if args and arg:
stack.append(popn(arg))
if isinstance(fn, closure):
if op == 'call':
fstack.append((pc, env))
pc, env = fn.pc, {'': fn.env}
elif hasattr(fn, '__call__'):
stack.append(fn(stack.pop()))
elif op == 'args':
vals = stack.pop()
if len(args) != len(vals): print 'warning: wrong arguments count: %d expected, %d given' % (len(args), len(vals))
env.update(dict(zip(args, vals)))
elif op == 'ret':
if not fstack: break
pc, env = fstack.pop()
elif op == 'jmp':
pc = labels[arg]
elif op == 'jmpf':
if not stack.pop(): pc = labels[arg]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment