Salome HOME
BOUNDARY... dans Telemac2D
[tools/eficas.git] / generator / Formatage.py
1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2007-2013   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 """
21     Ce module contient la classe Formatage qui permet le formatage d'une 
22     liste de chaines de caractères dans une syntaxe représentative d'un
23     jeu de commandes en un texte présentable
24 """
25 from __future__ import absolute_import
26 from __future__ import print_function
27 try :
28    from builtins import object
29 except : pass
30 import types,re
31 from Extensions.i18n import tr
32 filePattern="'[^\(\)]([^\(\)]*\([^\(\)]*\))*[^\(\)]*'"
33 filePattern2='"[^\(\)]([^\(\)]*\([^\(\)]*\))*[^\(\)]*"'
34
35 class Formatage (object):
36   """ 
37      Cette classe contient toutes les méthodes nécessaires au formatage
38      de la chaine de caracteres issue d'un generator en un fichier
39      'lisible' ie avec indentations
40
41      L'objet attend en parametre du constructeur (argument l_jdc) une representation
42      du jeu de commandes sous la forme d'une liste.
43
44      Chaque element de la liste est la representation d'une etape.
45
46      La representation d'une etape est une liste dont le premier element est une chaine de
47      caracteres donnant le debut de la commande ("xxx=lire_maillage(", par exemple).
48      Les elements suivants sont les representations des mots cles simples et facteurs.
49      Elle se termine avec un element de fin : ");"
50
51      La representation d'un mot cle simple est une chaine de caracteres (info=2, par exemple).
52
53      La representation d'un mot cle facteur est semblable à celle de l'étape : premier element
54      caracteristique du mot cle facteur suivi d'elements representatifs des mots cles simples.
55      Elle se termine avec un element de fin : ")" ou "),".
56   """
57   def __init__(self,l_jdc,code=None,mode=None,sep='=',l_max=72):
58     # l_jdc représente le jeu de commandes brut sous forme de liste
59     self.l_jdc = l_jdc
60     self.jdc_fini =''
61     self.count = 0
62     self.sep=sep
63     self.l_max=l_max
64     if mode == '.py':
65        self.sep = '='
66        self.l_max = 132 
67     elif code == 'ASTER':
68        self.sep = ':'
69        self.l_max = 72
70
71   def formate_jdc(self):
72     comment=re.compile("\n#")
73     commentaireavant=0
74     for etape in self.l_jdc:
75       self.count = self.count+1
76       self.texte_etape = ''
77       #if type(etape)==types.ListType:
78       if type(etape)==list:
79         # L'etape est sous la forme d'une liste dont le premier element est une chaine
80         self.indent=[]
81         self.indent.append(len(etape[0]))
82         self.indent_courant = self.indent[0]
83         self.texte_etape = '\n' + etape[0]
84         if len(etape)>1 :
85           self.formate_etape(etape[1:])
86       else :
87         # L'etape est deja sous forme de chaine de caracteres
88         self.indent=[]
89         self.texte_etape = etape
90
91       m=comment.match(self.texte_etape)
92       # si ce n est pas la premiere ligne
93       if self.jdc_fini != ""  : 
94         # si il n y avait pas de commentaire avant on met un saut de ligne
95         if commentaireavant == 0 :
96            self.jdc_fini = self.jdc_fini + '\n' + self.texte_etape
97         else :
98            self.jdc_fini = self.jdc_fini + self.texte_etape
99       # si c est la premiere ligne
100       else :
101         # on ne met pas de saut de ligne avant la premiere ligne 
102         # si c est un commentaire on enleve le saut de ligne precedent
103         if m : self.texte_etape=self.texte_etape[1:]
104         self.jdc_fini = self.texte_etape
105       if m : 
106         commentaireavant=1 
107       else :
108         commentaireavant=0 
109
110     return self.jdc_fini
111   
112   
113
114   def formate_etape(self,liste):
115     """
116         Enrichissement de la chaine de caracteres representant l'etape (attribut
117         texte_etape de l'objet Formatage).
118         Les elements a ajouter sont dans l'argument liste de la methode.
119         L'objet "liste" à traiter a été produit par le module generator. En particulier
120         les parenthèses et les virgules ont été produites par ce module
121     """
122     l_patterns_fin_etape = ( ');' , ');\n' )
123     l_patterns_fin_mcf   = ( ')'  , '),'   )
124
125     ind = 0
126     for element in liste :
127       if type(element) == types.ListType:
128
129         # il s'agit d'un mot-clé facteur
130         # on écrit son nom (element[0])
131         longueur = self.longueur(self.texte_etape)
132         try:
133           increment = len(('\n'+self.indent_courant*' ')*ind + element[0])
134         except:
135           print (tr('ERREUR'))
136           print (liste)
137           print (element)
138         self.texte_etape = self.texte_etape + (u'\n'+self.indent_courant*' ')*ind + element[0]
139         length = len(self.indent)
140         self.indent.insert(length,self.indent[length-1]+len(element[0]))
141         self.indent_courant = self.indent[length]
142         # on écrit ses fils
143         self.formate_etape(element[1:])
144       #elif type(element) == types.StringType:
145       elif type(element) == bytes:
146
147         # il s'agit d'un mot-clé simple ou de ')' ou ');' ou '),' ou ');\n'
148
149         if element in l_patterns_fin_mcf :
150               self.traite_mcfact(s_mcfact=element,ind=ind)
151         elif element in l_patterns_fin_etape :
152               self.traite_etape(s_etape=element,ind=ind)
153         else :
154               self.traite_mcsimp(s_mcsimp=element,ind=ind)
155
156       ind = 1
157
158   def traite_etape(self,s_etape,ind) :
159       """
160           Traite une partie du jdc formaté : s_etape, une chaîne de caractères
161           contenant une étape
162           L'attribut self.texte_etape est modifié (complété) par le traitement
163           L'attribut self.indent est modifié par le traitement
164           L'attribut self.indent_courant est modifié par le traitement
165       """
166       length = len(self.indent)
167       if length > 1:
168           last = self.indent[length-1]
169           self.indent.remove(last)
170           self.indent_courant=self.indent[length-2]
171       else :
172           self.indent_courant=self.indent[0]
173       self.texte_etape = self.texte_etape + s_etape.strip()
174
175   def traite_mcfact(self,s_mcfact,ind) :
176       """
177           Traite une partie du jdc formaté : s_mcfact, une chaîne de caractères
178           contenant un mot-clef facteur.
179           L'attribut self.texte_etape est modifié (complété) par le traitement
180           L'attribut self.indent est modifié par le traitement
181           L'attribut self.indent_courant est modifié par le traitement
182       """
183       self.texte_etape = self.texte_etape + s_mcfact.strip()
184       length = len(self.indent)
185       if length > 1:
186            last = self.indent[length-1]
187            self.indent.remove(last)
188            self.indent_courant=self.indent[length-2]
189       else :
190            self.indent_courant=self.indent[0]
191       return
192
193
194   def traite_mcsimp(self,s_mcsimp,ind) :
195       """
196           Traite une partie du jdc formaté : s_mcsimp, une chaîne de caractères
197           contenant un mot-clef simple.
198           L'attribut self.texte_etape est modifié (complété) par le traitement
199       """
200       #
201       # Ajout PN pour defi_fonction
202       if self.texte_etape.find("DEFI_FONCTION") > 1 :
203           bool_fonction=1
204           if s_mcsimp.find("\n")  > 1:
205               txt=""; bool = 0; numident=1
206               for l in s_mcsimp.splitlines() :
207                  if bool == 0 :
208                     bool = 1
209                     numident=s_mcsimp.find("=")+2
210                     txt=l
211                  else :
212                     txt=txt+('\n'+self.indent_courant*' '+numident*' ')*ind+l
213               s_mcsimp = txt
214       else : 
215           bool_fonction=0
216       longueur = self.longueur(self.texte_etape)
217       increment = len((u'\n'+self.indent_courant*' ')*ind + s_mcsimp.strip())
218       if (bool_fonction == 1 ) :
219           self.texte_etape = self.texte_etape+'\n'+self.indent_courant*' ' +s_mcsimp
220       elif ( ((1-ind)*longueur+increment) <= self.l_max ) :
221           self.texte_etape = self.texte_etape + ('\n'+self.indent_courant*' ')*ind +s_mcsimp.strip() 
222       else :
223           # il faut couper ...
224           #nom,valeur = string.split(s_mcsimp,self.sep,1)
225           nom,valeur = str.split(s_mcsimp,self.sep,1)
226           chaine = self.creer_chaine(nom,valeur,'\n'+self.indent_courant*' ',ind)
227           #self.jdc_fini = self.jdc_fini + ('\n'+self.indent_courant*' ')*ind + s_mcsimp.strip()
228           self.texte_etape = self.texte_etape + chaine
229       return
230
231
232   def longueur(self,texte):
233     """ 
234        texte est une string qui peut contenir des retours chariots
235        Cette méthode retourne la longueur de la dernière ligne de texte 
236     """
237     #liste = texte.split('\n')
238     #return len(liste[-1])
239     if texte [-1] == '\n' : return 0 
240     return len(texte[texte.rfind('\n'):-1])
241     
242
243   def creer_chaine(self,nom,valeur,increment,ind):
244     """
245         La methode creer_chaine reconstitue un objet Eficas à partir de
246              - son nom,
247              - sa valeur.
248     """
249     s=''
250     if len(increment + nom + self.sep) <= self.l_max:
251       texte = increment*ind
252       label = nom + self.sep
253       s=texte + label
254       longueur = len(increment + label)
255
256       if ('(' not in valeur) or (valeur[0:3]=='"""') :
257         # il s'agit d'une vraie chaîne de caractères
258         val = len(valeur)
259         texte = (self.l_max-2-val)*' '+valeur
260         s=s+'\n'+texte
261       elif re.match(filePattern,valeur) or re.match(filePattern2,valeur):
262         val = len(valeur)
263         texte = (self.l_max-2-val)*' '+valeur
264         s=s+'\n'+texte
265       elif ',' in valeur:
266         # il s'agit d'une liste de tuple
267         # c est trop complique on ne splitte pas
268         if valeur[0:2]=='((' or valeur[0:2]=='[(':
269            s=s+valeur
270            return s
271         # il s'agit d'une liste
272         liste = valeur.split(',')
273         i=0
274         for arg in liste :
275           ajout = arg.strip()
276           if len(ajout) == 0 : continue
277           longueur = self.longueur(texte = (texte + label)) + len(ajout +',') + (1-i)*len(increment)
278           if longueur  <= self.l_max:
279               if ajout[-1] != ')':
280                 texte = texte + ajout +','
281               else :
282                 texte = texte + ajout
283           else :
284             i=1
285             if ajout[-1] != ')':
286               texte = texte  + increment + (len(label)+2)*' ' + ajout  + ','
287             else :
288               texte = texte  + increment + (len(label)+2)*' ' + ajout
289
290         s=s+texte
291         s =  s + ','
292
293       else :
294         # On a une ( mais pas de , . On passe la chaine sans modification
295         val = len(valeur)
296         texte = (self.l_max-2-val)*' '+valeur
297         s=s+'\n'+texte
298
299     return s
300
301 class FormatageLigne(Formatage) :
302   def __init__(self,l_jdc,code=None,mode=None,sep='=',l_max="**"):
303       Formatage.__init__(self,l_jdc,code=None,mode=None,sep='=',l_max="**")
304       
305   def formate_jdc(self):
306       texte1=Formatage.formate_jdc(self)
307       newText=""
308       lignes=texte1.split("\n")
309       texte=""
310       pattern_debut_blanc  = re.compile(r"^ \s*.*")
311       pattern_commentaire   = re.compile(r"^\s*#.*")
312       pattern_vide=re.compile(r"\s*^$")
313       for l in lignes :
314           if pattern_commentaire.match(l) or pattern_vide.match(l): 
315              newText+=l+"\n"
316              continue
317           if not pattern_debut_blanc.match(l) : texte=l 
318           else : texte+=re.sub(r'^ \s*',' ',l)
319           if texte[-1]==";" :
320              newText+=texte+"\n"
321              texte=""
322       return newText
323
324