Source code

Revision control

Copy as Markdown

Other Tools

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from .util import hash_str
NOT_NESTED = 1
INSIDE_SYNC_NESTED = 2
INSIDE_CPOW_NESTED = 3
NESTED_ATTR_MAP = {
"not": NOT_NESTED,
"inside_sync": INSIDE_SYNC_NESTED,
"inside_cpow": INSIDE_CPOW_NESTED,
}
# Each element of this list is the IPDL source representation of a priority.
priorityList = ["normal", "input", "vsync", "mediumhigh", "control"]
priorityAttrMap = {src: idx for idx, src in enumerate(priorityList)}
NORMAL_PRIORITY = priorityAttrMap["normal"]
class Visitor:
def defaultVisit(self, node):
raise Exception(
"INTERNAL ERROR: no visitor for node type `%s'" % (node.__class__.__name__)
)
def visitTranslationUnit(self, tu):
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.builtinUsing:
using.accept(self)
for using in tu.using:
using.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
def visitStructDecl(self, struct):
for f in struct.fields:
f.accept(self)
for a in struct.attributes.values():
a.accept(self)
def visitStructField(self, field):
field.typespec.accept(self)
def visitUnionDecl(self, union):
for t in union.components:
t.accept(self)
for a in union.attributes.values():
a.accept(self)
def visitUsingStmt(self, using):
for a in using.attributes.values():
a.accept(self)
def visitProtocol(self, p):
for namespace in p.namespaces:
namespace.accept(self)
for mgr in p.managers:
mgr.accept(self)
for managed in p.managesStmts:
managed.accept(self)
for msgDecl in p.messageDecls:
msgDecl.accept(self)
for a in p.attributes.values():
a.accept(self)
def visitNamespace(self, ns):
pass
def visitManager(self, mgr):
pass
def visitManagesStmt(self, mgs):
pass
def visitMessageDecl(self, md):
for inParam in md.inParams:
inParam.accept(self)
for outParam in md.outParams:
outParam.accept(self)
for a in md.attributes.values():
a.accept(self)
def visitParam(self, decl):
for a in decl.attributes.values():
a.accept(self)
def visitTypeSpec(self, ts):
pass
def visitAttribute(self, a):
if isinstance(a.value, Node):
a.value.accept(self)
def visitStringLiteral(self, sl):
pass
def visitDecl(self, d):
for a in d.attributes.values():
a.accept(self)
class Loc:
def __init__(self, filename="<??>", lineno=0):
assert filename
self.filename = filename
self.lineno = lineno
def __repr__(self):
return "%r:%r" % (self.filename, self.lineno)
def __str__(self):
return "%s:%s" % (self.filename, self.lineno)
Loc.NONE = Loc(filename="<??>", lineno=0)
class _struct:
pass
class Node:
def __init__(self, loc=Loc.NONE):
self.loc = loc
def accept(self, visitor):
visit = getattr(visitor, "visit" + self.__class__.__name__, None)
if visit is None:
return getattr(visitor, "defaultVisit")(self)
return visit(self)
def addAttrs(self, attrsName):
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.name for ns in self.namespaces])
class TranslationUnit(NamespacedNode):
def __init__(self, type, name):
NamespacedNode.__init__(self, name=name)
self.filetype = type
self.filename = None
self.cxxIncludes = []
self.includes = []
self.builtinUsing = []
self.using = []
self.structsAndUnions = []
self.protocol = None
def addCxxInclude(self, cxxInclude):
self.cxxIncludes.append(cxxInclude)
def addInclude(self, inc):
self.includes.append(inc)
def addStructDecl(self, struct):
self.structsAndUnions.append(struct)
def addUnionDecl(self, union):
self.structsAndUnions.append(union)
def addUsingStmt(self, using):
self.using.append(using)
def setProtocol(self, protocol):
self.protocol = protocol
class CxxInclude(Node):
def __init__(self, loc, cxxFile):
Node.__init__(self, loc)
self.file = cxxFile
class Include(Node):
def __init__(self, loc, type, name):
Node.__init__(self, loc)
suffix = "ipdl"
if type == "header":
suffix += "h"
self.file = "%s.%s" % (name, suffix)
class UsingStmt(Node):
def __init__(
self,
loc,
cxxTypeSpec,
cxxHeader=None,
kind=None,
attributes={},
):
Node.__init__(self, loc)
assert isinstance(cxxTypeSpec, QualifiedId)
assert cxxHeader is None or isinstance(cxxHeader, str)
assert kind is None or kind == "class" or kind == "struct"
self.type = cxxTypeSpec
self.header = cxxHeader
self.kind = kind
self.attributes = attributes
def canBeForwardDeclared(self):
return self.isClass() or self.isStruct()
def isClass(self):
return self.kind == "class"
def isStruct(self):
return self.kind == "struct"
def isRefcounted(self):
return "RefCounted" in self.attributes
def isSendMoveOnly(self):
moveonly = self.attributes.get("MoveOnly")
return moveonly and moveonly.value in (None, "send")
def isDataMoveOnly(self):
moveonly = self.attributes.get("MoveOnly")
return moveonly and moveonly.value in (None, "data")
# "singletons"
class PrettyPrinted(type):
def __hash__(cls):
return hash_str(cls.pretty)
def __str__(cls):
return cls.pretty
class ASYNC(metaclass=PrettyPrinted):
pretty = "async"
class SYNC(metaclass=PrettyPrinted):
pretty = "sync"
class INOUT(metaclass=PrettyPrinted):
pretty = "inout"
class IN(metaclass=PrettyPrinted):
pretty = "in"
class OUT(metaclass=PrettyPrinted):
pretty = "out"
class Namespace(Node):
def __init__(self, loc, namespace):
Node.__init__(self, loc)
self.name = namespace
class Protocol(NamespacedNode):
def __init__(self, loc):
NamespacedNode.__init__(self, loc)
self.attributes = {}
self.sendSemantics = ASYNC
self.managers = []
self.managesStmts = []
self.messageDecls = []
def nestedUpTo(self):
if "NestedUpTo" not in self.attributes:
return NOT_NESTED
return NESTED_ATTR_MAP.get(self.attributes["NestedUpTo"].value, NOT_NESTED)
def implAttribute(self, side):
assert side in ("parent", "child")
attr = self.attributes.get(side.capitalize() + "Impl")
if attr is not None:
return attr.value
return None
def procAttribute(self, side):
assert side in ("parent", "child")
attr = self.attributes.get(side.capitalize() + "Proc")
if attr is not None:
return attr.value
elif side == "parent" and len(self.managers) == 0:
return "Parent" # Default for toplevel actors
return None
class StructField(Node):
def __init__(self, loc, type, name):
Node.__init__(self, loc)
self.typespec = type
self.name = name
class StructDecl(NamespacedNode):
def __init__(self, loc, name, fields, attributes):
NamespacedNode.__init__(self, loc, name)
self.fields = fields
self.attributes = attributes
# A list of indices into `fields` for determining the order in
# which fields are laid out in memory. We don't just reorder
# `fields` itself so as to keep the ordering reasonably stable
# for e.g. C++ constructors when new fields are added.
self.packed_field_ordering = []
class UnionDecl(NamespacedNode):
def __init__(self, loc, name, components, attributes):
NamespacedNode.__init__(self, loc, name)
self.components = components
self.attributes = attributes
class Manager(Node):
def __init__(self, loc, managerName):
Node.__init__(self, loc)
self.name = managerName
class ManagesStmt(Node):
def __init__(self, loc, managedName):
Node.__init__(self, loc)
self.name = managedName
class MessageDecl(Node):
def __init__(self, loc):
Node.__init__(self, loc)
self.name = None
self.attributes = {}
self.sendSemantics = ASYNC
self.direction = None
self.inParams = []
self.outParams = []
def addInParams(self, inParamsList):
self.inParams += inParamsList
def addOutParams(self, outParamsList):
self.outParams += outParamsList
def nested(self):
if "Nested" not in self.attributes:
return NOT_NESTED
return NESTED_ATTR_MAP.get(self.attributes["Nested"].value, NOT_NESTED)
def priority(self):
if "Priority" in self.attributes:
sourcePriority = self.attributes["Priority"].value
else:
sourcePriority = "normal"
return priorityAttrMap.get(sourcePriority, NORMAL_PRIORITY)
def replyPriority(self):
if "ReplyPriority" in self.attributes:
sourcePriority = self.attributes["ReplyPriority"].value
if sourcePriority in priorityAttrMap:
return priorityAttrMap[sourcePriority]
return self.priority()
class Param(Node):
def __init__(self, loc, typespec, name, attributes={}):
Node.__init__(self, loc)
self.name = name
self.typespec = typespec
self.attributes = attributes
class TypeSpec(Node):
def __init__(self, loc, spec):
Node.__init__(self, loc)
assert isinstance(spec, str)
self.spec = spec # str
self.array = False # bool
self.maybe = False # bool
self.nullable = False # bool
self.uniqueptr = False # bool
def basename(self):
return self.spec
def __str__(self):
return self.spec
class Attribute(Node):
def __init__(self, loc, name, value):
Node.__init__(self, loc)
self.name = name
self.value = value
class StringLiteral(Node):
def __init__(self, loc, value):
Node.__init__(self, loc)
self.value = value
def __str__(self):
return '"%s"' % self.value
class QualifiedId: # FIXME inherit from node?
def __init__(self, loc, baseid, quals=[]):
assert isinstance(baseid, str)
for qual in quals:
assert isinstance(qual, str)
self.loc = loc
self.baseid = baseid
self.quals = quals
def qualify(self, id):
self.quals.append(self.baseid)
self.baseid = id
def __str__(self):
# NOTE: include a leading "::" in order to force all QualifiedIds to be
# fully qualified types in C++
return "::" + "::".join(self.quals + [self.baseid])
# added by type checking passes
class Decl(Node):
def __init__(self, loc):
Node.__init__(self, loc)
self.progname = None # what the programmer typed, if relevant
self.shortname = None # shortest way to refer to this decl
self.fullname = None # full way to refer to this decl
self.loc = loc
self.type = None
self.scope = None
self.attributes = {}