marmots/vm.py

69 lines
1.9 KiB
Python
Raw Normal View History

from tpers import *
from scripting import Fail, Synt
class Vars(TPrs):
def InitPersistent(self):
self.rgmpsynt_sobj = [{}] # [0] is for globals?
def Get(self, synt):
for mpsynt_sobj in reversed(self.rgmpsynt_sobj):
try:
return mpsynt_sobj[synt]
except:
pass
return Fail("Variable " + synt.name.St() + " not defined")
def Define(self, synt, sobj):
self.rgmpsynt_sobj[-1][synt] = sobj
def Set(self, synt, sobj):
for mpsynt_sobj in reversed(self.rgmpsynt_sobj):
if synt in mpsynt_sobj:
mpsynt_sobj[synt] = sobj
return
return Fail("Variable " + synt.name.St() + " not defined")
def Push(self):
self.rgmpsynt_sobj.append({})
def Pop(self):
self.rgmpsynt_sobj.pop()
class Vm(TPrs):
def InitPersistent(self):
self.vstack = []
self.rstack = []
self.vars = Vars()
def Push(self, sobj):
self.vstack.append(sobj)
def Pop(self):
return self.vstack.pop()
def CallI(self, synt, r, ip):
if ip < len(r): # tail call optimization
self.rstack.append(r, ip)
return (synt.Compile(), 0)
def RunSynt(self, synt):
r = synt.Compile()
ip = 0
while True:
if ip < len(r):
instr = r[ip]
ip += 1
if isinstance(instr, Synt):
(r, ip) = self.CallI(instr, r, ip)
elif callable(instr):
synt = instr(self)
if synt != None:
(r, ip) = self.CallI(instr, r, ip)
else:
assert False, "invalid opcode"
else:
if len(rstack) == 0:
break
(r, ip) = self.rstack.pop()