eric6/Utilities/ClassBrowsers/idlclbr.py

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

eric ide

mercurial