1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2007-2013 EDF R&D
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.
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.
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
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 import string,traceback,re
23 identifier = re.compile(r"^[^\d\W]\w*\Z", re.UNICODE)
26 from Extensions.i18n import tr
27 from I_MACRO_ETAPE import MACRO_ETAPE
28 from Extensions import interpreteur_formule
29 from Editeur import analyse_catalogue
31 analyse_catalogue.l_noms_commandes.append('FORM') # déclare le nom FORM à l'analyseur de catalogue
34 class FORM_ETAPE(MACRO_ETAPE):
36 interpreteur = interpreteur_formule.Interpreteur_Formule
39 self.mc_liste=self.build_mc()
40 # on crée la liste des types autorisés (liste des noms de mots-clés
41 # simples dans le catalogue de FORMULE)
42 self.l_types_autorises = self.definition.entites.keys()
43 # en plus de la construction traditionnelle des fils de self
44 # il faut pour les FORMULE décortiquer l'expression ...
45 self.type_retourne,self.arguments,self.corps = self.analyse_formule()
48 def analyse_formule(self):
50 Cette méthode décortique l'expression de la FORMULE.
51 Elle retourne 3 valeurs:
52 - le type retourné par la FORMULE
53 - les arguments de la FORMULE
54 - le corps de la FORMULE, cad son expression
56 if len(self.mc_liste) == 0:
57 # pas de fils pour self --> la FORMULE est incomplète
60 if len(self.mc_liste) > 0:
61 child = self.mc_liste[0] # child est un MCSIMP
62 corps = child.getval()
65 if len(self.mc_liste) > 1:
66 child = self.mc_liste[1]
67 l_args= child.getval()
70 return type_retourne,l_args,corps
74 Retourne le nom de la FORMULE, cad le nom de la SD si elle existe,
78 return self.sd.get_name()
82 def get_formule(self):
84 Retourne un tuple décrivant la formule :
85 (nom,type_retourne,arguments,corps)
87 t,a,c = self.analyse_formule()
91 def verif_arguments(self,arguments = None):
93 Vérifie si les arguments passés en argument (si aucun prend les arguments courants)
94 sont des arguments valide pour une FORMULE.
96 - un booléen, qui vaut 1 si arguments licites, 0 sinon
97 - un message d'erreurs ('' si illicites)
100 arguments = self.arguments
102 return 0,"Une formule doit avoir au minimum un argument"
103 # il faut au préalable enlever les parenthèses ouvrantes et fermantes
104 # encadrant les arguments
105 arguments = string.strip(arguments)
106 if arguments[0] != '(':
107 return 0,tr("La liste des arguments d'une formule doit etre entre parentheses : parenthese ouvrante manquante")
108 if arguments[-1] != ')':
109 return 0,tr("La liste des arguments d'une formule doit etre entre parentheses : parenthese fermante manquante")
110 # on peut tester la syntaxe de chaque argument maintenant
113 arguments = arguments[1:-1] # on enlève les parenthèses ouvrante et fermante
114 l_arguments = string.split(arguments,',')
115 for a in l_arguments :
116 if not re.match(identifier,str(a)) : return 0, str(a)+" n est pas un identifiant"
119 def verif_corps(self,corps=None,arguments=None):
121 Cette méthode a pour but de vérifier si le corps de la FORMULE
122 est syntaxiquement correct.
124 - un booléen, qui vaut 1 si corps de FORMULE licite, 0 sinon
125 - un message d'erreurs ('' si illicite)
130 arguments = self.arguments
131 formule=(self.get_nom(),self.type_retourne,arguments,corps)
132 # on récupère la liste des constantes et des autres fonctions prédéfinies
133 # et qui peuvent être utilisées dans le corps de la formule courante
134 l_ctes,l_form = self.jdc.get_parametres_fonctions_avant_etape(self)
135 # on crée un objet vérificateur
137 verificateur = self.interpreteur(formule=formule,
141 traceback.print_exc()
142 return 0,tr("Impossible de realiser la verification de la formule")
143 return verificateur.isvalid(),verificateur.report()
145 def verif_nom(self,nom=None):
147 Vérifie si le nom passé en argument (si aucun prend le nom courant)
148 est un nom valide pour une FORMULE.
150 - un booléen, qui vaut 1 si nom licite, 0 sinon
151 - un message d'erreurs ('' si illicite)
156 return 0,tr("Pas de nom donne a la FORMULE")
158 return 0,tr("Un nom de FORMULE ne peut depasser 8 caracteres")
159 if nom[0] > "0" and nom[0] < "9" :
160 return 0,tr("Un nom de FORMULE ne peut pas commencer par un chiffre")
161 sd = self.parent.get_sd_autour_etape(nom,self)
163 return 0,tr("Un concept de nom %s existe deja !" %nom)
166 def verif_type(self,type=None):
168 Vérifie si le type passé en argument (si aucun prend le type courant)
169 est un type valide pour une FORMULE.
171 - un booléen, qui vaut 1 si type licite, 0 sinon
172 - un message d'erreurs ('' si illicite)
175 type = self.type_retourne
177 return 0,tr("Le type de la valeur retournee n'est pas specifie")
178 if type not in self.l_types_autorises:
179 return 0,tr("Une formule ne peut retourner une valeur de type : %s" %type)
182 def verif_formule(self,formule=None):
184 Vérifie la validité de la formule passée en argument.
185 Cette nouvelle formule est passée sous la forme d'un tuple : (nom,type_retourne,arguments,corps)
186 Si aucune formule passée, prend les valeurs courantes de la formule
188 - un booléen, qui vaut 1 si formule licite, 0 sinon
189 - un message d'erreurs ('' si illicite)
192 formule = (None,None,None,None)
193 test_nom,erreur_nom = self.verif_nom(formule[0])
194 test_type,erreur_type = self.verif_type(formule[1])
196 args = '('+formule[2]+')'
199 test_arguments,erreur_arguments = self.verif_arguments(args)
200 test_corps,erreur_corps = self.verif_corps(corps = formule[3], arguments = args)
201 # test global = produit des tests partiels
202 test = test_nom*test_type*test_arguments*test_corps
203 # message d'erreurs global = concaténation des messages partiels
206 for mess in (erreur_nom,erreur_type,erreur_arguments,erreur_corps):
207 erreur = erreur+(len(mess) > 0)*'\n'+mess
210 def verif_formule_python(self,formule=None):
212 Pour l instant ne fait qu un compile python
213 il serait possible d ajouter des tests sur les arguments
214 ou le type retourne mais ...
217 formule = (None,None,None,None)
218 test_nom,erreur_nom = self.verif_nom(formule[0])
220 args = '('+formule[2]+')'
223 test_arguments,erreur_arguments = self.verif_arguments(args)
228 compile(corps,'<string>','eval')
230 erreur_formule= "le corps de la formule n'est pas une formule python valide"
233 test = test_nom*test_arguments*test_formule
235 for mess in (erreur_nom,erreur_arguments,erreur_formule):
236 erreur = erreur+(len(mess) > 0)*'\n'+mess
240 def update(self,formule):
243 Met à jour les champs nom, type_retourne,arguments et corps de la FORMULE
244 par les nouvelles valeurs passées dans le tuple formule.
245 On stocke les valeurs SANS vérifications.
247 self.type_retourne = formule[1]
248 self.arguments = '('+formule[2]+')'
249 self.corps = formule[3]
250 # il faut ajouter le mot-clé simple correspondant dans mc_liste
251 # pour cela on utilise la méthode générale build_mc
252 # du coup on est obligé de modifier le dictionnaire valeur de self ...
254 self.valeur[self.type_retourne] = self.arguments+' = ' + self.corps
256 sd = self.get_sd_prod()
261 # Il faut que formule soit constituee de
265 # corps de la fonction
266 # il faut aussi que les arguments soient sous forme de tuple
267 def update_formule_python(self,formule):
270 if len(formule) < 4 :
273 if arguments[0] == '(' :
274 arguments=arguments[1:]
275 if arguments[-1] == ')' :
276 arguments=arguments[:-1]
277 self.arguments=tuple(arguments.split(','))
279 mocles={"NOM_PARA":self.arguments}
280 if formule[1] == "REEL":
281 mocles["VALE"]=formule[2]
282 if formule[1] == "COMPLEXE":
283 mocles["VALE_C"]=formule[2]
285 for k,v in self.definition.entites.items():
286 if not mocles.has_key(k):continue
287 child=self.definition.entites[k](None,nom=k,parent=self)
288 child.valeur=mocles[k]
289 child.state = 'modified'
290 self.mc_liste.append(child)
292 self.corps = formule[2]
293 self.type_retourne = formule[1]
294 sd = self.get_sd_prod()
302 Rend l'etape courante active.
303 Il faut ajouter la formule au contexte global du JDC
308 if nom == '' : return
310 self.jdc.append_fonction(self.sd)
316 Rend l'etape courante inactive
317 Il faut supprimer la formule du contexte global du JDC
321 if not self.sd : return
322 self.jdc.del_fonction(self.sd)
324 def update_concept(self,sd):
327 def delete_concept(self,sd):
332 Mettre a jour les mots cles de l etape et eventuellement le concept produit si reuse
333 suite à la disparition du concept sd
334 Seuls les mots cles simples MCSIMP font un traitement autre que de transmettre aux fils,
335 sauf les objets FORM_ETAPE qui doivent vérifier que le concept détruit n'est pas
336 utilisé dans le corps de la fonction
340 def replace_concept(self,old_sd,sd):
343 - old_sd=concept remplace
344 - sd = nouveau concept
346 Les objets FORM_ETAPE devraient vérifier que le concept remplacé n'est pas
347 utilisé dans le corps de la fonction