summaryrefslogtreecommitdiffstats
path: root/ipc/ipdl/ipdl/cxx/ast.py
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/ipdl/ipdl/cxx/ast.py')
-rw-r--r--ipc/ipdl/ipdl/cxx/ast.py1033
1 files changed, 1033 insertions, 0 deletions
diff --git a/ipc/ipdl/ipdl/cxx/ast.py b/ipc/ipdl/ipdl/cxx/ast.py
new file mode 100644
index 0000000000..a4aba98571
--- /dev/null
+++ b/ipc/ipdl/ipdl/cxx/ast.py
@@ -0,0 +1,1033 @@
+# 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,
+ rightconst=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&)."""
+ # XXX(nika): This type is complex enough at this point, perhaps we
+ # should get "fancy with recursive types" to simplify it.
+ 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 isinstance(rightconst, 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.rightconst = rightconst
+ 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,
+ rightconst=self.rightconst,
+ 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 FINAL")
+
+
+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)