File: Synopsis/Parsers/IDL/idltype.py
  1# -*- python -*-
  2#                           Package   : omniidl
  3# idltype.py                Created on: 1999/10/27
  4#			    Author    : Duncan Grisby (dpg1)
  5#
  6#    Copyright (C) 1999 AT&T Laboratories Cambridge
  7#
  8#  This file is part of omniidl.
  9#
 10#  omniidl is free software; you can redistribute it and/or modify it
 11#  under the terms of the GNU General Public License as published by
 12#  the Free Software Foundation; either version 2 of the License, or
 13#  (at your option) any later version.
 14#
 15#  This program is distributed in the hope that it will be useful,
 16#  but WITHOUT ANY WARRANTY; without even the implied warranty of
 17#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 18#  General Public License for more details.
 19#
 20#  You should have received a copy of the GNU General Public License
 21#  along with this program; if not, write to the Free Software
 22#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 23#  02111-1307, USA.
 24#
 25# Description:
 26#   
 27#   IDL type representation
 28
 29"""Definitions for IDL type representation
 30
 31Classes:
 32
 33  Type     -- abstract base class.
 34  Base     -- class for CORBA base types.
 35  String   -- class for string types.
 36  WString  -- class for wide string types.
 37  Sequence -- class for sequence types.
 38  Fixed    -- class for fixed-point types.
 39  Declared -- class for declared types.
 40
 41TypeCode kind constants:
 42
 43  tk_null, tk_void, tk_short, tk_long, tk_ushort, tk_ulong, tk_float,
 44  tk_double, tk_boolean, tk_char, tk_octet, tk_any, tk_TypeCode,
 45  tk_Principal, tk_objref, tk_struct, tk_union, tk_enum, tk_string,
 46  tk_sequence, tk_array, tk_alias, tk_except, tk_longlong,
 47  tk_ulonglong, tk_longdouble, tk_wchar, tk_wstring, tk_fixed,
 48  tk_value, tk_value_box, tk_native, tk_abstract_interface"""
 49
 50import idlutil
 51
 52tk_null               = 0
 53tk_void               = 1
 54tk_short              = 2
 55tk_long               = 3
 56tk_ushort             = 4
 57tk_ulong              = 5
 58tk_float              = 6
 59tk_double             = 7
 60tk_boolean            = 8
 61tk_char               = 9
 62tk_octet              = 10
 63tk_any               = 11
 64tk_TypeCode           = 12
 65tk_Principal          = 13
 66tk_objref             = 14
 67tk_struct             = 15
 68tk_union              = 16
 69tk_enum               = 17
 70tk_string             = 18
 71tk_sequence           = 19
 72tk_array              = 20
 73tk_alias              = 21
 74tk_except             = 22
 75tk_longlong           = 23
 76tk_ulonglong          = 24
 77tk_longdouble         = 25
 78tk_wchar              = 26
 79tk_wstring            = 27
 80tk_fixed              = 28
 81tk_value              = 29
 82tk_value_box          = 30
 83tk_native             = 31
 84tk_abstract_interface = 32
 85tk_local_interface    = 33
 86
 87# Non-standard kinds for forward-declared structs and unions
 88ot_structforward      = 100
 89ot_unionforward       = 101
 90
 91
 92class Error:
 93    """Exception class used by IdlType internals."""
 94
 95    def __init__(self, err):
 96        self.err = err
 97
 98    def __repr__(self):
 99        return self.err
