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