Salome HOME
gestion des listes et label sur 2
[tools/eficas.git] / Noyau / nommage.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 """
22    Ce module sert à nommer les concepts produits par les commandes.
23    Le nom du concept est obtenu en appelant la fonction GetNomConceptResultat
24    du module avec le nom de la commande en argument.
25
26    Cette fonction parcourt le source dans lequel la commande se trouve, parse le
27    fichier et retrouve le nom du concept qui se trouve à gauche du signe = précédant
28    le nom de la commande.
29
30    Cette fonction utilise la fonction cur_frame du module N_utils qui retourne la frame
31    d'exécution Python située 2 niveaux au-dessus. C'est à partir de cette frame que
32    l'on retrouve le fichier source et le numéro de ligne où se trouve l'appel à la commande.
33
34 """
35
36 # Modules Python
37 import re
38 import string
39 import linecache
40 from functools import partial
41
42 # Modules EFICAS
43 import N_utils
44 from strfunc import get_encoding
45
46 regex1 = '=?\s*%s\s*\('
47 # commentaire standard precede d'un nombre quelconque de blancs (pas
48 # multiligne)
49 pattern_comment = re.compile(r"^\s*#.*")
50
51
52 def _GetNomConceptResultat(ope, level=2):
53     """
54        Cette fonction recherche dans la pile des appels, l'appel à la commande
55        qui doit etre situé à 2 niveaux au-dessus (cur_frame(2)).
56        On retrouve d'abord la frame d'exécution f. Puis le numéro de la ligne
57        dans le source f.f_lineno et le nom du fichier source (f.f_code.co_filename).
58        A partir de là, on récupère la ligne de source avec linecache.getline
59        et on vérifie que cette ligne correspond véritablement à l'appel.
60
61        En effet, lorsque les commandes tiennent sur plusieurs lignes, on retrouve
62        la dernière ligne. Il faut donc remonter dans le source jusqu'à la première
63        ligne.
64
65        Enfin la fonction evalnom forme un nom acceptable lorsque le concept est un
66        élément d'une liste, par exemple.
67
68     """
69     f = N_utils.cur_frame(level)
70     lineno = f.f_lineno     # XXX Too bad if -O is used
71     # lineno = f_lineno(f)  # Ne marche pas toujours
72     co = f.f_code
73     filename = unicode(co.co_filename, get_encoding())
74     name = co.co_name
75     # pattern pour identifier le debut de la commande
76     pattern_oper = re.compile(regex1 % ope)
77
78     list = []
79     while lineno > 0:
80         line = linecache.getline(filename, lineno)
81         lineno = lineno - 1
82         if pattern_comment.match(line):
83             continue
84         list.append(line)
85         if pattern_oper.search(line):
86             l = pattern_oper.split(line)
87             list.reverse()
88             # On suppose que le concept resultat a bien ete
89             # isole en tete de la ligne de source
90             m = evalnom(string.strip(l[0]), f.f_locals)
91             # print "NOMS ",m
92             if m != []:
93                 return m[-1]
94             else:
95                 return ''
96     # print "appel inconnu"
97     return ""
98
99
100 def evalnom(text, d):
101     """
102      Retourne un nom pour le concept resultat identifie par text
103      Pour obtenir ce nom il y a plusieurs possibilites :
104       1. text est un identificateur python c'est le nom du concept
105       2. text est un element d'une liste on construit le nom en
106         evaluant la partie indice dans le contexte de l'appelant d
107     """
108     l = re.split('([\[\]]+)', text)
109     if l[-1] == '':
110         l = l[:-1]
111     lll = []
112     i = 0
113     while i < len(l):
114         s = l[i]
115         ll = re.split('[ ,]+', s)
116         if ll[0] == '':
117             ll = ll[1:]
118         if len(ll) == 1:
119             id0 = ll[0]
120         else:
121             lll = lll + ll[0:-1]
122             id0 = ll[-1]
123         if i + 1 < len(l) and l[i + 1] == '[':  # le nom est suivi d un subscript
124             sub = l[i + 2]
125             nom = id0 + '_' + str(eval(sub, d))
126             i = i + 4
127         else:
128             nom = id0
129             i = i + 1
130         lll.append(nom)
131     return lll
132
133
134 def f_lineno(f):
135     """
136        Calcule le numero de ligne courant
137        Devrait marcher meme avec -O
138        Semble ne pas marcher en présence de tuples longs
139     """
140     c = f.f_code
141     if not hasattr(c, 'co_lnotab'):
142         return f.f_lineno
143     tab = c.co_lnotab
144     line = c.co_firstlineno
145     stopat = f.f_lasti
146     addr = 0
147     for i in range(0, len(tab), 2):
148         addr = addr + ord(tab[i])
149         if addr > stopat:
150             break
151         line = line + ord(tab[i + 1])
152     return line
153
154
155 class NamingSystem(N_utils.Singleton):
156
157     """Cette classe définit un système de nommage dynamique des concepts."""
158     _singleton_id = 'nommage.NamingSystem'
159
160     def __init__(self):
161         """Initialisation"""
162         self.native = _GetNomConceptResultat
163         self.use_global_naming()
164
165     def use_naming_function(self, function):
166         """Utilise une fonction particulière de nommage."""
167         self.naming_func = function
168
169     def use_global_naming(self):
170         """Utilise la fonction native de nommage."""
171         self.naming_func = partial(self.native, level=3)
172
173     def __call__(self, *args):
174         """Appel à la fonction de nommage."""
175         return self.naming_func(*args)
176
177 GetNomConceptResultat = NamingSystem()