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()