Utilities/ClassBrowsers/idlclbr.py

changeset 0
de9c2efb9d02
child 12
1d8dd9706f46
equal deleted inserted replaced
-1:000000000000 0:de9c2efb9d02
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2005 - 2009 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Parse a CORBA IDL file and retrieve modules, interfaces, methods and attributes.
8
9 Parse enough of a CORBA IDL file to recognize module, interface and method definitions
10 and to find out the superclasses of an interface as well as its attributes.
11
12 It is based on the Python class browser found in this package.
13 """
14
15 import sys
16 import os
17 import re
18
19 import Utilities
20 import Utilities.ClassBrowsers as ClassBrowsers
21 import ClbrBaseClasses
22
23 SUPPORTED_TYPES = [ClassBrowsers.IDL_SOURCE]
24
25 _getnext = re.compile(r"""
26 (?P<String>
27 " [^"\\\n]* (?: \\. [^"\\\n]*)* "
28 )
29
30 | (?P<Comment>
31 ^ [ \t]* // .*? $
32 |
33 ^ [ \t]* /\* .*? \*/
34 )
35
36 | (?P<Method>
37 ^
38 (?P<MethodIndent> [ \t]* )
39 (?: oneway [ \t]+ )?
40 (?: [a-zA-Z0-9_:]+ | void ) [ \t]*
41 (?P<MethodName> [a-zA-Z_] [a-zA-Z0-9_]* )
42 [ \t]*
43 \(
44 (?P<MethodSignature> [^)]*? )
45 \);
46 [ \t]*
47 )
48
49 | (?P<Interface>
50 ^
51 (?P<InterfaceIndent> [ \t]* )
52 (?: abstract [ \t]+ )?
53 interface [ \t]+
54 (?P<InterfaceName> [a-zA-Z_] [a-zA-Z0-9_]* )
55 [ \t]*
56 (?P<InterfaceSupers> : [^{]+? )?
57 [ \t]* {
58 )
59
60 | (?P<Module>
61 ^
62 (?P<ModuleIndent> [ \t]* )
63 module [ \t]+
64 (?P<ModuleName> [a-zA-Z_] [a-zA-Z0-9_]* )
65 [ \t]* {
66 )
67
68 | (?P<Attribute>
69 ^
70 (?P<AttributeIndent> [ \t]* )
71 (?P<AttributeReadonly> readonly [ \t]+ )?
72 attribute [ \t]+
73 (?P<AttributeType> (?: [a-zA-Z0-9_:]+ [ \t]+ )+ )
74 (?P<AttributeNames> [^;]* )
75 ;
76 )
77
78 | (?P<Begin>
79 [ \t]* {
80 )
81
82 | (?P<End>
83 [ \t]* } [ \t]* ;
84 )
85 """, re.VERBOSE | re.DOTALL | re.MULTILINE).search
86
87 # function to replace comments
88 _commentsub = re.compile(r"""//[^\n]*\n|//[^\n]*$""").sub
89 # function to normalize whitespace
90 _normalize = re.compile(r"""[ \t]{2,}""").sub
91
92 _modules = {} # cache of modules we've seen
93
94 class VisibilityMixin(ClbrBaseClasses.ClbrVisibilityMixinBase):
95 """
96 Mixin class implementing the notion of visibility.
97 """
98 def __init__(self):
99 """
100 Method to initialize the visibility.
101 """
102 self.setPublic()
103
104 class Module(ClbrBaseClasses.Module, VisibilityMixin):
105 """
106 Class to represent a CORBA IDL module.
107 """
108 def __init__(self, module, name, file, lineno):
109 """
110 Constructor
111
112 @param module name of the module containing this class
113 @param name name of this class
114 @param file filename containing this class
115 @param lineno linenumber of the class definition
116 """
117 ClbrBaseClasses.Module.__init__(self, module, name, file, lineno)
118 VisibilityMixin.__init__(self)
119
120 class Interface(ClbrBaseClasses.Class, VisibilityMixin):
121 """
122 Class to represent a CORBA IDL interface.
123 """
124 def __init__(self, module, name, super, file, lineno):
125 """
126 Constructor
127
128 @param module name of the module containing this class
129 @param name name of this interface
130 @param super list of interface names this interface is inherited from
131 @param file filename containing this interface
132 @param lineno linenumber of the interface definition
133 """
134 ClbrBaseClasses.Class.__init__(self, module, name, super, file, lineno)
135 VisibilityMixin.__init__(self)
136
137 class Function(ClbrBaseClasses.Function, VisibilityMixin):
138 """
139 Class to represent a CORBA IDL function.
140 """
141 def __init__(self, module, name, file, lineno, signature = '', separator = ','):
142 """
143 Constructor
144
145 @param module name of the module containing this function
146 @param name name of this function
147 @param file filename containing this class
148 @param lineno linenumber of the class definition
149 @param signature parameterlist of the method
150 @param separator string separating the parameters
151 """
152 ClbrBaseClasses.Function.__init__(self, module, name, file, lineno,
153 signature, separator)
154 VisibilityMixin.__init__(self)
155
156 class Attribute(ClbrBaseClasses.Attribute, VisibilityMixin):
157 """
158 Class to represent a CORBA IDL attribute.
159 """
160 def __init__(self, module, name, file, lineno):
161 """
162 Constructor
163
164 @param module name of the module containing this class
165 @param name name of this class
166 @param file filename containing this attribute
167 @param lineno linenumber of the class definition
168 """
169 ClbrBaseClasses.Attribute.__init__(self, module, name, file, lineno)
170 VisibilityMixin.__init__(self)
171
172 def readmodule_ex(module, path=[]):
173 '''
174 Read a CORBA IDL file and return a dictionary of classes, functions and modules.
175
176 @param module name of the CORBA IDL file (string)
177 @param path path the file should be searched in (list of strings)
178 @return the resulting dictionary
179 '''
180
181 dict = {}
182 dict_counts = {}
183
184 if module in _modules:
185 # we've seen this file before...
186 return _modules[module]
187
188 # search the path for the file
189 f = None
190 fullpath = list(path)
191 f, file, (suff, mode, type) = ClassBrowsers.find_module(module, fullpath)
192 if type not in SUPPORTED_TYPES:
193 # not CORBA IDL source, can't do anything with this module
194 f.close()
195 _modules[module] = dict
196 return dict
197
198 _modules[module] = dict
199 classstack = [] # stack of (class, indent) pairs
200 indent = 0
201 src = Utilities.decode(f.read())[0]
202 f.close()
203
204 lineno, last_lineno_pos = 1, 0
205 i = 0
206 while 1:
207 m = _getnext(src, i)
208 if not m:
209 break
210 start, i = m.span()
211
212 if m.start("Method") >= 0:
213 # found a method definition or function
214 thisindent = indent
215 meth_name = m.group("MethodName")
216 meth_sig = m.group("MethodSignature")
217 meth_sig = meth_sig and meth_sig.replace('\\\n', '') or ''
218 meth_sig = _commentsub('', meth_sig)
219 meth_sig = _normalize(' ', meth_sig)
220 lineno = lineno + src.count('\n', last_lineno_pos, start)
221 last_lineno_pos = start
222 # close all interfaces/modules indented at least as much
223 while classstack and \
224 classstack[-1][1] >= thisindent:
225 del classstack[-1]
226 if classstack:
227 # it's an interface/module method
228 cur_class = classstack[-1][0]
229 if isinstance(cur_class, Interface) or isinstance(cur_class, Module):
230 # it's a method
231 f = Function(None, meth_name,
232 file, lineno, meth_sig)
233 cur_class._addmethod(meth_name, f)
234 # else it's a nested def
235 else:
236 # it's a function
237 f = Function(module, meth_name,
238 file, lineno, meth_sig)
239 if dict_counts.has_key(meth_name):
240 dict_counts[meth_name] += 1
241 meth_name = "%s_%d" % (meth_name, dict_counts[meth_name])
242 else:
243 dict_counts[meth_name] = 0
244 dict[meth_name] = f
245 classstack.append((f, thisindent)) # Marker for nested fns
246
247 elif m.start("String") >= 0:
248 pass
249
250 elif m.start("Comment") >= 0:
251 pass
252
253 elif m.start("Interface") >= 0:
254 # we found an interface definition
255 thisindent = indent
256 indent += 1
257 # close all interfaces/modules indented at least as much
258 while classstack and \
259 classstack[-1][1] >= thisindent:
260 del classstack[-1]
261 lineno = lineno + src.count('\n', last_lineno_pos, start)
262 last_lineno_pos = start
263 class_name = m.group("InterfaceName")
264 inherit = m.group("InterfaceSupers")
265 if inherit:
266 # the interface inherits from other interfaces
267 inherit = inherit[1:].strip()
268 inherit = [_commentsub('', inherit)]
269 # remember this interface
270 cur_class = Interface(module, class_name, inherit,
271 file, lineno)
272 if not classstack:
273 dict[class_name] = cur_class
274 else:
275 cls = classstack[-1][0]
276 cls._addclass(class_name, cur_class)
277 classstack.append((cur_class, thisindent))
278
279 elif m.start("Module") >= 0:
280 # we found a module definition
281 thisindent = indent
282 indent += 1
283 # close all interfaces/modules indented at least as much
284 while classstack and \
285 classstack[-1][1] >= thisindent:
286 del classstack[-1]
287 lineno = lineno + src.count('\n', last_lineno_pos, start)
288 last_lineno_pos = start
289 module_name = m.group("ModuleName")
290 # remember this module
291 cur_class = Module(module, module_name, file, lineno)
292 if not classstack:
293 dict[module_name] = cur_class
294 classstack.append((cur_class, thisindent))
295
296 elif m.start("Attribute") >= 0:
297 lineno = lineno + src.count('\n', last_lineno_pos, start)
298 last_lineno_pos = start
299 index = -1
300 while index >= -len(classstack):
301 if classstack[index][0] is not None and \
302 not isinstance(classstack[index][0], Function) and \
303 not classstack[index][1] >= indent:
304 attributes = m.group("AttributeNames").split(',')
305 ro = m.group("AttributeReadonly")
306 for attribute in attributes:
307 attr = Attribute(module, attribute, file, lineno)
308 if ro:
309 attr.setPrivate()
310 classstack[index][0]._addattribute(attr)
311 break
312 else:
313 index -= 1
314
315 elif m.start("Begin") >= 0:
316 # a begin of a block we are not interested in
317 indent += 1
318
319 elif m.start("End") >= 0:
320 # an end of a block
321 indent -= 1
322
323 else:
324 assert 0, "regexp _getnext found something unexpected"
325
326 return dict

eric ide

mercurial