1 # -*- coding: utf-8 -*-
7 escapedQuotesRE = re.compile(r"(\\\\|\\\"|\\\')")
8 stringsAndCommentsRE = \
9 re.compile("(\"\"\".*?\"\"\"|'''.*?'''|\"[^\"]*\"|\'[^\']*\'|#.*?\n)", re.DOTALL)
10 allchars = string.maketrans("", "")
11 allcharsExceptNewline = allchars[: allchars.index('\n')]+allchars[allchars.index('\n')+1:]
12 allcharsExceptNewlineTranstable = string.maketrans(allcharsExceptNewline, '*'*len(allcharsExceptNewline))
14 #------------------------------
15 def maskStringsAndComments(src):
16 #------------------------------
17 """Remplace tous les caracteres dans commentaires et strings par des * """
19 src = escapedQuotesRE.sub("**", src)
20 allstrings = stringsAndCommentsRE.split(src)
21 # every odd element is a string or comment
22 for i in xrange(1, len(allstrings), 2):
23 if allstrings[i].startswith("'''")or allstrings[i].startswith('"""'):
24 allstrings[i] = allstrings[i][:3]+ \
25 allstrings[i][3:-3].translate(allcharsExceptNewlineTranstable)+ \
28 allstrings[i] = allstrings[i][0]+ \
29 allstrings[i][1:-1].translate(allcharsExceptNewlineTranstable)+ \
32 return "".join(allstrings)
34 #un nombre queconque de blancs,un nom,des blancs
35 pattern_oper = re.compile(r"^\s*(.*?=\s*)?([a-zA-Z_]\w*)(\s*)(\()(.*)",re.DOTALL)
36 pattern_proc = re.compile(r"^\s*([a-zA-Z_]\w*)(\s*)(\()(.*)",re.DOTALL)
38 implicitContinuationChars = (('(', ')'), ('[', ']'), ('{', '}'))
39 linecontinueRE = re.compile(r"\\\s*(#.*)?$")
40 emptyHangingBraces = [0,0,0,0,0]
42 #--------------------------------------
43 class UnbalancedBracesException: pass
44 #--------------------------------------
52 def addChild(self,node):
53 self.childNodes.append(node)
65 def __init__(self,src):
72 def __init__(self,name,lineno,colno,firstparen):
77 self.firstparen=firstparen
82 def __init__(self,name,lineno,colno,endline,endcol):
90 def getText(self,jdc):
91 if self.endline > self.lineno:
92 debut=jdc.getLines()[self.lineno-1][self.colno:]
93 fin = jdc.getLines()[self.endline-1][:self.endcol]
95 lignecourante=self.lineno
96 while lignecourante < self.endline -1 :
97 texte = texte + jdc.getLines()[lignecourante]
98 lignecourante = lignecourante + 1
99 if chaineBlanche(fin) == 0 :
101 if texte[-1] == "\n" :
104 texte = jdc.getLines()[self.lineno-1][self.colno:self.endcol]
107 #-------------------------
108 def chaineBlanche(texte) :
109 #-------------------------
110 # retourne 1 si la chaine est composee de " "
113 for i in range(len(texte)) :
114 if texte[i] != " " : bool = 0
120 if hasattr(node,'name'):
123 print "pas de nom pour:",node
124 for c in node.childNodes:
127 #------------------------
128 def Parser(src,atraiter):
129 #------------------------
130 """Parse le texte src et retourne un arbre syntaxique (root).
132 Cet arbre syntaxique a comme noeuds (childNodes) les commandes à traiter (liste atraiter)
134 lines=src.splitlines(1)
135 maskedSrc=maskStringsAndComments(src)
136 maskedLines=maskedSrc.splitlines(1)
140 # (a) dans un premier temps on extrait les commandes et on les insère
141 # dans un arbre (root) les noeuds fils sont stockés dans
142 # root.childNodes (liste)
144 for line in maskedLines:
146 if debug:print "line",lineno,":",line
147 m=pattern_proc.match(line)
148 if m and (m.group(1) in atraiter):
149 if debug:print m.start(3),m.end(3),m.start(4)
150 root.addChild(Command(m.group(1),lineno,m.start(1),m.end(3)))
152 m=pattern_oper.match(line)
153 if m and (m.group(2) in atraiter):
154 root.addChild(Command(m.group(2),lineno,m.start(2),m.end(4)))
156 #(b) dans un deuxième temps , on récupère le texte complet de la commande
157 # jusqu'à la dernière parenthèse fermante
159 # iterateur sur les lignes physiques masquées
160 iterlines=iter(maskedLines)
163 for c in root.childNodes:
165 colno=c.colno # début de la commande
166 while linenum < lineno:
167 line=iterlines.next()
169 if linenum != lineno:
170 if debug:print "line %s:"%linenum, line
172 hangingBraces = list(emptyHangingBraces)
175 # update hanging braces
176 for i in range(len(implicitContinuationChars)):
177 contchar = implicitContinuationChars[i]
178 numHanging = hangingBraces[i]
180 hangingBraces[i] = numHanging+line.count(contchar[0]) - \
181 line.count(contchar[1])
183 hangingComments ^= line.count('"""') % 2
184 hangingComments ^= line.count("'''") % 2
186 if hangingBraces[0] < 0 or hangingBraces[1] < 0 or hangingBraces[2] < 0:
187 raise UnbalancedBracesException()
189 if linecontinueRE.search(line):
190 tmp.append(lines[linenum-1])
191 elif hangingBraces != emptyHangingBraces:
192 tmp.append(lines[linenum-1])
193 elif hangingComments:
194 tmp.append(lines[linenum-1])
196 tmp.append(lines[linenum-1])
200 decal=len(line)-line.rindex(')')
201 c.lastparen=len(src)-decal
202 if debug:print "logical line %s %s:" % (c.lineno,c.endline),src
204 line=iterlines.next()
213 """Retourne la position de la derniere parenthese fermante dans src a partir du debut de la string
215 La string doit contenir la premiere parenthese ouvrante
218 src=maskStringsAndComments(src)
228 raise UnbalancedBracesException()
231 #derniere parenthese fermante
237 """Retourne la position de la derniere parenthese fermante dans src a partir du debut de la string
239 La string ne contient pas la premiere parenthese ouvrante
241 src=maskStringsAndComments(src)
251 raise UnbalancedBracesException()
254 #derniere parenthese fermante