don't require syntParent when constructing synts
implement dirt-simple stack vm / "compiler"
This commit is contained in:
parent
f65c877a91
commit
3dc0752a5d
169
scripting.py
169
scripting.py
|
@ -3,6 +3,7 @@ from basetoken import *
|
||||||
from tpers import *
|
from tpers import *
|
||||||
from util import *
|
from util import *
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
from vm import *
|
||||||
|
|
||||||
def RegStmt(clsStmt):
|
def RegStmt(clsStmt):
|
||||||
SyntLine.rgclsStmt.append(clsStmt)
|
SyntLine.rgclsStmt.append(clsStmt)
|
||||||
|
@ -12,27 +13,26 @@ def RegRtype(clsRtype):
|
||||||
Rtype.rgclsRtype.append(clsRtype)
|
Rtype.rgclsRtype.append(clsRtype)
|
||||||
return clsRtype
|
return clsRtype
|
||||||
|
|
||||||
# rtype -- runtime type
|
|
||||||
# method: RglitFromSt(st) -- parse the string and return a list of potentially matching literals
|
|
||||||
# method: RgsyntFromSt(scope, st) -- parse the string and return a list of synts whose rtypes match this
|
|
||||||
# method: StForSobj(sobj) -- a user-visible description of the sobj
|
|
||||||
# method: FMember(sobj) -- returns true if sobj is a member of this type
|
|
||||||
# method: FOverlap(rtype) -- returns true if there is some overlap between this type and rtype
|
|
||||||
class Rtype(TPrs):
|
class Rtype(TPrs):
|
||||||
|
"Runtime type"
|
||||||
rgclsRtype = []
|
rgclsRtype = []
|
||||||
@classmethod
|
@classmethod
|
||||||
def RtypeMax(cls):
|
def RtypeMax(cls):
|
||||||
|
"Return an instance of this rtype which will match anything that any instance of this rtype matches."
|
||||||
return cls()
|
return cls()
|
||||||
def RglitFromSt(self, st):
|
def RglitFromSt(self, st):
|
||||||
|
"Return literal objects that match a (partially entered) string."
|
||||||
return []
|
return []
|
||||||
def RgsyntFromSt(self, syntBlock, st):
|
def RgsyntFromSt(self, syntBlock, st):
|
||||||
|
"Return syntax objects whose rtypes match this that match a (partially entered) string."
|
||||||
for lit in self.RglitFromSt(st):
|
for lit in self.RglitFromSt(st):
|
||||||
yield SyntLit(None, lit, self)
|
yield SyntLit(lit, self)
|
||||||
|
|
||||||
for synt in self.RgsyntVarRefFromSt(syntBlock, st):
|
for synt in self.RgsyntVarRefFromSt(syntBlock, st):
|
||||||
yield synt
|
yield synt
|
||||||
|
|
||||||
def RgsyntVarRefFromSt(self, syntBlock, st):
|
def RgsyntVarRefFromSt(self, syntBlock, st):
|
||||||
|
"Return variable references that match a (partially entered) string."
|
||||||
while syntBlock != None:
|
while syntBlock != None:
|
||||||
if isinstance(syntBlock, SyntBlock):
|
if isinstance(syntBlock, SyntBlock):
|
||||||
for synt in self.RgsyntFromSyntBlock(syntBlock, st):
|
for synt in self.RgsyntFromSyntBlock(syntBlock, st):
|
||||||
|
@ -44,13 +44,16 @@ class Rtype(TPrs):
|
||||||
# yield all vars in scope
|
# yield all vars in scope
|
||||||
for syntVar in syntBlock.rgsynt:
|
for syntVar in syntBlock.rgsynt:
|
||||||
if SyntVar.FVarOfType(syntVar, self) and syntVar.name.St().lower().startswith(st.lower()):
|
if SyntVar.FVarOfType(syntVar, self) and syntVar.name.St().lower().startswith(st.lower()):
|
||||||
yield SyntVarRef(None, syntVar)
|
yield SyntVarRef(syntVar)
|
||||||
|
|
||||||
def StForSobj(self, sobj):
|
def StForSobj(self, sobj):
|
||||||
|
"Return a user-visible description of a sobj."
|
||||||
return str(sobj)
|
return str(sobj)
|
||||||
def FMember(self, sobj):
|
def FMember(self, sobj):
|
||||||
|
"Returns true if sobj is a member of this type."
|
||||||
return isinstance(sobj, self.pythontype)
|
return isinstance(sobj, self.pythontype)
|
||||||
def FOverlap(self, rtype):
|
def FOverlap(self, rtype):
|
||||||
|
"Returns true if there is some overlap between this type and rtype."
|
||||||
return isinstance(rtype, self.__class__)
|
return isinstance(rtype, self.__class__)
|
||||||
|
|
||||||
@RegRtype
|
@RegRtype
|
||||||
|
@ -90,6 +93,13 @@ class RtypeAny(Rtype):
|
||||||
class Typeable(TPrs):
|
class Typeable(TPrs):
|
||||||
def InitTransient(self):
|
def InitTransient(self):
|
||||||
self.steditTypein = Stedit()
|
self.steditTypein = Stedit()
|
||||||
|
def PersistStedit(self):
|
||||||
|
assert self.FPersist()
|
||||||
|
try:
|
||||||
|
del self.steditTypein
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
self.steditTypein = Stedit()
|
||||||
def GetStTypein(self):
|
def GetStTypein(self):
|
||||||
st = self.steditTypein.GetValue()
|
st = self.steditTypein.GetValue()
|
||||||
return None if st == "" else st
|
return None if st == "" else st
|
||||||
|
@ -98,19 +108,16 @@ class Typeable(TPrs):
|
||||||
def HandleTypeinKey(self, key):
|
def HandleTypeinKey(self, key):
|
||||||
return self.steditTypein.HandleKey(key)
|
return self.steditTypein.HandleKey(key)
|
||||||
|
|
||||||
# synt -- a piece of syntax
|
|
||||||
# method: Project() -- projects it
|
|
||||||
#
|
|
||||||
class Synt(Typeable):
|
class Synt(Typeable):
|
||||||
desc = None
|
"A piece of syntax"
|
||||||
def InitPersistent(self, syntParent):
|
def InitPersistent(self):
|
||||||
self.syntParent = syntParent
|
self.syntParent = None
|
||||||
self.rgsynt = []
|
self.rgsynt = []
|
||||||
self.Populate()
|
self.Populate()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def SyntDefault(cls, syntParent):
|
def SyntDefault(cls):
|
||||||
return cls(syntParent)
|
return cls()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def RgsyntReplace(cls, syntChild, st, rtype):
|
def RgsyntReplace(cls, syntChild, st, rtype):
|
||||||
|
@ -131,8 +138,14 @@ class Synt(Typeable):
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def Replace(self, syntOld, syntNew):
|
def Replace(self, syntOld, syntNew):
|
||||||
self.rgsynt[self.Isynt(syntOld)] = syntNew
|
assert syntNew.syntParent == None
|
||||||
syntNew.syntParent = self
|
syntNew.syntParent = self
|
||||||
|
self.rgsynt[self.Isynt(syntOld)] = syntNew
|
||||||
|
|
||||||
|
def Append(self, syntNew):
|
||||||
|
assert syntNew.syntParent == None
|
||||||
|
syntNew.syntParent = self
|
||||||
|
self.rgsynt.append(syntNew)
|
||||||
|
|
||||||
def Isynt(self, syntChild):
|
def Isynt(self, syntChild):
|
||||||
if isinstance(syntChild, int):
|
if isinstance(syntChild, int):
|
||||||
|
@ -145,15 +158,19 @@ class Synt(Typeable):
|
||||||
def RtypeTopForChild(self, syntChild):
|
def RtypeTopForChild(self, syntChild):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def Eval(self, ectx):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def Populate(self):
|
def Populate(self):
|
||||||
|
"Populate rgsynt with useful default values."
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def Project(self, pcur):
|
def Project(self, pcur):
|
||||||
|
"Project the current synt into its corresponding pws."
|
||||||
pass
|
pass
|
||||||
|
def Compile(self):
|
||||||
|
"Return a list of {synt|callable}s to be interpreted."
|
||||||
|
if hasattr(self, "Eval"):
|
||||||
|
return [self.Eval]
|
||||||
|
return []
|
||||||
|
|
||||||
# desc - list of desces
|
# desc - list of desces
|
||||||
# desce:
|
# desce:
|
||||||
# string: "foo" -- literal uneditable text
|
# string: "foo" -- literal uneditable text
|
||||||
|
@ -172,6 +189,7 @@ class SyntDesc(Synt):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def DefProp(isynt):
|
def DefProp(isynt):
|
||||||
|
"Create an alias for rgsynt[isynt]."
|
||||||
def getI(self):
|
def getI(self):
|
||||||
return self.rgsynt[isynt]
|
return self.rgsynt[isynt]
|
||||||
def setI(self, syntNew):
|
def setI(self, syntNew):
|
||||||
|
@ -184,8 +202,8 @@ class SyntDesc(Synt):
|
||||||
def Populate(self):
|
def Populate(self):
|
||||||
for desce in self.Desc():
|
for desce in self.Desc():
|
||||||
if isinstance(desce, tuple):
|
if isinstance(desce, tuple):
|
||||||
synt = desce[0].SyntDefault(self)
|
synt = desce[0].SyntDefault()
|
||||||
self.rgsynt.append(synt)
|
self.Append(synt)
|
||||||
# for synt in self.rgsynt:
|
# for synt in self.rgsynt:
|
||||||
# synt.Populate()
|
# synt.Populate()
|
||||||
|
|
||||||
|
@ -229,6 +247,9 @@ class SyntDesc(Synt):
|
||||||
isynt += 1
|
isynt += 1
|
||||||
|
|
||||||
class SyntName(Synt):
|
class SyntName(Synt):
|
||||||
|
def InitPersistent(self):
|
||||||
|
Synt.InitPersistent(self)
|
||||||
|
self.PersistStedit()
|
||||||
def Project(self, pcur):
|
def Project(self, pcur):
|
||||||
PwTypein(pcur.PwHoriz(self), self.St(), self)
|
PwTypein(pcur.PwHoriz(self), self.St(), self)
|
||||||
def St(self):
|
def St(self):
|
||||||
|
@ -242,7 +263,7 @@ class SyntExpr(Synt):
|
||||||
yield synt
|
yield synt
|
||||||
for clsSyntOp in cls.rgclsSyntOp:
|
for clsSyntOp in cls.rgclsSyntOp:
|
||||||
if clsSyntOp.StForTypein().lower().startswith(st.lower()):
|
if clsSyntOp.StForTypein().lower().startswith(st.lower()):
|
||||||
yield clsSyntOp.SyntDefault(None)
|
yield clsSyntOp.SyntDefault()
|
||||||
|
|
||||||
def Project(self, pcur):
|
def Project(self, pcur):
|
||||||
self.syntParent.ProjectTypeinForChild(pcur.PwHoriz(self), self, " ")
|
self.syntParent.ProjectTypeinForChild(pcur.PwHoriz(self), self, " ")
|
||||||
|
@ -254,7 +275,7 @@ class SyntLine(SyntDesc):
|
||||||
def RgsyntReplace(cls, syntChild, st, rtype):
|
def RgsyntReplace(cls, syntChild, st, rtype):
|
||||||
for clsStmt in cls.rgclsStmt:
|
for clsStmt in cls.rgclsStmt:
|
||||||
if clsStmt.StForTypein().lower().startswith(st.lower()):
|
if clsStmt.StForTypein().lower().startswith(st.lower()):
|
||||||
yield clsStmt(None)
|
yield clsStmt()
|
||||||
|
|
||||||
class SyntBlock(Synt):
|
class SyntBlock(Synt):
|
||||||
def Project(self, pcur):
|
def Project(self, pcur):
|
||||||
|
@ -276,7 +297,7 @@ class SyntBlock(Synt):
|
||||||
|
|
||||||
def InsertLineAfter(self, syntAfter, syntStmt):
|
def InsertLineAfter(self, syntAfter, syntStmt):
|
||||||
if syntStmt == None:
|
if syntStmt == None:
|
||||||
syntStmt = SyntLine(self)
|
syntStmt = SyntLine()
|
||||||
if syntAfter == None:
|
if syntAfter == None:
|
||||||
self.rgsynt.insert(0, syntStmt)
|
self.rgsynt.insert(0, syntStmt)
|
||||||
else:
|
else:
|
||||||
|
@ -290,9 +311,12 @@ class SyntBlock(Synt):
|
||||||
psel.Inc(pwKey.PwParent())
|
psel.Inc(pwKey.PwParent())
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
def Compile(self):
|
||||||
|
return self.rgsynt
|
||||||
|
|
||||||
class SyntLit(Synt):
|
class SyntLit(Synt):
|
||||||
def InitPersistent(self, syntParent, value, rtype):
|
def InitPersistent(self, value, rtype):
|
||||||
Synt.InitPersistent(self, syntParent)
|
Synt.InitPersistent(self)
|
||||||
self.value = value
|
self.value = value
|
||||||
self.rtype = rtype
|
self.rtype = rtype
|
||||||
def StForTypein(self):
|
def StForTypein(self):
|
||||||
|
@ -301,9 +325,9 @@ class SyntLit(Synt):
|
||||||
return self.rtype
|
return self.rtype
|
||||||
def Project(self, pcur):
|
def Project(self, pcur):
|
||||||
self.syntParent.ProjectTypeinForChild(pcur.PwHoriz(self), self, self.StForTypein())
|
self.syntParent.ProjectTypeinForChild(pcur.PwHoriz(self), self, self.StForTypein())
|
||||||
def Exec(self, ectx):
|
def Eval(self, vm):
|
||||||
return self.value
|
vm.Push(self.value)
|
||||||
|
|
||||||
@RegStmt
|
@RegStmt
|
||||||
class SyntVar(SyntDesc):
|
class SyntVar(SyntDesc):
|
||||||
desc = [["Define"], " ", (SyntName, None), " to be ", (SyntExpr, 1)]
|
desc = [["Define"], " ", (SyntName, None), " to be ", (SyntExpr, 1)]
|
||||||
|
@ -312,22 +336,30 @@ class SyntVar(SyntDesc):
|
||||||
@classmethod
|
@classmethod
|
||||||
def FVarOfType(cls, synt, rtype):
|
def FVarOfType(cls, synt, rtype):
|
||||||
return isinstance(synt, cls) and synt.expr != None and rtype.FOverlap(synt.expr.Rtype())
|
return isinstance(synt, cls) and synt.expr != None and rtype.FOverlap(synt.expr.Rtype())
|
||||||
|
def Compile(self):
|
||||||
|
return [self.expr, self.Eval]
|
||||||
|
def Eval(self, vm):
|
||||||
|
vm.vars.Define(self, vm.Pop())
|
||||||
|
|
||||||
class SyntVarRef(Synt):
|
class SyntVarRef(Synt):
|
||||||
def __init__(self, syntParent, syntVar = None):
|
def InitPersistent(self, syntVar = None):
|
||||||
Synt.__init__(self, syntParent)
|
Synt.InitPersistent(self)
|
||||||
self.syntVar = syntVar
|
self.syntVar = syntVar
|
||||||
@classmethod
|
@classmethod
|
||||||
def RgsyntReplace(cls, syntChild, st, rtype):
|
def RgsyntReplace(cls, syntChild, st, rtype):
|
||||||
rtype = rtype and RtypeAny()
|
rtype = rtype or RtypeAny()
|
||||||
return rtype.RgsyntVarRefForChild(syntChild, st)
|
return rtype.RgsyntVarRefFromSt(syntChild, st)
|
||||||
def Rtype(self):
|
def Rtype(self):
|
||||||
return self.syntVar.Rtype()
|
return self.syntVar.Rtype()
|
||||||
def StForTypein(self):
|
def StForTypein(self):
|
||||||
return self.syntVar.name.St()
|
if self.syntVar:
|
||||||
|
return self.syntVar.name.St()
|
||||||
|
return "<var>"
|
||||||
def Project(self, pcur):
|
def Project(self, pcur):
|
||||||
self.syntParent.ProjectTypeinForChild(pcur.PwHoriz(self), self, self.StForTypein())
|
self.syntParent.ProjectTypeinForChild(pcur.PwHoriz(self), self, self.StForTypein())
|
||||||
|
def Eval(self, vm):
|
||||||
|
vm.Push(vm.vars.Get(self.syntVar))
|
||||||
|
|
||||||
class SyntBinOp(SyntDesc):
|
class SyntBinOp(SyntDesc):
|
||||||
@classmethod
|
@classmethod
|
||||||
def Desc(cls):
|
def Desc(cls):
|
||||||
|
@ -338,9 +370,16 @@ class SyntBinOp(SyntDesc):
|
||||||
def Create(cls, op, rtype, dgEval = None, stNameI = None):
|
def Create(cls, op, rtype, dgEval = None, stNameI = None):
|
||||||
def Decorate(dgEval):
|
def Decorate(dgEval):
|
||||||
stName = stNameI or dgEval.__name__
|
stName = stNameI or dgEval.__name__
|
||||||
def Eval(self, ectx):
|
def Eval(vm):
|
||||||
return dgEval(self.left.Eval(ectx), self.right.Eval(ectx))
|
right = vm.Pop()
|
||||||
clsNew = type(stName, (cls,), {"Eval": Eval, "op": op})
|
left = vm.Pop()
|
||||||
|
try:
|
||||||
|
vm.Push(dgEval(left, right))
|
||||||
|
except Exception as e:
|
||||||
|
vm.Push(Fail("Failed to " + op + ": " + e))
|
||||||
|
def Compile(self):
|
||||||
|
return [self.left, self.right, Eval]
|
||||||
|
clsNew = type(stName, (cls,), {"Compile": Compile, "op": op})
|
||||||
SyntExpr.rgclsSyntOp.append(clsNew)
|
SyntExpr.rgclsSyntOp.append(clsNew)
|
||||||
return clsNew
|
return clsNew
|
||||||
|
|
||||||
|
@ -354,9 +393,14 @@ class SyntBinOp(SyntDesc):
|
||||||
SyntBinOp.Create("+", RtypeNum(), lambda l,r: l + r, "SyntPlus")
|
SyntBinOp.Create("+", RtypeNum(), lambda l,r: l + r, "SyntPlus")
|
||||||
SyntBinOp.Create("-", RtypeNum(), lambda l,r: l - r, "SyntMinus")
|
SyntBinOp.Create("-", RtypeNum(), lambda l,r: l - r, "SyntMinus")
|
||||||
SyntBinOp.Create("*", RtypeNum(), lambda l,r: l * r, "SyntMult")
|
SyntBinOp.Create("*", RtypeNum(), lambda l,r: l * r, "SyntMult")
|
||||||
SyntBinOp.Create("/", RtypeNum(), lambda l,r: l / r, "SyntDiv")
|
SyntBinOp.Create("/", RtypeNum(), lambda l,r: l / r, "SyntDiv") # use ansi?
|
||||||
SyntBinOp.Create("=", RtypeBool(), lambda l,r: l == r, "SyntEq")
|
SyntBinOp.Create("=", RtypeBool(), lambda l,r: l == r, "SyntEq")
|
||||||
SyntBinOp.Create(">", RtypeBool(), lambda l,r: l > r, "SyntGt")
|
SyntBinOp.Create(">", RtypeBool(), lambda l,r: l > r, "SyntGt")
|
||||||
|
SyntBinOp.Create(">=", RtypeBool(), lambda l,r: l >= r, "SyntGte") # use ansi?
|
||||||
|
SyntBinOp.Create("<", RtypeBool(), lambda l,r: l < r, "SyntLt")
|
||||||
|
SyntBinOp.Create("<=", RtypeBool(), lambda l,r: l <= r, "SyntLte") # use ansi?
|
||||||
|
SyntBinOp.Create("and", RtypeBool(), lambda l,r: l and r, "SyntAnd")
|
||||||
|
SyntBinOp.Create("or", RtypeBool(), lambda l,r: l or r, "SyntOr")
|
||||||
|
|
||||||
@RegStmt
|
@RegStmt
|
||||||
class SyntIf(SyntDesc):
|
class SyntIf(SyntDesc):
|
||||||
|
@ -364,28 +408,29 @@ class SyntIf(SyntDesc):
|
||||||
expr = SyntDesc.DefProp(0)
|
expr = SyntDesc.DefProp(0)
|
||||||
blockIfTrue = SyntDesc.DefProp(1)
|
blockIfTrue = SyntDesc.DefProp(1)
|
||||||
blockIfFalse = SyntDesc.DefProp(2)
|
blockIfFalse = SyntDesc.DefProp(2)
|
||||||
|
def Compile(self):
|
||||||
|
return [self.expr, self.Compare, self.PopCtx]
|
||||||
|
def Compare(self, vm):
|
||||||
|
val = vm.Pop()
|
||||||
|
vm.vars.Push() # lexical scoping, bitches
|
||||||
|
if val:
|
||||||
|
return self.blockIfTrue
|
||||||
|
else:
|
||||||
|
return self.blockIfFalse
|
||||||
|
def PopCtx(self, vm):
|
||||||
|
vm.vars.Pop()
|
||||||
|
|
||||||
# scope -- a block? a scril? (scril lets you specifically avoid vars that are defined after a certain point) + game?
|
@RegStmt
|
||||||
# method: rgvar(stype) -- returns a list of variables in scope that match the current stype
|
class SyntSet(SyntDesc):
|
||||||
# var -- a variable
|
desc = [["Set"], " ", (SyntVarRef, 1), " to ", (SyntExpr, 1)]
|
||||||
# contains: stype, sargInitializer
|
lvalue = SyntDesc.DefProp(0)
|
||||||
# a var IS A SCRIL
|
expr = SyntDesc.DefProp(1)
|
||||||
# the scmd creates a new vari in the current ectx, and adds the scril to a map of things that refer to it
|
def Compile(self):
|
||||||
# sproj -- an object that can project a sarg into an pw
|
return [self.expr, self.Eval]
|
||||||
# stypes should be sprojectors and express a default projection as a class method (why?)
|
def Eval(self, vm):
|
||||||
# MiSarg -- an editor for sargs
|
vm.vars.Set(self.lvalue.syntVar, vm.Pop())
|
||||||
# MiSargNum, MiSargDrop
|
|
||||||
# MiScriptLine -- projects a scriptline
|
|
||||||
# sobj -- generic hungarian for any object that is usable in scripts
|
# sobj -- generic hungarian for any object that is usable in scripts
|
||||||
# fail -- a FAILURE OBJECT; if it is used as a sarg when evaluating an scmd, a failure is logged and the scmd returns fail.
|
# fail -- a FAILURE OBJECT; if it is used as a sarg when evaluating an scmd, a failure is logged and the scmd returns fail.
|
||||||
|
|
||||||
# execution:
|
|
||||||
# ectx -- execution context
|
|
||||||
# contains: mpvar_sobj
|
|
||||||
# block
|
|
||||||
# iscril (selection?)
|
|
||||||
# ectxReturn
|
|
||||||
# methods: call(block)
|
|
||||||
|
|
||||||
class Fail(TPrs):
|
class Fail(TPrs):
|
||||||
def InitPersistent(self, stFailure):
|
def InitPersistent(self, stFailure):
|
||||||
|
@ -858,7 +903,7 @@ class PselState(Token):
|
||||||
class GameScriptTest(Game):
|
class GameScriptTest(Game):
|
||||||
def InitPersistent(self):
|
def InitPersistent(self):
|
||||||
Game.InitPersistent(self)
|
Game.InitPersistent(self)
|
||||||
self.block = SyntBlock(None)
|
self.block = SyntBlock()
|
||||||
|
|
||||||
def GetRgclsTokTrans(self):
|
def GetRgclsTokTrans(self):
|
||||||
return [[PselState, self.block], [AutoJoiner, [Pov, self.block]]]
|
return [[PselState, self.block], [AutoJoiner, [Pov, self.block]]]
|
||||||
|
|
69
vm.py
Normal file
69
vm.py
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
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()
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue