1 // Copyright (C) 2007-2012 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include "SPythonParser.hxx"
22 #include "InterpKernelException.hxx"
27 using namespace ParaMEDMEM;
29 const char SPythonPredParser::FIELD_TYPE_STR[]="MEDCalculatorDBField";
31 const char SPythonParser::NUMBERS[]="0123456789";
33 SPythonParser::SPythonParser():_type(EMPTY_TYPE)
38 * This method checks that the input 's' follows the following pattern :
39 * "{number || var[.attribute]?{@number@}? || @number@ }*{+ - * / }*"
40 * \b All of {var} should be of type int,float funct or MEDCalculatorDBField.
42 bool SPythonParser::parseWithoutEqual(const std::string& s, int parLev, PyObject *glob, PyObject *loc, std::vector<SPythonParser>& alreadyParsed)
44 keepSelectedLevOfPar(s,parLev,glob,loc);
45 TypeOfEntity ty=_pred.getType();
58 if(isParenthesisMatching(_content,tmp))
64 if(isAlreadyControledParenthesis(_content))
73 _type=analyzeType(glob,loc,alreadyParsed);
80 return _type==FIELDDB_TYPE || _type==INT_TYPE || _type==FLOAT_TYPE;
83 void SPythonParser::keepSelectedLevOfPar(const std::string& s, int parLev, PyObject *glob, PyObject *loc)
87 std::size_t len=s.length();
94 _pred.assign(pred,glob,loc);
110 std::size_t end=s.find_first_of(')',i);
111 end=end!=std::string::npos?end-i:std::string::npos;
112 _content=s.substr(i,end);
117 _content=_content.substr(1,_content.length()-1);
118 _content_py=_content;
122 _pred.assign(pred,glob,loc);
125 std::size_t begin=s.find_last_of("(+-*/^",i-1,6);
126 begin=begin!=std::string::npos?begin+1:0;
127 pred=s.substr(begin,i-begin);
128 _pred.assign(pred,glob,loc);
133 * Size of returned vector is depth of parenthesis.
134 * Foreach level number of parenthesis groups.
136 std::vector<int> SPythonParser::levOfParenthesis(const std::string& s)
138 std::vector<int> ret(1);
140 std::size_t curLev=0;
141 std::size_t len=s.length();
142 for(std::size_t i=0;i<len;i++)
147 if(ret.size()<=++curLev)
161 * Analyzes regarding _content attribute the type of value.
163 TypeOfEntity SPythonParser::analyzeType(PyObject *glob, PyObject *loc, const std::vector<SPythonParser>& alreadyParsed)
165 static const int OPS_SEP_LGTH=5;
166 static const char OPS_SEP[OPS_SEP_LGTH+1]="+-*/^";
169 std::string content=_content;//.substr(1,_content.length()-2);
172 while(p!=std::string::npos)
174 std::size_t p2=content.find_first_of(OPS_SEP,p,OPS_SEP_LGTH);
175 std::size_t p3=p2!=std::string::npos?p2-p:p2;
176 std::string elt=content.substr(p,p3);
177 type=getTypeOfElt(elt,glob,loc,alreadyParsed);
178 _type=combineType(_type,type);
179 p=p2!=std::string::npos?p2+1:p2;
185 TypeOfEntity SPythonParser::getTypeOfElt(const std::string& elt, PyObject *glob, PyObject *loc, const std::vector<SPythonParser>& alreadyParsed) const
187 std::size_t sz=elt.length();
190 if(elt[0]=='@' && elt[sz-1]=='@')
192 std::string tmp=elt.substr(1,sz-2);
194 std::istringstream iss(tmp); iss >> id;
195 return alreadyParsed[id].getType();
198 return SPythonPredParser::getTypeOfVar(elt,glob,loc);
201 TypeOfEntity SPythonParser::combineType(TypeOfEntity t1, TypeOfEntity t2) const
207 if(t1==UNKNOWN_TYPE || t2==UNKNOWN_TYPE)
209 if((t1==INT_TYPE && t2==FLOAT_TYPE) || (t2==INT_TYPE && t1==FLOAT_TYPE))
211 if((t1==INT_TYPE && t2==FIELDDB_TYPE) || (t2==INT_TYPE && t1==FIELDDB_TYPE))
213 if((t1==FLOAT_TYPE && t2==FIELDDB_TYPE) || (t2==FLOAT_TYPE && t1==FIELDDB_TYPE))
219 * This method makes the assumption that s as a minimum length of size 2 with first char == '(' and the last ')'.
221 bool SPythonParser::isParenthesisMatching(const std::string& w, std::string& res)
223 std::ostringstream result;
225 std::size_t sLgth=w.length();
226 //std::string w(s,1,sLgth-2);
227 int nbOfParams=std::count(w.c_str(),w.c_str()+sLgth,',')+1;
229 for(int i=0;i<nbOfParams;i++)
231 std::size_t pos2=w.find(',',pos);
232 std::size_t pos3=pos2!=std::string::npos?pos2-pos:std::string::npos;
233 std::string w1=w.substr(pos,pos3);
236 if(!isElementInParenthesisMatching(w1,w1out,isNum))
245 pos=pos2!=std::string::npos?pos2+1:std::string::npos;
253 * This method checks that s match the following regexp : "@[0123456789]?@"
255 bool SPythonParser::isAlreadyControledParenthesis(const std::string& s)
257 std::size_t len=s.length();
260 if(s[0]!='@' || s[len-1]!='@')
262 std::string tmp=s.substr(1,len-2);
263 return tmp.find_first_not_of(NUMBERS,0,10)==std::string::npos;
267 * No assumption here check that the following regexp is followed [' ']*[0:9]*[' ']*:?[' ']*[0:9]*[' ']*
269 bool SPythonParser::isElementInParenthesisMatching(const std::string& s, std::string& result, bool& isNumber)
272 std::ostringstream ret;
273 std::size_t pos1=s.find_first_not_of(' ');
274 if(pos1==std::string::npos)
276 std::size_t pos2=s.find_first_not_of(NUMBERS,pos1,10);
277 std::string elt1=s.substr(pos1,pos2-pos1);
279 std::size_t pos3=s.find_first_not_of(' ',pos2);
280 if(pos3==std::string::npos)
290 std::size_t pos4=s.find_first_not_of(' ',pos3);
291 if(pos4==std::string::npos)
296 std::size_t pos5=s.find_first_not_of(NUMBERS,pos4,10);
297 if(pos5==pos4)//an another caracter found after : !
300 if(pos5==std::string::npos)
302 elt2=s.substr(pos4,std::string::npos);
307 elt2=s.substr(pos4,pos5-pos4);
310 std::size_t pos6=s.find_first_not_of(' ',pos5);
311 if(pos6==pos5)//an another caracter found after 2nd elt !
313 return pos6==std::string::npos;
316 std::string SPythonParser::substitute(const std::vector<SPythonParser>& v) const
318 std::string ret=_content_py;
319 replaceFromCompacted(ret,v);
323 std::string SPythonParser::replaceByCompacted(const std::string& s, int parLev, int id) const
328 std::size_t len=s.length();
329 std::size_t begin=0,end=0;
345 begin=s.find_last_of("(+-*/^",i-1,6);
346 begin=begin!=std::string::npos?begin+1:0;
350 end=s.find_first_of(')',i+1);
351 end=end!=std::string::npos?end-begin+1:std::string::npos;
355 std::ostringstream oss,oss1;
356 oss << '@' << id << '@';
357 return scpy.replace(begin,end,oss.str());
360 std::string SPythonParser::getRepr(const std::vector<SPythonParser>& v) const
362 std::string ret(_pred.getRepr());
366 replaceFromCompacted(ret,v);
370 void SPythonParser::replaceFromCompacted(std::string& ret,const std::vector<SPythonParser>& v)
372 std::size_t pos=ret.find_first_of('@',0);
374 while(pos!=std::string::npos)
376 pos2=ret.find_first_of('@',pos+1);
377 if(pos2==std::string::npos)
378 throw INTERP_KERNEL::Exception("Internal Error occurs !");
379 std::string tmp=ret.substr(pos+1,pos2-pos-1);
380 std::istringstream iss(tmp);
383 std::string tmp2=v[id].getRepr(v);
384 ret.replace(pos,pos2-pos+1,tmp2);
385 pos=ret.find_first_of('@',pos2+1+tmp2.size()-tmp.size()-2);
390 SPythonPredParser::SPythonPredParser():_type(EMPTY_TYPE)
395 * This method analyses _pred attribute to deduce type of returned param.
397 void SPythonPredParser::assign(const std::string& s, PyObject *glob, PyObject *loc)
401 if(s.empty()) { _type=IDENTITY_TYPE; return ; }
402 std::size_t p=s.find_last_of('.');
403 if(p==std::string::npos)
408 _method=s.substr(p+1);
412 int type=getTypeOfVar(_var,glob,loc);
415 if(type==FIELDDB_TYPE)
425 int type=getTypeOfVar(_var,glob,loc);
426 if(type==FIELDDB_TYPE)
427 {//To improve in case that some FieldDB swigged method return a different type than FieldDB
435 bool SPythonPredParser::empty() const
437 return _var.empty() && _method.empty();
440 TypeOfEntity SPythonPredParser::getTypeOfVar(const std::string& var, PyObject *glob, PyObject *loc)
442 static const char TMPVAR[]="tmpvvr37911022";
443 std::ostringstream oss; oss << TMPVAR << "=isinstance(" << var << "," << FIELD_TYPE_STR << ")";
444 PyObject *res=PyRun_String(oss.str().c_str(),Py_single_input,glob,loc);
447 if(PyDict_GetItemString(glob,TMPVAR)==Py_True)
449 oss.str(std::string(TMPVAR));
450 oss << TMPVAR << "=type(" << var << ").__name__";
451 PyRun_String(oss.str().c_str(),Py_single_input,glob,loc);
452 PyObject *p=PyDict_GetItemString(glob,TMPVAR);
453 const char *type=PyString_AS_STRING(p);
454 std::string typecpp=std::string(type);
455 if(typecpp=="function")
464 std::string SPythonPredParser::getRepr() const
470 std::string tmp(_var);
476 SPythonParserHL::SPythonParserHL(PyObject *glob, PyObject *loc):_glob(glob),_loc(loc)
480 bool SPythonParserHL::parse(const std::string& s, std::string& result)
482 std::vector<std::string> ps=splitBetweenEqualChar(s);
487 return parseWithoutEqual(ps[0],type,result);
489 if(!parseWithoutEqual(ps.back(),type,result))
491 for(int n=ps.size()-1;n!=0;n--)
494 TypeOfEntity typeLeft;
495 if(parseWithoutEqual(ps[n-1],typeLeft,leftRes))
497 if(typeLeft==FIELDDB_TYPE)
498 result=leftRes+".assign("+result+")";
500 result=leftRes+"="+result;
503 result=ps[n-1]+"="+result;
508 bool SPythonParserHL::parseWithoutEqual(const std::string& s, TypeOfEntity& type, std::string& result)
513 std::vector<int> v=SPythonParser::levOfParenthesis(sst);
514 std::size_t levOfPar=v.size();
515 std::vector<SPythonParser> allSubs;
517 for(std::size_t i=levOfPar;i!=0;i--)
518 for(int j=0;j<v[i-1];j++,k++)
521 if(!subs.parseWithoutEqual(sst,i-1,_glob,_loc,allSubs))
524 sst=subs.replaceByCompacted(sst,i-1,k);
525 allSubs.push_back(subs);
527 result=allSubs.back().substitute(allSubs);
528 type=allSubs.back().getType();
532 std::vector<std::string> SPythonParserHL::splitBetweenEqualChar(const std::string &s)
534 std::size_t p=0,p2,p3;
535 std::vector<std::string> ret;
536 while(p!=std::string::npos)
538 p2=s.find_first_of('=',p);
539 p3=p2!=std::string::npos?p2-p:p2;
540 std::string tmp=s.substr(p,p3);
542 p=p2!=std::string::npos?p2+1:p2;