diff options
Diffstat (limited to 'umbrello/umbrello/codegenerators/adawriter.cpp')
-rw-r--r-- | umbrello/umbrello/codegenerators/adawriter.cpp | 686 |
1 files changed, 686 insertions, 0 deletions
diff --git a/umbrello/umbrello/codegenerators/adawriter.cpp b/umbrello/umbrello/codegenerators/adawriter.cpp new file mode 100644 index 00000000..e1c79839 --- /dev/null +++ b/umbrello/umbrello/codegenerators/adawriter.cpp @@ -0,0 +1,686 @@ +/*************************************************************************** + * adawriter.cpp - description * + * ------------------- * + * Based on javawriter.cpp by Luis De la Parra Blum * + * copyright : (C) 2002 by Oliver Kellogg * + * (C) 2003-2007 Umbrello UML Modeller Authors <uml-devel@uml.sf.net> * + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "adawriter.h" + +#include <kdebug.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <qfile.h> +#include <qregexp.h> +#include <qtextstream.h> + +#include "../umldoc.h" +#include "../uml.h" +#include "../classifier.h" +#include "../enum.h" +#include "../classifierlistitem.h" +#include "../umlclassifierlistitemlist.h" +#include "../umltemplatelist.h" +#include "../folder.h" +#include "../association.h" +#include "../attribute.h" +#include "../operation.h" +#include "../template.h" +#include "../umlnamespace.h" + +const QString AdaWriter::defaultPackageSuffix = "_Holder"; + +AdaWriter::AdaWriter() { +} + +AdaWriter::~AdaWriter() {} + +/** + * returns "Ada" + */ +Uml::Programming_Language AdaWriter::getLanguage() { + return Uml::pl_Ada; +} + + +bool AdaWriter::isOOClass(UMLClassifier *c) { + Uml::Object_Type ot = c->getBaseType(); + if (ot == Uml::ot_Interface) + return true; + if (ot == Uml::ot_Enum) + return false; + if (ot != Uml::ot_Class) { + kDebug() << "AdaWriter::isOOClass: unknown object type " << ot << endl; + return false; + } + QString stype = c->getStereotype(); + if (stype == "CORBAConstant" || stype == "CORBATypedef" || + stype == "CORBAStruct" || stype == "CORBAUnion") + return false; + // CORBAValue, CORBAInterface, and all empty/unknown stereotypes are + // assumed to be OO classes. + return true; +} + +QString AdaWriter::className(UMLClassifier *c, bool inOwnScope) { + // If the class has an enclosing package then it is assumed that + // the class name is the type name; if the class does not have an + // enclosing package then the class name acts as the Ada package + // name. + QString retval; + QString className = cleanName(c->getName()); + UMLPackage *umlPkg = c->getUMLPackage(); + if (umlPkg == UMLApp::app()->getDocument()->getRootFolder(Uml::mt_Logical)) { + if (! inOwnScope) + retval = className + '.'; + retval.append("Object"); + } else { + if (! inOwnScope) + retval = umlPkg->getFullyQualifiedName(".") + '.'; + retval.append(className); + } + return retval; +} + +QString AdaWriter::packageName(UMLPackage *p) { + // If the class has an enclosing package then it is assumed that + // the class name is the type name; if the class does not have an + // enclosing package then the class name acts as the Ada package + // name. + UMLPackage *umlPkg = p->getUMLPackage(); + QString className = cleanName(p->getName()); + QString retval; + + if (umlPkg == UMLApp::app()->getDocument()->getRootFolder(Uml::mt_Logical)) + umlPkg = NULL; + + UMLClassifier *c = dynamic_cast<UMLClassifier*>(p); + if (umlPkg == NULL) { + retval = className; + if (c == NULL || !isOOClass(c)) + retval.append(defaultPackageSuffix); + } else { + retval = umlPkg->getFullyQualifiedName("."); + } + return retval; +} + +void AdaWriter::computeAssocTypeAndRole(UMLClassifier *c, + UMLAssociation *a, + QString& typeName, QString& roleName) { + UMLClassifier* assocEnd = dynamic_cast<UMLClassifier*>(a->getObject(Uml::B)); + if (assocEnd == NULL) + return; + const Uml::Association_Type assocType = a->getAssocType(); + if (assocType != Uml::at_Aggregation && assocType != Uml::at_Composition) + return; + const QString multi = a->getMulti(Uml::B); + bool hasNonUnityMultiplicity = (!multi.isEmpty() && multi != "1"); + hasNonUnityMultiplicity &= !multi.contains(QRegExp("^1 *\\.\\. *1$")); + roleName = cleanName(a->getRoleName(Uml::B)); + if (roleName.isEmpty()) + roleName = cleanName(a->getName()); + if (roleName.isEmpty()) { + QString artificialName = cleanName(assocEnd->getName()); + if (hasNonUnityMultiplicity) { + roleName = artificialName; + roleName.append("_Vector"); + } else { + roleName = "M_"; + roleName.append(artificialName); + } + } + typeName = className(assocEnd, (assocEnd == c)); + if (hasNonUnityMultiplicity) + typeName.append("_Array_Ptr"); + else if (assocType == Uml::at_Aggregation) + typeName.append("_Ptr"); +} + +void AdaWriter::writeClass(UMLClassifier *c) { + if (!c) { + kDebug() << "Cannot write class of NULL concept!" << endl; + return; + } + + const bool isClass = !c->isInterface(); + QString classname = cleanName(c->getName()); + QString fileName = packageName(c).lower(); + fileName.replace('.', '-'); + + //find an appropriate name for our file + fileName = overwritableName(c, fileName, ".ads"); + if (fileName.isEmpty()) { + emit codeGenerated(c, false); + return; + } + + QFile file; + if (!openFile(file, fileName)) { + emit codeGenerated(c, false); + return; + } + + // Start generating the code. + + QTextStream ada(&file); + //try to find a heading file(license, comments, etc) + QString str; + str = getHeadingFile(".ads"); + if (!str.isEmpty()) { + str.replace(QRegExp("%filename%"), fileName); + str.replace(QRegExp("%filepath%"), file.name()); + ada << str << endl; + } + + // Import referenced classes. + UMLPackageList imports; + findObjectsRelated(c, imports); + if (imports.count()) { + for (UMLPackage *con = imports.first(); con; con = imports.next()) { + if (con->getBaseType() != Uml::ot_Datatype) + ada << "with " << packageName(con) << "; " << m_endl; + } + ada << m_endl; + } + + // Generate generic formals. + UMLTemplateList template_params = c->getTemplateList(); + if (template_params.count()) { + ada << getIndent() << "generic" << m_endl; + m_indentLevel++; + for (UMLTemplate *t = template_params.first(); t; t = template_params.next()) { + QString formalName = t->getName(); + QString typeName = t->getTypeName(); + if (typeName == "class") { + ada << getIndent() << "type " << formalName << " is tagged private;" + << m_endl; + } else { + // Check whether it's a data type. + UMLClassifier *typeObj = t->getType(); + if (typeObj == NULL) { + kError() << "AdaWriter::writeClass(template_param " + << typeName << "): typeObj is NULL" << endl; + ada << getIndent() << "type " << formalName << " is new " << typeName + << " with private; -- CHECK: codegen error" + << m_endl; + } else if (typeObj->getBaseType() == Uml::ot_Datatype) { + ada << getIndent() << formalName << " : " << typeName << ";" + << m_endl; + } else { + ada << getIndent() << "type " << typeName << " is new " + << formalName << " with private;" << m_endl; + } + } + } + m_indentLevel--; + } + + // Here comes the package proper. + QString pkg = packageName(c); + ada << getIndent() << "package " << pkg << " is" << m_endl << m_endl; + m_indentLevel++; + if (c->getBaseType() == Uml::ot_Enum) { + UMLEnum *ue = static_cast<UMLEnum*>(c); + UMLClassifierListItemList litList = ue->getFilteredList(Uml::ot_EnumLiteral); + uint i = 0; + ada << getIndent() << "type " << classname << " is (" << m_endl; + m_indentLevel++; + for (UMLClassifierListItem *lit = litList.first(); lit; lit = litList.next()) { + QString enumLiteral = cleanName(lit->getName()); + ada << getIndent() << enumLiteral; + if (++i < litList.count()) + ada << "," << m_endl; + } + m_indentLevel--; + ada << ");" << m_endl << m_endl; + m_indentLevel--; + ada << getIndent() << "end " << pkg << ";" << m_endl << m_endl; + return; + } + if (! isOOClass(c)) { + QString stype = c->getStereotype(); + if (stype == "CORBAConstant") { + ada << getIndent() << "-- " << stype << " is Not Yet Implemented" << m_endl << m_endl; + } else if(stype == "CORBAStruct") { + if (isClass) { + UMLAttributeList atl = c->getAttributeList(); + UMLAttribute *at; + ada << getIndent() << "type " << classname << " is record" << m_endl; + m_indentLevel++; + for (at = atl.first(); at; at = atl.next()) { + QString name = cleanName(at->getName()); + QString typeName = at->getTypeName(); + ada << getIndent() << name << " : " << typeName; + QString initialVal = at->getInitialValue(); + if (initialVal.latin1() && ! initialVal.isEmpty()) + ada << " := " << initialVal; + ada << ";" << m_endl; + } + m_indentLevel--; + ada << getIndent() << "end record;" << m_endl << m_endl; + } + } else if(stype == "CORBAUnion") { + ada << getIndent() << "-- " << stype << " is Not Yet Implemented" << m_endl << m_endl; + } else if(stype == "CORBATypedef") { + ada << getIndent() << "-- " << stype << " is Not Yet Implemented" << m_endl << m_endl; + } else { + ada << getIndent() << "-- " << stype << ": Unknown stereotype" << m_endl << m_endl; + } + m_indentLevel--; + ada << getIndent() << "end " << pkg << ";" << m_endl << m_endl; + return; + } + + // Write class Documentation if non-empty or if force option set. + if (forceDoc() || !c->getDoc().isEmpty()) { + ada << "--" << m_endl; + ada << "-- class " << classname << endl; + ada << formatDoc(c->getDoc(), "-- "); + ada << m_endl; + } + + UMLClassifierList superclasses = c->getSuperClasses(); + + const QString name = className(c); + ada << getIndent() << "type " << name << " is "; + if (c->getAbstract()) + ada << "abstract "; + if (superclasses.isEmpty()) { + ada << "tagged "; + } else { + // FIXME: Multiple inheritance is not yet supported + UMLClassifier* parent = superclasses.first(); + ada << "new " << className(parent, false) << " with "; + } + ada << "private;" << m_endl << m_endl; + ada << getIndent() << "type " << name << "_Ptr is access all " << name << "'Class;" << m_endl << m_endl; + ada << getIndent() << "type " << name << "_Array is array (Positive range <>) of " << name << "_Ptr;" << m_endl << m_endl; + ada << getIndent() << "type " << name << "_Array_Ptr is access " << name << "_Array;" << m_endl << m_endl; + + // Generate accessors for public attributes. + UMLAttributeList atl; + if (isClass) { + UMLAttributeList atpub; + atpub.setAutoDelete(false); + + atl = c->getAttributeList(); + + UMLAttribute *at; + for (at = atl.first(); at; at = atl.next()) { + if (at->getVisibility() == Uml::Visibility::Public) + atpub.append(at); + } + if (forceSections() || atpub.count()) + ada << getIndent() << "-- Accessors for public attributes:" << m_endl << m_endl; + for (at = atpub.first(); at; at = atpub.next()) { + QString member = cleanName(at->getName()); + ada << getIndent() << "procedure Set_" << member << " ("; + if (! at->getStatic()) + ada << "Self : access " << name << "; "; + ada << "To : " << at->getTypeName() << ");" << m_endl; + ada << getIndent() << "function Get_" << member; + if (! at->getStatic()) + ada << " (Self : access " << name << ")"; + ada << " return " << at->getTypeName() << ";" << m_endl + << m_endl; + } + } + + // Generate public operations. + UMLOperationList opl(c->getOpList()); + UMLOperationList oppub; + oppub.setAutoDelete(false); + UMLOperation *op; + for (op = opl.first(); op; op = opl.next()) { + if (op->getVisibility() == Uml::Visibility::Public) + oppub.append(op); + } + if (forceSections() || oppub.count()) + ada << getIndent() << "-- Public methods:" << m_endl << m_endl; + for (op = oppub.first(); op; op = oppub.next()) + writeOperation(op, ada); + + m_indentLevel--; + ada << getIndent() << "private" << m_endl << m_endl; + m_indentLevel++; + + UMLAssociationList aggregations = c->getAggregations(); + UMLAssociationList compositions = c->getCompositions(); + + ada << getIndent() << "type " << name << " is "; + if (c->getAbstract()) + ada << "abstract "; + if (superclasses.isEmpty()) { + ada << "tagged "; + } else { + // FIXME: Multiple inheritance is not yet supported + UMLClassifier* parent = superclasses.first(); + ada << "new " << className(parent, false) << " with "; + } + ada << "record" << m_endl; + m_indentLevel++; + + if (forceSections() || !aggregations.isEmpty()) { + ada << getIndent() << "-- Aggregations:" << m_endl; + for (UMLAssociation *a = aggregations.first(); a; a = aggregations.next()) { + if (c != a->getObject(Uml::A)) + continue; + QString typeName, roleName; + computeAssocTypeAndRole(c, a, typeName, roleName); + ada << getIndent() << roleName << " : " << typeName << ";" << m_endl; + } + ada << endl; + } + if (forceSections() || !compositions.isEmpty()) { + ada << getIndent() << "-- Compositions:" << m_endl; + for (UMLAssociation *a = compositions.first(); a; a = compositions.next()) { + if (c != a->getObject(Uml::A)) + continue; + QString typeName, roleName; + computeAssocTypeAndRole(c, a, typeName, roleName); + ada << getIndent() << roleName << " : " << typeName << ";" << m_endl; + } + ada << endl; + } + + if (isClass && (forceSections() || atl.count())) { + ada << getIndent() << "-- Attributes:" << m_endl; + UMLAttribute *at; + for (at = atl.first(); at; at = atl.next()) { + if (at->getStatic()) + continue; + ada << getIndent() << cleanName(at->getName()) << " : " + << at->getTypeName(); + if (at && at->getInitialValue().latin1() && ! at->getInitialValue().isEmpty()) + ada << " := " << at->getInitialValue(); + ada << ";" << m_endl; + } + } + bool haveAttrs = (isClass && atl.count()); + if (aggregations.isEmpty() && compositions.isEmpty() && !haveAttrs) + ada << getIndent() << "null;" << m_endl; + m_indentLevel--; + ada << getIndent() << "end record;" << m_endl << m_endl; + if (haveAttrs) { + bool seen_static_attr = false; + for (UMLAttribute *at = atl.first(); at; at = atl.next()) { + if (! at->getStatic()) + continue; + if (! seen_static_attr) { + ada << getIndent() << "-- Static attributes:" << m_endl; + seen_static_attr = true; + } + ada << getIndent(); + if (at->getVisibility() == Uml::Visibility::Private) + ada << "-- Private: "; + ada << cleanName(at->getName()) << " : " << at->getTypeName(); + if (at && at->getInitialValue().latin1() && ! at->getInitialValue().isEmpty()) + ada << " := " << at->getInitialValue(); + ada << ";" << m_endl; + } + if (seen_static_attr) + ada << m_endl; + } + // Generate protected operations. + UMLOperationList opprot; + opprot.setAutoDelete(false); + for (op = opl.first(); op; op = opl.next()) { + if (op->getVisibility() == Uml::Visibility::Protected) + opprot.append(op); + } + if (forceSections() || opprot.count()) + ada << getIndent() << "-- Protected methods:" << m_endl << m_endl; + for (op = opprot.first(); op; op = opprot.next()) + writeOperation(op, ada); + + // Generate private operations. + // These are currently only generated as comments in the private part + // of the spec. + // Once umbrello supports the merging of automatically generated and + // hand written code sections, private operations should be generated + // into the package body. + UMLOperationList oppriv; + oppriv.setAutoDelete(false); + for (op = opl.first(); op; op = opl.next()) { + const Uml::Visibility::Value vis = op->getVisibility(); + if (vis == Uml::Visibility::Private || + vis == Uml::Visibility::Implementation) + oppriv.append(op); + } + if (forceSections() || oppriv.count()) + ada << getIndent() << "-- Private methods:" << m_endl << m_endl; + for (op = oppriv.first(); op; op = oppriv.next()) + writeOperation(op, ada, true); + + m_indentLevel--; + ada << getIndent() << "end " << pkg << ";" << m_endl << m_endl; + file.close(); + emit codeGenerated(c, true); +} + + +void AdaWriter::writeOperation(UMLOperation *op, QTextStream &ada, bool is_comment) { + UMLAttributeList atl = op->getParmList(); + QString rettype = op->getTypeName(); + bool use_procedure = (rettype.isEmpty() || rettype == "void"); + + ada << getIndent(); + if (is_comment) + ada << "-- "; + if (use_procedure) + ada << "procedure "; + else + ada << "function "; + ada << cleanName(op->getName()) << " "; + if (! (op->getStatic() && atl.count() == 0)) + ada << "("; + UMLClassifier *parentClassifier = static_cast<UMLClassifier*>(op->getUMLPackage()); + if (! op->getStatic()) { + ada << "Self : access " << className(parentClassifier); + if (atl.count()) + ada << ";" << m_endl; + } + if (atl.count()) { + uint i = 0; + m_indentLevel++; + for (UMLAttribute *at = atl.first(); at; at = atl.next()) { + ada << getIndent(); + if (is_comment) + ada << "-- "; + ada << cleanName(at->getName()) << " : "; + Uml::Parameter_Direction pk = at->getParmKind(); + if (pk == Uml::pd_Out) + ada << "out "; + else if (pk == Uml::pd_InOut) + ada << "in out "; + else + ada << "in "; + ada << at->getTypeName(); + if (! at->getInitialValue().isEmpty()) + ada << " := " << at->getInitialValue(); + if (++i < atl.count()) //FIXME gcc warning + ada << ";" << m_endl; + } + m_indentLevel--; + } + if (! (op->getStatic() && atl.count() == 0)) + ada << ")"; + if (! use_procedure) + ada << " return " << rettype; + if (op->getAbstract()) + ada << " is abstract"; + ada << ";" << m_endl << m_endl; +} + +QStringList AdaWriter::defaultDatatypes() { + QStringList l; + l.append("Boolean"); + l.append("Character"); + l.append("Positive"); + l.append("Natural"); + l.append("Integer"); + l.append("Short_Integer"); + l.append("Long_Integer"); + l.append("Float"); + l.append("Long_Float"); + l.append("Duration"); + l.append("String"); + return l; +} + +/** + * Check whether the given string is a reserved word for the + * language of this code generator + * + * @param rPossiblyReservedKeyword The string to check. + */ +bool AdaWriter::isReservedKeyword(const QString & rPossiblyReservedKeyword) { + + const QStringList keywords = reservedKeywords(); + + QStringList::ConstIterator it; + for (it = keywords.begin(); it != keywords.end(); ++it) + if ((*it).lower() == rPossiblyReservedKeyword.lower()) + return true; + + return false; +} + +/** + * get list of reserved keywords + */ +const QStringList AdaWriter::reservedKeywords() const { + + static QStringList keywords; + + if ( keywords.isEmpty() ) { + keywords.append( "abort" ); + keywords.append( "abs" ); + keywords.append( "abstract" ); + keywords.append( "accept" ); + keywords.append( "access" ); + keywords.append( "aliased" ); + keywords.append( "all" ); + keywords.append( "and" ); + keywords.append( "Argument_Error" ); + keywords.append( "array" ); + keywords.append( "Assert_Failure" ); + keywords.append( "at" ); + keywords.append( "begin" ); + keywords.append( "body" ); + keywords.append( "Boolean" ); + keywords.append( "case" ); + keywords.append( "Character" ); + keywords.append( "constant" ); + keywords.append( "Constraint_Error" ); + keywords.append( "Conversion_Error" ); + keywords.append( "Data_Error" ); + keywords.append( "declare" ); + keywords.append( "delay" ); + keywords.append( "delta" ); + keywords.append( "Dereference_Error" ); + keywords.append( "Device_Error" ); + keywords.append( "digits" ); + keywords.append( "do" ); + keywords.append( "Duration" ); + keywords.append( "else" ); + keywords.append( "elsif" ); + keywords.append( "end" ); + keywords.append( "End_Error" ); + keywords.append( "entry" ); + keywords.append( "exception" ); + keywords.append( "exit" ); + keywords.append( "false" ); + keywords.append( "Float" ); + keywords.append( "for" ); + keywords.append( "function" ); + keywords.append( "generic" ); + keywords.append( "goto" ); + keywords.append( "if" ); + keywords.append( "in" ); + keywords.append( "Index_Error" ); + keywords.append( "Integer" ); + keywords.append( "is" ); + keywords.append( "Layout_Error" ); + keywords.append( "Length_Error" ); + keywords.append( "limited" ); + keywords.append( "Long_Float" ); + keywords.append( "Long_Integer" ); + keywords.append( "Long_Long_Float" ); + keywords.append( "Long_Long_Integer" ); + keywords.append( "loop" ); + keywords.append( "mod" ); + keywords.append( "Mode_Error" ); + keywords.append( "Name_Error" ); + keywords.append( "Natural" ); + keywords.append( "new" ); + keywords.append( "not" ); + keywords.append( "null" ); + keywords.append( "of" ); + keywords.append( "or" ); + keywords.append( "others" ); + keywords.append( "out" ); + keywords.append( "package" ); + keywords.append( "Pattern_Error" ); + keywords.append( "Picture_Error" ); + keywords.append( "Pointer_Error" ); + keywords.append( "Positive" ); + keywords.append( "pragma" ); + keywords.append( "private" ); + keywords.append( "procedure" ); + keywords.append( "Program_Error" ); + keywords.append( "protected" ); + keywords.append( "raise" ); + keywords.append( "range" ); + keywords.append( "record" ); + keywords.append( "rem" ); + keywords.append( "renames" ); + keywords.append( "requeue" ); + keywords.append( "return" ); + keywords.append( "reverse" ); + keywords.append( "select" ); + keywords.append( "separate" ); + keywords.append( "Short_Float" ); + keywords.append( "Short_Integer" ); + keywords.append( "Short_Short_Float" ); + keywords.append( "Short_Short_Integer" ); + keywords.append( "Status_Error" ); + keywords.append( "Storage_Error" ); + keywords.append( "String" ); + keywords.append( "subtype" ); + keywords.append( "Tag_Error" ); + keywords.append( "tagged" ); + keywords.append( "task" ); + keywords.append( "Tasking_Error" ); + keywords.append( "terminate" ); + keywords.append( "Terminator_Error" ); + keywords.append( "then" ); + keywords.append( "Time_Error" ); + keywords.append( "Translation_Error" ); + keywords.append( "true" ); + keywords.append( "type" ); + keywords.append( "until" ); + keywords.append( "Update_Error" ); + keywords.append( "use" ); + keywords.append( "Use_Error" ); + keywords.append( "when" ); + keywords.append( "while" ); + keywords.append( "Wide_Character" ); + keywords.append( "Wide_String" ); + keywords.append( "with" ); + keywords.append( "xor" ); + } + + return keywords; +} + +#include "adawriter.moc" |