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