Files
tubestation/ipc/ipdl/ipdl/cxx/ast.py

1028 lines
25 KiB
Python

# 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/.
import copy
import functools
from ipdl.util import hash_str
class Visitor:
def defaultVisit(self, node):
raise Exception(
"INTERNAL ERROR: no visitor for node type `%s'" % (node.__class__.__name__)
)
def visitWhitespace(self, ws):
pass
def visitVerbatimNode(self, verb):
pass
def visitGroupNode(self, group):
for node in group.nodes:
node.accept(self)
def visitFile(self, f):
for thing in f.stuff:
thing.accept(self)
def visitCppDirective(self, ppd):
pass
def visitBlock(self, block):
for stmt in block.stmts:
stmt.accept(self)
def visitNamespace(self, ns):
self.visitBlock(ns)
def visitType(self, type):
pass
def visitTypeArray(self, ta):
ta.basetype.accept(self)
ta.nmemb.accept(self)
def visitTypeEnum(self, enum):
pass
def visitTypeFunction(self, fn):
pass
def visitTypeUnion(self, union):
for t, name in union.components:
t.accept(self)
def visitTypedef(self, tdef):
tdef.fromtype.accept(self)
def visitUsing(self, us):
us.type.accept(self)
def visitForwardDecl(self, fd):
pass
def visitDecl(self, decl):
decl.type.accept(self)
def visitParam(self, param):
self.visitDecl(param)
if param.default is not None:
param.default.accept(self)
def visitClass(self, cls):
for inherit in cls.inherits:
inherit.accept(self)
self.visitBlock(cls)
def visitInherit(self, inh):
pass
def visitFriendClassDecl(self, fcd):
pass
def visitMethodDecl(self, meth):
for param in meth.params:
param.accept(self)
if meth.ret is not None:
meth.ret.accept(self)
if meth.typeop is not None:
meth.typeop.accept(self)
if meth.T is not None:
meth.T.accept(self)
def visitMethodDefn(self, meth):
meth.decl.accept(self)
self.visitBlock(meth)
def visitFunctionDecl(self, fun):
self.visitMethodDecl(fun)
def visitFunctionDefn(self, fd):
self.visitMethodDefn(fd)
def visitConstructorDecl(self, ctor):
self.visitMethodDecl(ctor)
def visitConstructorDefn(self, cd):
cd.decl.accept(self)
for init in cd.memberinits:
init.accept(self)
self.visitBlock(cd)
def visitDestructorDecl(self, dtor):
self.visitMethodDecl(dtor)
def visitDestructorDefn(self, dd):
dd.decl.accept(self)
self.visitBlock(dd)
def visitExprLiteral(self, l):
pass
def visitExprVar(self, v):
pass
def visitExprPrefixUnop(self, e):
e.expr.accept(self)
def visitExprBinary(self, e):
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)
def visitExprDeref(self, ed):
self.visitExprPrefixUnop(ed)
def visitExprNot(self, en):
self.visitExprPrefixUnop(en)
def visitExprCast(self, ec):
ec.expr.accept(self)
def visitExprSelect(self, es):
es.obj.accept(self)
def visitExprAssn(self, ea):
ea.lhs.accept(self)
ea.rhs.accept(self)
def visitExprCall(self, ec):
ec.func.accept(self)
for arg in ec.args:
arg.accept(self)
def visitExprMove(self, ec):
self.visitExprCall(ec)
def visitExprNothing(self, ec):
self.visitExprCall(ec)
def visitExprSome(self, ec):
self.visitExprCall(ec)
def visitExprNew(self, en):
en.ctype.accept(self)
if en.newargs is not None:
for arg in en.newargs:
arg.accept(self)
if en.args is not None:
for arg in en.args:
arg.accept(self)
def visitExprDelete(self, ed):
ed.obj.accept(self)
def visitExprMemberInit(self, minit):
self.visitExprCall(minit)
def visitExprLambda(self, l):
self.visitBlock(l)
def visitStmtBlock(self, sb):
self.visitBlock(sb)
def visitStmtDecl(self, sd):
sd.decl.accept(self)
if sd.init is not None:
sd.init.accept(self)
def visitLabel(self, label):
pass
def visitCaseLabel(self, case):
pass
def visitDefaultLabel(self, dl):
pass
def visitStmtIf(self, si):
si.cond.accept(self)
si.ifb.accept(self)
if si.elseb is not None:
si.elseb.accept(self)
def visitStmtFor(self, sf):
if sf.init is not None:
sf.init.accept(self)
if sf.cond is not None:
sf.cond.accept(self)
if sf.update is not None:
sf.update.accept(self)
def visitStmtSwitch(self, ss):
ss.expr.accept(self)
self.visitBlock(ss)
def visitStmtBreak(self, sb):
pass
def visitStmtExpr(self, se):
se.expr.accept(self)
def visitStmtReturn(self, sr):
if sr.expr is not None:
sr.expr.accept(self)
# ------------------------------
class Node:
def __init__(self):
pass
def accept(self, visitor):
visit = getattr(visitor, "visit" + self.__class__.__name__, None)
if visit is None:
return getattr(visitor, "defaultVisit")(self)
return visit(self)
class Whitespace(Node):
# yes, this is silly. but we need to stick comments in the
# generated code without resorting to more serious hacks
def __init__(self, ws, indent=False):
Node.__init__(self)
self.ws = ws
self.indent = indent
Whitespace.NL = Whitespace("\n")
class VerbatimNode(Node):
# A block of text to be written verbatim to the output file.
#
# NOTE: This node is usually created by `code`. See `code.py` for details.
# FIXME: Merge Whitespace and VerbatimNode? They're identical.
def __init__(self, text, indent=0):
Node.__init__(self)
self.text = text
self.indent = indent
class GroupNode(Node):
# A group of nodes to be treated as a single node. These nodes have an
# optional indentation level which should be applied when generating them.
#
# NOTE: This node is usually created by `code`. See `code.py` for details.
def __init__(self, nodes, offset=0):
Node.__init__(self)
self.nodes = nodes
self.offset = offset
class File(Node):
def __init__(self, filename):
Node.__init__(self)
self.name = filename
# array of stuff in the file --- stmts and preprocessor thingies
self.stuff = []
def addthing(self, thing):
assert thing is not None
assert not isinstance(thing, list)
self.stuff.append(thing)
def addthings(self, things):
for t in things:
self.addthing(t)
# "look like" a Block so code doesn't have to care whether they're
# in global scope or not
def addstmt(self, stmt):
assert stmt is not None
assert not isinstance(stmt, list)
self.stuff.append(stmt)
def addstmts(self, stmts):
for s in stmts:
self.addstmt(s)
def addcode(self, tmpl, **context):
from ipdl.cxx.code import StmtCode
self.addstmt(StmtCode(tmpl, **context))
class CppDirective(Node):
"""represents |#[directive] [rest]|, where |rest| is any string"""
def __init__(self, directive, rest=None):
Node.__init__(self)
self.directive = directive
self.rest = rest
class Block(Node):
def __init__(self):
Node.__init__(self)
self.stmts = []
def addstmt(self, stmt):
assert stmt is not None
assert not isinstance(stmt, tuple)
self.stmts.append(stmt)
def addstmts(self, stmts):
for s in stmts:
self.addstmt(s)
def addcode(self, tmpl, **context):
from ipdl.cxx.code import StmtCode
self.addstmt(StmtCode(tmpl, **context))
# ------------------------------
# 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=False,
ptr=False,
ptrptr=False,
ptrconstptr=False,
ref=False,
rvalref=False,
hasimplicitcopyctor=True,
T=None,
inner=None,
):
"""
Represents the type |name<T>::inner| with the ptr and const
modifiers as specified.
To avoid getting fancy with recursive types, we limit the kinds
of pointer types that can be be constructed.
ptr => T*
ptrptr => T**
ptrconstptr => T* const*
ref => T&
rvalref => T&&
Any type, naked or pointer, can be const (const T) or ref (T&)."""
assert isinstance(name, str)
assert isinstance(const, bool)
assert isinstance(ptr, bool)
assert isinstance(ptrptr, bool)
assert isinstance(ptrconstptr, bool)
assert isinstance(ref, bool)
assert isinstance(rvalref, bool)
assert not isinstance(T, str)
Node.__init__(self)
self.name = name
self.const = const
self.ptr = ptr
self.ptrptr = ptrptr
self.ptrconstptr = ptrconstptr
self.ref = ref
self.rvalref = rvalref
self.hasimplicitcopyctor = hasimplicitcopyctor
self.T = T
self.inner = inner
# XXX could get serious here with recursive types, but shouldn't
# need that for this codegen
def __deepcopy__(self, memo):
return Type(
self.name,
const=self.const,
ptr=self.ptr,
ptrptr=self.ptrptr,
ptrconstptr=self.ptrconstptr,
ref=self.ref,
rvalref=self.rvalref,
T=copy.deepcopy(self.T, memo),
inner=copy.deepcopy(self.inner, memo),
)
Type.BOOL = Type("bool")
Type.INT = Type("int")
Type.INT32 = Type("int32_t")
Type.INTPTR = Type("intptr_t")
Type.NSRESULT = Type("nsresult")
Type.UINT32 = Type("uint32_t")
Type.UINT32PTR = Type("uint32_t", ptr=True)
Type.SIZE = Type("size_t")
Type.VOID = Type("void")
Type.VOIDPTR = Type("void", ptr=True)
Type.AUTO = Type("auto")
Type.AUTORVAL = Type("auto", rvalref=True)
class TypeArray(Node):
def __init__(self, basetype, nmemb):
"""the type |basetype DECLNAME[nmemb]|. |nmemb| is an Expr"""
self.basetype = basetype
self.nmemb = nmemb
class TypeEnum(Node):
def __init__(self, name=None):
"""name can be None"""
Node.__init__(self)
self.name = name
self.idnums = [] # pairs of ('Foo', [num]) or ('Foo', None)
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 = [] # [ Decl ]
def addComponent(self, type, name):
self.components.append(Decl(type, name))
class TypeFunction(Node):
def __init__(self, params=[], ret=Type("void")):
"""Anonymous function type std::function<>"""
self.params = params
self.ret = ret
@functools.total_ordering
class Typedef(Node):
def __init__(self, fromtype, totypename, templateargs=[]):
assert isinstance(totypename, str)
Node.__init__(self)
self.fromtype = fromtype
self.totypename = totypename
self.templateargs = templateargs
def __lt__(self, other):
return self.totypename < other.totypename
def __eq__(self, other):
return self.__class__ == other.__class__ and self.totypename == other.totypename
def __hash__(self):
return hash_str(self.totypename)
class Using(Node):
def __init__(self, type):
Node.__init__(self)
self.type = type
class ForwardDecl(Node):
def __init__(self, pqname, cls=False, struct=False):
# Exactly one of cls and struct must be set
assert cls ^ struct
self.pqname = pqname
self.cls = cls
self.struct = struct
class Decl(Node):
"""represents |Foo bar|, e.g. in a function signature"""
def __init__(self, type, name):
assert type is not None
assert not isinstance(type, str)
assert isinstance(name, str)
Node.__init__(self)
self.type = type
self.name = name
def __deepcopy__(self, memo):
return Decl(copy.deepcopy(self.type, memo), self.name)
class Param(Decl):
def __init__(self, type, name, default=None):
Decl.__init__(self, type, name)
self.default = default
def __deepcopy__(self, memo):
return Param(
copy.deepcopy(self.type, memo), self.name, copy.deepcopy(self.default, memo)
)
# ------------------------------
# class stuff
class Class(Block):
def __init__(
self,
name,
inherits=[],
interface=False,
abstract=False,
final=False,
specializes=None,
struct=False,
):
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 # [ 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, type, viz="public"):
assert isinstance(viz, str)
Node.__init__(self)
self.type = type
self.viz = viz
class FriendClassDecl(Node):
def __init__(self, friend):
Node.__init__(self)
self.friend = friend
# Python2 polyfill for Python3's Enum() functional API.
def make_enum(name, members_str):
members_list = members_str.split()
members_dict = {}
for member_value, member in enumerate(members_list, start=1):
members_dict[member] = member_value
return type(name, (), members_dict)
MethodSpec = make_enum("MethodSpec", "NONE VIRTUAL PURE OVERRIDE STATIC")
class MethodDecl(Node):
def __init__(
self,
name,
params=[],
ret=Type("void"),
methodspec=MethodSpec.NONE,
const=False,
warn_unused=False,
force_inline=False,
typeop=None,
T=None,
cls=None,
):
assert not (name and typeop)
assert name is None or isinstance(name, str)
assert not isinstance(ret, list)
for decl in params:
assert not isinstance(decl, str)
assert not isinstance(T, int)
assert isinstance(const, bool)
assert isinstance(warn_unused, bool)
assert isinstance(force_inline, bool)
if typeop is not None:
assert methodspec == MethodSpec.NONE
ret = None
Node.__init__(self)
self.name = name
self.params = params # [ Param ]
self.ret = ret # Type or None
self.methodspec = methodspec # enum
self.const = const # bool
self.warn_unused = warn_unused # bool
self.force_inline = force_inline or bool(T) # bool
self.typeop = typeop # Type or None
self.T = T # Type or None
self.cls = cls # Class or None
self.only_for_definition = False
def __deepcopy__(self, memo):
return MethodDecl(
self.name,
params=copy.deepcopy(self.params, memo),
ret=copy.deepcopy(self.ret, memo),
methodspec=self.methodspec,
const=self.const,
warn_unused=self.warn_unused,
force_inline=self.force_inline,
typeop=copy.deepcopy(self.typeop, memo),
T=copy.deepcopy(self.T, memo),
)
class MethodDefn(Block):
def __init__(self, decl):
Block.__init__(self)
self.decl = decl
class FunctionDecl(MethodDecl):
def __init__(
self,
name,
params=[],
ret=Type("void"),
methodspec=MethodSpec.NONE,
warn_unused=False,
force_inline=False,
T=None,
):
assert methodspec == MethodSpec.NONE or methodspec == MethodSpec.STATIC
MethodDecl.__init__(
self,
name,
params=params,
ret=ret,
methodspec=methodspec,
warn_unused=warn_unused,
force_inline=force_inline,
T=T,
)
class FunctionDefn(MethodDefn):
def __init__(self, decl):
MethodDefn.__init__(self, decl)
class ConstructorDecl(MethodDecl):
def __init__(self, name, params=[], explicit=False, force_inline=False):
MethodDecl.__init__(
self, name, params=params, ret=None, force_inline=force_inline
)
self.explicit = explicit
def __deepcopy__(self, memo):
return ConstructorDecl(
self.name, copy.deepcopy(self.params, memo), self.explicit
)
class ConstructorDefn(MethodDefn):
def __init__(self, decl, memberinits=[]):
MethodDefn.__init__(self, decl)
self.memberinits = memberinits
class DestructorDecl(MethodDecl):
def __init__(self, name, methodspec=MethodSpec.NONE, force_inline=False):
# C++ allows pure or override destructors, but ipdl cgen does not.
assert methodspec == MethodSpec.NONE or methodspec == MethodSpec.VIRTUAL
MethodDecl.__init__(
self,
name,
params=[],
ret=None,
methodspec=methodspec,
force_inline=force_inline,
)
def __deepcopy__(self, memo):
return DestructorDecl(
self.name, methodspec=self.methodspec, force_inline=self.force_inline
)
class DestructorDefn(MethodDefn):
def __init__(self, decl):
MethodDefn.__init__(self, decl)
# ------------------------------
# expressions
class ExprVar(Node):
def __init__(self, name):
assert isinstance(name, str)
Node.__init__(self)
self.name = name
ExprVar.THIS = ExprVar("this")
class ExprLiteral(Node):
def __init__(self, value, type):
"""|type| is a Python format specifier; 'd' for example"""
Node.__init__(self)
self.value = value
self.type = type
@staticmethod
def Int(i):
return ExprLiteral(i, "d")
@staticmethod
def String(s):
return ExprLiteral('"' + s + '"', "s")
def __str__(self):
return ("%" + self.type) % (self.value)
ExprLiteral.ZERO = ExprLiteral.Int(0)
ExprLiteral.ONE = ExprLiteral.Int(1)
ExprLiteral.NULL = ExprVar("nullptr")
ExprLiteral.TRUE = ExprVar("true")
ExprLiteral.FALSE = ExprVar("false")
class ExprPrefixUnop(Node):
def __init__(self, expr, op):
assert not isinstance(expr, tuple)
self.expr = expr
self.op = op
class ExprNot(ExprPrefixUnop):
def __init__(self, expr):
ExprPrefixUnop.__init__(self, expr, "!")
class ExprAddrOf(ExprPrefixUnop):
def __init__(self, expr):
ExprPrefixUnop.__init__(self, expr, "&")
class ExprDeref(ExprPrefixUnop):
def __init__(self, expr):
ExprPrefixUnop.__init__(self, expr, "*")
class ExprCast(Node):
def __init__(self, expr, type, static=False, const=False):
# Exactly one of these should be set
assert static ^ const
Node.__init__(self)
self.expr = expr
self.type = type
self.static = static
self.const = const
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):
assert obj and op and field
assert not isinstance(obj, str)
assert isinstance(op, str)
Node.__init__(self)
self.obj = obj
self.op = op
if isinstance(field, str):
self.field = ExprVar(field)
else:
self.field = field
class ExprAssn(Node):
def __init__(self, lhs, rhs, op="="):
Node.__init__(self)
self.lhs = lhs
self.op = op
self.rhs = rhs
class ExprCall(Node):
def __init__(self, func, args=[]):
assert hasattr(func, "accept")
assert isinstance(args, list)
for arg in args:
assert arg and not isinstance(arg, str)
Node.__init__(self)
self.func = func
self.args = args
class ExprMove(ExprCall):
def __init__(self, arg):
ExprCall.__init__(self, ExprVar("std::move"), args=[arg])
class ExprNew(Node):
# XXX taking some poetic license ...
def __init__(self, ctype, args=[], newargs=None):
assert not (ctype.const or ctype.ref or ctype.rvalref)
Node.__init__(self)
self.ctype = ctype
self.args = args
self.newargs = newargs
class ExprDelete(Node):
def __init__(self, obj):
Node.__init__(self)
self.obj = obj
class ExprMemberInit(ExprCall):
def __init__(self, member, args=[]):
ExprCall.__init__(self, member, args)
class ExprLambda(Block):
def __init__(self, captures=[], params=[], ret=None):
Block.__init__(self)
assert isinstance(captures, list)
assert isinstance(params, list)
self.captures = captures
self.params = params
self.ret = ret
# ------------------------------
# statements etc.
class StmtBlock(Block):
def __init__(self, stmts=[]):
Block.__init__(self)
self.addstmts(stmts)
class StmtDecl(Node):
def __init__(self, decl, init=None, initargs=None):
assert not (init and initargs)
assert not isinstance(init, str) # easy to confuse with Decl
assert not isinstance(init, list)
assert not isinstance(decl, tuple)
Node.__init__(self)
self.decl = decl
self.init = init
self.initargs = initargs
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):
Node.__init__(self)
self.name = name
class DefaultLabel(Node):
def __init__(self):
Node.__init__(self)
class StmtIf(Node):
def __init__(self, cond):
Node.__init__(self)
self.cond = cond
self.ifb = Block()
self.elseb = None
def addifstmt(self, stmt):
self.ifb.addstmt(stmt)
def addifstmts(self, stmts):
self.ifb.addstmts(stmts)
def addelsestmt(self, stmt):
if self.elseb is None:
self.elseb = Block()
self.elseb.addstmt(stmt)
def addelsestmts(self, stmts):
if self.elseb is None:
self.elseb = Block()
self.elseb.addstmts(stmts)
class StmtFor(Block):
def __init__(self, init=None, cond=None, update=None):
Block.__init__(self)
self.init = init
self.cond = cond
self.update = update
class StmtRangedFor(Block):
def __init__(self, var, iteree):
assert isinstance(var, ExprVar)
assert iteree
Block.__init__(self)
self.var = var
self.iteree = iteree
class StmtSwitch(Block):
def __init__(self, expr):
Block.__init__(self)
self.expr = expr
self.nr_cases = 0
def addcase(self, case, block):
"""NOTE: |case| is not checked for uniqueness"""
assert not isinstance(case, str)
assert (
isinstance(block, StmtBreak)
or isinstance(block, StmtReturn)
or isinstance(block, StmtSwitch)
or isinstance(block, GroupNode)
or isinstance(block, VerbatimNode)
or (
hasattr(block, "stmts")
and (
isinstance(block.stmts[-1], StmtBreak)
or isinstance(block.stmts[-1], StmtReturn)
or isinstance(block.stmts[-1], GroupNode)
or isinstance(block.stmts[-1], VerbatimNode)
)
)
)
self.addstmt(case)
self.addstmt(block)
self.nr_cases += 1
class StmtBreak(Node):
def __init__(self):
Node.__init__(self)
class StmtExpr(Node):
def __init__(self, expr):
assert expr is not None
Node.__init__(self)
self.expr = expr
class StmtReturn(Node):
def __init__(self, expr=None):
Node.__init__(self)
self.expr = expr
StmtReturn.TRUE = StmtReturn(ExprLiteral.TRUE)
StmtReturn.FALSE = StmtReturn(ExprLiteral.FALSE)