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