Bug 521898, part 5: Prepare for TU .protocol possibly being null (for headers). r=bent
authorChris Jones <jones.chris.g@gmail.com>
Fri, 08 Jun 2012 17:25:36 -0700
changeset 101027 fece9a6bae3f360c8878362e91ae4fce46653aa7
parent 101026 f713eb64e8e1370a38c12a9bd4a73f269cc3a6a2
child 101028 54a3bbdcfe04da3c89587181f19ce2ad7d184630
push idunknown
push userunknown
push dateunknown
reviewersbent
bugs521898
milestone16.0a1
Bug 521898, part 5: Prepare for TU .protocol possibly being null (for headers). r=bent
ipc/ipdl/ipdl.py
ipc/ipdl/ipdl/ast.py
ipc/ipdl/ipdl/lower.py
ipc/ipdl/ipdl/parser.py
ipc/ipdl/ipdl/type.py
--- a/ipc/ipdl/ipdl.py
+++ b/ipc/ipdl/ipdl.py
@@ -80,17 +80,19 @@ for f in files:
 
 # Second pass: generate code
 for f in files:
     # Read from parser cache
     filename = normalizedFilename(f)
     ast = ipdl.parse(None, filename, includedirs=includedirs)
     ipdl.gencxx(filename, ast, headersdir, cppdir)
     
