summaryrefslogtreecommitdiffstats
path: root/ipc/ipdl/ipdl/ast.py
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/ipdl/ipdl/ast.py')
-rw-r--r--ipc/ipdl/ipdl/ast.py468
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 = {}