Back to index

salome-med  6.5.0
SPythonParser.cxx
Go to the documentation of this file.
00001 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D
00002 //
00003 // This library is free software; you can redistribute it and/or
00004 // modify it under the terms of the GNU Lesser General Public
00005 // License as published by the Free Software Foundation; either
00006 // version 2.1 of the License.
00007 //
00008 // This library is distributed in the hope that it will be useful,
00009 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011 // Lesser General Public License for more details.
00012 //
00013 // You should have received a copy of the GNU Lesser General Public
00014 // License along with this library; if not, write to the Free Software
00015 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00016 //
00017 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
00018 //
00019 
00020 #include "SPythonParser.hxx"
00021 
00022 #include "InterpKernelException.hxx"
00023 
00024 #include <algorithm>
00025 #include <sstream>
00026 
00027 using namespace ParaMEDMEM;
00028 
00029 const char SPythonPredParser::FIELD_TYPE_STR[]="MEDCalculatorDBField";
00030 
00031 const char SPythonParser::NUMBERS[]="0123456789";
00032 
00033 SPythonParser::SPythonParser():_type(EMPTY_TYPE)
00034 {
00035 }
00036 
00042 bool SPythonParser::parseWithoutEqual(const std::string& s, int parLev, PyObject *glob, PyObject *loc, std::vector<SPythonParser>& alreadyParsed)
00043 {
00044   keepSelectedLevOfPar(s,parLev,glob,loc);
00045   TypeOfEntity ty=_pred.getType();
00046   switch(ty)
00047     {
00048     case FLOAT_TYPE:
00049     case INT_TYPE:
00050     case UNKNOWN_TYPE:
00051       {
00052         _type=ty;
00053         return false;
00054       }
00055     case FIELDDB_TYPE:
00056       {
00057         std::string tmp;
00058         if(isParenthesisMatching(_content,tmp))
00059           {
00060             _type=FIELDDB_TYPE;
00061             _content_py=tmp;
00062             return true;
00063           }
00064         if(isAlreadyControledParenthesis(_content))
00065           {
00066             _type=FIELDDB_TYPE;
00067             return true;
00068           }
00069         return false;
00070       }
00071     case IDENTITY_TYPE:
00072       {
00073         _type=analyzeType(glob,loc,alreadyParsed);
00074         break;
00075       }
00076     case FUNC_TYPE:
00077     case EMPTY_TYPE:
00078       return false;
00079     }
00080   return _type==FIELDDB_TYPE || _type==INT_TYPE || _type==FLOAT_TYPE;
00081 }
00082 
00083 void SPythonParser::keepSelectedLevOfPar(const std::string& s, int parLev, PyObject *glob, PyObject *loc)
00084 {
00085   int curLev=0;
00086   std::size_t i=0;
00087   std::size_t len=s.length();
00088   bool found=false;
00089   if(parLev==0)
00090     {
00091       _content=s;
00092       _content_py=s;
00093       std::string pred;
00094       _pred.assign(pred,glob,loc);
00095       return ;
00096     }
00097   for(i=0;i<len;i++)
00098     {
00099       switch(s[i])
00100         {
00101         case '(':
00102           ++curLev;
00103           break;
00104         case ')':
00105           curLev--;
00106           break;
00107         }
00108       if(curLev==parLev)
00109         {
00110           std::size_t end=s.find_first_of(')',i);
00111           end=end!=std::string::npos?end-i:std::string::npos;
00112           _content=s.substr(i,end);
00113           found=true;
00114           break;
00115         }
00116     }
00117   _content=_content.substr(1,_content.length()-1);
00118   _content_py=_content;
00119   std::string pred;
00120   if(i==0)
00121     {
00122       _pred.assign(pred,glob,loc);
00123       return ;
00124     }
00125   std::size_t begin=s.find_last_of("(+-*/^",i-1,6);
00126   begin=begin!=std::string::npos?begin+1:0;
00127   pred=s.substr(begin,i-begin);
00128   _pred.assign(pred,glob,loc);
00129 }
00130 
00131 
00136 std::vector<int> SPythonParser::levOfParenthesis(const std::string& s)
00137 {
00138   std::vector<int> ret(1);
00139   ret[0]=1;
00140   std::size_t curLev=0;
00141   std::size_t len=s.length();
00142   for(std::size_t i=0;i<len;i++)
00143     {
00144       switch(s[i])
00145         {
00146         case '(':
00147           if(ret.size()<=++curLev)
00148             ret.push_back(1);
00149           else
00150             ret[curLev]++;
00151           break;
00152         case ')':
00153           curLev--;
00154           break;
00155         }
00156     }
00157   return ret;
00158 }
00159 
00163 TypeOfEntity SPythonParser::analyzeType(PyObject *glob, PyObject *loc, const std::vector<SPythonParser>& alreadyParsed)
00164 {
00165   static const int OPS_SEP_LGTH=5;
00166   static const char OPS_SEP[OPS_SEP_LGTH+1]="+-*/^";
00167   _type=EMPTY_TYPE;
00168   TypeOfEntity type;
00169   std::string content=_content;//.substr(1,_content.length()-2);
00170   std::size_t p=0;
00171   int parId=0;
00172   while(p!=std::string::npos)
00173     {
00174       std::size_t p2=content.find_first_of(OPS_SEP,p,OPS_SEP_LGTH);
00175       std::size_t p3=p2!=std::string::npos?p2-p:p2;
00176       std::string elt=content.substr(p,p3);
00177       type=getTypeOfElt(elt,glob,loc,alreadyParsed);
00178       _type=combineType(_type,type);
00179       p=p2!=std::string::npos?p2+1:p2;
00180       parId++;
00181     }
00182   return _type;
00183 }
00184 
00185 TypeOfEntity SPythonParser::getTypeOfElt(const std::string& elt, PyObject *glob, PyObject *loc, const std::vector<SPythonParser>& alreadyParsed) const
00186 {
00187   std::size_t sz=elt.length();
00188   if(sz>=3)
00189     {
00190       if(elt[0]=='@' && elt[sz-1]=='@')
00191         {
00192           std::string tmp=elt.substr(1,sz-2);
00193           int id;
00194           std::istringstream iss(tmp); iss >> id;
00195           return alreadyParsed[id].getType();
00196         }
00197     }
00198   return SPythonPredParser::getTypeOfVar(elt,glob,loc);
00199 }
00200 
00201 TypeOfEntity SPythonParser::combineType(TypeOfEntity t1, TypeOfEntity t2) const
00202 {
00203   if(t1==EMPTY_TYPE)
00204     return t2;
00205   if(t1==t2)
00206     return t1;
00207   if(t1==UNKNOWN_TYPE || t2==UNKNOWN_TYPE)
00208     return UNKNOWN_TYPE;
00209   if((t1==INT_TYPE && t2==FLOAT_TYPE) || (t2==INT_TYPE && t1==FLOAT_TYPE))
00210     return FLOAT_TYPE;
00211   if((t1==INT_TYPE && t2==FIELDDB_TYPE) || (t2==INT_TYPE && t1==FIELDDB_TYPE))
00212     return FIELDDB_TYPE;
00213   if((t1==FLOAT_TYPE && t2==FIELDDB_TYPE) || (t2==FLOAT_TYPE && t1==FIELDDB_TYPE))
00214     return FIELDDB_TYPE;
00215   return UNKNOWN_TYPE;
00216 }
00217 
00221 bool SPythonParser::isParenthesisMatching(const std::string& w, std::string& res)
00222 {
00223   std::ostringstream result;
00224   //result << '(';
00225   std::size_t sLgth=w.length();
00226   //std::string w(s,1,sLgth-2);
00227   int nbOfParams=std::count(w.c_str(),w.c_str()+sLgth,',')+1;
00228   std::size_t pos=0;
00229   for(int i=0;i<nbOfParams;i++)
00230     {
00231       std::size_t pos2=w.find(',',pos);
00232       std::size_t pos3=pos2!=std::string::npos?pos2-pos:std::string::npos;
00233       std::string w1=w.substr(pos,pos3);
00234       std::string w1out;
00235       bool isNum;
00236       if(!isElementInParenthesisMatching(w1,w1out,isNum))
00237         return false;
00238       if(!isNum)
00239         result << '\"';
00240       result << w1out;
00241       if(!isNum)
00242         result << '\"';
00243       if(i!=nbOfParams-1)
00244         result << ',';
00245       pos=pos2!=std::string::npos?pos2+1:std::string::npos;
00246     }
00247   //result << ')';
00248   res=result.str();
00249   return true;
00250 }
00251 
00255 bool SPythonParser::isAlreadyControledParenthesis(const std::string& s)
00256 {
00257   std::size_t len=s.length();
00258   if(len<3)
00259     return false;
00260   if(s[0]!='@' || s[len-1]!='@')
00261     return false;
00262   std::string tmp=s.substr(1,len-2);
00263   return tmp.find_first_not_of(NUMBERS,0,10)==std::string::npos;
00264 }
00265 
00269 bool SPythonParser::isElementInParenthesisMatching(const std::string& s, std::string& result, bool& isNumber)
00270 {
00271   isNumber=false;
00272   std::ostringstream ret;
00273   std::size_t pos1=s.find_first_not_of(' ');
00274   if(pos1==std::string::npos)
00275     return false;
00276   std::size_t pos2=s.find_first_not_of(NUMBERS,pos1,10);
00277   std::string elt1=s.substr(pos1,pos2-pos1);
00278   ret << elt1;
00279   std::size_t pos3=s.find_first_not_of(' ',pos2);
00280   if(pos3==std::string::npos)
00281     {//'56'
00282       isNumber=true;
00283       result=ret.str();
00284       return true;
00285     }
00286   if(s[pos3]!=':')
00287     return false;
00288   ret << ':';
00289   pos3++;
00290   std::size_t pos4=s.find_first_not_of(' ',pos3);
00291   if(pos4==std::string::npos)
00292     {// '56:'
00293       result=ret.str();
00294       return true;
00295     }
00296   std::size_t pos5=s.find_first_not_of(NUMBERS,pos4,10);
00297   if(pos5==pos4)//an another caracter found after : !
00298     return false;
00299   std::string elt2;
00300   if(pos5==std::string::npos)
00301     {
00302       elt2=s.substr(pos4,std::string::npos);
00303       ret << elt2;
00304       result=ret.str();
00305       return true;
00306     }
00307   elt2=s.substr(pos4,pos5-pos4);
00308   ret << elt2;
00309   result=ret.str();
00310   std::size_t pos6=s.find_first_not_of(' ',pos5);
00311   if(pos6==pos5)//an another caracter found after 2nd elt !
00312     return false;
00313   return pos6==std::string::npos;
00314 }
00315 
00316 std::string SPythonParser::substitute(const std::vector<SPythonParser>& v) const
00317 {
00318   std::string ret=_content_py;
00319   replaceFromCompacted(ret,v);
00320   return ret;
00321 }
00322 
00323 std::string SPythonParser::replaceByCompacted(const std::string& s, int parLev, int id) const
00324 {
00325   std::string scpy(s);
00326   int curLev=0;
00327   std::size_t i=0;
00328   std::size_t len=s.length();
00329   std::size_t begin=0,end=0;
00330   for(i=0;i<len;i++)
00331     {
00332       switch(s[i])
00333         {
00334         case '(':
00335           ++curLev;
00336           break;
00337         case ')':
00338           curLev--;
00339           break;
00340         }
00341       if(curLev==parLev)
00342         {
00343           if(i!=0)
00344             {
00345               begin=s.find_last_of("(+-*/^",i-1,6);
00346               begin=begin!=std::string::npos?begin+1:0;
00347             }
00348           else
00349             begin=0;
00350           end=s.find_first_of(')',i+1);
00351           end=end!=std::string::npos?end-begin+1:std::string::npos;
00352           break;
00353         }
00354     }
00355   std::ostringstream oss,oss1;
00356   oss << '@' << id << '@';
00357   return scpy.replace(begin,end,oss.str());
00358 }
00359 
00360 std::string SPythonParser::getRepr(const std::vector<SPythonParser>& v) const
00361 {
00362   std::string ret(_pred.getRepr());
00363   ret+='(';
00364   ret+=_content_py;
00365   ret+=')';
00366   replaceFromCompacted(ret,v);
00367   return ret;
00368 }
00369 
00370 void SPythonParser::replaceFromCompacted(std::string& ret,const std::vector<SPythonParser>& v)
00371 {
00372   std::size_t pos=ret.find_first_of('@',0);
00373   std::size_t pos2;
00374   while(pos!=std::string::npos)
00375     {
00376       pos2=ret.find_first_of('@',pos+1);
00377       if(pos2==std::string::npos)
00378         throw INTERP_KERNEL::Exception("Internal Error occurs !");
00379       std::string tmp=ret.substr(pos+1,pos2-pos-1);
00380       std::istringstream iss(tmp);
00381       int id;
00382       iss >> id;
00383       std::string tmp2=v[id].getRepr(v);
00384       ret.replace(pos,pos2-pos+1,tmp2);
00385       pos=ret.find_first_of('@',pos2+1+tmp2.size()-tmp.size()-2);
00386     }
00387 }
00388 
00389 
00390 SPythonPredParser::SPythonPredParser():_type(EMPTY_TYPE)
00391 {
00392 }
00393 
00397 void SPythonPredParser::assign(const std::string& s, PyObject *glob, PyObject *loc)
00398 {
00399   _var.clear();
00400   _method.clear();
00401   if(s.empty()) { _type=IDENTITY_TYPE; return ; }
00402   std::size_t p=s.find_last_of('.');
00403   if(p==std::string::npos)
00404     _var=s;
00405   else
00406     {
00407       _var=s.substr(0,p);
00408       _method=s.substr(p+1);
00409     }
00410   if(_method.empty())
00411     {
00412       int type=getTypeOfVar(_var,glob,loc);
00413       if(type!=FUNC_TYPE)
00414         {
00415           if(type==FIELDDB_TYPE)
00416             _type=FIELDDB_TYPE;
00417           else
00418             _type=UNKNOWN_TYPE;
00419         }
00420       else
00421         _type=IDENTITY_TYPE;
00422     }
00423   else
00424     {
00425       int type=getTypeOfVar(_var,glob,loc);
00426       if(type==FIELDDB_TYPE)
00427         {//To improve in case that some FieldDB swigged method return a different type than FieldDB
00428           _type=FIELDDB_TYPE;
00429         }
00430       else
00431         _type=UNKNOWN_TYPE;
00432     }
00433 }
00434 
00435 bool SPythonPredParser::empty() const
00436 {
00437   return _var.empty() && _method.empty();
00438 }
00439 
00440 TypeOfEntity SPythonPredParser::getTypeOfVar(const std::string& var, PyObject *glob, PyObject *loc)
00441 {
00442   static const char TMPVAR[]="tmpvvr37911022";
00443   std::ostringstream oss; oss << TMPVAR << "=isinstance(" << var << "," << FIELD_TYPE_STR << ")";
00444   PyObject *res=PyRun_String(oss.str().c_str(),Py_single_input,glob,loc);
00445   if(res==0)
00446     return UNKNOWN_TYPE;
00447   if(PyDict_GetItemString(glob,TMPVAR)==Py_True)
00448     return FIELDDB_TYPE;
00449   oss.str(std::string(TMPVAR));
00450   oss << TMPVAR << "=type(" << var << ").__name__";
00451   PyRun_String(oss.str().c_str(),Py_single_input,glob,loc);
00452   PyObject *p=PyDict_GetItemString(glob,TMPVAR);
00453   const char *type=PyString_AS_STRING(p);
00454   std::string typecpp=std::string(type);
00455   if(typecpp=="function")
00456     return FUNC_TYPE;
00457   if(typecpp=="int")
00458     return INT_TYPE;
00459   if(typecpp=="float")
00460     return FLOAT_TYPE;
00461   return UNKNOWN_TYPE;
00462 }
00463 
00464 std::string SPythonPredParser::getRepr() const
00465 {
00466   if(_method.empty())
00467       return _var;
00468   else
00469     {
00470       std::string tmp(_var);
00471       tmp+='.';
00472       return tmp+_method;
00473     }
00474 }
00475 
00476 SPythonParserHL::SPythonParserHL(PyObject *glob, PyObject *loc):_glob(glob),_loc(loc)
00477 {
00478 }
00479 
00480 bool SPythonParserHL::parse(const std::string& s, std::string& result)
00481 {
00482   std::vector<std::string> ps=splitBetweenEqualChar(s);
00483   TypeOfEntity type;
00484   if(ps.empty())
00485     return false;
00486   if(ps.size()==1)
00487     return parseWithoutEqual(ps[0],type,result);
00488   result.clear();
00489   if(!parseWithoutEqual(ps.back(),type,result))
00490     return false;
00491   for(int n=ps.size()-1;n!=0;n--)
00492     {
00493       std::string leftRes;
00494       TypeOfEntity typeLeft;
00495       if(parseWithoutEqual(ps[n-1],typeLeft,leftRes))
00496           {
00497             if(typeLeft==FIELDDB_TYPE)
00498               result=leftRes+".assign("+result+")";
00499             else
00500               result=leftRes+"="+result;
00501           }
00502       else
00503         result=ps[n-1]+"="+result;
00504     }
00505   return true;
00506 }
00507 
00508 bool SPythonParserHL::parseWithoutEqual(const std::string& s, TypeOfEntity& type, std::string& result)
00509 {
00510   if(s.empty())
00511     return false;
00512   std::string sst(s);
00513   std::vector<int> v=SPythonParser::levOfParenthesis(sst);
00514   std::size_t levOfPar=v.size();
00515   std::vector<SPythonParser> allSubs;
00516   int k=0;
00517   for(std::size_t i=levOfPar;i!=0;i--)
00518     for(int j=0;j<v[i-1];j++,k++)
00519       {
00520         SPythonParser subs;
00521         if(!subs.parseWithoutEqual(sst,i-1,_glob,_loc,allSubs))
00522           return false;
00523         if(i!=1)
00524           sst=subs.replaceByCompacted(sst,i-1,k);
00525         allSubs.push_back(subs);
00526       }
00527   result=allSubs.back().substitute(allSubs);
00528   type=allSubs.back().getType();
00529   return true;
00530 }
00531 
00532 std::vector<std::string> SPythonParserHL::splitBetweenEqualChar(const std::string &s)
00533 {
00534   std::size_t p=0,p2,p3;
00535   std::vector<std::string> ret;
00536   while(p!=std::string::npos)
00537     {
00538       p2=s.find_first_of('=',p);
00539       p3=p2!=std::string::npos?p2-p:p2;
00540       std::string tmp=s.substr(p,p3);
00541       ret.push_back(tmp);
00542       p=p2!=std::string::npos?p2+1:p2;
00543     }
00544   return ret;
00545 }