-    allprotocols.append('%sMsgStart' % ast.protocol.name)
+    if ast.protocol:
+        allprotocols.append('%sMsgStart' % ast.protocol.name)
+
 
 allprotocols.sort()
 
 ipcmsgstart = StringIO()
 
 print >>ipcmsgstart, """
 // CODE GENERATED by ipdl.py. Do not edit.
 
--- a/ipc/ipdl/ipdl/ast.py
+++ b/ipc/ipdl/ipdl/ast.py
@@ -13,17 +13,19 @@ class Visitor:
         for cxxInc in tu.cxxIncludes:
             cxxInc.accept(self)
         for inc in tu.includes:
             inc.accept(self)
         for su in tu.structsAndUnions:
             su.accept(self)
         for using in tu.using:
             using.accept(self)
-        tu.protocol.accept(self)
+        if tu.protocol:
+            tu.protocol.accept(self)
+
 
     def visitCxxInclude(self, inc):
         pass
 
     def visitInclude(self, inc):
         # Note: we don't visit the child AST here, because that needs delicate
         # and pass-specific handling
         pass
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -20,30 +20,38 @@ EMIT_LOGGING_CODE = ('win32' == sys.plat
 ##
 class LowerToCxx:
     def lower(self, tu):
         '''returns |[ header: File ], [ cpp : File ]| representing the
 lowered form of |tu|'''
         # annotate the AST with IPDL/C++ IR-type stuff used later
         tu.accept(_DecorateWithCxxStuff())
 
-        pname = tu.protocol.name
-
-        pheader, pcpp = File(pname +'.h'), File(pname +'.cpp')
+        name = tu.name
+        pheader, pcpp = File(name +'.h'), File(name +'.cpp')
+
         _GenerateProtocolCode().lower(tu, pheader, pcpp)
-
-        parentheader, parentcpp = File(pname +'Parent.h'), File(pname +'Parent.cpp')
-        _GenerateProtocolParentCode().lower(
-            tu, pname+'Parent', parentheader, parentcpp)
-
-        childheader, childcpp = File(pname +'Child.h'), File(pname +'Child.cpp')
-        _GenerateProtocolChildCode().lower(
-            tu, pname+'Child', childheader, childcpp)
-
-        return [ pheader, parentheader, childheader ], [ pcpp, parentcpp, childcpp ]
+        headers = [ pheader ]
+        cpps = [ pcpp ]
+
+        if tu.protocol:
+            pname = tu.protocol.name
+
+            parentheader, parentcpp = File(pname +'Parent.h'), File(pname +'Parent.cpp')
+            _GenerateProtocolParentCode().lower(
+                tu, pname+'Parent', parentheader, parentcpp)
+
+            childheader, childcpp = File(pname +'Child.h'), File(pname +'Child.cpp')
+            _GenerateProtocolChildCode().lower(
+                tu, pname+'Child', childheader, childcpp)
+
+            headers += [ parentheader, childheader ]
+            cpps += [ parentcpp, childcpp ]
+
+        return headers, cpps
 
 
 ##-----------------------------------------------------------------------------
 ## Helper code
 ##
 
 _NULL_ACTOR_ID = ExprLiteral.ZERO
 _FREED_ACTOR_ID = ExprLiteral.ONE
@@ -1337,23 +1345,25 @@ class _GenerateProtocolCode(ipdl.ast.Vis
 
         cf = self.cppfile
         cf.addthings((
             [ _DISCLAIMER, Whitespace.NL ]
             + [ CppDirective('include','"'+h+'.h"')
                 for h in self.cppIncludeHeaders ]
             + [ Whitespace.NL ]
         ))
-       
-        # construct the namespace into which we'll stick all our defns
-        ns = Namespace(self.protocol.name)
-        cf.addthing(_putInNamespaces(ns, self.protocol.namespaces))
-        ns.addstmts(([ Whitespace.NL]
-                     + self.funcDefns
-                     +[ Whitespace.NL ]))
+
+        if self.protocol:       
+            # construct the namespace into which we'll stick all our defns
+            ns = Namespace(self.protocol.name)
+            cf.addthing(_putInNamespaces(ns, self.protocol.namespaces))
+            ns.addstmts(([ Whitespace.NL]
+                         + self.funcDefns
+                         +[ Whitespace.NL ]))
+
         cf.addthings(self.structUnionDefns)
 
 
     def visitCxxInclude(self, inc):
         self.hdrfile.addthing(CppDirective('include', '"'+ inc.file +'"'))
 
     def processStructOrUnionClass(self, su, which, forwarddecls, cls):
         clsdecl, methoddefns = _splitClassDeclDefn(cls)
@@ -2435,16 +2445,18 @@ class _GenerateProtocolActorCode(ipdl.as
             clsdefn,
             Whitespace.NL,
             Whitespace.NL
         ])
 
 
     def visitInclude(self, inc):
         ip = inc.tu.protocol
+        if not ip:
+            return
 
         self.hdrfile.addthings([
             _makeForwardDeclForActor(ip.decl.type, self.side),
             Whitespace.NL
         ])
         self.protocolCxxIncludes.append(
             CppDirective(
                 'include',
--- a/ipc/ipdl/ipdl/parser.py
+++ b/ipc/ipdl/ipdl/parser.py
@@ -201,18 +201,19 @@ def p_TranslationUnit(p):
             if tu.protocol is not None:
                 _error(thing.loc, "only one protocol definition per file")
             tu.protocol = thing
         else:
             assert(0)
 
     # The "canonical" namespace of the tu, what it's considered to be
     # in for the purposes of C++: |#include "foo/bar/TU.h"|
-    tu.namespaces = tu.protocol.namespaces
-    tu.name = tu.protocol.name
+    if tu.protocol:
+        tu.namespaces = tu.protocol.namespaces
+        tu.name = tu.protocol.name
 
     p[0] = tu
 
 ##--------------------
 ## Preamble
 def p_Preamble(p):
     """Preamble : Preamble PreambleStmt ';'
                 |"""
--- a/ipc/ipdl/ipdl/type.py
+++ b/ipc/ipdl/ipdl/type.py
@@ -561,17 +561,18 @@ With this information, it finally type c
         # now that the nodes have decls, type checking is much easier.
         if not runpass(CheckTypes(self.errors)):
             return False
 
         if not (runpass(BuildProcessGraph(self.errors))
                 and runpass(CheckProcessGraph(self.errors))):
             return False
 
-        if (len(tu.protocol.startStates)
+        if (tu.protocol
+            and len(tu.protocol.startStates)
             and not runpass(CheckStateMachine(self.errors))):
             return False
         return True
 
     def reportErrors(self, errout):
         for error in self.errors:
             print >>errout, error
 
@@ -607,47 +608,51 @@ class GatherDecls(TcheckVisitor):
         tu.symtab = SymbolTable(self.errors)
         savedSymtab = self.symtab
         self.symtab = tu.symtab
 
         # pretend like the translation unit "using"-ed these for the
         # sake of type checking and C++ code generation
         tu.using = self.builtinUsing + tu.using
 
-        p = tu.protocol
+        if tu.protocol:
+            assert tu.name == tu.protocol.name
+
+            p = tu.protocol
 
-        # for everyone's sanity, enforce that the filename and
-        # protocol name match
-        basefilename = os.path.basename(tu.filename)
-        expectedfilename = '%s.ipdl'% (p.name)
+            # for everyone's sanity, enforce that the filename and
+            # protocol name match
+            basefilename = os.path.basename(tu.filename)
+            expectedfilename = '%s.ipdl'% (p.name)
 
-        if basefilename != expectedfilename:
-            self.error(p.loc,
-                       "expected file defining protocol `%s' to be named `%s'; instead it's named `%s'",
-                       p.name, expectedfilename, basefilename)
+            if basefilename != expectedfilename:
+                self.error(p.loc,
+                           "expected file defining protocol `%s' to be named `%s'; instead it's named `%s'",
+                           p.name, expectedfilename, basefilename)
 
-        # FIXME/cjones: it's a little weird and counterintuitive to put
-        # both the namespace and non-namespaced name in the global scope.
-        # try to figure out something better; maybe a type-neutral |using|
-        # that works for C++ and protocol types?
-        qname = p.qname()
-        if 0 == len(qname.quals):
-            fullname = None
-        else:
-            fullname = str(qname)
-        p.decl = self.declare(
-            loc=p.loc,
-            type=ProtocolType(qname, p.sendSemantics,
-                              stateless=(0 == len(p.transitionStmts))),
-            shortname=p.name,
-            fullname=fullname)
+            # FIXME/cjones: it's a little weird and counterintuitive
+            # to put both the namespace and non-namespaced name in the
+            # global scope.  try to figure out something better; maybe
+            # a type-neutral |using| that works for C++ and protocol
+            # types?
+            qname = p.qname()
+            if 0 == len(qname.quals):
+                fullname = None
+            else:
+                fullname = str(qname)
+            p.decl = self.declare(
+                loc=p.loc,
+                type=ProtocolType(qname, p.sendSemantics,
+                                  stateless=(0 == len(p.transitionStmts))),
+                shortname=p.name,
+                fullname=fullname)
 
-        # XXX ugh, this sucks.  but we need this information to compute
-        # what friend decls we need in generated C++
-        p.decl.type._ast = p
+            # XXX ugh, this sucks.  but we need this information to compute
+            # what friend decls we need in generated C++
+            p.decl.type._ast = p
 
         # make sure we have decls for all dependent protocols
         for pinc in tu.includes:
             pinc.accept(self)
 
         # declare imported (and builtin) C++ types
         for using in tu.using:
             using.accept(self)
@@ -676,32 +681,35 @@ class GatherDecls(TcheckVisitor):
                 type=sutype,
                 shortname=su.name,
                 fullname=fullname)
 
         # second pass to check each definition
         for su in tu.structsAndUnions:
             su.accept(self)
 
-        # grab symbols in the protocol itself
-        p.accept(self)
+        if tu.protocol:
+            # grab symbols in the protocol itself
+            p.accept(self)
+
 
         tu.type = VOID
 
         self.symtab = savedSymtab
 
 
     def visitInclude(self, inc):
         if inc.tu is None:
             self.error(
                 inc.loc,
                 "(type checking here will be unreliable because of an earlier error)")
             return
         inc.tu.accept(self)
-        self.symtab.declare(inc.tu.protocol.decl)
+        if inc.tu.protocol:
+            self.symtab.declare(inc.tu.protocol.decl)
 
     def visitStructDecl(self, sd):
         stype = sd.decl.type
 
         self.symtab.enterScope(sd)
 
         for f in sd.fields:
             ftypedecl = self.symtab.lookup(str(f.typespec))
@@ -1187,17 +1195,18 @@ class CheckTypes(TcheckVisitor):
         TcheckVisitor.__init__(self, None, errors)
         self.visited = set()
         self.ptype = None
 
     def visitInclude(self, inc):
         if inc.tu.filename in self.visited:
             return
         self.visited.add(inc.tu.filename)
-        inc.tu.protocol.accept(self)
+        if inc.tu.protocol:
+            inc.tu.protocol.accept(self)
 
 
     def visitStructDecl(self, sd):
         if not fullyDefined(sd.decl.type):
             self.error(sd.decl.loc,
                        "struct `%s' is only partially defined", sd.name)
 
     def visitUnionDecl(self, ud):
@@ -1589,17 +1598,18 @@ class BuildProcessGraph(TcheckVisitor):
     class findSpawns(TcheckVisitor):
         def __init__(self, errors):
             TcheckVisitor.__init__(self, None, errors)
 
         def visitTranslationUnit(self, tu):
             TcheckVisitor.visitTranslationUnit(self, tu)
 
         def visitInclude(self, inc):
-            inc.tu.protocol.accept(self)
+            if inc.tu.protocol:
+                inc.tu.protocol.accept(self)
 
         def visitProtocol(self, p):
             ptype = p.decl.type
             # non-top-level protocols don't add any information
             if not ptype.isToplevel() or ptype in ProcessGraph.visitedSpawns:
                 return
 
             ProcessGraph.visitedSpawns.add(ptype)
@@ -1626,17 +1636,18 @@ class BuildProcessGraph(TcheckVisitor):
         self.visiting = None            # ActorType
         self.visited = set()            # set(ActorType)
 
     def visitTranslationUnit(self, tu):
         tu.accept(self.findSpawns(self.errors))
         TcheckVisitor.visitTranslationUnit(self, tu)
 
     def visitInclude(self, inc):
-        inc.tu.protocol.accept(self)
+        if inc.tu.protocol:
+            inc.tu.protocol.accept(self)
 
     def visitProtocol(self, p):
         ptype = p.decl.type
         # non-top-level protocols don't add any information
         if not ptype.isToplevel() or ptype in ProcessGraph.visitedBridges:
             return
 
         ProcessGraph.visitedBridges.add(ptype)