1# -*- python -*-
2#                           Package   : omniidl
3# defs.py                   Created on: 1999/11/2
4#			    Author    : David Scott (djs)
5#
6#    Copyright (C) 2003-2011 Apasphere Ltd
7#    Copyright (C) 1999 AT&T Laboratories Cambridge
8#
9#  This file is part of omniidl.
10#
11#  omniidl is free software; you can redistribute it and/or modify it
12#  under the terms of the GNU General Public License as published by
13#  the Free Software Foundation; either version 2 of the License, or
14#  (at your option) any later version.
15#
16#  This program is distributed in the hope that it will be useful,
17#  but WITHOUT ANY WARRANTY; without even the implied warranty of
18#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19#  General Public License for more details.
20#
21#  You should have received a copy of the GNU General Public License
22#  along with this program.  If not, see http://www.gnu.org/licenses/
23#
24# Description:
25#
26#   Produce the main header definitions for the C++ backend
27
28"""Produce the main header definitions"""
29
30from omniidl import idlast, idltype
31from omniidl_be.cxx import id, output, config, types, iface, cxx, ast, util
32from omniidl_be.cxx import value
33from omniidl_be.cxx.header import template
34
35# We behave as if the global code here is really inside a class
36import sys
37self = sys.modules[__name__]
38
39stream = None
40
41_insideClass      = 0
42_insideModule     = 0
43_insideInterface  = 0
44_interfaces       = {}
45_completedModules = {}
46
47def pushInsideClass():
48    global _insideClass
49    _insideClass = _insideClass + 1
50
51def popInsideClass():
52    global _insideClass
53    _insideClass = _insideClass - 1
54
55def pushInsideModule():
56    global _insideModule
57    _insideModule = _insideModule + 1
58
59def popInsideModule():
60    global _insideModule
61    _insideModule = _insideModule - 1
62
63def pushInsideInterface():
64    global _insideInterface
65    _insideInterface = _insideInterface + 1
66
67def popInsideInterface():
68    global _insideInterface
69    _insideInterface = _insideInterface - 1
70
71
72def init(_stream):
73    global stream, _insideClass, _insideModule, _insideInterface
74    global _interfaces, _completedModules
75
76    stream = _stream
77
78    # Need to keep track of how deep within the AST we are.
79    # In a recursive procedure these would be extra arguments,
80    # but the visitor pattern necessitates them being global.
81    _insideInterface = 0
82    _insideModule    = 0
83    _insideClass     = 0
84
85    # A repository id entry in this hash indicates that an interface
86    # has been declared- therefore any more AST forward nodes for this
87    # interface are ignored.
88    _interfaces = {}
89
90    # When we first encounter a module, we sometimes deal with all the
91    # continuations straight away. Therefore when we reencounter a
92    # continuation later, we don't duplicate the definitions.
93    _completedModules = {}
94
95    return self
96
97
98# Returns the prefix required inside a const declaration (it depends on
99# exactly what the declaration is nested inside)
100def const_qualifier(insideModule=None, insideClass=None):
101    if insideModule is None:
102        insideModule = _insideModule
103        insideClass  = _insideClass
104
105    if not insideModule and not insideClass:
106        return "_CORBA_GLOBAL_VAR"
107    elif insideClass:
108        return "static"
109    else:
110        return "_CORBA_MODULE_VAR"
111
112# Same logic for function qualifiers
113def func_qualifier():
114    return const_qualifier(_insideModule, _insideClass)
115
116# Inline functions are subtly different
117def inline_qualifier():
118    if not _insideModule and not _insideClass:
119        return "inline"
120    elif _insideClass:
121        return "static inline"
122    else:
123        return "_CORBA_MODULE_INLINE"
124
125
126#
127# Control arrives here
128#
129def visitAST(node):
130    global stream, _insideClass, _insideModule, _insideInterface
131    global _interfaces, _completedModules
132
133    _insideInterface  = 0
134    _insideModule     = 0
135    _insideClass      = 0
136    _interfaces       = {}
137    _completedModules = {}
138
139    for n in node.declarations():
140        if ast.shouldGenerateCodeForDecl(n):
141            n.accept(self)
142
143def visitModule(node):
144    # Ensure we only output the definitions once.
145    # In particular, when the splice-modules flag is set and this is
146    # a reopened module, the node will be marked as completed already.
147    if node in _completedModules:
148        return
149    _completedModules[node] = 1
150
151    ident = node.identifier()
152    cxx_id = id.mapID(ident)
153
154    if not config.state['Fragment']:
155        stream.out(template.module_begin, name = cxx_id)
156        stream.inc_indent()
157
158    # push self.__insideModule, true
159    pushInsideModule()
160
161    for n in node.definitions():
162        n.accept(self)
163
164    # deal with continuations (only if the splice-modules flag is set)
165    if config.state['Splice Modules']:
166        for c in node.continuations():
167            for n in c.definitions():
168                n.accept(self)
169            _completedModules[c] = 1
170
171    popInsideModule()
172
173    if not config.state['Fragment']:
174        stream.dec_indent()
175        stream.out(template.module_end, name = cxx_id)
176
177
178
179def visitInterface(node):
180    # It's legal to have a forward interface declaration after
181    # the actual interface definition. Make sure we ignore these.
182    _interfaces[node.repoId()] = 1
183
184    name = node.identifier()
185    cxx_name = id.mapID(name)
186
187    outer_environment = id.lookup(node)
188    outer_environment.enter(name)
189
190    pushInsideInterface()
191    pushInsideClass()
192
193    # make the necessary forward references, typedefs and define
194    # the _Helper class
195    I = iface.Interface(node)
196
197    I_Helper = iface.I_Helper(I)
198    I_Helper.hh(stream)
199
200    # recursively take care of other IDL declared within this
201    # scope (evaluate function later- lazy eval though 'thunking')
202    def Other_IDL(node = node):
203        for n in node.declarations():
204            n.accept(self)
205
206    # Output this interface's corresponding class
207    Ibase = iface.I(I,Other_IDL)
208    Ibase.hh(stream)
209
210    if not node.local():
211        _objref_I = iface._objref_I(I)
212        _objref_I.hh(stream)
213
214        _pof_I = iface._pof_I(I)
215        _pof_I.hh(stream)
216
217        # Skeleton class
218        _impl_I = iface._impl_I(I)
219        _impl_I.hh(stream)
220
221        # Generate BOA compatible skeletons?
222        if config.state['BOA Skeletons']:
223            _sk_I = iface._sk_I(I)
224            _sk_I.hh(stream)
225
226    popInsideClass()
227    popInsideInterface()
228
229    # Typecode and Any
230    if config.state['Typecode']:
231        qualifier = const_qualifier(_insideModule, _insideClass)
232        stream.out(template.typecode,
233                   qualifier = qualifier,
234                   name = cxx_name)
235
236    return
237
238
239def visitForward(node):
240    # Note it's legal to have multiple forward declarations
241    # of the same name. So ignore the duplicates.
242    if node.repoId() in _interfaces:
243        return
244    _interfaces[node.repoId()] = 1
245
246    environment = id.lookup(node)
247    name        = id.Name(node.scopedName())
248    guard       = name.guard()
249
250    # Potentially forward declare BOA skeleton class
251    class_sk = ""
252    if config.state['BOA Skeletons']:
253        class_sk = "class _sk_" + name.simple() + ";"
254
255    # output the definition
256    if node.abstract():
257        stream.out(template.abstract_interface_Helper,
258                   guard = guard,
259                   class_sk_name = class_sk,
260                   name = name.simple())
261    elif node.local():
262        stream.out(template.local_interface_Helper,
263                   guard = guard,
264                   class_sk_name = class_sk,
265                   name = name.simple())
266    else:
267        stream.out(template.interface_Helper,
268                   guard = guard,
269                   class_sk_name = class_sk,
270                   name = name.simple())
271
272
273def visitConst(node):
274    environment = id.lookup(node)
275
276    constType = types.Type(node.constType())
277    d_constType = constType.deref()
278    if d_constType.string():
279        type_string = "char *"
280    elif d_constType.wstring():
281        type_string = "::CORBA::WChar *"
282    elif d_constType.fixed():
283        type_string = constType.member()
284    else:
285        type_string = d_constType.member()
286        # should this be .base?
287
288    cxx_name = id.mapID(node.identifier())
289
290    value = d_constType.literal(node.value(), environment)
291
292    representedByInteger = d_constType.representable_by_int()
293
294    # depends on whether we are inside a class / in global scope
295    # etc
296    # should be rationalised with tyutil.const_qualifier
297    if _insideClass:
298        if representedByInteger:
299            stream.out(template.const_inclass_isinteger,
300                       type = type_string, name = cxx_name, val = value)
301        else:
302            stream.out(template.const_inclass_notinteger,
303                       type = type_string, name = cxx_name)
304    else:
305        where = "GLOBAL"
306        if _insideModule:
307            where = "MODULE"
308        if representedByInteger:
309            stream.out(template.const_outsideclass_isinteger,
310                       where = where,
311                       type = type_string,
312                       name = cxx_name,
313                       val = value)
314        else:
315            stream.out(template.const_outsideclass_notinteger,
316                       where = where,
317                       type = type_string,
318                       name = cxx_name)
319
320
321def visitTypedef(node):
322    environment = id.lookup(node)
323
324    is_global_scope = not (_insideModule or _insideInterface)
325
326    aliasType = types.Type(node.aliasType())
327
328    # is _this_ type a constructed type?
329    if node.constrType():
330        node.aliasType().decl().accept(self)
331
332    d_type = aliasType.deref()
333    derefTypeID = d_type.base(environment)
334
335    basicReferencedTypeID = aliasType.member(environment)
336
337    # each one is handled independently
338    for d in node.declarators():
339
340        # derivedName is the new typedef'd name
341        # alias_dims is a list of dimensions of the type being aliased
342
343        derivedName = id.mapID(d.identifier())
344
345        alias_dims = aliasType.dims()
346
347        # array_declarator indicates whether this is a simple (non-array)
348        # declarator or not
349        array_declarator = d.sizes() != []
350
351        # Typecode and Any
352        if config.state['Typecode']:
353            qualifier = const_qualifier(_insideModule,_insideClass)
354            stream.out(template.typecode,
355                       qualifier = qualifier,
356                       name = derivedName)
357
358        # is it a simple alias (ie not an array at this level)?
359        if not array_declarator:
360            # not an array declarator but a simple declarator to an array
361            if aliasType.array():
362                # simple alias to an array should alias all the
363                # array handling functions, but we don't need to duplicate
364                # array looping code since we can just call the functions
365                # for the base type
366                stream.out(template.typedef_simple_to_array,
367                           base = basicReferencedTypeID,
368                           derived = derivedName,
369                           qualifier = func_qualifier(),
370                           inline_qualifier = inline_qualifier())
371
372            # Non-array of string
373            elif d_type.string():
374                stream.out(template.typedef_simple_string,
375                           name = derivedName)
376            elif d_type.wstring():
377                stream.out(template.typedef_simple_wstring,
378                           name = derivedName)
379            elif d_type.typecode():
380                stream.out(template.typedef_simple_typecode,
381                           name = derivedName)
382            elif d_type.any():
383                stream.out(template.typedef_simple_any,
384                           name = derivedName)
385
386            elif d_type.fixed():
387                stream.out(template.typedef_simple_fixed,
388                           name = derivedName,
389                           digits = d_type.type().digits(),
390                           scale = d_type.type().scale())
391
392            # Non-array of basic type
393            elif isinstance(d_type.type(), idltype.Base):
394                stream.out(template.typedef_simple_basic,
395                           base = basicReferencedTypeID,
396                           derived = derivedName)
397
398            # a typedef to a struct or union, or a typedef to a
399            # typedef to a sequence
400            elif d_type.struct() or d_type.structforward() or \
401                 d_type.union() or d_type.unionforward() or \
402                 (d_type.sequence() and aliasType.typedef()):
403
404                stream.out(template.typedef_simple_constructed,
405                           base = basicReferencedTypeID,
406                           name = derivedName)
407
408            # Non-array of object reference
409            elif d_type.interface():
410                derefTypeID = derefTypeID.replace("_ptr","")
411                # Note that the base name is fully flattened
412                is_CORBA_Object = d_type.type().scopedName() ==\
413                                  ["CORBA", "Object"]
414                impl_base = ""
415                objref_base = ""
416                sk_base = ""
417                if not is_CORBA_Object:
418                    scopedName = d_type.type().decl().scopedName()
419                    name = id.Name(scopedName)
420                    impl_scopedName = name.prefix("_impl_")
421                    objref_scopedName = name.prefix("_objref_")
422                    sk_scopedName = name.prefix("_sk_")
423                    impl_name = impl_scopedName.unambiguous(environment)
424                    objref_name = objref_scopedName.unambiguous(environment)
425                    sk_name = sk_scopedName.unambiguous(environment)
426
427                    impl_base =   "typedef " + impl_name   + " _impl_"   +\
428                                   derivedName + ";"
429                    objref_base = "typedef " + objref_name + " _objref_" +\
430                                   derivedName + ";"
431                    sk_base =     "typedef " + sk_name     + " _sk_"     +\
432                                   derivedName + ";"
433
434                stream.out(template.typedef_simple_objref,
435                           base = derefTypeID,
436                           name = derivedName,
437                           impl_base = impl_base,
438                           objref_base = objref_base)
439                if config.state['BOA Skeletons']:
440                    stream.out(sk_base)
441
442            # Non-array of valuetype
443            elif d_type.value() or d_type.valuebox():
444                basicReferencedTypeID = basicReferencedTypeID.replace("_member",
445                                                                      "")
446                stream.out(template.typedef_simple_constructed,
447                           base = basicReferencedTypeID,
448                           name = derivedName)
449
450            # Non-array of enum
451            elif d_type.enum():
452                stream.out(template.typedef_simple_basic,
453                           base = basicReferencedTypeID,
454                           derived = derivedName)
455
456            # Non-array of sequence
457            elif d_type.sequence():
458                seqType = types.Type(d_type.type().seqType())
459                d_seqType = seqType.deref()
460                bounded = d_type.type().bound()
461
462                templateName = d_type.sequenceTemplate(environment)
463
464                if d_seqType.structforward() or d_seqType.unionforward():
465                    # Sequence of forward-declared struct or union.
466                    # We cannot use the normal sequence templates
467                    # since they have inline methods that require the
468                    # full definition of the member type. We use
469                    # templates with abstract virtual functions
470                    # instead.
471
472                    element = element_ptr = seqType.base(environment)
473
474                    def bounds(bounded = bounded,
475                               derivedName = derivedName,
476                               derived = templateName,
477                               element = element):
478                        if bounded:
479                            ct = template.sequence_bounded_ctors
480                        else:
481                            ct = template.sequence_unbounded_ctors
482                        stream.out(ct, name = derivedName, element=element,
483                                   bound=bounded, derived=derived)
484
485                    stream.out(template.sequence_forward_type,
486                               name = derivedName,
487                               derived = templateName,
488                               element = element,
489                               bounds = bounds)
490
491                else:
492                    # Normal case using a template class.
493
494                    if seqType.array():
495                        element = "*** INVALID"
496                        element_ptr = seqType.base(environment)
497                    else:
498                        if d_seqType.string():
499                            element = "_CORBA_String_element"
500                            element_ptr = "char*"
501                        elif d_seqType.wstring():
502                            element = "_CORBA_WString_element"
503                            element_ptr = "::CORBA::WChar*"
504                        elif d_seqType.interface():
505                            element = seqType.base(environment)
506                            element_ptr = element
507                        elif d_seqType.value() or d_seqType.valuebox():
508                            element = seqType.base(environment)
509                            element_ptr = element + "*"
510                        # only if an anonymous sequence
511                        elif seqType.sequence():
512                            element = d_seqType.sequenceTemplate(environment)
513                            element_ptr = element
514                        elif d_seqType.typecode():
515                            element = "::CORBA::TypeCode_member"
516                            element_ptr = element
517                        else:
518                            element = seqType.base(environment)
519                            element_ptr = element
520
521                    # enums are a special case
522                    # ----
523                    # gcc requires that the marshalling operators for the
524                    # element be declared before the sequence template is
525                    # typedef'd. This is a problem for enums, as the
526                    # marshalling operators are not yet defined (and are
527                    # not part of the type itself).
528                    # ----
529                    # Note that the fully dereferenced name is used
530                    friend = "friend"
531                    if is_global_scope:
532                        friend = ""
533
534                    if d_seqType.enum() and not seqType.array():
535                        stream.out(template.typedef_enum_oper_friend,
536                                   element = d_seqType.base(environment),
537                                   friend = friend)
538
539                    # derivedName is the new type identifier
540                    # element is the name of the basic element type
541                    # templateName contains the template instantiation
542
543                    def bounds(bounded = bounded, derivedName = derivedName,
544                               element_ptr = element_ptr,
545                               templateName = templateName):
546                        if bounded:
547                            ctor_template = template.sequence_bounded_ctors
548                        else:
549                            ctor_template = template.sequence_unbounded_ctors
550                        stream.out(ctor_template,
551                                   name = derivedName,
552                                   element = element_ptr,
553                                   derived = templateName)
554
555                    # output the main sequence definition
556                    stream.out(template.sequence_type,
557                               name = derivedName,
558                               derived = templateName,
559                               bounds = bounds)
560
561
562                # start building the _var and _out types
563                element_reference = "*** INVALID"
564                if not aliasType.array():
565                    if d_seqType.string():
566                        # special case alert
567                        element_reference = element
568                    elif d_seqType.wstring():
569                        # special case alert
570                        element_reference = element
571                    elif d_seqType.interface():
572                        element_reference = d_seqType.objRefTemplate("Element",
573                                                                     environment)
574                    elif d_seqType.value() or d_seqType.valuebox():
575                        element_reference = d_seqType.valueTemplate("Element",
576                                                                    environment)
577                    # only if an anonymous sequence
578                    elif seqType.sequence():
579                        element_reference = d_seqType.sequenceTemplate(environment) + "&"
580                    else:
581                        element_reference = element + "&"
582
583                def subscript_operator_var(stream = stream,
584                                           is_array = seqType.array(),
585                                           element_ptr = element_ptr,
586                                           element_ref = element_reference):
587
588                    if is_array:
589                        stream.out(template.sequence_var_array_subscript,
590                                   element = element_ptr)
591                    else:
592                        stream.out(template.sequence_var_subscript,
593                                   element = element_ref)
594
595                def subscript_operator_out(stream = stream,
596                                           is_array = seqType.array(),
597                                           element_ptr = element_ptr,
598                                           element_ref = element_reference):
599                    if is_array:
600                        stream.out(template.sequence_out_array_subscript,
601                                   element = element_ptr)
602                    else:
603                        stream.out(template.sequence_out_subscript,
604                                   element = element_ref)
605
606                # write the _var class definition
607                stream.out(template.sequence_var,
608                           name = derivedName,
609                           subscript_operator = subscript_operator_var)
610
611                # write the _out class definition
612                stream.out(template.sequence_out,
613                           name = derivedName,
614                           subscript_operator = subscript_operator_out)
615
616            else:
617                util.fatalError("Inexhaustive Case Match")
618
619
620        # ----------------------------------------------------------------
621        # declarator is an array typedef declarator
622        elif array_declarator:
623
624            all_dims = d.sizes() + alias_dims
625            dimsString = cxx.dimsToString(d.sizes())
626            taildims = cxx.dimsToString(d.sizes()[1:])
627
628            typestring = aliasType.member(environment)
629
630            # build the _dup loop
631            def dup_loop(stream = stream, all_dims = all_dims):
632                loop = cxx.For(stream, all_dims)
633                stream.out("\n_data@index@ = _s@index@;\n",
634                           index = loop.index())
635                loop.end()
636
637            # build the _copy loop
638            def copy_loop(stream = stream, all_dims = all_dims):
639                loop = cxx.For(stream, all_dims)
640                stream.out("\n_to@index@ = _from@index@;\n",
641                           index = loop.index())
642                loop.end()
643
644            stream.out(template.typedef_array,
645                       name = derivedName,
646                       type = typestring,
647                       dims = dimsString,
648                       taildims = taildims,
649                       firstdim = repr(all_dims[0]),
650                       dup_loop = dup_loop,
651                       copy_loop = copy_loop,
652                       qualifier = func_qualifier(),
653                       inline_qualifier = inline_qualifier())
654
655            # output the _copyHelper class
656            fqname = id.Name(d.scopedName()).fullyQualify()
657
658            if types.variableDecl(node):
659                stream.out(template.typedef_array_copyHelper,
660                           var_or_fix = "Variable",
661                           name = derivedName,
662                           fqname = fqname)
663
664                stream.out(template.typedef_array_variable_out_type,
665                           name = derivedName)
666            else:
667                stream.out(template.typedef_array_copyHelper,
668                           var_or_fix = "Fix",
669                           name = derivedName,
670                           fqname = fqname)
671
672                stream.out(template.typedef_array_fix_out_type,
673                           name = derivedName)
674
675
676
677def visitMember(node):
678    memberType = node.memberType()
679    if node.constrType():
680        # if the type was declared here, it must be an instance
681        # of idltype.Declared!
682        assert isinstance(memberType, idltype.Declared)
683        memberType.decl().accept(self)
684
685
686def visitStruct(node):
687    name = node.identifier()
688    cxx_name = id.mapID(name)
689
690    outer_environment = id.lookup(node)
691    environment = outer_environment.enter(name)
692
693    pushInsideClass()
694
695    # Deal with types constructed here
696    def Other_IDL(stream = stream, node = node, environment = environment):
697        for m in node.members():
698            if m.constrType():
699                m.memberType().decl().accept(self)
700
701    # Deal with the actual struct members
702    def members(stream = stream, node = node, environment = environment):
703        for m in node.members():
704            memberType = types.Type(m.memberType())
705
706            memtype = memberType.member(environment)
707
708            for d in m.declarators():
709                ident = d.identifier()
710
711                cxx_id = id.mapID(ident)
712
713                decl_dims = d.sizes()
714                is_array_declarator = decl_dims != []
715
716                # non-arrays of direct sequences are done via a typedef
717                if not is_array_declarator and memberType.sequence():
718                    stream.out(template.struct_nonarray_sequence,
719                               memtype = memtype,
720                               cxx_id = cxx_id)
721                else:
722                    dims_string = cxx.dimsToString(decl_dims)
723                    if is_array_declarator:
724                        stream.out(template.struct_array_declarator,
725                                   memtype = memtype,
726                                   cxx_id = cxx_id,
727                                   dims = dims_string,
728                                   tail_dims = cxx.dimsToString(d.sizes()[1:]),
729                                   prefix = config.state['Private Prefix'])
730
731                    stream.out(template.struct_normal_member,
732                               memtype = memtype,
733                               cxx_id = cxx_id,
734                               dims = dims_string)
735
736    # Output the structure itself
737    if types.variableDecl(node):
738        stream.out(template.struct,
739                   name = cxx_name,
740                   fix_or_var = "Variable",
741                   Other_IDL = Other_IDL,
742                   members = members)
743        stream.out(template.struct_variable_out_type,
744                   name = cxx_name)
745    else:
746        stream.out(template.struct,
747                   name = cxx_name,
748                   fix_or_var = "Fix",
749                   Other_IDL = Other_IDL,
750                   members = members)
751        stream.out(template.struct_fix_out_type,
752                   name = cxx_name)
753
754
755    popInsideClass()
756
757    # TypeCode and Any
758    if config.state['Typecode']:
759        # structs in C++ are classes with different default privacy policies
760        qualifier = const_qualifier(_insideModule, _insideClass)
761        stream.out(template.typecode,
762                   qualifier = qualifier,
763                   name = cxx_name)
764
765
766def visitStructForward(node):
767    cxx_name = id.mapID(node.identifier())
768    stream.out(template.struct_forward, name = cxx_name)
769
770
771def visitException(node):
772    exname = node.identifier()
773
774    cxx_exname = id.mapID(exname)
775
776    outer_environment = id.lookup(node)
777    environment = outer_environment.enter(exname)
778
779    pushInsideClass()
780
781    # if the exception has no members, inline some no-ops
782    no_members = (node.members() == [])
783
784    # other types constructed within this one
785    def Other_IDL(stream = stream, node = node):
786        for m in node.members():
787            if m.constrType():
788                m.memberType().decl().accept(self)
789
790    # deal with the exceptions members
791    def members(stream = stream, node = node, environment = environment):
792        for m in node.members():
793            memberType = types.Type(m.memberType())
794
795            for d in m.declarators():
796                decl_dims = d.sizes()
797                is_array_declarator = decl_dims != []
798
799                memtype = memberType.member(environment)
800                ident = d.identifier()
801
802                cxx_id = id.mapID(ident)
803
804                dims_string = cxx.dimsToString(decl_dims)
805
806                if is_array_declarator:
807                    stream.out(template.exception_array_declarator,
808                               memtype = memtype,
809                               cxx_id = cxx_id,
810                               dims = dims_string,
811                               tail_dims = cxx.dimsToString(d.sizes()[1:]),
812                               private_prefix = config.state['Private Prefix'])
813
814                stream.out(template.exception_member,
815                           memtype = memtype,
816                           cxx_id = cxx_id,
817                           dims = dims_string)
818
819    # deal with ctor args
820    ctor_args = []
821    for m in node.members():
822        memberType = types.Type(m.memberType())
823        d_memberType = memberType.deref()
824        for d in m.declarators():
825            decl_dims = d.sizes()
826            is_array_declarator = decl_dims != []
827            ctor_arg_type = memberType.op(types.IN, environment)
828            # sequences are not passed by reference here
829            if d_memberType.sequence():
830                if memberType.typedef():
831                    ctor_arg_type = "const " + id.Name(memberType.type().decl().scopedName()).unambiguous(environment)
832                else:
833                    ctor_arg_type = "const " + memberType.sequenceTemplate(environment)
834            elif d_memberType.typecode():
835                ctor_arg_type = "::CORBA::TypeCode_ptr"
836
837            ident = d.identifier()
838
839            cxx_id = id.mapID(ident)
840
841            if is_array_declarator:
842                ctor_arg_type = "const " + config.state['Private Prefix'] +\
843                                "_" + cxx_id
844            ctor_args.append(ctor_arg_type + " i_" + cxx_id)
845
846
847    ctor = ""
848    if ctor_args != []:
849        ctor = cxx_exname + "(" + ", ".join(ctor_args) + ");"
850
851    if no_members:
852        inline = "inline "
853        body = "{ }"
854        alignedSize = ""
855    else:
856        inline = ""
857        body = ";"
858        alignedSize = "size_t _NP_alignedSize(size_t) const;"
859
860    # output the main exception declaration
861    stream.out(template.exception,
862               name = cxx_exname,
863               Other_IDL = Other_IDL,
864               members = members,
865               constructor = ctor,
866               alignedSize = alignedSize,
867               inline = inline,
868               body = body)
869
870    popInsideClass()
871
872    # Typecode and Any
873    if config.state['Typecode']:
874        qualifier = const_qualifier(_insideModule, _insideClass)
875        stream.out(template.typecode,
876                   qualifier = qualifier,
877                   name = cxx_exname)
878
879
880
881def visitUnion(node):
882    ident = node.identifier()
883
884    cxx_id = id.mapID(ident)
885    outer_environment = id.lookup(node)
886    environment = outer_environment.enter(ident)
887
888    pushInsideClass()
889
890    switchType = types.Type(node.switchType())
891    d_switchType = switchType.deref()
892
893    ####################################################################
894    # in the case where there is no default case and an implicit default
895    # member, choose a discriminator value to set. Note that attempting
896    # to access the data is undefined
897    def chooseArbitraryDefault(switchType = switchType,
898                               values = ast.allCaseLabelValues(node),
899                               environment = environment):
900
901        # dereference the switch_type (ie if CASE <scoped_name>)
902        switchType = switchType.deref()
903
904        # for integer types, find the lowest unused number
905        def min_unused(start, used = values):
906            x = start
907            while x in used:
908                x = x + 1
909            return x
910
911        kind = switchType.type().kind()
912        if switchType.integer():
913            (low, high) = ast.integer_type_ranges[kind]
914            s = switchType.literal(min_unused(low+1))
915            return s
916
917        # for other types, first compute the set of all legal values
918        # (sets are all fairly small)
919        elif kind == idltype.tk_char:
920            all = list(map(chr, list(range(0, 255))))
921        elif kind == idltype.tk_boolean:
922            all = [0, 1]
923        elif kind == idltype.tk_enum:
924            all = switchType.type().decl().enumerators()
925        else:
926            util.fatalError("Failed to generate a default union "
927                            "discriminator value")
928
929        for item in all:
930            if item not in values:
931                return switchType.literal(item, environment)
932
933        return None
934    #
935    ###############################################################
936
937    # does the IDL union have any default case?
938    # It'll be handy to know which case is the default one later-
939    # so add a new attribute to mark it
940    ast.markDefaultCase(node)
941    hasDefault = ast.defaultCase(node) != None
942
943    # CORBA 2.3 C++ Mapping 1-34
944    # "A union has an implicit default member if it does not have
945    # a default case and not all permissible values of the union
946    # discriminant are listed"
947    exhaustive = ast.exhaustiveMatch(switchType, ast.allCaseLabelValues(node))
948    implicitDefault = not hasDefault and not exhaustive
949
950    if types.variableDecl(node):
951        fixed = "Variable"
952    else:
953        fixed = "Fix"
954
955    def Other_IDL(stream = stream, node = node):
956        # deal with constructed switch type
957        if node.constrType():
958            node.switchType().decl().accept(self)
959
960        # deal with children defined in this scope
961        for n in node.cases():
962            if n.constrType():
963                n.caseType().decl().accept(self)
964
965
966    # create the default constructor body
967    def default_constructor(stream = stream,
968                            implicitDefault = implicitDefault,
969                            hasDefault = hasDefault,
970                            choose = chooseArbitraryDefault):
971        if implicitDefault:
972            stream.out(template.union_constructor_implicit)
973        elif hasDefault:
974            stream.out(template.union_constructor_default,
975                       default = choose())
976        return
977
978    def ctor_cases(stream = stream, node = node, switchType = switchType,
979                   environment = environment, exhaustive = exhaustive):
980
981        booleanWrap = switchType.boolean() and exhaustive
982        trueName    = None
983
984        for c in node.cases():
985            for l in c.labels():
986                if l.default(): continue
987
988                discrimvalue = switchType.literal(l.value(), environment)
989                name = id.mapID(c.declarator().identifier())
990
991                if booleanWrap and discrimvalue == "1":
992                    trueName = name
993
994                stream.out(template.union_ctor_case,
995                           discrimvalue = discrimvalue,
996                           name = name)
997
998        # Booleans are a special case (isn't everything?)
999        if booleanWrap:
1000            stream.out(template.union_ctor_bool_default,
1001                       name = trueName)
1002        else:
1003            stream.out(template.union_ctor_default)
1004        return
1005
1006    # create the copy constructor and the assignment operator
1007    # bodies
1008    def copy_constructor(stream = stream, exhaustive = exhaustive,
1009                         node = node, ctor_cases = ctor_cases):
1010        if not exhaustive:
1011            # grab the default case
1012            default = "_release_member();"
1013            for c in node.cases():
1014                if c.isDefault:
1015                    case_id = c.declarator().identifier()
1016                    cxx_case_id = id.mapID(case_id)
1017                    default = cxx_case_id + "(_value." + cxx_case_id + "());"
1018
1019
1020            stream.out(template.union_ctor_nonexhaustive,
1021                       default = default,
1022                       cases = ctor_cases)
1023        else:
1024            stream.out(template.union_ctor_exhaustive,
1025                       cases = ctor_cases)
1026        return
1027
1028    # do we need an implicit _default function?
1029    def implicit_default(stream = stream, choose = chooseArbitraryDefault,
1030                         implicitDefault = implicitDefault):
1031
1032        if implicitDefault:
1033            stream.out(template.union_implicit_default,
1034                       arbitraryDefault = choose())
1035        return
1036
1037    # The body of the union _d(_value) function generated here
1038    def _d_fn(stream = stream, node = node, switchType = switchType,
1039              implicitDefault = implicitDefault,
1040              environment = environment):
1041
1042        # The plan:
1043        #  * Check the _pd__initialised flag is set, else throw BAD_PARAM
1044        #  * Check for the simple case where _value == _pd__d and return
1045        #  * Have a nested switch, the outer switch is keyed on the current
1046        #    discriminator value and the inner one is the requested new value
1047        #
1048        # Possibilities:
1049        #  * Could perform some code minimisation eg for the case
1050        #      union foo switch(boolean){
1051        #         case TRUE:
1052        #         case FALSE:
1053        #           T bar;
1054        #      };
1055        #    This is equivalent to a single default: case and no switch is
1056        #    required.
1057
1058        # Make sure we don't output a switch with no cases (if there is a
1059        # one-to-one mapping of labels to cases)
1060        need_switch = 0
1061
1062        # Need to fill in a default case only if the union has none itself
1063        outer_has_default = 0
1064
1065        cases = output.StringStream()
1066
1067        # Produce a set of "case <foo>: goto fail;" for every label
1068        # except those in an exception list
1069        def fail_all_but(exceptions, node = node, cases = cases,
1070                         switchType = switchType, environment = environment):
1071            for c in node.cases():
1072                for l in c.labels():
1073                    if l not in exceptions:
1074                        cases.out("case @label@: goto fail;",
1075                                  label = switchType.literal(l.value(),
1076                                                             environment))
1077
1078
1079        # switch (currently active case){
1080        #
1081        outer_has_default = 0 # only mention default: once
1082        for c in node.cases():
1083
1084            need_switch = 1
1085
1086            # If the currently active case has only one non-default label,
1087            # then the only legal action is to set it to its current value.
1088            # We've already checked for this in an if (...) statement before
1089            # here.
1090            if len(c.labels()) == 1 and not c.labels()[0].default():
1091                cases.out("case @label@: goto fail;",
1092                          label = switchType.literal(c.labels()[0].value(),
1093                                                     environment))
1094                continue
1095
1096            # output one C++ case label for each IDL case label
1097            # case 1:
1098            # case 2:
1099            # default:
1100
1101            this_case_is_default = 0
1102            for l in c.labels():
1103                if l.default():
1104                    this_case_is_default = 1
1105                    outer_has_default = 1
1106                    cases.out("default:")
1107                    continue
1108
1109                cases.out("case @label@:",
1110                          label = switchType.literal(l.value(), environment))
1111
1112            # switch (case to switch to){
1113            #
1114            cases.inc_indent()
1115            cases.out("switch (_value){\n")
1116            cases.inc_indent()
1117
1118            # If we currently are in the default case, fail all attempts
1119            # to switch cases.
1120            if this_case_is_default:
1121                fail_all_but(c.labels())
1122                cases.out("default: _pd__d = _value; return;")
1123                cases.dec_indent()
1124                cases.out("}\n")
1125                cases.dec_indent()
1126                continue
1127
1128            # This is not the default case, all possibilities have associated
1129            # UnionCaseLabels
1130            for l in c.labels():
1131                cases.out("case @label@: _pd__d = @label@; return;",
1132                          label = switchType.literal(l.value(), environment))
1133
1134
1135            cases.out("default: goto fail;")
1136            cases.dec_indent()
1137            cases.out("}\n")
1138            cases.dec_indent()
1139
1140        if not outer_has_default and not implicitDefault:
1141            cases.out("default: goto fail;")
1142
1143        # handle situation where have an implicit default member
1144        # (ie no actual case, but a legal set of discriminator values)
1145        # (assumes that the current discriminator is set to one of the
1146        # defaults)
1147        if implicitDefault:
1148            need_switch = 1
1149            cases.out("default:")
1150            cases.out("switch (_value){")
1151            cases.inc_indent()
1152            # again, make sure we aren't currently in the default state
1153            # and trying to set the discriminator to a non-default state
1154            fail_all_but([])
1155
1156            cases.out("default: _pd__d = _value; return;")
1157
1158            cases.dec_indent()
1159            cases.out("}")
1160
1161
1162        # output the code here
1163        switch = output.StringStream()
1164        if need_switch:
1165            switch.out("switch (_pd__d){\n  @cases@\n};", cases = cases)
1166        stream.out(template.union_d_fn_body, switch = switch)
1167
1168
1169    # get and set functions for each case:
1170    def members(stream = stream, node = node, environment = environment,
1171                switchType = switchType):
1172
1173        for c in node.cases():
1174            # Following the typedef chain will deliver the base type of
1175            # the alias. Whether or not it is an array is stored in an
1176            # ast.Typedef node.
1177            caseType = types.Type(c.caseType())
1178            d_caseType = caseType.deref()
1179
1180            # the mangled name of the member
1181            decl = c.declarator()
1182            decl_dims = decl.sizes()
1183
1184            full_dims = decl_dims + caseType.dims()
1185
1186            is_array = full_dims != []
1187            is_array_declarator = decl_dims != []
1188
1189            member = id.mapID(decl.identifier())
1190
1191            memtype = caseType.member(environment)
1192
1193            # Pick a discriminator value to use when selecting the
1194            # case. Pick the first non-default label if there is one.
1195            labels = c.labels()
1196
1197            label = labels[0]
1198            if label.default() and len(labels) > 1:
1199                # Pick a non-default label if there is one
1200                label = labels[1]
1201
1202            discrimvalue = switchType.literal(label.value(), environment)
1203
1204
1205            # only different when array declarator
1206            const_type_str = memtype
1207
1208            # create typedefs for anonymous arrays
1209            if is_array_declarator:
1210                prefix = config.state['Private Prefix']
1211                stream.out(template.union_array_declarator,
1212                           prefix = prefix,
1213                           memtype = memtype,
1214                           name = member,
1215                           dims = cxx.dimsToString(decl.sizes()),
1216                           tail_dims = cxx.dimsToString(decl.sizes()[1:]))
1217                const_type_str = prefix + "_" + member
1218                memtype = "_" + member
1219
1220            if is_array:
1221                # build the loop
1222                def loop(stream = stream, full_dims = full_dims,
1223                         member = member):
1224                    loop = cxx.For(stream, full_dims)
1225                    index = loop.index()
1226                    stream.out("\n_pd_" + member + index + " = _value" +\
1227                               index + ";\n")
1228                    loop.end()
1229                    return
1230
1231                stream.out(template.union_array,
1232                           memtype = memtype,
1233                           const_type = const_type_str,
1234                           name = member,
1235                           isDefault = str(c.isDefault),
1236                           discrimvalue = discrimvalue,
1237                           first_dim = repr(full_dims[0]),
1238                           loop = loop)
1239
1240            elif d_caseType.any():
1241                # note type != CORBA::Any when its an alias...
1242                stream.out(template.union_any,
1243                           type = memtype,
1244                           name = member,
1245                           isDefault = str(c.isDefault),
1246                           discrimvalue = discrimvalue)
1247
1248            elif d_caseType.typecode():
1249                stream.out(template.union_typecode,
1250                           name = member,
1251                           isDefault = str(c.isDefault),
1252                           discrimvalue = discrimvalue)
1253
1254            elif isinstance(d_caseType.type(), idltype.Base) or \
1255                 d_caseType.enum():
1256                # basic type
1257                stream.out(template.union_basic,
1258                           type = memtype,
1259                           name = member,
1260                           isDefault = str(c.isDefault),
1261                           discrimvalue = discrimvalue)
1262
1263            elif d_caseType.string():
1264                stream.out(template.union_string,
1265                           type = memtype,
1266                           name = member,
1267                           isDefault = str(c.isDefault),
1268                           discrimvalue = discrimvalue)
1269
1270            elif d_caseType.wstring():
1271                stream.out(template.union_wstring,
1272                           name = member,
1273                           isDefault = str(c.isDefault),
1274                           discrimvalue = discrimvalue)
1275
1276            elif d_caseType.interface():
1277                scopedName = d_caseType.type().decl().scopedName()
1278
1279                name     = id.Name(scopedName)
1280                ptr_name = name.suffix("_ptr").unambiguous(environment)
1281                var_name = name.suffix("_var").unambiguous(environment)
1282
1283                if isinstance(d_caseType.type().decl(), idlast.Forward):
1284                    helper = name.suffix("_Helper").unambiguous(environment)
1285                    duplicate = helper + "::duplicate"
1286                else:
1287                    iclass    = name.unambiguous(environment)
1288                    duplicate = iclass + "::_duplicate"
1289
1290                stream.out(template.union_objref,
1291                           member = member,
1292                           memtype = memtype,
1293                           ptr_name = ptr_name,
1294                           var_name = var_name,
1295                           duplicate = duplicate,
1296                           isDefault = str(c.isDefault),
1297                           discrimvalue = discrimvalue)
1298
1299            elif caseType.typedef() or d_caseType.struct() or \
1300                 d_caseType.union() or d_caseType.fixed():
1301                stream.out(template.union_constructed,
1302                           type = memtype,
1303                           name = member,
1304                           isDefault = str(c.isDefault),
1305                           discrimvalue = discrimvalue)
1306
1307            elif d_caseType.sequence():
1308                sequence_template = d_caseType.sequenceTemplate(environment)
1309                stream.out(template.union_sequence,
1310                           sequence_template = sequence_template,
1311                           member = member,
1312                           isDefault = str(c.isDefault),
1313                           discrimvalue = discrimvalue)
1314
1315            elif d_caseType.value() or d_caseType.valuebox():
1316                scopedName = d_caseType.type().decl().scopedName()
1317                name = id.Name(scopedName)
1318                type = name.unambiguous(environment)
1319
1320                stream.out(template.union_value,
1321                           member=member,
1322                           type=type,
1323                           isDefault = str(c.isDefault),
1324                           discrimvalue = discrimvalue)
1325
1326            else:
1327                util.fatalError("Unknown union case type encountered")
1328
1329        return
1330
1331    # declare the instance of the discriminator and
1332    # the actual data members (shock, horror)
1333    union_body       = output.StringStream()
1334    release_body     = output.StringStream()
1335    need_release     = 0
1336    explicit_default = 0
1337
1338    for c in node.cases():
1339
1340        # find the dereferenced type of the member if it's an alias
1341        caseType   = types.Type(c.caseType())
1342        d_caseType = caseType.deref()
1343        case_kind  = d_caseType.type().kind()
1344
1345        decl       = c.declarator()
1346        decl_dims  = decl.sizes()
1347        full_dims  = caseType.dims() + decl_dims
1348
1349        is_array            = full_dims != []
1350        is_array_declarator = decl_dims != []
1351
1352        member_name = id.mapID(c.declarator().identifier())
1353        member_type = caseType.base(environment)
1354
1355
1356        # Work out type for the union member
1357        if is_array_declarator:
1358            # _slice typedef defined earlier
1359            member_type = "_" + member_name + "_slice*"
1360
1361        elif caseType.sequence():
1362            # _seq typedef defined earlier
1363            member_type = "_" + member_name + "_seq*"
1364
1365        elif is_array:
1366            member_type = member_type + "_slice*"
1367
1368        elif case_kind in [ idltype.tk_any,
1369                            idltype.tk_struct,
1370                            idltype.tk_union,
1371                            idltype.tk_sequence,
1372                            idltype.tk_except,
1373                            idltype.tk_fixed,
1374                            idltype.tk_value,
1375                            idltype.tk_value_box,
1376                            ]:
1377            member_type = member_type + "*"
1378
1379        # Float types have conditional code that may or may not store
1380        # them by pointer.
1381        if not is_array and case_kind in [ idltype.tk_float,
1382                                           idltype.tk_double ]:
1383            union_member = template.union_member_float
1384        else:
1385            union_member = template.union_member
1386
1387        # Output union member
1388        union_body.out(union_member,
1389                       type = member_type,
1390                       name = member_name)
1391
1392
1393        # Code to release the member
1394        release = None
1395        helper  = None
1396
1397        if is_array:
1398            release = template.union_release_array
1399
1400        elif case_kind in [ idltype.tk_any,
1401                            idltype.tk_struct,
1402                            idltype.tk_union,
1403                            idltype.tk_sequence,
1404                            idltype.tk_except,
1405                            idltype.tk_fixed,
1406                            ]:
1407            release = template.union_release_delete
1408
1409        elif case_kind in [ idltype.tk_objref,
1410                            idltype.tk_abstract_interface,
1411                            idltype.tk_local_interface,
1412                            ]:
1413
1414            if isinstance(d_caseType.type().decl(), idlast.Forward):
1415                # Use the helper class to call release
1416                release = template.union_release_helper
1417
1418                scopedName = d_caseType.type().decl().scopedName()
1419                name       = id.Name(scopedName)
1420                helper     = name.suffix("_Helper").unambiguous(environment)
1421            else:
1422                release = template.union_release_corba_release
1423
1424        elif case_kind in [ idltype.tk_TypeCode,
1425                            ]:
1426            release = template.union_release_corba_release
1427
1428        elif case_kind in [ idltype.tk_value,
1429                            idltype.tk_value_box,
1430                            ]:
1431            release = template.union_release_valuetype
1432
1433        elif case_kind == idltype.tk_string:
1434            release = template.union_release_string
1435
1436        elif case_kind == idltype.tk_wstring:
1437            release = template.union_release_wstring
1438
1439        if release is not None:
1440            need_release = 1
1441            release_member = output.StringStream()
1442            release_member.out(release, name=member_name, helper=helper)
1443        else:
1444            release_member = ""
1445
1446        cases = output.StringStream()
1447        for label in c.labels():
1448            if label.default():
1449                cases.out("default:")
1450                explicit_default = 1
1451            else:
1452                cases.out("case @label@:",
1453                          label = switchType.literal(label.value(),
1454                                                     environment))
1455
1456        release_body.out(template.union_release_case,
1457                         cases          = cases,
1458                         release_member = release_member)
1459
1460    if need_release:
1461        if not explicit_default:
1462            # Output an empty default case to prevent fussy compilers
1463            # complaining
1464            release_body.out(template.union_release_case,
1465                             cases          = "default:",
1466                             release_member = "")
1467
1468        release_member = output.StringStream()
1469        release_member.out(template.union_release_member,
1470                                 cases = release_body)
1471    else:
1472        release_member = template.union_release_member_empty
1473
1474    # write out the union class
1475    stream.out(template.union,
1476               unionname           = cxx_id,
1477               fixed               = fixed,
1478               Other_IDL           = Other_IDL,
1479               default_constructor = default_constructor,
1480               copy_constructor    = copy_constructor,
1481               discrimtype         = d_switchType.base(environment),
1482               _d_body             = _d_fn,
1483               implicit_default    = implicit_default,
1484               members             = members,
1485               union_body          = union_body,
1486               release_member      = release_member)
1487
1488    if types.variableDecl(node):
1489        stream.out(template.union_variable_out_type,
1490                   unionname = cxx_id)
1491    else:
1492        stream.out(template.union_fix_out_type,
1493                   unionname = cxx_id)
1494
1495    popInsideClass()
1496
1497    # TypeCode and Any
1498    if config.state['Typecode']:
1499        qualifier = const_qualifier(_insideModule, _insideClass)
1500        stream.out(template.typecode,
1501                   qualifier = qualifier,
1502                   name = cxx_id)
1503
1504    return
1505
1506
1507def visitUnionForward(node):
1508    cxx_name = id.mapID(node.identifier())
1509    stream.out(template.union_forward, name = cxx_name)
1510
1511
1512def visitEnum(node):
1513    name = id.mapID(node.identifier())
1514
1515    enumerators = node.enumerators()
1516    memberlist = [id.Name(x.scopedName()).simple() for x in enumerators]
1517    stream.out(template.enum,
1518               name = name,
1519               memberlist = ", ".join(memberlist))
1520
1521    # TypeCode and Any
1522    if config.state['Typecode']:
1523        qualifier = const_qualifier(_insideModule, _insideClass)
1524        stream.out(template.typecode,
1525                   qualifier = qualifier, name = name)
1526
1527    return
1528
1529def visitValue(node):
1530    v = value.getValueType(node)
1531    v.module_decls(stream, self)
1532
1533def visitValueAbs(node):
1534    v = value.getValueType(node)
1535    v.module_decls(stream, self)
1536
1537def visitValueForward(node):
1538    v = value.getValueType(node)
1539    v.module_decls(stream, self)
1540
1541def visitValueBox(node):
1542    v = value.getValueType(node)
1543    v.module_decls(stream, self)
1544