Synopsis - Synopsis/Parsers/IDL/omni.py

File: Synopsis/Parsers/IDL/omni.py

      1#
      2# Copyright (C) 2000 Stefan Seefeld
      3# All rights reserved.
      4# Licensed to the public under the terms of the GNU LGPL (>= 2),
      5# see the file COPYING for details.
      6#
      7
      8from Synopsis import IR, ASG
      9from Synopsis.QualifiedName import QualifiedCxxName as QName
     10from Synopsis.SourceFile import *
     11import idlast, idltype, idlvisitor, idlutil
     12import _omniidl
     13import sys, getopt, os, os.path, string, types
     14
     15sourcefile = None
     16
     17def strip_filename(filename):
     18   "This is aliased as strip if -b used and basename set"
     19
     20   if len(basename) > len(filename): return filename
     21   if filename[:len(basename)] == basename:
     22      return filename[len(basename):]
     23   return filename
     24
     25class TypeTranslator(idlvisitor.TypeVisitor):
     26   """maps idltype objects to ASG.TypeId objects in a ASG.Dictionary"""
     27
     28   def __init__(self, types):
     29      self.types = types
     30      self.__result = None
     31      self.__basetypes = {idltype.tk_void:       QName(('void',)),
     32                          idltype.tk_short:      QName(('short',)),
     33                          idltype.tk_long:       QName(('long',)),
     34                          idltype.tk_ushort:     QName(('unsigned short',)),
     35                          idltype.tk_ulong:      QName(('unsigned long',)),
     36                          idltype.tk_float:      QName(('float',)),
     37                          idltype.tk_double:     QName(('double',)),
     38                          idltype.tk_boolean:    QName(('boolean',)),
     39                          idltype.tk_char:       QName(('char',)),
     40                          idltype.tk_octet:      QName(('octet',)),
     41                          idltype.tk_any:        QName(('any',)),
     42                          idltype.tk_TypeCode:   QName(('CORBA','TypeCode',)),
     43                          idltype.tk_Principal:  QName(('CORBA','Principal',)),
     44                          idltype.tk_longlong:   QName(('long long',)),
     45                          idltype.tk_ulonglong:  QName(('unsigned long long',)),
     46                          idltype.tk_longdouble: QName(('long double',)),
     47                          idltype.tk_wchar:      QName(('wchar',))}
     48
     49   def internalize(self, idltype):
     50
     51      idltype.accept(self)
     52      return self.__result
     53
     54   def has_key(self, name): return self.types.has_key(name)
     55
     56   def add(self, name, type):
     57      self.types[name] = type
     58
     59   def get(self, name):
     60      return self.types[name]
     61
     62   def visitBaseType(self, idltype):
     63
     64      type = ASG.BuiltinTypeId('IDL', self.__basetypes[idltype.kind()])
     65      self.types[type.name] = type
     66      self.__result = type.name
     67
     68   def visitStringType(self, idltype):
     69
     70      # FIXME: Should we create a ParametrizedTypeId with the appropriate bound parameters ?
     71      if idltype.bound() == 0:
     72         qname = QName(('string',))
     73      else:
     74         qname = QName(('string<%s>'%idltype.bound(),))
     75      if qname not in self.types:
     76         self.types[qname] = ASG.BuiltinTypeId('IDL', qname)
     77      self.__result = qname
     78
     79   def visitWStringType(self, idltype):
     80
     81      # FIXME: Should we create a ParametrizedTypeId with the appropriate bound parameters ?
     82      if idltype.bound() == 0:
     83         qname = QName(('wstring',))
     84      else:
     85         qname = QName(('wstring<%s>'%idltype.bound(),))
     86      if qname not in self.types:
     87         self.types[qname] = ASG.BuiltinTypeId('IDL', qname)
     88      self.__result = qname
     89
     90   def visitSequenceType(self, idltype):
     91
     92      qname = QName(('sequence',))
     93      if not self.types.has_key(qname):
     94         self.types[qname] = ASG.BuiltinTypeId("IDL", qname)
     95      idltype.seqType().accept(self)
     96      ptype = self.types[self.__result]
     97      type = ASG.ParametrizedTypeId("IDL", self.types[qname], [ptype])
     98      qname  = QName(('sequence<%s>'%str(ptype.name),))
     99      self.types[qname] = type
    100      self.__result = qname
    101
    102   def visitDeclaredType(self, idltype):
    103
    104      self.__result = QName(idltype.decl().scopedName())
    105
    106class ASGTranslator(idlvisitor.AstVisitor):
    107
    108   def __init__(self, declarations, types, primary_file_only):
    109
    110      self.declarations = declarations
    111      self.primary_file_only = primary_file_only
    112      self.types = types
    113      self.__scope = []
    114      self.__operation = None
    115      self.__enum = None
    116
    117   def scope(self): return self.__scope[-1].name
    118
    119   def add_declaration(self, declaration):
    120      self.__scope[-1].declarations.append(declaration)
    121
    122   def addType(self, name, type):
    123
    124      if self.types.has_key(name):
    125         if isinstance(self.types.get(name), ASG.UnknownTypeId):
    126            self.types.add(name, type)
    127         else:
    128            pass
    129         return
    130      self.types.add(name, type)
    131
    132   def getType(self, name): return self.types.get(QName(name))
    133   def visitAST(self, node):
    134
    135      self.__scope.append(ASG.Scope(sourcefile, 0, 'file', QName()))
    136      # add an 'Object' Type to the Type Dictionary. Don't declare it in the ASG since
    137      # there is no corresponding declaration
    138      qname = QName(('CORBA', 'Object'))
    139      object = ASG.Class(sourcefile, 0, 'interface', qname)
    140      self.addType(qname, ASG.DeclaredTypeId('IDL', qname, object))
    141      for n in node.declarations():
    142         n.accept(self)
    143      for d in self.__scope[-1].declarations:
    144         self.declarations.append(d)
    145
    146   def visitModule(self, node):
    147
    148      visible = node.mainFile() or not self.primary_file_only
    149      qname = QName(list(self.scope()) + [node.identifier()])
    150      module = ASG.Module(sourcefile, node.line(), 'module', qname)
    151      if visible:
    152         self.add_declaration(module)
    153      self.__scope.append(module)
    154      self.addType(qname, ASG.DeclaredTypeId('IDL', qname, module))
    155      if not self.primary_file_only or node.mainFile():
    156         comments = [c.text() for c in node.comments()]
    157         if comments:
    158            module.annotations['comments'] = comments
    159      for n in node.definitions():
    160         n.accept(self)
    161      self.__scope.pop()
    162
    163   def visitInterface(self, node):
    164
    165      visible = node.mainFile() or not self.primary_file_only
    166      qname = QName(list(self.scope()) + [node.identifier()])
    167      class_ = ASG.Class(sourcefile, node.line(), 'interface', qname)
    168      if visible:
    169         self.add_declaration(class_)
    170      self.__scope.append(class_)
    171      self.addType(qname, ASG.DeclaredTypeId('IDL', qname, class_))
    172      if not self.primary_file_only or node.mainFile():
    173         comments = [c.text() for c in node.comments()]
    174         if comments:
    175            class_.annotations['comments'] = comments
    176      for i in node.inherits():
    177         parent = self.getType(i.scopedName())
    178         class_.parents.append(ASG.Inheritance("", parent, []))
    179      for c in node.contents(): c.accept(self)
    180      self.__scope.pop()
    181
    182   def visitForward(self, node):
    183
    184      visible = node.mainFile() or not self.primary_file_only
    185      name = list(self.scope())
    186      qname = QName(name + [node.identifier()])
    187      forward = ASG.Forward(sourcefile, node.line(), 'interface', qname)
    188      if visible:
    189         self.add_declaration(forward)
    190      self.addType(qname, ASG.UnknownTypeId('IDL', qname))
    191
    192   def visitConst(self, node):
    193
    194      visible = node.mainFile() or not self.primary_file_only
    195      name = list(self.scope())
    196      qname = QName(name + [node.identifier()])
    197      type = self.types.internalize(node.constType())
    198      if node.constType().kind() == idltype.tk_enum:
    199         value = "::" + idlutil.ccolonName(node.value().scopedName())
    200      else:
    201         value = str(node.value())
    202      const = ASG.Const(sourcefile, node.line(), 'const',
    203                        self.getType(type), qname, value)
    204      if visible:
    205         self.add_declaration(const)
    206      comments = [c.text() for c in node.comments()]
    207      if comments:
    208         const.annotations['comments'] = comments
    209
    210   def visitTypedef(self, node):
    211
    212      visible = node.mainFile() or not self.primary_file_only
    213      # if this is an inline constructed type, it is a 'Declared' type
    214      # and we need to visit the declaration first
    215      if node.constrType():
    216         node.aliasType().decl().accept(self)
    217      type = self.types.internalize(node.aliasType())
    218      comments = [c.text() for c in node.comments()]
    219      for d in node.declarators():
    220         # reinit the type for this declarator, as each declarator of
    221         # a single typedef declaration can have a different type. *sigh*
    222         dtype = type
    223         if d.sizes():
    224            array = ASG.ArrayTypeId('IDL', self.getType(type), [str(s) for s in d.sizes()])
    225            dtype = map(None, type[:-1])
    226            dtype.append(type[-1] + string.join(map(lambda s:"["+ str(s) +"]", d.sizes()),''))
    227            self.addType(QName(dtype), array)
    228         name = list(self.scope())
    229         qname = QName(name + [d.identifier()])
    230         typedef = ASG.Typedef(sourcefile, node.line(), 'typedef', qname, self.getType(dtype), node.constrType())
    231         d_comments = comments + [c.text() for c in d.comments()]
    232         if d_comments:
    233            typedef.annotations['comments'] = d_comments
    234         self.addType(qname, ASG.DeclaredTypeId('IDL', qname, typedef))
    235         if visible:
    236            self.add_declaration(typedef)
    237
    238   def visitMember(self, node):
    239
    240      visible = node.mainFile() or not self.primary_file_only
    241      # if this is an inline constructed type, it is a 'Declared' type
    242      # and we need to visit the declaration first
    243      if node.constrType():
    244         node.memberType().decl().accept(self)
    245      type = self.types.internalize(node.memberType())
    246      comments = [c.text() for c in node.comments()]
    247      for d in node.declarators():
    248         # reinit the type for this declarator, as each declarator of
    249         # a single typedef declaration can have a different type. *sigh*
    250         dtype = type
    251         if d.sizes():
    252            array = ASG.ArrayTypeId('IDL', self.getType(type), [str(s) for s in node.sizes()])
    253            dtype = type[:-1]
    254            dtype.append(type[-1] + string.join(map(lambda s:"["+s+"]", d.sizes()),''))
    255            self.addType(dtype, array)
    256         qname = QName(list(self.scope()) + [d.identifier()])
    257         member = ASG.Variable(sourcefile, node.line(), 'variable', qname, self.getType(dtype), node.constrType())
    258         d_comments = comments + [c.text() for c in d.comments()]
    259         if d_comments:
    260            member.annotations['comments'] = d_comments
    261         self.addType(qname, ASG.DeclaredTypeId('IDL', qname, member))
    262         if visible:
    263            self.add_declaration(member)
    264
    265   def visitStruct(self, node):
    266
    267      visible = node.mainFile() or not self.primary_file_only
    268      qname = QName(list(self.scope()) + [node.identifier()])
    269      if self.primary_file_only and not node.mainFile():
    270         forward = ASG.Forward(sourcefile, node.line(), 'struct', qname)
    271         if visible:
    272            self.add_declaration(forward)
    273         self.addType(qname, ASG.DeclaredTypeId('IDL', qname, forward))
    274         return
    275      struct = ASG.Class(sourcefile, node.line(), 'struct', qname)
    276      if visible:
    277         self.add_declaration(struct)
    278      self.addType(qname, ASG.DeclaredTypeId('IDL', qname, struct))
    279      comments = [c.text() for c in node.comments()]
    280      if comments:
    281         struct.annotations['comments'] = comments
    282      self.__scope.append(struct)
    283      for member in node.members(): member.accept(self)
    284      self.__scope.pop()
    285
    286   def visitException(self, node):
    287
    288      visible = node.mainFile() or not self.primary_file_only
    289      qname = QName(list(self.scope()) + [node.identifier()])
    290      if self.primary_file_only and not node.mainFile():
    291         forward = ASG.Forward(sourcefile, node.line(), 'exception', qname)
    292         if visible:
    293            self.add_declaration(forward)
    294         self.addType(qname, ASG.DeclaredTypeId('IDL', qname, forward))
    295         return
    296      exc = ASG.Class(sourcefile, node.line(), 'exception', qname)
    297      if visible:
    298         self.add_declaration(exc)
    299      self.addType(qname, ASG.DeclaredTypeId('IDL', qname, exc))
    300      self.__scope.append(exc)
    301      comments = [c.text() for c in node.comments()]
    302      if comments:
    303         exc.annotations['comments'] = comments
    304      for member in node.members(): member.accept(self)
    305      self.__scope.pop()
    306
    307    #    def visitCaseLabel(self, node):    return
    308
    309   def visitUnionCase(self, node):
    310
    311      # if this is an inline constructed type, it is a 'Declared' type
    312      # and we need to visit the declaration first
    313      if node.constrType():
    314         node.caseType().decl().accept(self)
    315      type = self.types.internalize(node.caseType())
    316      declarator = node.declarator()
    317      if declarator.sizes():
    318         array = ASG.ArrayTypeId('IDL', self.getType(type), [str(s) for s in declarator.sizes()])
    319         type = type[:-1]
    320         type.append(type[-1] + string.join(map(lambda s:"["+s+"]",node.sizes()),''))
    321         self.addType(type, array)
    322      qname = QName(list(self.scope()) + [node.declarator().identifier()])
    323      self.__scope[-1].declarations.append(
    324         ASG.Operation(sourcefile, node.line(), 'case',
    325                       [], self.getType(type), [], qname, qname[-1]))
    326
    327   def visitUnion(self, node):
    328
    329      visible = node.mainFile() or not self.primary_file_only
    330      qname = QName(list(self.scope()) + [node.identifier()])
    331      if self.primary_file_only and not node.mainFile():
    332         forward = ASG.Forward(sourcefile, node.line(), 'union', qname)
    333         if visible:
    334            self.add_declaration(forward)
    335         self.addType(qname, ASG.DeclaredTypeId('IDL', qname, forward))
    336         return
    337      class_ = ASG.Class(sourcefile, node.line(), 'union', qname)
    338      self.add_declaration(class_)
    339      self.__scope.append(class_)
    340      self.addType(qname, ASG.DeclaredTypeId('IDL', qname, class_))
    341      comments = [c.text() for c in node.comments()]
    342      if comments:
    343         class_.annotations['comments'] = comments
    344      for c in node.cases(): c.accept(self)
    345      self.__scope.pop()
    346
    347   def visitEnumerator(self, node):
    348
    349      qname = QName(list(self.scope()) + [node.identifier()])
    350      enum = ASG.Enumerator(sourcefile, node.line(), qname, '')
    351      self.addType(qname, ASG.DeclaredTypeId('IDL', qname, enum))
    352      self.__enum.enumerators.append(enum)
    353
    354   def visitEnum(self, node):
    355
    356      visible = node.mainFile() or not self.primary_file_only
    357      qname = QName(list(self.scope()) + [node.identifier()])
    358      if self.primary_file_only and not node.mainFile():
    359         forward = ASG.Forward(sourcefile, node.line(), 'enum', qname)
    360         if visible:
    361            self.add_declaration(forward)
    362         self.addType(qname, ASG.DeclaredTypeId('IDL', qname, forward))
    363         return
    364      self.__enum = ASG.Enum(sourcefile, node.line(), qname, [])
    365      if visible:
    366         self.add_declaration(self.__enum)
    367      self.addType(qname, ASG.DeclaredTypeId('IDL', qname, self.__enum))
    368      comments = [c.text() for c in node.comments()]
    369      if comments:
    370         self.__enum.annotations['comments'] = comments
    371      for enumerator in node.enumerators(): enumerator.accept(self)
    372      self.__enum = None
    373
    374   def visitAttribute(self, node):
    375
    376      visible = node.mainFile() or not self.primary_file_only
    377      scopename = list(self.scope())
    378      if self.primary_file_only and not node.mainFile(): return
    379      # Add real Operation objects
    380      pre = []
    381      if node.readonly(): pre.append("readonly")
    382      type = self.types.internalize(node.attrType())
    383      comments = [c.text() for c in node.comments()]
    384      for id in node.identifiers():
    385         qname = QName(scopename + [id])
    386         attr = ASG.Operation(sourcefile, node.line(), 'attribute',
    387                              pre, self.getType(type), [], qname, qname[-1])
    388         if comments:
    389            attr.annotations['comments'] = comments
    390         if visible:
    391            self.add_declaration(attr)
    392
    393   def visitParameter(self, node):
    394
    395      operation = self.__operation
    396      pre = []
    397      if node.direction() == 0: pre.append("in")
    398      elif node.direction() == 1: pre.append("out")
    399      else: pre.append("inout")
    400      post = []
    401      name = self.types.internalize(node.paramType())
    402      operation.parameters.append(ASG.Parameter(pre, self.getType(name), post, node.identifier()))
    403
    404   def visitOperation(self, node):
    405
    406      visible = node.mainFile() or not self.primary_file_only
    407      pre = []
    408      if node.oneway(): pre.append("oneway")
    409      return_type = self.types.internalize(node.returnType())
    410      qname = QName(list(self.scope()) + [node.identifier()])
    411      self.__operation = ASG.Operation(sourcefile, node.line(), 'operation', pre, self.getType(return_type), [], qname, qname[-1])
    412      comments = [c.text() for c in node.comments()]
    413      if comments:
    414         self.__operation.annotations['comments'] = comments
    415      for p in node.parameters(): p.accept(self)
    416      for e in node.raises():
    417         exception = self.getType(e.scopedName())
    418         self.__operation.exceptions.append(exception)
    419
    420      if visible:
    421         self.add_declaration(self.__operation)
    422      self.__operation = None
    423
    424#    def visitNative(self, node):       return
    425#    def visitStateMember(self, node):  return
    426#    def visitFactory(self, node):      return
    427#    def visitValueForward(self, node): return
    428#    def visitValueBox(self, node):     return
    429#    def visitValueAbs(self, node):     return
    430#    def visitValue(self, node):        return
    431
    432def parse(ir, cppfile, src, primary_file_only,
    433          base_path, verbose, debug):
    434   global basename, strip, sourcefile
    435
    436   if base_path:
    437      basename = base_path
    438
    439   _omniidl.keepComments(1)
    440   _omniidl.noForwardWarning()
    441   tree = _omniidl.compile(open(cppfile, 'r+'))
    442   if tree == None:
    443      sys.stderr.write("omni: Error parsing %s\n"%cppfile)
    444      sys.exit(1)
    445
    446   sourcefile = SourceFile(strip_filename(src), src, 'IDL')
    447   sourcefile.annotations['primary'] = True
    448   new_ir = IR.IR()
    449   new_ir.files[sourcefile.name] = sourcefile
    450   type_trans = TypeTranslator(new_ir.asg.types)
    451   ast_trans = ASGTranslator(new_ir.asg.declarations, type_trans, primary_file_only)
    452   tree.accept(ast_trans)
    453   sourcefile.declarations[:] = new_ir.asg.declarations
    454   ir.merge(new_ir)
    455   _omniidl.clear()
    456   return ir
    457

Generated on Thu Apr 16 16:27:14 2009 by
synopsis (version devel)