Utilities/ClassBrowsers/idlclbr.py

changeset 0
de9c2efb9d02
child 12
1d8dd9706f46
diff -r 000000000000 -r de9c2efb9d02 Utilities/ClassBrowsers/idlclbr.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Utilities/ClassBrowsers/idlclbr.py	Mon Dec 28 16:03:33 2009 +0000
@@ -0,0 +1,326 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2005 - 2009 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Parse a CORBA IDL file and retrieve modules, interfaces, methods and attributes.
+
+Parse enough of a CORBA IDL file to recognize module, interface and method definitions
+and to find out the superclasses of an interface as well as its attributes.
+
+It is based on the Python class browser found in this package.
+"""
+
+import sys
+import os
+import re
+
+import Utilities
+import Utilities.ClassBrowsers as ClassBrowsers
+import ClbrBaseClasses
+
+SUPPORTED_TYPES = [ClassBrowsers.IDL_SOURCE]
+    
+_getnext = re.compile(r"""
+    (?P<String>
+        " [^"\\\n]* (?: \\. [^"\\\n]*)* "
+    )
+
+|   (?P<Comment>
+        ^ [ \t]* // .*? $
+    |
+        ^ [ \t]* /\* .*? \*/
+    )
+
+|   (?P<Method>
+        ^
+        (?P<MethodIndent> [ \t]* )
+        (?: oneway [ \t]+ )?
+        (?: [a-zA-Z0-9_:]+ | void ) [ \t]*
+        (?P<MethodName> [a-zA-Z_] [a-zA-Z0-9_]* )
+        [ \t]* 
+        \(
+        (?P<MethodSignature> [^)]*? )
+        \);
+        [ \t]*
+    )
+
+|   (?P<Interface>
+        ^
+        (?P<InterfaceIndent> [ \t]* )
+        (?: abstract [ \t]+ )?
+        interface [ \t]+
+        (?P<InterfaceName> [a-zA-Z_] [a-zA-Z0-9_]* )
+        [ \t]*
+        (?P<InterfaceSupers> : [^{]+? )?
+        [ \t]* {
+    )
+
+|   (?P<Module>
+        ^
+        (?P<ModuleIndent> [ \t]* )
+        module [ \t]+
+        (?P<ModuleName> [a-zA-Z_] [a-zA-Z0-9_]* )
+        [ \t]* {
+    )
+
+|   (?P<Attribute>
+        ^
+        (?P<AttributeIndent> [ \t]* )
+        (?P<AttributeReadonly> readonly [ \t]+ )?
+        attribute [ \t]+
+        (?P<AttributeType>  (?: [a-zA-Z0-9_:]+ [ \t]+ )+ )
+        (?P<AttributeNames> [^;]* )
+        ;
+    )
+
+|   (?P<Begin>
+        [ \t]* {
+    )
+
+|   (?P<End>
+        [ \t]* } [ \t]* ;
+    )
+""", re.VERBOSE | re.DOTALL | re.MULTILINE).search
+
+# function to replace comments
+_commentsub = re.compile(r"""//[^\n]*\n|//[^\n]*$""").sub   
+# function to normalize whitespace
+_normalize = re.compile(r"""[ \t]{2,}""").sub               
+
+_modules = {}                           # cache of modules we've seen
+
+class VisibilityMixin(ClbrBaseClasses.ClbrVisibilityMixinBase):
+    """
+    Mixin class implementing the notion of visibility.
+    """
+    def __init__(self):
+        """
+        Method to initialize the visibility.
+        """
+        self.setPublic()
+
+class Module(ClbrBaseClasses.Module, VisibilityMixin):
+    """
+    Class to represent a CORBA IDL module.
+    """
+    def __init__(self, module, name, file, lineno):
+        """
+        Constructor
+        
+        @param module name of the module containing this class
+        @param name name of this class
+        @param file filename containing this class
+        @param lineno linenumber of the class definition
+        """
+        ClbrBaseClasses.Module.__init__(self, module, name, file, lineno)
+        VisibilityMixin.__init__(self)
+
+class Interface(ClbrBaseClasses.Class, VisibilityMixin):
+    """
+    Class to represent a CORBA IDL interface.
+    """
+    def __init__(self, module, name, super, file, lineno):
+        """
+        Constructor
+        
+        @param module name of the module containing this class
+        @param name name of this interface
+        @param super list of interface names this interface is inherited from
+        @param file filename containing this interface
+        @param lineno linenumber of the interface definition
+        """
+        ClbrBaseClasses.Class.__init__(self, module, name, super, file, lineno)
+        VisibilityMixin.__init__(self)
+
+class Function(ClbrBaseClasses.Function, VisibilityMixin):
+    """
+    Class to represent a CORBA IDL function.
+    """
+    def __init__(self, module, name, file, lineno, signature = '', separator = ','):
+        """
+        Constructor
+        
+        @param module name of the module containing this function
+        @param name name of this function
+        @param file filename containing this class
+        @param lineno linenumber of the class definition
+        @param signature parameterlist of the method
+        @param separator string separating the parameters
+        """
+        ClbrBaseClasses.Function.__init__(self, module, name, file, lineno, 
+                                          signature, separator)
+        VisibilityMixin.__init__(self)
+
+class Attribute(ClbrBaseClasses.Attribute, VisibilityMixin):
+    """
+    Class to represent a CORBA IDL attribute.
+    """
+    def __init__(self, module, name, file, lineno):
+        """
+        Constructor
+        
+        @param module name of the module containing this class
+        @param name name of this class
+        @param file filename containing this attribute
+        @param lineno linenumber of the class definition
+        """
+        ClbrBaseClasses.Attribute.__init__(self, module, name, file, lineno)
+        VisibilityMixin.__init__(self)
+
+def readmodule_ex(module, path=[]):
+    '''
+    Read a CORBA IDL file and return a dictionary of classes, functions and modules.
+
+    @param module name of the CORBA IDL file (string)
+    @param path path the file should be searched in (list of strings)
+    @return the resulting dictionary
+    '''
+
+    dict = {}
+    dict_counts = {}
+
+    if module in _modules:
+        # we've seen this file before...
+        return _modules[module]
+
+    # search the path for the file
+    f = None
+    fullpath = list(path)
+    f, file, (suff, mode, type) = ClassBrowsers.find_module(module, fullpath)
+    if type not in SUPPORTED_TYPES:
+        # not CORBA IDL source, can't do anything with this module
+        f.close()
+        _modules[module] = dict
+        return dict
+
+    _modules[module] = dict
+    classstack = [] # stack of (class, indent) pairs
+    indent = 0
+    src = Utilities.decode(f.read())[0]
+    f.close()
+
+    lineno, last_lineno_pos = 1, 0
+    i = 0
+    while 1:
+        m = _getnext(src, i)
+        if not m:
+            break
+        start, i = m.span()
+
+        if m.start("Method") >= 0:
+            # found a method definition or function
+            thisindent = indent
+            meth_name = m.group("MethodName")
+            meth_sig = m.group("MethodSignature")
+            meth_sig = meth_sig and meth_sig.replace('\\\n', '') or ''
+            meth_sig = _commentsub('', meth_sig)
+            meth_sig = _normalize(' ', meth_sig)
+            lineno = lineno + src.count('\n', last_lineno_pos, start)
+            last_lineno_pos = start
+            # close all interfaces/modules indented at least as much
+            while classstack and \
+                  classstack[-1][1] >= thisindent:
+                del classstack[-1]
+            if classstack:
+                # it's an interface/module method
+                cur_class = classstack[-1][0]
+                if isinstance(cur_class, Interface) or isinstance(cur_class, Module):
+                    # it's a method
+                    f = Function(None, meth_name,
+                                 file, lineno, meth_sig)
+                    cur_class._addmethod(meth_name, f)
+                # else it's a nested def
+            else:
+                # it's a function
+                f = Function(module, meth_name,
+                             file, lineno, meth_sig)
+                if dict_counts.has_key(meth_name):
+                    dict_counts[meth_name] += 1
+                    meth_name = "%s_%d" % (meth_name, dict_counts[meth_name])
+                else:
+                    dict_counts[meth_name] = 0
+                dict[meth_name] = f
+            classstack.append((f, thisindent)) # Marker for nested fns
+
+        elif m.start("String") >= 0:
+            pass
+
+        elif m.start("Comment") >= 0:
+            pass
+
+        elif m.start("Interface") >= 0:
+            # we found an interface definition
+            thisindent = indent
+            indent += 1
+            # close all interfaces/modules indented at least as much
+            while classstack and \
+                  classstack[-1][1] >= thisindent:
+                del classstack[-1]
+            lineno = lineno + src.count('\n', last_lineno_pos, start)
+            last_lineno_pos = start
+            class_name = m.group("InterfaceName")
+            inherit = m.group("InterfaceSupers")
+            if inherit:
+                # the interface inherits from other interfaces
+                inherit = inherit[1:].strip()
+                inherit = [_commentsub('', inherit)]
+            # remember this interface
+            cur_class = Interface(module, class_name, inherit,
+                              file, lineno)
+            if not classstack:
+                dict[class_name] = cur_class
+            else:
+                cls = classstack[-1][0]
+                cls._addclass(class_name, cur_class)
+            classstack.append((cur_class, thisindent))
+
+        elif m.start("Module") >= 0:
+            # we found a module definition
+            thisindent = indent
+            indent += 1
+            # close all interfaces/modules indented at least as much
+            while classstack and \
+                  classstack[-1][1] >= thisindent:
+                del classstack[-1]
+            lineno = lineno + src.count('\n', last_lineno_pos, start)
+            last_lineno_pos = start
+            module_name = m.group("ModuleName")
+            # remember this module
+            cur_class = Module(module, module_name, file, lineno)
+            if not classstack:
+                dict[module_name] = cur_class
+            classstack.append((cur_class, thisindent))
+
+        elif m.start("Attribute") >= 0:
+            lineno = lineno + src.count('\n', last_lineno_pos, start)
+            last_lineno_pos = start
+            index = -1
+            while index >= -len(classstack):
+                if classstack[index][0] is not None and \
+                   not isinstance(classstack[index][0], Function) and \
+                   not classstack[index][1] >= indent:
+                    attributes = m.group("AttributeNames").split(',')
+                    ro = m.group("AttributeReadonly")
+                    for attribute in attributes:
+                        attr = Attribute(module, attribute, file, lineno)
+                        if ro:
+                            attr.setPrivate()
+                        classstack[index][0]._addattribute(attr)
+                    break
+                else:
+                    index -= 1
+
+        elif m.start("Begin") >= 0:
+            # a begin of a block we are not interested in
+            indent += 1
+
+        elif m.start("End") >= 0:
+            # an end of a block
+            indent -= 1
+
+        else:
+            assert 0, "regexp _getnext found something unexpected"
+
+    return dict

eric ide

mercurial