KDevelop API Documentation

perlparser.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                           perlparser.cpp  -  description
00003                              -------------------
00004     begin                : Sun Nov 2 2003
00005     copyright            : (C) 2003 by luc
00006     email                : willems.luc(at)pandora.be
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 #include "perlparser.h"
00019 
00020 #include <kdebug.h>
00021 #include <qfile.h>
00022 #include <qregexp.h>
00023 #include <qfileinfo.h>
00024 
00025 perlparser::perlparser(KDevCore* core,CodeModel* model, QString interpreter) {
00026   m_core = core;
00027   m_model = model;
00028   m_interpreter=interpreter;
00029   //get INC paths for current installed perl
00030   getPerlINC();
00031 
00032 }
00033 
00034 perlparser::~perlparser(){
00035 }
00036 
00037 const QStringList perlparser::UseFiles()
00038 {
00039   return m_usefiles;
00040 }
00041 
00042 void perlparser::initialParse() {
00043   m_usefiles.clear();
00044 }
00045 
00046 void perlparser::parse(const QString &fileName){
00047   QFile f(fileName);
00048   if (!f.open(IO_ReadOnly))
00049       return;
00050   QTextStream stream(&f);
00051   QStringList list;
00052   QString rawline;
00053   while (!stream.eof()) {
00054    rawline = stream.readLine();
00055    list.append(rawline.stripWhiteSpace().local8Bit());
00056  }
00057  f.close();
00058  kdDebug(9016) << "parsing " << fileName << endl;
00059 
00060  m_file = m_model->create<FileModel>();
00061  m_file->setName(fileName );
00062  this->parseLines(&list,fileName);
00063  m_model->addFile( m_file );
00064 }
00065 
00066 void perlparser::parseLines(QStringList* lines,const QString &fileName)
00067 {
00068   QRegExp  packagere("^[ \t]*package[ \t]+([+A-Za-z0-9_:]*).*\\;");
00069   QRegExp     basere("^[ \t]*use[ \t]+base[ \t]*\\(\'*\"*([A-Za-z0-9_:]*)");
00070   QRegExp      libre("^[ \t]*use[ \t]+lib[ \t]*\\(\'*\"*([A-Za-z0-9_:]*)");
00071   QRegExp      usere("^[ \t]*use[ \t]+([+A-Za-z0-9_:]*).*\\;");
00072   QRegExp      isare("^[ \t]*@ISA[ \t=qw\\(\'\"]*([A-Za-z0-9_: ]*)");
00073   QRegExp   globalre("^[ \t]*our[ \t]+\\(*([ \t,$%@*+A-Za-z0-9_]*)\\)*.*");
00074   QRegExp   myre("^[ \t]*my[ \t]+\\(*([ \t,$%@*+A-Za-z0-9_]*)\\)*.*");
00075   QRegExp      subre("^[ \t]*sub[ \t]+([A-Za-z0-9_]+)([A-Za-z0-9_]|([ \t]*[{])?)$");
00076   QRegExp    blessre("bless[ \t]*[\\( ]*([,$%@*+A-Za-z0-9_]*).*;");
00077   QRegExp     namere("^[ \t]*([$%@*])([A-Za-z0-9_]*).*$");
00078   QRegExp  privatere("^_([A-Za-z0-9_]*)");
00079   QRegExp  startpod("^=[a-z0-9]+ [a-z0-9]*");
00080   QRegExp  cutpod("^=cut");
00081 
00082   QString line;
00083 
00084   //clear all "last" know things
00085   m_lastsub="";
00086   m_lastattr="";
00087   m_inpackage = false;
00088   m_inscript = false;
00089   m_inclass=false;
00090 
00091   m_lastscript=0;
00092   m_lastpackage=0;
00093   m_lastclass=0;
00094 
00095   int lineNo = -1;
00096   
00097   bool inpod = false;
00098   bool endpod = false;
00099 
00100   //check if we are parsing a script or module
00101   QFileInfo fi(fileName);
00102   bool inscript =(fi.extension() == "pl");
00103   kdDebug(9016) << "inscript : " << inscript << "," << fi.extension() << endl;
00104 
00105   if (inscript) {
00106     addScript(fileName,lineNo,fi.fileName());
00107   }
00108 
00109   for ( QStringList::Iterator it = lines->begin(); it != lines->end(); ++it ) {
00110     ++lineNo;
00111     line = (*it).local8Bit();
00112     //empty line ?
00113     if (line.isEmpty()) { continue;}
00114     //some POD checking , quick and dirty but it seams to work
00115     if(inpod && endpod) { inpod=false; endpod=false;}
00116     //are we in pod documentation ?
00117     if (startpod.search(line)>=0) {inpod=true; continue;}
00118     //are we in pod documentation ?
00119     if (inpod) { endpod=( cutpod.search(line)>=0 ); continue; }
00120 
00121 
00122     //sub matching
00123     if (subre.search(line)>=0){
00124           QString subname=subre.cap(1);
00125           kdDebug(9016) << "subre match [" << subname << "]" << endl;
00126           bool prive = privatere.search(subname) >= 0;
00127           kdDebug(9016) << "prive match [" << prive << "]" << endl;
00128           if (m_inscript)      { addScriptSub(fileName,lineNo,subname,prive);}
00129           else {
00130              if (m_inclass)    { addClassMethod(fileName,lineNo,subname,prive);}
00131              else              { addPackageSub(fileName,lineNo,subname,prive);}
00132           }
00133           continue;
00134     } //sub
00135 
00136     //our matching
00137     if (globalre.search(line)>=0) {
00138         //splitup multible ours
00139         QString varlist=globalre.cap(1);
00140         kdDebug(9016) << "globalre match [" << varlist <<"]" << endl;
00141         QStringList vars=QStringList::split(",",varlist);
00142         for ( QStringList::Iterator it = vars.begin(); it != vars.end(); ++it ) {
00143             if (namere.search(*it)>=0) {
00144               QString var = namere.cap(2);
00145               kdDebug(9016) << "namere match [" << var << "]" << endl;
00146               if (m_lastpackage)  { addAttributetoPackage(fileName,lineNo,var); }
00147               else                { addAttributetoScript(fileName,lineNo,var); }
00148             }
00149         }
00150         continue;
00151     } //globalre
00152 
00153         
00154     //bless matching
00155     if ((blessre.search(line)>=0) && (!m_inscript)) {
00156          kdDebug(9016) << "blessre match []" << endl;
00157          addClass(fileName,lineNo);
00158          addConstructor(fileName,lineNo,m_lastsub);
00159          continue;
00160     } //bless
00161 
00162     //base matching
00163     if ((basere.search(line)>=0) && (!m_inscript)) {
00164          QString parent = basere.cap(1);
00165          //create child & parent classes
00166          kdDebug(9016) << "basere match [" << parent << "]" << endl;
00167          addClass(fileName,lineNo);
00168          addParentClass(parent);
00169          continue;
00170     } else {
00171       if (libre.search(line)>=0) {
00172          QString path = libre.cap(1);
00173          //add lib to INC path list
00174          kdDebug(9016) << "libre match [" << path << "]" << endl;
00175          m_INClist.append(path);
00176          continue;
00177       } else {
00178          if (usere.search(line)>=0) {
00179            //add lib to use list for later parsing
00180            QString lib = usere.cap(1);
00181            kdDebug(9016) << "usere match [" << lib << "]" << endl;
00182            addUseLib(lib);
00183            continue;
00184          }                              \
00185      }
00186     } //base
00187 
00188     if ((isare.search(line)>=0) && (!m_inscript)) {
00189          QString parent = isare.cap(1);
00190          //create child & parent classes
00191          kdDebug(9016) << "isare match [" << parent << "]" << endl;
00192          addClass(fileName,lineNo);
00193          addParentClass(parent);
00194          continue;
00195     } //isa
00196 
00197     if ((packagere.search(line)>=0) && (!m_inscript)) {
00198          QString package=packagere.cap(1);
00199          kdDebug(9016) << "packagere match [" << package << "]" << endl;
00200          addPackage(fileName,lineNo,package);
00201          continue;
00202     }//package
00203 
00204   } // for lines loop
00205 }
00206 
00207 void perlparser::addPackage(const QString& fileName ,int lineNr , const QString& name)
00208 {
00209  kdDebug(9016) << "AddPackage [" << name << "]" << endl;
00210  NamespaceDom package = m_model->create<NamespaceModel>();
00211 
00212  package->setName(name);
00213  package->setFileName(fileName );
00214  package->setStartPosition(lineNr, 0 );
00215  package->setScope(name);
00216 
00217  if (!m_file->hasNamespace(name)) {
00218      m_file->addNamespace(package);
00219      m_lastpackage=package;
00220  } else {
00221    kdDebug(9016) << "addPackage [" << name << " exist]" << endl;
00222  }
00223 
00224  //clear all "last" know things
00225  m_lastpackagename=name;
00226  m_lastsub="";
00227  m_lastattr="";
00228  m_inpackage=true;
00229  m_inscript = false;
00230  m_inclass=false;
00231 
00232  m_lastclass=0;
00233  m_lastscript=0;
00234 
00235 }
00236 
00237 void perlparser::addScript(const QString& fileName ,int lineNr ,const QString& name)
00238 {
00239  kdDebug(9016) << "addScript [" << name << "]" << endl;
00240 
00241  //map name of script under /scripts
00242  //m_file->setName("/Scripts/"+name);
00243 
00244  kdDebug(9016) << "addScript [" << name << "]" << endl;
00245  NamespaceDom script = m_model->create<NamespaceModel>();
00246 
00247  script->setName(name);
00248  script->setFileName(fileName );
00249  script->setStartPosition(lineNr, 0 );
00250  script->setScope(name);
00251 
00252  if (!m_file->hasNamespace(name)) {
00253       m_file->addNamespace(script);
00254       m_lastscript=script;
00255  } else {
00256    kdDebug(9016) << "addScript [" << name << " exist]" << endl;
00257  }
00258  
00259  //clear all "last" know things
00260  m_lastsub="";
00261  m_lastattr="";
00262  m_inpackage = false;
00263  m_inscript = true;
00264  m_inclass=false;
00265 
00266  m_lastscriptname=name;
00267  m_lastpackage=0;
00268  m_lastclass=0;
00269 
00270 }
00271 
00272 void perlparser::addAttributetoPackage(const QString& fileName ,int lineNr ,const QString& name)
00273 {
00274  kdDebug(9016) << "addAttributetoPackage [" << name << "]" << endl;
00275  VariableDom var = m_model->create<VariableModel>();
00276  var->setName(name);
00277  var->setFileName( fileName );
00278  var->setStartPosition( lineNr, 0 );
00279  if (m_lastpackage) {
00280     if (!m_lastpackage->hasVariable(var->name()))
00281          m_lastpackage->addVariable(var);
00282  } else {
00283     kdDebug(9016) << "addAttributetoPackge[ no m_file]" << endl;
00284  }
00285 
00286  m_lastattr=name;
00287 }
00288 
00289 void perlparser::addAttributetoScript(const QString& fileName ,int lineNr ,const QString& name)
00290 {
00291   kdDebug(9016) << "addAttributetoScript [" << name << "]" << endl;
00292   VariableDom var = m_model->create<VariableModel>();
00293   var->setName(name);
00294   var->setFileName( fileName );
00295   var->setStartPosition( lineNr, 0 );
00296   if (m_lastscript) {
00297     if (!m_lastscript->hasVariable(var->name()))
00298        m_lastscript->addVariable(var);
00299   } else {
00300     kdDebug(9016) << "addAttributeScript[ no m_file]" << endl;
00301   }
00302 }
00303 
00304 void perlparser::addClass(const QString& fileName ,int lineNr)
00305 {
00306   kdDebug(9016) << "addClass [ " << m_lastpackagename << " ]" << endl;
00307   if (m_lastpackage->hasClass(m_lastpackagename)) {
00308     kdDebug(9016) << "Class already defined" << endl;
00309   } else {
00310     kdDebug(9016) << "new Class" << endl;
00311     ClassDom lastClass = m_model->create<ClassModel>();
00312     lastClass->setName(m_lastpackagename);
00313     lastClass->setFileName(fileName);
00314       lastClass->setStartPosition(lineNr, 0);
00315     m_lastpackage->addClass(lastClass);
00316     m_lastclass=lastClass;
00317     m_inclass=true;
00318   }
00319 }
00320 
00321 void perlparser::addConstructor(const QString& fileName ,int lineNr ,const QString& name)
00322 {
00323   kdDebug(9016) << "set Constructor["<< name << "]" << endl;
00324 
00325   FunctionDom method;
00326 
00327   if (m_lastpackage->hasFunction(name)) {
00328       //remove last sub frompackage scope
00329       method = m_lastpackage->functionByName(name)[0];
00330       method->getStartPosition(&lineNr,0);
00331       m_lastpackage->removeFunction(method);
00332   }
00333   method = m_lastclass->functionByName(name)[0];
00334   if (!method) { 
00335      kdDebug(9016) << "add new Constructor["<< name << ", " << lineNr << "]" << endl;
00336      method = m_model->create<FunctionModel>();
00337      method->setName(name);
00338      method->setFileName( fileName );
00339      method->setStartPosition( lineNr, 0 );
00340      m_lastclass->addFunction(method);
00341   }
00342   method->setStatic(true);
00343   //update class position
00344   m_lastclass->setStartPosition(lineNr,0);
00345 }
00346 
00347 void perlparser::addGlobalSub(const QString& fileName ,int lineNr ,const QString& name ,bool privatesub)
00348 {
00349   kdDebug(9016) << "addGlobalSub[ " << name << "]" << endl;
00350 
00351   FunctionDom method = m_model->create<FunctionModel>();
00352   method->setName(name);
00353   method->setFileName( fileName );
00354   method->setStartPosition( lineNr, 0 );
00355   method->setStatic(true);
00356   if (privatesub)
00357      method->setAccess(CodeModelItem::Private);
00358   if (m_lastpackage) {
00359     if (!m_lastpackage->hasFunction(method->name()))
00360          m_lastpackage->addFunction(method);
00361   } else {
00362     kdDebug(9016) << "addGlobalsub[ no m_lastpackage]" << endl;
00363   }
00364 
00365  //also add seperate to namespace
00366  addPackageSub(fileName,lineNr,name,privatesub);
00367  m_lastsub=name;
00368 }
00369 
00370 void perlparser::addScriptSub(const QString& fileName ,int lineNr ,const QString& name ,bool privatesub)
00371 
00372 {
00373   kdDebug(9016) << "addScriptSub[ " << name << "]" << endl;
00374   FunctionDom method = m_model->create<FunctionModel>();
00375   method->setName(name);
00376   method->setFileName( fileName );
00377   method->setStartPosition( lineNr, 0 );
00378   if (privatesub)
00379      method->setAccess(CodeModelItem::Private);
00380   if(m_lastscript) {
00381     m_lastscript->addFunction(method);
00382   } else {
00383   }
00384 
00385   m_lastsub=name;
00386 }
00387 
00388 void perlparser::addClassMethod(const QString& fileName ,int lineNr ,const QString& name ,bool privatesub)
00389 {
00390   kdDebug(9016) << "addClassMethod[ " << name << "]" << endl;
00391   FunctionDom method = m_model->create<FunctionModel>();
00392   method->setName(name);
00393   method->setFileName( fileName );
00394   method->setStartPosition( lineNr, 0 );
00395   method->setVirtual(true);
00396   if (privatesub)
00397      method->setAccess(CodeModelItem::Private);
00398   if (m_lastclass) {
00399     if (!m_lastclass->hasFunction(method->name()))
00400        m_lastclass->addFunction(method);
00401   } else {
00402     kdDebug(9016) << "addClassmethod[ no m_lastclass]" << endl;
00403   }
00404 
00405 // addPackageSub(fileName,lineNr,name,privatesub);
00406  m_lastsub=name;
00407 }
00408 
00409 void perlparser::addPackageSub(const QString& fileName ,int lineNr ,const QString& name ,bool privatesub)
00410 {
00411   kdDebug(9016) << "addPackageSub[ " << name << "]" << endl;
00412   FunctionDom method = m_model->create<FunctionModel>();
00413   method->setName(name);
00414   method->setFileName( fileName );
00415   method->setStartPosition( lineNr, 0 );
00416   if (privatesub)
00417      method->setAccess(CodeModelItem::Private);
00418   if (m_lastpackage) {
00419     if (!m_lastpackage->hasFunction(method->name()))
00420        m_lastpackage->addFunction(method);
00421  } else {
00422    kdDebug(9016) << "addPackageSub[ no m_file]" << endl;
00423  }
00424  m_lastsub=name;
00425 }
00426 
00427 void perlparser::addParentClass(const QString& parent)
00428 {
00429  kdDebug(9016) << "addParentClass[ " << parent << "]" << endl;
00430  if (m_lastclass) {
00431         m_lastclass->addBaseClass(parent);
00432  } else {
00433     kdDebug(9016) << "addParentClass[ no m_lastclass]" << endl;
00434  }
00435 }
00436 
00437 void perlparser::addUseLib(const QString& lib)
00438 {
00439  if (!m_model->hasFile(lib)) {
00440    if (m_usefiles.findIndex(lib) == -1) {
00441       //only add if not already parsed or in the list
00442       kdDebug(9016) << "add lib for later parsing [" << lib << "]" << endl;
00443       m_usefiles.append(lib);
00444    }
00445  }
00446 }
00447 
00448 void perlparser::getPerlINC() {
00449 
00450 
00451  m_INClist.clear();
00452 
00453  QString cmd = "/usr/bin/perl -e\" print join('|',@INC);\"";
00454  QString result;
00455 
00456  FILE *fd = popen(cmd.local8Bit().data(), "r");
00457  char buffer[4090];
00458  QByteArray array;
00459 
00460  while (!feof(fd)) {
00461         int n = fread(buffer, 1, 2048, fd);
00462         if (n == -1) {
00463             pclose(fd);
00464             return;
00465         }
00466         array.setRawData(buffer, n);
00467         result=QString::QString(array);
00468         array.resetRawData(buffer, n);
00469  }
00470  pclose(fd);
00471  //get INC list so we can use it to parse "use" modules
00472  m_INClist = QStringList::split(QString("|"),result);
00473  kdDebug(9016) << "INC " << m_INClist.size() << " "<< result << endl;
00474 }
00475 
00476 QString perlparser::findLib( const QString& lib)
00477 {
00478   QString result;
00479 
00480   QString file=lib;
00481   file.replace( QRegExp("::"), QString("/"));
00482 
00483   //find the correct path by using the INC list
00484   QStringList::Iterator inc = m_INClist.begin();
00485   while((inc != m_INClist.end()) && (result.isEmpty()) ) {
00486      QFileInfo fi((*inc) + "/" + file + ".pm");
00487      if ( fi.exists() ) {
00488         result = (*inc) + "/" + file + ".pm";
00489      }
00490      ++inc;
00491   }
00492   return result;
00493 }
00494 
KDE Logo
This file is part of the documentation for KDevelop Version 3.1.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Mar 23 00:03:50 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003