umbrello API Documentation

pascalwriter.cpp

00001 /***************************************************************************
00002  *                                                                         *
00003  *   This program is free software; you can redistribute it and/or modify  *
00004  *   it under the terms of the GNU General Public License as published by  *
00005  *   the Free Software Foundation; either version 2 of the License, or     *
00006  *   (at your option) any later version.                                   *
00007  *                                                                         *
00008  *   copyright (C) 2006                                                    *
00009  *   Umbrello UML Modeller Authors <uml-devel@uml.sf.net>                  *
00010  ***************************************************************************/
00011 
00012 #include "pascalwriter.h"
00013 
00014 #include <kdebug.h>
00015 #include <klocale.h>
00016 #include <kmessagebox.h>
00017 #include <qfile.h>
00018 #include <qregexp.h>
00019 #include <qtextstream.h>
00020 
00021 #include "../umldoc.h"
00022 #include "../uml.h"
00023 #include "../classifier.h"
00024 #include "../enum.h"
00025 #include "../classifierlistitem.h"
00026 #include "../umlclassifierlistitemlist.h"
00027 #include "../umltemplatelist.h"
00028 #include "../folder.h"
00029 #include "../association.h"
00030 #include "../attribute.h"
00031 #include "../operation.h"
00032 #include "../template.h"
00033 #include "../umlnamespace.h"
00034 #include "classifierinfo.h"
00035 
00036 const QString PascalWriter::defaultPackageSuffix = "_Holder";
00037 
00038 PascalWriter::PascalWriter() {
00039 }
00040 
00041 PascalWriter::~PascalWriter() {}
00042 
00046 Uml::Programming_Language PascalWriter::getLanguage() {
00047     return Uml::pl_Pascal;
00048 }
00049 
00050 
00051 bool PascalWriter::isOOClass(UMLClassifier *c) {
00052     Uml::Object_Type ot = c->getBaseType();
00053     if (ot == Uml::ot_Interface)
00054         return true;
00055     if (ot == Uml::ot_Enum)
00056         return false;
00057     if (ot != Uml::ot_Class) {
00058         kDebug() << "PascalWriter::isOOClass: unknown object type " << ot << endl;
00059         return false;
00060     }
00061     QString stype = c->getStereotype();
00062     if (stype == "CORBAConstant" || stype == "CORBATypedef" ||
00063             stype == "CORBAStruct" || stype == "CORBAUnion")
00064         return false;
00065     // CORBAValue, CORBAInterface, and all empty/unknown stereotypes are
00066     // assumed to be OO classes.
00067     return true;
00068 }
00069 
00070 QString PascalWriter::qualifiedName(UMLPackage *p, bool withType, bool byValue) {
00071     UMLPackage *umlPkg = p->getUMLPackage();
00072     QString className = cleanName(p->getName());
00073     QString retval;
00074 
00075     if (umlPkg == UMLApp::app()->getDocument()->getRootFolder(Uml::mt_Logical))
00076         umlPkg = NULL;
00077 
00078     UMLClassifier *c = dynamic_cast<UMLClassifier*>(p);
00079     if (umlPkg == NULL) {
00080         retval = className;
00081         if (c == NULL || !isOOClass(c))
00082             retval.append(defaultPackageSuffix);
00083     } else {
00084         retval = umlPkg->getFullyQualifiedName(".");
00085         if (isOOClass(c)) {
00086             retval.append(".");
00087             retval.append(className);
00088         }
00089     }
00090     if (! withType)
00091         return retval;
00092     if (c && isOOClass(c)) {
00093         retval.append(".Object");
00094         if (! byValue)
00095             retval.append("_Ptr");
00096     } else {
00097         retval.append(".");
00098         retval.append(className);
00099     }
00100     return retval;
00101 }
00102 
00103 void PascalWriter::computeAssocTypeAndRole
00104 (UMLAssociation *a, QString& typeName, QString& roleName) {
00105     roleName = a->getRoleName(Uml::A);
00106     if (roleName.isEmpty()) {
00107         if (a->getMulti(Uml::A).isEmpty()) {
00108             roleName = "M_";
00109             roleName.append(typeName);
00110         } else {
00111             roleName = typeName;
00112             roleName.append("_Vector");
00113         }
00114     }
00115     UMLClassifier* c = dynamic_cast<UMLClassifier*>(a->getObject(Uml::A));
00116     if (c == NULL)
00117         return;
00118     typeName = cleanName(c->getName());
00119     if (! a->getMulti(Uml::A).isEmpty())
00120         typeName.append("_Array_Access");
00121 }
00122 
00123 void PascalWriter::writeClass(UMLClassifier *c) {
00124     if (!c) {
00125         kDebug() << "Cannot write class of NULL concept!" << endl;
00126         return;
00127     }
00128 
00129     const bool isClass = !c->isInterface();
00130     QString classname = cleanName(c->getName());
00131     QString fileName = qualifiedName(c).lower();
00132     fileName.replace('.', '-');
00133 
00134     //find an appropriate name for our file
00135     fileName = overwritableName(c, fileName, ".pas");
00136     if (fileName.isEmpty()) {
00137         emit codeGenerated(c, false);
00138         return;
00139     }
00140 
00141     QFile file;
00142     if (!openFile(file, fileName)) {
00143         emit codeGenerated(c, false);
00144         return;
00145     }
00146 
00147     // Start generating the code.
00148 
00149     QTextStream pas(&file);
00150     //try to find a heading file(license, comments, etc)
00151     QString str;
00152     str = getHeadingFile(".pas");
00153     if (!str.isEmpty()) {
00154         str.replace(QRegExp("%filename%"), fileName);
00155         str.replace(QRegExp("%filepath%"), file.name());
00156         pas << str << endl;
00157     }
00158 
00159     QString unit = qualifiedName(c);
00160     pas << "unit " << unit << ";" << m_endl << m_endl;
00161     pas << "INTERFACE" << m_endl << m_endl;
00162     // Use referenced classes.
00163     UMLPackageList imports;
00164     findObjectsRelated(c, imports);
00165     if (imports.count()) {
00166         pas << "uses" << m_endl;
00167         bool first = true;
00168         for (UMLPackage *con = imports.first(); con; con = imports.next()) {
00169             if (con->getBaseType() != Uml::ot_Datatype) {
00170                 if (first)
00171                     first = false;
00172                 else
00173                     pas << "," << m_endl;
00174                 pas << "  " << qualifiedName(con);
00175             }
00176         }
00177         pas << ";" << m_endl << m_endl;
00178     }
00179 
00180     pas << "type" << m_endl;
00181     m_indentLevel++;
00182     if (c->getBaseType() == Uml::ot_Enum) {
00183         UMLEnum *ue = static_cast<UMLEnum*>(c);
00184         UMLClassifierListItemList litList = ue->getFilteredList(Uml::ot_EnumLiteral);
00185         uint i = 0;
00186         pas << getIndent() << classname << " = (" << m_endl;
00187         m_indentLevel++;
00188         for (UMLClassifierListItem *lit = litList.first(); lit; lit = litList.next()) {
00189             QString enumLiteral = cleanName(lit->getName());
00190             pas << getIndent() << enumLiteral;
00191             if (++i < litList.count())
00192                 pas << "," << m_endl;
00193         }
00194         m_indentLevel--;
00195         pas << ");" << m_endl << m_endl;
00196         m_indentLevel--;
00197         pas << "end." << m_endl << m_endl;
00198         return;
00199     }
00200     UMLAttributeList atl = c->getAttributeList();
00201     if (! isOOClass(c)) {
00202         QString stype = c->getStereotype();
00203         if (stype == "CORBAConstant") {
00204             pas << getIndent() << "// " << stype << " is Not Yet Implemented" << m_endl << m_endl;
00205         } else if(stype == "CORBAStruct") {
00206             if (isClass) {
00207                 UMLAttribute *at;
00208                 pas << getIndent() << classname << " = record" << m_endl;
00209                 m_indentLevel++;
00210                 for (at = atl.first(); at; at = atl.next()) {
00211                     QString name = cleanName(at->getName());
00212                     QString typeName = at->getTypeName();
00213                     pas << getIndent() << name << " : " << typeName;
00214                     QString initialVal = at->getInitialValue();
00215                     if (initialVal.latin1() && ! initialVal.isEmpty())
00216                         pas << " := " << initialVal;
00217                     pas << ";" << m_endl;
00218                 }
00219                 m_indentLevel--;
00220                 pas << "end;" << m_endl << m_endl;
00221             }
00222         } else if(stype == "CORBAUnion") {
00223             pas << getIndent() << "// " << stype << " is Not Yet Implemented" << m_endl << m_endl;
00224         } else if(stype == "CORBATypedef") {
00225             pas << getIndent() << "// " << stype << " is Not Yet Implemented" << m_endl << m_endl;
00226         } else {
00227             pas << getIndent() << "// " << stype << ": Unknown stereotype" << m_endl << m_endl;
00228         }
00229         m_indentLevel--;
00230         pas << getIndent() << "end." << m_endl << m_endl;
00231         return;
00232     }
00233 
00234     // Write class Documentation if non-empty or if force option set.
00235     if (forceDoc() || !c->getDoc().isEmpty()) {
00236         pas << "//" << m_endl;
00237         pas << "// class " << classname << endl;
00238         pas << formatDoc(c->getDoc(), "// ");
00239         pas << m_endl;
00240     }
00241 
00242     UMLClassifierList superclasses = c->getSuperClasses();
00243 
00244     pas << getIndent() << classname << " = object";
00245     if (!superclasses.isEmpty()) {
00246         // FIXME: Multiple inheritance is not yet supported
00247         UMLClassifier* parent = superclasses.first();
00248         pas << "(" << qualifiedName(parent) << ")";
00249     }
00250     pas << m_endl;
00251 
00252     ClassifierInfo info(c, UMLApp::app()->getDocument());
00253     UMLAttributeList atpub = info.atpub;
00254     if (isClass && (forceSections() || atpub.count())) {
00255         pas << getIndent() << "// Public attributes:" << m_endl;
00256         UMLAttribute *at;
00257         for (at = atpub.first(); at; at = atpub.next()) {
00258             // if (at->getStatic())
00259             //     continue;
00260             pas << getIndent() << cleanName(at->getName()) << " : "
00261                 << at->getTypeName();
00262             if (at && at->getInitialValue().latin1() && ! at->getInitialValue().isEmpty())
00263                 pas << " := " << at->getInitialValue();
00264             pas << ";" << m_endl;
00265         }
00266     }
00267     bool haveAttrs = (isClass && atl.count());
00268 
00269     // Generate public operations.
00270     UMLOperationList opl(c->getOpList());
00271     UMLOperationList oppub;
00272     oppub.setAutoDelete(false);
00273     UMLOperation *op;
00274     for (op = opl.first(); op; op = opl.next()) {
00275          if (op->getVisibility() == Uml::Visibility::Public)
00276             oppub.append(op);
00277     }
00278     if (forceSections() || oppub.count())
00279         pas << getIndent() << "// Public methods:" << m_endl << m_endl;
00280     for (op = oppub.first(); op; op = oppub.next())
00281         writeOperation(op, pas);
00282 
00283     if (info.atprot.count()) {
00284         pas << "protected" << m_endl << m_endl;
00285         UMLAttribute *at;
00286         UMLAttributeList atprot = info.atprot;
00287         for (at = atprot.first(); at; at = atprot.next()) {
00288             // if (at->getStatic())
00289             //     continue;
00290             pas << getIndent() << cleanName(at->getName()) << " : "
00291                 << at->getTypeName();
00292             if (at && at->getInitialValue().latin1() && ! at->getInitialValue().isEmpty())
00293                 pas << " := " << at->getInitialValue();
00294             pas << ";" << m_endl;
00295         }
00296         pas << m_endl;
00297     }
00298     if (info.atpriv.count()) {
00299         pas << "private" << m_endl << m_endl;
00300         UMLAttribute *at;
00301         UMLAttributeList atpriv = info.atpriv;
00302         for (at = atpriv.first(); at; at = atpriv.next()) {
00303             // if (at->getStatic())
00304             //     continue;
00305             pas << getIndent() << cleanName(at->getName()) << " : "
00306                 << at->getTypeName();
00307             if (at && at->getInitialValue().latin1() && ! at->getInitialValue().isEmpty())
00308                 pas << " := " << at->getInitialValue();
00309             pas << ";" << m_endl;
00310         }
00311         pas << m_endl;
00312     }
00313     pas << getIndent() << "end;" << m_endl << m_endl;
00314 
00315     pas << getIndent() << "P" << classname << " = ^" << classname <<";" << m_endl << m_endl;
00316 
00317     m_indentLevel--;
00318     pas << "end;" << m_endl << m_endl;
00319     file.close();
00320     emit codeGenerated(c, true);
00321 }
00322 
00323 
00324 void PascalWriter::writeOperation(UMLOperation *op, QTextStream &pas, bool is_comment) {
00325     if (op->getStatic()) {
00326         pas << "// TODO: generate status method " << op->getName() << m_endl;
00327         return;
00328     }
00329     UMLAttributeList atl = op->getParmList();
00330     QString rettype = op->getTypeName();
00331     bool use_procedure = (rettype.isEmpty() || rettype == "void");
00332 
00333     pas << getIndent();
00334     if (is_comment)
00335         pas << "// ";
00336     if (use_procedure)
00337         pas << "procedure ";
00338     else
00339         pas << "function ";
00340     pas << cleanName(op->getName()) << " ";
00341     if (atl.count()) {
00342         pas << "(" << m_endl;
00343         uint i = 0;
00344         m_indentLevel++;
00345         for (UMLAttribute *at = atl.first(); at; at = atl.next()) {
00346             pas << getIndent();
00347             if (is_comment)
00348                 pas << "// ";
00349             pas << cleanName(at->getName()) << " : ";
00350             Uml::Parameter_Direction pk = at->getParmKind();
00351             if (pk != Uml::pd_In)
00352                 pas << "var ";
00353             pas << at->getTypeName();
00354             if (! at->getInitialValue().isEmpty())
00355                 pas << " := " << at->getInitialValue();
00356             if (++i < (uint)atl.count())
00357                 pas << ";" << m_endl;
00358         }
00359         m_indentLevel--;
00360         pas << ")";
00361     }
00362     if (! use_procedure)
00363         pas << " : " << rettype;
00364     pas << "; virtual; abstract;" << m_endl << m_endl;
00365     // TBH, we make the methods abstract here because we don't have the means
00366     // for generating meaningful implementations.
00367 }
00368 
00369 QStringList PascalWriter::defaultDatatypes() {
00370     QStringList l;
00371     l.append("AnsiString");
00372     l.append("Boolean");
00373     l.append("Byte");
00374     l.append("ByteBool");
00375     l.append("Cardinal");
00376     l.append("Character");
00377     l.append("Currency");
00378     l.append("Double");
00379     l.append("Extended");
00380     l.append("Int64");
00381     l.append("Integer");
00382     l.append("Longint");
00383     l.append("LongBool");
00384     l.append("Longword");
00385     l.append("QWord");
00386     l.append("Real");
00387     l.append("Shortint");
00388     l.append("ShortString");
00389     l.append("Single");
00390     l.append("Smallint");
00391     l.append("String");
00392     l.append("WideString");
00393     l.append("Word");
00394     return l;
00395 }
00396 
00403 bool PascalWriter::isReservedKeyword(const QString & rPossiblyReservedKeyword) {
00404 
00405     const QStringList keywords = reservedKeywords();
00406 
00407     QStringList::ConstIterator it;
00408     for (it = keywords.begin(); it != keywords.end(); ++it)
00409         if ((*it).lower() == rPossiblyReservedKeyword.lower())
00410             return true;
00411 
00412     return false;
00413 }
00414 
00418 const QStringList PascalWriter::reservedKeywords() const {
00419 
00420     static QStringList keywords;
00421 
00422     if ( keywords.isEmpty() ) {
00423         keywords.append( "absolute" );
00424         keywords.append( "abstract" );
00425         keywords.append( "and" );
00426         keywords.append( "array" );
00427         keywords.append( "as" );
00428         keywords.append( "asm" );
00429         keywords.append( "assembler" );
00430         keywords.append( "automated" );
00431         keywords.append( "begin" );
00432         keywords.append( "case" );
00433         keywords.append( "cdecl" );
00434         keywords.append( "class" );
00435         keywords.append( "const" );
00436         keywords.append( "constructor" );
00437         keywords.append( "contains" );
00438         keywords.append( "default" );
00439         keywords.append( "deprecated" );
00440         keywords.append( "destructor" );
00441         keywords.append( "dispid" );
00442         keywords.append( "dispinterface" );
00443         keywords.append( "div" );
00444         keywords.append( "do" );
00445         keywords.append( "downto" );
00446         keywords.append( "dynamic" );
00447         keywords.append( "else" );
00448         keywords.append( "end" );
00449         keywords.append( "except" );
00450         keywords.append( "export" );
00451         keywords.append( "exports" );
00452         keywords.append( "external" );
00453         keywords.append( "far" );
00454         keywords.append( "file" );
00455         keywords.append( "final" );
00456         keywords.append( "finalization" );
00457         keywords.append( "finally" );
00458         keywords.append( "for" );
00459         keywords.append( "forward" );
00460         keywords.append( "function" );
00461         keywords.append( "goto" );
00462         keywords.append( "if" );
00463         keywords.append( "implementation" );
00464         keywords.append( "implements" );
00465         keywords.append( "in" );
00466         keywords.append( "index" );
00467         keywords.append( "inherited" );
00468         keywords.append( "initialization" );
00469         keywords.append( "inline" );
00470         keywords.append( "inline" );
00471         keywords.append( "interface" );
00472         keywords.append( "is" );
00473         keywords.append( "label" );
00474         keywords.append( "library" );
00475         keywords.append( "library" );
00476         keywords.append( "local" );
00477         keywords.append( "message" );
00478         keywords.append( "mod" );
00479         keywords.append( "name" );
00480         keywords.append( "near" );
00481         keywords.append( "nil" );
00482         keywords.append( "nodefault" );
00483         keywords.append( "not" );
00484         keywords.append( "object" );
00485         keywords.append( "of" );
00486         keywords.append( "or" );
00487         keywords.append( "out" );
00488         keywords.append( "overload" );
00489         keywords.append( "override" );
00490         keywords.append( "package" );
00491         keywords.append( "packed" );
00492         keywords.append( "pascal" );
00493         keywords.append( "platform" );
00494         keywords.append( "private" );
00495         keywords.append( "procedure" );
00496         keywords.append( "program" );
00497         keywords.append( "property" );
00498         keywords.append( "protected" );
00499         keywords.append( "public" );
00500         keywords.append( "published" );
00501         keywords.append( "raise" );
00502         keywords.append( "read" );
00503         keywords.append( "readonly" );
00504         keywords.append( "record" );
00505         keywords.append( "register" );
00506         keywords.append( "reintroduce" );
00507         keywords.append( "repeat" );
00508         keywords.append( "requires" );
00509         keywords.append( "resident" );
00510         keywords.append( "resourcestring" );
00511         keywords.append( "safecall" );
00512         keywords.append( "sealed" );
00513         keywords.append( "set" );
00514         keywords.append( "shl" );
00515         keywords.append( "shr" );
00516         keywords.append( "static" );
00517         keywords.append( "stdcall" );
00518         keywords.append( "stored" );
00519         keywords.append( "string" );
00520         keywords.append( "then" );
00521         keywords.append( "threadvar" );
00522         keywords.append( "to" );
00523         keywords.append( "try" );
00524         keywords.append( "type" );
00525         keywords.append( "unit" );
00526         keywords.append( "unsafe" );
00527         keywords.append( "until" );
00528         keywords.append( "uses" );
00529         keywords.append( "var" );
00530         keywords.append( "varargs" );
00531         keywords.append( "virtual" );
00532         keywords.append( "while" );
00533         keywords.append( "with" );
00534         keywords.append( "write" );
00535         keywords.append( "writeonly" );
00536         keywords.append( "xor" );
00537     }
00538 
00539     return keywords;
00540 }
00541 
00542 #include "pascalwriter.moc"
KDE Logo
This file is part of the documentation for umbrello Version 3.1.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Jun 26 08:07:59 2007 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003