scripting overhaul

This commit is contained in:
Jeremy Penner 2011-09-06 22:14:17 -04:00
parent 60ca1e19f1
commit 6213a0f917
2 changed files with 411 additions and 260 deletions

47
script-thoughts.txt Normal file
View file

@ -0,0 +1,47 @@
How to refer to things
====
MarMOTS: set model?
when sending a message: send to all in set (useful? or explicit foreach better?)
when asking a question: ask a random member? if != 1 I think this is almost never what you really want.
====
1) construct model:
all values (except for constants) come from some class of object, of which there are always only small number available to you
the instance of the class that you query is chosen by narrowing the set by "picking" in the event conditions
pros of picking:
= lets you say when(anything) and have it make sense
= if there is only one of something you always get it right
cons:
= not always an easy way to express what you want
2) game maker:
self, other, pick
-- gml has the set model!
other == other involved in collision
=============
namespaces:
---------------------------------------------|--------------
| * System *
| Thing
| Whatsit
| Enemy
| ...
| variable?
some core stuff should be global (if, expr, true, false)
I keep forgetting that this kind of interface suggests type inference
what is a type? it's
- number
- string (ansi)
- boolean (yes/no)
- object<|x,y,z|>
- with mixins x, y, z
object<|x|> is a subtype of object<|x,y|>
- list<t>
- void
- t

View file

