# 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 sys
from ipdl.cgen
import CodePrinter
from ipdl.cxx.ast
import MethodSpec, TypeArray, Visitor, DestructorDecl
class CxxCodeGen(CodePrinter, Visitor):
def __init__(self, outf=sys.stdout, indentCols=4):
CodePrinter.__init__(self, outf, indentCols)
def cgen(self, cxxfile):
cxxfile.accept(self)
def visitWhitespace(self, ws):
if ws.indent:
self.printdent(
"")
self.write(ws.ws)
def visitVerbatimNode(self, verb):
if verb.indent:
self.printdent(
"")
self.write(verb.text)
def visitGroupNode(self, group):
offsetCols = self.indentCols * group.offset
self.col += offsetCols
for node
in group.nodes:
node.accept(self)
self.col -= offsetCols
def visitCppDirective(self, cd):
if cd.rest:
self.println(
"#%s %s" % (cd.directive, cd.rest))
else:
self.println(
"#%s" % (cd.directive))
def visitNamespace(self, ns):
self.println(
"namespace " + ns.name +
" {")
self.visitBlock(ns)
self.println(
"} // namespace " + ns.name)
def visitType(self, t):
if t.const:
self.write(
"const ")
self.write(t.name)
if t.T
is not None:
self.write(
"<")
if type(t.T)
is list:
t.T[0].accept(self)
for tt
in t.T[1:]:
self.write(
", ")
tt.accept(self)
else:
t.T.accept(self)
self.write(
">")
if t.inner
is not None:
self.write(
"::")
t.inner.accept(self)
ts =
""
if t.ptr:
ts +=
"*"
elif t.ptrptr:
ts +=
"**"
elif t.ptrconstptr:
ts +=
"* const*"
if t.ref:
ts +=
"&"
elif t.rvalref:
ts +=
"&&"
elif t.rightconst:
ts +=
" const"
self.write(ts)
def visitTypeEnum(self, te):
self.write(
"enum")
if te.name:
self.write(
" " + te.name)
self.println(
" {")
self.indent()
nids = len(te.idnums)
for i, (id, num)
in enumerate(te.idnums):
self.printdent(id)
if num:
self.write(
" = " + str(num))
if i != (nids - 1):
self.write(
",")
self.println()
self.dedent()
self.printdent(
"}")
def visitTypeUnion(self, u):
self.write(
"union")
if u.name:
self.write(
" " + u.name)
self.println(
" {")
self.indent()
for decl
in u.components:
self.printdent()
decl.accept(self)
self.println(
";")
self.dedent()
self.printdent(
"}")
def visitTypeFunction(self, fn):
self.write(
"std::function<")
fn.ret.accept(self)
self.write(
"(")
self.writeDeclList(fn.params)
self.write(
")>")
def visitTypedef(self, td):
if td.templateargs:
formals =
", ".join([
"class " + T
for T
in td.templateargs])
args =
", ".join(td.templateargs)
self.printdent(
"template<" + formals +
"> using " + td.totypename +
" = ")
td.fromtype.accept(self)
self.println(
"<" + args +
">;")
else:
self.printdent(
"typedef ")
td.fromtype.accept(self)
self.println(
" " + td.totypename +
";")
def visitUsing(self, us):
self.printdent(
"using ")
us.type.accept(self)
self.println(
";")
def visitForwardDecl(self, fd):
if fd.cls:
self.printdent(
"class ")
elif fd.struct:
self.printdent(
"struct ")
self.write(str(fd.pqname))
self.println(
";")
def visitDecl(self, d):
# C-syntax arrays make code generation much more annoying
if isinstance(d.type, TypeArray):
d.type.basetype.accept(self)
else:
d.type.accept(self)
if d.name:
self.write(
" " + d.name)
if isinstance(d.type, TypeArray):
self.write(
"[")
d.type.nmemb.accept(self)
self.write(
"]")
def visitParam(self, p):
self.visitDecl(p)
if p.default
is not None:
self.write(
" = ")
p.default.accept(self)
def visitClass(self, c):
if c.specializes
is not None:
self.printdentln(
"template<>")
if c.struct:
self.printdent(
"struct")
else:
self.printdent(
"class")
self.write(
" " + c.name)
if c.final:
self.write(
" final")
if c.specializes
is not None:
self.write(
" <")
c.specializes.accept(self)
self.write(
">")
ninh = len(c.inherits)
if 0 < ninh:
self.println(
" :")
self.indent()
for i, inherit
in enumerate(c.inherits):
self.printdent()
inherit.accept(self)
if i != (ninh - 1):
self.println(
",")
self.dedent()
self.println()
self.printdentln(
"{")
self.indent()
self.visitBlock(c)
self.dedent()
self.printdentln(
"};")
def visitInherit(self, inh):
self.write(inh.viz +
" ")
inh.type.accept(self)
def visitFriendClassDecl(self, fcd):
self.printdentln(
"friend class " + fcd.friend +
";")
def visitMethodDecl(self, md):
if md.T:
self.write(
"template<")
self.write(
"typename ")
md.T.accept(self)
self.println(
">")
self.printdent()
if md.warn_unused:
self.write(
"[[nodiscard]] ")
if md.methodspec == MethodSpec.STATIC:
self.write(
"static ")
elif md.methodspec == MethodSpec.VIRTUAL
or md.methodspec == MethodSpec.PURE:
self.write(
"virtual ")
if md.ret:
if md.only_for_definition:
self.write(
"auto ")
else:
md.ret.accept(self)
self.println()
self.printdent()
if md.cls
is not None:
assert md.only_for_definition
self.write(md.cls.name)
if md.cls.specializes
is not None:
self.write(
"<")
md.cls.specializes.accept(self)
self.write(
">")
self.write(
"::")
if md.typeop
is not None:
self.write(
"operator ")
md.typeop.accept(self)
else:
if isinstance(md, DestructorDecl):
self.write(
"~")
self.write(md.name)
self.write(
"(")
self.writeDeclList(md.params)
self.write(
")")
if md.const:
self.write(
" const")
if md.ret
and md.only_for_definition:
self.write(
" -> ")
md.ret.accept(self)
if md.methodspec == MethodSpec.OVERRIDE:
self.write(
" override")
elif md.methodspec == MethodSpec.FINAL:
self.write(
" final")
elif md.methodspec == MethodSpec.PURE:
self.write(
" = 0")
def visitMethodDefn(self, md):
# Method specifiers are for decls, not defns.
assert md.decl.methodspec == MethodSpec.
NONE
self.printdent()
md.decl.accept(self)
self.println()
self.printdentln(
"{")
self.indent()
self.visitBlock(md)
self.dedent()
self.printdentln(
"}")
def visitConstructorDecl(self, cd):
if cd.explicit:
self.write(
"explicit ")
else:
self.write(
"MOZ_IMPLICIT ")
self.visitMethodDecl(cd)
def visitConstructorDefn(self, cd):
self.printdent()
cd.decl.accept(self)
if len(cd.memberinits):
self.println(
" :")
self.indent()
ninits = len(cd.memberinits)
for i, init
in enumerate(cd.memberinits):
self.printdent()
init.accept(self)
if i != (ninits - 1):
self.println(
",")
self.dedent()
self.println()
self.printdentln(
"{")
self.indent()
self.visitBlock(cd)
self.dedent()
self.printdentln(
"}")
def visitDestructorDecl(self, dd):
self.visitMethodDecl(dd)
def visitDestructorDefn(self, dd):
self.printdent()
dd.decl.accept(self)
self.println()
self.printdentln(
"{")
self.indent()
self.visitBlock(dd)
self.dedent()
self.printdentln(
"}")
def visitExprLiteral(self, el):
self.write(str(el))
def visitExprVar(self, ev):
self.write(ev.name)
def visitExprPrefixUnop(self, e):
self.write(
"(")
self.write(e.op)
self.write(
"(")
e.expr.accept(self)
self.write(
")")
self.write(
")")
def visitExprCast(self, c):
if c.static:
pfx, sfx =
"static_cast<",
">"
else:
assert c.const
pfx, sfx =
"const_cast<",
">"
self.write(pfx)
c.type.accept(self)
self.write(sfx +
"(")
c.expr.accept(self)
self.write(
")")
def visitExprBinary(self, e):
self.write(
"(")
e.left.accept(self)
self.write(
") " + e.op +
" (")
e.right.accept(self)
self.write(
")")
def visitExprConditional(self, c):
self.write(
"(")
c.cond.accept(self)
self.write(
" ? ")
c.ife.accept(self)
self.write(
" : ")
c.elsee.accept(self)
self.write(
")")
def visitExprSelect(self, es):
self.write(
"(")
es.obj.accept(self)
self.write(
")")
self.write(es.op)
es.field.accept(self)
def visitExprAssn(self, ea):
ea.lhs.accept(self)
self.write(
" " + ea.op +
" ")
ea.rhs.accept(self)
def visitExprCall(self, ec):
ec.func.accept(self)
self.write(
"(")
self.writeExprList(ec.args)
self.write(
")")
def visitExprNew(self, en):
self.write(
"new ")
if en.newargs
is not None:
self.write(
"(")
self.writeExprList(en.newargs)
self.write(
") ")
en.ctype.accept(self)
if en.args
is not None:
self.write(
"(")
self.writeExprList(en.args)
self.write(
")")
def visitExprDelete(self, ed):
self.write(
"delete ")
ed.obj.accept(self)
def visitExprLambda(self, l):
self.write(
"[")
ncaptures = len(l.captures)
for i, c
in enumerate(l.captures):
c.accept(self)
if i != (ncaptures - 1):
self.write(
", ")
self.write(
"](")
self.writeDeclList(l.params)
self.write(
")")
if l.ret:
self.write(
" -> ")
l.ret.accept(self)
self.println(
" {")
self.indent()
self.visitBlock(l)
self.dedent()
self.printdent(
"}")
def visitStmtBlock(self, b):
self.printdentln(
"{")
self.indent()
self.visitBlock(b)
self.dedent()
self.printdentln(
"}")
def visitLabel(self, label):
self.dedent()
# better not be at global scope ...
self.printdentln(label.name +
":")
self.indent()
def visitCaseLabel(self, cl):
self.dedent()
self.printdentln(
"case " + cl.name +
":")
self.indent()
def visitDefaultLabel(self, dl):
self.dedent()
self.printdentln(
"default:")
self.indent()
def visitStmtIf(self, si):
self.printdent(
"if (")
si.cond.accept(self)
self.println(
") {")
self.indent()
si.ifb.accept(self)
self.dedent()
self.printdentln(
"}")
if si.elseb
is not None:
self.printdentln(
"else {")
self.indent()
si.elseb.accept(self)
self.dedent()
self.printdentln(
"}")
def visitStmtFor(self, sf):
self.printdent(
"for (")
if sf.init
is not None:
sf.init.accept(self)
self.write(
"; ")
if sf.cond
is not None:
sf.cond.accept(self)
self.write(
"; ")
if sf.update
is not None:
sf.update.accept(self)
self.println(
") {")
self.indent()
self.visitBlock(sf)
self.dedent()
self.printdentln(
"}")
def visitStmtRangedFor(self, rf):
self.printdent(
"for (auto& ")
rf.var.accept(self)
self.write(
" : ")
rf.iteree.accept(self)
self.println(
") {")
self.indent()
self.visitBlock(rf)
self.dedent()
self.printdentln(
"}")
def visitStmtSwitch(self, sw):
self.printdent(
"switch (")
sw.expr.accept(self)
self.println(
") {")
self.indent()
self.visitBlock(sw)
self.dedent()
self.printdentln(
"}")
def visitStmtBreak(self, sb):
self.printdentln(
"break;")
def visitStmtDecl(self, sd):
self.printdent()
sd.decl.accept(self)
if sd.initargs
is not None:
self.write(
"{")
self.writeDeclList(sd.initargs)
self.write(
"}")
if sd.init
is not None:
self.write(
" = ")
sd.init.accept(self)
self.println(
";")
def visitStmtExpr(self, se):
self.printdent()
se.expr.accept(self)
self.println(
";")
def visitStmtReturn(self, sr):
self.printdent(
"return")
if sr.expr:
self.write(
" ")
sr.expr.accept(self)
self.println(
";")
def writeDeclList(self, decls):
# FIXME/cjones: try to do nice formatting of these guys
ndecls = len(decls)
if 0 == ndecls:
return
elif 1 == ndecls:
decls[0].accept(self)
return
self.indent()
self.indent()
for i, decl
in enumerate(decls):
self.println()
self.printdent()
decl.accept(self)
if i != (ndecls - 1):
self.write(
",")
self.dedent()
self.dedent()
def writeExprList(self, exprs):
# FIXME/cjones: try to do nice formatting and share code with
# writeDeclList()
nexprs = len(exprs)
for i, expr
in enumerate(exprs):
expr.accept(self)
if i != (nexprs - 1):
self.write(
", ")