final frontend support for protocol state machines. patch includes a minor refactoring as well.
authorChris Jones <jones.chris.g@gmail.com>
Thu, 09 Jul 2009 13:11:52 -0500
changeset 35764 5e73cb310bddace1b684274e32c2f0b66fe26ed2
parent 35763 c9176c61346b625798d12c103b48f6a71ffbbd02
child 35765 b5822dea95a4f7ce6d673527213dc0d1aa58dc37
push id10694
push userbsmedberg@mozilla.com
push dateMon, 14 Dec 2009 15:23:10 +0000
treeherdermozilla-central@683dfdc4adf0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone1.9.2a1pre
final frontend support for protocol state machines. patch includes a minor refactoring as well.
ipc/ipdl/ipdl/ast.py
ipc/ipdl/ipdl/parser.py
ipc/ipdl/ipdl/type.py
--- a/ipc/ipdl/ipdl/ast.py
+++ b/ipc/ipdl/ipdl/ast.py
@@ -313,23 +313,27 @@ class State(Node):
 
 class Param(Node):
     def __init__(self, loc, typespec, name):
         Node.__init__(self, loc)
         self.name = name
         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?
     def __init__(self, loc, baseid, quals=[ ]):
         self.loc = loc
         self.baseid = baseid
         self.quals = quals
 
--- a/ipc/ipdl/ipdl/parser.py
+++ b/ipc/ipdl/ipdl/parser.py
@@ -400,21 +400,33 @@ def p_ParamList(p):
         p[0] = [ ]
     elif 2 == len(p):
         p[0] = [ p[1] ]
     else:
         p[1].append(p[3])
         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
 def p_CxxType(p):
     """CxxType : QualifiedID
                | ID"""
     if isinstance(p[0], QualifiedId):
         p[0] = TypeSpec(p[1].loc, p[1])
--- a/ipc/ipdl/ipdl/type.py
+++ b/ipc/ipdl/ipdl/type.py
@@ -32,23 +32,23 @@
 
 import sys
 
 from ipdl.ast import CxxInclude, Decl, Loc, QualifiedId, TypeSpec, UsingStmt, Visitor, ASYNC, SYNC, RPC, IN, OUT, INOUT, ANSWER, CALL, RECV, SEND
 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
     def typename(self):
         return self.__class__.__name__
 
     def name(self): raise Exception, 'NYI'
     def fullname(self): raise Exception, 'NYI'
@@ -112,16 +112,17 @@ class GeneratedCxxType(CxxType):
 
 ##--------------------
 class IPDLType(Type):
     def isIPDL(self):  return True
     def isVisible(self): return True
     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
     def isRpc(self): return self.sendSemantics is RPC
 
     def talksAsync(self): return True
     def talksSync(self): return self.isSync() or self.isRpc()
     def talksRpc(self): return self.isRpc()
@@ -185,16 +186,27 @@ class ProtocolType(IPDLType):
         return False
     def isManager(self):
         return len(self.manages) > 0
     def isManaged(self):
         return self.manager is not None
     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('<builtin>', 0)
 def makeBuiltinUsing(tname):
     quals = tname.split('::')
     base = quals.pop()
     quals = quals[0:]
     return UsingStmt(_builtinloc,
                      TypeSpec(_builtinloc,
@@ -435,16 +447,47 @@ class GatherDecls(Visitor):
             sdecl.type = StateType()
 
             self.symtab.declare(sdecl)
             trans.state.decl = sdecl
 
         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
         # IPDL spec, and we'd like to catch those before C++ compilers
         # are allowed to obfuscate the error
 
         self.symtab.exitScope(p)
 
@@ -548,60 +591,53 @@ class GatherDecls(Visitor):
 
         # enter message scope
         self.symtab.enterScope(md)
 
         msgtype = MessageType(md.sendSemantics, md.direction,
                               ctor=isctor, dtor=isdtor, cdtype=cdtype)
 
         # replace inparam Param nodes with proper Decls
-        for i, inparam in enumerate(md.inParams):
-            inptname = inparam.typespec.basename()
-            inploc = inparam.typespec.loc
+        def paramToDecl(param):
+            ptname = param.typespec.basename()
+            ploc = param.typespec.loc
 
-            inptdecl = self.symtab.lookup(inptname)
+            ptdecl = self.symtab.lookup(ptname)
 
-            if inptdecl is None:
+            if ptdecl is None:
                 self.errors.append(
                     errormsg(
-                        inploc,
-                        "inparam typename `%s' of message `%s' has not been declared",
-                        inptname, msgname))
+                        ploc,
+                        "argument typename `%s' of message `%s' has not been declared",
+                        ptname, msgname))
+                return None
             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
-        for i, outparam in enumerate(md.outParams):
-            outptname = outparam.typespec.basename()
-            outploc = outparam.typespec.loc
+                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
 
-            outptdecl = self.symtab.lookup(outptname)
+                self.symtab.declare(pdecl)
+                return pdecl
 
-            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
+        for i, inparam in enumerate(md.inParams):
+            pdecl = paramToDecl(inparam)
+            if pdecl is not None:
+                msgtype.params.append(pdecl.type)
+                md.inParams[i] = pdecl
+        for i, outparam in enumerate(md.outParams):
+            pdecl = paramToDecl(outparam)
+            if pdecl is not None:
+                msgtype.returns.append(pdecl.type)
+                md.outParams[i] = pdecl
 
         self.symtab.exitScope(md)
 
         decl = Decl(loc)
         decl.progname = msgname
         decl.type = msgtype
 
         self.symtab.declare(decl)