add discriminated union types to IPDL

This commit is contained in:
Chris Jones 2009-09-10 23:55:03 -05:00
Родитель 9988d69938
Коммит dd1940dc7b
11 изменённых файлов: 1305 добавлений и 108 удалений

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

@ -46,9 +46,29 @@ include "mozilla/plugins/PluginMessageUtils.h";
using NPError;
using NPWindow;
// FIXME/bent: demo purposes only
using mozilla::void_t;
using mozilla::null_t;
namespace mozilla {
namespace plugins {
// FIXME/bent: demo purposes only
union Variant {
int;
double;
void_t;
null_t;
PPluginInstance;
};
rpc protocol PPluginInstance
{
manager PPluginModule;
@ -56,6 +76,15 @@ rpc protocol PPluginInstance
manages PPluginScriptableObject;
manages PBrowserStream;
// FIXME/bent: demo purposes only
child:
Test(Variant v1, Variant v2);
child:
/* NPP_NewStream */
rpc PBrowserStream(nsCString url,

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

@ -57,7 +57,6 @@ rpc protocol PPluginScriptableObject
manager PPluginInstance;
child:
// NPClass methods
rpc Invalidate();

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

@ -65,6 +65,62 @@ class PluginInstanceChild : public PPluginInstanceChild
protected:
friend class BrowserStreamChild;
// FIXME/bent: demo purposes only
virtual nsresult
RecvTest(const Variant& v1, const Variant& v2)
{
printf("\n[PluginInstanceChild] v1: ");
switch (v1.type()) {
case Variant::Tint: {
int i = v1;
printf("variant-int %d", i);
break;
}
case Variant::Tdouble: {
double d = v1;
printf("variant-double %e", d);
break;
}
case Variant::TPPluginInstanceChild: {
const PPluginInstanceChild* p = v1;
printf("plugin instance %p", p);
break;
}
default:
NS_RUNTIMEABORT("unexpected Variant value");
}
printf(", v2: ");
switch (v2.type()) {
case Variant::Tint: {
int i = v2;
printf("variant-int %d", i);
break;
}
case Variant::Tdouble: {
double d = v2;
printf("variant-double %e", d);
break;
}
case Variant::TPPluginInstanceChild: {
const PPluginInstanceChild* p = v2;
printf("plugin instance %p", p);
break;
}
default:
NS_RUNTIMEABORT("unexpected Variant value");
}
puts("\n");
return NS_OK;
}
virtual nsresult AnswerNPP_SetWindow(const NPWindow& window, NPError* rv);
virtual nsresult AnswerNPP_GetValue(const nsString& key, nsString* value);

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

@ -47,6 +47,14 @@
#include "nsStringGlue.h"
namespace mozilla {
// XXX might want to move these to nscore.h or something, they can be
// generally useful
struct void_t { };
struct null_t { };
namespace ipc {
typedef intptr_t NPRemoteIdentifier;
@ -364,6 +372,32 @@ struct ParamTraits<NPVariant>
}
};
template<>
struct ParamTraits<mozilla::void_t>
{
typedef mozilla::void_t paramType;
static void Write(Message* aMsg, const paramType& aParam) { }
static bool
Read(const Message* aMsg, void** aIter, paramType* aResult)
{
*aResult = paramType();
return true;
}
};
template<>
struct ParamTraits<mozilla::null_t>
{
typedef mozilla::null_t paramType;
static void Write(Message* aMsg, const paramType& aParam) { }
static bool
Read(const Message* aMsg, void** aIter, paramType* aResult)
{
*aResult = paramType();
return true;
}
};
template <>
struct ParamTraits<mozilla::plugins::IPCByteRange>
{

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

@ -188,6 +188,15 @@ PluginModuleParent::NPP_New(NPMIMEType pluginType,
printf ("[PluginModuleParent] %s: got return value %hd\n", __FUNCTION__,
prv);
// FIXME/bent: demo purposes only
Variant v1(0);
Variant v2(parentInstance);
printf("\n[PluginModuleParent] sending Test msg\n\n");
parentInstance->SendTest(v1, v2);
if (NPERR_NO_ERROR != prv)
return prv;
NS_ASSERTION(parentInstance,

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

@ -42,6 +42,8 @@ class Visitor:
cxxInc.accept(self)
for protoInc in tu.protocolIncludes:
protoInc.accept(self)
for union in tu.unions:
union.accept(self)
for using in tu.using:
using.accept(self)
tu.protocol.accept(self)
@ -54,6 +56,10 @@ class Visitor:
# and pass-specific handling
pass
def visitUnionDecl(self, union):
for t in union.components:
t.accept(self)
def visitUsingStmt(self, using):
pass
@ -133,6 +139,20 @@ class Node:
if not hasattr(self, attrsName):
setattr(self, attrsName, _struct())
class NamespacedNode(Node):
def __init__(self, loc=Loc.NONE, name=None):
Node.__init__(self, loc)
self.name = name
self.namespaces = [ ]
def addOuterNamespace(self, namespace):
self.namespaces.insert(0, namespace)
def qname(self):
return QualifiedId(self.loc, self.name,
[ ns.namespace for ns in self.namespaces ])
class TranslationUnit(Node):
def __init__(self):
Node.__init__(self)
@ -140,10 +160,12 @@ class TranslationUnit(Node):
self.cxxIncludes = [ ]
self.protocolIncludes = [ ]
self.using = [ ]
self.unions = [ ]
self.protocol = None
def addCxxInclude(self, cxxInclude): self.cxxIncludes.append(cxxInclude)
def addProtocolInclude(self, pInc): self.protocolIncludes.append(pInc)
def addUnionDecl(self, union): self.unions.append(union)
def addUsingStmt(self, using): self.using.append(using)
def setProtocol(self, protocol): self.protocol = protocol
@ -217,20 +239,20 @@ _prettyTable = {
}
class Protocol(Node):
def __init__(self, loc):
class Namespace(Node):
def __init__(self, loc, namespace):
Node.__init__(self, loc)
self.name = None
self.namespaces = [ ]
self.namespace = namespace
class Protocol(NamespacedNode):
def __init__(self, loc):
NamespacedNode.__init__(self, loc)
self.sendSemantics = ASYNC
self.managesStmts = [ ]
self.messageDecls = [ ]
self.transitionStmts = [ ]
self.startStates = [ ]
def addOuterNamespace(self, namespace):
self.namespaces.insert(0, namespace)
def addManagesStmts(self, managesStmts):
self.managesStmts += managesStmts
@ -240,10 +262,10 @@ class Protocol(Node):
def addTransitionStmts(self, transStmts):
self.transitionStmts += transStmts
class Namespace(Node):
def __init__(self, loc, namespace):
Node.__init__(self, loc)
self.namespace = namespace
class UnionDecl(NamespacedNode):
def __init__(self, loc, name, components):
NamespacedNode.__init__(self, loc, name)
self.components = components
class ManagerStmt(Node):
def __init__(self, loc, managerName):

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

@ -60,9 +60,12 @@ class Visitor:
def visitTypeEnum(self, enum):
pass
def visitTypeUnion(self, union):
for t, name in union.components:
t.accept(self)
def visitTypedef(self, tdef):
tdef.fromtype.accept(self)
tdef.totype.accept(self)
def visitForwardDecl(self, fd):
pass
@ -120,6 +123,11 @@ class Visitor:
e.left.accept(self)
e.right.accept(self)
def visitExprConditional(self, c):
c.cond.accept(self)
c.ife.accept(self)
c.elsee.accept(self)
def visitExprAddrOf(self, eao):
self.visitExprPrefixUnop(eao)
@ -175,6 +183,9 @@ class Visitor:
ss.expr.accept(self)
self.visitBlock(ss)
def visitStmtBreak(self, sb):
pass
def visitStmtExpr(self, se):
se.expr.accept(self)
@ -239,21 +250,47 @@ class Block(Node):
# type and decl thingies
class Namespace(Block):
def __init__(self, name):
assert isinstance(name, str)
Block.__init__(self)
self.name = name
class Type(Node):
def __init__(self, name, const=0, ptr=0, ref=0, actor=0):
def __init__(self, name, const=0,
ptr=0, ptrconst=0, ptrptr=0, ptrconstptr=0,
ref=0,
actor=0):
"""
To avoid getting fancy with recursive types, we limit the kinds
of pointer types that can be be constructed.
ptr => T*
ptrconst => T* const
ptrptr => T**
ptrconstptr => T* const*
Any type, naked or pointer, can be const (const T) or ref (T&).
The "actor" flag is used internally when we need to know if the C++
type actually represents an IPDL actor type.
"""
Node.__init__(self)
self.name = name
self.const = const
self.ptr = ptr
self.ptrconst = ptrconst
self.ptrptr = ptrptr
self.ptrconstptr = ptrconstptr
self.ref = ref
self.actor = actor
# XXX could get serious here with recursive types, but shouldn't
# need that for this codegen
def __deepcopy__(self, memo):
return Type(self.name, self.const, self.ptr, self.ref, self.actor)
return Type(self.name,
const=self.const,
ptr=self.ptr, ptrconst=self.ptrconst,
ptrptr=self.ptrptr, ptrconstptr=self.ptrconstptr,
ref=self.ref, actor=self.actor)
class TypeEnum(Node):
def __init__(self, name=None):
@ -265,11 +302,22 @@ class TypeEnum(Node):
def addId(self, id, num=None):
self.idnums.append((id, num))
class TypeUnion(Node):
def __init__(self, name=None):
Node.__init__(self)
self.name = name
self.components = [ ] # pairs of (Type, name)
def addComponent(self, type, name):
self.components.append((type, name))
class Typedef(Node):
def __init__(self, fromtype, totype):
def __init__(self, fromtype, totypename):
assert isinstance(totypename, str)
Node.__init__(self)
self.fromtype = fromtype
self.totype = totype
self.totypename = totypename
class ForwardDecl(Node):
def __init__(self, pqname, cls=0, struct=0):
@ -292,17 +340,21 @@ class Decl(Node):
# class stuff
class Class(Block):
def __init__(self, name, inherits=[ ],
interface=False, abstract=False, final=False):
interface=0, abstract=0, final=0,
specializes=None, struct=0):
assert not (interface and abstract)
assert not (abstract and final)
assert not (interface and final)
assert not (inherits and specializes)
Block.__init__(self)
self.name = name
self.inherits = inherits
self.interface = interface
self.abstract = abstract
self.final = final
self.inherits = inherits # [ Type ]
self.interface = interface # bool
self.abstract = abstract # bool
self.final = final # bool
self.specializes = specializes # Type or None
self.struct = struct # bool
class Inherit(Node):
def __init__(self, name, viz='public'):
@ -317,18 +369,24 @@ class FriendClassDecl(Node):
class MethodDecl(Node):
def __init__(self, name, params=[ ], ret=Type('void'),
virtual=False, const=False, pure=False, static=False):
virtual=0, const=0, pure=0, static=0, typeop=0):
assert not (virtual and static)
assert not pure or virtual # pure => virtual
assert not (static and typeop)
if typeop:
ret = None
Node.__init__(self)
self.name = name
self.params = params
self.ret = ret
self.virtual = virtual
self.const = const
self.pure = pure
self.static = static
self.params = params # [ Param ]
self.ret = ret # Type or None
self.virtual = virtual # bool
self.const = const # bool
self.pure = pure # bool
self.static = static # bool
self.typeop = typeop # bool
def __deepcopy__(self, memo):
return MethodDecl(self.name,
copy.deepcopy(self.params, memo),
@ -343,8 +401,9 @@ class MethodDefn(Block):
self.decl = decl
class ConstructorDecl(MethodDecl):
def __init__(self, name, params=[ ]):
def __init__(self, name, params=[ ], explicit=0):
MethodDecl.__init__(self, name, params=params, ret=None)
self.explicit = explicit
class ConstructorDefn(MethodDefn):
def __init__(self, decl, memberinits=[ ]):
@ -352,7 +411,7 @@ class ConstructorDefn(MethodDefn):
self.memberinits = memberinits
class DestructorDecl(MethodDecl):
def __init__(self, name, virtual=False):
def __init__(self, name, virtual=0):
MethodDecl.__init__(self, name, params=[ ], ret=None,
virtual=virtual)
class DestructorDefn(MethodDefn):
@ -414,10 +473,18 @@ class ExprCast(Node):
class ExprBinary(Node):
def __init__(self, left, op, right):
Node.__init__(self)
self.left = left
self.op = op
self.right = right
class ExprConditional(Node):
def __init__(self, cond, ife, elsee):
Node.__init__(self)
self.cond = cond
self.ife = ife
self.elsee = elsee
class ExprSelect(Node):
def __init__(self, obj, op, field):
Node.__init__(self)
@ -440,8 +507,15 @@ class ExprCall(Node):
class ExprNew(ExprCall):
# XXX taking some poetic license ...
def __init__(self, type, args=[ ]):
ExprCall.__init__(self, ExprVar(type.name), args)
def __init__(self, type, args=[ ], newargs=None):
assert not (type.const or type.ref)
ctorname = type.name
if type.ptr: ctorname += '*'
elif type.ptrptr: ctorname += '**'
ExprCall.__init__(self, ExprVar(ctorname), args)
self.newargs = newargs
class ExprDelete(Node):
def __init__(self, obj):
@ -467,6 +541,9 @@ class Label(Node):
def __init__(self, name):
Node.__init__(self)
self.name = name
Label.PUBLIC = Label('public')
Label.PROTECTED = Label('protected')
Label.PRIVATE = Label('private')
class CaseLabel(Node):
def __init__(self, name):
@ -501,6 +578,10 @@ class StmtSwitch(Block):
self.addstmt(block)
self.nr_cases += 1
class StmtBreak(Node):
def __init__(self):
Node.__init__(self)
class StmtExpr(Node):
def __init__(self, expr):
Node.__init__(self)

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

@ -55,10 +55,17 @@ class CxxCodeGen(CodePrinter, Visitor):
def visitType(self, t):
ts = ''
if t.const: ts += 'const '
ts += t.name
if t.ptr: ts += '*'
elif t.ptrconst: ts += '* const'
elif t.ptrptr: ts += '**'
elif t.ptrconstptr: ts += '* const*'
if t.ref: ts += '&'
self.write(ts)
def visitTypeEnum(self, te):
@ -80,12 +87,26 @@ class CxxCodeGen(CodePrinter, Visitor):
self.printdent('}')
def visitTypeUnion(self, u):
self.write('union')
if u.name:
self.write(' '+ u.name)
self.println(' {')
self.indent()
for t, name in u.components:
self.printdent()
t.accept(self)
self.println(' '+ name +';')
self.dedent()
self.printdent('}')
def visitTypedef(self, td):
self.printdent('typedef ')
td.fromtype.accept(self)
self.write(' ')
td.totype.accept(self)
self.println(';')
self.println(' '+ td.totypename +';')
def visitForwardDecl(self, fd):
if fd.cls: self.printdent('class ')
@ -99,6 +120,12 @@ class CxxCodeGen(CodePrinter, Visitor):
self.write(' '+ d.name)
def visitClass(self, c):
if c.specializes is not None:
self.printdentln('template<>')
if c.struct:
self.printdent('struct')
else:
self.printdent('class')
if c.interface:
# FIXME/cjones: turn this "on" when we get the analysis
@ -110,6 +137,11 @@ class CxxCodeGen(CodePrinter, Visitor):
self.write(' NS_FINAL_CLASS')
self.write(' '+ c.name)
if c.specializes is not None:
self.write(' <')
c.specializes.accept(self)
self.write('>')
ninh = len(c.inherits)
if 0 < ninh:
self.println(' :')
@ -136,8 +168,10 @@ class CxxCodeGen(CodePrinter, Visitor):
def visitFriendClassDecl(self, fcd):
self.printdentln('friend class '+ fcd.friend +';')
def visitMethodDecl(self, md):
assert not (md.static and md.virtual)
if md.static:
self.write('static ')
if md.virtual:
@ -153,6 +187,7 @@ class CxxCodeGen(CodePrinter, Visitor):
if md.pure:
self.write(' = 0')
def visitMethodDefn(self, md):
self.printdent()
md.decl.accept(self)
@ -166,7 +201,8 @@ class CxxCodeGen(CodePrinter, Visitor):
def visitConstructorDecl(self, cd):
# FIXME/cjones: explicit when possible
if cd.explicit:
self.write('explicit ')
self.visitMethodDecl(cd)
def visitConstructorDefn(self, cd):
@ -244,6 +280,15 @@ class CxxCodeGen(CodePrinter, Visitor):
e.right.accept(self)
self.write(')')
def visitExprConditional(self, c):
self.write('(')
c.cond.accept(self)
self.write(' ? ')
c.ife.accept(self)
self.write(' : ')
c.elsee.accept(self)
self.write(')')
def visitExprSelect(self, es):
es.obj.accept(self)
self.write(es.op + es.field)
@ -261,6 +306,10 @@ class CxxCodeGen(CodePrinter, Visitor):
def visitExprNew(self, en):
self.write('new ')
if en.newargs is not None:
self.write('(')
self.writeExprList(en.newargs)
self.write(') ')
self.visitExprCall(en)
def visitExprDelete(self, ed):
@ -317,6 +366,9 @@ class CxxCodeGen(CodePrinter, Visitor):
self.dedent()
self.printdentln('}')
def visitStmtBreak(self, sb):
self.printdentln('break;')
def visitStmtDecl(self, sd):
self.printdent()

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -168,6 +168,7 @@ reserved = set((
'state',
'sync',
'transfer',
'union',
'using'))
tokens = [
'COLONCOLON', 'ID', 'STRING'
@ -207,15 +208,28 @@ def t_error(t):
##-----------------------------------------------------------------------------
def p_TranslationUnit(p):
"""TranslationUnit : Preamble NamespacedProtocolDefn"""
"""TranslationUnit : Preamble NamespacedStuff"""
tu = Parser.current.tu
for stmt in p[1]:
if isinstance(stmt, CxxInclude): tu.addCxxInclude(stmt)
elif isinstance(stmt, ProtocolInclude): tu.addProtocolInclude(stmt)
elif isinstance(stmt, UsingStmt): tu.addUsingStmt(stmt)
if isinstance(stmt, CxxInclude):
tu.addCxxInclude(stmt)
elif isinstance(stmt, ProtocolInclude):
tu.addProtocolInclude(stmt)
elif isinstance(stmt, UsingStmt):
tu.addUsingStmt(stmt)
else:
assert 0
tu.protocol = p[2]
for thing in p[2]:
if isinstance(thing, UnionDecl):
tu.addUnionDecl(thing)
elif isinstance(thing, Protocol):
if tu.protocol is not None:
_error(thing.loc, "only one protocol definition per file")
tu.protocol = thing
else:
assert(0)
p[0] = tu
##--------------------
@ -258,16 +272,39 @@ def p_UsingStmt(p):
p[0] = UsingStmt(locFromTok(p, 1), p[2])
##--------------------
## Protocol definition
def p_NamespacedProtocolDefn(p):
"""NamespacedProtocolDefn : NAMESPACE ID '{' NamespacedProtocolDefn '}'
| ProtocolDefn"""
## Namespaced stuff
def p_NamespacedStuff(p):
"""NamespacedStuff : NamespacedStuff NamespaceThing
| NamespaceThing"""
if 2 == len(p):
p[0] = p[1]
else:
protocol = p[4]
protocol.addOuterNamespace(Namespace(locFromTok(p, 1), p[2]))
p[0] = protocol
p[1].extend(p[2])
p[0] = p[1]
def p_NamespaceThing(p):
"""NamespaceThing : NAMESPACE ID '{' NamespacedStuff '}'
| UnionDecl
| ProtocolDefn"""
if 2 == len(p):
p[0] = [ p[1] ]
else:
for thing in p[4]:
thing.addOuterNamespace(Namespace(locFromTok(p, 1), p[2]))
p[0] = p[4]
def p_UnionDecl(p):
"""UnionDecl : UNION ID '{' ComponentTypes '}' ';'"""
p[0] = UnionDecl(locFromTok(p, 1), p[2], p[4])
def p_ComponentTypes(p):
"""ComponentTypes : ComponentTypes Type ';'
| Type ';'"""
if 3 == len(p):
p[0] = [ p[1] ]
else:
p[1].append(p[2])
p[0] = p[1]
def p_ProtocolDefn(p):
"""ProtocolDefn : OptionalSendSemanticsQual PROTOCOL ID '{' ManagerStmtOpt ManagesStmts OptionalMessageDecls TransitionStmts '}' ';'"""

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

@ -118,6 +118,7 @@ class IPDLType(Type):
def isMessage(self): return False
def isProtocol(self): return False
def isActor(self): return False
def isUnion(self): return False
def isAsync(self): return self.sendSemantics is ASYNC
def isSync(self): return self.sendSemantics is SYNC
@ -199,7 +200,7 @@ class ProtocolType(IPDLType):
return not self.isManaged()
class ActorType(IPDLType):
def __init__(self, protocol, state):
def __init__(self, protocol, state=None):
self.protocol = protocol
self.state = state
def isActor(self): return True
@ -209,6 +210,15 @@ class ActorType(IPDLType):
def fullname(self):
return self.protocol.fullname()
class UnionType(IPDLType):
def __init__(self, qname, components):
self.qname = qname
self.components = components
def isUnionType(self): return True
def name(self): return self.qname.baseid
def fullname(self): return str(self.qname)
##--------------------
_builtinloc = Loc('<builtin>', 0)
def makeBuiltinUsing(tname):
@ -395,8 +405,7 @@ class GatherDecls(TcheckVisitor):
# 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 = QualifiedId(p.loc, p.name,
[ ns.namespace for ns in p.namespaces ])
qname = p.qname()
if 0 == len(qname.quals):
fullname = None
else:
@ -415,6 +424,10 @@ class GatherDecls(TcheckVisitor):
for using in tu.using:
using.accept(self)
# declare unions
for union in tu.unions:
union.accept(self)
# grab symbols in the protocol itself
p.accept(self)
@ -427,6 +440,32 @@ class GatherDecls(TcheckVisitor):
pi.tu.accept(self)
self.symtab.declare(pi.tu.protocol.decl)
def visitUnionDecl(self, ud):
qname = ud.qname()
if 0 == len(qname.quals):
fullname = None
else:
fullname = str(qname)
components = [ ]
nactors = 0 # FIXME
for c in ud.components:
ctype = self.symtab.lookup(str(c)).type
if ctype.isIPDL() and ctype.isProtocol():
ctype = ActorType(ctype)
nactors += 1
components.append(ctype)
if nactors > 1:
self.error(ud.loc, 'sorry, IPDL currently limits you to one actor type per union. file a bug against :cjones')
ud.decl = self.declare(
loc=ud.loc,
type=UnionType(qname, components),
shortname=ud.name,
fullname=fullname)
def visitUsingStmt(self, using):
fullname = str(using.type)
if using.type.basename() == fullname: