Salome HOME
debug intempestif
[tools/eficas.git] / Traducteur2 / parseur.py
1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2007-2017   EDF R&D
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.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 #
20 import re,string
21 import compiler
22
23 debug=0
24
25 escapedQuotesRE = re.compile(r"(\\\\|\\\"|\\\')")
26 stringsAndCommentsRE =  \
27       re.compile("(\"\"\".*?\"\"\"|'''.*?'''|\"[^\"]*\"|\'[^\']*\'|#.*?\n)", re.DOTALL)
28 allchars = string.maketrans("", "")
29 allcharsExceptNewline = allchars[: allchars.index('\n')]+allchars[allchars.index('\n')+1:]
30 allcharsExceptNewlineTranstable = string.maketrans(allcharsExceptNewline, '*'*len(allcharsExceptNewline))
31
32 #------------------------------
33 def maskStringsAndComments(src):
34 #------------------------------
35     """Remplace tous les caracteres dans commentaires et strings par des * """
36
37     src = escapedQuotesRE.sub("**", src)
38     allstrings = stringsAndCommentsRE.split(src)
39     # every odd element is a string or comment
40     for i in xrange(1, len(allstrings), 2):
41         if allstrings[i].startswith("'''")or allstrings[i].startswith('"""'):
42             allstrings[i] = allstrings[i][:3]+ \
43                            allstrings[i][3:-3].translate(allcharsExceptNewlineTranstable)+ \
44                            allstrings[i][-3:]
45         else:
46             allstrings[i] = allstrings[i][0]+ \
47                            allstrings[i][1:-1].translate(allcharsExceptNewlineTranstable)+ \
48                            allstrings[i][-1]
49
50     return "".join(allstrings)
51
52 #un nombre queconque de blancs,un nom,des blancs
53 pattern_oper   = re.compile(r"^\s*(.*?=\s*)?([a-zA-Z_]\w*)(\s*)(\()(.*)",re.DOTALL)
54 pattern_proc   = re.compile(r"^\s*([a-zA-Z_]\w*)(\s*)(\()(.*)",re.DOTALL)
55
56 implicitContinuationChars = (('(', ')'), ('[', ']'), ('{', '}'))
57 linecontinueRE = re.compile(r"\\\s*(#.*)?$")
58 emptyHangingBraces = [0,0,0,0,0]
59
60 #--------------------------------------
61 class UnbalancedBracesException: pass
62 #--------------------------------------
63
64 #-----------
65 class Node:
66 #-----------
67     def __init__(self):
68         self.childNodes=[]
69
70     def addChild(self,node):
71         self.childNodes.append(node)
72
73
74 #-------------------
75 class FactNode(Node):
76 #-------------------
77     pass
78
79
80 #-------------------
81 class JDCNode(Node):
82 #-------------------
83     def __init__(self,src):
84         Node.__init__(self)
85         self.src=src
86
87 #-------------------
88 class Command(Node):
89 #-------------------
90     def __init__(self,name,lineno,colno,firstparen):
91         Node.__init__(self)
92         self.name=name
93         self.lineno=lineno
94         self.colno=colno
95         self.firstparen=firstparen
96
97 #-------------------
98 class Keyword(Node):
99 #-------------------
100     def __init__(self,name,lineno,colno,endline,endcol):
101         Node.__init__(self)
102         self.name=name
103         self.lineno=lineno
104         self.colno=colno
105         self.endline=endline
106         self.endcol=endcol
107
108     def getText(self,jdc):
109         if self.endline > self.lineno:
110             debut=jdc.getLines()[self.lineno-1][self.colno:]
111             fin  = jdc.getLines()[self.endline-1][:self.endcol]
112             texte=debut
113             lignecourante=self.lineno
114             while  lignecourante < self.endline -1  :
115                 texte = texte + jdc.getLines()[lignecourante]
116                 lignecourante = lignecourante + 1
117             if chaineBlanche(fin) == 0 :
118                 texte=texte + fin
119             if texte[-1] == "\n" :
120                 texte=texte[0:-1]
121         else:
122             texte = jdc.getLines()[self.lineno-1][self.colno:self.endcol]
123         return texte
124
125 #-------------------------
126 def chaineBlanche(texte) :
127 #-------------------------
128 # retourne 1 si la chaine est composee de " "
129 # retourne 0 sinon
130     bool = 1 ;
131     for i in range(len(texte)) :
132         if texte[i] != " " : bool = 0
133     return bool
134
135 #-------------------
136 def printNode(node):
137 #-------------------
138     if hasattr(node,'name'):
139         print node.name
140     else:
141         print "pas de nom pour:",node
142     for c in node.childNodes:
143         printNode(c)
144
145 #------------------------
146 def parser(src,atraiter):
147 #------------------------
148     """Parse le texte src et retourne un arbre syntaxique (root).
149
150        Cet arbre syntaxique a comme noeuds (childNodes) les commandes a traiter (liste atraiter)
151     """
152     lines=src.splitlines(1)
153     maskedSrc=maskStringsAndComments(src)
154     maskedLines=maskedSrc.splitlines(1)
155
156     root=JDCNode(src)
157
158     # (a) dans un premier temps on extrait les commandes et on les insere
159     #     dans un arbre (root)  les noeuds fils sont stockes dans
160     #     root.childNodes (liste)
161     lineno=0
162     for line in maskedLines:
163         lineno=lineno+1
164         if debug:print "line",lineno,":",line
165         m=pattern_proc.match(line)
166         if m and (m.group(1) in atraiter):
167             if debug:print m.start(3),m.end(3),m.start(4)
168             root.addChild(Command(m.group(1),lineno,m.start(1),m.end(3)))
169         else:
170             m=pattern_oper.match(line)
171             if m and (m.group(2) in atraiter):
172                 root.addChild(Command(m.group(2),lineno,m.start(2),m.end(4)))
173
174     #(b) dans un deuxieme temps , on recupere le texte complet de la commande
175     #    jusqu'a la  derniere parenthese fermante
176
177     # iterateur sur les lignes physiques masquees
178     iterlines=iter(maskedLines)
179
180     linenum=0
181     for c in root.childNodes:
182         lineno=c.lineno
183         colno=c.colno                       # debut de la commande
184         while linenum < lineno:
185             line=iterlines.next()
186             linenum=linenum+1
187             if linenum != lineno:
188                 if debug:print "line %s:"%linenum, line
189         tmp = []
190         hangingBraces = list(emptyHangingBraces)
191         hangingComments = 0
192         while 1:
193             # update hanging braces
194             for i in range(len(implicitContinuationChars)):
195                 contchar = implicitContinuationChars[i]
196                 numHanging = hangingBraces[i]
197
198                 hangingBraces[i] = numHanging+line.count(contchar[0]) - \
199                                 line.count(contchar[1])
200
201             hangingComments ^= line.count('"""') % 2
202             hangingComments ^= line.count("'''") % 2
203
204             if hangingBraces[0] < 0 or hangingBraces[1] < 0 or hangingBraces[2] < 0:
205                 raise UnbalancedBracesException()
206
207             if linecontinueRE.search(line):
208                 tmp.append(lines[linenum-1])
209             elif hangingBraces != emptyHangingBraces:
210                 tmp.append(lines[linenum-1])
211             elif hangingComments:
212                 tmp.append(lines[linenum-1])
213             else:
214                 tmp.append(lines[linenum-1])
215                 src="".join(tmp)
216                 c.src=src
217                 c.endline=linenum
218                 decal=len(line)-line.rindex(')')
219                 c.lastParen=len(src)-decal
220                 if debug:print "logical line %s %s:" % (c.lineno,c.endline),src
221                 break
222             line=iterlines.next()
223             linenum=linenum+1
224
225     return root
226
227
228 #-----------------
229 def lastParen(src):
230 #-----------------
231     """Retourne la position de la derniere parenthese fermante dans src a partir du debut de la string
232
233        La string doit contenir la premiere parenthese ouvrante
234     """
235
236     src=maskStringsAndComments(src)
237     level=0
238     i,n=0,len(src)
239     while i < n:
240         ch=src[i]
241         i=i+1
242         if ch in ('(','['):
243             level=level+1
244         if ch in (')',']'):
245             if level == 0:
246                 raise UnbalancedBracesException()
247             level=level-1
248             if level == 0:
249                 #derniere parenthese fermante
250                 return i
251
252 #-------------------
253 def lastParen2(src):
254 #-------------------
255     """Retourne la position de la derniere parenthese fermante dans src a partir du debut de la string
256
257        La string ne contient pas la premiere parenthese ouvrante
258     """
259     src=maskStringsAndComments(src)
260     level=1
261     i,n=0,len(src)
262     while i < n:
263         ch=src[i]
264         i=i+1
265         if ch in ('(','['):
266             level=level+1
267         if ch in (')',']'):
268             if level == 0:
269                 raise UnbalancedBracesException()
270             level=level-1
271             if level == 0:
272                 #derniere parenthese fermante
273                 return i