100
101
102class Type:
103    """Type abstract class.
104
105Function:
106
107  kind()          -- TypeCode kind of type.
108  unalias()       -- Return an equivalent Type object with aliases stripped
109  accept(visitor) -- visitor pattern accept. See idlvisitor.py."""
110
111    def __init__(self, kind, local):
112        self.__kind  = kind
113        self.__local = local
114
115    def kind(self):            return self.__kind
116    def local(self):           return self.__local
117
118    def unalias(self):
119        type = self
120        while type.kind() == tk_alias:
121            if len(type.decl().sizes()) > 0:
122                return type
123            type = type.decl().alias().aliasType()
124        return type
125
126    def accept(self, visitor): pass
127
128
129# Base types
130class Base (Type):
131    """Class for CORBA base types. (Type)
132
133No non-inherited functions."""
134
135    def __init__(self, kind):
136        if kind not in [tk_null, tk_void, tk_short, tk_long, tk_ushort,
137                        tk_ulong, tk_float, tk_double, tk_boolean,
138                        tk_char, tk_octet, tk_any, tk_TypeCode,
139                        tk_Principal, tk_longlong, tk_ulonglong,
140                        tk_longdouble, tk_wchar]:
141
142            raise Error("Attempt to create Base type with invalid kind.")
143
144        Type.__init__(self, kind, 0)
145
146    def accept(self, visitor): visitor.visitBaseType(self)
147
148
149# Strings can be used like base types without a declaration. eg:
150#
151#   void op(in string<10> s);
152#
153# therefore, the String type must include its bound here, rather than
154# relying on looking at the corresponding declaration
155
156class String (Type):
157    """Class for string types (Type)
158
159Function:
160
161  bound() -- bound of bounded string. 0 for unbounded."""
162
163    def __init__(self, bound):
164        Type.__init__(self, tk_string, 0)
165        self.__bound = bound
166
167    def accept(self, visitor): visitor.visitStringType(self)
168    def bound(self): return self.__bound
169
170class WString (Type):
171    """Class for wide string types (Type)
172
173Function:
174
175  bound() -- bound of bounded wstring. 0 for unbounded."""
176
177    def __init__(self, bound):
178        Type.__init__(self, tk_wstring, 0)
179        self.__bound = bound
180
181    def accept(self, visitor): visitor.visitWStringType(self)
182    def bound(self): return self.__bound
183
184
185# Sequences are never declared. They either appear as
186#
187#   typedef sequence <...> ...
188#
189# or inside a struct, union, or valuetype
190
191class Sequence (Type):
192    """Class for sequence types (Type)
193
194Functions:
195
196  seqType() -- Type this is a sequence of.
197  bound()   -- bound of bounded sequence. 0 for unbounded."""
198
199    def __init__(self, seqType, bound, local):
200        Type.__init__(self, tk_sequence, local)
201        self.__seqType = seqType
202        self.__bound   = bound
203
204    def accept(self, visitor): visitor.visitSequenceType(self)
205    def seqType(self): return self.__seqType
206    def bound(self):   return self.__bound
207
208
209# Same goes for fixed
210
211class Fixed (Type):
212    """Class for fixed point types (Type)
213
214Functions:
215
216  digits() -- digits.
217  scale()  -- scale."""
218
219    def __init__(self, digits, scale):
220        Type.__init__(self, tk_fixed, 0)
221        self.__digits = digits
222        self.__scale  = scale
223
224    def accept(self, visitor): visitor.visitFixedType(self)
225    def digits(self): return self.__digits
226    def scale(self):  return self.__scale
227
228
229# All other types must be declared, at least implicitly, so they have
230# an associated declaration object
231
232class Declared (Type):
233    """Class for declared types (Type)
234
235Functions:
236
237  decl()       -- Decl object which corresponds to this type.
238  scopedName() -- Fully scoped name of the type as a list of strings.
239  name()       -- Simple name of the type."""
240
241    def __init__(self, decl, scopedName, kind, local):
242        if kind not in [tk_objref, tk_struct, tk_union, tk_enum,
243                        tk_array, tk_alias, tk_except, tk_value,
244                        tk_value_box, tk_native, tk_abstract_interface,
245                        tk_local_interface, ot_structforward,
246                        ot_unionforward]:
247
248            raise Error("Attempt to create Declared type with invalid kind.")
249
250        Type.__init__(self, kind, local)
251        self.__decl       = decl
252        self.__scopedName = scopedName
253
254    def accept(self, visitor): visitor.visitDeclaredType(self)
255
256    # Decl object where the type was declared.
257    def decl(self):       return self.__decl
258
259    # List containing scoped name:
260    def scopedName(self): return self.__scopedName
261
262    # Simple name
263    def name(self):       return self.__scopedName[-1]
264
265
266def containsValueType(t, track=None):
267    """Returns true if the type contains valuetypes"""
268
269    import idlast
270
271    if track is None:
272        track = {}
273
274    if track.has_key(id(t)):
275        return 0
276    track[id(t)] = None
277
278    if isinstance(t, Sequence):
279        return containsValueType(t.seqType(), track)
280
281    if isinstance(t, Declared):
282        d = t.decl()
283
284        if isinstance(d, idlast.Declarator):
285            alias = d.alias()
286            if alias:
287                return containsValueType(alias.aliasType(), track)
288
289        if isinstance(d, idlast.Struct):
290            for m in d.members():
291                if containsValueType(m.memberType(), track):
292                    return 1
293
294        if isinstance(d, idlast.Union):
295            for c in d.cases():
296                if containsValueType(c.caseType(), track):
297                    return 1
298
299        if isinstance(d, idlast.ValueAbs):
300            return 1
301
302        if isinstance(d, idlast.Value):
303            return 1
304
305        if isinstance(d, idlast.ValueBox):
306            return 1
307
308        if isinstance(d, idlast.Interface) and d.abstract():
309            return 1
310
311    return 0
312
313
314# Map of singleton Base Type objects
315baseTypeMap = {
316    tk_null:       Base(tk_null),
317    tk_void:       Base(tk_void),
318    tk_short:      Base(tk_short),
319    tk_long:       Base(tk_long),
320    tk_ushort:     Base(tk_ushort),
321    tk_ulong:      Base(tk_ulong),
322    tk_float:      Base(tk_float),
323    tk_double:     Base(tk_double),
324    tk_boolean:    Base(tk_boolean),
325    tk_char:       Base(tk_char),
326    tk_octet:      Base(tk_octet),
327    tk_any:        Base(tk_any),
328    tk_TypeCode:   Base(tk_TypeCode),
329    tk_Principal:  Base(tk_Principal),
330    tk_longlong:   Base(tk_longlong),
331    tk_ulonglong:  Base(tk_ulonglong),
332    tk_longdouble: Base(tk_longdouble),
333    tk_wchar:      Base(tk_wchar)
334    }
335
336# Maps of String and WString Type objects, indexed by bound
337stringTypeMap =  { 0: String(0) }
338wstringTypeMap = { 0: WString(0) }
339
340# Map of Sequence Type objects, indexed by (type object,bound)
341sequenceTypeMap = {}
342
343# Map of Fixed Type objects, indexed by (digits,scale)
344fixedTypeMap = {}
345
346# Map of declared type objects, indexed by stringified scoped name
347declaredTypeMap = {}
348
349
350# Private functions to create or return existing Type objects
351def baseType(kind):
352    return baseTypeMap[kind]
353
354def stringType(bound):
355    try:
356        return stringTypeMap[bound]
357    except KeyError:
358        st = String(bound)
359        stringTypeMap[bound] = st
360        return st
361
362def wstringType(bound):
363    try:
364        return wstringTypeMap[bound]
365    except KeyError:
366        wst = WString(bound)
367        wstringTypeMap[bound] = wst
368        return wst
369
370def sequenceType(type_spec, bound, local):
371    try:
372        return sequenceTypeMap[(type_spec,bound)]
373    except KeyError:
374        st = Sequence(type_spec, bound, local)
375        sequenceTypeMap[(type_spec,bound)] = st
376        return st
377
378def fixedType(digits, scale):
379    try:
380        return fixedTypeMap[(digits,scale)]
381    except KeyError:
382        ft = Fixed(digits, scale)
383        fixedTypeMap[(digits,scale)] = ft
384        return ft
385
386def declaredType(decl, scopedName, kind, local):
387    sname = idlutil.slashName(scopedName)
388    if declaredTypeMap.has_key(sname):
389        dt = declaredTypeMap[sname]
390        if dt.kind() == kind:
391            return dt
392    dt = Declared(decl, scopedName, kind, local)
393    declaredTypeMap[sname] = dt
394    return dt
395
396def clear():
397    """Clear back-end structures ready for another run"""
398    stringTypeMap.clear()
399    wstringTypeMap.clear()
400    sequenceTypeMap.clear()
401    fixedTypeMap.clear()
402    declaredTypeMap.clear()
403