00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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
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
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
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
00113 if (line.isEmpty()) { continue;}
00114
00115 if(inpod && endpod) { inpod=false; endpod=false;}
00116
00117 if (startpod.search(line)>=0) {inpod=true; continue;}
00118
00119 if (inpod) { endpod=( cutpod.search(line)>=0 ); continue; }
00120
00121
00122
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 }
00135
00136
00137 if (globalre.search(line)>=0) {
00138
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 }
00152
00153
00154
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 }
00161
00162
00163 if ((basere.search(line)>=0) && (!m_inscript)) {
00164 QString parent = basere.cap(1);
00165
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
00174 kdDebug(9016) << "libre match [" << path << "]" << endl;
00175 m_INClist.append(path);
00176 continue;
00177 } else {
00178 if (usere.search(line)>=0) {
00179
00180 QString lib = usere.cap(1);
00181 kdDebug(9016) << "usere match [" << lib << "]" << endl;
00182 addUseLib(lib);
00183 continue;
00184 } \
00185 }
00186 }
00187
00188 if ((isare.search(line)>=0) && (!m_inscript)) {
00189 QString parent = isare.cap(1);
00190
00191 kdDebug(9016) << "isare match [" << parent << "]" << endl;
00192 addClass(fileName,lineNo);
00193 addParentClass(parent);
00194 continue;
00195 }
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 }
00203
00204 }
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
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
00242
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
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
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
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
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
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
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
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
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