From 8e88e8c3e2bc788dfc6bacec2df85655a725c53c Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Thu, 9 Jul 2009 13:11:52 -0500 Subject: [PATCH] final frontend support for protocol state machines. patch includes a minor refactoring as well. --- ipc/ipdl/ipdl/ast.py | 6 +- ipc/ipdl/ipdl/parser.py | 20 +++++-- ipc/ipdl/ipdl/type.py | 126 ++++++++++++++++++++++++++-------------- 3 files changed, 102 insertions(+), 50 deletions(-) diff --git a/ipc/ipdl/ipdl/ast.py b/ipc/ipdl/ipdl/ast.py index 038f48c061c..81b6bd2ddfc 100644 --- a/ipc/ipdl/ipdl/ast.py +++ b/ipc/ipdl/ipdl/ast.py @@ -318,13 +318,17 @@ class Param(Node): self.typespec = typespec class TypeSpec(Node): - def __init__(self, loc, spec): + def __init__(self, loc, spec, state=None): Node.__init__(self, loc) self.spec = spec + self.state = state def basename(self): return self.spec.baseid + def isActor(self): + return self.state is not None + def __str__(self): return str(self.spec) class QualifiedId: # FIXME inherit from node? diff --git a/ipc/ipdl/ipdl/parser.py b/ipc/ipdl/ipdl/parser.py index a2b657a8da9..04b81c05e58 100644 --- a/ipc/ipdl/ipdl/parser.py +++ b/ipc/ipdl/ipdl/parser.py @@ -405,11 +405,23 @@ def p_ParamList(p): p[0] = p[1] def p_Param(p): - """Param : ID ID""" + """Param : Type ID""" + p[0] = Param(locFromTok(p, 1), p[1], p[2]) + +def p_Type(p): + """Type : ActorType + | ID""" # ID == CxxType; we forbid qnames here, + # in favor of the |using| declaration + if isinstance(p[1], TypeSpec): + p[0] = p[1] + else: + loc = locFromTok(p, 1) + p[0] = TypeSpec(loc, QualifiedId(loc, p[1])) + +def p_ActorType(p): + """ActorType : ID ':' State""" loc = locFromTok(p, 1) - p[0] = Param(loc, - TypeSpec(loc, QualifiedId(loc, p[1])), - p[2]) + p[0] = TypeSpec(loc, QualifiedId(loc, p[1]), state=p[3]) ##-------------------- ## C++ stuff diff --git a/ipc/ipdl/ipdl/type.py b/ipc/ipdl/ipdl/type.py index 0fe6d8d072c..2bb3a8f8a58 100644 --- a/ipc/ipdl/ipdl/type.py +++ b/ipc/ipdl/ipdl/type.py @@ -37,13 +37,13 @@ import ipdl.builtin as builtin class Type: # Is this a C++ type? - def isCxx(): + def isCxx(self): return False # Is this an IPDL type? - def isIPDL(): + def isIPDL(self): return False # Can this type appear in IPDL programs? - def isVisible(): + def isVisible(self): return False def isVoid(self): return False @@ -117,6 +117,7 @@ class IPDLType(Type): def isState(self): return False def isMessage(self): return False def isProtocol(self): return False + def isActor(self): return False def isAsync(self): return self.sendSemantics is ASYNC def isSync(self): return self.sendSemantics is SYNC @@ -190,6 +191,17 @@ class ProtocolType(IPDLType): def isToplevel(self): return not self.isManaged() +class ActorType(IPDLType): + def __init__(self, protocol, state): + self.protocol = protocol + self.state = state + def isActor(self): return True + + def name(self): + return self.protocol.name() + def fullname(self): + return self.protocol.fullname() + ##-------------------- _builtinloc = Loc('', 0) def makeBuiltinUsing(tname): @@ -440,6 +452,37 @@ class GatherDecls(Visitor): for trans in p.transitionStmts: trans.accept(self) + # visit the message decls once more and resolve the state names + # attached to actor params and returns + def resolvestate(param): + loc = param.loc + statename = param.type.state.name + statedecl = self.symtab.lookup(statename) + if statedecl is None: + self.errors.append( + errormsg( + loc, + "protocol `%s' does not have the state `%s'", + param.type.protocol.name(), + statename)) + elif not statedecl.type.isState(): + self.errors.append( + errormsg( + loc, + "tag `%s' is supposed to be of state type, but is instead of type `%s'", + statename, + statedecl.type.typename())) + else: + param.type.state = statedecl + + for msg in p.messageDecls: + for iparam in msg.inParams: + if iparam.type.isIPDL() and iparam.type.isActor(): + resolvestate(iparam) + for oparam in msg.outParams: + if oparam.type.isIPDL() and oparam.type.isActor(): + resolvestate(oparam) + # FIXME/cjones declare all the little C++ thingies that will # be generated. they're not relevant to IPDL itself, but # those ("invisible") symbols can clash with others in the @@ -553,50 +596,43 @@ class GatherDecls(Visitor): ctor=isctor, dtor=isdtor, cdtype=cdtype) # replace inparam Param nodes with proper Decls + def paramToDecl(param): + ptname = param.typespec.basename() + ploc = param.typespec.loc + + ptdecl = self.symtab.lookup(ptname) + + if ptdecl is None: + self.errors.append( + errormsg( + ploc, + "argument typename `%s' of message `%s' has not been declared", + ptname, msgname)) + return None + else: + pdecl = Decl(ploc) + pdecl.progname = param.name + ptype = None + if ptdecl.type.isIPDL() and ptdecl.type.isProtocol(): + ptype = ActorType(ptdecl.type, + param.typespec.state) + else: + ptype = ptdecl.type + pdecl.type = ptype + + self.symtab.declare(pdecl) + return pdecl + for i, inparam in enumerate(md.inParams): - inptname = inparam.typespec.basename() - inploc = inparam.typespec.loc - - inptdecl = self.symtab.lookup(inptname) - - if inptdecl is None: - self.errors.append( - errormsg( - inploc, - "inparam typename `%s' of message `%s' has not been declared", - inptname, msgname)) - else: - inpdecl = Decl(inploc) - inpdecl.progname = inparam.name - inpdecl.type = inptdecl.type - - self.symtab.declare(inpdecl) - - msgtype.params.append(inpdecl.type) - md.inParams[i] = inpdecl - - # replace outparam Param with proper Decls + pdecl = paramToDecl(inparam) + if pdecl is not None: + msgtype.params.append(pdecl.type) + md.inParams[i] = pdecl for i, outparam in enumerate(md.outParams): - outptname = outparam.typespec.basename() - outploc = outparam.typespec.loc - - outptdecl = self.symtab.lookup(outptname) - - if outptdecl is None: - self.errors.append( - errormsg( - outploc, - "outparam typename `%s' of message `%s' has not been declared", - outptname, msgname)) - else: - outpdecl = Decl(outploc) - outpdecl.progname = outparam.name - outpdecl.type = outptdecl.type - - self.symtab.declare(outpdecl) - - msgtype.returns.append(outpdecl.type) - md.outParams[i] = outpdecl + pdecl = paramToDecl(outparam) + if pdecl is not None: + msgtype.returns.append(pdecl.type) + md.outParams[i] = pdecl self.symtab.exitScope(md)