# 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: @classmethod def __hash__(cls): return hash_str(cls.pretty) @classmethod def __str__(cls): return cls.pretty class ASYNC(PrettyPrinted): pretty = "async" class INTR(PrettyPrinted): pretty = "intr" class SYNC(PrettyPrinted): pretty = "sync" class INOUT(PrettyPrinted): pretty = "inout" class IN(PrettyPrinted): pretty = "in" class OUT(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 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 = {}