Bug 560000: Allow IPDL unions and structs to be recursively defined. r=benjamn

This commit is contained in:
Chris Jones 2010-05-22 14:35:38 -05:00
Родитель ca7af8ea8c
Коммит 81dfc13752
4 изменённых файлов: 519 добавлений и 252 удалений

Просмотреть файл

@ -459,7 +459,8 @@ class FriendClassDecl(Node):
class MethodDecl(Node):
def __init__(self, name, params=[ ], ret=Type('void'),
virtual=0, const=0, pure=0, static=0, warn_unused=0, inline=0,
virtual=0, const=0, pure=0, static=0, warn_unused=0,
inline=0, force_inline=0,
typeop=None,
T=None):
assert not (virtual and static)
@ -468,6 +469,8 @@ class MethodDecl(Node):
assert not (name and typeop)
assert name is None or isinstance(name, str)
assert not isinstance(ret, list)
for decl in params: assert not isinstance(decl, str)
assert not isinstance(T, int)
if typeop is not None:
ret = None
@ -481,19 +484,25 @@ class MethodDecl(Node):
self.pure = pure # bool
self.static = static # bool
self.warn_unused = warn_unused # bool
self.inline = (inline or T) # bool
self.force_inline = (force_inline or T) # bool
self.inline = inline # bool
self.typeop = typeop # Type or None
self.T = T # Type or None
def __deepcopy__(self, memo):
return MethodDecl(
self.name,
copy.deepcopy(self.params, memo),
copy.deepcopy(self.ret, memo),
self.virtual, self.const, self.pure, self.static, self.warn_unused,
copy.deepcopy(self.typeop, memo),
copy.deepcopy(self.T, memo),
self.inline)
params=copy.deepcopy(self.params, memo),
ret=copy.deepcopy(self.ret, memo),
virtual=self.virtual,
const=self.const,
pure=self.pure,
static=self.static,
warn_unused=self.warn_unused,
inline=self.inline,
force_inline=self.force_inline,
typeop=copy.deepcopy(self.typeop, memo),
T=copy.deepcopy(self.T, memo))
class MethodDefn(Block):
def __init__(self, decl):
@ -501,8 +510,9 @@ class MethodDefn(Block):
self.decl = decl
class ConstructorDecl(MethodDecl):
def __init__(self, name, params=[ ], explicit=0):
MethodDecl.__init__(self, name, params=params, ret=None)
def __init__(self, name, params=[ ], explicit=0, force_inline=0):
MethodDecl.__init__(self, name, params=params, ret=None,
force_inline=force_inline)
self.explicit = explicit
def __deepcopy__(self, memo):
@ -516,12 +526,16 @@ class ConstructorDefn(MethodDefn):
self.memberinits = memberinits
class DestructorDecl(MethodDecl):
def __init__(self, name, virtual=0):
def __init__(self, name, virtual=0, force_inline=0, inline=0):
MethodDecl.__init__(self, name, params=[ ], ret=None,
virtual=virtual)
virtual=virtual,
force_inline=force_inline, inline=inline)
def __deepcopy__(self, memo):
return DestructorDecl(self.name, self.virtual)
return DestructorDecl(self.name,
virtual=self.virtual,
force_inline=self.force_inline,
inline=self.inline)
class DestructorDefn(MethodDefn):
@ -752,6 +766,8 @@ class StmtBreak(Node):
class StmtExpr(Node):
def __init__(self, expr):
assert expr is not None
Node.__init__(self)
self.expr = expr

Просмотреть файл

@ -208,6 +208,8 @@ class CxxCodeGen(CodePrinter, Visitor):
self.println('>')
self.printdent()
if md.inline:
self.write('inline ')
if md.static:
self.write('static ')
if md.virtual:
@ -276,6 +278,8 @@ class CxxCodeGen(CodePrinter, Visitor):
def visitDestructorDecl(self, dd):
if dd.inline:
self.write('inline ')
if dd.virtual:
self.write('virtual ')

Просмотреть файл

