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 def maskStringsAndComments(src):
15 """Remplace tous les caracteres dans commentaires et strings par des * """
16 src = escapedQuotesRE.sub("**", src)
17 allstrings = stringsAndCommentsRE.split(src)
18 # every odd element is a string or comment
19 for i in xrange(1, len(allstrings), 2):
20 if allstrings[i].startswith("'''")or allstrings[i].startswith('"""'):
21 allstrings[i] = allstrings[i][:3]+ \
22 allstrings[i][3:-3].translate(allcharsExceptNewlineTranstable)+ \
25 allstrings[i] = allstrings[i][0]+ \
26 allstrings[i][1:-1].translate(allcharsExceptNewlineTranstable)+ \
29 return "".join(allstrings)
31 #un nombre queconque de blancs,un nom,des blancs
32 pattern_oper = re.compile(r"^\s*(.*?=\s*)?([a-zA-Z_]\w*)(\s*)(\()(.*)",re.DOTALL)
33 pattern_proc = re.compile(r"^\s*([a-zA-Z_]\w*)(\s*)(\()(.*)",re.DOTALL)
35 implicitContinuationChars = (('(', ')'), ('[', ']'), ('{', '}'))
36 linecontinueRE = re.compile(r"\\\s*(#.*)?$")
37 emptyHangingBraces = [0,0,0,0,0]
39 class UnbalancedBracesException: pass
45 def addChild(self,node):
46 self.childNodes.append(node)
49 class FactNode(Node):pass
51 def __init__(self,src):
56 def __init__(self,name,lineno,colno,firstparen):
61 self.firstparen=firstparen
64 def __init__(self,name,lineno,colno,endline,endcol):
72 def getText(self,jdc):
73 if self.endline > self.lineno:
74 lignecourante=self.lineno + 1
75 debut=jdc.getLines()[self.lineno-1][self.colno:]
76 fin = jdc.getLines()[self.endline-1][:self.endcol]
78 lignecourante=self.lineno + 1
79 while lignecourante > self.endline :
80 texte = texte + jdc.getLines()[lignecourante]
81 lignecourante = lignecourante + 1
82 if chaineBlanche(fin) == 0 :
84 if texte[-1] == "\n" :
87 texte = jdc.getLines()[self.lineno-1][self.colno:self.endcol]
90 def chaineBlanche(texte) :
91 # retourne 1 si la chaine est composee de " "
94 for i in range(len(texte)) :
95 if texte[i] != " " : bool = 0
99 if hasattr(node,'name'):
102 print "pas de nom pour:",node
103 for c in node.childNodes:
106 def parser(src,atraiter):
107 """Parse le texte src et retourne un arbre syntaxique (root).
109 Cet arbre syntaxique a comme noeuds (childNodes) les commandes à traiter (liste atraiter)
111 lines=src.splitlines(1)
112 maskedSrc=maskStringsAndComments(src)
113 maskedLines=maskedSrc.splitlines(1)
117 # (a) dans un premier temps on extrait les commandes et on les insère dans un arbre (root)
118 # les noeuds fils sont stockés dans root.childNodes (liste)
120 for line in maskedLines:
122 if debug:print "line",lineno,":",line
123 m=pattern_proc.match(line)
124 if m and (m.group(1) in atraiter):
125 if debug:print m.start(3),m.end(3),m.start(4)
126 root.addChild(Command(m.group(1),lineno,m.start(1),m.end(3)))
128 m=pattern_oper.match(line)
129 if m and (m.group(2) in atraiter):
130 root.addChild(Command(m.group(2),lineno,m.start(2),m.end(4)))
132 #(b) dans un deuxième temps , on récupère le texte complet de la commande jusqu'à la
133 # dernière parenthèse fermante
135 #iterateur sur les lignes physiques masquées
136 iterlines=iter(maskedLines)
139 for c in root.childNodes:
141 colno=c.colno # début de la commande
142 while linenum < lineno:
143 line=iterlines.next()
145 if linenum != lineno:
146 if debug:print "line %s:"%linenum, line
148 hangingBraces = list(emptyHangingBraces)
151 # update hanging braces
152 for i in range(len(implicitContinuationChars)):
153 contchar = implicitContinuationChars[i]
154 numHanging = hangingBraces[i]
156 hangingBraces[i] = numHanging+line.count(contchar[0]) - \
157 line.count(contchar[1])
159 hangingComments ^= line.count('"""') % 2
160 hangingComments ^= line.count("'''") % 2
162 if hangingBraces[0] < 0 or hangingBraces[1] < 0 or hangingBraces[2] < 0:
163 raise UnbalancedBracesException()
165 if linecontinueRE.search(line):
166 tmp.append(lines[linenum-1])
167 elif hangingBraces != emptyHangingBraces:
168 tmp.append(lines[linenum-1])
169 elif hangingComments:
170 tmp.append(lines[linenum-1])
172 tmp.append(lines[linenum-1])
176 decal=len(line)-line.rindex(')')
177 c.lastparen=len(src)-decal
178 if debug:print "logical line %s %s:" % (c.lineno,c.endline),src
180 line=iterlines.next()
187 """Retourne la position de la derniere parenthese fermante dans src a partir du debut de la string
189 La string doit contenir la premiere parenthese ouvrante
191 src=maskStringsAndComments(src)
201 raise UnbalancedBracesException()
204 #derniere parenthese fermante
208 """Retourne la position de la derniere parenthese fermante dans src a partir du debut de la string
210 La string ne contient pas la premiere parenthese ouvrante
212 src=maskStringsAndComments(src)
222 raise UnbalancedBracesException()
225 #derniere parenthese fermante