1# This Source Code Form is subject to the terms of the Mozilla Public
2# License, v. 2.0. If a copy of the MPL was not distributed with this
3# file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5import copy
6import functools
7
8from ipdl.util import hash_str
9
10
11class Visitor:
12    def defaultVisit(self, node):
13        raise Exception(
14            "INTERNAL ERROR: no visitor for node type `%s'" % (node.__class__.__name__)
15        )
16
17    def visitWhitespace(self, ws):
18        pass
19
20    def visitVerbatimNode(self, verb):
21        pass
22
23    def visitGroupNode(self, group):
24        for node in group.nodes:
25            node.accept(self)
26
27    def visitFile(self, f):
28        for thing in f.stuff:
29            thing.accept(self)
30
31    def visitCppDirective(self, ppd):
32        pass
33
34    def visitBlock(self, block):
35        for stmt in block.stmts:
36            stmt.accept(self)
37
38    def visitNamespace(self, ns):
39        self.visitBlock(ns)
40
41    def visitType(self, type):
42        pass
43
44    def visitTypeArray(self, ta):
45        ta.basetype.accept(self)
46        ta.nmemb.accept(self)
47
48    def visitTypeEnum(self, enum):
49        pass
50
51    def visitTypeFunction(self, fn):
52        pass
53
54    def visitTypeUnion(self, union):
55        for t, name in union.components:
56            t.accept(self)
57
58    def visitTypedef(self, tdef):
59        tdef.fromtype.accept(self)
60
61    def visitUsing(self, us):
62        us.type.accept(self)
63
64    def visitForwardDecl(self, fd):
65        pass
66
67    def visitDecl(self, decl):
68        decl.type.accept(self)
69
70    def visitParam(self, param):
71        self.visitDecl(param)
72        if param.default is not None:
73            param.default.accept(self)
74
75    def visitClass(self, cls):
76        for inherit in cls.inherits:
77            inherit.accept(self)
78        self.visitBlock(cls)
79
80    def visitInherit(self, inh):
81        pass
82
83    def visitFriendClassDecl(self, fcd):
84        pass
85
86    def visitMethodDecl(self, meth):
87        for param in meth.params:
88            param.accept(self)
89        if meth.ret is not None:
90            meth.ret.accept(self)
91        if meth.typeop is not None:
92            meth.typeop.accept(self)
93        if meth.T is not None:
94            meth.T.accept(self)
95
96    def visitMethodDefn(self, meth):
97        meth.decl.accept(self)
98        self.visitBlock(meth)
99
100    def visitFunctionDecl(self, fun):
101        self.visitMethodDecl(fun)
102
103    def visitFunctionDefn(self, fd):
104        self.visitMethodDefn(fd)
105
106    def visitConstructorDecl(self, ctor):
107        self.visitMethodDecl(ctor)
108
109    def visitConstructorDefn(self, cd):
110        cd.decl.accept(self)
111        for init in cd.memberinits:
112            init.accept(self)
113        self.visitBlock(cd)
114
115    def visitDestructorDecl(self, dtor):
116        self.visitMethodDecl(dtor)
117
118    def visitDestructorDefn(self, dd):
119        dd.decl.accept(self)
120        self.visitBlock(dd)
121
122    def visitExprLiteral(self, l):
123        pass
124
125    def visitExprVar(self, v):
126        pass
127
128    def visitExprPrefixUnop(self, e):
129        e.expr.accept(self)
130
131    def visitExprBinary(self, e):
132        e.left.accept(self)
133        e.right.accept(self)
134
135    def visitExprConditional(self, c):
136        c.cond.accept(self)
137        c.ife.accept(self)
138        c.elsee.accept(self)
139
140    def visitExprAddrOf(self, eao):
141        self.visitExprPrefixUnop(eao)
142
143    def visitExprDeref(self, ed):
144        self.visitExprPrefixUnop(ed)
145
146    def visitExprNot(self, en):
147        self.visitExprPrefixUnop(en)
148
149    def visitExprCast(self, ec):
150        ec.expr.accept(self)
151
152    def visitExprSelect(self, es):
153        es.obj.accept(self)
154
155    def visitExprAssn(self, ea):
156        ea.lhs.accept(self)
157        ea.rhs.accept(self)
158
159    def visitExprCall(self, ec):
160        ec.func.accept(self)
161        for arg in ec.args:
162            arg.accept(self)
163
164    def visitExprNew(self, en):
165        en.ctype.accept(self)
166        if en.newargs is not None:
167            for arg in en.newargs:
168                arg.accept(self)
169        if en.args is not None:
170            for arg in en.args:
171                arg.accept(self)
172
173    def visitExprDelete(self, ed):
174        ed.obj.accept(self)
175
176    def visitExprMemberInit(self, minit):
177        self.visitExprCall(minit)
178
179    def visitExprLambda(self, l):
180        self.visitBlock(l)
181
182    def visitStmtBlock(self, sb):
183        self.visitBlock(sb)
184
185    def visitStmtDecl(self, sd):
186        sd.decl.accept(self)
187        if sd.init is not None:
188            sd.init.accept(self)
189
190    def visitLabel(self, label):
191        pass
192
193    def visitCaseLabel(self, case):
194        pass
195
196    def visitDefaultLabel(self, dl):
197        pass
198
199    def visitStmtIf(self, si):
200        si.cond.accept(self)
201        si.ifb.accept(self)
202        if si.elseb is not None:
203            si.elseb.accept(self)
204
205    def visitStmtFor(self, sf):
206        if sf.init is not None:
207            sf.init.accept(self)
208        if sf.cond is not None:
209            sf.cond.accept(self)
210        if sf.update is not None:
211            sf.update.accept(self)
212
213    def visitStmtSwitch(self, ss):
214        ss.expr.accept(self)
215        self.visitBlock(ss)
216
217    def visitStmtBreak(self, sb):
218        pass
219
220    def visitStmtExpr(self, se):
221        se.expr.accept(self)
222
223    def visitStmtReturn(self, sr):
224        if sr.expr is not None:
225            sr.expr.accept(self)
226
227
228# ------------------------------
229
230
231class Node:
232    def __init__(self):
233        pass
234
235    def accept(self, visitor):
236        visit = getattr(visitor, "visit" + self.__class__.__name__, None)
237        if visit is None:
238            return getattr(visitor, "defaultVisit")(self)
239        return visit(self)
240
241
242class Whitespace(Node):
243    # yes, this is silly.  but we need to stick comments in the
244    # generated code without resorting to more serious hacks
245    def __init__(self, ws, indent=False):
246        Node.__init__(self)
247        self.ws = ws
248        self.indent = indent
249
250
251Whitespace.NL = Whitespace("\n")
252
253
254class VerbatimNode(Node):
255    # A block of text to be written verbatim to the output file.
256    #
257    # NOTE: This node is usually created by `code`. See `code.py` for details.
258    # FIXME: Merge Whitespace and VerbatimNode? They're identical.
259    def __init__(self, text, indent=0):
260        Node.__init__(self)
261        self.text = text
262        self.indent = indent
263
264
265class GroupNode(Node):
266    # A group of nodes to be treated as a single node. These nodes have an
267    # optional indentation level which should be applied when generating them.
268    #
269    # NOTE: This node is usually created by `code`. See `code.py` for details.
270    def __init__(self, nodes, offset=0):
271        Node.__init__(self)
272        self.nodes = nodes
273        self.offset = offset
274
275
276class File(Node):
277    def __init__(self, filename):
278        Node.__init__(self)
279        self.name = filename
280        # array of stuff in the file --- stmts and preprocessor thingies
281        self.stuff = []
282
283    def addthing(self, thing):
284        assert thing is not None
285        assert not isinstance(thing, list)
286        self.stuff.append(thing)
287
288    def addthings(self, things):
289        for t in things:
290            self.addthing(t)
291
292    # "look like" a Block so code doesn't have to care whether they're
293    # in global scope or not
294    def addstmt(self, stmt):
295        assert stmt is not None
296        assert not isinstance(stmt, list)
297        self.stuff.append(stmt)
298
299    def addstmts(self, stmts):
300        for s in stmts:
301            self.addstmt(s)
302
303    def addcode(self, tmpl, **context):
304        from ipdl.cxx.code import StmtCode
305
306        self.addstmt(StmtCode(tmpl, **context))
307
308
309class CppDirective(Node):
310    """represents |#[directive] [rest]|, where |rest| is any string"""
311
312    def __init__(self, directive, rest=None):
313        Node.__init__(self)
314        self.directive = directive
315        self.rest = rest
316
317
318class Block(Node):
319    def __init__(self):
320        Node.__init__(self)
321        self.stmts = []
322
323    def addstmt(self, stmt):
324        assert stmt is not None
325        assert not isinstance(stmt, tuple)
326        self.stmts.append(stmt)
327
328    def addstmts(self, stmts):
329        for s in stmts:
330            self.addstmt(s)
331
332    def addcode(self, tmpl, **context):
333        from ipdl.cxx.code import StmtCode
334
335        self.addstmt(StmtCode(tmpl, **context))
336
337
338# ------------------------------
339# type and decl thingies
340
341
342class Namespace(Block):
343    def __init__(self, name):
344        assert isinstance(name, str)
345
346        Block.__init__(self)
347        self.name = name
348
349
350class Type(Node):
351    def __init__(
352        self,
353        name,
354        const=False,
355        ptr=False,
356        ptrptr=False,
357        ptrconstptr=False,
358        ref=False,
359        rvalref=False,
360        hasimplicitcopyctor=True,
361        T=None,
362        inner=None,
363    ):
364        """
365        Represents the type |name<T>::inner| with the ptr and const
366        modifiers as specified.
367
368        To avoid getting fancy with recursive types, we limit the kinds
369        of pointer types that can be be constructed.
370
371          ptr            => T*
372          ptrptr         => T**
373          ptrconstptr    => T* const*
374          ref            => T&
375          rvalref        => T&&
376
377        Any type, naked or pointer, can be const (const T) or ref (T&)."""
378        assert isinstance(name, str)
379        assert isinstance(const, bool)
380        assert isinstance(ptr, bool)
381        assert isinstance(ptrptr, bool)
382        assert isinstance(ptrconstptr, bool)
383        assert isinstance(ref, bool)
384        assert isinstance(rvalref, bool)
385        assert not isinstance(T, str)
386
387        Node.__init__(self)
388        self.name = name
389        self.const = const
390        self.ptr = ptr
391        self.ptrptr = ptrptr
392        self.ptrconstptr = ptrconstptr
393        self.ref = ref
394        self.rvalref = rvalref
395        self.hasimplicitcopyctor = hasimplicitcopyctor
396        self.T = T
397        self.inner = inner
398        # XXX could get serious here with recursive types, but shouldn't
399        # need that for this codegen
400
401    def __deepcopy__(self, memo):
402        return Type(
403            self.name,
404            const=self.const,
405            ptr=self.ptr,
406            ptrptr=self.ptrptr,
407            ptrconstptr=self.ptrconstptr,
408            ref=self.ref,
409            rvalref=self.rvalref,
410            T=copy.deepcopy(self.T, memo),
411            inner=copy.deepcopy(self.inner, memo),
412        )
413
414
415Type.BOOL = Type("bool")
416Type.INT = Type("int")
417Type.INT32 = Type("int32_t")
418Type.INTPTR = Type("intptr_t")
419Type.NSRESULT = Type("nsresult")
420Type.UINT32 = Type("uint32_t")
421Type.UINT32PTR = Type("uint32_t", ptr=True)
422Type.SIZE = Type("size_t")
423Type.VOID = Type("void")
424Type.VOIDPTR = Type("void", ptr=True)
425Type.AUTO = Type("auto")
426Type.AUTORVAL = Type("auto", rvalref=True)
427
428
429class TypeArray(Node):
430    def __init__(self, basetype, nmemb):
431        """the type |basetype DECLNAME[nmemb]|.  |nmemb| is an Expr"""
432        self.basetype = basetype
433        self.nmemb = nmemb
434
435
436class TypeEnum(Node):
437    def __init__(self, name=None):
438        """name can be None"""
439        Node.__init__(self)
440        self.name = name
441        self.idnums = []  # pairs of ('Foo', [num]) or ('Foo', None)
442
443    def addId(self, id, num=None):
444        self.idnums.append((id, num))
445
446
447class TypeUnion(Node):
448    def __init__(self, name=None):
449        Node.__init__(self)
450        self.name = name
451        self.components = []  # [ Decl ]
452
453    def addComponent(self, type, name):
454        self.components.append(Decl(type, name))
455
456
457class TypeFunction(Node):
458    def __init__(self, params=[], ret=Type("void")):
459        """Anonymous function type std::function<>"""
460        self.params = params
461        self.ret = ret
462
463
464@functools.total_ordering
465class Typedef(Node):
466    def __init__(self, fromtype, totypename, templateargs=[]):
467        assert isinstance(totypename, str)
468
469        Node.__init__(self)
470        self.fromtype = fromtype
471        self.totypename = totypename
472        self.templateargs = templateargs
473
474    def __lt__(self, other):
475        return self.totypename < other.totypename
476
477    def __eq__(self, other):
478        return self.__class__ == other.__class__ and self.totypename == other.totypename
479
480    def __hash__(self):
481        return hash_str(self.totypename)
482
483
484class Using(Node):
485    def __init__(self, type):
486        Node.__init__(self)
487        self.type = type
488
489
490class ForwardDecl(Node):
491    def __init__(self, pqname, cls=False, struct=False):
492        # Exactly one of cls and struct must be set
493        assert cls ^ struct
494
495        self.pqname = pqname
496        self.cls = cls
497        self.struct = struct
498
499
500class Decl(Node):
501    """represents |Foo bar|, e.g. in a function signature"""
502
503    def __init__(self, type, name):
504        assert type is not None
505        assert not isinstance(type, str)
506        assert isinstance(name, str)
507
508        Node.__init__(self)
509        self.type = type
510        self.name = name
511
512    def __deepcopy__(self, memo):
513        return Decl(copy.deepcopy(self.type, memo), self.name)
514
515
516class Param(Decl):
517    def __init__(self, type, name, default=None):
518        Decl.__init__(self, type, name)
519        self.default = default
520
521    def __deepcopy__(self, memo):
522        return Param(
523            copy.deepcopy(self.type, memo), self.name, copy.deepcopy(self.default, memo)
524        )
525
526
527# ------------------------------
528# class stuff
529
530
531class Class(Block):
532    def __init__(
533        self,
534        name,
535        inherits=[],
536        interface=False,
537        abstract=False,
538        final=False,
539        specializes=None,
540        struct=False,
541    ):
542        assert not (interface and abstract)
543        assert not (abstract and final)
544        assert not (interface and final)
545        assert not (inherits and specializes)
546
547        Block.__init__(self)
548        self.name = name
549        self.inherits = inherits  # [ Type ]
550        self.interface = interface  # bool
551        self.abstract = abstract  # bool
552        self.final = final  # bool
553        self.specializes = specializes  # Type or None
554        self.struct = struct  # bool
555
556
557class Inherit(Node):
558    def __init__(self, type, viz="public"):
559        assert isinstance(viz, str)
560        Node.__init__(self)
561        self.type = type
562        self.viz = viz
563
564
565class FriendClassDecl(Node):
566    def __init__(self, friend):
567        Node.__init__(self)
568        self.friend = friend
569
570
571# Python2 polyfill for Python3's Enum() functional API.
572
573
574def make_enum(name, members_str):
575    members_list = members_str.split()
576    members_dict = {}
577    for member_value, member in enumerate(members_list, start=1):
578        members_dict[member] = member_value
579    return type(name, (), members_dict)
580
581
582MethodSpec = make_enum("MethodSpec", "NONE VIRTUAL PURE OVERRIDE STATIC")
583
584
585class MethodDecl(Node):
586    def __init__(
587        self,
588        name,
589        params=[],
590        ret=Type("void"),
591        methodspec=MethodSpec.NONE,
592        const=False,
593        warn_unused=False,
594        force_inline=False,
595        typeop=None,
596        T=None,
597        cls=None,
598    ):
599        assert not (name and typeop)
600        assert name is None or isinstance(name, str)
601        assert not isinstance(ret, list)
602        for decl in params:
603            assert not isinstance(decl, str)
604        assert not isinstance(T, int)
605        assert isinstance(const, bool)
606        assert isinstance(warn_unused, bool)
607        assert isinstance(force_inline, bool)
608
609        if typeop is not None:
610            assert methodspec == MethodSpec.NONE
611            ret = None
612
613        Node.__init__(self)
614        self.name = name
615        self.params = params  # [ Param ]
616        self.ret = ret  # Type or None
617        self.methodspec = methodspec  # enum
618        self.const = const  # bool
619        self.warn_unused = warn_unused  # bool
620        self.force_inline = force_inline or bool(T)  # bool
621        self.typeop = typeop  # Type or None
622        self.T = T  # Type or None
623        self.cls = cls  # Class or None
624        self.only_for_definition = False
625
626    def __deepcopy__(self, memo):
627        return MethodDecl(
628            self.name,
629            params=copy.deepcopy(self.params, memo),
630            ret=copy.deepcopy(self.ret, memo),
631            methodspec=self.methodspec,
632            const=self.const,
633            warn_unused=self.warn_unused,
634            force_inline=self.force_inline,
635            typeop=copy.deepcopy(self.typeop, memo),
636            T=copy.deepcopy(self.T, memo),
637        )
638
639
640class MethodDefn(Block):
641    def __init__(self, decl):
642        Block.__init__(self)
643        self.decl = decl
644
645
646class FunctionDecl(MethodDecl):
647    def __init__(
648        self,
649        name,
650        params=[],
651        ret=Type("void"),
652        methodspec=MethodSpec.NONE,
653        warn_unused=False,
654        force_inline=False,
655        T=None,
656    ):
657        assert methodspec == MethodSpec.NONE or methodspec == MethodSpec.STATIC
658        MethodDecl.__init__(
659            self,
660            name,
661            params=params,
662            ret=ret,
663            methodspec=methodspec,
664            warn_unused=warn_unused,
665            force_inline=force_inline,
666            T=T,
667        )
668
669
670class FunctionDefn(MethodDefn):
671    def __init__(self, decl):
672        MethodDefn.__init__(self, decl)
673
674
675class ConstructorDecl(MethodDecl):
676    def __init__(self, name, params=[], explicit=False, force_inline=False):
677        MethodDecl.__init__(
678            self, name, params=params, ret=None, force_inline=force_inline
679        )
680        self.explicit = explicit
681
682    def __deepcopy__(self, memo):
683        return ConstructorDecl(
684            self.name, copy.deepcopy(self.params, memo), self.explicit
685        )
686
687
688class ConstructorDefn(MethodDefn):
689    def __init__(self, decl, memberinits=[]):
690        MethodDefn.__init__(self, decl)
691        self.memberinits = memberinits
692
693
694class DestructorDecl(MethodDecl):
695    def __init__(self, name, methodspec=MethodSpec.NONE, force_inline=False):
696        # C++ allows pure or override destructors, but ipdl cgen does not.
697        assert methodspec == MethodSpec.NONE or methodspec == MethodSpec.VIRTUAL
698        MethodDecl.__init__(
699            self,
700            name,
701            params=[],
702            ret=None,
703            methodspec=methodspec,
704            force_inline=force_inline,
705        )
706
707    def __deepcopy__(self, memo):
708        return DestructorDecl(
709            self.name, methodspec=self.methodspec, force_inline=self.force_inline
710        )
711
712
713class DestructorDefn(MethodDefn):
714    def __init__(self, decl):
715        MethodDefn.__init__(self, decl)
716
717
718# ------------------------------
719# expressions
720
721
722class ExprVar(Node):
723    def __init__(self, name):
724        assert isinstance(name, str)
725
726        Node.__init__(self)
727        self.name = name
728
729
730ExprVar.THIS = ExprVar("this")
731
732
733class ExprLiteral(Node):
734    def __init__(self, value, type):
735        """|type| is a Python format specifier; 'd' for example"""
736        Node.__init__(self)
737        self.value = value
738        self.type = type
739
740    @staticmethod
741    def Int(i):
742        return ExprLiteral(i, "d")
743
744    @staticmethod
745    def String(s):
746        return ExprLiteral('"' + s + '"', "s")
747
748    def __str__(self):
749        return ("%" + self.type) % (self.value)
750
751
752ExprLiteral.ZERO = ExprLiteral.Int(0)
753ExprLiteral.ONE = ExprLiteral.Int(1)
754ExprLiteral.NULL = ExprVar("nullptr")
755ExprLiteral.TRUE = ExprVar("true")
756ExprLiteral.FALSE = ExprVar("false")
757
758
759class ExprPrefixUnop(Node):
760    def __init__(self, expr, op):
761        assert not isinstance(expr, tuple)
762        self.expr = expr
763        self.op = op
764
765
766class ExprNot(ExprPrefixUnop):
767    def __init__(self, expr):
768        ExprPrefixUnop.__init__(self, expr, "!")
769
770
771class ExprAddrOf(ExprPrefixUnop):
772    def __init__(self, expr):
773        ExprPrefixUnop.__init__(self, expr, "&")
774
775
776class ExprDeref(ExprPrefixUnop):
777    def __init__(self, expr):
778        ExprPrefixUnop.__init__(self, expr, "*")
779
780
781class ExprCast(Node):
782    def __init__(self, expr, type, static=False, const=False):
783        # Exactly one of these should be set
784        assert static ^ const
785
786        Node.__init__(self)
787        self.expr = expr
788        self.type = type
789        self.static = static
790        self.const = const
791
792
793class ExprBinary(Node):
794    def __init__(self, left, op, right):
795        Node.__init__(self)
796        self.left = left
797        self.op = op
798        self.right = right
799
800
801class ExprConditional(Node):
802    def __init__(self, cond, ife, elsee):
803        Node.__init__(self)
804        self.cond = cond
805        self.ife = ife
806        self.elsee = elsee
807
808
809class ExprSelect(Node):
810    def __init__(self, obj, op, field):
811        assert obj and op and field
812        assert not isinstance(obj, str)
813        assert isinstance(op, str)
814
815        Node.__init__(self)
816        self.obj = obj
817        self.op = op
818        if isinstance(field, str):
819            self.field = ExprVar(field)
820        else:
821            self.field = field
822
823
824class ExprAssn(Node):
825    def __init__(self, lhs, rhs, op="="):
826        Node.__init__(self)
827        self.lhs = lhs
828        self.op = op
829        self.rhs = rhs
830
831
832class ExprCall(Node):
833    def __init__(self, func, args=[]):
834        assert hasattr(func, "accept")
835        assert isinstance(args, list)
836        for arg in args:
837            assert arg and not isinstance(arg, str)
838
839        Node.__init__(self)
840        self.func = func
841        self.args = args
842
843
844class ExprMove(ExprCall):
845    def __init__(self, arg):
846        ExprCall.__init__(self, ExprVar("std::move"), args=[arg])
847
848
849class ExprNew(Node):
850    # XXX taking some poetic license ...
851    def __init__(self, ctype, args=[], newargs=None):
852        assert not (ctype.const or ctype.ref or ctype.rvalref)
853
854        Node.__init__(self)
855        self.ctype = ctype
856        self.args = args
857        self.newargs = newargs
858
859
860class ExprDelete(Node):
861    def __init__(self, obj):
862        Node.__init__(self)
863        self.obj = obj
864
865
866class ExprMemberInit(ExprCall):
867    def __init__(self, member, args=[]):
868        ExprCall.__init__(self, member, args)
869
870
871class ExprLambda(Block):
872    def __init__(self, captures=[], params=[], ret=None):
873        Block.__init__(self)
874        assert isinstance(captures, list)
875        assert isinstance(params, list)
876        self.captures = captures
877        self.params = params
878        self.ret = ret
879
880
881# ------------------------------
882# statements etc.
883
884
885class StmtBlock(Block):
886    def __init__(self, stmts=[]):
887        Block.__init__(self)
888        self.addstmts(stmts)
889
890
891class StmtDecl(Node):
892    def __init__(self, decl, init=None, initargs=None):
893        assert not (init and initargs)
894        assert not isinstance(init, str)  # easy to confuse with Decl
895        assert not isinstance(init, list)
896        assert not isinstance(decl, tuple)
897
898        Node.__init__(self)
899        self.decl = decl
900        self.init = init
901        self.initargs = initargs
902
903
904class Label(Node):
905    def __init__(self, name):
906        Node.__init__(self)
907        self.name = name
908
909
910Label.PUBLIC = Label("public")
911Label.PROTECTED = Label("protected")
912Label.PRIVATE = Label("private")
913
914
915class CaseLabel(Node):
916    def __init__(self, name):
917        Node.__init__(self)
918        self.name = name
919
920
921class DefaultLabel(Node):
922    def __init__(self):
923        Node.__init__(self)
924
925
926class StmtIf(Node):
927    def __init__(self, cond):
928        Node.__init__(self)
929        self.cond = cond
930        self.ifb = Block()
931        self.elseb = None
932
933    def addifstmt(self, stmt):
934        self.ifb.addstmt(stmt)
935
936    def addifstmts(self, stmts):
937        self.ifb.addstmts(stmts)
938
939    def addelsestmt(self, stmt):
940        if self.elseb is None:
941            self.elseb = Block()
942        self.elseb.addstmt(stmt)
943
944    def addelsestmts(self, stmts):
945        if self.elseb is None:
946            self.elseb = Block()
947        self.elseb.addstmts(stmts)
948
949
950class StmtFor(Block):
951    def __init__(self, init=None, cond=None, update=None):
952        Block.__init__(self)
953        self.init = init
954        self.cond = cond
955        self.update = update
956
957
958class StmtRangedFor(Block):
959    def __init__(self, var, iteree):
960        assert isinstance(var, ExprVar)
961        assert iteree
962
963        Block.__init__(self)
964        self.var = var
965        self.iteree = iteree
966
967
968class StmtSwitch(Block):
969    def __init__(self, expr):
970        Block.__init__(self)
971        self.expr = expr
972        self.nr_cases = 0
973
974    def addcase(self, case, block):
975        """NOTE: |case| is not checked for uniqueness"""
976        assert not isinstance(case, str)
977        assert (
978            isinstance(block, StmtBreak)
979            or isinstance(block, StmtReturn)
980            or isinstance(block, StmtSwitch)
981            or isinstance(block, GroupNode)
982            or isinstance(block, VerbatimNode)
983            or (
984                hasattr(block, "stmts")
985                and (
986                    isinstance(block.stmts[-1], StmtBreak)
987                    or isinstance(block.stmts[-1], StmtReturn)
988                    or isinstance(block.stmts[-1], GroupNode)
989                    or isinstance(block.stmts[-1], VerbatimNode)
990                )
991            )
992        )
993        self.addstmt(case)
994        self.addstmt(block)
995        self.nr_cases += 1
996
997
998class StmtBreak(Node):
999    def __init__(self):
1000        Node.__init__(self)
1001
1002
1003class StmtExpr(Node):
1004    def __init__(self, expr):
1005        assert expr is not None
1006
1007        Node.__init__(self)
1008        self.expr = expr
1009
1010
1011class StmtReturn(Node):
1012    def __init__(self, expr=None):
1013        Node.__init__(self)
1014        self.expr = expr
1015
1016
1017StmtReturn.TRUE = StmtReturn(ExprLiteral.TRUE)
1018StmtReturn.FALSE = StmtReturn(ExprLiteral.FALSE)
1019