Salome HOME
Merge from V6_main_20120808 08Aug12
[modules/med.git] / src / MEDCalculator / Swig / SPythonInterpreter.cxx
1 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "SPythonInterpreter.hxx"
21 #include "SPythonParser.hxx"
22
23 #include <vector>
24 #include <sstream>
25 #include <algorithm>
26
27 using namespace ParaMEDMEM;
28
29 const char *SPythonInterpreter::INDENT_TOKEN[]={"def","class","for","if","while","try","except"};
30
31 const char SPythonInterpreter::NUMBERS[]="0123456789";
32
33 SPythonInterpreter::SPythonInterpreter(PyObject *globals, PyObject *locals):_indent_must_change(false),_glob(globals),_loc(locals)
34 {
35   _indent_pos.insert(0);
36 }
37
38 void SPythonInterpreter::initialize()
39 {
40   _indent_pos.clear();
41   _indent_pos.insert(0);
42   _indent_must_change=false;
43   _cmd.clear();
44 }
45
46 bool SPythonInterpreter::run(const char *str, bool& isSPython)
47 {
48   isSPython=false;
49   std::string s(str);
50   if(s.empty())
51     {
52       finishSession();
53       _indent_must_change=false;
54       return true;
55     }
56   std::size_t pos=s.find_first_not_of(' ');
57   if(pos==std::string::npos)
58     return false;
59   if(s[pos]=='#')
60     return false;
61   if(!checkIndentCoherency(s,pos))
62     return true;
63   if(!isIndenter(s,pos))
64     {
65       _indent_must_change=false;
66       if(pos==0)
67         {
68           if(isSPythonExpression(s))
69             {
70               isSPython=true;
71               return true;
72             }
73           else
74             {
75               _cmd+=s;
76               _cmd+="\n";
77               return finishSession();
78             }
79         }
80       _cmd+=s;
81       _cmd+="\n";
82       return false;
83     }
84   else
85     {
86       _indent_must_change=true;
87       _cmd+=s;
88       _cmd+="\n";
89       return false;
90     }
91 }
92
93 bool SPythonInterpreter::finishSession()
94 {
95   PyObject *res=0;
96   if(_cmd.empty())
97     return false;
98   res=PyRun_String(_cmd.c_str(),Py_file_input,_glob,_loc);
99   _cmd.clear();
100   checkPythonInterp(res);
101   //_indent_pos.clear();
102   //_indent_pos.insert(0);
103   return true;
104 }
105
106 void SPythonInterpreter::checkPythonInterp(PyObject *r)
107 {
108   if(!r)
109     PyErr_Print();
110 }
111
112 bool SPythonInterpreter::checkIndentCoherency(const std::string& s, std::size_t p)
113 {
114   if(!_indent_must_change)
115     {
116       if(_indent_pos.find(p)!=_indent_pos.end())
117         {
118           std::set<int>::iterator it=_indent_pos.begin();
119           bool found=false;
120           for(;it!=_indent_pos.end() && !found;it++)
121             if(*it==(int)p)
122               found=true;
123           if(found)
124             _indent_pos.erase(it,_indent_pos.end());
125           return true;
126         }
127       else
128         {//let python doing the job of error msg !
129           _cmd+=s;
130           finishSession();
131           _indent_pos.clear();
132           return true;
133         }
134     }
135   else
136     {
137       if((int)p>*_indent_pos.rbegin())
138         {
139           _indent_pos.insert(p);
140           return true;
141         }
142       else
143         {//let python doing the job of error msg !
144           _cmd+=s;
145           finishSession();
146           _indent_pos.clear();
147           return true;
148         }
149     }
150 }
151
152 /*!
153  * looks that s contains at the begin of non empty char a python keyword that forces indentation of next line.
154  */
155 bool SPythonInterpreter::isIndenter(const std::string& s, std::size_t p)
156 {
157   std::string s1=s.substr(p);
158   for(int i=0;i<NB_OF_INDENT;i++)
159     {
160       std::string elt(INDENT_TOKEN[i]);
161       std::size_t sz=elt.length();
162       if(s1.length()>=sz)
163         if(s1.substr(0,sz)==elt)
164           return true;
165     }
166   return false;
167 }
168
169 std::string SPythonInterpreter::strip(const std::string& s)
170 {
171   std::size_t sz=s.length();
172   std::size_t n1=std::count(s.c_str(),s.c_str()+sz,' ');
173   std::size_t n2=std::count(s.c_str(),s.c_str()+sz,'\n');
174   std::size_t n3=std::count(s.c_str(),s.c_str()+sz,'\t');
175   std::string ret(sz-n1-n2-n3,'$');
176   std::size_t i=0,j=0;
177   for(;i!=std::string::npos;)
178     {
179       i=s.find_first_not_of(" \n\t",i);
180       if(i!=std::string::npos)
181         ret[j++]=s[i++];
182     }
183   return ret;
184 }
185
186 bool SPythonInterpreter::isSPythonExpression(const std::string& s)
187 {
188   std::string w(s);
189   if(w.find("import ")!=std::string::npos)
190     return false;
191   if(w.find_first_of('@')!=std::string::npos)
192     return false;
193   if(w.find("del ")!=std::string::npos)
194     return false;
195   const char PRINT[]="print ";
196   bool isPrint=w.find(PRINT)!=std::string::npos;
197   if(isPrint)
198     {
199       std::size_t p=w.find(PRINT);
200       w=w.substr(p+sizeof(PRINT)-1);
201     }
202   std::string result;
203   if(!isSPythonExpressionLev1(w,result))
204     return false;
205   if(isPrint)
206     result=std::string(PRINT)+result;
207   _cmd+=result+"\n";
208   finishSession();
209   return true;
210 }
211
212 bool SPythonInterpreter::isSPythonExpressionLev1(const std::string& s, std::string& result)
213 {
214   std::string sst=strip(s);
215   SPythonParserHL p(_glob,_loc);
216   if(!p.parse(sst,result))
217     return false;
218   return true;
219 }
220
221 bool SPythonInterpreter::isCandidateParenthesis(const std::string& s, std::size_t p1, std::size_t& n)
222 {
223   std::size_t p2=s.find_first_of(')',p1);
224   std::size_t p3=s.find_first_of('(',p1+1);
225   if(p2!=std::string::npos && (p3==std::string::npos || (p3!=std::string::npos && p2<p3) ))
226     {
227       n=p2-p1;
228       return true;
229     }
230   return false;
231 }