Salome HOME
sources v1.2
[modules/kernel.git] / src / ModuleGenerator / IDLparser.py
1 #  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
2 #  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
3
4 #  This library is free software; you can redistribute it and/or 
5 #  modify it under the terms of the GNU Lesser General Public 
6 #  License as published by the Free Software Foundation; either 
7 #  version 2.1 of the License. 
8
9 #  This library is distributed in the hope that it will be useful, 
10 #  but WITHOUT ANY WARRANTY; without even the implied warranty of 
11 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
12 #  Lesser General Public License for more details. 
13
14 #  You should have received a copy of the GNU Lesser General Public 
15 #  License along with this library; if not, write to the Free Software 
16 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA 
17
18 #  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
19 #
20 #
21 #
22 #  File   : IDLparser.py
23 #  Module : SALOME
24
25 import string, sys, fpformat, re, os
26 import xml.sax
27 import pdb
28
29 from xml.sax.handler import *
30 from omniidl import idlast, idltype, idlvisitor, idlutil, output
31
32 #values of this map are used in some nodes defenition
33 common_data={"AUTHOR"   : "",
34              "ICON"     : "",
35              "VERSION"  : "",
36              "COMP_TYPE": "",
37              "COMP_NAME": "",
38              "COMP_MULT": "1"
39              }
40
41 #--------------------------------------------------
42 # print error message
43 #--------------------------------------------------
44 def error (message):
45     print "ERROR : ", message
46
47
48 #--------------------------------------------------
49 # base class implementing tree
50 #--------------------------------------------------
51 class Tree:
52     
53     def __init__(self, name = '', content = ''):
54         self.name = name
55         self.content = content
56         self.parent = None
57         self.childs = []
58         
59     def addChild(self, tree):
60         if tree is not None: 
61             self.childs.append(tree)
62             tree.parent = self
63         return tree
64
65     def addNamedChild(self, name, content = ''):
66         return self.addChild(Tree(name, content))
67
68     def replaceChild(self, tree):
69          if tree is not None:
70             pos = 0
71             for i in self.childs:
72                 if i.name == tree.name:
73                     self.childs.pop(pos)
74                     self.childs.insert(pos, tree)
75                     return tree
76                 pos += 1
77
78          return self.addChild(tree)
79        
80     def insertFirstChild(self, tree):
81         if tree is not None:
82             self.childs.insert(0, tree)
83         return tree
84     
85     def insertFirstNamedChild(self, name, content = ''):
86         return self.insertFirstChild(Tree(name, content))
87
88     def output_xml(self, f, depth=0):
89         d = depth
90         if self.name != '':
91             s = string.ljust('', 4*depth)
92             s += '<' + self.name + '>'
93             if self.content != '':
94                 s +=  self.content
95             else:
96                 if len(self.childs) > 0:
97                     s += '\n'
98             f.write(s)
99             d +=  1
100             
101         for i in self.childs:
102             i.output_xml(f, d)
103             
104         if self.name != '':
105             s = '</' + self.name + '>\n'
106             if len(self.childs) > 0 :
107                 s = string.ljust('', 4*depth) + s
108             f.write(s)
109
110     def Dump(self, levels=-1, depth=0):
111         #Dumps the tree contents
112         
113         if levels == 0: return
114         
115         s = string.ljust('', 4*depth)
116         print s, self, self.content
117         for i in self.childs:
118             i.Dump(levels-1, depth+1)
119
120     def parents(self):
121         #Returns list of the parents
122         l = []
123         p = self.parent
124         while p:
125             l.append(p)
126             l.append(p.name)
127             p = p.parent
128         return l
129         
130     def getChild(self, name, content=None):
131
132         # content == None, don't compare content
133         for i in self.childs:
134             if (i.name == name):
135                 if (content is None) | (i.content == content):
136                     return i
137         return None
138
139     def getNode(self, name, content='', depth=-1):
140
141         # recursive search
142         # content == None, don't compare content
143         if (self.name == name):
144             if (content is None) | (self.content == content):
145                 return self
146             
147         if (depth != 0):
148             for i in self.childs:
149                 n = i.getNode(name, content, depth-1)
150                 if n:  return n #return a value 
151             
152         return None
153
154     def __repr__(self):
155         s = '<'
156         if self.name != '':
157             s += self.name
158         else:
159             s +=  'None'
160         s += '>'
161         return s
162
163     def merge(self, t):
164         pass
165     
166 #--------------------------------------------------
167 # implements inParameter tree
168 #--------------------------------------------------
169 class inParameter(Tree):
170     
171     def __init__(self, name=None, type='', comment=''):
172         Tree.__init__(self, 'inParameter')
173         if name is None:  return
174         
175         self.addNamedChild('inParameter-type', type)
176         self.addNamedChild('inParameter-name', name)
177         self.addNamedChild('inParameter-comment', comment)
178             
179     def merge(self, P):
180
181         T = P.getChild('inParameter-type')
182         self.replaceChild(T)
183     
184 #--------------------------------------------------
185 # implements outParameter tree
186 #--------------------------------------------------
187 class outParameter(Tree):
188     
189     def __init__(self, name=None, type='', comment = ''):
190         
191         Tree.__init__(self, 'outParameter')
192         if name is None:  return
193         
194         self.addNamedChild('outParameter-type', type)
195         self.addNamedChild('outParameter-name', name)
196         self.addNamedChild('outParameter-comment', comment)
197             
198     def merge(self, P):
199
200         T = P.getChild('outParameter-type')
201         self.replaceChild(T)
202     
203 #--------------------------------------------------
204 # implements service tree
205 #--------------------------------------------------
206 class Service(Tree):
207     
208     def __init__(self, name=None):
209         
210         Tree.__init__(self, 'component-service')
211         if name is None:  return
212         
213         self.addNamedChild('service-name', name)
214         self.addNamedChild('service-author',common_data["AUTHOR"])
215         self.addNamedChild('service-version',common_data["VERSION"])
216         self.addNamedChild('service-comment')
217         self.addNamedChild('service-by-default', "0")
218         self.addNamedChild('inParameter-list')
219         self.addNamedChild('outParameter-list')
220             
221     def createInParameter(self, name, type):
222         L = self.getChild('inParameter-list')
223         if L is None:
224             error ("Service.createInParameter() : 'inParameter-list' is not found"); return None;
225         p = inParameter(name, type)
226         L.addChild(p)
227         return p
228     
229     def createOutParameter(self, name, type):
230         L = self.getChild('outParameter-list')
231         if L is None:
232             error ("Service.createOutParameter() : 'outParameter-list' is not found"); return None;
233         p = outParameter(name, type)
234         L.addChild(p)
235         return p
236
237
238     def merge(self, S):
239         
240         L_ext = S.getChild('inParameter-list')
241         L_int = self.getChild('inParameter-list')
242
243         if L_ext is not None and L_int is not None:
244
245             L_merge = Tree('inParameter-list')
246         
247             for i_ext in L_ext.childs:
248                 # i_ext = <inParameter>
249                 n_ext = i_ext.getChild('inParameter-name')
250                 if n_ext is None:  continue
251                 present = 0
252             
253                 for i_int in L_int.childs:
254                     # i_int = <inParameter>
255                     n_int = i_int.getChild('inParameter-name')
256                     
257                     if n_int is None:  continue
258                     
259                     if (n_int.content == n_ext.content):
260                         present = 1
261                         break;
262                 
263                 if present :
264                         i_int.merge(i_ext)
265                         L_merge.addChild(i_int)
266                 else:
267                         L_merge.addChild(i_ext)
268                         
269             self.replaceChild(L_merge)
270             
271         else : error("Service.merge(): 'inParameter-list' is not found") #either L_ext or  L_int is None
272             
273         L_ext = S.getChild('outParameter-list')
274         L_int = self.getChild('outParameter-list')
275
276         if L_ext is None or L_int is None:
277             error ("Service.merge() : 'outParameter-list' is not found")
278             
279         L_merge = Tree('outParameter-list')
280         
281         for i_ext in L_ext.childs:
282             #i_ext = <outParameter>
283             present = 0
284             n_ext = i_ext.getChild('outParameter-name')
285             if n_ext is None:   continue
286             for i_int in L_int.childs:
287                 n_int = i_int.getChild('outParameter-name')
288                 if n_int is None:  continue
289                 if (n_int.content == n_ext.content):
290                     present = 1
291                     break;
292                 
293             if present :
294                 i_int.merge(i_ext)
295                 L_merge.addChild(i_int)
296             else:
297                 L_merge.addChild(i_ext)
298                 
299         self.replaceChild(L_merge)
300
301
302 #--------------------------------------------------
303 # implements interface tree
304 #--------------------------------------------------
305 class Interface(Tree):
306     
307     def __init__(self, name=None):
308                
309         Tree.__init__(self)
310
311         if name is None:  return
312         
313         self.addNamedChild('component-interface-name', name)
314         self.addNamedChild('component-interface-comment');
315         self.addNamedChild('component-service-list')
316             
317     def createService(self, name):
318         L = self.getChild('component-service-list')
319
320         if L is None:
321             error ("Interface.createService() : 'component-service-list' is not found")
322             return None
323
324         s = Service(name)
325         L.addChild(s)
326         return s
327
328     def merge(self, I):
329
330         L_ext = I.getChild('component-service-list')
331         L_int = self.getChild('component-service-list')
332       
333         if L_ext is None or L_int is None:
334            error("Interface.merge() : 'component-service-list' is not found!")
335            return
336        
337         L_merge = Tree('component-service-list')
338         
339         for i_ext in L_ext.childs:
340             
341             present = 0
342             n_ext = i_ext.getChild('service-name')
343             if n_ext is None: continue
344             
345             for i_int in L_int.childs:
346                 n_int = i_int.getChild('service-name')
347                 if n_int is None:  continue
348                 if (n_int.content == n_ext.content):
349                     present = 1
350                     break;
351                 
352             if present == 0:
353                 i_int.merge(i_ext)
354                 L_merge.addChild(i_int)
355             else:
356                 L_merge.addChild(i_ext)
357                 
358         self.replaceChild(L_merge)
359
360
361 #--------------------------------------------------
362 # implements Component tree
363 #--------------------------------------------------
364 class Component(Tree):
365     def __init__(self, name=None):
366         Tree.__init__(self, 'component')
367
368         if name is None: return
369         
370         self.addNamedChild('component-name', name)
371         self.addNamedChild('component-type',common_data["COMP_TYPE"])
372         self.addNamedChild('component-author',common_data["AUTHOR"])
373         self.addNamedChild('component-version',common_data["VERSION"])
374         self.addNamedChild('component-comment')
375         self.addNamedChild('component-multistudy', common_data["COMP_MULT"])
376         self.addNamedChild('component-icone',common_data["ICON"])
377         self.addNamedChild('constraint')
378         self.addNamedChild('component-interface-list')
379             
380     def createInterface(self, name):
381         L = self.getChild('component-interface-list')
382         if L is None:
383             error("createInterface: No component-interface-list is found")
384             return None
385         i = Interface(name)
386         L.addChild(i)
387         return i
388
389     def merge(self, C):
390         ext=C.getChild('component-author')
391         int=self.getChild('component-author')
392         if int is not None  and  ext is not None  and  len(ext.content):
393             int.content = ext.content
394             
395         ext=C.getChild('component-type')
396         int=self.getChild('component-type')
397         if int is not None  and  ext is not None  and  len(ext.content):
398             int.content = ext.content
399
400         ext=C.getChild('component-icone')
401         int=self.getChild('component-icone')
402         if int is not None  and  ext is not None  and  len(ext.content):
403             int.content = ext.content
404
405         ext=C.getChild('component-version')
406         int=self.getChild('component-version')
407         if int is not None  and  ext is not None  and  len(ext.content):
408             int.content = ext.content
409
410         ext=C.getChild('component-comment')
411         int=self.getChild('component-comment')
412         if int is not None  and  ext is not None  and  len(ext.content):
413             int.content = ext.content
414
415         ext=C.getChild('component-multistudy')
416         int=self.getChild('component-multistudy')
417         if int is not None  and  ext is not None  and  len(ext.content):
418             int.content = ext.content
419             
420         ext=C.getChild('constraint')
421         int=self.getChild('constraint')
422         if int is not None  and  ext is not None  and  len(ext.content):
423             int.content = ext.content
424              
425         L_ext = C.getChild('component-interface-list')
426         L_int = self.getChild('component-interface-list')
427         if L_ext is None or L_int is None:
428             error("Component.merge : No component-interface-list is found")
429             return
430         L_merge = Tree('component-interface-list')
431         
432         for i_ext in L_ext.childs:
433             present = 0
434             n_ext = i_ext.getChild('component-interface-name')
435
436             if n_ext is None:  continue
437             
438             for i_int in L_int.childs:
439                 n_int = i_int.getChild('component-interface-name')
440                 if n_int is None:  continue
441                 if (n_int.content == n_ext.content):
442                     present = 1
443                     break;
444                 
445             if present :
446                 i_int.merge(i_ext)
447                 L_merge.addChild(i_int)
448             else:
449                 L_merge.addChild(i_ext)
450                 
451         self.replaceChild(L_merge)
452     
453 #--------------------------------------------------
454 # implements document tree
455 #--------------------------------------------------
456 class Catalog(ContentHandler, Tree):
457     def __init__(self, filename = None):
458         Tree.__init__(self)
459         self.buffer = ''
460         self.list = []
461         if (filename):
462             parser = xml.sax.make_parser()
463             parser.setContentHandler(self)
464             parser.parse(filename)
465         else:
466             t = self.addNamedChild('begin-catalog')
467             t.addNamedChild('component-list')
468
469         n = self.getChild('begin-catalog')
470         if n is None:
471             error("Catalog.__init__ : No 'begin-catalog' is found!")
472             return
473         if n.getChild('path-prefix-list') is None:
474             n.insertFirstNamedChild('path-prefix-list')
475         if n.getChild('component-list') is None:
476             n.addNamedChild('component-list')
477             
478     def removeComponent(self, name):
479         complist = self.getNode('component-list')
480         idx = 0
481         if complist is None:
482             print "Catalog.removeComponent() : 'component-list' is not found"
483             return
484         for comp in complist.childs:
485             cname = comp.getChild('component-name')
486             if cname is not None:
487                 if cname.content == name:
488                     complist.childs.pop(idx)
489                     print "Component " + name + " is removed"
490             idx += 1       
491  
492     def startDocument(self):
493         self.list.append(self)
494     
495     def startElement(self, name, attrs):
496         p = self.list[len(self.list)-1]
497
498         if name == 'component':
499             e = p.addChild(Component())
500         elif name == 'component-interface-name':
501             e = p.addNamedChild(name)
502         elif name == 'component-service':
503             e = p.addChild(Service())
504         elif name == 'inParameter':
505             e = p.addChild(inParameter())
506         elif name == 'outParameter':
507             e = p.addChild(outParameter())
508         else:
509             e = p.addNamedChild(name)
510         self.list.append(e)
511         self.buffer = ''
512         
513     def endElement(self, name):
514         self.buffer = string.join(string.split(self.buffer), ' ')
515         p = self.list[len(self.list)-1]
516         p.content = self.buffer
517         self.buffer = ''
518         e = self.list.pop()
519
520         
521     def characters(self, ch):
522         self.buffer += ch
523
524     def mergeComponent(self, comp):
525         
526         L_int = self.getNode('component-list')
527         if   L_int is None:
528             error("Catalog.mergeComponent : 'component-list' is not found")
529             return
530         
531         i_ext = comp
532         present = 0
533         n_ext = i_ext.getChild('component-name')
534         if n_ext is None:
535             error("Catalog.mergeComponent : 'component-name' is not found")
536             return
537         for i_int in L_int.childs:
538             n_int = i_int.getChild('component-name')
539             if n_int is None:  continue
540             
541             if (n_int.content == n_ext.content):
542                 present = 1
543                 break;
544                 
545         if present == 0:
546             print '   add component', n_ext.content
547             L_int.addChild(i_ext)
548         else:
549             print '   replace component', n_ext.content
550             i_int.merge(i_ext)
551             
552
553             
554
555 # IDL file reader
556
557 ttsMap = {
558     idltype.tk_void:       "void",
559     idltype.tk_short:      "short",
560     idltype.tk_long:       "long",
561     idltype.tk_ushort:     "unsigned short",
562     idltype.tk_ulong:      "unsigned long",
563     idltype.tk_float:      "float",
564     idltype.tk_double:     "double",
565     idltype.tk_boolean:    "boolean",
566     idltype.tk_char:       "char",
567     idltype.tk_octet:      "octet",
568     idltype.tk_any:        "any",
569     idltype.tk_TypeCode:   "CORBA::TypeCode",
570     idltype.tk_Principal:  "CORBA::Principal",
571     idltype.tk_longlong:   "long long",
572     idltype.tk_ulonglong:  "unsigned long long",
573     idltype.tk_longdouble: "long double",
574     idltype.tk_wchar:      "wchar"
575     }
576
577
578 #--------------------------------------------------
579 # class ModuleCatalogVisitor
580 #--------------------------------------------------
581 class ModuleCatalogVisitor (idlvisitor.AstVisitor):
582     
583     def __init__(self, catalog):
584         self.catalog = catalog
585         self.EngineType = 0
586         
587     def visitAST(self, node):
588         for n in node.declarations():
589             n.accept(self)
590             
591     def visitModule(self, node):
592         for n in node.definitions():
593             n.accept(self)
594                 
595     def visitInterface(self, node):
596         if node.mainFile():
597
598             self.EngineType = 0
599             
600             for i in node.inherits():
601                 s = i.scopedName();
602                 if ((s[0] == "Engines") & (s[1] == "Component")):
603                     self.EngineType = 1; break
604                 
605             if common_data["COMP_NAME"] :  Comp = Component(common_data["COMP_NAME"])
606             else :  Comp = Component(node.identifier())
607             
608             self.currentInterface = Comp.createInterface(node.identifier())
609         
610             for c in node.callables():
611                 if isinstance(c, idlast.Operation):
612                     c.accept(self)
613
614             if (self.EngineType):
615                 self.catalog.mergeComponent(Comp)
616
617             self.EngineType = 0
618             
619     def visitOperation(self, node):
620
621         self.currentService = self.currentInterface.createService \
622                                        (node.identifier())
623         
624         for c in node.parameters():
625             c.accept(self)
626             
627         node.returnType().accept(self)
628         if (self.currentType != "void"):
629             self.currentService.createOutParameter \
630                 ("return", self.currentType)
631         
632
633     def visitDeclaredType(self, type):
634         self.currentType = type.name()
635             
636     def visitBaseType(self, type):
637         self.currentType = ttsMap[type.kind()]
638     
639     def visitStringType(self, type):
640         self.currentType = "string"
641         
642     def visitParameter(self, node):
643         node.paramType().accept(self)
644         if node.is_in():
645             self.currentService.createInParameter \
646                      (node.identifier(), self.currentType)
647         if node.is_out():
648             self.currentService.createOutParameter \
649                      (node.identifier(), self.currentType)
650         
651 #--------------------------------------------------
652 # extract value of <param_name> from <args> list
653 # it's proposed that the matching <args> item
654 # looks like <param_name>=<value>, for example,
655 # catalog=/tmp/myxml.xml
656 #--------------------------------------------------
657 def getParamValue( param_name, args ):
658     pattern="^"+param_name+"="
659
660     res = ""        #initial value
661     for opt in args:
662         s = re.compile(pattern).search(opt)
663         if s:
664             res = opt[s.end():]
665             break     #found
666
667     return res    
668
669 #--------------------------------------------------
670 # parse idl and store xml file
671 #--------------------------------------------------
672 def run(tree, args):
673     CatalogFileName=getParamValue("catalog",args)
674     if CatalogFileName is None:
675         CatalogFileName = 'CatalogModulePersonnel.xml'
676     
677     if (re.compile(".*?.xml$").match(CatalogFileName, 1) is None):
678         CatalogFileName = CatalogFileName + '.xml'
679
680     #=========  Read parameters  ======================    
681     common_data["ICON"] = getParamValue("icon",args)              # get icon file
682
683     common_data["AUTHOR"] = getParamValue("author",args)          # get author name
684     if common_data["AUTHOR"] is None:   common_data["AUTHOR"] = os.getenv("USER");
685     
686     common_data["VERSION"] = getParamValue("version",args)        # get version
687
688     common_data["COMP_NAME"] = getParamValue("name",args)         # get icon file
689
690     val = getParamValue("type",args)                              # get icon file
691     if val:   common_data["COMP_TYPE"] = val
692
693     val = getParamValue("multistudy",args)                        # get icon file
694     if val :    common_data["COMP_MULT"]  = val
695
696     remove_comp = getParamValue("remove", args)
697     
698     #==================================================    
699     
700     if (os.path.exists(CatalogFileName)):
701         print "Importing", CatalogFileName
702         C = Catalog(CatalogFileName)
703     else:
704         print "Warning : ",CatalogFileName, " was not found."
705         C = Catalog()
706         
707     print "Reading idl file"
708     
709     visitor = ModuleCatalogVisitor(C)
710     tree.accept(visitor)
711
712     if remove_comp :
713         C.removeComponent(remove_comp)
714     
715     if (os.path.exists(CatalogFileName)):
716         print "Updating", CatalogFileName
717         CatalogFileName_old = CatalogFileName + '_old'
718         os.rename(CatalogFileName, CatalogFileName_old)
719     else:
720         CatalogFileName_old = ""
721         print "Writing", CatalogFileName
722         
723     CatalogFileName_new = CatalogFileName + '_new'
724     f=open(CatalogFileName_new, 'w')
725     f.write("<?xml version='1.0' encoding='us-ascii' ?>\n\n")
726     C.output_xml(f)
727     f.close()
728
729     os.rename(CatalogFileName_new, CatalogFileName)
730     if ((CatalogFileName_old != "") & os.path.exists(CatalogFileName_old)):
731         os.unlink(CatalogFileName_old)
732         
733     print
734
735
736 if __name__ == "__main__":
737     print
738     print "Usage : omniidl -bIDLparser -Wbcatalog=<my_catalog.xml>[,icon=<pngfile>][,version=<num>][,author=<name>][,name=<component_name>][,multistudy=<component_multistudy>][,remove=component_name] <file.idl>"
739     print