code = [ ['val', 2], # 2 ['val', 3], # 3 ['get', '*'], # * ( ) ['call', 2], # 2 ( ), ['get', 'puts'], # ['call', 1], # ]
# ops - # env - def vm(ops, env={}): # , class closure: # pc - "" ( ops) # env - def __init__(self, pc, env): self.pc, self.env = pc, env # pc - # stack - # fstack (frame stack) - pc, stack, fstack = 0, [], []
['label', 'label-name']
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 # label if op == 'label': pass # elif op == 'val': stack.append(arg) # 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)
make-person = fn(name, age) { return fn() { // name age print name, age++; }; }; vasya = make-person("Vasily", 20); petya = make-person("Peter", 24); vasya(); // Vasily 20 vasya(); // Vasily 21 petya(); // Peter 24 petya(); // Peter 25
fn
. Everything she does: puts on the stack an object of the closure
class, which contains the address of the code of the function (in fact, the address of the label with the name of the desired function) and the current environment.
elif op == 'fn': stack.append(closure(labels[arg], env))
# 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))) # return elif op == 'ret': # return , if not fstack: break # pc, env = fstack.pop()
Source: https://habr.com/ru/post/270797/