1 // Copyright (C) 2007-2014 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, or (at your option) any later version.
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
19 // Author : Anthony Geay (CEA/DEN)
21 #include "SPythonParser.hxx"
23 #include "InterpKernelException.hxx"
28 using namespace ParaMEDMEM;
30 const char SPythonPredParser::FIELD_TYPE_STR[]="MEDCalculatorDBField";
32 const char SPythonParser::NUMBERS[]="0123456789";
34 SPythonParser::SPythonParser():_type(EMPTY_TYPE)
39 * This method checks that the input 's' follows the following pattern :
40 * "{number || var[.attribute]?{@number@}? || @number@ }*{+ - * / }*"
41 * \b All of {var} should be of type int,float funct or MEDCalculatorDBField.
43 bool SPythonParser::parseWithoutEqual(const std::string& s, int parLev, PyObject *glob, PyObject *loc, std::vector<SPythonParser>& alreadyParsed)
45 keepSelectedLevOfPar(s,parLev,glob,loc);
46 TypeOfEntity ty=_pred.getType();
59 if(isParenthesisMatching(_content,tmp))
65 if(isAlreadyControledParenthesis(_content))
74 _type=analyzeType(glob,loc,alreadyParsed);
81 return _type==FIELDDB_TYPE || _type==INT_TYPE || _type==FLOAT_TYPE;
84 void SPythonParser::keepSelectedLevOfPar(const std::string& s, int parLev, PyObject *glob, PyObject *loc)
88 std::size_t len=s.length();
95 _pred.assign(pred,glob,loc);
111 std::size_t end=s.find_first_of(')',i);
112 end=end!=std::string::npos?end-i:std::string::npos;
113 _content=s.substr(i,end);
118 _content=_content.substr(1,_content.length()-1);
119 _content_py=_content;
123 _pred.assign(pred,glob,loc);
126 std::size_t begin=s.find_last_of("(+-*/^",i-1,6);
127 begin=begin!=std::string::npos?begin+1:0;
128 pred=s.substr(begin,i-begin);
129 _pred.assign(pred,glob,loc);
134 * Size of returned vector is depth of parenthesis.
135 * Foreach level number of parenthesis groups.
137 std::vector<int> SPythonParser::levOfParenthesis(const std::string& s)
139 std::vector<int> ret(1);
141 std::size_t curLev=0;
142 std::size_t len=s.length();
143 for(std::size_t i=0;i<len;i++)
148 if(ret.size()<=++curLev)
162 * Analyzes regarding _content attribute the type of value.
164 TypeOfEntity SPythonParser::analyzeType(PyObject *glob, PyObject *loc, const std::vector<SPythonParser>& alreadyParsed)
166 static const int OPS_SEP_LGTH=5;
167 static const char OPS_SEP[OPS_SEP_LGTH+1]="+-*/^";
170 std::string content=_content;//.substr(1,_content.length()-2);
173 while(p!=std::string::npos)
175 std::size_t p2=content.find_first_of(OPS_SEP,p,OPS_SEP_LGTH);
176 std::size_t p3=p2!=std::string::npos?p2-p:p2;
177 std::string elt=content.substr(p,p3);
178 type=getTypeOfElt(elt,glob,loc,alreadyParsed);
179 _type=combineType(_type,type);
180 p=p2!=std::string::npos?p2+1:p2;
186 TypeOfEntity SPythonParser::getTypeOfElt(const std::string& elt, PyObject *glob, PyObject *loc, const std::vector<SPythonParser>& alreadyParsed) const
188 std::size_t sz=elt.length();
191 if(elt[0]=='@' && elt[sz-1]=='@')
193 std::string tmp=elt.substr(1,sz-2);
195 std::istringstream iss(tmp); iss >> id;
196 return alreadyParsed[id].getType();
199 return SPythonPredParser::getTypeOfVar(elt,glob,loc);
202 TypeOfEntity SPythonParser::combineType(TypeOfEntity t1, TypeOfEntity t2) const
208 if(t1==UNKNOWN_TYPE || t2==UNKNOWN_TYPE)
210 if((t1==INT_TYPE && t2==FLOAT_TYPE) || (t2==INT_TYPE && t1==FLOAT_TYPE))
212 if((t1==INT_TYPE && t2==FIELDDB_TYPE) || (t2==INT_TYPE && t1==FIELDDB_TYPE))
214 if((t1==FLOAT_TYPE && t2==FIELDDB_TYPE) || (t2==FLOAT_TYPE && t1==FIELDDB_TYPE))
220 * This method makes the assumption that s as a minimum length of size 2 with first char == '(' and the last ')'.
222 bool SPythonParser::isParenthesisMatching(const std::string& w, std::string& res)
224 std::ostringstream result;
226 std::size_t sLgth=w.length();
227 //std::string w(s,1,sLgth-2);
228 int nbOfParams=std::count(w.c_str(),w.c_str()+sLgth,',')+1;
230 for(int i=0;i<nbOfParams;i++)
232 std::size_t pos2=w.find(',',pos);
233 std::size_t pos3=pos2!=std::string::npos?pos2-pos:std::string::npos;
234 std::string w1=w.substr(pos,pos3);
237 if(!isElementInParenthesisMatching(w1,w1out,isNum))
246 pos=pos2!=std::string::npos?pos2+1:std::string::npos;
254 * This method checks that s match the following regexp : "@[0123456789]?@"
256 bool SPythonParser::isAlreadyControledParenthesis(const std::string& s)
258 std::size_t len=s.length();
261 if(s[0]!='@' || s[len-1]!='@')
263 std::string tmp=s.substr(1,len-2);
264 return tmp.find_first_not_of(NUMBERS,0,10)==std::string::npos;
268 * No assumption here check that the following regexp is followed [' ']*[0:9]*[' ']*:?[' ']*[0:9]*[' ']*
270 bool SPythonParser::isElementInParenthesisMatching(const std::string& s, std::string& result, bool& isNumber)
273 std::ostringstream ret;
274 std::size_t pos1=s.find_first_not_of(' ');
275 if(pos1==std::string::npos)
277 std::size_t pos2=s.find_first_not_of(NUMBERS,pos1,10);
278 std::string elt1=s.substr(pos1,pos2-pos1);
280 std::size_t pos3=s.find_first_not_of(' ',pos2);
281 if(pos3==std::string::npos)
291 std::size_t pos4=s.find_first_not_of(' ',pos3);
292 if(pos4==std::string::npos)
297 std::size_t pos5=s.find_first_not_of(NUMBERS,pos4,10);
298 if(pos5==pos4)//an another caracter found after : !
301 if(pos5==std::string::npos)
303 elt2=s.substr(pos4,std::string::npos);
308 elt2=s.substr(pos4,pos5-pos4);
311 std::size_t pos6=s.find_first_not_of(' ',pos5);
312 if(pos6==pos5)//an another caracter found after 2nd elt !
314 return pos6==std::string::npos;
317 std::string SPythonParser::substitute(const std::vector<SPythonParser>& v) const
319 std::string ret=_content_py;
320 replaceFromCompacted(ret,v);
324 std::string SPythonParser::replaceByCompacted(const std::string& s, int parLev, int id) const
329 std::size_t len=s.length();
330 std::size_t begin=0,end=0;
346 begin=s.find_last_of("(+-*/^",i-1,6);
347 begin=begin!=std::string::npos?begin+1:0;
351 end=s.find_first_of(')',i+1);
352 end=end!=std::string::npos?end-begin+1:std::string::npos;
356 std::ostringstream oss,oss1;
357 oss << '@' << id << '@';
358 return scpy.replace(begin,end,oss.str());
361 std::string SPythonParser::getRepr(const std::vector<SPythonParser>& v) const
363 std::string ret(_pred.getRepr());
367 replaceFromCompacted(ret,v);
371 void SPythonParser::replaceFromCompacted(std::string& ret,const std::vector<SPythonParser>& v)
373 std::size_t pos=ret.find_first_of('@',0);
375 while(pos!=std::string::npos)
377 pos2=ret.find_first_of('@',pos+1);
378 if(pos2==std::string::npos)
379 throw INTERP_KERNEL::Exception("Internal Error occurs !");
380 std::string tmp=ret.substr(pos+1,pos2-pos-1);
381 std::istringstream iss(tmp);
384 std::string tmp2=v[id].getRepr(v);
385 ret.replace(pos,pos2-pos+1,tmp2);
386 pos=ret.find_first_of('@',pos2+1+tmp2.size()-tmp.size()-2);
391 SPythonPredParser::SPythonPredParser():_type(EMPTY_TYPE)
396 * This method analyses _pred attribute to deduce type of returned param.
398 void SPythonPredParser::assign(const std::string& s, PyObject *glob, PyObject *loc)
402 if(s.empty()) { _type=IDENTITY_TYPE; return ; }
403 std::size_t p=s.find_last_of('.');
404 if(p==std::string::npos)
409 _method=s.substr(p+1);
413 int type=getTypeOfVar(_var,glob,loc);
416 if(type==FIELDDB_TYPE)
426 int type=getTypeOfVar(_var,glob,loc);
427 if(type==FIELDDB_TYPE)
428 {//To improve in case that some FieldDB swigged method return a different type than FieldDB
436 bool SPythonPredParser::empty() const
438 return _var.empty() && _method.empty();
441 TypeOfEntity SPythonPredParser::getTypeOfVar(const std::string& var, PyObject *glob, PyObject *loc)
443 static const char TMPVAR[]="tmpvvr37911022";
444 std::ostringstream oss; oss << TMPVAR << "=isinstance(" << var << "," << FIELD_TYPE_STR << ")";
445 PyObject *res=PyRun_String(oss.str().c_str(),Py_single_input,glob,loc);
448 if(PyDict_GetItemString(glob,TMPVAR)==Py_True)
450 oss.str(std::string(TMPVAR));
451 oss << TMPVAR << "=type(" << var << ").__name__";
452 PyRun_String(oss.str().c_str(),Py_single_input,glob,loc);
453 PyObject *p=PyDict_GetItemString(glob,TMPVAR);
454 const char *type=PyString_AS_STRING(p);
455 std::string typecpp=std::string(type);
456 if(typecpp=="function")
465 std::string SPythonPredParser::getRepr() const
471 std::string tmp(_var);
477 SPythonParserHL::SPythonParserHL(PyObject *glob, PyObject *loc):_glob(glob),_loc(loc)
481 bool SPythonParserHL::parse(const std::string& s, std::string& result)
483 std::vector<std::string> ps=splitBetweenEqualChar(s);
488 return parseWithoutEqual(ps[0],type,result);
490 if(!parseWithoutEqual(ps.back(),type,result))
492 for(int n=ps.size()-1;n!=0;n--)
495 TypeOfEntity typeLeft;
496 if(parseWithoutEqual(ps[n-1],typeLeft,leftRes))
498 if(typeLeft==FIELDDB_TYPE)
499 result=leftRes+".assign("+result+")";
501 result=leftRes+"="+result;
504 result=ps[n-1]+"="+result;
509 bool SPythonParserHL::parseWithoutEqual(const std::string& s, TypeOfEntity& type, std::string& result)
514 std::vector<int> v=SPythonParser::levOfParenthesis(sst);
515 std::size_t levOfPar=v.size();
516 std::vector<SPythonParser> allSubs;
518 for(std::size_t i=levOfPar;i!=0;i--)
519 for(int j=0;j<v[i-1];j++,k++)
522 if(!subs.parseWithoutEqual(sst,i-1,_glob,_loc,allSubs))
525 sst=subs.replaceByCompacted(sst,i-1,k);
526 allSubs.push_back(subs);
528 result=allSubs.back().substitute(allSubs);
529 type=allSubs.back().getType();
533 std::vector<std::string> SPythonParserHL::splitBetweenEqualChar(const std::string &s)
535 std::size_t p=0,p2,p3;
536 std::vector<std::string> ret;
537 while(p!=std::string::npos)
539 p2=s.find_first_of('=',p);
540 p3=p2!=std::string::npos?p2-p:p2;
541 std::string tmp=s.substr(p,p3);
543 p=p2!=std::string::npos?p2+1:p2;