@ -2,6 +2,308 @@ from engine import *
from basetoken import * from basetoken import *
from tpers import * from tpers import *
from util import * from util import *
from contextlib import contextmanager
def RegStmt(clsStmt):
SyntLine.rgclsStmt.append(clsStmt)
return clsStmt
def RegRtype(clsRtype):
Rtype.rgclsRtype.append(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):
rgclsRtype = []
@classmethod
def RtypeMax(cls):
return cls()
def RglitFromSt(self, st):
return []
def RgsyntFromSt(self, syntBlock, st):
for lit in self.RglitFromSt(st):
yield SyntLit(None, lit, self)
while syntBlock != None:
if isinstance(syntBlock, SyntBlock):
for synt in self.RgsyntFromSyntBlock(syntBlock, st):
yield synt
syntBlock = syntBlock.syntParent
# helper for RgsyntFromSt
def RgsyntFromSyntBlock(self, syntBlock, st):
# yield all vars in scope
for syntLine in syntBlock.rgsynt:
if SyntVar.FVarOfType(syntLine.rgsynt[0], self):
yield SyntVarRef(None, syntLine.rgsynt[0])
def StForSobj(self, sobj):
return str(sobj)
def FMember(self, sobj):
return isinstance(sobj, self.pythontype)
def FOverlap(self, rtype):
return isinstance(rtype, self.__class__)
@RegRtype
class RtypeBool(Rtype):
pythontype = bool
def RglitFromSt(self, st):
if "true".startswith(st.lower()):
yield True
if "false".startswith(st.lower()):
yield False
@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):
def RgsyntFromSt(self, syntBlock, st):
for clsRtype in self.rgclsRtype:
rtype = clsRtype.RtypeMax()
for synt in rtype.RgsyntFromSt(syntBlock, st):
yield synt
def FMember(self, sobj):
return True
def FOverlap(self, rtype):
return True
class Typeable(TPrs):
def InitTransient(self):
self.steditTypein = Stedit()
def GetStTypein(self):
st = self.steditTypein.GetValue()
return None if st == "" else st
def SetStTypein(self, stTypein):
self.steditTypein.SetValue(stTypein or "")
def HandleTypeinKey(self, key):
return self.steditTypein.HandleKey(key)
# synt -- a piece of syntax
# method: Project() -- projects it
#
class Synt(Typeable):
desc = None
def InitPersistent(self, syntParent):
self.syntParent = syntParent
self.rgsynt = []
self.Populate()
@classmethod
def SyntDefault(cls, syntParent):
return cls(syntParent)
def ProjectTypeinForChild(self, pwParent, syntChild, st):
def OnSelect(synt, psel):
self.Replace(syntChild, synt)
syntChild.SetStTypein(None)
if syntChild.GetStTypein() != None:
pwParent = PwDropdown(pwParent)
PwTypein(pwParent, st, syntChild)
if syntChild.GetStTypein() != None:
for synt in self.RgsyntForChild(syntChild, syntChild.GetStTypein()):
PwButton(pwParent, synt.StForTypein(), synt, OnSelect)
def RgsyntForChild(self, syntChild, st):
return []
def Replace(self, syntOld, syntNew):
self.rgsynt[self.Isynt(syntOld)] = syntNew
syntNew.syntParent = self
def Isynt(self, syntChild):
if isinstance(syntChild, int):
return syntChild
return self.rgsynt.index(syntChild)
def Rtype(self):
return None
def RtypeTopForChild(self, syntChild):
return None
def Eval(self, ectx):
pass
def Populate(self):
pass
def Project(self, pcur):
pass
# desc - list of desces
# desce:
# string: "foo" -- literal uneditable text
# list: ["foo"] -- text to edit the current synt
# tuple: (clsSynt, type) -- child description
# clsSynt: class of child synt
# type: number - same as another child expression with that number
# None - no rtype specified / possible
# tuple (number, rtypeTop) - number == same as another child expression with that number, rtypeTop = required type
class SyntDesc(Synt):
@classmethod
def StForTypein(cls):
for desce in cls.desc:
if isinstance(desce, list) and len(desce) == 1:
return desce[0]
@staticmethod
def DefProp(isynt):
def get(self):
return self.rgsynt[isynt]
def set(self, syntNew):
self.Replace(isynt, syntNew)
def delete(self):
self.Replace(isynt, None)
return property(get, set, delete)
def Populate(self):
for desce in self.desc:
if isinstance(desce, tuple):
synt = desce[0].SyntDefault(self)
self.rgsynt.append(synt)
# for synt in self.rgsynt:
# synt.Populate()
def SyntProperty(self, isynt):
def get():
return self.rgsynt[isynt]
def set(syntNew):
self.Replace(isynt, syntNew)
def delete():
self.Replace(isynt, None)
return property(get, set, delete)
def RtypeTopForChild(self, syntChild):
isyntChild = self.Isynt(syntChild)
isyntDesce = 0
for desce in self.desc:
if isinstance(desce, tuple):
if isyntDesce == isyntChild:
if isinstance(desce[1], tuple):
return desce[1][0]
return None
isyntDesce += 1
return None
def Project(self, pcur):
"adds more horizontal pws to a horizontal pw"
isynt = 0
for desce in self.desc:
if isinstance(desce, str):
PwStatic(pcur.PwHoriz(self), desce)
elif isinstance(desce, list):
# selection for the synt itself
self.syntParent.ProjectTypeinForChild(pcur.PwHoriz(self), self, desce[0])
elif isinstance(desce, tuple):
# embedded syntax
self.rgsynt[isynt].Project(pcur)
isynt += 1
class SyntName(Synt):
def Project(self, pcur):
PwTypein(pcur.PwHoriz(self), self.GetStTypein(), self)
class SyntExpr(Synt):
def Project(self, pcur):
self.syntParent.ProjectTypeinForChild(pcur.PwHoriz(self), self, " ")
class SyntLine(Synt):
rgclsStmt = []
def Populate(self):
self.rgsynt.append(SyntBlank(self))
def SetStmt(self, syntStmt):
self.Replace(self.rgsynt[0], syntStmt)
def Project(self, pcur):
pwKey = PwKeyHandler(pcur.pwVert, self.HandleKey)
with pcur.ProjectHoriz(pwKey, self):
self.rgsynt[0].Project(pcur)
def RgsyntForChild(self, syntChild, st):
for clsStmt in self.rgclsStmt:
if clsStmt.StForTypein().lower().startswith(st.lower()):
yield clsStmt(None)
def HandleKey(self, pwKey, pov, psel, key):
if ansi.FEnter(key):
self.syntParent.InsertLineAfter(self, None)
psel.Inc(pwKey.PwParent())
return True
return False
class SyntBlock(Synt):
def Project(self, pcur):
with pcur.Indent(2 if pcur.pwHoriz != None else 0):
pcur.EndLine()
if pcur.pwVert == None:
pcur.pwVert = PwBlock(None, self, pcur.dxindent)
def OnInsertNewLine(syntAfter, psel):
self.InsertLineAfter(syntAfter, None)
psel.Inc(pcur.pwVert)
PwButtonHidden(pcur.pwVert, "[insert new line]", None, OnInsertNewLine, pcur.dxindent)
for syntLine in self.rgsynt:
syntLine.Project(pcur)
def InsertLineAfter(self, syntAfter, syntStmt):
syntLine = SyntLine(self)
if syntStmt != None:
syntLine.SetStmt(syntStmt)
if syntAfter == None:
self.rgsynt.insert(0, syntLine)
else:
self.rgsynt.insert(self.rgsynt.index(syntAfter) + 1, syntLine)
return syntLine
class SyntLit(Synt):
def InitPersistent(self, syntParent, value, rtype):
Synt.InitPersistent(self, syntParent)
self.value = value
self.rtype = rtype
def Rtype(self):
return rtype
@RegStmt
class SyntBlank(SyntDesc):
desc = [[" "]]
@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(expr.Rtype())
class SyntVarRef(Synt):
def __init__(self, syntParent, syntVar = None):
Synt.__init__(self, syntParent)
self.syntVar = syntVar
def Rtype(self):
return self.syntVar.Rtype()
@RegStmt
class SyntIf(SyntDesc):
desc = [["If"], " ", (SyntExpr, (1, RtypeBool)), ", then:", (SyntBlock, None), "or else:", (SyntBlock, None)]
expr = SyntDesc.DefProp(0)
blockIfTrue = SyntDesc.DefProp(1)
blockIfFalse = SyntDesc.DefProp(2)
# scope -- a block? a scril? (scril lets you specifically avoid vars that are defined after a certain point) + game? # scope -- a block? a scril? (scril lets you specifically avoid vars that are defined after a certain point) + game?
# method: rgvar(stype) -- returns a list of variables in scope that match the current stype # method: rgvar(stype) -- returns a list of variables in scope that match the current stype
@ -25,265 +327,45 @@ from util import *
# ectxReturn # ectxReturn
# methods: call(block) # methods: call(block)
class Block(TPrs):
def InitPersistent(self, scrilParent):
self.rgscril = []
self.scrilParent = scrilParent
def InsertScrilAfter(self, scrilAfter, scmd = None):
scrilNew = Scril(self, scmd)
if scrilAfter == None:
self.rgscril.insert(0, scrilNew)
else:
self.rgscril.insert(self.rgscril.index(scrilAfter) + 1, scrilNew)
return scrilNew
def Project(self, pwBlock, dxIndent = 0):
if pwBlock == None:
pwBlock = PwBlock(None, self, 0)
PwButtonHidden(pwBlock, "[insert new line]", None, self.InsertScrilAfter, dxIndent)
for scril in self.rgscril:
scril.Project(pwBlock, dxIndent)
return pwBlock
class Typeable(TPrs):
def InitTransient(self):
self.steditTypein = Stedit()
def GetStTypein(self):
st = self.steditTypein.GetValue()
return None if st == "" else st
def SetStTypein(self, stTypein):
self.steditTypein.SetValue(stTypein or "")
def HandleTypeinKey(self, key):
return self.steditTypein.HandleKey(key)
# Sarg -- pointer to scripting object / argument to a command
# this object type appears to exist solely so that MiSarg can edit something without digging through a list
class Sarg(Typeable):
def InitPersistent(self, stype, scril):
self.stype = stype
self.sobj = stype.SobjDefault(scril)
def FExpr(self):
"Returns true if the sobj must be evaluated to get a result."
return self.sobj.__class__ == Scril
def Eval(self, ectx):
if self.FExpr():
return self.sobj.Exec(ectx)
else:
return self.sobj
class Fail(TPrs): class Fail(TPrs):
def InitPersistent(self, stFailure): def InitPersistent(self, stFailure):
self.stFailure == stFailure self.stFailure == stFailure
# stype -- a description of a sobj (scripting object) # projection cursor
# method: FMember(sobj) -- returns true if an object is in the set of things that this stype represents class Pcur(object):
# method: FOverlaps(stype) -- returns true if there is some overlap between the two stypes @staticmethod
# -- there is no subtype/supertype relation because stypes are used to help the user, def PwProjected(synt):
# and I suspect being specific in this manner is too much of a burden to place on them. pcur = Pcur()
# methods: rgsarg(scope) -- returns a list of all legal objects that exist in the current scope synt.Project(pcur)
# this includes functions which return things of this stype, and variables return pcur.pwVert
# literals are not included
# project(cls, game, sarg) -- returns an MiSarg which displays and edits (default sproj for a sarg?)
class Stype(object):
"""A definition of a scripting object type. All methods are class methods; stypes are never instantiated."""
def __init__(self): def __init__(self):
raise "do not instantiate stypes" self.pwVert = None
@classmethod self.pwHoriz = None
def FMember(cls, sobj): self.dxindent = 0
return isinstance(sobj, cls.pythontype)
@classmethod
def FOverlaps(cls, stype):
return stype == self
@classmethod
def Rgsobj(cls, scope):
return []
@classmethod
def Rgsobj_st(cls, scope):
return [(sobj, str(sobj)) for sobj in cls.Rgsobj(scope)]
@classmethod
def OnSelect(cls, sarg, sobj):
sarg.sobj = sobj
@classmethod
def Sproj(cls, sarg, pwBlock, pwScril):
ProjectTypein(pwScril, sarg, str(sarg.sobj), cls.Rgsobj_st, cls.OnSelect)
return False
def ProjectTypein(pwParent, typeable, st, dgRgsobj_st, dgOnSelect): @contextmanager
def OnSelect(sobj): def Indent(self, dxindent = 2):
dgOnSelect(typeable, sobj) self.dxindent += dxindent
typeable.SetStTypein(None) yield
if typeable.GetStTypein() != None: self.dxindent -= dxindent
pwParent = PwDropdown(pwParent)
PwTypein(pwParent, st, typeable)
if typeable.GetStTypein() != None:
for sobj, st in dgRgsobj_st(typeable):
PwButton(pwParent, st, sobj, OnSelect)
class StypeBool(Stype): @contextmanager
pythontype = bool def ProjectHoriz(self, pwParent, synt):
@classmethod self.ProjectHorizI(pwParent, synt)
def SobjDefault(cls, scril): yield
return False self.EndLine()
@classmethod
def Rgsobj(cls, scope):
return [True, False]
class StypeBlock(Stype): def PwHoriz(self, synt):
pythontype = Block if self.pwHoriz == None:
@classmethod self.ProjectHorizI(self.pwVert, synt)
def SobjDefault(cls, scril): return self.pwHoriz
return Block(scril)
@classmethod
def Sproj(cls, sarg, pwBlock, pwScril):
sarg.sobj.Project(pwBlock, pwScril.DxIndent() + 2)
return True
# scmd -- a definition of a scripting command def EndLine(self):
class Scmd(object): self.pwHoriz = None
"""A definition of a scripting command. All methods are class methods; scmds are never instantiated."""
def __init__(self):
raise "do not instantiate scmds"
# used by RegScmd to build a list of all valid scmds for editing def ProjectHorizI(self, pwParent, synt):
rgscmd = [] self.pwHoriz = PwList(pwParent, synt, self.dxindent)
@classmethod
def Rgscmd_st(cls, scril):
return [(scmd, scmd.StName()) for scmd in cls.rgscmd]
@classmethod
def Desc(cls, *rgsarg):
"""
Returns a list of desces. A desce can be a constant string, representing nonselectable helper text,
an sproj, a list containing an sproj and a reference to a passed-in sarg, which explicitly binds that
sproj to that sarg, or a list containing a string, which stands for the selectable text which represents
the scril itself.
ie, [["Move"], " ", [SprojMovable, rgsarg[1]], " to ", [SprojPosition, rgsarg[0]]]
If a bare sproj is given, bind it to the first unbound sarg (after processing all explicitly bound sargs).
This method must accept invalid sargs; it is the sproj's job to relay the invalidness to the user.
"""
return cls.desc
stName = None
@classmethod
def StName(cls):
"Returns the name that the user types in to select this scmd."
if cls.stName != None:
return cls.stName
for desce in cls.Desc(Scril(None, cls).rgsarg):
if type(desce) == list and type(desce[0]) == str:
return desce[0]
assert False, "no selectable self in desc"
@classmethod
def Csarg(cls):
"Returns the number of arguments that this command takes."
return len(cls.rgstypeArg)
@classmethod
def StypeResult(cls):
return cls.stypeResult
@classmethod
def RgstypeArg(cls):
return cls.rgstypeArg
def RegScmd(stypeResult, *rgstypeArg):
def RegI(cls):
cls.stypeResult = stypeResult
cls.rgstypeArg = rgstypeArg
Scmd.rgscmd.append(cls)
return cls
return RegI
@RegScmd(None)
class ScmdBlank(Scmd):
stName = ""
desc = [[" "]]
@classmethod
def Exec(cls, ectx):
pass
@RegScmd(None)
class ScmdHelloWorld(Scmd):
"Hello, world!"
desc = [["Hello World"], "!"]
@classmethod
def Exec(cls, ectx):
print "Hello, world!"
@RegScmd(None, StypeBool, StypeBlock, StypeBlock)
class ScmdIf(Scmd):
desc = [["If"], " ", StypeBool.Sproj, ", then:", StypeBlock.Sproj, "or else:", StypeBlock.Sproj]
@classmethod
def Exec(cls, ectx, sargExpr, sargIfTrue, sargIfFalse):
if sargExpr.Eval(ectx):
print "true!"
# needs work
#===========================================================================
# @RegScmd(None, StypeSt, StypeObj)
# class ScmdVar(Scmd):
# desc = ["Define a new ", ["variable"], " called \"", StypeSt, "\", set to ", StypeObj, "."]
# @classmethod
# def Exec(cls, ectx, sargStName, sargInit):
# ectx.mpvar_sobj[ectx.ScrilCurr()] = sargInit.Eval()
#===========================================================================
class Scril(Typeable):
"A line in a script."
def InitPersistent(self, blockParent, scmd = None):
self.scmd = scmd or ScmdBlank
self.rgsarg = [Sarg(stypeArg, self) for stypeArg in self.scmd.RgstypeArg()]
self.blockParent = blockParent
def SetScmd(self, scmd):
if (scmd.Csarg() > self.scmd.Csarg()):
self.rgsarg.extend([Sarg(stypeArg, self) for stypeArg in scmd.RgstypeArg()[self.scmd.Csarg():]])
elif (scmd.Csarg() < self.scmd.Csarg()):
self.rgsarg = self.rgsarg[:scmd.Csarg()]
self.scmd = scmd
def Exec(self, ectx):
return self.scmd.Exec(ectx, *self.rgsarg)
def HandleKey(self, pwKey, pov, psel, key):
if ansi.FEnter(key):
self.blockParent.InsertScrilAfter(self, ScmdBlank)
return True
return False
def Project(self, pwBlock, dxindent):
"adds horizontal pws to a vertical pw"
pwScril = None
desc = self.scmd.Desc(*self.rgsarg)
rgsargUnbound = list(self.rgsarg)
#filter bound sargs
for desce in desc:
if isinstance(desce, list) and len(desce) > 1:
rgsargUnbound.remove(desce[1])
fNewScril = True
for desce in desc:
if fNewScril:
pwKey = PwKeyHandler(pwBlock, self.HandleKey)
pwScril = PwList(pwKey, self, dxindent)
fNewScril = False
if isinstance(desce, str):
PwStatic(pwScril, desce)
elif isinstance(desce, list):
if isinstance(desce[0], str):
# selection for the scmd / scril
ProjectTypein(pwScril, self, desce[0], Scmd.Rgscmd_st, Scril.SetScmd)
else:
# mapping to sarg
fNewScril = self.ProjectSarg(pwBlock, pwScril, desce[0], desce[1])
else:
# sproj
fNewScril = self.ProjectSarg(pwBlock, pwScril, desce, rgsargUnbound.pop(0))
def ProjectSarg(self, pwBlock, pwScril, sproj, sarg):
return sproj(sarg, pwBlock, pwScril)
# pw - projected widget # pw - projected widget
# Nothing ever depends on the object identity or permanence of a pw! # Nothing ever depends on the object identity or permanence of a pw!
@ -295,6 +377,12 @@ class Pw(object):
if pwParent != None: if pwParent != None:
pwParent.AddChild(self) pwParent.AddChild(self)
self.pwParent = pwParent self.pwParent = pwParent
def PrintTree(self, dxindent = 0):
print (" " * dxindent) + self.StDebug()
for pwChild in self.RgpwChild():
pwChild.PrintTree(dxindent + 2)
def StDebug(self):
return self.__class__.__name__
def PwParent(self): def PwParent(self):
return self.pwParent return self.pwParent
def Value(self): def Value(self):
@ -327,10 +415,31 @@ class PwContainer(Pw):
def FContainer(self): def FContainer(self):
return True return True
class PwContainOne(Pw):
def AddChild(self, pw):
self.pwChild = pw
def RgpwChild(self):
return [self.pwChild]
def FContainer(self):
return True
class PwExpand(PwContainOne):
def DxDyNew(self, w, dxStart, mpksel):
dxdy = self.pwChild.DxDyNew(w, dxStart, mpksel)
if dxdy[0] == 0 and dxdy[1] > 0:
return dxdy
return (0, dxdy[0] + 1)
def Draw(self, ascr, x, y, w, dxStart, mpksel, fOverlay):
if not fOverlay:
ascr.PutSt(" " * w, x, y, self.pwChild.ColFg(), self.pwChild.ColBg(mpksel.Get(self.pwChild)))
self.pwChild.Draw(ascr, x, y, w, dxStart, mpksel, fOverlay)
class PwStatic(Pw): class PwStatic(Pw):
def __init__(self, pwParent, stText): def __init__(self, pwParent, stText):
Pw.__init__(self, pwParent) Pw.__init__(self, pwParent)
self.stText = stText self.stText = stText
def StDebug(self):
return Pw.StDebug(self) + " '" + self.StTextDisplay(Ksel.NAV) + "'"
def DxDyNew(self, w, dxStart, mpksel): def DxDyNew(self, w, dxStart, mpksel):
rgsnippet = self.Rgsnippet(w, dxStart, mpksel) rgsnippet = self.Rgsnippet(w, dxStart, mpksel)
if len(rgsnippet) == 1: if len(rgsnippet) == 1:
@ -414,7 +523,7 @@ class PwButton(PwStatic):
return ansi.BLUE | ansi.FBRIGHT return ansi.BLUE | ansi.FBRIGHT
def HandleKey(self, pov, psel, key): def HandleKey(self, pov, psel, key):
if key == ansi.K_RETURN: if key == ansi.K_RETURN:
self.dgEnter(self.Value()) self.dgEnter(self.Value(), psel)
return True return True
return False return False
@ -632,7 +741,7 @@ class Pov(TokenClient):
self.pselstate = self.game.rgtoken("pselstate")[0] self.pselstate = self.game.rgtoken("pselstate")[0]
def PwProjected(self): def PwProjected(self):
return self.block.Project(None) return Pcur.PwProjected(self.block)
def run(self): def run(self):
while True: while True:
@ -662,7 +771,7 @@ class PselState(Token):
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(self.block.Project(None).PwFirstSelectable(), Ksel.NAV) self.mpclient_psel[client] = Psel(Pcur.PwProjected(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 = {}
@ -689,12 +798,7 @@ class PselState(Token):
class GameScriptTest(Game): class GameScriptTest(Game):
def InitPersistent(self): def InitPersistent(self):
Game.InitPersistent(self) Game.InitPersistent(self)
self.block = Block(None) self.block = SyntBlock(None)
self.block.InsertScrilAfter(None, ScmdHelloWorld)
self.block.InsertScrilAfter(None, ScmdBlank)
self.block.InsertScrilAfter(None, ScmdHelloWorld)
self.block.InsertScrilAfter(None, ScmdIf)
self.block.InsertScrilAfter(None, ScmdHelloWorld)
def GetRgclsTokTrans(self): def GetRgclsTokTrans(self):
return [[PselState, self.block], [AutoJoiner, [Pov, self.block]]] return [[PselState, self.block], [AutoJoiner, [Pov, self.block]]]