Refactor / simplify scripting syntax classes
* Introduce Stype, a generalized object for producing synts by text matching * consistently use stype to determine what can be inserted in a given place * rewrite SyntDesc to more extensively use Stypes * Introduce SyntHole, a generalized anyblob that can be put anywhere and evals to failure * Remove all data types but flags, introduce bots * Remove math * Remove compiler / VM * Remove unused methods
This commit is contained in:
parent
6790f23474
commit
4e720f0d67
|
@ -28,6 +28,13 @@ from twisted.internet import reactor
|
||||||
from tpers import TPrs, TPLS, Version
|
from tpers import TPrs, TPLS, Version
|
||||||
import tpers
|
import tpers
|
||||||
|
|
||||||
|
|
||||||
|
# TPrs - persistent base class; includes migration facilities and the ability to selectively opt-out of
|
||||||
|
# being persisted. Most long-lived objects should probably be derived from TPrs.
|
||||||
|
# Ownable - has a parent ownable; die() will be called when its parent dies.
|
||||||
|
# Taggable - ownable, and also has tags. Assumes an eventual Game ancestor where the tag index is stored.
|
||||||
|
# Token - taggable, and also has a tasklet that runs for as long as it's alive.
|
||||||
|
|
||||||
class Event(TPrs):
|
class Event(TPrs):
|
||||||
def InitPersistent(self, game):
|
def InitPersistent(self, game):
|
||||||
self.game = game
|
self.game = game
|
||||||
|
|
|
@ -1,3 +1,28 @@
|
||||||
|
My old scripting system is an overcomplicated unusable disaster zone!!
|
||||||
|
Let's start very simply with something like Bitsy.
|
||||||
|
|
||||||
|
* one layer on a board is the Object Layer; it is where the player lives
|
||||||
|
* there is a static finite set of named objects, no dynamic creation, no querying
|
||||||
|
* nothing happens without the player bumping into it
|
||||||
|
|
||||||
|
VERBS
|
||||||
|
* Show Message <string>
|
||||||
|
* Show Long Message (pop-up) <textarea?>
|
||||||
|
|
||||||
|
* If <flag> Then / Else
|
||||||
|
* Set Flag <true/false/flag>
|
||||||
|
|
||||||
|
* Set Visibility of <object | layer> to <true/false/flag>
|
||||||
|
* Move <object> <N/E/W/S>...
|
||||||
|
|
||||||
|
EVENTS
|
||||||
|
* player touches object
|
||||||
|
|
||||||
|
Once this exists we can expand if we want, but in the meantime this would be *awesome*.
|
||||||
|
|
||||||
|
======
|
||||||
|
OLD THOUGHTS
|
||||||
|
|
||||||
script quotas:
|
script quotas:
|
||||||
- infinite loops are bad.
|
- infinite loops are bad.
|
||||||
- we do not want "new frames" to happen constantly, so a "when this {expr} happens" event will be triggered
|
- we do not want "new frames" to happen constantly, so a "when this {expr} happens" event will be triggered
|
||||||
|
|
491
scripting.py
491
scripting.py
|
@ -18,95 +18,113 @@ 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 *
|
|
||||||
|
|
||||||
# sobj -- generic hungarian for any object that is usable in scripts
|
# sobj -- generic hungarian for any object that is usable in scripts
|
||||||
# stmt -- statement; a synt that can be used as a line in a SyntBlock
|
# stmt -- statement; a synt that can be used as a line in a SyntBlock
|
||||||
def RegStmt(clsStmt):
|
def RegStmt(clsStmt):
|
||||||
SyntLine.rgclsStmt.append(clsStmt)
|
StypeStmt.rgclsSynt.append(clsStmt)
|
||||||
return clsStmt
|
return clsStmt
|
||||||
|
|
||||||
def RegRtype(clsRtype):
|
class Botdef(TPrs):
|
||||||
Rtype.rgclsRtype.append(clsRtype)
|
def InitPersistent(self, stName, ach, x, y):
|
||||||
return clsRtype
|
self.stName = stName
|
||||||
|
self.ast = ast
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
self.syntOnTouch = SyntBlock()
|
||||||
|
|
||||||
class Rtype(TPrs):
|
class Flagdef(TPrs):
|
||||||
"Runtime type"
|
def InitPersistent(self, stName, value = True):
|
||||||
rgclsRtype = []
|
self.stName = stName
|
||||||
@classmethod
|
self.value = True
|
||||||
def RtypeMax(cls):
|
|
||||||
"Return an instance of this rtype which will match anything that any instance of this rtype matches."
|
class Rbot(TPrs):
|
||||||
return cls()
|
def InitPersistent(self, botdef):
|
||||||
def RglitFromSt(self, st):
|
self.botdef = botdef
|
||||||
"Return literal objects that match a (partially entered) string."
|
self.x = botdef.x
|
||||||
return []
|
self.y = botdef.y
|
||||||
def RgsyntFromSt(self, syntBlock, st):
|
|
||||||
"Return syntax objects whose rtypes match this that match a (partially entered) string."
|
class Defs(TPrs):
|
||||||
for lit in self.RglitFromSt(st):
|
def InitPersistent(self, rgflagdef = None, rgbotdef = None):
|
||||||
yield SyntLit(lit, self)
|
self.rgflagdef = rgflagdef or []
|
||||||
|
self.rgbotdef = rgbotdef or []
|
||||||
for synt in self.RgsyntVarRefFromSt(syntBlock, st):
|
|
||||||
yield synt
|
|
||||||
|
|
||||||
def RgsyntVarRefFromSt(self, syntBlock, st):
|
|
||||||
"Return variable references that match a (partially entered) string."
|
|
||||||
while syntBlock != None:
|
|
||||||
if isinstance(syntBlock, SyntBlock):
|
|
||||||
for synt in self.RgsyntFromSyntBlock(syntBlock, st):
|
|
||||||
yield synt
|
|
||||||
syntBlock = syntBlock.syntParent
|
|
||||||
|
|
||||||
# helper for RgsyntVarRefFromSt
|
def AddFlag(self, stName, fValue):
|
||||||
def RgsyntFromSyntBlock(self, syntBlock, st):
|
self.rgflagdef.append(Flagdef(stName, fValue))
|
||||||
# yield all vars in scope
|
|
||||||
for syntVar in syntBlock.rgsynt:
|
|
||||||
if SyntVar.FVarOfType(syntVar, self) and syntVar.name.St().lower().startswith(st.lower()):
|
|
||||||
yield SyntVarRef(syntVar)
|
|
||||||
|
|
||||||
|
class Vm(TPrs):
|
||||||
|
def InitPersistent(self, defs):
|
||||||
|
self.rgflagdef = defs.rgflagdef
|
||||||
|
self.rgbotdef = defs.rgbotdef
|
||||||
|
self.mpflagdef = { flagdef: flagdef.value for flagdef in defs.rgflagdef }
|
||||||
|
self.mpbotdef = { botdef: Rbot(botdef) for botdef in defs.rgbotdef }
|
||||||
|
def SetFlag(self, flagdef, fValue):
|
||||||
|
self.mpflagdef[flagdef] = fValue
|
||||||
|
def FFlagSet(self, flagdef):
|
||||||
|
return self.mpflagdef[flagdef]
|
||||||
|
|
||||||
|
def Log(self, fail):
|
||||||
|
print(fail.stMessage, fail.synt)
|
||||||
|
|
||||||
|
class Stype(TPrs):
|
||||||
|
"Syntax type"
|
||||||
|
def RgsyntFromSt(self, defs, st):
|
||||||
|
"Return syntax objects whose rtypes match this that match a (partially entered) string."
|
||||||
|
return []
|
||||||
|
|
||||||
|
class StypeEnum(Stype):
|
||||||
|
@classmethod
|
||||||
|
def RgclsSynt(cls):
|
||||||
|
return cls.rgclsSynt
|
||||||
|
def RgsyntFromSt(self, defs, st):
|
||||||
|
for clsStmt in self.rgclsSynt:
|
||||||
|
if clsStmt.StForTypein().lower().startswith(st.lower()):
|
||||||
|
yield clsStmt()
|
||||||
|
|
||||||
|
class StypeStmt(StypeEnum):
|
||||||
|
rgclsSynt = []
|
||||||
|
|
||||||
|
class Rtype(Stype):
|
||||||
|
"Runtime type"
|
||||||
def StForSobj(self, sobj):
|
def StForSobj(self, sobj):
|
||||||
"Return a user-visible description of a 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."
|
"Returns true if sobj is a member of this type."
|
||||||
return isinstance(sobj, self.pythontype)
|
return isinstance(sobj, self.pythontype)
|
||||||
def FOverlap(self, rtype):
|
|
||||||
"Returns true if there is some overlap between this type and rtype."
|
|
||||||
return isinstance(rtype, self.__class__)
|
|
||||||
|
|
||||||
@RegRtype
|
|
||||||
class RtypeBool(Rtype):
|
class RtypeBool(Rtype):
|
||||||
pythontype = bool
|
pythontype = bool
|
||||||
def RglitFromSt(self, st):
|
def RgsyntFromSt(self, defs, st):
|
||||||
if "true".startswith(st.lower()):
|
if "true".startswith(st.lower()):
|
||||||
yield True
|
yield SyntLit(True, self)
|
||||||
if "false".startswith(st.lower()):
|
if "false".startswith(st.lower()):
|
||||||
yield False
|
yield SyntLit(False, self)
|
||||||
@RegRtype
|
|
||||||
class RtypeNum(Rtype):
|
|
||||||
pythontype = float
|
|
||||||
def RglitFromSt(self, st):
|
|
||||||
try:
|
|
||||||
yield float(st)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
@RegRtype
|
|
||||||
class RtypeString(Rtype):
|
|
||||||
pythontype = str
|
|
||||||
def RglitFromSt(self, st):
|
|
||||||
if st.startswith('"') or st.startswith("'"):
|
|
||||||
yield st[1:]
|
|
||||||
|
|
||||||
class RtypeAny(Rtype):
|
class RtypeFlag(Rtype):
|
||||||
def RgsyntFromSt(self, syntBlock, st):
|
pythontype = Flagdef
|
||||||
for clsRtype in self.rgclsRtype:
|
def RgsyntFromSt(self, defs, st):
|
||||||
rtype = clsRtype.RtypeMax()
|
return (SyntFlagRef(flagdef) for flagdef in defs.rgflagdef if flagdef.stName.lower().startswith(st.lower()))
|
||||||
for synt in rtype.RgsyntFromSt(syntBlock, st):
|
|
||||||
|
class RtypeUnion(Rtype):
|
||||||
|
def InitPersistent(self, *rgrtype):
|
||||||
|
self.rgrtype = rgrtype
|
||||||
|
|
||||||
|
def RgsyntFromSt(self, defs, st):
|
||||||
|
for rtype in self.rgrtype:
|
||||||
|
for synt in rtype.RgsyntFromSt(defs, st):
|
||||||
yield synt
|
yield synt
|
||||||
|
|
||||||
|
def StForSobj(self, sobj):
|
||||||
|
for rtype in self.rgrtype:
|
||||||
|
if rtype.FMember(sobj):
|
||||||
|
return rtype.StForSobj(sobj)
|
||||||
|
return str(sobj)
|
||||||
|
|
||||||
def FMember(self, sobj):
|
def FMember(self, sobj):
|
||||||
return True
|
return any((rtype.FMember(sobj) for rtype in self.rgrtype))
|
||||||
def FOverlap(self, rtype):
|
|
||||||
return True
|
|
||||||
|
|
||||||
class Typeable(TPrs):
|
class Typeable(TPrs):
|
||||||
def InitTransient(self):
|
def InitTransient(self):
|
||||||
self.steditTypein = Stedit()
|
self.steditTypein = Stedit()
|
||||||
|
@ -129,11 +147,10 @@ class Synt(Typeable):
|
||||||
def SyntDefault(cls):
|
def SyntDefault(cls):
|
||||||
return cls()
|
return cls()
|
||||||
|
|
||||||
@classmethod
|
def ProjectTypein(self, pcur):
|
||||||
def RgsyntReplace(cls, syntChild, st, rtype):
|
return self.syntParent.ProjectTypeinForChild(pcur.defs, pcur.PwHoriz(self), self, self.StForTypein())
|
||||||
return []
|
|
||||||
|
|
||||||
def ProjectTypeinForChild(self, pwParent, syntChild, st):
|
def ProjectTypeinForChild(self, defs, pwParent, syntChild, st):
|
||||||
def OnSelect(synt, psel):
|
def OnSelect(synt, psel):
|
||||||
self.Replace(syntChild, synt)
|
self.Replace(syntChild, synt)
|
||||||
syntChild.SetStTypein(None)
|
syntChild.SetStTypein(None)
|
||||||
|
@ -141,11 +158,13 @@ class Synt(Typeable):
|
||||||
pwParent = PwDropdown(pwParent)
|
pwParent = PwDropdown(pwParent)
|
||||||
PwTypein(pwParent, st, syntChild)
|
PwTypein(pwParent, st, syntChild)
|
||||||
if syntChild.GetStTypein() != None:
|
if syntChild.GetStTypein() != None:
|
||||||
for synt in self.RgsyntForChild(syntChild, syntChild.GetStTypein()):
|
stype = self.StypeForChild(syntChild)
|
||||||
PwButton(pwParent, synt.StForTypein(), synt, OnSelect)
|
if stype:
|
||||||
|
for synt in stype.RgsyntFromSt(defs, syntChild.GetStTypein()):
|
||||||
|
PwButton(pwParent, synt.StForTypein(), synt, OnSelect)
|
||||||
|
|
||||||
def RgsyntForChild(self, syntChild, st):
|
def StypeForChild(self, syntChild):
|
||||||
return []
|
return None
|
||||||
|
|
||||||
def Replace(self, syntOld, syntNew):
|
def Replace(self, syntOld, syntNew):
|
||||||
assert syntNew.syntParent == None
|
assert syntNew.syntParent == None
|
||||||
|
@ -162,12 +181,6 @@ class Synt(Typeable):
|
||||||
return syntChild
|
return syntChild
|
||||||
return self.rgsynt.index(syntChild)
|
return self.rgsynt.index(syntChild)
|
||||||
|
|
||||||
def Rtype(self):
|
|
||||||
return None
|
|
||||||
|
|
||||||
def RtypeTopForChild(self, syntChild):
|
|
||||||
return None
|
|
||||||
|
|
||||||
def Populate(self):
|
def Populate(self):
|
||||||
"Populate rgsynt with useful default values."
|
"Populate rgsynt with useful default values."
|
||||||
pass
|
pass
|
||||||
|
@ -175,20 +188,17 @@ class Synt(Typeable):
|
||||||
def Project(self, pcur):
|
def Project(self, pcur):
|
||||||
"Project the current synt into its corresponding pws."
|
"Project the current synt into its corresponding pws."
|
||||||
pass
|
pass
|
||||||
def Compile(self):
|
def Eval(self, vm):
|
||||||
"Return a list of instrs to be interpreted. See vm.py for details on what an instr can be."
|
"Execute yourself, in the context of vm."
|
||||||
return [self.Eval]
|
return Fail("Missing information", self)
|
||||||
|
|
||||||
|
|
||||||
# desc - list of desces
|
# desc - list of desces
|
||||||
# desce:
|
# desce:
|
||||||
# string: "foo" -- literal uneditable text
|
# string: "foo" -- literal uneditable text
|
||||||
# list: ["foo"] -- text to edit the current synt
|
# list: ["foo"] -- text to edit the current synt
|
||||||
# tuple: (clsSynt, type) -- child description
|
# synt: synt - insert an empty instance of this synt
|
||||||
# clsSynt: class of child synt
|
# stype: stype - insert a SyntHole, use stype to determine what can go there
|
||||||
# type: number - same as another child expression with that number
|
# tuple: (stype, synt) - insert a Synt that can replace itself, use stype to determine what can go there
|
||||||
# None - no rtype specified / possible
|
|
||||||
# tuple (number, rtypeTop) - number == same as another child expression with that number, rtypeTop = required type
|
|
||||||
class SyntDesc(Synt):
|
class SyntDesc(Synt):
|
||||||
@classmethod
|
@classmethod
|
||||||
def StForTypein(cls):
|
def StForTypein(cls):
|
||||||
|
@ -210,37 +220,30 @@ class SyntDesc(Synt):
|
||||||
return cls.desc
|
return cls.desc
|
||||||
def Populate(self):
|
def Populate(self):
|
||||||
for desce in self.Desc():
|
for desce in self.Desc():
|
||||||
if isinstance(desce, tuple):
|
if hasattr(desce, "SyntDefault"):
|
||||||
synt = desce[0].SyntDefault()
|
self.Append(desce.SyntDefault())
|
||||||
self.Append(synt)
|
elif isinstance(desce, tuple):
|
||||||
# for synt in self.rgsynt:
|
self.Append(desce[1].SyntDefault())
|
||||||
# synt.Populate()
|
elif isinstance(desce, Stype):
|
||||||
|
self.Append(SyntHole.SyntDefault())
|
||||||
|
|
||||||
def DesceChild(self, isyntChild):
|
def DesceChild(self, isyntChild):
|
||||||
isyntDesce = 0;
|
isyntDesce = 0
|
||||||
for desce in self.Desc():
|
for desce in self.Desc():
|
||||||
if isinstance(desce, tuple):
|
if isinstance(desce, Stype) or hasattr(desce, "SyntDefault") or isinstance(desce, tuple):
|
||||||
if isyntDesce == isyntChild:
|
if isyntDesce == isyntChild:
|
||||||
return desce
|
return desce
|
||||||
isyntDesce += 1
|
isyntDesce += 1
|
||||||
return None
|
|
||||||
|
|
||||||
def RtypeTopForChild(self, syntChild):
|
|
||||||
isyntChild = self.Isynt(syntChild)
|
|
||||||
desce = self.DesceChild(isyntChild)
|
|
||||||
if desce != None and isinstance(desce[1], tuple):
|
|
||||||
return desce[1][0]
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def RgsyntForChild(self, syntChild, st):
|
def StypeForChild(self, syntChild):
|
||||||
isyntChild = self.Isynt(syntChild)
|
isyntChild = self.Isynt(syntChild)
|
||||||
desce = self.DesceChild(isyntChild)
|
desce = self.DesceChild(isyntChild)
|
||||||
if desce != None:
|
if isinstance(desce, Stype):
|
||||||
rtype = None
|
return desce
|
||||||
if isinstance(desce[1], tuple):
|
elif isinstance(desce, tuple):
|
||||||
rtype = desce[1][1]
|
return desce[0]
|
||||||
return desce[0].RgsyntReplace(syntChild, st, rtype)
|
|
||||||
return []
|
|
||||||
def Project(self, pcur):
|
def Project(self, pcur):
|
||||||
"adds more horizontal pws to a horizontal pw"
|
"adds more horizontal pws to a horizontal pw"
|
||||||
isynt = 0
|
isynt = 0
|
||||||
|
@ -249,13 +252,13 @@ class SyntDesc(Synt):
|
||||||
PwStatic(pcur.PwHoriz(self), desce)
|
PwStatic(pcur.PwHoriz(self), desce)
|
||||||
elif isinstance(desce, list):
|
elif isinstance(desce, list):
|
||||||
# selection for the synt itself
|
# selection for the synt itself
|
||||||
self.syntParent.ProjectTypeinForChild(pcur.PwHoriz(self), self, desce[0])
|
self.ProjectTypein(pcur)
|
||||||
elif isinstance(desce, tuple):
|
elif isinstance(desce, Stype) or hasattr(desce, "SyntDefault") or isinstance(desce, tuple):
|
||||||
# embedded syntax
|
# embedded syntax
|
||||||
self.rgsynt[isynt].Project(pcur)
|
self.rgsynt[isynt].Project(pcur)
|
||||||
isynt += 1
|
isynt += 1
|
||||||
|
|
||||||
class SyntName(Synt):
|
class SyntText(Synt):
|
||||||
def InitPersistent(self):
|
def InitPersistent(self):
|
||||||
Synt.InitPersistent(self)
|
Synt.InitPersistent(self)
|
||||||
self.st = ""
|
self.st = ""
|
||||||
|
@ -263,39 +266,18 @@ class SyntName(Synt):
|
||||||
Synt.InitTransient(self)
|
Synt.InitTransient(self)
|
||||||
self.SetStTypein(self.st)
|
self.SetStTypein(self.st)
|
||||||
def Project(self, pcur):
|
def Project(self, pcur):
|
||||||
PwTypein(pcur.PwHoriz(self), self.St(), self)
|
PwTypein(pcur.PwHoriz(self), self.St(), self, ansi.GREEN)
|
||||||
def St(self):
|
def St(self):
|
||||||
return self.GetStTypein()
|
return self.GetStTypein()
|
||||||
def HandleTypeinKey(self, key):
|
def HandleTypeinKey(self, key):
|
||||||
val = Synt.HandleTypeinKey(self, key)
|
val = Synt.HandleTypeinKey(self, key)
|
||||||
self.st = self.GetStTypein()
|
self.st = self.GetStTypein()
|
||||||
return val
|
return val
|
||||||
|
|
||||||
class SyntExpr(Synt):
|
|
||||||
rgclsSyntOp = []
|
|
||||||
@classmethod
|
|
||||||
def RgsyntReplace(cls, syntChild, st, rtype):
|
|
||||||
for synt in RtypeAny().RgsyntFromSt(syntChild.syntParent, st):
|
|
||||||
yield synt
|
|
||||||
for clsSyntOp in cls.rgclsSyntOp:
|
|
||||||
if clsSyntOp.StForTypein().lower().startswith(st.lower()):
|
|
||||||
yield clsSyntOp.SyntDefault()
|
|
||||||
|
|
||||||
def Project(self, pcur):
|
|
||||||
self.syntParent.ProjectTypeinForChild(pcur.PwHoriz(self), self, " ")
|
|
||||||
def Eval(self, vm):
|
def Eval(self, vm):
|
||||||
Fail.Push(vm, "Empty expression", self)
|
return self.st
|
||||||
|
|
||||||
class SyntLine(SyntDesc):
|
class SyntHole(SyntDesc):
|
||||||
rgclsStmt = []
|
desc = [[" "]]
|
||||||
desc = [[" "]]
|
|
||||||
@classmethod
|
|
||||||
def RgsyntReplace(cls, syntChild, st, rtype):
|
|
||||||
for clsStmt in cls.rgclsStmt:
|
|
||||||
if clsStmt.StForTypein().lower().startswith(st.lower()):
|
|
||||||
yield clsStmt()
|
|
||||||
def Compile(self):
|
|
||||||
return []
|
|
||||||
|
|
||||||
class SyntBlock(Synt):
|
class SyntBlock(Synt):
|
||||||
def Project(self, pcur):
|
def Project(self, pcur):
|
||||||
|
@ -305,19 +287,19 @@ class SyntBlock(Synt):
|
||||||
pcur.pwVert = PwBlock(None, self, pcur.dxindent)
|
pcur.pwVert = PwBlock(None, self, pcur.dxindent)
|
||||||
def OnInsertNewLine(syntAfter, psel):
|
def OnInsertNewLine(syntAfter, psel):
|
||||||
self.InsertLineAfter(syntAfter, None)
|
self.InsertLineAfter(syntAfter, None)
|
||||||
psel.Inc(pcur.pwVert)
|
psel.Inc(pcur.pwVert) # does nothing because we need to reproject
|
||||||
PwButtonHidden(pcur.pwVert, "[insert new line]", None, OnInsertNewLine, pcur.dxindent)
|
PwButtonHidden(pcur.pwVert, "[insert new line]", None, OnInsertNewLine, pcur.dxindent)
|
||||||
for syntLine in self.rgsynt:
|
for syntLine in self.rgsynt:
|
||||||
pwKey = PwKeyHandler(pcur.pwVert, self.HandleKey)
|
pwKey = PwKeyHandler(pcur.pwVert, self.HandleKey)
|
||||||
with pcur.ProjectHoriz(pwKey, syntLine):
|
with pcur.ProjectHoriz(pwKey, syntLine):
|
||||||
syntLine.Project(pcur)
|
syntLine.Project(pcur)
|
||||||
|
|
||||||
def RgsyntForChild(self, syntChild, st):
|
|
||||||
return SyntLine.RgsyntReplace(syntChild, st, None)
|
|
||||||
|
|
||||||
|
def StypeForChild(self, syntChild):
|
||||||
|
return StypeStmt()
|
||||||
|
|
||||||
def InsertLineAfter(self, syntAfter, syntStmt):
|
def InsertLineAfter(self, syntAfter, syntStmt):
|
||||||
if syntStmt == None:
|
if syntStmt == None:
|
||||||
syntStmt = SyntLine()
|
syntStmt = SyntHole()
|
||||||
if syntAfter == None:
|
if syntAfter == None:
|
||||||
self.rgsynt.insert(0, syntStmt)
|
self.rgsynt.insert(0, syntStmt)
|
||||||
else:
|
else:
|
||||||
|
@ -331,8 +313,11 @@ 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
|
def Eval(self, vm):
|
||||||
|
for synt in self.rgsynt:
|
||||||
|
# todo: log failures
|
||||||
|
synt.Eval(vm)
|
||||||
|
|
||||||
class SyntLit(Synt):
|
class SyntLit(Synt):
|
||||||
def InitPersistent(self, value, rtype):
|
def InitPersistent(self, value, rtype):
|
||||||
|
@ -344,137 +329,80 @@ class SyntLit(Synt):
|
||||||
def Rtype(self):
|
def Rtype(self):
|
||||||
return self.rtype
|
return self.rtype
|
||||||
def Project(self, pcur):
|
def Project(self, pcur):
|
||||||
self.syntParent.ProjectTypeinForChild(pcur.PwHoriz(self), self, self.StForTypein())
|
self.ProjectTypein(pcur)
|
||||||
def Eval(self, vm):
|
def Eval(self, vm):
|
||||||
vm.Push(self.value)
|
return self.value
|
||||||
|
|
||||||
|
class SyntFlagRef(Synt):
|
||||||
|
def InitPersistent(self, flagdef = None):
|
||||||
|
Synt.InitPersistent(self)
|
||||||
|
self.flagdef = flagdef
|
||||||
|
|
||||||
|
def StForTypein(self):
|
||||||
|
if self.flagdef:
|
||||||
|
return self.flagdef.stName
|
||||||
|
return "<flag>"
|
||||||
|
|
||||||
|
def Project(self, pcur):
|
||||||
|
self.ProjectTypein(pcur)
|
||||||
|
|
||||||
|
def Eval(self, vm):
|
||||||
|
try:
|
||||||
|
return vm.FFlagSet(self.flagdef)
|
||||||
|
except:
|
||||||
|
return Fail("No such flag", self)
|
||||||
|
|
||||||
|
class SyntIsFlagSet(SyntDesc):
|
||||||
|
desc = [["set"]]
|
||||||
|
def Eval(self, vm, val):
|
||||||
|
return val
|
||||||
|
class SyntIsFlagUnset(SyntDesc):
|
||||||
|
desc = [["not set"]]
|
||||||
|
def Eval(self, vm, val):
|
||||||
|
return not val
|
||||||
|
class SyntIsFlagEqualTo(SyntDesc):
|
||||||
|
desc = [["equal to"], " ", RtypeFlag()]
|
||||||
|
flag = SyntDesc.DefProp(0)
|
||||||
|
def Eval(self, vm, val):
|
||||||
|
return val == self.flag.Eval(vm)
|
||||||
|
class SyntIsFlagNotEqualTo(SyntDesc):
|
||||||
|
desc = [["not equal to"], " ", RtypeFlag()]
|
||||||
|
flag = SyntDesc.DefProp(0)
|
||||||
|
def Eval(self, vm, val):
|
||||||
|
return val != self.flag.Eval(vm)
|
||||||
|
|
||||||
|
class StypeFlagTest(StypeEnum):
|
||||||
|
rgclsSynt = [SyntIsFlagSet, SyntIsFlagUnset, SyntIsFlagEqualTo, SyntIsFlagNotEqualTo]
|
||||||
|
|
||||||
@RegStmt
|
@RegStmt
|
||||||
class SyntVar(SyntDesc):
|
|
||||||
desc = [["Define"], " ", (SyntName, None), " to be ", (SyntExpr, 1)]
|
|
||||||
name = SyntDesc.DefProp(0)
|
|
||||||
expr = SyntDesc.DefProp(1)
|
|
||||||
@classmethod
|
|
||||||
def FVarOfType(cls, synt, 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):
|
|
||||||
def InitPersistent(self, syntVar = None):
|
|
||||||
Synt.InitPersistent(self)
|
|
||||||
self.syntVar = syntVar
|
|
||||||
@classmethod
|
|
||||||
def RgsyntReplace(cls, syntChild, st, rtype):
|
|
||||||
rtype = rtype or RtypeAny()
|
|
||||||
return rtype.RgsyntVarRefFromSt(syntChild, st)
|
|
||||||
def Rtype(self):
|
|
||||||
return self.syntVar.Rtype()
|
|
||||||
def StForTypein(self):
|
|
||||||
if self.syntVar:
|
|
||||||
return self.syntVar.name.St()
|
|
||||||
return "<var>"
|
|
||||||
def Project(self, pcur):
|
|
||||||
self.syntParent.ProjectTypeinForChild(pcur.PwHoriz(self), self, self.StForTypein())
|
|
||||||
def Eval(self, vm):
|
|
||||||
vm.Push(vm.vars.Get(self.syntVar, self))
|
|
||||||
|
|
||||||
class SyntBinOp(SyntDesc):
|
|
||||||
@classmethod
|
|
||||||
def Desc(cls):
|
|
||||||
return [(SyntExpr, None), " ", [cls.op], " ", (SyntExpr, None)]
|
|
||||||
left = SyntDesc.DefProp(0)
|
|
||||||
right = SyntDesc.DefProp(1)
|
|
||||||
@classmethod
|
|
||||||
def Create(cls, op, rtype, dgEval = None, stNameI = None):
|
|
||||||
def Decorate(dgEval):
|
|
||||||
stName = stNameI or dgEval.__name__
|
|
||||||
def Eval(self, vm):
|
|
||||||
right = vm.Pop()
|
|
||||||
left = vm.Pop()
|
|
||||||
try:
|
|
||||||
vm.Push(dgEval(left, right))
|
|
||||||
except Exception as e:
|
|
||||||
Fail.Push(vm, "Failed to " + op + ": " + str(e), self)
|
|
||||||
def Compile(self):
|
|
||||||
return [self.left, self.right, self.Eval]
|
|
||||||
clsNew = type(stName, (cls,), {"Compile": Compile, "Eval": Eval, "op": op})
|
|
||||||
SyntExpr.rgclsSyntOp.append(clsNew)
|
|
||||||
return clsNew
|
|
||||||
|
|
||||||
if dgEval == None: # used as a decorator
|
|
||||||
return Decorate
|
|
||||||
clsNew = Decorate(dgEval)
|
|
||||||
if stNameI != None:
|
|
||||||
globals()[stNameI] = clsNew
|
|
||||||
return clsNew
|
|
||||||
|
|
||||||
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, "SyntMult")
|
|
||||||
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, "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
|
|
||||||
class SyntIf(SyntDesc):
|
class SyntIf(SyntDesc):
|
||||||
desc = [["If"], " ", (SyntExpr, (1, RtypeBool)), ", then:", (SyntBlock, None), "or else:", (SyntBlock, None)]
|
desc = [["If"], " ", RtypeFlag(), " is ", (StypeFlagTest(), SyntIsFlagSet), ", then:", SyntBlock, "or else:", SyntBlock]
|
||||||
expr = SyntDesc.DefProp(0)
|
expr = SyntDesc.DefProp(0)
|
||||||
blockIfTrue = SyntDesc.DefProp(1)
|
test = SyntDesc.DefProp(1)
|
||||||
blockIfFalse = SyntDesc.DefProp(2)
|
blockIfTrue = SyntDesc.DefProp(2)
|
||||||
def Compile(self):
|
blockIfFalse = SyntDesc.DefProp(3)
|
||||||
return [self.expr, self.Compare, self.PopCtx]
|
def Eval(self, vm):
|
||||||
def Compare(self, vm):
|
if self.test.Eval(vm, self.expr.Eval(vm)):
|
||||||
val = vm.Pop()
|
return self.blockIfTrue.Eval(vm)
|
||||||
vm.vars.Push() # lexical scoping, bitches
|
|
||||||
if val:
|
|
||||||
return self.blockIfTrue
|
|
||||||
else:
|
else:
|
||||||
return self.blockIfFalse
|
return self.blockIfFalse.Eval(vm)
|
||||||
def PopCtx(self, vm):
|
|
||||||
vm.vars.Pop()
|
|
||||||
|
|
||||||
@RegStmt
|
@RegStmt
|
||||||
class SyntSet(SyntDesc):
|
class SyntSet(SyntDesc):
|
||||||
desc = [["Set"], " ", (SyntVarRef, 1), " to ", (SyntExpr, 1)]
|
desc = [["Set flag"], " ", RtypeFlag(), " to ", RtypeUnion(RtypeBool(), RtypeFlag())]
|
||||||
lvalue = SyntDesc.DefProp(0)
|
lvalue = SyntDesc.DefProp(0)
|
||||||
expr = SyntDesc.DefProp(1)
|
expr = SyntDesc.DefProp(1)
|
||||||
def Compile(self):
|
|
||||||
return [self.expr, self.Eval]
|
|
||||||
def Eval(self, vm):
|
def Eval(self, vm):
|
||||||
val = vm.Pop()
|
# todo: fail if flagdef or expr isn't set properly?
|
||||||
if not isinstance(val, Fail):
|
vm.SetFlag(self.lvalue.flagdef, self.expr.Eval(vm))
|
||||||
vm.Log(vm.vars.Set(self.lvalue.syntVar, vm.Pop(), self))
|
|
||||||
|
|
||||||
class SyntEvent(SyntDesc):
|
|
||||||
rgclsSyntEvent = []
|
|
||||||
desc = [[" "]]
|
|
||||||
@classmethod
|
|
||||||
def RgsyntReplace(cls, syntChild, st, rtype):
|
|
||||||
for clsSyntEvent in cls.rgclsSyntEvent:
|
|
||||||
if clsSyntEvent.StForTypein().lower().startswith(st.lower()):
|
|
||||||
yield clsSyntEvent.SyntDefault()
|
|
||||||
for synt in SyntExpr.RgsyntReplace(syntChild, st, rtype):
|
|
||||||
yield synt
|
|
||||||
|
|
||||||
class SyntWhen(SyntDesc):
|
|
||||||
desc = [["When"], " ", (SyntEvent, 1), ":", (SyntBlock, 2)]
|
|
||||||
|
|
||||||
#debug
|
|
||||||
@RegStmt
|
@RegStmt
|
||||||
class SyntPrint(SyntDesc):
|
class SyntPrint(SyntDesc):
|
||||||
desc = [["Print"], " ", (SyntExpr, 1)]
|
desc = [["Show Message"], " \"", SyntText, "\""]
|
||||||
expr = SyntDesc.DefProp(0)
|
expr = SyntDesc.DefProp(0)
|
||||||
def Compile(self):
|
|
||||||
return [self.expr, self.Eval]
|
|
||||||
def Eval(self, vm):
|
def Eval(self, vm):
|
||||||
print vm.Pop()
|
# todo
|
||||||
|
print(self.expr.Eval(vm))
|
||||||
|
|
||||||
class Fail(TPrs):
|
class Fail(TPrs):
|
||||||
"""
|
"""
|
||||||
|
@ -483,27 +411,21 @@ class Fail(TPrs):
|
||||||
edit a script while the game is running and see the effect of their changes immediately; this suggests that failures
|
edit a script while the game is running and see the effect of their changes immediately; this suggests that failures
|
||||||
should be logged and the script should continue to run.
|
should be logged and the script should continue to run.
|
||||||
"""
|
"""
|
||||||
def InitPersistent(self, stFailure, synt):
|
def InitPersistent(self, vm, stFailure, synt):
|
||||||
self.stFailure = stFailure
|
self.stFailure = stFailure
|
||||||
self.synt = synt
|
self.synt = synt
|
||||||
@staticmethod
|
vm.Log(self)
|
||||||
def Push(vm, stFailure, synt):
|
|
||||||
fail = Fail(stFailure, synt)
|
|
||||||
vm.Push(fail)
|
|
||||||
vm.Log(fail)
|
|
||||||
@staticmethod
|
|
||||||
def Log(vm, stFailure, synt):
|
|
||||||
vm.Log(Fail(stFailure, synt))
|
|
||||||
|
|
||||||
# projection cursor
|
# projection cursor
|
||||||
class Pcur(object):
|
class Pcur(object):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def PwProjected(synt):
|
def PwProjected(defs, synt):
|
||||||
pcur = Pcur()
|
pcur = Pcur(defs)
|
||||||
synt.Project(pcur)
|
synt.Project(pcur)
|
||||||
return pcur.pwVert
|
return pcur.pwVert
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, defs):
|
||||||
|
self.defs = defs
|
||||||
self.pwVert = None
|
self.pwVert = None
|
||||||
self.pwHoriz = None
|
self.pwHoriz = None
|
||||||
self.dxindent = 0
|
self.dxindent = 0
|
||||||
|
@ -633,13 +555,14 @@ class PwStatic(Pw):
|
||||||
ascr.PutSt(snippet.st, x, y, self.ColFg(), self.ColBg(ksel))
|
ascr.PutSt(snippet.st, x, y, self.ColFg(), self.ColBg(ksel))
|
||||||
|
|
||||||
class PwTypein(PwStatic):
|
class PwTypein(PwStatic):
|
||||||
def __init__(self, pwParent, stSobj, typeable):
|
def __init__(self, pwParent, stSobj, typeable, colBgDefault = ansi.BLUE):
|
||||||
if typeable.GetStTypein() == None:
|
if typeable.GetStTypein() == None:
|
||||||
stDisplay = stSobj
|
stDisplay = stSobj
|
||||||
else:
|
else:
|
||||||
stDisplay = None
|
stDisplay = None
|
||||||
PwStatic.__init__(self, pwParent, stDisplay)
|
PwStatic.__init__(self, pwParent, stDisplay)
|
||||||
self.typeable = typeable
|
self.typeable = typeable
|
||||||
|
self.colBgDefault = colBgDefault
|
||||||
def Value(self):
|
def Value(self):
|
||||||
return self.typeable
|
return self.typeable
|
||||||
def StTextDisplay(self, ksel):
|
def StTextDisplay(self, ksel):
|
||||||
|
@ -653,7 +576,7 @@ class PwTypein(PwStatic):
|
||||||
return ansi.YELLOW
|
return ansi.YELLOW
|
||||||
elif ksel == Ksel.OTHERNAV:
|
elif ksel == Ksel.OTHERNAV:
|
||||||
return ansi.MAGENTA
|
return ansi.MAGENTA
|
||||||
return ansi.BLUE
|
return self.colBgDefault
|
||||||
def HandleKey(self, pov, psel, key):
|
def HandleKey(self, pov, psel, key):
|
||||||
return self.typeable.HandleTypeinKey(key)
|
return self.typeable.HandleTypeinKey(key)
|
||||||
def Draw(self, ascr, x, y, w, dxStart, mpksel, fOverlay):
|
def Draw(self, ascr, x, y, w, dxStart, mpksel, fOverlay):
|
||||||
|
@ -899,20 +822,20 @@ class Psel(TPrs):
|
||||||
|
|
||||||
# projector overlay -- handles navigation, drawing the projection, etc
|
# projector overlay -- handles navigation, drawing the projection, etc
|
||||||
class Pov(TokenClient):
|
class Pov(TokenClient):
|
||||||
def InitPersistent(self, owner, client, block):
|
def InitPersistent(self, owner, client, defs, block):
|
||||||
TokenClient.InitPersistent(self, owner, client, "drawable", "overlay")
|
TokenClient.InitPersistent(self, owner, client, "drawable", "overlay")
|
||||||
|
self.defs = defs
|
||||||
self.block = block
|
self.block = block
|
||||||
self.pselstate = self.game.rgtoken("pselstate")[0]
|
self.pselstate = self.game.rgtoken("pselstate")[0]
|
||||||
|
|
||||||
def PwProjected(self):
|
def PwProjected(self):
|
||||||
return Pcur.PwProjected(self.block)
|
return Pcur.PwProjected(self.defs, self.block)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
while True:
|
while True:
|
||||||
key = self.client.evKey.receive(self)
|
key = self.client.evKey.receive(self)
|
||||||
if key == ansi.K_PGDN:
|
if key == ansi.K_PGDN:
|
||||||
Vm().RunSynt(self.block)
|
self.block.Eval(Vm(self.defs))
|
||||||
continue
|
|
||||||
psel = self.pselstate.PselByClient(self.client)
|
psel = self.pselstate.PselByClient(self.client)
|
||||||
pwSel = psel.PwSelected(self.PwProjected())
|
pwSel = psel.PwSelected(self.PwProjected())
|
||||||
while pwSel != None:
|
while pwSel != None:
|
||||||
|
@ -928,8 +851,9 @@ class Pov(TokenClient):
|
||||||
pw.Draw(ascr, 1, 1, ascr.W(), 0, mpksel, True)
|
pw.Draw(ascr, 1, 1, ascr.W(), 0, mpksel, True)
|
||||||
|
|
||||||
class PselState(LeaveJoinToken):
|
class PselState(LeaveJoinToken):
|
||||||
def InitPersistent(self, owner, block):
|
def InitPersistent(self, owner, defs, block):
|
||||||
Token.InitPersistent(self, owner, "pselstate")
|
Token.InitPersistent(self, owner, "pselstate")
|
||||||
|
self.defs = defs
|
||||||
self.block = block
|
self.block = block
|
||||||
def InitTransient(self):
|
def InitTransient(self):
|
||||||
Token.InitTransient(self)
|
Token.InitTransient(self)
|
||||||
|
@ -937,8 +861,8 @@ class PselState(LeaveJoinToken):
|
||||||
def OnLeave(self, client):
|
def OnLeave(self, client):
|
||||||
del self.mpclient_psel[client]
|
del self.mpclient_psel[client]
|
||||||
def OnJoin(self, client):
|
def OnJoin(self, client):
|
||||||
print "client joined,", client
|
print("client joined,", client)
|
||||||
self.mpclient_psel[client] = Psel(Pcur.PwProjected(self.block).PwFirstSelectable(), Ksel.NAV)
|
self.mpclient_psel[client] = Psel(Pcur.PwProjected(self.defs, self.block).PwFirstSelectable(), Ksel.NAV)
|
||||||
class Mpksel(object):
|
class Mpksel(object):
|
||||||
def __init__(self, pwRoot, client, mpclient_psel):
|
def __init__(self, pwRoot, client, mpclient_psel):
|
||||||
self.mppw_ksel = {}
|
self.mppw_ksel = {}
|
||||||
|
@ -960,10 +884,13 @@ class PselState(LeaveJoinToken):
|
||||||
class GameScriptTest(Game):
|
class GameScriptTest(Game):
|
||||||
def InitPersistent(self):
|
def InitPersistent(self):
|
||||||
Game.InitPersistent(self)
|
Game.InitPersistent(self)
|
||||||
|
self.defs = Defs()
|
||||||
|
self.defs.AddFlag("flag1", True)
|
||||||
|
self.defs.AddFlag("flag2", False)
|
||||||
self.block = SyntBlock()
|
self.block = SyntBlock()
|
||||||
|
|
||||||
def GetRgclsTokTrans(self):
|
def GetRgclsTokTrans(self):
|
||||||
return [[PselState, self.block], [AutoJoiner, [Pov, self.block]]]
|
return [[PselState, self.defs, self.block], [AutoJoiner, [Pov, self.defs, self.block]]]
|
||||||
|
|
||||||
class RunnerScriptTest(Runner):
|
class RunnerScriptTest(Runner):
|
||||||
def InitPersistent(self):
|
def InitPersistent(self):
|
||||||
|
|
Loading…
Reference in a new issue