Salome HOME
travail sur monPlusieurs
[tools/eficas.git] / Noyau / nommage.py
1 # -*- coding: iso-8859-1 -*-
2
3 # Copyright (C) 2007-2013   EDF R&D
4 #
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2.1 of the License.
9 #
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 # Lesser General Public License for more details.
14 #
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18 #
19 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #
21
22
23 """
24    Ce module sert à nommer les concepts produits par les commandes.
25    Le nom du concept est obtenu en appelant la fonction GetNomConceptResultat
26    du module avec le nom de la commande en argument.
27
28    Cette fonction parcourt le source dans lequel la commande se trouve, parse le
29    fichier et retrouve le nom du concept qui se trouve à gauche du signe = précédant
30    le nom de la commande.
31
32    Cette fonction utilise la fonction cur_frame du module N_utils qui retourne la frame
33    d'exécution Python située 2 niveaux au-dessus. C'est à partir de cette frame que
34    l'on retrouve le fichier source et le numéro de ligne où se trouve l'appel à la commande.
35
36 """
37
38 # Modules Python
39 import re,string
40 import linecache
41 from functools import partial
42
43 # Modules EFICAS
44 import N_utils
45
46 regex1='=?\s*%s\s*\('
47 #commentaire standard precede d'un nombre quelconque de blancs (pas multiligne)
48 pattern_comment   = re.compile(r"^\s*#.*")
49
50 def _GetNomConceptResultat(ope, level=2):
51   """
52      Cette fonction recherche dans la pile des appels, l'appel à la commande
53      qui doit etre situé à 2 niveaux au-dessus (cur_frame(2)).
54      On retrouve d'abord la frame d'exécution f. Puis le numéro de la ligne
55      dans le source f.f_lineno et le nom du fichier source (f.f_code.co_filename).
56      A partir de là, on récupère la ligne de source avec linecache.getline
57      et on vérifie que cette ligne correspond véritablement à l'appel.
58
59      En effet, lorsque les commandes tiennent sur plusieurs lignes, on retrouve
60      la dernière ligne. Il faut donc remonter dans le source jusqu'à la première
61      ligne.
62
63      Enfin la fonction evalnom forme un nom acceptable lorsque le concept est un
64      élément d'une liste, par exemple.
65
66   """
67   f=N_utils.cur_frame(level)
68   lineno = f.f_lineno     # XXX Too bad if -O is used
69   #lineno = f_lineno(f)  # Ne marche pas toujours
70   co = f.f_code
71   filename = co.co_filename
72   name = co.co_name
73   #pattern pour identifier le debut de la commande
74   pattern_oper=re.compile(regex1 % ope)
75
76   list=[]
77   while lineno > 0:
78     line = linecache.getline(filename, lineno)
79     lineno=lineno-1
80     if pattern_comment.match(line):continue
81     list.append(line)
82     if pattern_oper.search(line):
83       l=pattern_oper.split(line)
84       list.reverse()
85       # On suppose que le concept resultat a bien ete
86       # isole en tete de la ligne de source
87       m=evalnom(string.strip(l[0]),f.f_locals)
88       #print "NOMS ",m
89       if m!=[] :  return m[-1]
90       else : return ''
91   #print "appel inconnu"
92   return ""
93
94 def evalnom(text,d):
95   """
96    Retourne un nom pour le concept resultat identifie par text
97    Pour obtenir ce nom il y a plusieurs possibilites :
98     1. text est un identificateur python c'est le nom du concept
99     2. text est un element d'une liste on construit le nom en
100       evaluant la partie indice dans le contexte de l'appelant d
101   """
102   l=re.split('([\[\]]+)',text)
103   if l[-1] == '' :l=l[:-1]
104   lll=[]
105   i=0
106   while i<len(l):
107     s=l[i]
108     ll=re.split('[ ,]+',s)
109     if ll[0] == '' :ll=ll[1:]
110     if len(ll) == 1:
111       id0=ll[0]
112     else:
113       lll=lll+ll[0:-1]
114       id0=ll[-1]
115     if i+1<len(l) and l[i+1] == '[': # le nom est suivi d un subscript
116       sub=l[i+2]
117       nom=id0+'_'+str(eval(sub,d))
118       i=i+4
119     else:
120       nom=id0
121       i=i+1
122     lll.append(nom)
123   return lll
124
125 def f_lineno(f):
126    """
127       Calcule le numero de ligne courant
128       Devrait marcher meme avec -O
129       Semble ne pas marcher en présence de tuples longs
130    """
131    c=f.f_code
132    if not hasattr(c, 'co_lnotab'):return f.f_lineno
133    tab=c.co_lnotab
134    line = c.co_firstlineno
135    stopat = f.f_lasti
136    addr = 0
137    for i in range(0, len(tab), 2):
138        addr = addr + ord(tab[i])
139        if addr > stopat:
140            break
141        line = line + ord(tab[i+1])
142    return line
143
144
145 class NamingSystem(N_utils.Singleton):
146     """Cette classe définit un système de nommage dynamique des concepts."""
147     _singleton_id = 'nommage.NamingSystem'
148     
149     def __init__(self):
150         """Initialisation"""
151         self.native = _GetNomConceptResultat
152         self.use_global_naming()
153
154     def use_naming_function(self, function):
155         """Utilise une fonction particulière de nommage."""
156         self.naming_func = function
157
158     def use_global_naming(self):
159         """Utilise la fonction native de nommage."""
160         self.naming_func = partial(self.native, level=3)
161
162     def __call__(self, *args):
163         """Appel à la fonction de nommage."""
164         return self.naming_func(*args)
165
166 GetNomConceptResultat = NamingSystem()