1# -*- python -*-
2#                           Package   : omniidl
3# types.py                  Created on: 2000/4/10
4#                           Author    : David Scott (djs)
5#
6#    Copyright (C) 2003-2009 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#   Type utility functions designed for the C++ backend
27
28try:
29    # Python 3 does not have a built in reduce()
30    from functools import reduce
31except ImportError:
32    pass
33
34from omniidl import idltype, idlast, idlutil
35from omniidl_be.cxx import util, config, id
36
37# direction constants
38IN     = 0
39OUT    = 1
40INOUT  = 2
41RET    = 3
42
43# we don't support these
44unsupported_typecodes =[idltype.tk_Principal,
45                        idltype.tk_native]
46
47class Type:
48    """Wrapper around an IDL type providing useful extra functionality"""
49    def __init__(self, type):
50        assert isinstance(type, idltype.Type)
51        self.__type = type
52
53    def type(self):
54        """type(types.Type): idltype.Type
55           returns the wrapped type"""
56        return self.__type
57
58    def kind(self):
59        """type(types.Type): idltype.kind
60           returns the kind of the wrapped type"""
61        return self.__type.kind()
62
63    def deref(self, keep_dims = 0):
64        """deref(types.Type, keep_dims boolean option) -> types.Type
65           Return the type with outer aliases removed.
66           (if keep_dims is true then it will not remove aliases with
67           array dimensions)"""
68        type = self
69        while (type.typedef()):
70            decl = type.__type.decl()
71            if keep_dims and decl.sizes() != []:
72                return type
73            type = Type(decl.alias().aliasType())
74
75        return type
76
77    def variable(self):
78        """variable(types.Type): boolean
79           Returns whether the type has a variable length representation
80           under the C++ mapping"""
81        type = self.__type
82
83        if type.kind() in already_Variable:
84            return already_Variable[type.kind()]
85
86        if isinstance(type, idltype.Declared):
87            decl = type.decl()
88            return variableDecl(decl)
89
90        util.fatalError("Error while computing the variable-ness of a type")
91
92    def dims(self):
93        """dims(types.Type): int list
94           Returns the full dimensions of the type"""
95
96        type = self.__type
97        if isinstance(type, idltype.Declared):
98            decl = type.decl()
99            if type.kind() == idltype.tk_alias:
100                sizes = []
101                if decl.sizes() != None:
102                    sizes = decl.sizes()
103                if decl.alias() != None:
104                    sizes = sizes + Type(decl.alias().aliasType()).dims()
105                return sizes
106            if isinstance(type.decl(), idlast.Typedef):
107                return Type(type.decl().aliasType()).dims()
108            return []
109        return []
110
111    def array(self):
112        """array(types.Type): boolean
113           Returns true if this type has array dimensions"""
114        return self.dims() != []
115
116    def __apply_mapping(self, xxx_todo_changeme, thing):
117        # __apply_mapping(types.Type, (const bool, ref bool, ptr bool), string)
118        #  : string
119        # Make an instance of "thing" which is optionally const, a reference
120        # and a pointer types
121        (const, ref, ptr) = xxx_todo_changeme
122        text = thing
123        if const: text = "const " + text
124        if ptr:   text = text + "*"
125        if ref:   text = text + "&"
126        return text
127
128    def _argmapping(self, direction):
129        # _argmapping(types.Type, int direction): const * reference * pointer
130        #   Returns info on operation argument mapping for a type for
131        #   a particular direction.
132
133        # CORBA2.3 P1-204 Table 1-3 Basic argument and result mapping
134        array = self.array()
135        variable = self.variable()
136
137        if array and not variable:
138            # array of fixed size elements
139            return ( (1, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 1) )[direction]
140
141        if array and variable:
142            # array of variable size elements
143            return ( (1, 0, 0), (0, 1, 1), (0, 0, 0), (0, 0, 1) )[direction]
144
145        type = self.deref().__type
146        kind = type.kind()
147
148        if kind in [ idltype.tk_short, idltype.tk_long, idltype.tk_longlong,
149                     idltype.tk_ushort, idltype.tk_ulong, idltype.tk_ulonglong,
150                     idltype.tk_float, idltype.tk_double, idltype.tk_enum,
151                     idltype.tk_longdouble, idltype.tk_boolean,
152                     idltype.tk_char, idltype.tk_wchar, idltype.tk_octet ]:
153            # from short to enum the entries are the same
154            return ( (0, 0, 0), (0, 1, 0), (0, 1, 0), (0, 0, 0) )[direction]
155
156        if kind in [ idltype.tk_objref,
157                     idltype.tk_TypeCode,
158                     idltype.tk_abstract_interface,
159                     idltype.tk_local_interface ]:
160
161            # objref_ptr objref_ptr& objref_ptr& objref_ptr
162            return ( (0, 0, 0), (0, 1, 0), (0, 1, 0), (0, 0, 0) )[direction]
163
164        if kind in [ idltype.tk_struct, idltype.tk_union ]:
165            if variable:
166                # variable struct or union
167                return ((1, 1, 0), (0, 1, 1), (0, 1, 0), (0, 0, 1))[direction]
168            else:
169                # fixed struct or union
170                return ((1, 1, 0), (0, 1, 0), (0, 1, 0), (0, 0, 0))[direction]
171
172        if kind in [ idltype.tk_string, idltype.tk_wstring ]:
173            return ( (1, 0, 0), (0, 1, 0), (0, 1, 0), (0, 0, 0) )[direction]
174
175        if kind in [ idltype.tk_sequence, idltype.tk_any ]:
176            return ( (1, 1, 0), (0, 1, 1), (0, 1, 0), (0, 0, 1) )[direction]
177
178        if kind == idltype.tk_fixed:
179            return ( (1, 1, 0), (0, 1, 0), (0, 1, 0), (0, 0, 0) )[direction]
180
181        if kind in [ idltype.tk_value,
182                     idltype.tk_value_box ]:
183
184            return ( (0, 0, 1), (0, 1, 1), (0, 1, 1), (0, 0, 1) )[direction]
185
186        if kind == idltype.tk_void:
187            return (0, 0, 0)
188
189        if kind in unsupported_typecodes:
190            util.unsupportedIDL()
191
192        util.fatalError("Unknown type encountered (kind = " + str(kind) + ")")
193        return
194
195    def op_is_pointer(self, direction):
196        if not self.array() and \
197           (self.deref().string() or self.deref().wstring()):
198            return 0
199        return self._argmapping(direction)[2]
200
201    def __var_argmapping(self, direction):
202        # __var_argmapping(types.Type, direction): const * reference * pointer
203        #  Returns info on argument mapping for a type in a _var
204        #  context
205
206        # CORBA2.3 P1-204 Table 1-4 T_var argument and result mapping
207        kind = self.__type.kind()
208
209        if (kind in [ idltype.tk_objref,
210                      idltype.tk_struct,
211                      idltype.tk_union,
212                      idltype.tk_string,
213                      idltype.tk_wstring,
214                      idltype.tk_sequence,
215                      idltype.tk_any,
216                      idltype.tk_value,
217                      idltype.tk_value_box,
218                      idltype.tk_abstract_interface,
219                      idltype.tk_local_interface ]
220            or
221            self.array()):
222
223            return ( (1, 1, 0), (0, 1, 0), (0, 1, 0), (0, 0, 0) )[direction]
224
225        util.fatalError("T_var argmapping requested for type with no such "
226                        "concept")
227        return
228
229    def base(self, environment = None, gscope = 0):
230        """base(types.Type, id.Environment option): C++ type string
231           Returns a basic C++ mapped version of the type"""
232        kind = self.kind()
233        d_type = self.deref(1)
234        d_kind = d_type.kind()
235
236        # CORBA2.3 P1-15 1.5 Mapping for Basic Data Types
237        if kind in basic_map:
238            return basic_map[kind]
239        if self.string() or d_type.string():
240            return "char*"
241        if self.wstring() or d_type.wstring():
242            return "::CORBA::WChar*"
243        if self.typecode():
244            return "::CORBA::TypeCode_ptr"
245        if self.any():
246            return "::CORBA::Any"
247        if self.void():
248            return "void"
249        if self.fixed():
250            return "::CORBA::Fixed"
251        if self.sequence():
252            return self.sequenceTemplate(environment, gscope=gscope)
253
254        name = id.Name(self.type().scopedName()).unambiguous(environment)
255        if gscope:
256            assert environment is None
257            name = "::" + name
258
259        if d_type.interface() or d_type.typecode():
260            return name + "_ptr"
261        else:
262            return name
263
264    def __base_type_OUT(self, environment = None):
265        # ___base_type_OUT(types.Type, id.Environment option): special C++
266        #  OUT type
267        type = self.__type
268        d_type = self.deref()
269        d_kind = type.kind()
270        if d_kind in basic_map_out:
271            return basic_map_out[d_kind]
272        if d_type.string():
273            return "::CORBA::String_out"
274        if d_type.wstring():
275            return "::CORBA::WString_out"
276        if d_type.typecode():
277            return "::CORBA::TypeCode_OUT_arg"
278        if d_type.any():
279            return "::CORBA::Any_OUT_arg"
280        if d_type.sequence():
281            return Type(d_type.type().seqType()).__base_type_OUT(environment)
282
283        name = id.Name(type.scopedName())
284        uname = name.unambiguous(environment)
285
286        return uname + "_out"
287
288    def __base_type_INOUT(self, environment = None):
289        # __base_type_INOUT(types.Type): special C++ INOUT type string
290
291        d_type = self.deref()
292        kind = d_type.kind()
293        if d_type.string():
294            return "::CORBA::String_INOUT_arg"
295        if d_type.wstring():
296            return "::CORBA::WString_INOUT_arg"
297        if d_type.typecode():
298            return "::CORBA::TypeCode_INOUT_arg"
299        if d_type.any():
300            return "::CORBA::Any_INOUT_arg"
301
302        name = id.Name(self.type().scopedName())
303        uname = name.unambiguous(environment)
304
305        if d_type.interface():
306            name = id.Name(d_type.type().scopedName())
307
308            if d_type.objref():
309                objref_name = name.prefix("_objref_")
310            else:
311                objref_name = name
312
313            if d_type.type().scopedName() == ["CORBA", "Object"]:
314                return "::CORBA::Object_INOUT_arg"
315
316            return "_CORBA_ObjRef_INOUT_arg< " + objref_name.fullyQualify() + \
317                   ", " + name.unambiguous(environment) + "_Helper >"
318
319        if d_type.value() or d_type.valuebox():
320            name = id.Name(d_type.type().scopedName())
321            return "_CORBA_Value_INOUT_arg< " + name.fullyQualify() + \
322                   ", " + name.unambiguous(environment) + "_Helper >"
323
324        return uname + "_INOUT_arg"
325
326    def op(self, direction, environment = None, use_out = 1):
327        """op(types.Type, int direction, id.Environment option, use_out bool)
328           : C++ type argument mapping"""
329        type = Type(self.__type)
330        d_type = type.deref()
331
332        base = self.base(environment)
333
334        old_sig = config.state['Old Signatures']
335
336        # this is very superfluous:
337        if not self.array():
338            if d_type.any() and self.typedef() and not old_sig:
339                if direction == OUT:
340                    return d_type.__base_type_OUT(environment)
341
342
343            if d_type.typecode() and not old_sig:
344                if direction == OUT:
345                    return d_type.__base_type_OUT(environment)
346                elif direction == INOUT and use_out:
347                    return d_type.__base_type_INOUT(environment)
348                else:
349                    base = d_type.base(environment)
350
351
352        # Use the ObjRef template for non-arrays of objrefs rather than use
353        # the (equivalent?) _out type?
354        if not d_type.objref() or type.array():
355
356            # if its an out type and a typedef (to a variable type),
357            # use the predefined _out type
358            if type.typedef() and type.variable() and direction == OUT:
359
360                if (not d_type.string() or not d_type.wstring() or \
361                    (d_type.string() and type.array()) or \
362                    (d_type.wstring() and type.array())):
363
364                    base = id.Name(type.__type.scopedName()).unambiguous(environment)
365                    base = base + "_out"
366                    return base
367        # superfluous deref for a typedef to an objref
368        if d_type.objref() and not type.array():
369            base = d_type.base(environment)
370
371        # Deal with special cases ----------------------------------
372        if not self.array():
373
374            if direction == OUT and not use_out:
375                if d_type.string() and not old_sig:
376                    return self.__base_type_OUT(environment)
377                if d_type.wstring() and not old_sig:
378                    return self.__base_type_OUT(environment)
379                if d_type.interface() and not old_sig:
380                    return self.__base_type_OUT(environment)
381                if d_type.typecode() and not old_sig:
382                    return self.__base_type_OUT(environment)
383                if d_type.any() and not old_sig:
384                    return self.__base_type_OUT(environment)
385
386            if direction == OUT:
387                if d_type.string():
388                    return self.__base_type_OUT(environment)
389                if d_type.wstring():
390                    return self.__base_type_OUT(environment)
391                if d_type.typecode():
392                    return self.__base_type_OUT(environment)
393                if d_type.interface():
394                    return self.__base_type_OUT(environment)
395                if d_type.any() and (not old_sig or use_out):
396                    return self.__base_type_OUT(environment)
397                if d_type.variable() and (not old_sig or use_out):
398                    return self.__base_type_OUT(environment)
399
400            if direction == INOUT:
401                if d_type.string() and use_out:
402                    return self.__base_type_INOUT(environment)
403                if d_type.wstring() and use_out:
404                    return self.__base_type_INOUT(environment)
405                if d_type.typecode() and use_out:
406                    return self.__base_type_INOUT(environment)
407                if d_type.interface() and use_out:
408                    return self.__base_type_INOUT(environment)
409
410        if d_type.string() and not type.array():
411            base = d_type.base(environment)
412
413        if d_type.wstring() and not type.array():
414            base = d_type.base(environment)
415
416        # P1-104 mentions two cases: returning an array and a variable
417        # array out argument. For the latter rely on the _out type
418        if (type.array() and direction == RET):
419            base = base + "_slice"
420
421        mapping = self._argmapping(direction)
422
423        return self.__apply_mapping(mapping, base)
424
425    def member(self, environment = None, decl = None, gscope = 0):
426        """member(types.Type, id.Environment option, idlast.Declarator option):
427           C++ member type"""
428
429        if gscope:
430            assert environment is None
431
432        decl_dims = []
433        if decl != None:
434            assert isinstance(decl, idlast.Declarator)
435            decl_dims = decl.sizes()
436
437        is_array_declarator = decl_dims != []
438
439        if not self.array():
440            d_type = self.deref()
441            if d_type.string():
442                return "::CORBA::String_member"
443            if d_type.wstring():
444                return "::CORBA::WString_member"
445            if d_type.interface():
446                return d_type.objRefTemplate("Member", environment,
447                                             gscope=gscope)
448            if d_type.typecode():
449                return "::CORBA::TypeCode_member"
450
451            if self.sequence():
452                return d_type.sequenceTemplate(environment, gscope=gscope)
453
454            if self.value() or self.valuebox():
455                m = self.base(environment) + "_member"
456                if gscope: m = "::" + m
457                return m
458
459        if self.typedef():
460            # for the type to have dimensions, it must be a typedef
461            m = id.Name(self.__type.scopedName()).unambiguous(environment)
462            if gscope: m = "::" + m
463            return m
464
465        return self.base(environment, gscope=gscope)
466
467    def objRefTemplate(self, suffix, environment = None, gscope = 0):
468        """objRefTemplate(types.Type, suffix string, id.Environment option):
469           Returns a template objref instance for the current type"""
470        type = self.deref().__type
471        name = type.decl().scopedName()
472        if name == ["CORBA", "Object"]:
473            return "::CORBA::Object_" + suffix
474
475        name = id.Name(name)
476        uname = name.unambiguous(environment)
477        if self.objref():
478            objref_name = name.prefix("_objref_")
479            objref_uname = objref_name.unambiguous(environment)
480        else:
481            objref_uname = uname
482
483        if gscope:
484            uname = "::" + uname
485            objref_uname = "::" + objref_uname
486
487        return "_CORBA_ObjRef_" + suffix + \
488               "< " + objref_uname + ", " + uname + "_Helper> "
489
490    def valueTemplate(self, suffix, environment = None, gscope = 0):
491        """valueTemplate(types.Type, suffix string, id.Environment option):
492           Returns a template value instance for the current type"""
493        type = self.deref().__type
494        name = type.decl().scopedName()
495        name = id.Name(name)
496        uname = name.unambiguous(environment)
497        if gscope:
498            uname = "::" + uname
499
500        return "_CORBA_Value_%s< %s, %s > " % (suffix, uname,
501                                               uname + "_Helper")
502
503    def literal(self, value, environment = None):
504        """literal(types.Type, value any, id.Environment option): string
505           Returns a C++ representation of a value"""
506
507        type = self.deref()
508        kind = type.__type.kind()
509
510        # (unsigned) short ints are themselves
511        if kind in [ idltype.tk_short, idltype.tk_ushort ]:
512            return str(value)
513
514        # careful with long ints to avoid "L" postfix
515        if kind in [ idltype.tk_long, idltype.tk_ulong ]:
516            s = str(value)
517            if s[-1] == 'L':             s = s[0:-1]
518            if kind == idltype.tk_ulong: s = s + "U"
519            return s
520
521        if kind in [ idltype.tk_longlong, idltype.tk_ulonglong ]:
522            s = str(value)
523            if s[-1] == 'L':                 s = s[:-1]
524            if kind == idltype.tk_ulonglong: s = s + "U"
525            return "_CORBA_LONGLONG_CONST(" + s + ")"
526
527        if kind in [ idltype.tk_float ]:
528            return idlutil.reprFloat(value) + "F"
529
530        if kind in [ idltype.tk_double ]:
531            return idlutil.reprFloat(value)
532
533        if kind in [ idltype.tk_longdouble ]:
534            return idlutil.reprFloat(value) + "L"
535
536        # chars are single-quoted
537        if kind in [ idltype.tk_char ]:
538            return "'" + idlutil.escapifyString(value) + "'"
539
540        if kind in [ idltype.tk_wchar ]:
541            return "L'" + idlutil.escapifyWString([value], "x") + "'"
542
543        # booleans are straightforward
544        if kind in [ idltype.tk_boolean ]:
545            return str(value)
546
547        if kind in [ idltype.tk_enum ]:
548            # value is an enumerator
549            enum_name = id.Name(value.scopedName())
550            #enum_name = id.Name(type.__type.decl().scopedName() + [str(value)])
551            return enum_name.unambiguous(environment)
552
553        if kind in [ idltype.tk_string ]:
554            return '"' + idlutil.escapifyString(value) + '"'
555
556        if kind in [ idltype.tk_wstring ]:
557            return 'L"' + idlutil.escapifyWString(value, "x") + '"'
558
559        if kind in [ idltype.tk_octet ]:
560            return str(value)
561
562        if kind in [ idltype.tk_fixed ]:
563            return '"' + value + '"'
564
565        util.fatalError("Internal error when handling value (" +\
566                        repr(value) +")" )
567
568    def sequenceTemplate(self, environment = None, gscope = 0):
569        """sequenceTemplate(types.Type, id.Environment option): C++ template
570           Returns a C++ template instance for the current type as a
571           sequence"""
572        # returns a template instantiation suitable for the
573        # sequence type
574        sequence = self.__type
575        assert isinstance(sequence, idltype.Sequence)
576
577        SeqType = Type(sequence.seqType())
578        d_SeqType = SeqType.deref()
579        SeqTypeID = SeqType.base(environment, gscope=gscope)
580        d_SeqTypeID = d_SeqType.base(environment, gscope=gscope)
581        if d_SeqType.typecode():
582            d_SeqTypeID = "::CORBA::TypeCode_member"
583            SeqTypeID = "::CORBA::TypeCode_member"
584        elif d_SeqType.interface():
585            d_SeqTypeID = d_SeqTypeID.replace("_ptr","")
586            SeqTypeID = SeqTypeID.replace("_ptr","")
587        elif d_SeqType.string():
588            d_SeqTypeID = "::CORBA::String_member"
589        elif d_SeqType.wstring():
590            d_SeqTypeID = "::CORBA::WString_member"
591
592        if SeqType.string():
593            SeqTypeID = "::CORBA::String_member"
594
595        if SeqType.wstring():
596            SeqTypeID = "::CORBA::WString_member"
597
598        # silly special case (not needed?):
599        #if d_SeqType.objref() and SeqType.typedef():
600        #    SeqTypeID = id.Name(SeqType.type().scopedName()).\
601        #                unambiguous(environment)
602
603        seq_dims = SeqType.dims()
604        is_array = seq_dims != []
605        dimension = reduce(lambda x,y: x * y, seq_dims, 1)
606
607        template = {}
608        template["bounded"]   = sequence.bound()
609        template["array"]     = is_array
610        template["dimension"] = dimension
611
612        template["seqTypeID"] = SeqTypeID
613        template["derefSeqTypeID"] = d_SeqTypeID
614
615        # if the seqType is a typedef to a sequence, use the typedef name
616        # else if a direct sequence<sequence<...., do recursion
617        if d_SeqType.sequence() and not SeqType.typedef():
618            element_template = d_SeqType.sequenceTemplate(environment)
619            template["seqTypeID"] = element_template
620            template["derefSeqTypeID"] = element_template
621
622        if is_array:
623            if d_SeqType.sequence():
624                template["derefSeqTypeID"] = d_SeqType.\
625                                             sequenceTemplate(environment)
626
627        if d_SeqType.char():
628            template["suffix"] = "_Char"
629        elif d_SeqType.wchar():
630            template["suffix"] = "_WChar"
631        elif d_SeqType.boolean():
632            template["suffix"] = "_Boolean"
633        elif d_SeqType.octet():
634            template["suffix"] = "_Octet"
635            # strings are always special
636        elif d_SeqType.string() and not is_array:
637            template["suffix"] = "_String"
638        elif d_SeqType.wstring() and not is_array:
639            template["suffix"] = "_WString"
640        elif d_SeqType.structforward() or d_SeqType.unionforward():
641            template["forward"] = 1
642        elif d_SeqType.type().kind() in typeSizeAlignMap:
643            template["fixed"] = typeSizeAlignMap[d_SeqType.type().kind()]
644        elif d_SeqType.interface():
645            scopedName = d_SeqType.type().decl().scopedName()
646            is_CORBA_Object = scopedName == ["CORBA", "Object"]
647            scopedName = id.Name(scopedName)
648
649            if not is_CORBA_Object and d_SeqType.objref():
650                # CORBA::Object doesn't have an _objref_xxx
651                scopedName = scopedName.prefix("_objref_")
652
653            objref_name = scopedName.unambiguous(environment)
654
655            if not is_array:
656                objref_template = d_SeqType.objRefTemplate("Element", environment)
657            else:
658                objref_template = d_SeqType.objRefTemplate("Member", environment)
659            template["objref_name"]     = objref_name
660            template["objref_template"] = objref_template
661            template["objref_helper"]   = SeqTypeID + "_Helper"
662            template["objref"]          = 1
663
664        elif d_SeqType.value() or d_SeqType.valuebox():
665            scopedName = d_SeqType.type().decl().scopedName()
666            scopedName = id.Name(scopedName)
667
668            value_name = scopedName.unambiguous(environment)
669
670            if not is_array:
671                value_template = d_SeqType.valueTemplate("Element", environment)
672            else:
673                value_template = d_SeqType.valueTemplate("Member", environment)
674
675            template["value_name"]     = value_name
676            template["value_template"] = value_template
677            template["value_helper"]   = SeqTypeID + "_Helper"
678            template["value"]          = 1
679
680        return self.__templateToString(template)
681
682    # converts a hash of template properties into a template instance
683    def __templateToString(self, template):
684        # ------------------------------------
685        # work out the template name
686        if template["bounded"]:
687            name = "_CORBA_Bounded_Sequence"
688        else:
689            name = "_CORBA_Unbounded_Sequence"
690
691        if template["array"]:
692            name = name + "_Array"
693
694        if "suffix" in template:
695            name = name + template["suffix"]
696
697        if "forward" in template:
698            name = name + "_Forward"
699
700        elif "objref" in template and not template["array"]:
701            name = name + "_ObjRef"
702
703        elif "value" in template and not template["array"]:
704            name = name + "_Value"
705
706        if "fixed" in template:
707            name = name + "_w_FixSizeElement"
708
709        # ------------------------------------
710        # build the argument list
711        args = []
712
713        seqTypeID      = template["seqTypeID"]
714        derefSeqTypeID = template["derefSeqTypeID"]
715        dimension      = template["dimension"]
716
717        # Note the difference between an ObjRef and an array of ObjRefs
718        if template["array"]:
719            args.extend([seqTypeID, seqTypeID + "_slice"])
720
721            if "objref" in template:
722                args.append(template["objref_template"])
723
724            elif "value" in template:
725                args.append(template["value_template"])
726
727            elif "suffix" not in template:
728                # __Boolean __Octet __String
729                # these already contain the type info- no need for another
730                # parameter...
731                args.append(derefSeqTypeID)
732
733            args.append(str(dimension))
734
735        elif "objref" in template:
736            args.extend([template["objref_name"],
737                         template["objref_template"],
738                         template["objref_helper"]])
739
740        elif "value" in template:
741            args.extend([template["value_name"],
742                         template["value_template"],
743                         template["value_helper"]])
744
745        elif "suffix" not in template:
746            # see above
747            args.append(seqTypeID)
748
749        if "bounded" in template and \
750           template["bounded"]:
751            args.append(str(template["bounded"]))
752
753        if "fixed" in template:
754            (element_size, alignment) = template["fixed"]
755            args.extend([str(element_size), str(alignment)])
756
757        # -----------------------------------
758        # build the template instance
759        if args:
760            name = name + "< " + ", ".join(args) + " > "
761            return name
762
763        return name
764
765    def _var(self, environment = None):
766        """Returns a representation of the type which is responsible for its
767           own destruction. Assigning a heap allocated thing to this type
768           should allow the user to forget about deallocation."""
769        d_T = self.deref()
770
771        if self.array() or d_T.struct()    or d_T.union() or \
772                           d_T.exception() or d_T.sequence() or \
773                           d_T.interface() or d_T.value() or \
774                           d_T.valuebox():
775            name = id.Name(self.type().decl().scopedName()).suffix("_var")
776            return name.unambiguous(environment)
777
778        if d_T.typecode(): return "::CORBA::TypeCode_var"
779        if d_T.any():      return "::CORBA::Any_var"
780        if d_T.string():   return "::CORBA::String_var"
781        if d_T.wstring():  return "::CORBA::WString_var"
782        if d_T.enum():
783            name = id.Name(self.type().decl().scopedName())
784            return name.unambiguous(environment)
785
786        if self.is_basic_data_types():
787            return basic_map[d_T.kind()]
788
789        if d_T.void():
790            raise NotImplementedError("No such thing as a void _var type")
791
792        raise AssertionError("Unknown _var type, kind = " + str(d_T.kind()))
793
794    def out(self, ident):
795        if self.is_basic_data_types():
796            return ident
797
798        return ident + ".out()"
799
800    def free(self, thing, environment = None):
801        """Ensures that any heap allocated storage associated with this type
802           has been deallocated."""
803
804        if self.array():
805            name = id.Name(self.type().decl().scopedName()).suffix("_free")
806            return name.unambiguous(environment) + "(" + thing + ");"
807
808        d_T = self.deref()
809
810        if d_T.interface() or d_T.typecode():
811            return "::CORBA::release(" + thing + ");"
812        if d_T.string():   return "::CORBA::string_free(" + thing + ");"
813
814        if d_T.wstring():   return "::CORBA::wstring_free(" + thing + ");"
815
816        if d_T.struct() or d_T.union() or d_T.exception() or \
817           d_T.sequence() or d_T.any():
818            if d_T.variable():
819                return "delete " + thing + ";"
820            return "" # stored by value
821
822        if d_T.enum() or d_T.void() or (self.is_basic_data_types()):
823            return ""
824
825        raise AssertionError("Don't know how to free type, kind = " +
826                             str(d_T.kind()))
827
828    def copy(self, src, dest, environment = None):
829        """Copies an entity from src to dest"""
830
831        if self.array():
832            name = id.Name(self.type().decl().scopedName()).suffix("_dup")
833            return dest + " = " + name.unambiguous(environment) + "("+src+");"
834
835        d_T = self.deref()
836        if d_T.typecode():
837            return dest + " = ::CORBA::TypeCode::_duplicate(" + src + ");"
838        if d_T.interface():
839            # Use the internal omniORB duplicate function in case the
840            # normal one isn't available
841            name = id.Name(self.type().decl().scopedName()).suffix("_Helper")
842            return name.unambiguous(environment) + "::duplicate" +\
843                   "(" + src + ");\n" + dest + " = " + src + ";"
844        if d_T.string():
845            return dest + " = ::CORBA::string_dup(" + src + ");"
846        if d_T.wstring():
847            return dest + " = ::CORBA::wstring_dup(" + src + ");"
848        if d_T.any():
849            return dest + " = new ::CORBA::Any(" + src + ");"
850
851        if d_T.struct() or d_T.union() or d_T.exception() or d_T.sequence():
852            name = id.Name(self.type().decl().scopedName()).\
853                   unambiguous(environment)
854            if d_T.variable():
855                return dest + " = new " + name + "(" + src + ");"
856            return dest + " = " + src + ";"
857
858        if d_T.enum() or self.is_basic_data_types():
859            return dest + " = " + src + ";"
860
861        raise AssertionError("Don't know how to copy type, kind = " +
862                             str(d_T.kind()))
863
864    def representable_by_int(self):
865        """representable_by_int(types.Type): boolean
866           Returns true if the type is representable by an integer"""
867        return self.integer() or self.char() or self.boolean() or self.octet()
868
869    def is_basic_data_types(self):
870        d_T = self.deref()
871        return d_T.kind() in basic_map
872
873    def integer(self):
874        type = self.__type
875        return type.kind() in [ idltype.tk_short, idltype.tk_long,
876                                idltype.tk_longlong, idltype.tk_ushort,
877                                idltype.tk_ulong, idltype.tk_ulonglong ]
878    def char(self):
879        type = self.__type
880        return type.kind() == idltype.tk_char
881
882    def wchar(self):
883        type = self.__type
884        return type.kind() == idltype.tk_wchar
885
886    def floating(self):
887        type = self.__type
888        return type.kind() in [ idltype.tk_float, idltype.tk_double ]
889
890    def float(self):
891        type = self.__type
892        return type.kind() == idltype.tk_float
893
894    def double(self):
895        type = self.__type
896        return type.kind() == idltype.tk_double
897
898    def boolean(self):
899        type = self.__type
900        return type.kind() == idltype.tk_boolean
901
902    def enum(self):
903        type = self.__type
904        return type.kind() == idltype.tk_enum
905
906    def octet(self):
907        type = self.__type
908        return type.kind() == idltype.tk_octet
909
910    def string(self):
911        type = self.__type
912        return type.kind() == idltype.tk_string
913
914    def wstring(self):
915        type = self.__type
916        return type.kind() == idltype.tk_wstring
917
918    def objref(self):
919        type = self.__type
920        return type.kind() == idltype.tk_objref
921
922    def sequence(self):
923        type = self.__type
924        return type.kind() == idltype.tk_sequence
925
926    def typecode(self):
927        type = self.__type
928        return type.kind() == idltype.tk_TypeCode
929
930    def typedef(self):
931        type = self.__type
932        return type.kind() == idltype.tk_alias
933
934    def struct(self):
935        type = self.__type
936        return type.kind() == idltype.tk_struct
937
938    def structforward(self):
939        type = self.__type
940        return type.kind() == idltype.ot_structforward
941
942    def union(self):
943        type = self.__type
944        return type.kind() == idltype.tk_union
945
946    def unionforward(self):
947        type = self.__type
948        return type.kind() == idltype.ot_unionforward
949
950    def exception(self):
951        type = self.__type
952        return type.kind() == idltype.tk_except
953
954    def void(self):
955        type = self.__type
956        return type.kind() == idltype.tk_void
957
958    def any(self):
959        type = self.__type
960        return type.kind() == idltype.tk_any
961
962    def fixed(self):
963        type = self.__type
964        return type.kind() == idltype.tk_fixed
965
966    def value(self):
967        type = self.__type
968        return type.kind() == idltype.tk_value
969
970    def valuebox(self):
971        type = self.__type
972        return type.kind() == idltype.tk_value_box
973
974    def abstract_interface(self):
975        type = self.__type
976        return type.kind() == idltype.tk_abstract_interface
977
978    def local_interface(self):
979        type = self.__type
980        return type.kind() == idltype.tk_local_interface
981
982    def interface(self):
983        type = self.__type
984        return type.kind() in [ idltype.tk_objref,
985                                idltype.tk_abstract_interface,
986                                idltype.tk_local_interface ]
987
988
989def variableDecl(decl):
990    """types.variableDecl(idlast.Decl): boolean
991        Returns true if the declaration represents a variable type"""
992    # interfaces are mapped to objects, which are always
993    # variable types. same goes for exceptions.
994    if isinstance(decl, idlast.Interface)       or \
995       isinstance(decl, idlast.Forward)         or \
996       isinstance(decl, idlast.Exception):
997        return 1
998    elif isinstance(decl, idlast.Const)         or \
999         isinstance(decl, idlast.Enum):
1000        return 0
1001
1002    # a typedef is only a type alias- as such it has no storage
1003    # at all. However it eventually points to something that would.
1004    elif isinstance(decl, idlast.Typedef):
1005        return Type(decl.aliasType()).variable()
1006
1007    # a structure is variable if any one of its constituents
1008    # is also variable
1009    elif isinstance(decl, idlast.Struct):
1010        for m in decl.members():
1011            if Type(m.memberType()).variable():
1012                return 1
1013        return 0
1014
1015    # a union is variable if any one if its constituents
1016    # is also variable
1017    elif isinstance(decl, idlast.Union):
1018        for c in decl.cases():
1019            if Type(c.caseType()).variable():
1020                return 1
1021        return 0
1022
1023    # a declarator is variable if it is an alias to a variable
1024    # type
1025    elif isinstance(decl, idlast.Declarator) and \
1026         decl.alias() != None:
1027        return Type(decl.alias().aliasType()).variable()
1028
1029    util.fatalError("Unknown AST node, scopedName = " +repr(decl.scopedName()))
1030
1031
1032
1033
1034def direction(param):
1035    if param.is_in() and param.is_out():
1036        return INOUT
1037    elif param.is_in():
1038        return IN
1039    elif param.is_out():
1040        return OUT
1041
1042    # Top 12 things likely to be overheard from a Klingon Programmer:
1043    # ...
1044    #
1045    #   7) "Klingon function calls do not have 'parameters' - they
1046    #       have 'arguments' - and they ALWAYS WIN THEM."
1047    # ...
1048
1049    util.fatalError("Illegal parameter direction")
1050
1051
1052#################################################################
1053# Tables of useful data ripped from the CORBA spec
1054
1055# already_Variable maps typecode kinds onto true/ false
1056#
1057# An entry in this table indicates we already know is a type is
1058# variable or not, without having to look at its declaration.
1059# (note that eg structs and unions are only variable if one of
1060#  their members are)
1061
1062# CORBA2.3 P1-21 1.9 Mapping for Structured Types
1063already_Variable = {
1064    idltype.tk_null:               0,
1065    idltype.tk_void:               0,
1066    idltype.tk_short:              0,
1067    idltype.tk_long:               0,
1068    idltype.tk_ushort:             0,
1069    idltype.tk_ulong:              0,
1070    idltype.tk_float:              0,
1071    idltype.tk_double:             0,
1072    idltype.tk_boolean:            0,
1073    idltype.tk_char:               0,
1074    idltype.tk_octet:              0,
1075    idltype.tk_any:                1,
1076    idltype.tk_objref:             1,
1077    idltype.tk_string:             1,
1078    idltype.tk_sequence:           1,
1079    idltype.tk_except:             1,
1080    idltype.tk_longlong:           0,
1081    idltype.tk_ulonglong:          0,
1082    idltype.tk_longdouble:         0,
1083    idltype.tk_wchar:              0,
1084    idltype.tk_wstring:            1,
1085    idltype.tk_fixed:              0,
1086    idltype.tk_value:              1,
1087    idltype.tk_value_box:          1,
1088    idltype.tk_abstract_interface: 1,
1089    idltype.tk_TypeCode:           1,
1090    idltype.tk_local_interface:    1,
1091    }
1092
1093# CORBA2.3 P1-15 1.5 Mapping for Basic Data Types
1094basic_map = {
1095    idltype.tk_short:              "::CORBA::Short",
1096    idltype.tk_long:               "::CORBA::Long",
1097    idltype.tk_longlong:           "::CORBA::LongLong",
1098    idltype.tk_ushort:             "::CORBA::UShort",
1099    idltype.tk_ulong:              "::CORBA::ULong",
1100    idltype.tk_ulonglong:          "::CORBA::ULongLong",
1101    idltype.tk_float:              "::CORBA::Float",
1102    idltype.tk_double:             "::CORBA::Double",
1103    idltype.tk_longdouble:         "::CORBA::LongDouble",
1104    idltype.tk_char:               "::CORBA::Char",
1105    idltype.tk_wchar:              "::CORBA::WChar",
1106    idltype.tk_boolean:            "::CORBA::Boolean",
1107    idltype.tk_octet:              "::CORBA::Octet"
1108    }
1109basic_map_out = { }
1110for key,value in list(basic_map.items()):
1111    basic_map_out[key] = value + "_out"
1112
1113
1114# Info on size and alignment of basic types
1115typeSizeAlignMap = {
1116    idltype.tk_char:      (1, 1),
1117    idltype.tk_boolean:   (1, 1),
1118    idltype.tk_wchar:     (2, 2),
1119    idltype.tk_short:     (2, 2),
1120    idltype.tk_ushort:    (2, 2),
1121    idltype.tk_long:      (4, 4),
1122    idltype.tk_ulong:     (4, 4),
1123    idltype.tk_float:     (4, 4),
1124    idltype.tk_enum:      (4, 4),
1125    idltype.tk_double:    (8, 8),
1126    idltype.tk_octet:     (1, 1),
1127    idltype.tk_longlong:  (8, 8),
1128    idltype.tk_ulonglong: (8, 8)
1129    }
1130