@ -197,16 +197,15 @@ def _shmemRevokeRights(shmemexpr):
def _lookupShmem(idexpr):
return ExprCall(ExprVar('LookupSharedMemory'), args=[ idexpr ])
def _makeForwardDecl(ptype, side):
clsname = _actorName(ptype.qname.baseid, side)
def _makeForwardDeclForQClass(clsname, quals):
fd = ForwardDecl(clsname, cls=1)
if 0 == len(ptype.qname.quals):
if 0 == len(quals):
return fd
outerns = Namespace(ptype.qname.quals[0])
outerns = Namespace(quals[0])
innerns = outerns
for ns in ptype.qname.quals[1:]:
for ns in quals[1:]:
tmpns = Namespace(ns)
innerns.addstmt(tmpns)
innerns = tmpns
@ -214,6 +213,14 @@ def _makeForwardDecl(ptype, side):
innerns.addstmt(fd)
return outerns
def _makeForwardDeclForActor(ptype, side):
return _makeForwardDeclForQClass(_actorName(ptype.qname.baseid, side),
ptype.qname.quals)
def _makeForwardDecl(type):
return _makeForwardDeclForQClass(type.name(), type.qname.quals)
def _putInNamespaces(cxxthing, namespaces):
"""|namespaces| is in order [ outer, ..., inner ]"""
if 0 == len(namespaces): return cxxthing
@ -532,30 +539,18 @@ class HasFQName:
def fqClassName(self):
return self.decl.type.fullname()
class StructDecl(ipdl.ast.StructDecl, HasFQName):
@staticmethod
def upgrade(structDecl):
assert isinstance(structDecl, ipdl.ast.StructDecl)
structDecl.__class__ = StructDecl
return structDecl
class _StructField(_HybridDecl):
def __init__(self, ipdltype, name, sd, side=None, other=None):
special = _hasVisibleActor(ipdltype)
fname = name
if special:
fname += side.title()
_HybridDecl.__init__(self, ipdltype, fname)
class _CompoundTypeComponent(_HybridDecl):
def __init__(self, ipdltype, name, side, ct):
_HybridDecl.__init__(self, ipdltype, name)
self.side = side
self.special = special
if special:
if other is not None:
self.other = other
else:
self.other = _StructField(ipdltype, name, sd, _otherSide(side), self)
self.sd = sd
self.special = _hasVisibleActor(ipdltype)
self.recursive = ct.decl.type.mutuallyRecursiveWith(ipdltype)
def internalType(self):
if self.recursive:
return self.ptrToType()
else:
return self.bareType()
# @override the following methods to pass |self.side| instead of
# forcing the caller to remember which side we're declared to
@ -574,6 +569,62 @@ class _StructField(_HybridDecl):
return _HybridDecl.inType(self, self.side)
class StructDecl(ipdl.ast.StructDecl, HasFQName):
@staticmethod
def upgrade(structDecl):
assert isinstance(structDecl, ipdl.ast.StructDecl)
structDecl.__class__ = StructDecl
return structDecl
class _StructField(_CompoundTypeComponent):
def __init__(self, ipdltype, name, sd, side=None):
fname = name
special = _hasVisibleActor(ipdltype)
if special:
fname += side.title()
_CompoundTypeComponent.__init__(self, ipdltype, fname, side, sd)
def getMethod(self, thisexpr=None, sel='.'):
meth = self.var()
if thisexpr is not None:
return ExprSelect(thisexpr, sel, meth.name)
return meth
def initExpr(self, thisexpr):
expr = ExprCall(self.getMethod(thisexpr=thisexpr))
if self.ipdltype.isIPDL() and self.ipdltype.isActor():
expr = ExprCast(expr, self.bareType(), const=1)
return expr
def refExpr(self, thisexpr=None):
ref = self.memberVar()
if thisexpr is not None:
ref = ExprSelect(thisexpr, '.', ref.name)
if self.recursive:
ref = ExprDeref(ref)
return ref
def argVar(self):
return ExprVar('_'+ self.name)
def memberVar(self):
return ExprVar(self.name + '_')
def initStmts(self):
if self.recursive:
return [ StmtExpr(ExprAssn(self.memberVar(),
ExprNew(self.bareType()))) ]
else:
return []
def destructStmts(self):
if self.recursive:
return [ StmtExpr(ExprDelete(self.memberVar())) ]
else:
return []
class UnionDecl(ipdl.ast.UnionDecl, HasFQName):
def callType(self, var=None):
func = ExprVar('type')
@ -588,7 +639,7 @@ class UnionDecl(ipdl.ast.UnionDecl, HasFQName):
return unionDecl
class _UnionMember(_HybridDecl):
class _UnionMember(_CompoundTypeComponent):
"""Not in the AFL sense, but rather a member (e.g. |int;|) of an
IPDL union type."""
def __init__(self, ipdltype, ud, side=None, other=None):
@ -597,16 +648,13 @@ IPDL union type."""
if special:
flatname += side.title()
_HybridDecl.__init__(self, ipdltype, 'V'+ flatname)
_CompoundTypeComponent.__init__(self, ipdltype, 'V'+ flatname, side, ud)
self.flattypename = flatname
self.side = side
self.special = special
if special:
if other is not None:
self.other = other
else:
self.other = _UnionMember(ipdltype, ud, _otherSide(side), self)
self.ud = ud
def enum(self):
return 'T' + self.flattypename
@ -619,7 +667,10 @@ IPDL union type."""
def unionType(self):
"""Type used for storage in generated C union decl."""
return TypeArray(Type('char'), ExprSizeof(self.bareType()))
if self.recursive:
return self.ptrToType()
else:
return TypeArray(Type('char'), ExprSizeof(self.internalType()))
def unionValue(self):
# NB: knows that Union's storage C union is named |mValue|
@ -641,7 +692,7 @@ IPDL union type."""
rhs = ExprCast(rhs, self.bareType(), const=1)
return ExprAssn(ExprDeref(self.callGetPtr()), rhs)
def callPlacementCtor(self, expr=None):
def callCtor(self, expr=None):
assert not isinstance(expr, list)
if expr is None:
@ -651,13 +702,21 @@ IPDL union type."""
else:
args = [ expr ]
return ExprNew(self.bareType(self.side),
args=args,
newargs=[ self.callGetPtr() ])
if self.recursive:
return ExprAssn(self.callGetPtr(),
ExprNew(self.bareType(self.side),
args=args))
else:
return ExprNew(self.bareType(self.side),
args=args,
newargs=[ self.callGetPtr() ])
def callPlacementDtor(self):
return ExprCall(
ExprSelect(self.callGetPtr(), '->', '~'+ self.typedef()))
def callDtor(self):
if self.recursive:
return ExprDelete(self.callGetPtr())
else:
return ExprCall(
ExprSelect(self.callGetPtr(), '->', '~'+ self.typedef()))
def getTypeName(self): return 'get_'+ self.flattypename
def getConstTypeName(self): return 'get_'+ self.flattypename
@ -669,15 +728,24 @@ IPDL union type."""
def ptrToSelfExpr(self):
"""|*ptrToSelfExpr()| has type |self.bareType()|"""
return ExprCast(ExprAddrOf(self.unionValue()),
self.ptrToType(),
reinterpret=1)
v = self.unionValue()
if self.recursive:
return v
else:
return ExprCast(ExprAddrOf(v), self.ptrToType(), reinterpret=1)
def constptrToSelfExpr(self):
"""|*constptrToSelfExpr()| has type |self.constType()|"""
return ExprCast(ExprAddrOf(self.unionValue()),
self.constPtrToType(),
reinterpret=1)
v = self.unionValue()
if self.recursive:
return v
return ExprCast(ExprAddrOf(v), self.constPtrToType(), reinterpret=1)
def ptrToInternalType(self):
t = self.ptrToType()
if self.recursive:
t.ref = 1
return t
def defaultValue(self):
if self.ipdltype.isIPDL() and self.ipdltype.isActor():
@ -685,22 +753,6 @@ IPDL union type."""
# XXX sneaky here, maybe need ExprCtor()?
return ExprCall(self.bareType())
# @override the following methods to pass |self.side| instead of
# forcing the caller to remember which side we're declared to
# represent.
def bareType(self, side=None):
return _HybridDecl.bareType(self, self.side)
def refType(self, side=None):
return _HybridDecl.refType(self, self.side)
def constRefType(self, side=None):
return _HybridDecl.constRefType(self, self.side)
def ptrToType(self, side=None):
return _HybridDecl.ptrToType(self, self.side)
def constPtrToType(self, side=None):
return _HybridDecl.constPtrToType(self, self.side)
def inType(self, side=None):
return _HybridDecl.inType(self, self.side)
##--------------------------------------------------
class MessageDecl(ipdl.ast.MessageDecl):
@ -1192,6 +1244,7 @@ child actors.'''
def __init__(self):
self.protocol = None # protocol we're generating a class for
self.file = None # File stuff is stuck in
self.structUnionDefns = []
def lower(self, tu, outcxxfile):
self.protocol = tu.protocol
@ -1212,6 +1265,8 @@ child actors.'''
ipdl.ast.Visitor.visitTranslationUnit(self, tu)
f.addthings(self.structUnionDefns)
f.addthing(Whitespace.NL)
f.addthings(_includeGuardEnd(f))
@ -1219,12 +1274,36 @@ child actors.'''
def visitCxxInclude(self, inc):
self.file.addthing(CppDirective('include', '"'+ inc.file +'"'))
def processStructOrUnionClass(self, su, which, forwarddecls, cls):
clsdecl, methoddefns = _splitClassDeclDefn(cls, inlinedefns=1)
self.file.addthings(
[ Whitespace.NL ]
+ forwarddecls
+ [ Whitespace("""
//-----------------------------------------------------------------------------
// Declaration of the IPDL type |%s %s|
//
"""% (which, su.name)),
_putInNamespaces(clsdecl, su.namespaces),
])
self.structUnionDefns.extend([
Whitespace("""
//-----------------------------------------------------------------------------
// Method definitions for the IPDL type |%s %s|
//
"""% (which, su.name)),
_putInNamespaces(methoddefns, su.namespaces),
])
def visitStructDecl(self, sd):
self.file.addthings(_generateCxxStruct(sd))
return self.processStructOrUnionClass(sd, 'struct',
*_generateCxxStruct(sd))
def visitUnionDecl(self, ud):
self.file.addthings(_generateCxxUnionStuff(ud))
return self.processStructOrUnionClass(ud, 'union',
*_generateCxxUnion(ud))
def visitProtocol(self, p):
self.file.addthing(Whitespace("""
@ -1354,29 +1433,30 @@ class _ComputeTypeDeps(TypeVisitor):
types that need forward declaration; (ii) types that need a |using|
stmt. Some types generate both kinds.'''
def __init__(self):
def __init__(self, fortype):
ipdl.type.TypeVisitor.__init__(self)
self.usingTypedefs = [ ]
self.forwardDeclStmts = [ ]
self.seen = set()
self.fortype = fortype
def maybeTypedef(self, fqname, name):
if fqname != name:
self.usingTypedefs.append(Typedef(Type(fqname), name))
def visitBuiltinCxxType(self, t):
if t in self.seen: return
self.seen.add(t)
if t in self.visited: return
self.visited.add(t)
self.maybeTypedef(t.fullname(), t.name())
def visitImportedCxxType(self, t):
if t in self.seen: return
self.seen.add(t)
if t in self.visited: return
self.visited.add(t)
self.maybeTypedef(t.fullname(), t.name())
def visitActorType(self, t):
if t in self.seen: return
self.seen.add(t)
if t in self.visited: return
self.visited.add(t)
fqname, name = t.fullname(), t.name()
self.maybeTypedef(_actorName(fqname, 'Parent'),
@ -1385,15 +1465,18 @@ stmt. Some types generate both kinds.'''
_actorName(name, 'Child'))
self.forwardDeclStmts.extend([
_makeForwardDecl(t.protocol, 'parent'), Whitespace.NL,
_makeForwardDecl(t.protocol, 'child'), Whitespace.NL
_makeForwardDeclForActor(t.protocol, 'parent'), Whitespace.NL,
_makeForwardDeclForActor(t.protocol, 'child'), Whitespace.NL
])
def visitStructOrUnionType(self, su, defaultVisit):
if su in self.seen: return
self.seen.add(su)
if su in self.visited or su == self.fortype: return
self.visited.add(su)
self.maybeTypedef(su.fullname(), su.name())
if su.mutuallyRecursiveWith(self.fortype):
self.forwardDeclStmts.append(_makeForwardDecl(su))
return defaultVisit(self, su)
def visitStructType(self, t):
@ -1414,51 +1497,112 @@ stmt. Some types generate both kinds.'''
def _generateCxxStruct(sd):
''' '''
# compute all the typedefs and forward decls we need to make
gettypedeps = _ComputeTypeDeps()
gettypedeps = _ComputeTypeDeps(sd.decl.type)
for f in sd.fields:
f.ipdltype.accept(gettypedeps)
usingTypedefs = gettypedeps.usingTypedefs
forwarddeclstmts = gettypedeps.forwardDeclStmts
struct = Class(sd.name, struct=1)
struct.addstmts(
[ Label.PRIVATE ]
+ usingTypedefs
+ [ Whitespace.NL,
Label.PUBLIC,
ConstructorDefn(ConstructorDecl(sd.name)),
Whitespace.NL,
ConstructorDefn(
ConstructorDecl(
sd.name,
params=[ Decl(f.constRefType(), '_'+ f.name)
for f in sd.fields ]),
memberinits=[ ExprCall(f.var(),
args=[ ExprVar('_'+ f.name) ])
for f in sd.fields ]),
Whitespace.NL,
Whitespace('// Default copy ctor, op=, and dtor are OK\n\n',
indent=1)
]
+ [ StmtDecl(Decl(f.bareType(), f.name)) for f in sd.fields ])
struct = Class(sd.name, struct=1, final=1)
struct.addstmts([ Label.PRIVATE ]
+ usingTypedefs
+ [ Whitespace.NL, Label.PUBLIC ])
constreftype = Type(sd.name, const=1, ref=1)
initvar = ExprVar('Init')
callinit = ExprCall(initvar)
assignvar = ExprVar('Assign')
return (
[
Whitespace("""
//-----------------------------------------------------------------------------
// Definition of the IPDL type |struct %s|
//
"""% (sd.name))
]
+ forwarddeclstmts
+ [ _putInNamespaces(struct, sd.namespaces) ])
def fieldsAsParamList():
return [ Decl(f.inType(), f.argVar().name) for f in sd.fields ]
def assignFromOther(oexpr):
return ExprCall(assignvar,
args=[ f.initExpr(oexpr) for f in sd.fields ])
# Struct()
defctor = ConstructorDefn(ConstructorDecl(sd.name))
defctor.addstmt(StmtExpr(callinit))
struct.addstmts([ defctor, Whitespace.NL ])
# Struct(const field1& _f1, ...)
valctor = ConstructorDefn(ConstructorDecl(sd.name,
params=fieldsAsParamList(),
force_inline=1))
valctor.addstmts([
StmtExpr(callinit),
StmtExpr(ExprCall(assignvar,
args=[ f.argVar() for f in sd.fields ]))
])
struct.addstmts([ valctor, Whitespace.NL ])
# Struct(const Struct& _o)
ovar = ExprVar('_o')
copyctor = ConstructorDefn(ConstructorDecl(
sd.name,
params=[ Decl(constreftype, ovar.name) ],
force_inline=1))
copyctor.addstmts([
StmtExpr(callinit),
StmtExpr(assignFromOther(ovar))
])
struct.addstmts([ copyctor, Whitespace.NL ])
# ~Struct()
dtor = DestructorDefn(DestructorDecl(sd.name))
for f in sd.fields:
dtor.addstmts(f.destructStmts())
struct.addstmts([ dtor, Whitespace.NL ])
# Struct& operator=(const Struct& _o)
opeq = MethodDefn(MethodDecl(
'operator=',
params=[ Decl(constreftype, ovar.name) ],
force_inline=1))
opeq.addstmt(StmtExpr(assignFromOther(ovar)))
struct.addstmts([ opeq, Whitespace.NL ])
# field1& f1()
# const field1& f1() const
for f in sd.fields:
get = MethodDefn(MethodDecl(f.getMethod().name,
params=[ ],
ret=f.refType(),
force_inline=1))
get.addstmt(StmtReturn(f.refExpr()))
getconst = deepcopy(get)
getconst.decl.ret = f.constRefType()
getconst.decl.const = 1
struct.addstmts([ get, getconst, Whitespace.NL ])
# private:
struct.addstmt(Label.PRIVATE)
# Init()
init = MethodDefn(MethodDecl(initvar.name))
for f in sd.fields:
init.addstmts(f.initStmts())
struct.addstmts([ init, Whitespace.NL ])
# Assign(const field1& _f1, ...)
assign = MethodDefn(MethodDecl(assignvar.name,
params=fieldsAsParamList()))
assign.addstmts([ StmtExpr(ExprAssn(f.refExpr(), f.argVar()))
for f in sd.fields ])
struct.addstmts([ assign, Whitespace.NL ])
# members
struct.addstmts([ StmtDecl(Decl(f.internalType(), f.memberVar().name))
for f in sd.fields ])
return forwarddeclstmts, struct
##--------------------------------------------------
def _generateCxxUnionStuff(ud):
def _generateCxxUnion(ud):
# This Union class basically consists of a type (enum) and a
# union for storage. The union can contain POD and non-POD
# types. Each type needs a copy ctor, assignment operator,
@ -1522,11 +1666,11 @@ def _generateCxxUnionStuff(ud):
def maybeReconstruct(memb, newTypeVar):
ifdied = StmtIf(callMaybeDestroy(newTypeVar))
ifdied.addifstmt(StmtExpr(memb.callPlacementCtor()))
ifdied.addifstmt(StmtExpr(memb.callCtor()))
return ifdied
# compute all the typedefs and forward decls we need to make
gettypedeps = _ComputeTypeDeps()
gettypedeps = _ComputeTypeDeps(ud.decl.type)
for c in ud.components:
c.ipdltype.accept(gettypedeps)
@ -1549,8 +1693,8 @@ def _generateCxxUnionStuff(ud):
cls.addstmt(Label.PRIVATE)
cls.addstmts(
usingTypedefs
# hacky typedef's that allow placement dtors of builtins
+ [ Typedef(c.bareType(), c.typedef()) for c in ud.components ])
# hacky typedef's that allow placement dtors of builtins
+ [ Typedef(c.internalType(), c.typedef()) for c in ud.components ])
cls.addstmt(Whitespace.NL)
# the C++ union the discunion use for storage
@ -1565,11 +1709,13 @@ def _generateCxxUnionStuff(ud):
# and |const T*|
for c in ud.components:
getptr = MethodDefn(MethodDecl(
c.getPtrName(), params=[ ], ret=c.ptrToType()))
c.getPtrName(), params=[ ], ret=c.ptrToInternalType(),
force_inline=1))
getptr.addstmt(StmtReturn(c.ptrToSelfExpr()))
getptrconst = MethodDefn(MethodDecl(
c.getConstPtrName(), params=[ ], ret=c.constPtrToType(), const=1))
c.getConstPtrName(), params=[ ], ret=c.constPtrToType(),
const=1, force_inline=1))
getptrconst.addstmt(StmtReturn(c.constptrToSelfExpr()))
cls.addstmts([ getptr, getptrconst ])
@ -1595,7 +1741,7 @@ def _generateCxxUnionStuff(ud):
for c in ud.components:
dtorswitch.addcase(
CaseLabel(c.enum()),
StmtBlock([ StmtExpr(c.callPlacementDtor()),
StmtBlock([ StmtExpr(c.callDtor()),
StmtBreak() ]))
dtorswitch.addcase(
DefaultLabel(),
@ -1611,7 +1757,7 @@ def _generateCxxUnionStuff(ud):
# add helper methods that ensure the discunion has a
# valid type
sanity = MethodDefn(MethodDecl(
assertsanityvar.name, ret=Type.VOID, const=1))
assertsanityvar.name, ret=Type.VOID, const=1, force_inline=1))
sanity.addstmts([
_abortIfFalse(ExprBinary(tfirstvar, '<=', mtypevar),
'invalid type tag'),
@ -1624,7 +1770,7 @@ def _generateCxxUnionStuff(ud):
MethodDecl(assertsanityvar.name,
params=[ Decl(typetype, atypevar.name) ],
ret=Type.VOID,
const=1))
const=1, force_inline=1))
sanity2.addstmts([
StmtExpr(ExprCall(assertsanityvar)),
_abortIfFalse(ExprBinary(mtypevar, '==', atypevar),
@ -1637,7 +1783,7 @@ def _generateCxxUnionStuff(ud):
cls.addstmts([
Label.PUBLIC,
ConstructorDefn(
ConstructorDecl(ud.name),
ConstructorDecl(ud.name, force_inline=1),
memberinits=[ ExprMemberInit(mtypevar, [ tnonevar ]) ]),
Whitespace.NL
])
@ -1648,7 +1794,7 @@ def _generateCxxUnionStuff(ud):
copyctor = ConstructorDefn(ConstructorDecl(
ud.name, params=[ Decl(c.inType(), othervar.name) ]))
copyctor.addstmts([
StmtExpr(c.callPlacementCtor(othervar)),
StmtExpr(c.callCtor(othervar)),
StmtExpr(ExprAssn(mtypevar, c.enumvar())) ])
cls.addstmts([ copyctor, Whitespace.NL ])
@ -1661,7 +1807,7 @@ def _generateCxxUnionStuff(ud):
copyswitch.addcase(
CaseLabel(c.enum()),
StmtBlock([
StmtExpr(c.callPlacementCtor(
StmtExpr(c.callCtor(
ExprCall(ExprSelect(othervar,
'.', c.getConstTypeName())))),
StmtBreak()
@ -1682,7 +1828,8 @@ def _generateCxxUnionStuff(ud):
cls.addstmts([ dtor, Whitespace.NL ])
# type()
typemeth = MethodDefn(MethodDecl('type', ret=typetype, const=1))
typemeth = MethodDefn(MethodDecl('type', ret=typetype,
const=1, force_inline=1))
typemeth.addstmt(StmtReturn(mtypevar))
cls.addstmts([ typemeth, Whitespace.NL ])
@ -1736,23 +1883,26 @@ def _generateCxxUnionStuff(ud):
getValueVar = ExprVar(c.getTypeName())
getConstValueVar = ExprVar(c.getConstTypeName())
getvalue = MethodDefn(MethodDecl(getValueVar.name, ret=c.refType()))
getvalue = MethodDefn(MethodDecl(getValueVar.name,
ret=c.refType(),
force_inline=1))
getvalue.addstmts([
StmtExpr(callAssertSanity(expectTypeVar=c.enumvar())),
StmtReturn(ExprDeref(c.callGetPtr()))
])
getconstvalue = MethodDefn(MethodDecl(
getConstValueVar.name, ret=c.constRefType(), const=1))
getConstValueVar.name, ret=c.constRefType(),
const=1, force_inline=1))
getconstvalue.addstmts([
StmtExpr(callAssertSanity(expectTypeVar=c.enumvar())),
StmtReturn(ExprDeref(c.callGetConstPtr()))
])
optype = MethodDefn(MethodDecl('', typeop=c.refType()))
optype = MethodDefn(MethodDecl('', typeop=c.refType(), force_inline=1))
optype.addstmt(StmtReturn(ExprCall(getValueVar)))
opconsttype = MethodDefn(MethodDecl(
'', const=1, typeop=c.constRefType()))
'', const=1, typeop=c.constRefType(), force_inline=1))
opconsttype.addstmt(StmtReturn(ExprCall(getConstValueVar)))
cls.addstmts([ getvalue, getconstvalue,
@ -1766,17 +1916,7 @@ def _generateCxxUnionStuff(ud):
StmtDecl(Decl(typetype, mtypevar.name))
])
return (
[
Whitespace("""
//-----------------------------------------------------------------------------
// Definition of the IPDL type |union %s|
//
"""% (ud.name))
]
+ forwarddeclstmts
+ [ _putInNamespaces(cls, ud.namespaces) ])
return forwarddeclstmts, cls
##-----------------------------------------------------------------------------
@ -1880,7 +2020,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
# this generates the actor's full impl in self.cls
tu.protocol.accept(self)
clsdecl, clsdefn = _ClassDeclDefn().split(self.cls)
clsdecl, clsdefn = _splitClassDeclDefn(self.cls)
# XXX damn C++ ... return types in the method defn aren't in
# class scope
@ -1957,7 +2097,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
ip = pi.tu.protocol
self.hdrfile.addthings([
_makeForwardDecl(ip.decl.type, self.side),
_makeForwardDeclForActor(ip.decl.type, self.side),
Whitespace.NL
])
self.protocolCxxIncludes.append(
@ -2011,7 +2151,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
for friend in friends:
self.hdrfile.addthings([
Whitespace.NL,
_makeForwardDecl(friend, self.prettyside),
_makeForwardDeclForActor(friend, self.prettyside),
Whitespace.NL
])
self.cls.addstmts([
@ -3323,7 +3463,6 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
outtype = _cxxPtrToType(arraytype, self.side)
write = MethodDefn(self.writeMethodDecl(intype, var))
# FIXME hacky init of |i|
forwrite = StmtFor(init=ExprAssn(Decl(Type.UINT32, ivar.name),
ExprLiteral.ZERO),
cond=ExprBinary(ivar, '<', lenvar),
@ -3340,7 +3479,6 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
read = MethodDefn(self.readMethodDecl(outtype, var))
avar = ExprVar('a')
# FIXME hacky init of |i|
forread = StmtFor(init=ExprAssn(Decl(Type.UINT32, ivar.name),
ExprLiteral.ZERO),
cond=ExprBinary(ivar, '<', lenvar),
@ -3420,7 +3558,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
read = MethodDefn(self.readMethodDecl(outtype, var))
def get(sel, f):
return ExprSelect(var, sel, f.name)
return ExprCall(f.getMethod(thisexpr=var, sel=sel))
for f in sd.fields:
writefield = StmtExpr(self.write(f.ipdltype, get('.', f), msgvar))
@ -4162,32 +4300,34 @@ class _GenerateProtocolChildCode(_GenerateProtocolActorCode):
## Utility passes
##
class _ClassDeclDefn:
def split(self, cls):
"""Warning: destructively splits |cls|!"""
defns = Block()
def _splitClassDeclDefn(cls, inlinedefns=0):
"""Destructively split |cls| methods into declarations and
definitions (if |not methodDecl.force_inline|). Return classDecl,
methodDefns."""
defns = Block()
for i, stmt in enumerate(cls.stmts):
if isinstance(stmt, MethodDefn) and not stmt.decl.inline:
decl, defn = self.splitMethodDefn(stmt, cls.name)
cls.stmts[i] = StmtDecl(decl)
defns.addstmts([ defn, Whitespace.NL ])
for i, stmt in enumerate(cls.stmts):
if isinstance(stmt, MethodDefn) and not stmt.decl.force_inline:
decl, defn = _splitMethodDefn(stmt, cls.name, inlinedefns)
cls.stmts[i] = StmtDecl(decl)
defns.addstmts([ defn, Whitespace.NL ])
return cls, defns
return cls, defns
def splitMethodDefn(self, md, clsname):
saveddecl = deepcopy(md.decl)
md.decl.name = (clsname +'::'+ md.decl.name)
md.decl.virtual = 0
md.decl.static = 0
md.decl.warn_unused = 0
for param in md.decl.params:
if isinstance(param, Param):
param.default = None
return saveddecl, md
def _splitMethodDefn(md, clsname, inlinedefn):
saveddecl = deepcopy(md.decl)
md.decl.name = (clsname +'::'+ md.decl.name)
md.decl.virtual = 0
md.decl.static = 0
md.decl.warn_unused = 0
md.decl.inline = inlinedefn
for param in md.decl.params:
if isinstance(param, Param):
param.default = None
return saveddecl, md
# XXX this is tantalizingly similar to _SplitDeclDefn, but just
# XXX this is tantalizingly similar to _splitClassDeclDefn, but just
# different enough that I don't see the need to define
# _GenerateSkeleton in terms of that
class _GenerateSkeletonImpl(Visitor):

Просмотреть файл

@ -32,7 +32,7 @@
import os, sys
from ipdl.ast import CxxInclude, Decl, Loc, QualifiedId, State, TransitionStmt, TypeSpec, UsingStmt, Visitor, ASYNC, SYNC, RPC, IN, OUT, INOUT, ANSWER, CALL, RECV, SEND
from ipdl.ast import CxxInclude, Decl, Loc, QualifiedId, State, StructDecl, TransitionStmt, TypeSpec, UnionDecl, UsingStmt, Visitor, ASYNC, SYNC, RPC, IN, OUT, INOUT, ANSWER, CALL, RECV, SEND
import ipdl.builtin as builtin
_DELETE_MSG = '__delete__'
@ -56,6 +56,9 @@ def cartesian_product(s1, s2):
class TypeVisitor:
def __init__(self):
self.visited = set()
def defaultVisit(self, node, *args):
raise Exception, "INTERNAL ERROR: no visitor for node type `%s'"% (
node.__class__.__name__)
@ -90,13 +93,18 @@ class TypeVisitor:
a.state.accept(self, *args)
def visitStructType(self, s, *args):
if s in self.visited:
return
self.visited.add(s)
for field in s.fields:
field.accept(self, *args)
def visitFieldType(self, f, *args):
f.type.accept(self, *args)
def visitUnionType(self, u, *args):
if u in self.visited:
return
self.visited.add(u)
for component in u.components:
component.accept(self, *args)
@ -109,6 +117,7 @@ class TypeVisitor:
def visitShmemChmodType(self, c, *args):
c.shmem.accept(self)
class Type:
def __cmp__(self, o):
return cmp(self.fullname(), o.fullname())
@ -124,6 +133,9 @@ class Type:
# Is this an IPDL type?
def isIPDL(self):
return False
# Is this type neither compound nor an array?
def isAtom(self):
return False
# Can this type appear in IPDL programs?
def isVisible(self):
return False
@ -142,13 +154,14 @@ class Type:
return visit(self, *args)
class VoidType(Type):
# the following are not type-o's (hah): void is both a Cxx and IPDL type
def isCxx():
def isCxx(self):
return True
def isIPDL():
def isIPDL(self):
return False
def isAtom(self):
return True
def isVisible(self):
return True
return False
def isVoid(self):
return True
@ -161,6 +174,8 @@ VOID = VoidType()
class CxxType(Type):
def isCxx(self):
return True
def isAtom(self):
return True
def isBuiltin(self):
return False
def isImported(self):
@ -205,6 +220,8 @@ class IPDLType(Type):
def isStruct(self): return False
def isUnion(self): return False
def isArray(self): return False
def isAtom(self): return True
def isCompound(self): return False
def isShmem(self): return False
def isChmod(self): return False
@ -340,29 +357,78 @@ class ActorType(IPDLType):
def fullname(self):
return self.protocol.fullname()
class StructType(IPDLType):
class _CompoundType(IPDLType):
def __init__(self):
self.defined = False # bool
self.mutualRec = set() # set(_CompoundType | ArrayType)
def isAtom(self):
return False
def isCompound(self):
return True
def itercomponents(self):
raise '"pure virtual" method'
def mutuallyRecursiveWith(self, t, exploring=None):
'''|self| is mutually recursive with |t| iff |self| and |t|
are in a cycle in the type graph rooted at |self|. This function
looks for such a cycle and returns True if found.'''
if exploring is None:
exploring = set()
if t.isAtom():
return False
elif t is self or t in self.mutualRec:
return True
elif t.isArray():
isrec = self.mutuallyRecursiveWith(t.basetype, exploring)
if isrec: self.mutualRec.add(t)
return isrec
elif t in exploring:
return False
exploring.add(t)
for c in t.itercomponents():
if self.mutuallyRecursiveWith(c, exploring):
self.mutualRec.add(c)
return True
exploring.remove(t)
return False
class StructType(_CompoundType):
def __init__(self, qname, fields):
_CompoundType.__init__(self)
self.qname = qname
self.fields = fields # [ Type ]
def isStruct(self): return True
def isStruct(self): return True
def itercomponents(self):
for f in self.fields:
yield f
def name(self): return self.qname.baseid
def fullname(self): return str(self.qname)
class UnionType(IPDLType):
class UnionType(_CompoundType):
def __init__(self, qname, components):
_CompoundType.__init__(self)
self.qname = qname
self.components = components
self.components = components # [ Type ]
def isUnion(self): return True
def itercomponents(self):
for c in self.components:
yield c
def isUnion(self): return True
def name(self): return self.qname.baseid
def fullname(self): return str(self.qname)
class ArrayType(IPDLType):
def __init__(self, basetype):
self.basetype = basetype
def isAtom(self): return False
def isArray(self): return True
def name(self): return self.basetype.name() +'[]'
def fullname(self): return self.basetype.fullname() +'[]'
@ -376,25 +442,24 @@ class ShmemType(IPDLType):
def fullname(self):
return str(self.qname)
def iteractortypes(type):
def iteractortypes(t, visited=None):
"""Iterate over any actor(s) buried in |type|."""
# XXX |yield| semantics makes it hard to use TypeVisitor
if not type or not type.isIPDL():
return
elif type.isActor():
yield type
elif type.isArray():
for actor in iteractortypes(type.basetype):
yield actor
elif type.isStruct():
for f in type.fields:
for actor in iteractortypes(f):
yield actor
elif type.isUnion():
for c in type.components:
for actor in iteractortypes(c):
yield actor
if visited is None:
visited = set()
# XXX |yield| semantics makes it hard to use TypeVisitor
if not t.isIPDL():
return
elif t.isActor():
yield t
elif t.isArray():
for actor in iteractortypes(t.basetype, visited):
yield actor
elif t.isCompound() and t not in visited:
visited.add(t)
for c in t.itercomponents():
for actor in iteractortypes(c, visited):
yield actor
def hasactor(type):
"""Return true iff |type| is an actor or has one buried within."""
@ -613,6 +678,28 @@ class GatherDecls(TcheckVisitor):
for using in tu.using:
using.accept(self)
# first pass to "forward-declare" all structs and unions in
# order to support recursive definitions
for su in tu.structsAndUnions:
qname = su.qname()
if 0 == len(qname.quals):
fullname = None
else:
fullname = str(qname)
if isinstance(su, StructDecl):
sutype = StructType(qname, [ ])
elif isinstance(su, UnionDecl):
sutype = UnionType(qname, [ ])
else: assert 0 and 'unknown type'
su.decl = self.declare(
loc=su.loc,
type=sutype,
shortname=su.name,
fullname=fullname)
# second pass to check each definition
for su in tu.structsAndUnions:
su.accept(self)
@ -634,17 +721,6 @@ class GatherDecls(TcheckVisitor):
self.symtab.declare(pi.tu.protocol.decl)
def visitStructDecl(self, sd):
qname = sd.qname()
if 0 == len(qname.quals):
fullname = None
else:
fullname = str(qname)
sd.decl = self.declare(
loc=sd.loc,
type=StructType(qname, [ ]),
shortname=sd.name,
fullname=fullname)
stype = sd.decl.type
self.symtab.enterScope(sd)
@ -666,26 +742,15 @@ class GatherDecls(TcheckVisitor):
self.symtab.exitScope(sd)
def visitUnionDecl(self, ud):
qname = ud.qname()
if 0 == len(qname.quals):
fullname = None
else:
fullname = str(qname)
components = [ ]
utype = ud.decl.type
for c in ud.components:
cdecl = self.symtab.lookup(str(c))
if cdecl is None:
self.error(c.loc, "unknown component type `%s' of union `%s'",
str(c), ud.name)
continue
components.append(self._canonicalType(cdecl.type, c))
ud.decl = self.declare(
loc=ud.loc,
type=UnionType(qname, components),
shortname=ud.name,
fullname=fullname)
utype.components.append(self._canonicalType(cdecl.type, c))
def visitUsingStmt(self, using):
fullname = str(using.type)
@ -944,35 +1009,27 @@ class GatherDecls(TcheckVisitor):
ploc = param.typespec.loc
ptdecl = self.symtab.lookup(ptname)
if ptdecl is None:
self.error(
ploc,
"argument typename `%s' of message `%s' has not been declared",
ptname, msgname)
return None
ptype = VOID
else:
ptype = self._canonicalType(ptdecl.type, param.typespec,
chmodallowed=1)
return self.declare(
loc=ploc,
type=ptype,
progname=param.name)
return self.declare(loc=ploc,
type=ptype,
progname=param.name)
for i, inparam in enumerate(md.inParams):
pdecl = paramToDecl(inparam)
if pdecl is not None:
msgtype.params.append(pdecl.type)
md.inParams[i] = pdecl
else:
md.inParams[i].type = 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
else:
md.outParams[i].type = None
msgtype.returns.append(pdecl.type)
md.outParams[i] = pdecl
self.symtab.exitScope(md)
@ -1096,6 +1153,45 @@ def formatcycles(cycles):
r.append("`%s'" % s)
return ", ".join(r)
def fullyDefined(t, exploring=None):
'''The rules for "full definition" of a type are
defined(atom) := true
defined(array basetype) := defined(basetype)
defined(struct f1 f2...) := defined(f1) and defined(f2) and ...
defined(union c1 c2 ...) := defined(c1) or defined(c2) or ...
'''
if exploring is None:
exploring = set()
if t.isAtom():
return True
elif t.isArray():
return fullyDefined(t.basetype, exploring)
elif t.defined:
return True
assert t.isCompound()
if t in exploring:
return False
exploring.add(t)
for c in t.itercomponents():
cdefined = fullyDefined(c, exploring)
if t.isStruct() and not cdefined:
t.defined = False
break
elif t.isUnion() and cdefined:
t.defined = True
break
else:
if t.isStruct(): t.defined = True
elif t.isUnion(): t.defined = False
exploring.remove(t)
return t.defined
class CheckTypes(TcheckVisitor):
def __init__(self, errors):
# don't need the symbol table, we just want the error reporting
@ -1110,6 +1206,17 @@ class CheckTypes(TcheckVisitor):
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):
if not fullyDefined(ud.decl.type):
self.error(ud.decl.loc,
"union `%s' is only partially defined", ud.name)
def visitProtocol(self, p):
self.ptype = p.decl.type