1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2007-2017 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 from __future__ import absolute_import
23 import string,traceback,re
24 identifier = re.compile(r"^[^\d\W]\w*\Z", re.UNICODE)
27 from Extensions.i18n import tr
28 from .I_MACRO_ETAPE import MACRO_ETAPE
29 from Extensions import interpreteur_formule
30 from Editeur import analyse_catalogue
32 analyse_catalogue.l_noms_commandes.append('FORM') # declare le nom FORM a l'analyseur de catalogue
35 class FORM_ETAPE(MACRO_ETAPE):
37 interpreteur = interpreteur_formule.Interpreteur_Formule
40 self.mc_liste=self.build_mc()
41 # on cree la liste des types autorises (liste des noms de mots-cles
42 # simples dans le catalogue de FORMULE)
43 self.l_types_autorises = list(self.definition.entites.keys())
44 # en plus de la construction traditionnelle des fils de self
45 # il faut pour les FORMULE decortiquer l'expression ...
46 self.type_retourne,self.arguments,self.corps = self.analyse_formule()
49 def analyse_formule(self):
51 Cette methode decortique l'expression de la FORMULE.
52 Elle retourne 3 valeurs:
53 - le type retourne par la FORMULE
54 - les arguments de la FORMULE
55 - le corps de la FORMULE, cad son expression
57 if len(self.mc_liste) == 0:
58 # pas de fils pour self --> la FORMULE est incomplete
61 if len(self.mc_liste) > 0:
62 child = self.mc_liste[0] # child est un MCSIMP
63 corps = child.getval()
66 if len(self.mc_liste) > 1:
67 child = self.mc_liste[1]
68 l_args= child.getval()
71 return type_retourne,l_args,corps
75 Retourne le nom de la FORMULE, cad le nom de la SD si elle existe,
79 return self.sd.get_name()
83 def get_formule(self):
85 Retourne un tuple decrivant la formule :
86 (nom,type_retourne,arguments,corps)
88 t,a,c = self.analyse_formule()
92 def verif_arguments(self,arguments = None):
94 Verifie si les arguments passes en argument (si aucun prend les arguments courants)
95 sont des arguments valide pour une FORMULE.
97 - un booleen, qui vaut 1 si arguments licites, 0 sinon
98 - un message d'erreurs ('' si illicites)
101 arguments = self.arguments
103 return 0,"Une formule doit avoir au minimum un argument"
104 # il faut au prealable enlever les parentheses ouvrantes et fermantes
105 # encadrant les arguments
106 arguments = string.strip(arguments)
107 if arguments[0] != '(':
108 return 0,tr("La liste des arguments d'une formule doit etre entre parentheses : parenthese ouvrante manquante")
109 if arguments[-1] != ')':
110 return 0,tr("La liste des arguments d'une formule doit etre entre parentheses : parenthese fermante manquante")
111 # on peut tester la syntaxe de chaque argument maintenant
114 arguments = arguments[1:-1] # on enleve les parentheses ouvrante et fermante
115 l_arguments = string.split(arguments,',')
116 for a in l_arguments :
117 if not re.match(identifier,str(a)) : return 0, str(a)+" n est pas un identifiant"
120 def verif_corps(self,corps=None,arguments=None):
122 Cette methode a pour but de verifier si le corps de la FORMULE
123 est syntaxiquement correct.
125 - un booleen, qui vaut 1 si corps de FORMULE licite, 0 sinon
126 - un message d'erreurs ('' si illicite)
131 arguments = self.arguments
132 formule=(self.get_nom(),self.type_retourne,arguments,corps)
133 # on recupere la liste des constantes et des autres fonctions predefinies
134 # et qui peuvent etre utilisees dans le corps de la formule courante
135 l_ctes,l_form = self.jdc.get_parametres_fonctions_avant_etape(self)
136 # on cree un objet verificateur
138 verificateur = self.interpreteur(formule=formule,
142 traceback.print_exc()
143 return 0,tr("Impossible de realiser la verification de la formule")
144 return verificateur.isvalid(),verificateur.report()
146 def verif_nom(self,nom=None):
148 Verifie si le nom passe en argument (si aucun prend le nom courant)
149 est un nom valide pour une FORMULE.
151 - un booleen, qui vaut 1 si nom licite, 0 sinon
152 - un message d'erreurs ('' si illicite)
157 return 0,tr("Pas de nom donne a la FORMULE")
159 return 0,tr("Un nom de FORMULE ne peut depasser 8 caracteres")
160 if nom[0] > "0" and nom[0] < "9" :
161 return 0,tr("Un nom de FORMULE ne peut pas commencer par un chiffre")
162 sd = self.parent.get_sd_autour_etape(nom,self)
164 return 0,tr("Un concept de nom %s existe deja !" %nom)
167 def verif_type(self,type=None):
169 Verifie si le type passe en argument (si aucun prend le type courant)
170 est un type valide pour une FORMULE.
172 - un booleen, qui vaut 1 si type licite, 0 sinon
173 - un message d'erreurs ('' si illicite)
176 type = self.type_retourne
178 return 0,tr("Le type de la valeur retournee n'est pas specifie")
179 if type not in self.l_types_autorises:
180 return 0,tr("Une formule ne peut retourner une valeur de type : %s" %type)
183 def verif_formule(self,formule=None):
185 Verifie la validite de la formule passee en argument.
186 Cette nouvelle formule est passee sous la forme d'un tuple : (nom,type_retourne,arguments,corps)
187 Si aucune formule passee, prend les valeurs courantes de la formule
189 - un booleen, qui vaut 1 si formule licite, 0 sinon
190 - un message d'erreurs ('' si illicite)
193 formule = (None,None,None,None)
194 test_nom,erreur_nom = self.verif_nom(formule[0])
195 test_type,erreur_type = self.verif_type(formule[1])
197 args = '('+formule[2]+')'
200 test_arguments,erreur_arguments = self.verif_arguments(args)
201 test_corps,erreur_corps = self.verif_corps(corps = formule[3], arguments = args)
202 # test global = produit des tests partiels
203 test = test_nom*test_type*test_arguments*test_corps
204 # message d'erreurs global = concatenation des messages partiels
207 for mess in (erreur_nom,erreur_type,erreur_arguments,erreur_corps):
208 erreur = erreur+(len(mess) > 0)*'\n'+mess
211 def verif_formule_python(self,formule=None):
213 Pour l instant ne fait qu un compile python
214 il serait possible d ajouter des tests sur les arguments
215 ou le type retourne mais ...
218 formule = (None,None,None,None)
219 test_nom,erreur_nom = self.verif_nom(formule[0])
221 args = '('+formule[2]+')'
224 test_arguments,erreur_arguments = self.verif_arguments(args)
229 compile(corps,'<string>','eval')
231 erreur_formule= "le corps de la formule n'est pas une formule python valide"
234 test = test_nom*test_arguments*test_formule
236 for mess in (erreur_nom,erreur_arguments,erreur_formule):
237 erreur = erreur+(len(mess) > 0)*'\n'+mess
241 def update(self,formule):
244 Met a jour les champs nom, type_retourne,arguments et corps de la FORMULE
245 par les nouvelles valeurs passees dans le tuple formule.
246 On stocke les valeurs SANS verifications.
248 self.type_retourne = formule[1]
249 self.arguments = '('+formule[2]+')'
250 self.corps = formule[3]
251 # il faut ajouter le mot-cle simple correspondant dans mc_liste
252 # pour cela on utilise la methode generale build_mc
253 # du coup on est oblige de modifier le dictionnaire valeur de self ...
255 self.valeur[self.type_retourne] = self.arguments+' = ' + self.corps
257 sd = self.get_sd_prod()
262 # Il faut que formule soit constituee de
266 # corps de la fonction
267 # il faut aussi que les arguments soient sous forme de tuple
268 def update_formule_python(self,formule):
271 if len(formule) < 4 :
274 if arguments[0] == '(' :
275 arguments=arguments[1:]
276 if arguments[-1] == ')' :
277 arguments=arguments[:-1]
278 self.arguments=tuple(arguments.split(','))
280 mocles={"NOM_PARA":self.arguments}
281 if formule[1] == "REEL":
282 mocles["VALE"]=formule[2]
283 if formule[1] == "COMPLEXE":
284 mocles["VALE_C"]=formule[2]
286 for k,v in self.definition.entites.items():
287 if not k in mocles : continue
288 child=self.definition.entites[k](None,nom=k,parent=self)
289 child.valeur=mocles[k]
290 child.state = 'modified'
291 self.mc_liste.append(child)
293 self.corps = formule[2]
294 self.type_retourne = formule[1]
295 sd = self.get_sd_prod()
303 Rend l'etape courante active.
304 Il faut ajouter la formule au contexte global du JDC
309 if nom == '' : return
311 self.jdc.append_fonction(self.sd)
317 Rend l'etape courante inactive
318 Il faut supprimer la formule du contexte global du JDC
322 if not self.sd : return
323 self.jdc.del_fonction(self.sd)
325 def update_concept(self,sd):
328 def delete_concept(self,sd):
333 Mettre a jour les mots cles de l etape et eventuellement le concept produit si reuse
334 suite a la disparition du concept sd
335 Seuls les mots cles simples MCSIMP font un traitement autre que de transmettre aux fils,
336 sauf les objets FORM_ETAPE qui doivent verifier que le concept detruit n'est pas
337 utilise dans le corps de la fonction
341 def replace_concept(self,old_sd,sd):
344 - old_sd=concept remplace
345 - sd = nouveau concept
347 Les objets FORM_ETAPE devraient verifier que le concept remplace n'est pas
348 utilise dans le corps de la fonction