diff options
Diffstat (limited to '')
-rw-r--r-- | ipc/ipdl/ipdl/ast.py | 468 |
1 files changed, 468 insertions, 0 deletions
diff --git a/ipc/ipdl/ipdl/ast.py b/ipc/ipdl/ipdl/ast.py new file mode 100644 index 0000000000..e50cbb5c65 --- /dev/null +++ b/ipc/ipdl/ipdl/ast.py @@ -0,0 +1,468 @@ +# 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 = {} |