Salome HOME
bug
[tools/eficas.git] / generator / Formatage.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 """
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 formateJdc(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)==list:
78         # L'etape est sous la forme d'une liste dont le premier element est une chaine
79         self.indent=[]
80         self.indent.append(len(etape[0]))
81         self.indent_courant = self.indent[0]
82         self.texte_etape = '\n' + etape[0]
83         if len(etape)>1 :
84           self.formateEtape(etape[1:])
85       else :
86         # L'etape est deja sous forme de chaine de caracteres
87         self.indent=[]
88         self.texte_etape = etape
89
90       m=comment.match(self.texte_etape)
91       # si ce n est pas la premiere ligne
92       if self.jdc_fini != ""  :
93         # si il n y avait pas de commentaire avant on met un saut de ligne
94         if commentaireavant == 0 :
95            self.jdc_fini = self.jdc_fini + '\n' + self.texte_etape
96         else :
97            self.jdc_fini = self.jdc_fini + self.texte_etape
98       # si c est la premiere ligne
99       else :
100         # on ne met pas de saut de ligne avant la premiere ligne
101         # si c est un commentaire on enleve le saut de ligne precedent
102         if m : self.texte_etape=self.texte_etape[1:]
103         self.jdc_fini = self.texte_etape
104       if m :
105         commentaireavant=1
106       else :
107         commentaireavant=0
108
109     return self.jdc_fini
110
111
112
113   def formateEtape(self,liste):
114     """
115         Enrichissement de la chaine de caracteres representant l'etape (attribut
116         texte_etape de l'objet Formatage).
117         Les elements a ajouter sont dans l'argument liste de la methode.
118         L'objet "liste" à traiter a été produit par le module generator. En particulier
119         les parenthèses et les virgules ont été produites par ce module
120     """
121     l_patterns_fin_etape = ( ');' , ');\n' )
122     l_patterns_fin_mcf   = ( ')'  , '),'   )
123
124     ind = 0
125     for element in liste :
126       if type(element)==list:
127
128         # il s'agit d'un mot-clé facteur
129         # on écrit son nom (element[0])
130         longueur = self.longueur(self.texte_etape)
131         try:
132           increment = len(('\n'+self.indent_courant*' ')*ind + element[0])
133         except:
134           print (tr('ERREUR'))
135           print (liste)
136           print (element)
137         self.texte_etape = self.texte_etape + (u'\n'+self.indent_courant*' ')*ind + element[0]
138         length = len(self.indent)
139         self.indent.insert(length,self.indent[length-1]+len(element[0]))
140         self.indent_courant = self.indent[length]
141         # on écrit ses fils
142         self.formateEtape(element[1:])
143       #elif type(element) == types.StringType:
144       #elif type(element) == bytes:
145       # PNPNPN -> marre du python 2 et 3
146       # on remplace par else dans if
147       else :
148
149         # il s'agit d'un mot-clé simple ou de ')' ou ');' ou '),' ou ');\n'
150
151         if element in l_patterns_fin_mcf :
152               self.traiteMcfact(s_mcfact=element,ind=ind)
153         elif element in l_patterns_fin_etape :
154               self.traiteEtape(s_etape=element,ind=ind)
155         else :
156               self.traiteMcsimp(s_mcsimp=element,ind=ind)
157
158       ind = 1
159
160   def traiteEtape(self,s_etape,ind) :
161       """
162           Traite une partie du jdc formaté : s_etape, une chaîne de caractères
163           contenant une étape
164           L'attribut self.texte_etape est modifié (complété) par le traitement
165           L'attribut self.indent est modifié par le traitement
166           L'attribut self.indent_courant est modifié par le traitement
167       """
168       length = len(self.indent)
169       if length > 1:
170           last = self.indent[length-1]
171           self.indent.remove(last)
172           self.indent_courant=self.indent[length-2]
173       else :
174           self.indent_courant=self.indent[0]
175       self.texte_etape = self.texte_etape + s_etape.strip()
176
177   def traiteMcfact(self,s_mcfact,ind) :
178       """
179           Traite une partie du jdc formaté : s_mcfact, une chaîne de caractères
180           contenant un mot-clef facteur.
181           L'attribut self.texte_etape est modifié (complété) par le traitement
182           L'attribut self.indent est modifié par le traitement
183           L'attribut self.indent_courant est modifié par le traitement
184       """
185       self.texte_etape = self.texte_etape + s_mcfact.strip()
186       length = len(self.indent)
187       if length > 1:
188            last = self.indent[length-1]
189            self.indent.remove(last)
190            self.indent_courant=self.indent[length-2]
191       else :
192            self.indent_courant=self.indent[0]
193       return
194
195
196   def traiteMcsimp(self,s_mcsimp,ind) :
197       """
198           Traite une partie du jdc formaté : s_mcsimp, une chaîne de caractères
199           contenant un mot-clef simple.
200           L'attribut self.texte_etape est modifié (complété) par le traitement
201       """
202       #
203       # Ajout PN pour defi_fonction
204       if self.texte_etape.find("DEFI_FONCTION") > 1 :
205           bool_fonction=1
206           if s_mcsimp.find("\n")  > 1:
207               txt=""; bool = 0; numident=1
208               for l in s_mcsimp.splitlines() :
209                  if bool == 0 :
210                     bool = 1
211                     numident=s_mcsimp.find("=")+2
212                     txt=l
213                  else :
214                     txt=txt+('\n'+self.indent_courant*' '+numident*' ')*ind+l
215               s_mcsimp = txt
216       else :
217           bool_fonction=0
218       longueur = self.longueur(self.texte_etape)
219       increment = len((u'\n'+self.indent_courant*' ')*ind + s_mcsimp.strip())
220       if (bool_fonction == 1 ) :
221           self.texte_etape = self.texte_etape+'\n'+self.indent_courant*' ' +s_mcsimp
222       elif ( ((1-ind)*longueur+increment) <= self.l_max ) :
223           self.texte_etape = self.texte_etape + ('\n'+self.indent_courant*' ')*ind +s_mcsimp.strip()
224       else :
225           # il faut couper ...
226           #nom,valeur = string.split(s_mcsimp,self.sep,1)
227           nom,valeur = str.split(s_mcsimp,self.sep,1)
228           chaine = self.creerChaine(nom,valeur,'\n'+self.indent_courant*' ',ind)
229           #self.jdc_fini = self.jdc_fini + ('\n'+self.indent_courant*' ')*ind + s_mcsimp.strip()
230           self.texte_etape = self.texte_etape + chaine
231       return
232
233
234   def longueur(self,texte):
235     """
236        texte est une string qui peut contenir des retours chariots
237        Cette méthode retourne la longueur de la dernière ligne de texte
238     """
239     #liste = texte.split('\n')
240     #return len(liste[-1])
241     if texte [-1] == '\n' : return 0
242     return len(texte[texte.rfind('\n'):-1])
243
244
245   def creerChaine(self,nom,valeur,increment,ind):
246     """
247         La methode creerChaine reconstitue un objet Eficas à partir de
248              - son nom,
249              - sa valeur.
250     """
251     s=''
252     if len(increment + nom + self.sep) <= self.l_max:
253       texte = increment*ind
254       label = nom + self.sep
255       s=texte + label
256       longueur = len(increment + label)
257
258       if ('(' not in valeur) or (valeur[0:3]=='"""') :
259         # il s'agit d'une vraie chaîne de caractères
260         val = len(valeur)
261         texte = (self.l_max-2-val)*' '+valeur
262         s=s+'\n'+texte
263       elif re.match(filePattern,valeur) or re.match(filePattern2,valeur):
264         val = len(valeur)
265         texte = (self.l_max-2-val)*' '+valeur
266         s=s+'\n'+texte
267       elif ',' in valeur:
268         # il s'agit d'une liste de tuple
269         # c est trop complique on ne splitte pas
270         if valeur[0:2]=='((' or valeur[0:2]=='[(':
271            s=s+valeur
272            return s
273         # il s'agit d'une liste
274         liste = valeur.split(',')
275         i=0
276         for arg in liste :
277           ajout = arg.strip()
278           if len(ajout) == 0 : continue
279           longueur = self.longueur(texte = (texte + label)) + len(ajout +',') + (1-i)*len(increment)
280           if longueur  <= self.l_max:
281               if ajout[-1] != ')':
282                 texte = texte + ajout +','
283               else :
284                 texte = texte + ajout
285           else :
286             i=1
287             if ajout[-1] != ')':
288               texte = texte  + increment + (len(label)+2)*' ' + ajout  + ','
289             else :
290               texte = texte  + increment + (len(label)+2)*' ' + ajout
291
292         s=s+texte
293         s =  s + ','
294
295       else :
296         # On a une ( mais pas de , . On passe la chaine sans modification
297         val = len(valeur)
298         texte = (self.l_max-2-val)*' '+valeur
299         s=s+'\n'+texte
300
301     return s
302
303 class FormatageLigne(Formatage) :
304   def __init__(self,l_jdc,code=None,mode=None,sep='=',l_max="**"):
305       Formatage.__init__(self,l_jdc,code=None,mode=None,sep='=',l_max="**")
306
307   def formateJdc(self):
308       texte1=Formatage.formateJdc(self)
309       newText=""
310       lignes=texte1.split("\n")
311       texte=""
312       pattern_debut_blanc  = re.compile(r"^ \s*.*")
313       pattern_commentaire   = re.compile(r"^\s*#.*")
314       pattern_vide=re.compile(r"\s*^$")
315       for l in lignes :
316           if pattern_commentaire.match(l) or pattern_vide.match(l):
317              newText+=l+"\n"
318              continue
319           if not pattern_debut_blanc.match(l) : texte=l
320           else : texte+=re.sub(r'^ \s*',' ',l)
321           if texte[-1]==";" :
322              newText+=texte+"\n"
323              texte=""
324       return newText
325
326